From 36a8ba6f19a8f58dc755dc9c3c6c1c8858bdcde4 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Wed, 9 Sep 2026 08:45:46 +0900 Subject: [PATCH 01/31] =?UTF-8?q?:bug:=20::=20=EC=8B=A0=EA=B7=9C=20API=20s?= =?UTF-8?q?pec=EC=9C=BC=EB=A1=9C=20=EC=9E=84=EC=8B=9C=20=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - API의 스펙 변경에 따라 로드가 안되는 문제가 있어 임시 작업 --- .../model/timecapsule/MyTimeCapsuleResponse.kt | 9 +++++++++ .../network/service/TimeCapsuleService.kt | 7 ++++++- .../timecapsule/TimeCapsuleDataSource.kt | 3 ++- .../timecapsule/TimeCapsuleDataSourceImpl.kt | 9 +++++++-- .../timecapsule/TimeCapsuleRepository.kt | 3 ++- .../timecapsule/TimeCapsuleRepositoryImpl.kt | 5 +++-- .../timecapsule/GetMyTimeCapsuleUseCase.kt | 17 ++++++++++++----- .../java/com/idiotfrogs/home/HomeViewModel.kt | 4 ++-- .../idiotfrogs/profile/profile/ProfileScreen.kt | 4 ++-- .../profile/profile/ProfileViewModel.kt | 10 +++------- 10 files changed, 48 insertions(+), 23 deletions(-) diff --git a/core/model/src/main/java/com/idiotfrogs/model/timecapsule/MyTimeCapsuleResponse.kt b/core/model/src/main/java/com/idiotfrogs/model/timecapsule/MyTimeCapsuleResponse.kt index 3bda5085..0c7dc5ce 100644 --- a/core/model/src/main/java/com/idiotfrogs/model/timecapsule/MyTimeCapsuleResponse.kt +++ b/core/model/src/main/java/com/idiotfrogs/model/timecapsule/MyTimeCapsuleResponse.kt @@ -5,6 +5,15 @@ import kotlinx.serialization.Serializable @Serializable data class MyTimeCapsuleResponse( + val content: List, + val totalPages: Int, + val totalElements: Long, + val number: Int, + val last: Boolean, +) + +@Serializable +data class MyTimeCapsuleContent( val timeCapsuleId: Long, val title: String, val openedAt: LocalDate? = null, diff --git a/core/network/src/main/java/com/idiotfrogs/network/service/TimeCapsuleService.kt b/core/network/src/main/java/com/idiotfrogs/network/service/TimeCapsuleService.kt index 026f1e8e..32b264c9 100644 --- a/core/network/src/main/java/com/idiotfrogs/network/service/TimeCapsuleService.kt +++ b/core/network/src/main/java/com/idiotfrogs/network/service/TimeCapsuleService.kt @@ -11,6 +11,7 @@ import com.idiotfrogs.model.timecapsule.TimeCapsuleCreateRequest import com.idiotfrogs.model.timecapsule.TimeCapsuleCreateResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleInviteCodeResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleResponse +import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus import com.idiotfrogs.model.timecapsule.WateringResponse import okhttp3.MultipartBody import okhttp3.RequestBody @@ -34,7 +35,11 @@ interface TimeCapsuleService { ): TimeCapsuleCreateResponse @GET("time-capsules/my") - suspend fun getMyTimeCapsule(): List + suspend fun getMyTimeCapsule( + @Query("status") status: TimeCapsuleStatus, + @Query("page") page: Int, + @Query("size") size: Int + ): MyTimeCapsuleResponse @DELETE("time-capsules/{capsuleId}") suspend fun deleteTimeCapsule(@Path("capsuleId") capsuleId: Long) diff --git a/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSource.kt b/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSource.kt index 4b03700f..3d4d7ee2 100644 --- a/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSource.kt +++ b/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSource.kt @@ -11,6 +11,7 @@ import com.idiotfrogs.model.timecapsule.TimeCapsuleCreateRequest import com.idiotfrogs.model.timecapsule.TimeCapsuleCreateResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleInviteCodeResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleResponse +import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus import com.idiotfrogs.model.timecapsule.WateringResponse import okhttp3.MultipartBody import okhttp3.RequestBody @@ -21,7 +22,7 @@ interface TimeCapsuleDataSource { mainImage: MultipartBody.Part ): TimeCapsuleCreateResponse - suspend fun getMyTimeCapsule(): List + suspend fun getMyTimeCapsule(status: TimeCapsuleStatus, page: Int, size: Int): MyTimeCapsuleResponse suspend fun deleteTimeCapsule(capsuleId: Long) diff --git a/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSourceImpl.kt b/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSourceImpl.kt index 2358ea92..6f754fd6 100644 --- a/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSourceImpl.kt +++ b/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSourceImpl.kt @@ -11,6 +11,7 @@ import com.idiotfrogs.model.timecapsule.TimeCapsuleCreateRequest import com.idiotfrogs.model.timecapsule.TimeCapsuleCreateResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleInviteCodeResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleResponse +import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus import com.idiotfrogs.model.timecapsule.WateringResponse import com.idiotfrogs.network.service.TimeCapsuleService import okhttp3.MultipartBody @@ -30,8 +31,12 @@ class TimeCapsuleDataSourceImpl @Inject constructor( ) } - override suspend fun getMyTimeCapsule(): List { - return timeCapsuleService.getMyTimeCapsule() + override suspend fun getMyTimeCapsule(status: TimeCapsuleStatus, page: Int, size: Int): MyTimeCapsuleResponse { + return timeCapsuleService.getMyTimeCapsule( + status = status, + page = page, + size = size + ) } override suspend fun deleteTimeCapsule(capsuleId: Long) { diff --git a/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepository.kt b/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepository.kt index 129921d4..d9cb3026 100644 --- a/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepository.kt +++ b/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepository.kt @@ -11,6 +11,7 @@ import com.idiotfrogs.model.timecapsule.TimeCapsuleCreateRequest import com.idiotfrogs.model.timecapsule.TimeCapsuleCreateResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleInviteCodeResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleResponse +import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus import com.idiotfrogs.model.timecapsule.WateringResponse import java.io.File @@ -20,7 +21,7 @@ interface TimeCapsuleRepository { mainImage: File ): TimeCapsuleCreateResponse - suspend fun getMyTimeCapsule(): List + suspend fun getMyTimeCapsule(status: TimeCapsuleStatus, page: Int, size: Int): MyTimeCapsuleResponse suspend fun deleteTimeCapsule(capsuleId: Long) diff --git a/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepositoryImpl.kt b/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepositoryImpl.kt index 4594a8d5..cf6e2068 100644 --- a/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepositoryImpl.kt +++ b/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepositoryImpl.kt @@ -12,6 +12,7 @@ import com.idiotfrogs.model.timecapsule.TimeCapsuleCreateRequest import com.idiotfrogs.model.timecapsule.TimeCapsuleCreateResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleInviteCodeResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleResponse +import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus import com.idiotfrogs.util.exception.AlreadyContributorException import com.idiotfrogs.model.timecapsule.WateringResponse import com.idiotfrogs.network.service.TimeCapsuleService @@ -39,8 +40,8 @@ class TimeCapsuleRepositoryImpl @Inject constructor( ) } - override suspend fun getMyTimeCapsule(): List { - return timeCapsuleDataSource.getMyTimeCapsule() + override suspend fun getMyTimeCapsule(status: TimeCapsuleStatus, page: Int, size: Int): MyTimeCapsuleResponse { + return timeCapsuleDataSource.getMyTimeCapsule(status, page, size) } override suspend fun deleteTimeCapsule(capsuleId: Long) { diff --git a/domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetMyTimeCapsuleUseCase.kt b/domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetMyTimeCapsuleUseCase.kt index 3f531a0b..47011970 100644 --- a/domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetMyTimeCapsuleUseCase.kt +++ b/domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetMyTimeCapsuleUseCase.kt @@ -1,7 +1,7 @@ package com.idiotfrogs.domain.usecase.timecapsule import com.idiotfrogs.data.repository.timecapsule.TimeCapsuleRepository -import com.idiotfrogs.model.timecapsule.MyTimeCapsuleResponse +import com.idiotfrogs.model.timecapsule.MyTimeCapsuleContent import com.idiotfrogs.model.timecapsule.TimeCapsuleRole import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus import com.idiotfrogs.util.safeCatching @@ -10,10 +10,17 @@ import javax.inject.Inject class GetMyTimeCapsuleUseCase @Inject constructor( private val timeCapsuleRepository: TimeCapsuleRepository ) { - suspend operator fun invoke(): Result>> = + suspend operator fun invoke(): Result>> = safeCatching { - timeCapsuleRepository.getMyTimeCapsule() - .filter { it.timeCapsuleStatus != TimeCapsuleStatus.OPENED } - .groupBy { it.role } + // FIXME: 임시 코드 + (timeCapsuleRepository.getMyTimeCapsule( + status = TimeCapsuleStatus.BURIED, + page = 0, + size = 50 + ).content + timeCapsuleRepository.getMyTimeCapsule( + status = TimeCapsuleStatus.BEFOREBURIED, + page = 0, + size = 50 + ).content).groupBy { it.role } } } \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/HomeViewModel.kt b/feature/home/src/main/java/com/idiotfrogs/home/HomeViewModel.kt index cd8975df..b7b8c420 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/HomeViewModel.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/HomeViewModel.kt @@ -5,7 +5,7 @@ import com.idiotfrogs.domain.usecase.auth.PutFcmTokenUseCase import com.idiotfrogs.domain.usecase.timecapsule.GetMyTimeCapsuleUseCase import com.idiotfrogs.domain.usecase.timecapsule.RequestCollaboratorUseCase import com.idiotfrogs.domain.usecase.user.GetMyProfileUseCase -import com.idiotfrogs.model.timecapsule.MyTimeCapsuleResponse +import com.idiotfrogs.model.timecapsule.MyTimeCapsuleContent import com.idiotfrogs.model.timecapsule.PendingCollaboratorsRequest import com.idiotfrogs.model.timecapsule.TimeCapsuleRole import com.idiotfrogs.model.user.ProfileResponse @@ -118,7 +118,7 @@ data class HomeUiState( @Immutable data class HomeData( val user: ProfileResponse? = null, - val capsules: Map> = emptyMap() + val capsules: Map> = emptyMap() ) sealed interface HomeAction { diff --git a/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt b/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt index 2106751c..a7076634 100644 --- a/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt +++ b/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt @@ -37,7 +37,7 @@ import com.idiotfrogs.designsystem.theme.MSTheme import com.idiotfrogs.designsystem.util.DrawType import com.idiotfrogs.designsystem.util.noRippleClickable import com.idiotfrogs.designsystem.util.wavyStroke -import com.idiotfrogs.model.timecapsule.MyTimeCapsuleResponse +import com.idiotfrogs.model.timecapsule.MyTimeCapsuleContent import com.idiotfrogs.model.timecapsule.TimeCapsuleRole import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus import com.idiotfrogs.model.user.ProfileResponse @@ -291,7 +291,7 @@ private fun ProfileScreenPreview() { isOnboarding = true ), capsules = listOf( - MyTimeCapsuleResponse( + MyTimeCapsuleContent( timeCapsuleId = 0L, title = "제목입니다. 제목입니다.", createdAt = Clock.System.todayIn(TimeZone.currentSystemDefault()), diff --git a/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileViewModel.kt b/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileViewModel.kt index 8f94de9e..b81e39d9 100644 --- a/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileViewModel.kt +++ b/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileViewModel.kt @@ -5,8 +5,7 @@ import com.idiotfrogs.domain.usecase.auth.LogoutUseCase import com.idiotfrogs.domain.usecase.timecapsule.GetMyTimeCapsuleUseCase import com.idiotfrogs.domain.usecase.user.GetMyProfileUseCase import com.idiotfrogs.domain.usecase.user.WithdrawUseCase -import com.idiotfrogs.model.timecapsule.MyTimeCapsuleResponse -import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus +import com.idiotfrogs.model.timecapsule.MyTimeCapsuleContent import com.idiotfrogs.model.user.ProfileResponse import com.idiotfrogs.util.base.BaseViewModel import com.idiotfrogs.util.base.DataUiState @@ -62,10 +61,7 @@ class ProfileViewModel @Inject constructor( state.copy( data = ProfileData( user = userResult.getOrNull(), - capsules = capsulesResult.getOrNull() - ?.flatMap { it.value } - ?.filter { it.timeCapsuleStatus == TimeCapsuleStatus.OPENED } - ?: emptyList(), + capsules = capsulesResult.getOrNull()?.flatMap { it.value } ?: emptyList(), ), isLoading = false, errorMessage = null, @@ -125,7 +121,7 @@ data class ProfileUiState( @Immutable data class ProfileData( val user: ProfileResponse? = null, - val capsules: List = emptyList() + val capsules: List = emptyList() ) sealed interface ProfileAction { From 13e8d7b4ad039ee769642da39a77de9cbc8fb6cc Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Wed, 9 Sep 2026 15:43:56 +0900 Subject: [PATCH 02/31] =?UTF-8?q?:sparkles:=20::=20=ED=99=88=20=EB=B9=88?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EC=9E=91=EC=97=85=20=EB=B0=8F=20=EC=98=A4?= =?UTF-8?q?=ED=94=88=EB=90=9C=20=ED=8B=B0=EC=BC=93=20=EC=84=A0=EC=9E=91?= =?UTF-8?q?=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/res/drawable/ic_home.png | Bin 0 -> 565 bytes .../src/main/res/drawable/ic_home_colored.png | Bin 0 -> 358 bytes .../main/res/drawable/ic_opened_ticket.png | Bin 0 -> 633 bytes .../res/drawable/ic_opened_ticket_colored.png | Bin 0 -> 437 bytes .../src/main/res/drawable/img_home_empty.png | Bin 2338 -> 3663 bytes .../res/drawable/img_home_empty_guide.png | Bin 0 -> 2516 bytes .../designsystem/component/MSDIm.kt | 3 +- .../designsystem/component/MSMenuFab.kt | 20 +- .../java/com/idiotfrogs/home/HomeScreen.kt | 265 ++++++------------ .../java/com/idiotfrogs/home/HomeViewModel.kt | 3 - .../home/component/HomeBottomBar.kt | 220 +++++++++++++++ .../home/component/HomeEmptyScreen.kt | 62 ++++ .../idiotfrogs/home/component/HomeHeader.kt | 6 +- .../home/component/HomeJoinContainer.kt | 1 - .../idiotfrogs/home/component/OpenedTicket.kt | 97 +++++++ 15 files changed, 487 insertions(+), 190 deletions(-) create mode 100644 common/resource/src/main/res/drawable/ic_home.png create mode 100644 common/resource/src/main/res/drawable/ic_home_colored.png create mode 100644 common/resource/src/main/res/drawable/ic_opened_ticket.png create mode 100644 common/resource/src/main/res/drawable/ic_opened_ticket_colored.png create mode 100644 common/resource/src/main/res/drawable/img_home_empty_guide.png create mode 100644 feature/home/src/main/java/com/idiotfrogs/home/component/HomeBottomBar.kt create mode 100644 feature/home/src/main/java/com/idiotfrogs/home/component/HomeEmptyScreen.kt create mode 100644 feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt diff --git a/common/resource/src/main/res/drawable/ic_home.png b/common/resource/src/main/res/drawable/ic_home.png new file mode 100644 index 0000000000000000000000000000000000000000..de1c83abbc5fb75dbc9e22e9afd976c980650d2b GIT binary patch literal 565 zcmV-50?Pe~P)L)!@`6SQ!6 zml51Rn81z@H>l4XzNbm7a;p_4MTr1A;02@f$HBQ+thl1Wg^ri4dhiqE*#<7qm=zN|K zo1Vtw@mib!)-yMeHdnsy_bUYq@(kpII&#w+BUe+1M8#Y=2ajwRlBVPY!-74}+MKZR zssxG&CC&syR_KmO_D8@}y#TpDr_;GT5)is-Q0uFvx6}g3X0zFR+5{9EBv*>|P;9Io z81*Yf3+NC_j;lPl6xI-5Qy^u75O+_NX=~_H^YhFc+}IZL?bk!a+`um0rL4#mZ?7iK z?fHBjAUr&|8jVID1=qn-kt9hB7lV=>31rFk#P6ldg$+BxQ!%v)5PZCFl0iQCU9#Mm z;h!>WCQ}(}gq~lT$@JI0lB8JF#11S!;00000NkvXXu0mjf Dqt@|3 literal 0 HcmV?d00001 diff --git a/common/resource/src/main/res/drawable/ic_home_colored.png b/common/resource/src/main/res/drawable/ic_home_colored.png new file mode 100644 index 0000000000000000000000000000000000000000..1bebf3be63bf845da469823567ccc1907f733e5c GIT binary patch literal 358 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9GG!XV7ZFl!D-1!HlL zyA#8@b22Z19F}xPUq=Rpjs4tz5?O(Kz7p4nlHmNblJdl&R0g-q^xVXG8>b}$WgdFE zIEGX(UY**@+hicnx?XRA-vZ?gjd^U!8yNEz`7Mxc5MCfW=lvo7TTEPEJid7AUHDS5 z-hO)Xi~EMj!ZUw%9A_+az0+&xe~ICcw9BDbqnV2Z6gId&u{q;gl)?9PmG?hCy`8~Z zR>s{7*%Y|jG3eB1OMT6I6K>2pW~}j%V|7ngZtyYfd?)8S3r!zfm{k^8&g0-xwdWTP z*QLdG8|zQ{SnNkl)FdPn3RRONWmS|^!oDj01AiGCZ0oD>B3lGldD6+gJd5EkW zSySS3nOO-8qArM@u=LdLNYpXwDf+f7MWC@*Ebh14Z4YFl5@dw0NlFozKo3S)mi3jC z$8nsNg|r+2N>rE4)Q38Yog}N=iQ@#26n$AE%gij%jp=YcpT8hFMwEzC?OeZqX4Lq` z7dtb^Nw^Qr8Nk%^=@ioE{I^USHpb$pTeM4gPEf1Wyuo0w=DK(ebhJLwZA0$DFl&ABxf*YS?AX&8K9`MzE zq9}C0Xgy8{djzfDc}CPcWDzTIHUkqVjSsS0Zm?Y@_%C&+CHgwPd#ie#{ttWul literal 0 HcmV?d00001 diff --git a/common/resource/src/main/res/drawable/ic_opened_ticket_colored.png b/common/resource/src/main/res/drawable/ic_opened_ticket_colored.png new file mode 100644 index 0000000000000000000000000000000000000000..34b49a1f88beaf5add57f29b2e9cf16ed4166fef GIT binary patch literal 437 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9GG!XV7ZFl!D-1!HlL zyA#8@b22Z19F}xPUq=Rpjs4tz5?O(Kz7p4nlHmNblJdl&R0g-q^xVXG8>b}$bs2cN zIEGX(o(+AQd&oe*cJV*`xeYlNaxU~;;GM<$f-R*b?}8Cy64MQZn+l0cdk%hFGeToU1ysBPlyUp#T;nk4s(Ua^G2rIBAuex+%@e93o*#iyFtR4J{@mu=RK z^P8{KH&$ovT9T*Br`B7Rz53%L&OCvl4WfbCd7u9)g?Q{O^C{B&f2mb2d=4A;YRk_y z%j8w~jlKHCvI}-BcYG`MD^|t&vB%|whE3+t1@03r%RZ3W6D)N_u{k8eneEw^qxU|zY?OcpZ0`+w*(vkiS0pgunBmJ%(TcJWH(@sfVTu}DgJ2> zvXD=|e*M}b;3a{v6eIgVtJV6IfR~I-ex6wb>cdzxHb#2(1K!vECg3H(<>h5h8IQZ& zE<#zJBG#j}cR?_Z5kD;v{XoFjZvq0fLlsS%eZU{o*dvR!%R%FifS1Ug_Ln^<5fKg= z9}@7A;MuchG5>y`JnJEp+TBPE$92!j6*@Q$%)5`W|+@g0F$Fl{~lVn5W3 z6i_|WqV*CFgCHW{9dNE|$h2s&{gB;(Z35mg5lxFXijz&iJ0_xCU0uCbo`)9~7rzkj ziiv2(?2qjicq}B~6%*0;Ff`=lFtlGlinxDF?`gj&&m*LW`^Q8ylswgk>6xY-(ZJ;Q zkW`aj(!&wy_Yd3TPt3MftMxwuUNK|x^S-7<`mscM#!T!{^V3L~eV|%qMB}J_!t7^b z1nG31F(aB5Yh)ph2zbRzL_~XmBO;#(c*R6Cli-uszdD`HF#)fz4Ut4v7LRT7EZisH z4Kt#ds?gYeiT676%JPUA(Zp9{fwb;(NE7#nM2-ksi(2Uud^L|qh^CqS+Fl2$V@5R7 zsVB5wy1BW*L8wP$N}=PKc8JzX{*W+4NNG1(0 zoT53xSvbY^0HfOIQlc#`oB!X2!{HX1!<5h5*yHBr<}M4Am~nCnu)e;I?5qmN6fhRy9L>%! z%PJs~Xs%{wS65fa@vnfax%{qXXEA}&$t0R1=7?rz6_HgmZSO)!Z$)GhjpLAiDZ@RK zKUG5}(ImH@l#mvi{AhMo0hx0|v=UzJ0$5NyizN1FAuTMC6_8mpsaw+=Y(z!MXQ322 zUJesxzN7asD3FCjb6Alu{Yz#c(MF?@oUhGTkrFuOV;ZC(l*mG&nPZs5!6<66%VpuT za6Y-#_O(4&k>#4V zyBwAht>5oUR3s6D>~uPR5Gb6vY2hx|Cli4Z`TSD$I~)#QBVD{Wmfq8NX3511-<0uf zo^crApt`vkr0=bimXy#D# zKzW3;@dC(gPa6yd;%IA?HAt_^ncPG(vBo2N98PxrR#`9lL*_>zh6snW64x%HhAlq|5lv>3)+~llRG$k)n*3_B7+i4va0(O6 zINFgtF5SinJcvS_YZfT6L`qI1`)&IKmZlKvaT>NHKa!RBV=T#+=*+qtg@>_Rej8ho zSSFXGaM4my5q4mdEJrB;V^=CdtJT8Zwgjb!CVrbEb-ahZT8mTK(M-47JtD;g;Mw*o zfrTjhJncjo3kfVlsiLvp7TaUIY=#6DqEyk?KTF(`&E|hdU?Iw09wTK8S;z}gs%R!2 znb_BGK)M*EC-(4ih$f#8q;%2x{r;c!m#uT0TMZq=sfPGa?y+nfUM&MK&ev=@kO*)8ACR*1206AZmh~MM04PUXs#=n z5!TZ2LNt?R7un;;*3$9D5OG{Ogac9qZ$xulI`sJQ<5vV`@Xh2uvIlqu!XUBmN;J(N zVaI#-?Cflhzyz;E({A?_q^1p)N&k9B%{0=77{D#NOtyXeovEjqgR`_0bH^HmwW!ZqsL**P>~c>j_PdNqQ|> ziVM)_69Df|u8j*2+v7aj8rwR)7U>4OkEyeb8cHohGkcrOc2grHwGho@Y{m9?yWMVN zXM{RsV@38rQ?1C_h^E~fMGdtgYa^OD*^ce;CeF56C9A?`yTjWkzYC83pHi}6OgtD2 zUN)tvb?wr^Z*FeX=zo*W+G;n`gr*lG*0KO2r5LdhcaYXnG*>Yq-L)cI`OK|aE{}qQ zuy|(uLzYp}gqt>MTc0MPXhumB5`bzu)9$&vygcODwL3kw>fOj|UkR!;l9Acg>2!`) z^+x;Ji{`r5MlNmOJ@4Zx3bzt9*QP^4tUL-=QMi>5&E%5&PKxhFD=1v;4UuW2U3?G( z5-rhAv?V_IdKHY5l@d*8f^aJ*n!s*A$Y#F?7b=fyFWgFsCS(w!+W73aN%PrVE|c zf2*#wZcS<(7%O9YlDbg0Xh~y4b2Lp8dM36CJHisMd#h@&{~U0>5!(M&>+>lC20 zK9kqi*PoQ(Fzss^E1DoNNjX;|hyTXH?X$sBXsFBdxU>nseEH(+DBD=;(S~Q$F7Gd{ z0uBi{zfD`R9)eZ{l$LOdYfB8>Zuf{%A}0JH9*HkS1)z0GH}|BfKSU613SKJZ!#i<3 zFKW3ozMBP0Tuk=DFvspbz&5Mmc2@wM7107P4m zc{KtLY(Vqb9^ly>+G7xH3FZj5BTd(q33stTiCHCkracDHmPCY0D;bsmGYhxSKF41Z zD`P!-45B>%-s4V;aiSt0_#*opABe`J6pGlh7NR{6Inr_EQX0ansS75a8QJ4@kQxEw zoS0L2nz^l^D<_j@^h=r9@@LGnoRB?EqVfFUs%;HROwXw+$0z@kS(?LkPjp{IqQKDIlqtR&M!$GtHNV$z_?0kzg=yC=4Sx*^`@AoqS zq7{U>jVe+e?T8P@;+<-K9E+{Z#F_XbL@N+iujPA;A9u<}I}<<5ktQBb{{^BIh>4oK zoA;g=E@@|ScF-826^tyC#tn#F?^tJYq4LVi*TT6j5tHF1DRJ^Ebi5|B%HG!^lVmgo zqE&$DbS_bk%xMbK1&>%BE5KCj$O%E5^=qbYufj|#0GUba>+4S?B`z(gbzZ#E<~~Ul zqFKlXE?H5MWFt8nCIvt~+^5=sq?7@(5fSt9B@v5len-k~x2K*T@$>g=Nk*>kd47Jr zFI71-2ML8qi(4Si=agFAb0BRs+64BC z7ECbTLw=0|!un?3;j zRduP#;*r)icXxhv4-XHGVHkef@AqHK>~++?yWQ^P`}gmk4}UL6jAlH$Ass!&uN6g% zGv#x~kb_=*HpOQ|0i!YBI))sjC5^;5_%G3npx@&&Vr6`p>KJjNA3uJ4jL(Uc@!1fK z2pZxuqJVM#_^V^aQDfNrPkcrcVCTc+gA^_^7zcjnm~qq?v3-iqhytP!QOaRRL?fc& z*NY;e5mE8$MG=j-JkI}QGn%TnV0yCD8TXxv!XKwttaz#2;-boGb3TiawcO4sEfH#EZ<{Z<1?aw z?39eUm?SJI%jozL0c3wss7zp-4IiTsK{_SFz{B8<8B;ySXG8%qW}_qr$~_|c7M~FX z$e4|i8Dr|lZ~&q*m%5k?d{%VKh*Iyr8t+hcjEK^bR!z(PhmIL1Qj3`Ykk7bO1z?cf zm2qh~BLKFTKg8!m0nvyk8AAZbY1GMNV0nvK1x*H7KI6ebd`1*74*uWKjH#5zkjQ3? zsbSYYFdYS2Me;h2I zF)n>VMm0zd=0)ZdV|l22Fh@&TCFrZNnpADB zWJb+Qx0$Q)+0ZfKe^O3E0LW>y*RTMp&8nL*0QMW51z-Tw&eYLlAY(R)jM*qMW}|5H z-zb(On!3?UBFkg+#tagc^k-C(Az{hE4BccVVMz->SN}*vBckHhiy|y}F@yRsBuq=$ zHjyzKMaFED%oyD;BQXyCQ#2z;CuJC9B^mYnN$mB$%xwbnW0cFVuq4S;y^Mq@0N5r9 z05*!{pZcfvG6Nt0(DgqSKKLC&jvCGTBR(Svu%wgO%=r?Z6DyMi026(U&x#cR&X*mf zJDSBgzcV||EI3TS6%^Ctg z%UMY#3rn(p)63>KAc>}_0>HuYS)(9;fhBLxFfC^sTId|jh|)1y2Bzg~oA`|Am~kR4 zX9SQ+fC`%=EN?aI@Hqn{r%{Q9geA+FDG1=8!sbRnmNU~$XAYLXs|fU`zr8U_Z; z8of`GKx?91jL>x3nM8JyMu*NxSbhy%ISqqs#^^i%3Cn9|>d`Q;0L3~!Mi~%(>H%E1|V!&B*&{sujg%~z#4${(A z1yX5_=4j>=VZedFAice*ima#^qz-2#Ef^R&M)ah6HI=kICrv&TLX)th`fQpp94rZ= zRjwgn$zG#;hD04v)^bL|XGJt)Djh^80pvEiSjzxe&eYi? zVaal4>eFzrBy`q3L&B13fbMRR0QMQ>GYr62IqKXQ15>YNn*jNY%wd4M%5h@OAMtsy zB9=sF6TRw0O)-|_G!vep$W`5 zxFK^YnVH|noJuTzLEY3GC7+d`OPb6nW=04tbE=sULd%?Lyhb+DoKNw4h?SUWjtZWY z%rr*@&r0T)Q?aD^ogV)s@c*aXZujC>7w>kqqUNl91ge?RON8(D1xBDbt5%{f{rtPW zPU1^d9FVBBmNVd#&wYQ0o)180P^MZX2xv1l{;U(NIa@ama?)n4S!4bE<*2)Uff2Bz zxK_z)EN_ReGFz_(V1QN`Bm++PtTkJ&0wf4%TC^n%_Kg<*g}5p#|G1Pl?H6vW8F2J! zjb-#|m{W!J41KA=0%z-ezm5eQq=SZ~%&}yTTe|{r6&SD~PvrZ%L9TmLYq;egZ3@)0MDAVDu4zS z3IssF?k8lC(dBt9+8=YQ~_kn3}!@D7e62ZSQgVLPXxg5`Az3$jwO4{ zB~!&2=2oNk;SP?Lu@#wV&Pk~SSPqBj&k{3f=0Jx!e6SCtmhsQeoxh(-#mptJyf}F@ z$M+5cZdhw6TL{Bv4yvd4GsHWXQEGvulFUN1XzOA&KSw&0u^;kn)6`7|6Ba}o^C&vX;Bv1Lz$zuNX|Q({xdwJM#J1m4&-L_ zX7zpKGLb`GV)$>c58m^^gqsd$w}KC{54I2bVcD6^0+tE?0W2D92g0c@#Q*>R07*qo IM6N<$f;bO5WB>pF diff --git a/common/resource/src/main/res/drawable/img_home_empty_guide.png b/common/resource/src/main/res/drawable/img_home_empty_guide.png new file mode 100644 index 0000000000000000000000000000000000000000..59f67bd14cb049be9242554994e72a6193827c95 GIT binary patch literal 2516 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 literal 0 HcmV?d00001 diff --git a/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSDIm.kt b/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSDIm.kt index 16dc0dbf..e435925a 100644 --- a/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSDIm.kt +++ b/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSDIm.kt @@ -18,6 +18,7 @@ import com.idiotfrogs.designsystem.util.noRippleClickable @Composable fun MSDim( + modifier: Modifier = Modifier, visible: Boolean, onDismiss: () -> Unit, color: Color = Color(0x3D444444), @@ -31,7 +32,7 @@ fun MSDim( if (alpha > 0f) { Box( - Modifier + modifier .fillMaxSize() .background(color.copy(alpha = color.alpha * alpha)) .noRippleClickable( diff --git a/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSMenuFab.kt b/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSMenuFab.kt index 170296e3..213286db 100644 --- a/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSMenuFab.kt +++ b/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSMenuFab.kt @@ -1,6 +1,8 @@ package com.idiotfrogs.designsystem.component import android.annotation.SuppressLint +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -29,6 +31,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight @@ -99,10 +102,16 @@ fun MSMenuFab( } } if (hasFab) { + val iconRotation by animateFloatAsState( + targetValue = if (expanded) 45f else 0f, + animationSpec = tween(200), + label = "fab icon rotation" + ) + FloatingActionButton( modifier = Modifier .wavyStroke( - color = Color(0xFF29A047), + color = MSTheme.color.greyG5, strokeWidth = 4.dp, cornerRadius = 28.dp, amplitude = 1.dp, @@ -111,7 +120,7 @@ fun MSMenuFab( .size(56.dp) .padding(2.dp), shape = CircleShape, - containerColor = MSTheme.color.primaryNormal, + containerColor = MSTheme.color.greyG5, elevation = FloatingActionButtonDefaults.elevation( defaultElevation = 4.dp, pressedElevation = 4.dp, @@ -124,11 +133,10 @@ fun MSMenuFab( Image( modifier = Modifier .size(24.dp) - .graphicsLayer { - rotationZ = if (expanded) 45f else 0f - }, + .graphicsLayer { rotationZ = iconRotation }, painter = painterResource(imageRes), - contentDescription = "fab content" + contentDescription = "fab content", + colorFilter = ColorFilter.tint(MSTheme.color.white) ) } } diff --git a/feature/home/src/main/java/com/idiotfrogs/home/HomeScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/HomeScreen.kt index 1e363c10..a66b5846 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/HomeScreen.kt @@ -1,30 +1,20 @@ package com.idiotfrogs.home -import androidx.compose.animation.core.tween -import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.ime -import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.systemBarsPadding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.text.input.rememberTextFieldState import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.pulltorefresh.PullToRefreshBox -import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf @@ -35,65 +25,45 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp -import androidx.compose.ui.zIndex import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import com.idiotfrogs.designsystem.component.MSDim import com.idiotfrogs.designsystem.component.MSLoadingOverlay -import com.idiotfrogs.designsystem.component.MSMenuFab -import com.idiotfrogs.designsystem.component.MSTabBar -import com.idiotfrogs.designsystem.component.MSText -import com.idiotfrogs.designsystem.component.MSToast import com.idiotfrogs.designsystem.model.MSMenuFabModel import com.idiotfrogs.designsystem.theme.MSTheme import com.idiotfrogs.designsystem.util.DevicePreview -import com.idiotfrogs.designsystem.util.noRippleClickable import com.idiotfrogs.home.component.HomeHeader import com.idiotfrogs.home.component.HomeJoinContainer -import com.idiotfrogs.home.component.HomeTicket -import com.idiotfrogs.model.timecapsule.TimeCapsuleRole import com.idiotfrogs.navigation.LocalComposeMSNavigator import com.idiotfrogs.navigation.Routes -import com.idiotfrogs.extension.toYearMonthDay -import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus -import com.idiotfrogs.resource.R -import dev.chrisbanes.haze.hazeSource -import dev.chrisbanes.haze.rememberHazeState -import kotlinx.coroutines.delay +import com.idiotfrogs.home.component.BottomMenu +import com.idiotfrogs.home.component.HomeBottomBar +import com.idiotfrogs.home.component.HomeEmptyScreen +import com.idiotfrogs.home.component.OpenedTicket import org.orbitmvi.orbit.compose.collectAsState import org.orbitmvi.orbit.compose.collectSideEffect +private val TOP_BAR_SIZE = 56.dp +private val BOTTOM_BAR_SIZE = 80.dp + @Composable fun HomeRoute( viewModel: HomeViewModel = hiltViewModel() ) { val navigator = LocalComposeMSNavigator.current val uiState by viewModel.collectAsState() - var showToast by remember { mutableStateOf(false) } - - LaunchedEffect(showToast) { - if (!showToast) return@LaunchedEffect - delay(2000L) - showToast = false - } viewModel.collectSideEffect { when (it) { HomeSideEffect.NavigateToCreate -> navigator.navigate(Routes.Create) HomeSideEffect.NavigateToProfile -> navigator.navigate(Routes.Profile) is HomeSideEffect.NavigateToDetail -> navigator.navigate(Routes.Detail(it.id)) - HomeSideEffect.ShowToast -> showToast = true } } Box(modifier = Modifier.fillMaxSize()) { uiState.data?.let { data -> HomeScreen( - showToast = showToast, data = data, isRefreshing = uiState.isLoading, onAction = viewModel::onAction @@ -107,29 +77,24 @@ fun HomeRoute( @OptIn(ExperimentalMaterial3Api::class) @Composable fun HomeScreen( - showToast: Boolean, data: HomeData, isRefreshing: Boolean, onAction: (HomeAction) -> Unit, ) { - val hazeState = rememberHazeState() var expanded by remember { mutableStateOf(false) } - var currentTab by remember { mutableStateOf(HomeTab.CREATED) } var showJoinContainer by remember { mutableStateOf(false) } + val ime = WindowInsets.ime val density = LocalDensity.current val imeHeight by remember { derivedStateOf { ime.getBottom(density) } } - - val showDim by remember { - derivedStateOf { expanded || showJoinContainer } - } + val showDim by remember { derivedStateOf { expanded || showJoinContainer } } val menuList by remember { mutableStateOf( listOf( MSMenuFabModel("새 티켓 생성하기") { expanded = false - onAction(HomeAction.CreateClicked) + onAction.invoke(HomeAction.CreateClicked) }, MSMenuFabModel("참여코드로 합류하기") { expanded = false @@ -140,6 +105,7 @@ fun HomeScreen( } val textFieldState = rememberTextFieldState() + val pagerState = rememberPagerState(initialPage = 0) { BottomMenu.entries.size } LaunchedEffect(imeHeight) { if (showJoinContainer && imeHeight == 0) { @@ -148,151 +114,95 @@ fun HomeScreen( } } - val pagerState = rememberPagerState { HomeTab.entries.size } + var selectedMenu by remember { mutableStateOf(BottomMenu.HOME) } - LaunchedEffect(currentTab) { - pagerState.animateScrollToPage( - page = currentTab.ordinal, - animationSpec = tween() - ) - } - - LaunchedEffect(pagerState.currentPage) { - currentTab = HomeTab.entries[pagerState.currentPage] + LaunchedEffect(selectedMenu) { + pagerState.animateScrollToPage(selectedMenu.ordinal) } - Box { - if (showToast) { - MSToast( - modifier = Modifier - .padding(horizontal = 20.dp) - .align(Alignment.BottomCenter) - .systemBarsPadding() - .zIndex(1f), - hazeState = hazeState, - ) { - Image( - painter = painterResource(R.drawable.img_friend_accept), - contentDescription = "알림", - modifier = Modifier.size(24.dp) - ) - Spacer(Modifier.width(8.dp)) - MSText( - text = "타임 캡슐 참여 요청이 완료되었어요.", - color = MSTheme.color.white - ) - } - } - - val lazyListState = rememberLazyListState() - val showBorder by remember { - derivedStateOf { - lazyListState.firstVisibleItemScrollOffset > 0 || // 1px이라도 움직였거나 - lazyListState.firstVisibleItemIndex > 0 // 첫 번째 아이템을 넘어간 경우 - } - } - - Column( - modifier = Modifier - .fillMaxSize() - .background(MSTheme.color.bgNormal) - .systemBarsPadding() - .hazeSource(hazeState) - ) { - HomeHeader( - profileUrl = data.user?.profileImageUrl, - navigateToProfile = { onAction(HomeAction.ProfileClicked) } - ) - MSTabBar( - showBorder = showBorder, - tabs = HomeTab.entries.map { it.title }, - selectedIndex = currentTab.ordinal, - onClick = { currentTab = HomeTab.entries[it] }, - ) - if (data.capsules.isEmpty()) { - Column( - modifier = Modifier - .fillMaxSize() - .padding(bottom = 90.dp), - verticalArrangement = Arrangement.spacedBy(32.dp, alignment = Alignment.Bottom) - ) { - MSText( - modifier = Modifier - .align(Alignment.CenterHorizontally) - .padding(end = 15.dp), - text = "생성된 티켓이 없습니다\n버튼을 눌러서 티켓을 추가해 보세요", - fontSize = 14.dp, - fontWeight = FontWeight.Normal, - color = MSTheme.color.greyG4, - textAlign = TextAlign.Center - ) - Image( - modifier = Modifier - .align(Alignment.End) - .padding(end = 107.dp) - .size(width = 92.dp, height = 246.dp), - painter = painterResource(R.drawable.img_home_empty), - contentDescription = "empty_home" + Box( + modifier = Modifier + .fillMaxSize() + .background(MSTheme.color.white) + .systemBarsPadding() + ) { + HomeHeader( + selectedMenu = selectedMenu, + profileUrl = data.user?.profileImageUrl, + navigateToProfile = { onAction.invoke(HomeAction.ProfileClicked) } + ) + HorizontalPager( + state = pagerState, + userScrollEnabled = false + ) { page -> + when (page) { + BottomMenu.HOME.ordinal -> { + HomeEmptyScreen( + modifier = Modifier.padding(top = TOP_BAR_SIZE, bottom = BOTTOM_BAR_SIZE), + selectedMenu = BottomMenu.HOME ) } - } else { - HorizontalPager( - state = pagerState, - ) { page -> - val tab = HomeTab.entries[page] - val role = when (tab) { - HomeTab.CREATED -> TimeCapsuleRole.HOST - HomeTab.JOINED -> TimeCapsuleRole.CONTRIBUTOR - } - val data = data.capsules[role].orEmpty() - val refreshState = rememberPullToRefreshState() - PullToRefreshBox( - isRefreshing = isRefreshing, - state = refreshState, - onRefresh = { onAction.invoke(HomeAction.Refresh) } + BottomMenu.OPENED.ordinal -> { + LazyVerticalGrid( + modifier = Modifier.padding(top = TOP_BAR_SIZE, start = 20.dp, end = 20.dp), + columns = GridCells.Fixed(2), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalArrangement = Arrangement.spacedBy(24.dp), + contentPadding = PaddingValues(top = 20.dp, bottom = BOTTOM_BAR_SIZE) ) { - LazyColumn( - state = lazyListState, - modifier = Modifier.fillMaxSize(), - contentPadding = PaddingValues(top = 24.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(16.dp), - ) { - items(data) { - HomeTicket( - modifier = Modifier.noRippleClickable { - onAction(HomeAction.TimeCapsuleClicked(it.timeCapsuleId)) - }, - buried = it.timeCapsuleStatus == TimeCapsuleStatus.BURIED, - createdAt = it.createdAt.toYearMonthDay(), - title = it.title, - imageUrl = it.mainImageUrl, - step = it.stage - ) - } + items(10) { + OpenedTicket() } } } } } +// PullToRefreshBox( +// isRefreshing = isRefreshing, +// state = refreshState, +// onRefresh = { onAction.invoke(HomeAction.Refresh) } +// ) { +// LazyColumn( +// state = lazyListState, +// modifier = Modifier.fillMaxSize(), +// contentPadding = PaddingValues(top = 24.dp), +// horizontalAlignment = Alignment.CenterHorizontally, +// verticalArrangement = Arrangement.spacedBy(16.dp), +// ) { +// items(data) { +// HomeTicket( +// modifier = Modifier.noRippleClickable { +// onAction(HomeAction.TimeCapsuleClicked(it.timeCapsuleId)) +// }, +// buried = it.timeCapsuleStatus == TimeCapsuleStatus.BURIED, +// createdAt = it.createdAt.toYearMonthDay(), +// title = it.title, +// imageUrl = it.mainImageUrl, +// step = it.stage +// ) +// } +// } +// } + + + fun onDimClick() { + expanded = false; showJoinContainer = false + } + MSDim( + modifier = Modifier.padding(bottom = 80.dp), // 하단바 영역 침범 x visible = showDim, - onDismiss = { - expanded = false - showJoinContainer = false - } + onDismiss = { onDimClick() } ) - MSMenuFab( - modifier = Modifier - .align(Alignment.BottomEnd) - .navigationBarsPadding() - .padding(end = 20.dp, bottom = 24.dp), + HomeBottomBar( + modifier = Modifier.align(Alignment.BottomCenter), + selectedMenu = selectedMenu, + showDim = showDim, + fabMenuList = menuList, expanded = expanded, - hasFab = true, - offset = DpOffset(x = 0.dp, y = (-16).dp), - menuList = menuList, - onClick = { expanded = !expanded }, - onDismiss = { expanded = false }, + onSelectChange = { selectedMenu = it }, + onExpandChange = { expanded = it }, + onClickDim = { onDimClick() } ) HomeJoinContainer( isShow = showJoinContainer, @@ -307,7 +217,6 @@ fun HomeScreen( @Composable fun HomeScreenPreview() { HomeScreen( - showToast = false, data = HomeData(), isRefreshing = false, onAction = {}, diff --git a/feature/home/src/main/java/com/idiotfrogs/home/HomeViewModel.kt b/feature/home/src/main/java/com/idiotfrogs/home/HomeViewModel.kt index b7b8c420..0ee03c98 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/HomeViewModel.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/HomeViewModel.kt @@ -86,7 +86,6 @@ class HomeViewModel @Inject constructor( requestCollaboratorUseCase(body).onSuccess { intent { reduce { state.copy(isLoading = false, errorMessage = null) } - postSideEffect(HomeSideEffect.ShowToast) fetchHome() } }.onFailure { @@ -133,6 +132,4 @@ sealed interface HomeSideEffect { data object NavigateToCreate : HomeSideEffect data object NavigateToProfile : HomeSideEffect data class NavigateToDetail(val id: Long) : HomeSideEffect - - data object ShowToast : HomeSideEffect } diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeBottomBar.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeBottomBar.kt new file mode 100644 index 00000000..ff419a0c --- /dev/null +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeBottomBar.kt @@ -0,0 +1,220 @@ +package com.idiotfrogs.home.component + +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.animateDpAsState +import androidx.compose.animation.core.spring +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.DpOffset +import androidx.compose.ui.unit.dp +import com.idiotfrogs.designsystem.component.MSDim +import com.idiotfrogs.designsystem.component.MSMenuFab +import com.idiotfrogs.designsystem.component.MSText +import com.idiotfrogs.designsystem.model.MSMenuFabModel +import com.idiotfrogs.designsystem.theme.MSTheme +import com.idiotfrogs.designsystem.util.noRippleClickable +import com.idiotfrogs.designsystem.util.wavyStroke +import com.idiotfrogs.resource.R + +enum class BottomMenu { HOME, OPENED } + +@Composable +fun HomeBottomBar( + modifier: Modifier = Modifier, + expanded: Boolean, + showDim: Boolean, + fabMenuList: List, + selectedMenu: BottomMenu, + onSelectChange: (BottomMenu) -> Unit, + onExpandChange: (Boolean) -> Unit, + onClickDim: () -> Unit, +) { + Box( + modifier = modifier + .fillMaxWidth() + .height(80.dp) + ) { + Row( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 20.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + BoxWithConstraints( + modifier = Modifier + .weight(1f) + .height(56.dp) + .wavyStroke( + color = MSTheme.color.greyG5, + cornerRadius = 54.dp, + fillColor = MSTheme.color.white, + amplitude = (0.5).dp, + spacing = 2.dp + ) + ) { + val itemWidth = maxWidth / BottomMenu.entries.size + val indicatorOffset by animateDpAsState( + targetValue = itemWidth * (BottomMenu.entries.find { it == selectedMenu }?.ordinal ?: 0), + animationSpec = spring( + dampingRatio = Spring.DampingRatioLowBouncy, + stiffness = Spring.StiffnessMediumLow + ), + label = "indicatorOffset" + ) + + Box( + modifier = Modifier + .width(itemWidth) + .offset(x = indicatorOffset) + .fillMaxHeight() + .wavyStroke( + color = MSTheme.color.greyG5, + cornerRadius = 54.dp, + fillColor = MSTheme.color.greyG5, + amplitude = (0.7).dp, + spacing = 2.dp, + ) + ) + Row(modifier = Modifier.fillMaxWidth()) { + Column( + modifier = Modifier + .weight(1f) + .fillMaxHeight() + .noRippleClickable(onClick = { onSelectChange.invoke(BottomMenu.HOME) }), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Image( + modifier = Modifier.size(24.dp), + painter = painterResource( + if (selectedMenu == BottomMenu.HOME) { + R.drawable.ic_home_colored + } else { + R.drawable.ic_home + } + ), + contentDescription = "ic_home" + ) + Spacer(modifier = Modifier.height(2.dp)) + MSText( + text = "홈", + color = if (selectedMenu == BottomMenu.HOME) { + MSTheme.color.white + } else { + MSTheme.color.greyG3 + }, + fontWeight = if (selectedMenu == BottomMenu.HOME) { + FontWeight.SemiBold + } else { + FontWeight.Medium + }, + fontSize = 10.dp + ) + } + Column( + modifier = Modifier + .weight(1f) + .fillMaxHeight() + .noRippleClickable(onClick = { onSelectChange.invoke(BottomMenu.OPENED) }), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Image( + modifier = Modifier.size(24.dp), + painter = painterResource( + if (selectedMenu == BottomMenu.OPENED) { + R.drawable.ic_opened_ticket_colored + } else { + R.drawable.ic_opened_ticket + } + ), + contentDescription = "ic_home" + ) + Spacer(modifier = Modifier.height(2.dp)) + MSText( + text = "오픈된 티켓", + color = if (selectedMenu == BottomMenu.OPENED) { + MSTheme.color.white + } else { + MSTheme.color.greyG3 + }, + fontWeight = if (selectedMenu == BottomMenu.OPENED) { + FontWeight.SemiBold + } else { + FontWeight.Medium + }, + fontSize = 10.dp + ) + } + } + } + // 실제 FAB 는 딤 위에 그리므로 여기서는 자리만 잡아둔다 + Spacer(modifier = Modifier.size(56.dp)) + } + // 하단바 영역 전체를 딤으로 덮고 FAB 만 그 위로 올려 딤에서 제외한다 + MSDim( + visible = showDim, + onDismiss = onClickDim + ) + MSMenuFab( + modifier = Modifier + .align(Alignment.CenterEnd) + .padding(end = 20.dp), + expanded = expanded, + hasFab = true, + offset = DpOffset(x = 0.dp, y = (-16).dp), + menuList = fabMenuList, + onClick = { onExpandChange.invoke(!expanded) }, + onDismiss = { onExpandChange.invoke(false) }, + ) + } +} + +@Preview(showBackground = true) +@Composable +private fun HomeBottomBarPreview() { + var showDim by remember { mutableStateOf(false) } + var expanded by remember { mutableStateOf(false) } + var selectedMenu by remember { mutableStateOf(BottomMenu.HOME) } + val menuList by remember { + mutableStateOf( + listOf( + MSMenuFabModel("새 티켓 생성하기") { expanded = false }, + MSMenuFabModel("참여코드로 합류하기") { expanded = false }, + ) + ) + } + HomeBottomBar( + fabMenuList = menuList, + showDim = showDim, + expanded = expanded, + selectedMenu = selectedMenu, + onSelectChange = { selectedMenu = it }, + onExpandChange = { expanded = it }, + onClickDim = { } + ) +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeEmptyScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeEmptyScreen.kt new file mode 100644 index 00000000..3b98ebb2 --- /dev/null +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeEmptyScreen.kt @@ -0,0 +1,62 @@ +package com.idiotfrogs.home.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.paint +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.idiotfrogs.designsystem.component.MSText +import com.idiotfrogs.designsystem.theme.MSTheme +import com.idiotfrogs.resource.R + +@Composable +fun HomeEmptyScreen( + modifier: Modifier = Modifier, + selectedMenu: BottomMenu, +) { + Column( + modifier = modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(30.dp, alignment = Alignment.Bottom) + ) { + Box( + modifier = Modifier.paint( + painter = painterResource(R.drawable.img_home_empty_guide), + contentScale = ContentScale.Crop + ), + contentAlignment = Alignment.Center + ) { + MSText( + modifier = Modifier.padding(horizontal = 20.dp, vertical = 10.dp), + text = (if (selectedMenu == BottomMenu.HOME) "생성한 티켓" else "오픈된 티켓") + + "이 없습니다\n버튼을 눌러서 티켓을 추가해 보세요", + fontSize = 16.dp, + fontWeight = FontWeight.Normal, + color = MSTheme.color.greyG4, + textAlign = TextAlign.Center + ) + } + Image( + modifier = Modifier + .align(Alignment.End) + .padding(end = 79.dp) + .size(width = 102.dp, height = 239.dp), + painter = painterResource(R.drawable.img_home_empty), + contentDescription = "empty_home" + ) + Spacer(modifier = Modifier.height(29.dp)) + } +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeHeader.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeHeader.kt index 464c738f..e1075143 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeHeader.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeHeader.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.idiotfrogs.designsystem.component.MSText @@ -23,6 +24,7 @@ import com.skydoves.landscapist.glide.GlideImage @Composable fun HomeHeader( + selectedMenu: BottomMenu, profileUrl: String?, navigateToProfile: () -> Unit, ) { @@ -33,8 +35,9 @@ fun HomeHeader( verticalAlignment = Alignment.CenterVertically ) { MSText( - text = "타임 티켓", + text = if (selectedMenu == BottomMenu.HOME) "홈" else "오픈된 티켓", fontSize = 24.dp, + fontWeight = FontWeight.Bold, color = MSTheme.color.greyG5 ) Spacer(modifier = Modifier.weight(1f)) @@ -70,6 +73,7 @@ fun HomeHeader( @Composable private fun HomeHeaderPreview() { HomeHeader( + selectedMenu = BottomMenu.HOME, profileUrl = "", navigateToProfile = {}, ) diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeJoinContainer.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeJoinContainer.kt index 39add033..80d76f47 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeJoinContainer.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeJoinContainer.kt @@ -15,7 +15,6 @@ import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.tooling.preview.Preview import com.idiotfrogs.designsystem.component.MSActionContainer import com.idiotfrogs.designsystem.theme.MSTheme -import com.idiotfrogs.resource.R @Composable fun BoxScope.HomeJoinContainer( diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt new file mode 100644 index 00000000..5ef9c8a0 --- /dev/null +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt @@ -0,0 +1,97 @@ +package com.idiotfrogs.home.component + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithCache +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.graphics.BlendMode +import androidx.compose.ui.graphics.CompositingStrategy +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.res.imageResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.dp +import com.idiotfrogs.designsystem.component.MSText +import com.idiotfrogs.designsystem.theme.MSTheme +import com.idiotfrogs.designsystem.util.wavyStroke +import com.idiotfrogs.resource.R +import com.skydoves.landscapist.glide.GlideImage + +@Composable +fun OpenedTicket() { + Column( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + ) { + Box( + modifier = Modifier + .rotate(10f) + .wavyStroke( + color = MSTheme.color.greyG5, + fillColor = MSTheme.color.white + ) + .fillMaxWidth() + .height(40.dp) + ) + Box( + modifier = Modifier + .wavyStroke( + color = MSTheme.color.greyG5, + fillColor = MSTheme.color.white + ) + .fillMaxWidth() + .aspectRatio(1f) + ) { + val mask = ImageBitmap.imageResource(id = R.drawable.img_mask_main) + GlideImage( + modifier = Modifier + .graphicsLayer { compositingStrategy = CompositingStrategy.Offscreen } + .fillMaxSize() + .padding(12.dp) + .drawWithCache { + onDrawWithContent { + drawContent() + drawImage( + image = mask, + dstSize = IntSize(size.width.toInt(), size.height.toInt()), + blendMode = BlendMode.DstIn + ) + } + }, + imageModel = { R.drawable.img_sample } + ) + } + Spacer(modifier = Modifier.height(12.dp)) + MSText( + text = "제목입니다. 제목입니다.", + fontWeight = FontWeight.Bold, + fontSize = 16.dp, + color = MSTheme.color.greyG5 + ) + Spacer(modifier = Modifier.height(8.dp)) + MSText( + text = "2027. 10. 24 ~ 2027. 10. 24 ", + fontWeight = FontWeight.Normal, + fontSize = 12.dp, + color = MSTheme.color.greyG5.copy(alpha = 0.6f) + ) + } +} + +@Preview(widthDp = 160, heightDp = 286) +@Composable +fun OpenedTicketPreview() { + OpenedTicket() +} \ No newline at end of file From c8b3e8783b8fc86daa48cb2033075208a4109350 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Wed, 9 Sep 2026 17:18:23 +0900 Subject: [PATCH 03/31] =?UTF-8?q?:sparkles:=20::=20=ED=99=88=20=ED=8B=B0?= =?UTF-8?q?=EC=BC=93=20=EC=A4=91=EA=B0=84=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/idiotfrogs/home/HomeScreen.kt | 55 +++-- .../idiotfrogs/home/component/HomeTicket.kt | 221 +++++++----------- 2 files changed, 130 insertions(+), 146 deletions(-) diff --git a/feature/home/src/main/java/com/idiotfrogs/home/HomeScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/HomeScreen.kt index a66b5846..7d18c8ff 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/HomeScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.itemsIndexed import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.text.input.rememberTextFieldState @@ -39,6 +40,7 @@ import com.idiotfrogs.navigation.Routes import com.idiotfrogs.home.component.BottomMenu import com.idiotfrogs.home.component.HomeBottomBar import com.idiotfrogs.home.component.HomeEmptyScreen +import com.idiotfrogs.home.component.HomeTicket import com.idiotfrogs.home.component.OpenedTicket import org.orbitmvi.orbit.compose.collectAsState import org.orbitmvi.orbit.compose.collectSideEffect @@ -137,21 +139,48 @@ fun HomeScreen( ) { page -> when (page) { BottomMenu.HOME.ordinal -> { - HomeEmptyScreen( - modifier = Modifier.padding(top = TOP_BAR_SIZE, bottom = BOTTOM_BAR_SIZE), - selectedMenu = BottomMenu.HOME - ) + if (false) { + HomeEmptyScreen( + modifier = Modifier.padding(top = TOP_BAR_SIZE, bottom = BOTTOM_BAR_SIZE), + selectedMenu = BottomMenu.HOME + ) + } else { + LazyVerticalGrid( + modifier = Modifier.padding(top = TOP_BAR_SIZE), + columns = GridCells.Fixed(2) + ) { + itemsIndexed(listOf(1,1,1,1,1,1)) { index, item -> + val isLeft = index % 2 == 0 + val isLastRow = index / 2 == 2 // 추후 하드코딩에서 변경 + HomeTicket( + modifier = Modifier.padding( + start = if (isLeft) 20.dp else 8.dp, + end = if (isLeft) 8.dp else 20.dp, + bottom = if (isLastRow) 0.dp else 16.dp + ), + buried = index / 2 == 0 + ) + } + } + } } BottomMenu.OPENED.ordinal -> { - LazyVerticalGrid( - modifier = Modifier.padding(top = TOP_BAR_SIZE, start = 20.dp, end = 20.dp), - columns = GridCells.Fixed(2), - horizontalArrangement = Arrangement.spacedBy(16.dp), - verticalArrangement = Arrangement.spacedBy(24.dp), - contentPadding = PaddingValues(top = 20.dp, bottom = BOTTOM_BAR_SIZE) - ) { - items(10) { - OpenedTicket() + if (false) { + HomeEmptyScreen( + modifier = Modifier.padding(top = TOP_BAR_SIZE, bottom = BOTTOM_BAR_SIZE), + selectedMenu = BottomMenu.OPENED + ) + } else { + LazyVerticalGrid( + modifier = Modifier.padding(top = TOP_BAR_SIZE, start = 20.dp, end = 20.dp), + columns = GridCells.Fixed(2), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalArrangement = Arrangement.spacedBy(24.dp), + contentPadding = PaddingValues(top = 20.dp, bottom = BOTTOM_BAR_SIZE) + ) { + items(10) { + OpenedTicket() + } } } } diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt index 3bce2960..744233a0 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt @@ -14,18 +14,16 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawWithCache import androidx.compose.ui.graphics.BlendMode -import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.CompositingStrategy import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.imageResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight @@ -49,145 +47,102 @@ enum class GuideItem(val imgRes: Int, val width: Dp, val height: Dp) { @Composable fun HomeTicket( - buried: Boolean, - createdAt: String, - title: String, - imageUrl: String?, - step: Int, modifier: Modifier = Modifier, + buried: Boolean, +// createdAt: String, +// title: String, +// imageUrl: String?, +// step: Int, ) { - Box(modifier = modifier) { - Column { - Box( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 20.dp) - .zIndex(1f) - .wavyStroke( - color = MSTheme.color.greyG5, - cornerRadius = 16.dp, - strokeWidth = 4.dp, - amplitude = 1.dp, - spacing = 3.dp, - fillColor = MSTheme.color.primaryNormal - ) - ) { - Column( + Column( + modifier = modifier + .fillMaxWidth() + .wrapContentHeight() + ) { + Box( + modifier = Modifier + .zIndex(1f) + .wavyStroke( + color = MSTheme.color.greyG5, + fillColor = MSTheme.color.primaryNormal, + amplitude = (1.5).dp, + spacing = 4.dp, + ) + .fillMaxWidth() + .height(55.dp), + contentAlignment = Alignment.CenterStart + ) { + if (buried) { + Row( modifier = Modifier - .padding(20.dp) - .fillMaxWidth() + .padding(start = 12.dp) + .background( + color = MSTheme.color.primaryLight.copy(alpha = 0.6f), + shape = RoundedCornerShape(8.dp) + ) + .padding(start = 6.dp, end = 8.dp, top = 4.dp, bottom = 4.dp), + horizontalArrangement = Arrangement.spacedBy(1.dp), + verticalAlignment = Alignment.CenterVertically ) { - if (buried) { - Row( - modifier = Modifier - .background( - color = MSTheme.color.primaryLight.copy(0.6f), - shape = RoundedCornerShape(12.dp) - ) - .padding(6.dp), - horizontalArrangement = Arrangement.spacedBy(4.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Image( - modifier = Modifier.size(16.dp), - painter = painterResource(R.drawable.ic_shovels), - contentDescription = "buried", - colorFilter = ColorFilter.tint(MSTheme.color.greyG5) - ) - MSText( - text = "묻어짐", - fontWeight = FontWeight.SemiBold, - fontSize = 12.dp, - color = MSTheme.color.greyG5 - ) - } - Spacer(modifier = Modifier.height(12.dp)) - } - MSText( - text = title, - fontSize = 20.dp, - fontWeight = FontWeight.Bold, - color = MSTheme.color.greyG5 + Image( + modifier = Modifier.size(16.dp), + painter = painterResource(R.drawable.ic_shovels), + contentDescription = "ic_shovels" ) - Spacer(modifier = Modifier.height(8.dp)) MSText( - text = createdAt, - fontWeight = FontWeight.Normal, - fontSize = 14.dp, - color = MSTheme.color.greyG4 - ) - } - } - val mask = ImageBitmap.imageResource(id = R.drawable.img_mask_main) - Box( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 20.dp) - .offset(y = (-10).dp) - .wavyStroke( - color = MSTheme.color.greyG5, - cornerRadius = 16.dp, - strokeWidth = 4.dp, - amplitude = (1.5).dp, - spacing = 4.dp, - fillColor = MSTheme.color.white - ) - .aspectRatio(1f) - ) { - imageUrl?.let { - GlideImage( - modifier = Modifier - .graphicsLayer { compositingStrategy = CompositingStrategy.Offscreen } - .fillMaxSize() - .padding(24.dp) - .clip(RoundedCornerShape(8.dp)) - .drawWithCache { - onDrawWithContent { - drawContent() - drawImage( - image = mask, - dstSize = IntSize(size.width.toInt(), size.height.toInt()), - blendMode = BlendMode.DstIn - ) - } - }, - imageModel = { imageUrl } - ) - } ?: run { - Image( - modifier = Modifier - .graphicsLayer { compositingStrategy = CompositingStrategy.Offscreen } - .fillMaxSize() - .padding(24.dp) - .clip(RoundedCornerShape(8.dp)) - .drawWithCache { - onDrawWithContent { - drawContent() - drawImage( - image = mask, - dstSize = IntSize(size.width.toInt(), size.height.toInt()), - blendMode = BlendMode.DstIn - ) - } - }, - painter = painterResource(R.drawable.img_sample), - contentDescription = "thumbnail", - contentScale = ContentScale.Crop + text = "D-12", + fontSize = 12.dp, + fontWeight = FontWeight.SemiBold, + color = MSTheme.color.greyG5 ) } } } - val guideItem = GuideItem.entries.getOrNull(step - 2) // step 1 보정 + index 보정 - if (guideItem != null) { - Image( + Box( + modifier = Modifier + .offset(y = (-10).dp) + .wavyStroke( + color = MSTheme.color.greyG5, + fillColor = MSTheme.color.white, + amplitude = (1.5).dp, + spacing = 4.dp, + ) + .fillMaxWidth() + .aspectRatio(1f) + ) { + val mask = ImageBitmap.imageResource(id = R.drawable.img_mask_main) + GlideImage( modifier = Modifier - .aspectRatio(guideItem.width / guideItem.height) - .size(width = guideItem.width, height = guideItem.height) - .align(Alignment.BottomCenter), - painter = painterResource(guideItem.imgRes), - contentDescription = "ticket_guide" + .graphicsLayer { compositingStrategy = CompositingStrategy.Offscreen } + .fillMaxSize() + .padding(12.dp) + .drawWithCache { + onDrawWithContent { + drawContent() + drawImage( + image = mask, + dstSize = IntSize(size.width.toInt(), size.height.toInt()), + blendMode = BlendMode.DstIn + ) + } + }, + imageModel = { R.drawable.img_sample } ) } + Spacer(modifier = Modifier.height(2.dp)) // 위에서 offset 준 만큼 원본에서 차감 + MSText( + text = "제목입니다. 제목입니다.", + fontWeight = FontWeight.Bold, + fontSize = 16.dp, + color = MSTheme.color.greyG5 + ) + Spacer(modifier = Modifier.height(8.dp)) + MSText( + text = "2027. 10. 24 ~ 2027. 10. 24 ", + fontWeight = FontWeight.Normal, + fontSize = 12.dp, + color = MSTheme.color.greyG5.copy(alpha = 0.6f) + ) } } @@ -196,9 +151,9 @@ fun HomeTicket( private fun HomeTicketPreview() { HomeTicket( buried = true, - createdAt = "2027. 10. 24.", - title = "제목입니다.", - imageUrl = null, - step = 1 +// createdAt = "2027. 10. 24.", +// title = "제목입니다.", +// imageUrl = null, +// step = 1 ) } \ No newline at end of file From d67df86429c0908af5f2bb4e03d438f4109c7890 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Thu, 10 Sep 2026 15:20:53 +0900 Subject: [PATCH 04/31] =?UTF-8?q?:sparkles:=20::=20=ED=99=88=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20=EA=B4=80=EB=A0=A8=20=EC=9E=91=EC=97=85=20=EB=B0=8F?= =?UTF-8?q?=20=ED=94=84=EB=A1=9C=ED=95=84=20=ED=99=94=EB=A9=B4=20=ED=83=80?= =?UTF-8?q?=EC=9E=84=20=EC=BA=A1=EC=8A=90=20API=20=ED=98=B8=EC=B6=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 홈 화면에서 사용되는 배너 2종 추가 - 홈 상세 화면 임시 작업 및 네비게이션 연동 --- .../com/idiotfrogs/memoryseal/MainActivity.kt | 4 +- .../res/drawable/img_remind_banner_bg.png | Bin 0 -> 15034 bytes .../res/drawable/img_ticket_guide_step2.png | Bin 16576 -> 17390 bytes .../drawable/img_ticket_guide_step2_small.png | Bin 0 -> 4386 bytes .../res/drawable/img_ticket_guide_step3.png | Bin 16836 -> 17273 bytes .../drawable/img_ticket_guide_step3_small.png | Bin 0 -> 5013 bytes .../res/drawable/img_ticket_guide_step4.png | Bin 22521 -> 24166 bytes .../drawable/img_ticket_guide_step4_small.png | Bin 0 -> 9548 bytes .../res/drawable/img_ticket_guide_step5.png | Bin 32103 -> 31551 bytes .../java/com/idiotfrogs/navigation/Routes.kt | 7 + .../home/component/HomeMaxLineItem.kt | 15 + .../home/component/HomeRemindBanner.kt | 103 +++++++ .../home/component/HomeSectionDivider.kt | 40 +++ .../home/component/HomeSmallTicket.kt | 284 ++++++++++++++++++ .../idiotfrogs/home/component/HomeTicket.kt | 159 ---------- .../idiotfrogs/home/component/OpenedTicket.kt | 8 +- .../home/detail/HomeDetailScreen.kt | 71 +++++ .../idiotfrogs/home/{ => home}/HomeScreen.kt | 117 +++++--- .../home/{ => home}/HomeViewModel.kt | 6 +- .../profile/profile/ProfileScreen.kt | 18 -- .../profile/profile/ProfileViewModel.kt | 20 +- 21 files changed, 609 insertions(+), 243 deletions(-) create mode 100644 common/resource/src/main/res/drawable/img_remind_banner_bg.png create mode 100644 common/resource/src/main/res/drawable/img_ticket_guide_step2_small.png create mode 100644 common/resource/src/main/res/drawable/img_ticket_guide_step3_small.png create mode 100644 common/resource/src/main/res/drawable/img_ticket_guide_step4_small.png create mode 100644 feature/home/src/main/java/com/idiotfrogs/home/component/HomeMaxLineItem.kt create mode 100644 feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt create mode 100644 feature/home/src/main/java/com/idiotfrogs/home/component/HomeSectionDivider.kt create mode 100644 feature/home/src/main/java/com/idiotfrogs/home/component/HomeSmallTicket.kt delete mode 100644 feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt create mode 100644 feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt rename feature/home/src/main/java/com/idiotfrogs/home/{ => home}/HomeScreen.kt (65%) rename feature/home/src/main/java/com/idiotfrogs/home/{ => home}/HomeViewModel.kt (93%) diff --git a/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt b/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt index d60ebd9b..c84aa9ed 100644 --- a/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt +++ b/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt @@ -28,7 +28,8 @@ import com.idiotfrogs.create.CreateRoute import com.idiotfrogs.designsystem.theme.MSTheme import com.idiotfrogs.detail.DetailRoute import com.idiotfrogs.friend.FriendRoute -import com.idiotfrogs.home.HomeRoute +import com.idiotfrogs.home.detail.HomeDetailRoute +import com.idiotfrogs.home.home.HomeRoute import com.idiotfrogs.management.ManagementRoute import com.idiotfrogs.memory.MemoryRoute import com.idiotfrogs.message.MessageRoute @@ -134,6 +135,7 @@ class MainActivity : ComponentActivity() { entry { LoginRoute() } entry { SignUpRoute() } entry { HomeRoute() } + entry { HomeDetailRoute(it.homeDetailType) } entry { CreateRoute() } entry { ProfileRoute() } entry { EditProfileRoute() } diff --git a/common/resource/src/main/res/drawable/img_remind_banner_bg.png b/common/resource/src/main/res/drawable/img_remind_banner_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..c482339c4462f12029a2b4a908077d683561226d GIT binary patch literal 15034 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 literal 0 HcmV?d00001 diff --git a/common/resource/src/main/res/drawable/img_ticket_guide_step2.png b/common/resource/src/main/res/drawable/img_ticket_guide_step2.png index 60616f22cc8e8e2d2560a70e98932bb73530f03c..307b877e898f54fd46ec162ba8c6fa7b423fa02c 100644 GIT binary patch literal 17390 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 Z`~55_pfvae{2T|AtfbP%3UOoq{{du)z_0)S literal 16576 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 literal 0 HcmV?d00001 diff --git a/common/resource/src/main/res/drawable/img_ticket_guide_step3.png b/common/resource/src/main/res/drawable/img_ticket_guide_step3.png index c0940fa740af56bef97afd61fe7e6009db55b94e..57a7b894daf5f73bfbb97fdab496883ded44cb3d 100644 GIT binary patch literal 17273 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 b-##p1eNBnT+kgMr3v5 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

ch-Jub)!m?w1X97K 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 S0{>(ILQ+&tq+H0r|9=43Od%8i diff --git a/common/resource/src/main/res/drawable/img_ticket_guide_step3_small.png b/common/resource/src/main/res/drawable/img_ticket_guide_step3_small.png new file mode 100644 index 0000000000000000000000000000000000000000..7a7cc7ff7d057d5910926848e91f718af71db889 GIT binary patch literal 5013 zcmchb=Q|wC*T+|aEN-!}f*@hBAw*kI!z!zHqDS=JqHKf^b%|bMt>`6Dqqh~k6VXD5 zw%RJuR`ihdxS!{F@%syYFXo&%^J1>+TxZVA=Q~k4TFTUvOq2isfLc{WLGRjkU5_jv z`L$h_C<0$Q3J(<%ZvcSmdQJr<0er}0yj~>n)>D=TRE)4}T?eENa+-1gKy?Dur4`wA zd>g4~jC}Ue9{JkJ%MPIAwOs$Y4-w*v%26c54ER(HsGy^@EdRPt&OP`veK=LZOW1phAvsY_s^mG$-)j)SN4mMgI)Qg%dSjQ&0`Np} zDL#q$=ej0&rKLv2OCk^`g_7444p;g3sn1STU!v!pI{6JtDGBbYwltdJ)wD%D?cD`C z88BF0EfyuNG&Vh5)cobk)XWU#x6~+)sLHJkzu%LK3(h;gBsfM{C2T9F2aDDWA%(!m z{?&=uSsnxev3^V-R6P+B`%3(KaX^bjyk<`VxpBfIB%JoPc6U>Mrk5=XXC6LBCDPjR zWNBs0=Q+Fi=w_h?n zxsJa0=AxgfSMpxsotU`SiLoQ_!d%iaCkZ4U&0<4}HRBf;4w2hDoeUd%wGQm<$BK}$ z^irhq@T6@(2SL8KObV4P&)?6h2#(|P9+$>J_Tvr?JiR9=1+K;}@+E?ri#P(VdIs)! zD^T3Uf8W}2k~m&hHEDN3_-da_i47OjX;4BGwQgJK&@msn;EmeH{YYAZc@s7RNV0qQ zvObJCcG1Ln(BYW>0YadF4=ege^Nw_39p2Wb-HE_KSgZ|JD?3TucxU+V&pS~@4v#;v zQjo#{IY*QNJ=k0+Y1b@7+)mH`HokE~Fx1gJq{k$5NY}$c4fx2~5`bBwuvl1FdGxNPYRxEek^qvP=1sNkQvNRj?@>37zX>l7C}p#u^`DdeXTRY0aWb=u&arZ#i}~Cb7Z8_gs8xsM%0bh% zDuy{Rzn`;T#kpX2f&f}UDPq(kty4Dte0tY?k;r&!usZbtq>xm0XD@*W?*IL;bBP-C zu+v3>R}~oEqZ`QLS^51LDzku_d1n|E1%k20&id5{87&DB+Ol1RmuX5>8yK823NiavNgb$LMUIz;ugt8>gQ?8F#MB(zOqMTrBql|HHuBkI=@cO?vf|hF5I|dz zQye6RBXZJY;)UGmndfF_t!G2+R{P>C&IsK!_=VTF7X`SmovDe+AceVR>L`)tlBTU! zZEx!Fe{t=NnwKA6N3u%u33oXicv+f$CF~5lx~@z*34d@=OpBiJN)O=TYX5>XX*<|e z^2@bKah+R$mbv^G*lri+X%Do~M_TjkYh-pSSD|(@eB!CBGCg5#qb@PUKSz z2+Uf%VLfqkkb3Bac;!oHLA94br158+K67#1ToGNY%$)M&H`7?N&m`?)Z#0J_^Uzwe z957Lwpic~^K{Z}r!Dq|Uw6^EseLQI;zQ^~MQ9#=J+>Hi-oKGVUvt`~4ut0u1o!{V6 zEx!r=r>PCD_Wd4&oI9PG#ZGNq;i1hC%f;wx!dK97l z`S0Xh+jXr^nEH$lcODI9hCF7n$r?Xn zRomNJlpGb{fuCPD0SVXsDUYk9rv50+;o@hYddKmZ5^myb~; zN=%p{Cq26uLsMN(iZj@3kna{TRm{<>n&o$#ESD57$dS~w<63Lg#e}&X_=)GU#l-f# zEnwQ1fh1oo$TuF1rss%fP^I8S*upUml+vNR@eaTkegY|@aXZUeUQ@guMdR)bb&1_K z_QMKK_urPvF%C%@I1VwV<~#3e)n?bhd@}x6;cV7f#RUnrO>?r7!60k0x9bFQGh@ws z#<$yhiw~GOCMTiN-7QAjny)%HyO~gPVfvd7o_(0A9T$u~+0Cn#rD+WhsJ8W})wSe? zCELaBHANU8Mjd4h5x76s7-1#OlO!tkin=$Dd|$$C&OA>bG{%Fu58xp@l%2#cW02A`_c$+X z!shCpZ;0D0+8#=g8t%~nEv3kKkpr>R6&e4 zPQS!Xa0qxje=<+qJ`aD$s2Z}s??o#_-ZCI}z6>YmTymUsERRD{W1CpZA#wZ_KGbpxFXxL?>o=WHOT7NNbrsyC zht-|UE{=<6{h(}#Dl0(q)~Q_XYm;=|v7<; z2DF^@XV2g&zAuh81&XwD+SU=fIVX35Amk8eLR__mD&0z*ItKMg=eE^p{+)I5HDS_Z zG)Yp+4`VZ7Fk2IOZzG#F@WZ~B{D4EE%W=5FGSu>)nUIbHMrnDKd&{asetMOLd$dV4 zWXC2A#$b6Mw>2%(Tc7hZR6YAFLie*356`~Sh1==w~_6enC zdoudo-YFuHt1LP^gat;%IYc@CcVoL-Pb>=^6>DKHpXD~G+jI;`Bs5M7c*zuCz!sj zi4`xRDPF-3G%a0e+PgZX#vJ^OrhM%h*H#S=Hb~#p71mGmOEwg(H4IT6t{2?L(Z1E3 zec&1e&0wOvg1>?N+ZM2=!n{|NL?fb9wW&Gt$dK^WQDer2h0_AS+NmwR39DFSo077ygQU_1f zb@{(R=$iNQsGZgQ%P3;5@xydoisT|zMb-Q3jeQq-oH!f8)X=H(pV=n#_b$@(e~)KR zp2g)4sx?Zg&n#9-PwxfL+Zl;&Cnb{)Ra#eL)HrEH{fLD=uG*Of?ka7)`wr}doSlvp zu=LoPotf%xCPW`r;2toTOV-bD*Z({?z0%itpZ_Ag>AEVic?R0r2|~ebZSbjuh0lF` zefqHUy68Cn30TmIChygrN7vpt$Ge?lNyyqmkFv+vm~-vN4`-y>c-s3A;K&-TS!=<(yf* zv1sM&tcLAb^{hA79>BJ0l>LQ&l7kfX5PGyd;wFp?`JainNP90%OjySYCc282<+Gu> zF5JT`2$^t*Eq~zyP>_eh0TiN0-Ue!8Ys)+#HP2iBq9Zk$v2n-Q#YOYu08{7kxSW4b zEr@m#{aIm!o0$9jN#BxFI%ON?;701#c1E7R-_!R?hh|{)*z-UU^hG+;2$A~;gzl8H z*z(VrOPO9^k}B9N&z|=%tt%!Hi8>Bm*i4ZK5)*d#H-7qTboqm2n`RiNX&!#jzn$ll z*c(BJs9j}P3t5wtki4vfNqQ+gnA~tHA-~7OMEkd!GfPX|#ih*gCEK=`8%XbmFYT~g zluQw-ODzHY{)f=GE~?zLUhRm@*%RYa@klIcpT`;rJ4Dyar3Hx=h+*B8MWGl3ogLGaHSEDN?@L96`xovjoxe3hRb8 z34dI@Y~cafzu#qezO~>a4`J*HF9{Out2W~r#i&=Y)z$QQTu!LYIrP+z;BUV7p&Z)1 z(ORX*I569@FkPyze=ZRgKo0|L+i5zkAl(oU9xwyc!qh*RT zknpNy{kJwZsq>^%)dhXo^Q)k*xUc@zjE5gOIAUY(3zCQW7vz@7tv9C?#AQ#%X%IX< zs%QPD_Oa)pid>k5N;=si9-{Pg6D)1uT#woD%BJf>MR{hJKUj)N2qsNF+bNF2v>NGs z%ONK30d@pq==6GpD$4C*^--x))K{S?ikZx<5g3em#Gd?{UNgOEyMIfGgUQ!EQAZ)b5dMJzq89R}CwiKp28 z^DdGqKg3UwZu_olf6YZ3A2y~vb2?=y!Ia%JYHxb3?QL0{B)wE))mVFNY{~9&0{oI& z)bkhe#vFVxa3ig5o}cwCA*sdt#O=JVkr^Knp;_bhI?YiG+8(&7$ybmMcJXsqVaXO^ z4=fgWTsZ%;7@uMM8HnAk_@cqwyV&ZFPc<@6qJf`vl)veDl@@l3W<{_Be=J+&?f?7O zf+ZFA_oU|MnDId`a(oP{NLJ8jd! zwCVLgAHJ5}5oy(B5ngFM-$0ka0vhd1$*KkByMw|j!YvVBDb3zr+@$c7tH999td9Gk`3W)^S4){Z*6RbI-;59!%+OPz7#ftEB*F)^|z)E;AIN7dA_jr3@cUM zII0CwUm;_cHS$hdA>WlzvRn~Xj?1bl&7A+^Bd@Ttn|Als(PZF{#Oq%(fU2UFLWR6# G=>Gs|QjDko literal 0 HcmV?d00001 diff --git a/common/resource/src/main/res/drawable/img_ticket_guide_step4.png b/common/resource/src/main/res/drawable/img_ticket_guide_step4.png index 33585e75bbe3552c9e430eb9c171234a3a441b55..85551a6118ad9eb9d111c30c57c87374c438cb35 100644 GIT binary patch literal 24166 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 G4E!IaQX=92 literal 22521 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 Km9CdG4gDW%d_~v* literal 0 HcmV?d00001 diff --git a/common/resource/src/main/res/drawable/img_ticket_guide_step5.png b/common/resource/src/main/res/drawable/img_ticket_guide_step5.png index df335d0adfe0f9c94a30c622a84ee07ac9c2332b..8bb00b23283a718604064a18f37f09804260ddf1 100644 GIT binary patch literal 31551 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 literal 32103 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 diff --git a/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt b/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt index 8ad16617..df83bed4 100644 --- a/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt +++ b/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt @@ -13,6 +13,10 @@ sealed interface Routes: NavKey { @Serializable data object Home : Routes @Serializable + data class HomeDetail( + val homeDetailType: HomeDetailType + ): Routes + @Serializable data object Create : Routes @Serializable data object Profile : Routes @@ -35,3 +39,6 @@ sealed interface Routes: NavKey { @Serializable data class WateringDetail(val id: Long) : Routes } + +// 각각 '타임 티켓'과 '오픈 예정 티켓'에 대응 +enum class HomeDetailType { BEFORE_BURIED, BURIED } diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeMaxLineItem.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeMaxLineItem.kt new file mode 100644 index 00000000..0473df92 --- /dev/null +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeMaxLineItem.kt @@ -0,0 +1,15 @@ +package com.idiotfrogs.home.component + +import androidx.compose.foundation.lazy.grid.GridItemSpan +import androidx.compose.foundation.lazy.grid.LazyGridItemScope +import androidx.compose.foundation.lazy.grid.LazyGridScope +import androidx.compose.runtime.Composable + +fun LazyGridScope.maxLineItem( + content: @Composable (LazyGridItemScope.() -> Unit), +) { + this.item( + span = { GridItemSpan(maxLineSpan) }, + content = content + ) +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt new file mode 100644 index 00000000..0ebf4887 --- /dev/null +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt @@ -0,0 +1,103 @@ +package com.idiotfrogs.home.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.idiotfrogs.designsystem.component.MSText +import com.idiotfrogs.designsystem.theme.MSTheme +import com.idiotfrogs.designsystem.util.wavyStroke +import com.idiotfrogs.resource.R + +enum class Weather(val text: String) { + SPRING("봄"), SUMMER("여름"), AUTUMN("가을"), WINTER("겨울") +} + +@Composable +fun HomeRemindBanner( + modifier: Modifier = Modifier, + weather: Weather +) { + Column( + modifier = modifier + .fillMaxWidth() + .height(213.dp) + .wavyStroke( + strokeWidth = 4.dp, + cornerRadius = 27.dp, + color = MSTheme.color.greyG5, + fillColor = MSTheme.color.bgNormal, + clipContent = true + ), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 20.dp, start = 20.dp, end = 20.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(10.dp) + ) { + MSText( + text = "지난 ${weather.text} 우리", + fontWeight = FontWeight.Bold, + fontSize = 20.dp, + color = MSTheme.color.greyG5 + ) + MSText( + text = "티켓이름티켓이름티켓이름", + fontWeight = FontWeight.Medium, + fontSize = 16.dp, + color = MSTheme.color.greyG5 + ) + } + Box( + modifier = Modifier + .size(53.dp) + .wavyStroke( + color = MSTheme.color.black, + clipContent = true + ) + ) { + Image( + modifier = Modifier.fillMaxSize(), + painter = painterResource(R.drawable.img_sample), + contentScale = ContentScale.Crop, + contentDescription = "img_ticket" + ) + } + } + Image( + modifier = Modifier + .fillMaxWidth() + .weight(1f), + painter = painterResource(R.drawable.img_remind_banner_bg), + contentScale = ContentScale.FillBounds, + contentDescription = "img_remind_banner_bg" + ) + } +} + +@Preview +@Composable +fun HomeRemindBannerPreview() { + HomeRemindBanner(weather = Weather.AUTUMN) +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeSectionDivider.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeSectionDivider.kt new file mode 100644 index 00000000..409292c1 --- /dev/null +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeSectionDivider.kt @@ -0,0 +1,40 @@ +package com.idiotfrogs.home.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import com.idiotfrogs.designsystem.component.MSText +import com.idiotfrogs.designsystem.theme.MSTheme +import com.idiotfrogs.resource.R + +@Composable +fun HomeSectionDivider( + modifier: Modifier = Modifier, + sectionName: String, +) { + Row( + modifier = modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + MSText( + text = sectionName, + fontWeight = FontWeight.Bold, + fontSize = 20.dp, + color = MSTheme.color.black + ) + Image( + modifier = Modifier.size(20.dp), + painter = painterResource(R.drawable.ic_chevron_right), + contentDescription = "ic_chevron_right" + ) + } +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeSmallTicket.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeSmallTicket.kt new file mode 100644 index 00000000..bc7135d7 --- /dev/null +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeSmallTicket.kt @@ -0,0 +1,284 @@ +package com.idiotfrogs.home.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithCache +import androidx.compose.ui.graphics.BlendMode +import androidx.compose.ui.graphics.CompositingStrategy +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.res.imageResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex +import com.idiotfrogs.designsystem.component.MSText +import com.idiotfrogs.designsystem.theme.MSTheme +import com.idiotfrogs.designsystem.util.wavyStroke +import com.idiotfrogs.resource.R +import com.skydoves.landscapist.glide.GlideImage + +/** 사진 영역에 준 offset. 가이드 이미지도 동일하게 올려 바디 하단선에 맞춘다. */ +private val BODY_OFFSET_Y = (-10).dp + +enum class BigGuideItem(val imgRes: Int, val height: Dp) { + STEP_2(imgRes = R.drawable.img_ticket_guide_step2, height = 328.dp), + STEP_3(imgRes = R.drawable.img_ticket_guide_step3, height = 328.dp), + STEP_4(imgRes = R.drawable.img_ticket_guide_step4, height = 328.dp), + STEP_5(imgRes = R.drawable.img_ticket_guide_step5, height = 442.dp) +} + +enum class SmallGuideItem(val imgRes: Int, val height: Dp) { + STEP_2(imgRes = R.drawable.img_ticket_guide_step2_small, height = 148.dp), + STEP_3(imgRes = R.drawable.img_ticket_guide_step3_small, height = 156.dp), + STEP_4(imgRes = R.drawable.img_ticket_guide_step4_small, height = 183.dp), +} + +@Composable +fun HomeBigTicket( + modifier: Modifier = Modifier, + step: Int, +) { + // 티켓 바디(헤더 + 사진). 가이드 이미지는 이 Box 하단을 기준으로 정렬된다. + Box(modifier = Modifier.fillMaxWidth()) { + Column( + modifier = modifier + .fillMaxWidth() + .padding(start = 20.dp, end = 21.dp) + ) { + Box( + modifier = Modifier + .zIndex(1f) + .wavyStroke( + color = MSTheme.color.greyG5, + fillColor = MSTheme.color.primaryNormal, + strokeWidth = 4.dp, + amplitude = 1.dp, + spacing = 4.dp, + ) + .fillMaxWidth() + .height(94.dp), + contentAlignment = Alignment.CenterStart + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(20.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + MSText( + text = "제목입니다. 제목입니다.", + fontWeight = FontWeight.Bold, + fontSize = 24.dp, + color = MSTheme.color.greyG5 + ) + MSText( + text = "2027. 10. 24.", + fontWeight = FontWeight.Normal, + fontSize = 14.dp, + color = MSTheme.color.greyG5 + ) + } + } + Box( + modifier = Modifier + .offset(y = BODY_OFFSET_Y) + .wavyStroke( + strokeWidth = 4.dp, + color = MSTheme.color.greyG5, + fillColor = MSTheme.color.white, + amplitude = (1.5).dp, + spacing = 4.dp, + ) + .fillMaxWidth() + .aspectRatio(1f) + ) { + val mask = ImageBitmap.imageResource(id = R.drawable.img_mask_main) + GlideImage( + modifier = Modifier + .graphicsLayer { compositingStrategy = CompositingStrategy.Offscreen } + .fillMaxSize() + .padding(24.dp) + .drawWithCache { + onDrawWithContent { + drawContent() + drawImage( + image = mask, + dstSize = IntSize(size.width.toInt(), size.height.toInt()), + blendMode = BlendMode.DstIn + ) + } + }, + imageModel = { R.drawable.img_sample } + ) + } + } + BigGuideItem.entries.getOrNull(step - 1)?.let { + Image( + modifier = Modifier + .align(Alignment.BottomCenter) + .offset(y = BODY_OFFSET_Y) + .fillMaxWidth() + .height(it.height), + painter = painterResource(it.imgRes), + contentDescription = "img_ticket_guide" + ) + } + } +} + +@Composable +fun HomeSmallTicket( + modifier: Modifier = Modifier, + buried: Boolean, +// createdAt: String, +// title: String, +// imageUrl: String?, + step: Int, +) { + Column(modifier = modifier.fillMaxWidth()) { + // 티켓 바디(헤더 + 사진). 가이드 이미지는 이 Box 하단을 기준으로 정렬된다. + Box(modifier = Modifier.fillMaxWidth()) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(start = 14.dp, end = 16.dp) + ) { + Box( + modifier = Modifier + .zIndex(1f) + .wavyStroke( + color = MSTheme.color.greyG5, + fillColor = MSTheme.color.primaryNormal, + amplitude = 1.dp, + spacing = 4.dp, + ) + .fillMaxWidth() + .height(55.dp), + contentAlignment = Alignment.CenterStart + ) { + if (buried) { + Row( + modifier = Modifier + .padding(start = 12.dp) + .background( + color = MSTheme.color.primaryLight.copy(alpha = 0.6f), + shape = RoundedCornerShape(8.dp) + ) + .padding(start = 6.dp, end = 8.dp, top = 4.dp, bottom = 4.dp), + horizontalArrangement = Arrangement.spacedBy(1.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Image( + modifier = Modifier.size(16.dp), + painter = painterResource(R.drawable.ic_shovels), + contentDescription = "ic_shovels" + ) + MSText( + text = "D-12", + fontSize = 12.dp, + fontWeight = FontWeight.SemiBold, + color = MSTheme.color.greyG5 + ) + } + } + } + Box( + modifier = Modifier + .offset(y = BODY_OFFSET_Y) + .wavyStroke( + color = MSTheme.color.greyG5, + fillColor = MSTheme.color.white, + amplitude = (1.5).dp, + spacing = 4.dp, + ) + .fillMaxWidth() + .aspectRatio(1f) + ) { + val mask = ImageBitmap.imageResource(id = R.drawable.img_mask_main) + GlideImage( + modifier = Modifier + .graphicsLayer { compositingStrategy = CompositingStrategy.Offscreen } + .fillMaxSize() + .padding(12.dp) + .drawWithCache { + onDrawWithContent { + drawContent() + drawImage( + image = mask, + dstSize = IntSize(size.width.toInt(), size.height.toInt()), + blendMode = BlendMode.DstIn + ) + } + }, + imageModel = { R.drawable.img_sample } + ) + } + } + SmallGuideItem.entries.getOrNull(step - 1)?.let { + Image( + modifier = Modifier + .align(Alignment.BottomCenter) + .offset(y = BODY_OFFSET_Y) + .fillMaxWidth() + .height(it.height), + painter = painterResource(it.imgRes), + contentDescription = "img_ticket_guide" + ) + } + } + Column( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(start = 14.dp, end = 16.dp) + ) { + Spacer(modifier = Modifier.height(2.dp)) // 위에서 offset 준 만큼 원본에서 차감 + MSText( + text = "제목입니다. 제목입니다.", + fontWeight = FontWeight.Bold, + fontSize = 16.dp, + color = MSTheme.color.greyG5 + ) + Spacer(modifier = Modifier.height(8.dp)) + MSText( + text = "2027. 10. 24", + fontWeight = FontWeight.Normal, + fontSize = 12.dp, + color = MSTheme.color.greyG5.copy(alpha = 0.6f) + ) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun HomeSmallTicketPreview() { + HomeSmallTicket( + buried = true, +// createdAt = "2027. 10. 24.", +// title = "제목입니다.", +// imageUrl = null, + step = 1 + ) +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt deleted file mode 100644 index 744233a0..00000000 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt +++ /dev/null @@ -1,159 +0,0 @@ -package com.idiotfrogs.home.component - -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.aspectRatio -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.offset -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawWithCache -import androidx.compose.ui.graphics.BlendMode -import androidx.compose.ui.graphics.CompositingStrategy -import androidx.compose.ui.graphics.ImageBitmap -import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.res.imageResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.IntSize -import androidx.compose.ui.unit.dp -import androidx.compose.ui.zIndex -import com.idiotfrogs.designsystem.component.MSText -import com.idiotfrogs.designsystem.theme.MSTheme -import com.idiotfrogs.designsystem.util.wavyStroke -import com.idiotfrogs.resource.R -import com.skydoves.landscapist.glide.GlideImage - -enum class GuideItem(val imgRes: Int, val width: Dp, val height: Dp) { - STEP_2(imgRes = R.drawable.img_ticket_guide_step2, width = 395.dp, height = 359.dp), - STEP_3(imgRes = R.drawable.img_ticket_guide_step3, width = 394.dp, height = 363.dp), - STEP_4(imgRes = R.drawable.img_ticket_guide_step4, width = 383.dp, height = 354.dp), - STEP_5(imgRes = R.drawable.img_ticket_guide_step5, width = 383.dp, height = 446.dp) -} - -@Composable -fun HomeTicket( - modifier: Modifier = Modifier, - buried: Boolean, -// createdAt: String, -// title: String, -// imageUrl: String?, -// step: Int, -) { - Column( - modifier = modifier - .fillMaxWidth() - .wrapContentHeight() - ) { - Box( - modifier = Modifier - .zIndex(1f) - .wavyStroke( - color = MSTheme.color.greyG5, - fillColor = MSTheme.color.primaryNormal, - amplitude = (1.5).dp, - spacing = 4.dp, - ) - .fillMaxWidth() - .height(55.dp), - contentAlignment = Alignment.CenterStart - ) { - if (buried) { - Row( - modifier = Modifier - .padding(start = 12.dp) - .background( - color = MSTheme.color.primaryLight.copy(alpha = 0.6f), - shape = RoundedCornerShape(8.dp) - ) - .padding(start = 6.dp, end = 8.dp, top = 4.dp, bottom = 4.dp), - horizontalArrangement = Arrangement.spacedBy(1.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Image( - modifier = Modifier.size(16.dp), - painter = painterResource(R.drawable.ic_shovels), - contentDescription = "ic_shovels" - ) - MSText( - text = "D-12", - fontSize = 12.dp, - fontWeight = FontWeight.SemiBold, - color = MSTheme.color.greyG5 - ) - } - } - } - Box( - modifier = Modifier - .offset(y = (-10).dp) - .wavyStroke( - color = MSTheme.color.greyG5, - fillColor = MSTheme.color.white, - amplitude = (1.5).dp, - spacing = 4.dp, - ) - .fillMaxWidth() - .aspectRatio(1f) - ) { - val mask = ImageBitmap.imageResource(id = R.drawable.img_mask_main) - GlideImage( - modifier = Modifier - .graphicsLayer { compositingStrategy = CompositingStrategy.Offscreen } - .fillMaxSize() - .padding(12.dp) - .drawWithCache { - onDrawWithContent { - drawContent() - drawImage( - image = mask, - dstSize = IntSize(size.width.toInt(), size.height.toInt()), - blendMode = BlendMode.DstIn - ) - } - }, - imageModel = { R.drawable.img_sample } - ) - } - Spacer(modifier = Modifier.height(2.dp)) // 위에서 offset 준 만큼 원본에서 차감 - MSText( - text = "제목입니다. 제목입니다.", - fontWeight = FontWeight.Bold, - fontSize = 16.dp, - color = MSTheme.color.greyG5 - ) - Spacer(modifier = Modifier.height(8.dp)) - MSText( - text = "2027. 10. 24 ~ 2027. 10. 24 ", - fontWeight = FontWeight.Normal, - fontSize = 12.dp, - color = MSTheme.color.greyG5.copy(alpha = 0.6f) - ) - } -} - -@Preview(showBackground = true) -@Composable -private fun HomeTicketPreview() { - HomeTicket( - buried = true, -// createdAt = "2027. 10. 24.", -// title = "제목입니다.", -// imageUrl = null, -// step = 1 - ) -} \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt index 5ef9c8a0..59a9d4e9 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt @@ -40,7 +40,9 @@ fun OpenedTicket() { .rotate(10f) .wavyStroke( color = MSTheme.color.greyG5, - fillColor = MSTheme.color.white + fillColor = MSTheme.color.white, + amplitude = 1.dp, + spacing = 4.dp, ) .fillMaxWidth() .height(40.dp) @@ -49,7 +51,9 @@ fun OpenedTicket() { modifier = Modifier .wavyStroke( color = MSTheme.color.greyG5, - fillColor = MSTheme.color.white + fillColor = MSTheme.color.white, + amplitude = 1.dp, + spacing = 4.dp, ) .fillMaxWidth() .aspectRatio(1f) diff --git a/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt new file mode 100644 index 00000000..4bc79ce0 --- /dev/null +++ b/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt @@ -0,0 +1,71 @@ +package com.idiotfrogs.home.detail + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.itemsIndexed +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.idiotfrogs.home.component.HomeSmallTicket +import com.idiotfrogs.navigation.HomeDetailType +import com.idiotfrogs.resource.R + +@Composable +fun HomeDetailRoute( + homeDetailType: HomeDetailType +) { + HomeDetailScreen(homeDetailType) +} + +@Composable +fun HomeDetailScreen(homeDetailType: HomeDetailType) { + Column( + modifier = Modifier + .fillMaxSize() + .systemBarsPadding() + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(56.dp) + .padding(start = 20.dp), + contentAlignment = Alignment.CenterStart + ) { + Image( + modifier = Modifier.size(24.dp), + painter = painterResource(R.drawable.ic_chevron_left), + contentDescription = "ic_chevron_left" + ) + } + LazyVerticalGrid(columns = GridCells.Fixed(2)) { + itemsIndexed(listOf(1, 1, 1, 1, 1, 1)) { index, item -> + val isLastRow = index / 2 == 2 // 추후 하드코딩에서 변경 + HomeSmallTicket( + modifier = Modifier.padding( + bottom = if (isLastRow) 0.dp else 16.dp + ), + buried = index / 2 == 0, + step = index + ) + } + } + } +} + +@Preview +@Composable +fun HomeDetailScreenPreview() { + HomeDetailScreen(homeDetailType = HomeDetailType.BEFORE_BURIED) +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/HomeScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt similarity index 65% rename from feature/home/src/main/java/com/idiotfrogs/home/HomeScreen.kt rename to feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt index 7d18c8ff..844ef047 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt @@ -1,4 +1,4 @@ -package com.idiotfrogs.home +package com.idiotfrogs.home.home import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -33,15 +33,22 @@ import com.idiotfrogs.designsystem.component.MSLoadingOverlay import com.idiotfrogs.designsystem.model.MSMenuFabModel import com.idiotfrogs.designsystem.theme.MSTheme import com.idiotfrogs.designsystem.util.DevicePreview +import com.idiotfrogs.designsystem.util.noRippleClickable import com.idiotfrogs.home.component.HomeHeader import com.idiotfrogs.home.component.HomeJoinContainer import com.idiotfrogs.navigation.LocalComposeMSNavigator import com.idiotfrogs.navigation.Routes import com.idiotfrogs.home.component.BottomMenu +import com.idiotfrogs.home.component.HomeBigTicket import com.idiotfrogs.home.component.HomeBottomBar import com.idiotfrogs.home.component.HomeEmptyScreen -import com.idiotfrogs.home.component.HomeTicket +import com.idiotfrogs.home.component.HomeRemindBanner +import com.idiotfrogs.home.component.HomeSectionDivider +import com.idiotfrogs.home.component.HomeSmallTicket import com.idiotfrogs.home.component.OpenedTicket +import com.idiotfrogs.home.component.Weather +import com.idiotfrogs.home.component.maxLineItem +import com.idiotfrogs.navigation.HomeDetailType import org.orbitmvi.orbit.compose.collectAsState import org.orbitmvi.orbit.compose.collectSideEffect @@ -60,6 +67,7 @@ fun HomeRoute( HomeSideEffect.NavigateToCreate -> navigator.navigate(Routes.Create) HomeSideEffect.NavigateToProfile -> navigator.navigate(Routes.Profile) is HomeSideEffect.NavigateToDetail -> navigator.navigate(Routes.Detail(it.id)) + is HomeSideEffect.NavigateToHomeDetail -> navigator.navigate(Routes.HomeDetail(it.homeDetailType)) } } @@ -134,6 +142,7 @@ fun HomeScreen( navigateToProfile = { onAction.invoke(HomeAction.ProfileClicked) } ) HorizontalPager( + modifier = Modifier.padding(top = TOP_BAR_SIZE), state = pagerState, userScrollEnabled = false ) { page -> @@ -141,24 +150,72 @@ fun HomeScreen( BottomMenu.HOME.ordinal -> { if (false) { HomeEmptyScreen( - modifier = Modifier.padding(top = TOP_BAR_SIZE, bottom = BOTTOM_BAR_SIZE), + modifier = Modifier.padding(bottom = BOTTOM_BAR_SIZE), selectedMenu = BottomMenu.HOME ) } else { LazyVerticalGrid( - modifier = Modifier.padding(top = TOP_BAR_SIZE), - columns = GridCells.Fixed(2) + columns = GridCells.Fixed(2), + horizontalArrangement = Arrangement.spacedBy((-12).dp) // 줄기가 겹쳐지도록 ) { - itemsIndexed(listOf(1,1,1,1,1,1)) { index, item -> - val isLeft = index % 2 == 0 + if (true) { + maxLineItem { HomeBigTicket(step = 1) } + } + if (true) { // todo: 조건 변경 + maxLineItem { + HomeRemindBanner( + modifier = Modifier.padding(20.dp), + weather = Weather.AUTUMN + ) + } + } + maxLineItem { + HomeSectionDivider( + modifier = Modifier + .noRippleClickable { + onAction.invoke( + HomeAction.HomeDetailClicked( + HomeDetailType.BEFORE_BURIED + ) + ) + } + .padding(horizontal = (22.5).dp, vertical = 20.dp), + sectionName = "타임 티켓" + ) + } + itemsIndexed(listOf(1, 1, 1, 1, 1, 1)) { index, item -> val isLastRow = index / 2 == 2 // 추후 하드코딩에서 변경 - HomeTicket( + HomeSmallTicket( modifier = Modifier.padding( - start = if (isLeft) 20.dp else 8.dp, - end = if (isLeft) 8.dp else 20.dp, bottom = if (isLastRow) 0.dp else 16.dp ), - buried = index / 2 == 0 + buried = index / 2 == 0, + step = index + ) + } + maxLineItem { + HomeSectionDivider( + modifier = Modifier + .noRippleClickable { + onAction.invoke( + HomeAction.HomeDetailClicked( + HomeDetailType.BURIED + ) + ) + } + .padding(horizontal = (22.5).dp) + .padding(top = 40.dp, bottom = 15.dp), + sectionName = "오픈 예정 티켓" + ) + } + itemsIndexed(listOf(1, 1, 1, 1, 1, 1)) { index, item -> + val isLastRow = index / 2 == 2 // 추후 하드코딩에서 변경 + HomeSmallTicket( + modifier = Modifier.padding( + bottom = if (isLastRow) 0.dp else 16.dp + ), + buried = index / 2 == 0, + step = index ) } } @@ -167,12 +224,12 @@ fun HomeScreen( BottomMenu.OPENED.ordinal -> { if (false) { HomeEmptyScreen( - modifier = Modifier.padding(top = TOP_BAR_SIZE, bottom = BOTTOM_BAR_SIZE), + modifier = Modifier.padding(bottom = BOTTOM_BAR_SIZE), selectedMenu = BottomMenu.OPENED ) } else { LazyVerticalGrid( - modifier = Modifier.padding(top = TOP_BAR_SIZE, start = 20.dp, end = 20.dp), + modifier = Modifier.padding(horizontal = 20.dp), columns = GridCells.Fixed(2), horizontalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(24.dp), @@ -186,33 +243,6 @@ fun HomeScreen( } } } -// PullToRefreshBox( -// isRefreshing = isRefreshing, -// state = refreshState, -// onRefresh = { onAction.invoke(HomeAction.Refresh) } -// ) { -// LazyColumn( -// state = lazyListState, -// modifier = Modifier.fillMaxSize(), -// contentPadding = PaddingValues(top = 24.dp), -// horizontalAlignment = Alignment.CenterHorizontally, -// verticalArrangement = Arrangement.spacedBy(16.dp), -// ) { -// items(data) { -// HomeTicket( -// modifier = Modifier.noRippleClickable { -// onAction(HomeAction.TimeCapsuleClicked(it.timeCapsuleId)) -// }, -// buried = it.timeCapsuleStatus == TimeCapsuleStatus.BURIED, -// createdAt = it.createdAt.toYearMonthDay(), -// title = it.title, -// imageUrl = it.mainImageUrl, -// step = it.stage -// ) -// } -// } -// } - fun onDimClick() { expanded = false; showJoinContainer = false @@ -250,9 +280,4 @@ fun HomeScreenPreview() { isRefreshing = false, onAction = {}, ) -} - -private enum class HomeTab(val title: String) { - CREATED("생성한 티켓"), - JOINED("참여한 티켓"), -} +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/HomeViewModel.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt similarity index 93% rename from feature/home/src/main/java/com/idiotfrogs/home/HomeViewModel.kt rename to feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt index 0ee03c98..acfde52d 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/HomeViewModel.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt @@ -1,4 +1,4 @@ -package com.idiotfrogs.home +package com.idiotfrogs.home.home import androidx.compose.runtime.Immutable import com.idiotfrogs.domain.usecase.auth.PutFcmTokenUseCase @@ -9,6 +9,7 @@ import com.idiotfrogs.model.timecapsule.MyTimeCapsuleContent import com.idiotfrogs.model.timecapsule.PendingCollaboratorsRequest import com.idiotfrogs.model.timecapsule.TimeCapsuleRole import com.idiotfrogs.model.user.ProfileResponse +import com.idiotfrogs.navigation.HomeDetailType import com.idiotfrogs.notification.FcmTokenProvider import com.idiotfrogs.util.base.DataUiState import com.idiotfrogs.util.base.BaseViewModel @@ -102,6 +103,7 @@ class HomeViewModel @Inject constructor( is HomeAction.TimeCapsuleClicked -> postSideEffect(HomeSideEffect.NavigateToDetail(action.id)) is HomeAction.JoinCodeSubmitted -> requestCollaborator(PendingCollaboratorsRequest(action.code)) HomeAction.Refresh -> fetchHome() + is HomeAction.HomeDetailClicked -> postSideEffect(HomeSideEffect.NavigateToHomeDetail(action.homeDetailType)) } } } @@ -126,10 +128,12 @@ sealed interface HomeAction { data class TimeCapsuleClicked(val id: Long) : HomeAction data class JoinCodeSubmitted(val code: String) : HomeAction data object Refresh : HomeAction + data class HomeDetailClicked(val homeDetailType: HomeDetailType) : HomeAction } sealed interface HomeSideEffect { data object NavigateToCreate : HomeSideEffect data object NavigateToProfile : HomeSideEffect data class NavigateToDetail(val id: Long) : HomeSideEffect + data class NavigateToHomeDetail(val homeDetailType: HomeDetailType) : HomeSideEffect } diff --git a/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt b/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt index a7076634..a16cc394 100644 --- a/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt +++ b/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt @@ -37,20 +37,14 @@ import com.idiotfrogs.designsystem.theme.MSTheme import com.idiotfrogs.designsystem.util.DrawType import com.idiotfrogs.designsystem.util.noRippleClickable import com.idiotfrogs.designsystem.util.wavyStroke -import com.idiotfrogs.model.timecapsule.MyTimeCapsuleContent -import com.idiotfrogs.model.timecapsule.TimeCapsuleRole -import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus import com.idiotfrogs.model.user.ProfileResponse import com.idiotfrogs.navigation.LocalComposeMSNavigator import com.idiotfrogs.navigation.Routes import com.idiotfrogs.profile.component.ProfileCard import com.idiotfrogs.profile.component.ProfileHeader import com.idiotfrogs.resource.R -import kotlinx.datetime.TimeZone -import kotlinx.datetime.todayIn import org.orbitmvi.orbit.compose.collectAsState import org.orbitmvi.orbit.compose.collectSideEffect -import kotlin.time.Clock const val HeaderHeight = 56 @@ -69,7 +63,6 @@ fun ProfileRoute( } ProfileSideEffect.NavigateToBack -> navigator.popBackStack() ProfileSideEffect.NavigateToEditProfile -> navigator.navigate(Routes.EditProfile) - is ProfileSideEffect.NavigateToDetail -> navigator.navigate(Routes.Detail(event.id)) } } @@ -290,17 +283,6 @@ private fun ProfileScreenPreview() { email = "", isOnboarding = true ), - capsules = listOf( - MyTimeCapsuleContent( - timeCapsuleId = 0L, - title = "제목입니다. 제목입니다.", - createdAt = Clock.System.todayIn(TimeZone.currentSystemDefault()), - mainImageUrl = "", - role = TimeCapsuleRole.CONTRIBUTOR, - timeCapsuleStatus = TimeCapsuleStatus.BURIED, - stage = 1 - ) - ) ), onAction = {}, ) diff --git a/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileViewModel.kt b/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileViewModel.kt index b81e39d9..74e58d47 100644 --- a/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileViewModel.kt +++ b/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileViewModel.kt @@ -19,7 +19,6 @@ import javax.inject.Inject @HiltViewModel class ProfileViewModel @Inject constructor( - private val getMyTimeCapsuleUseCase: GetMyTimeCapsuleUseCase, private val getMyProfileUseCase: GetMyProfileUseCase, private val logoutUseCase: LogoutUseCase, private val withdrawUseCase: WithdrawUseCase @@ -44,25 +43,18 @@ class ProfileViewModel @Inject constructor( intent { reduce { state.copy(isLoading = true) } } val userDeferred = async { getMyProfileUseCase() } - val capsulesDeferred = async { getMyTimeCapsuleUseCase() } val userResult = userDeferred.await() - val capsulesResult = capsulesDeferred.await() - - val results = listOf(userResult, capsulesResult) intent { - if (results.any { it.isFailure }) { - val errorMessage = results.first { it.isFailure }.exceptionOrNull()?.message + if (userResult.isFailure) { + val errorMessage = userResult.exceptionOrNull()?.message reduce { state.copy(isLoading = false, errorMessage = errorMessage) } } else { reduce { state.copy( - data = ProfileData( - user = userResult.getOrNull(), - capsules = capsulesResult.getOrNull()?.flatMap { it.value } ?: emptyList(), - ), + data = ProfileData(user = userResult.getOrNull()), isLoading = false, errorMessage = null, ) @@ -106,7 +98,6 @@ class ProfileViewModel @Inject constructor( ProfileAction.WithdrawConfirmed -> withdraw() ProfileAction.EditProfileClicked -> intent { postSideEffect(ProfileSideEffect.NavigateToEditProfile) } ProfileAction.BackClicked -> intent { postSideEffect(ProfileSideEffect.NavigateToBack) } - is ProfileAction.TicketClicked -> intent { postSideEffect(ProfileSideEffect.NavigateToDetail(action.id))} } } } @@ -120,14 +111,12 @@ data class ProfileUiState( @Immutable data class ProfileData( - val user: ProfileResponse? = null, - val capsules: List = emptyList() + val user: ProfileResponse? = null ) sealed interface ProfileAction { data object EditProfileClicked : ProfileAction data object BackClicked : ProfileAction - data class TicketClicked(val id: Long) : ProfileAction data object LogoutConfirmed : ProfileAction data object WithdrawConfirmed : ProfileAction } @@ -135,6 +124,5 @@ sealed interface ProfileAction { sealed interface ProfileSideEffect { data object NavigateToEditProfile : ProfileSideEffect data object NavigateToBack : ProfileSideEffect - data class NavigateToDetail(val id: Long) : ProfileSideEffect data object NavigateToLogin : ProfileSideEffect } From 809f3cfb3a1a2e74adfdaf47f1160cbb258582da Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Thu, 10 Sep 2026 17:03:42 +0900 Subject: [PATCH 05/31] =?UTF-8?q?:sparkles:=20::=20=EC=98=A4=ED=94=88?= =?UTF-8?q?=EB=90=9C=20=ED=8B=B0=EC=BC=93=20=EB=B0=B0=EB=84=88=20=EC=9E=84?= =?UTF-8?q?=EC=8B=9C=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../home/component/HomeOpenedBanner.kt | 113 +++++++++++++++++ .../home/component/HomeRemindBanner.kt | 2 +- .../{HomeSmallTicket.kt => HomeTicket.kt} | 114 ++++++++++++++++-- .../com/idiotfrogs/home/home/HomeScreen.kt | 7 +- 4 files changed, 225 insertions(+), 11 deletions(-) create mode 100644 feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt rename feature/home/src/main/java/com/idiotfrogs/home/component/{HomeSmallTicket.kt => HomeTicket.kt} (71%) diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt new file mode 100644 index 00000000..f561a710 --- /dev/null +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt @@ -0,0 +1,113 @@ +package com.idiotfrogs.home.component + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.PagerState +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.layout.layout +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.util.lerp +import androidx.compose.ui.zIndex +import kotlin.math.absoluteValue + +/** 인접한 두 티켓이 서로 겹치는 폭. */ +private val TICKET_OVERLAP = 84.dp + +/** 좌/우 이웃 티켓 기울기(도). 중앙은 0도. */ +private const val SIDE_ROTATION = 15f + +/** 좌/우 이웃 티켓 투명도. 중앙은 1f(원래 색). */ +private const val SIDE_ALPHA = 0.12f + +/** 좌/우 이웃 티켓을 아래로 내리는 정도. 중앙은 0. */ +private val SIDE_OFFSET_Y = 22.dp + +/** + * 기울어진 모서리가 잘리지 않도록 페이지 위아래에 두는 여백. + * 티켓을 축소하는 대신 이만큼 Pager가 커진다. 모서리가 잘려 보이면 이 값만 키우면 된다. + */ +private val TILT_MARGIN = 44.dp + +/** + * HomeMiddleTicket이 갖고 있던 바깥 여백(27/31)에 겹침 폭의 절반을 더한 값. + * 페이지 슬롯이 그만큼 좁아져 슬롯 간격이 '티켓 폭 - TICKET_OVERLAP'이 된다. + */ +private val PAGER_PADDING = PaddingValues( + start = 27.dp + TICKET_OVERLAP / 2, + end = 31.dp + TICKET_OVERLAP / 2, +) + +@Composable +fun HomeOpenedBanner( + capsuleSteps: List, +) { + if (capsuleSteps.size == 1) { + HomeBigTicket(step = capsuleSteps.first()) + return + } + + val pagerState = rememberPagerState { capsuleSteps.size } + HorizontalPager( + modifier = Modifier.fillMaxWidth(), + state = pagerState, + contentPadding = PAGER_PADDING, + // 슬롯 밖으로 넘겨 그리는 만큼, 슬롯이 화면 밖인 페이지도 미리 구성해 가장자리 팝인을 막는다. + beyondViewportPageCount = 1, + ) { page -> + HomeMiddleTicket( + modifier = Modifier.deckPage(pagerState, page), + step = capsuleSteps[page], + ) + } +} + +/** + * 카드 덱처럼 보이도록 페이지에 적용하는 변환. + * 중앙은 정면·원래 색이고 좌/우로 갈수록 [SIDE_ROTATION]만큼 기울며 [SIDE_ALPHA]까지 옅어진다. + * 축소는 하지 않으므로 티켓이 그려지는 크기는 중앙·좌우 모두 같다. + */ +private fun Modifier.deckPage(state: PagerState, page: Int): Modifier { + val distanceFromCenter = (page - state.currentPage).absoluteValue + + return this + // 겹쳤을 때 중앙이 맨 위, 멀어질수록 아래로. 페이지끼리 정렬되려면 체인 맨 앞이어야 한다. + // 매 프레임 변하는 offsetFraction이 아니라 currentPage만 읽어 재구성을 최소화한다. + .zIndex(-distanceFromCenter.toFloat()) + // 아래로 내린 이웃 티켓까지 담기도록 하단 여백만 SIDE_OFFSET_Y 더 준다. + .padding(top = TILT_MARGIN, bottom = TILT_MARGIN + SIDE_OFFSET_Y) + // 슬롯보다 TICKET_OVERLAP만큼 넓게 측정해 좌우로 균등하게 넘겨 그린다. + // 부모에 보고하는 폭은 슬롯 그대로라 Pager의 페이지 크기는 변하지 않고 티켓끼리만 겹친다. + .layout { measurable, constraints -> + val overlap = TICKET_OVERLAP.roundToPx() + val width = constraints.maxWidth + overlap + val placeable = measurable.measure(constraints.copy(minWidth = width, maxWidth = width)) + layout(constraints.maxWidth, placeable.height) { + placeable.place(-overlap / 2, 0) + } + } + .graphicsLayer { + val offset = state.deckOffsetOf(page) + val distance = offset.absoluteValue + + rotationZ = SIDE_ROTATION * offset + translationY = SIDE_OFFSET_Y.toPx() * distance + // 겹친 wavyStroke·가이드 이미지가 따로 진해지지 않도록 레이어 단위로 알파를 준다. + alpha = lerp(1f, SIDE_ALPHA, distance) + } +} + +/** -1 = 왼쪽 이웃, 0 = 중앙, +1 = 오른쪽 이웃. 드래그 중에도 연속적인 값이다. */ +private fun PagerState.deckOffsetOf(page: Int): Float = + ((page - currentPage) - currentPageOffsetFraction).coerceIn(-1f, 1f) + +@Preview(showBackground = true, heightDp = 520) +@Composable +private fun HomeOpenedBannerPreview() { + HomeOpenedBanner(capsuleSteps = listOf(2, 3, 4)) +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt index 0ebf4887..2cebe436 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt @@ -98,6 +98,6 @@ fun HomeRemindBanner( @Preview @Composable -fun HomeRemindBannerPreview() { +private fun HomeRemindBannerPreview() { HomeRemindBanner(weather = Weather.AUTUMN) } \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeSmallTicket.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt similarity index 71% rename from feature/home/src/main/java/com/idiotfrogs/home/component/HomeSmallTicket.kt rename to feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt index bc7135d7..31a79335 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeSmallTicket.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt @@ -41,11 +41,11 @@ import com.skydoves.landscapist.glide.GlideImage /** 사진 영역에 준 offset. 가이드 이미지도 동일하게 올려 바디 하단선에 맞춘다. */ private val BODY_OFFSET_Y = (-10).dp -enum class BigGuideItem(val imgRes: Int, val height: Dp) { - STEP_2(imgRes = R.drawable.img_ticket_guide_step2, height = 328.dp), - STEP_3(imgRes = R.drawable.img_ticket_guide_step3, height = 328.dp), - STEP_4(imgRes = R.drawable.img_ticket_guide_step4, height = 328.dp), - STEP_5(imgRes = R.drawable.img_ticket_guide_step5, height = 442.dp) +enum class DefaultGuideItem(val imgRes: Int, val bigHeight: Dp, val midHeight: Dp) { + STEP_2(imgRes = R.drawable.img_ticket_guide_step2, bigHeight = 328.dp, midHeight = 302.dp), + STEP_3(imgRes = R.drawable.img_ticket_guide_step3, bigHeight = 328.dp, midHeight = 302.dp), + STEP_4(imgRes = R.drawable.img_ticket_guide_step4, bigHeight = 328.dp, midHeight = 302.dp), + STEP_5(imgRes = R.drawable.img_ticket_guide_step5, bigHeight = 442.dp, midHeight = 316.dp) } enum class SmallGuideItem(val imgRes: Int, val height: Dp) { @@ -60,7 +60,7 @@ fun HomeBigTicket( step: Int, ) { // 티켓 바디(헤더 + 사진). 가이드 이미지는 이 Box 하단을 기준으로 정렬된다. - Box(modifier = Modifier.fillMaxWidth()) { + Box(modifier = modifier.fillMaxWidth()) { Column( modifier = modifier .fillMaxWidth() @@ -96,7 +96,7 @@ fun HomeBigTicket( text = "2027. 10. 24.", fontWeight = FontWeight.Normal, fontSize = 14.dp, - color = MSTheme.color.greyG5 + color = MSTheme.color.greyG5.copy(alpha = 0.6f) ) } } @@ -133,13 +133,109 @@ fun HomeBigTicket( ) } } - BigGuideItem.entries.getOrNull(step - 1)?.let { + DefaultGuideItem.entries.getOrNull(step - 1)?.let { + Image( + modifier = Modifier + .align(Alignment.BottomCenter) + .offset(y = BODY_OFFSET_Y) + .fillMaxWidth() + .height(it.bigHeight), + painter = painterResource(it.imgRes), + contentDescription = "img_ticket_guide" + ) + } + } +} + +@Composable +fun HomeMiddleTicket( + modifier: Modifier = Modifier, + step: Int +) { + // 티켓 바디(헤더 + 사진). 가이드 이미지는 이 Box 하단을 기준으로 정렬된다. + Box(modifier = modifier.fillMaxWidth()) { + Column( + modifier = Modifier + .fillMaxWidth() + // 바깥 27/31dp는 Pager의 contentPadding으로 올라갔다(HomeOpenedBanner 참고). + // 51-27 / 53-31 이라 바디가 그려지는 위치·크기는 이전과 동일하다. + .padding(start = 24.dp, end = 22.dp) + ) { + Box( + modifier = Modifier + .zIndex(1f) + .wavyStroke( + color = MSTheme.color.greyG5, + fillColor = MSTheme.color.primaryNormal, + strokeWidth = 4.dp, + amplitude = 1.dp, + spacing = 4.dp, + ) + .fillMaxWidth() + .height(89.dp), + contentAlignment = Alignment.CenterStart + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(20.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + MSText( + text = "제목입니다. 제목입니다.", + fontWeight = FontWeight.Bold, + fontSize = 20.dp, + color = MSTheme.color.greyG5 + ) + MSText( + text = "2027. 10. 24.", + fontWeight = FontWeight.Normal, + fontSize = 14.dp, + color = MSTheme.color.greyG5.copy(alpha = 0.6f) + ) + } + } + Box( + modifier = Modifier + .offset(y = BODY_OFFSET_Y) + .wavyStroke( + strokeWidth = 4.dp, + color = MSTheme.color.greyG5, + fillColor = MSTheme.color.white, + amplitude = (1.5).dp, + spacing = 4.dp, + ) + .fillMaxWidth() + .height(278.dp) + ) { + val mask = ImageBitmap.imageResource(id = R.drawable.img_mask_main) + GlideImage( + modifier = Modifier + .graphicsLayer { compositingStrategy = CompositingStrategy.Offscreen } + .fillMaxSize() + .padding(24.dp) + .drawWithCache { + onDrawWithContent { + drawContent() + drawImage( + image = mask, + dstSize = IntSize(size.width.toInt(), size.height.toInt()), + blendMode = BlendMode.DstIn + ) + } + }, + imageModel = { R.drawable.img_sample } + ) + } + } + DefaultGuideItem.entries.getOrNull(step - 1)?.let { Image( modifier = Modifier .align(Alignment.BottomCenter) .offset(y = BODY_OFFSET_Y) + // 기존 padding(27/31)은 Pager의 contentPadding으로 옮겼다. .fillMaxWidth() - .height(it.height), + .height(it.midHeight), painter = painterResource(it.imgRes), contentDescription = "img_ticket_guide" ) diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt index 844ef047..1ab1ae45 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt @@ -42,6 +42,7 @@ import com.idiotfrogs.home.component.BottomMenu import com.idiotfrogs.home.component.HomeBigTicket import com.idiotfrogs.home.component.HomeBottomBar import com.idiotfrogs.home.component.HomeEmptyScreen +import com.idiotfrogs.home.component.HomeOpenedBanner import com.idiotfrogs.home.component.HomeRemindBanner import com.idiotfrogs.home.component.HomeSectionDivider import com.idiotfrogs.home.component.HomeSmallTicket @@ -159,7 +160,11 @@ fun HomeScreen( horizontalArrangement = Arrangement.spacedBy((-12).dp) // 줄기가 겹쳐지도록 ) { if (true) { - maxLineItem { HomeBigTicket(step = 1) } + maxLineItem { + HomeOpenedBanner( + capsuleSteps = listOf(1,2,3,4) + ) + } } if (true) { // todo: 조건 변경 maxLineItem { From 4606c377e4ab3be160dd5b8c0b73b8bedf6ae7bb Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Mon, 14 Sep 2026 10:41:22 +0900 Subject: [PATCH 06/31] =?UTF-8?q?:sparkles:=20::=20=EC=98=A4=ED=94=88?= =?UTF-8?q?=EB=90=9C=20=ED=8B=B0=EC=BC=93=20=EB=B0=B0=EB=84=88=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../home/component/HomeOpenedBanner.kt | 73 +++++-------------- 1 file changed, 19 insertions(+), 54 deletions(-) diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt index f561a710..9731859c 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt @@ -2,63 +2,48 @@ package com.idiotfrogs.home.component import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.height import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.layout.layout import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.util.lerp import androidx.compose.ui.zIndex import kotlin.math.absoluteValue -/** 인접한 두 티켓이 서로 겹치는 폭. */ -private val TICKET_OVERLAP = 84.dp - -/** 좌/우 이웃 티켓 기울기(도). 중앙은 0도. */ +// 좌우 티켓 기울기 private const val SIDE_ROTATION = 15f -/** 좌/우 이웃 티켓 투명도. 중앙은 1f(원래 색). */ +// 좌우 티켓 투명도 private const val SIDE_ALPHA = 0.12f -/** 좌/우 이웃 티켓을 아래로 내리는 정도. 중앙은 0. */ +// 좌우 티켓을 중앙에 대비해서 아래로 내릴 크기 private val SIDE_OFFSET_Y = 22.dp -/** - * 기울어진 모서리가 잘리지 않도록 페이지 위아래에 두는 여백. - * 티켓을 축소하는 대신 이만큼 Pager가 커진다. 모서리가 잘려 보이면 이 값만 키우면 된다. - */ -private val TILT_MARGIN = 44.dp - -/** - * HomeMiddleTicket이 갖고 있던 바깥 여백(27/31)에 겹침 폭의 절반을 더한 값. - * 페이지 슬롯이 그만큼 좁아져 슬롯 간격이 '티켓 폭 - TICKET_OVERLAP'이 된다. - */ -private val PAGER_PADDING = PaddingValues( - start = 27.dp + TICKET_OVERLAP / 2, - end = 31.dp + TICKET_OVERLAP / 2, -) - @Composable fun HomeOpenedBanner( + modifier: Modifier = Modifier, capsuleSteps: List, ) { + // 단일 티켓인 경우 디자인이 다름 if (capsuleSteps.size == 1) { - HomeBigTicket(step = capsuleSteps.first()) + HomeBigTicket(modifier = modifier, step = capsuleSteps.first()) return } val pagerState = rememberPagerState { capsuleSteps.size } HorizontalPager( - modifier = Modifier.fillMaxWidth(), + modifier = modifier + .fillMaxWidth() + .height(460.dp), state = pagerState, - contentPadding = PAGER_PADDING, - // 슬롯 밖으로 넘겨 그리는 만큼, 슬롯이 화면 밖인 페이지도 미리 구성해 가장자리 팝인을 막는다. - beyondViewportPageCount = 1, + contentPadding = PaddingValues(start = 27.dp, end = 31.dp), // 티켓 바깥 여백 + pageSpacing = (-84).dp, // 음수 간격이기 때문에 각 페이지가 해당 값 만큼 포개진다. + beyondViewportPageCount = 1, // 양 옆에도 보여야 하므로 해당 페이지 외 미리 로드 ) { page -> HomeMiddleTicket( modifier = Modifier.deckPage(pagerState, page), @@ -67,45 +52,25 @@ fun HomeOpenedBanner( } } -/** - * 카드 덱처럼 보이도록 페이지에 적용하는 변환. - * 중앙은 정면·원래 색이고 좌/우로 갈수록 [SIDE_ROTATION]만큼 기울며 [SIDE_ALPHA]까지 옅어진다. - * 축소는 하지 않으므로 티켓이 그려지는 크기는 중앙·좌우 모두 같다. - */ +// 포개진 카드 덱 모양으로 변환하는 함수 +// 중앙은 원본 색상이며 좌/우로 갈수록 최대 15도 기울며 0.12% 까지 옅어진다. private fun Modifier.deckPage(state: PagerState, page: Int): Modifier { + // 중앙에 있는 페이지 대비 거리 값 val distanceFromCenter = (page - state.currentPage).absoluteValue return this - // 겹쳤을 때 중앙이 맨 위, 멀어질수록 아래로. 페이지끼리 정렬되려면 체인 맨 앞이어야 한다. - // 매 프레임 변하는 offsetFraction이 아니라 currentPage만 읽어 재구성을 최소화한다. - .zIndex(-distanceFromCenter.toFloat()) - // 아래로 내린 이웃 티켓까지 담기도록 하단 여백만 SIDE_OFFSET_Y 더 준다. - .padding(top = TILT_MARGIN, bottom = TILT_MARGIN + SIDE_OFFSET_Y) - // 슬롯보다 TICKET_OVERLAP만큼 넓게 측정해 좌우로 균등하게 넘겨 그린다. - // 부모에 보고하는 폭은 슬롯 그대로라 Pager의 페이지 크기는 변하지 않고 티켓끼리만 겹친다. - .layout { measurable, constraints -> - val overlap = TICKET_OVERLAP.roundToPx() - val width = constraints.maxWidth + overlap - val placeable = measurable.measure(constraints.copy(minWidth = width, maxWidth = width)) - layout(constraints.maxWidth, placeable.height) { - placeable.place(-overlap / 2, 0) - } - } + .zIndex(-distanceFromCenter.toFloat()) // 중앙 (0)을 기준으로 음수 값 .graphicsLayer { - val offset = state.deckOffsetOf(page) + val offset = state.getOffsetDistanceInPages(page) // 중앙 기준 얼마나 떨어져 있는지 (소수점) + .coerceIn(-1f, 1f) val distance = offset.absoluteValue rotationZ = SIDE_ROTATION * offset translationY = SIDE_OFFSET_Y.toPx() * distance - // 겹친 wavyStroke·가이드 이미지가 따로 진해지지 않도록 레이어 단위로 알파를 준다. alpha = lerp(1f, SIDE_ALPHA, distance) } } -/** -1 = 왼쪽 이웃, 0 = 중앙, +1 = 오른쪽 이웃. 드래그 중에도 연속적인 값이다. */ -private fun PagerState.deckOffsetOf(page: Int): Float = - ((page - currentPage) - currentPageOffsetFraction).coerceIn(-1f, 1f) - @Preview(showBackground = true, heightDp = 520) @Composable private fun HomeOpenedBannerPreview() { From 69bf1ac7ce0bee8611f0b51d8d2256ba991417b3 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Mon, 14 Sep 2026 11:02:03 +0900 Subject: [PATCH 07/31] =?UTF-8?q?:sparkles:=20::=20=EC=98=A4=ED=94=88?= =?UTF-8?q?=EB=90=9C=20=ED=8B=B0=EC=BC=93=20=EC=BD=9C=EC=95=84=EC=9B=83=20?= =?UTF-8?q?=EB=B0=8F=20=EB=B0=B0=EA=B2=BD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/res/drawable/bg_callout.png | Bin 0 -> 1812 bytes .../src/main/res/drawable/bg_light.png | Bin 0 -> 92517 bytes .../home/component/HomeOpenedBanner.kt | 94 ++++++++++++++---- 3 files changed, 75 insertions(+), 19 deletions(-) create mode 100644 common/resource/src/main/res/drawable/bg_callout.png create mode 100644 common/resource/src/main/res/drawable/bg_light.png diff --git a/common/resource/src/main/res/drawable/bg_callout.png b/common/resource/src/main/res/drawable/bg_callout.png new file mode 100644 index 0000000000000000000000000000000000000000..1525bbcdae439aea82190f51152ca68db4f9bea4 GIT binary patch literal 1812 zcmV+v2kZEWP)Y9# zvT6JQ?wTPHx+$V2P}4T0NduS~Y!?nqQJc6JAc3+QtfgI%p|oyn(=lpdT@BUPZkhn{ z2i%_TefK`zJO&vMii78q9Nv5P{UUka`QCHxy+nc_2!bF8f*=TjAP9mW2!bF8f*=Tj zAP9mW2!bF8f*=TjAP9mW2!bG#7Mn;A)&_^8i=&=nhT|s36i3XQ>*p9CL0BUovSyAP zhe8}UT&MQz->b?ZW%{^!_bz>G&QEh>I2uS0R*5)yqS7L(sM@KwM;ni+?4v)`Z{y03gDP>d$%+)BbP7G#F%Nf15SFHyLyPJ}$7wCHmQPP>F}}HPuS&G~g45A` zxyKjeh2e{~9Zu?tG0u@BPuvZ8%MQ18t3z)73uw~BD$0Q`RgIwyM5Q;hqRNI zbWU(|lUF4P8y|dkH=RyXJRbKObGaN13=BXU`nbA=h1klZic}PT^gX_%L5Q1 z1PFmm6?%!fGB)V<=hZd4e4B-xws1axzP~I|&Q{x}j&O2H^H$tW!bSmIW*d2FTeAt* zY;)|0ip8jEYim_37E>%lH9bA8qS5Gr?%5VFHjX5Y1=BzGasPzQ0nVBP6M{oB%5Ldb zM-&j}DEj%ssF^Njjp zU#^F9AVlkQ=zeV*<{A;`p0N!LcKh8kgc+!`7hQ!Rlmsq$y723UbIBGhzHt1(0>yb$ z)M4P3=Kk7ZUW)0!7&{%kT(iq>YA6rrNHnGEht{f!XxY{^Ws%`xv;LJ>|AppF#ina z!?+`6Ubrjv&jkb-r4_QdK-(0@`(_{c!y9HFYtOLs2W>aa@dPa+9}u2;rWpJo7G>TE z$ODkma66Z%v1o@hTjfys${{DVqry~?Fx{-wl0b*Os{erMs_~{wC zW2{>YER@J$i~KQ6V6lW0uEMH#f+-9sMS(?Q&f%E36dyk)gCo!wY7@cdnHBf5qkx( zH$f02c>BJ8!+W3SJohV%Uus?>FF;K|Cd@KDE^>NWZQH=y;*YJG1=Hg1B@eL9EP?YZ`L z-qf~YH-q_~o4~T$6(0l3+nW4f7iVn|1&@bI=UR0a_G@H8=;6}KCb~^>Z(K`jL)RLU z$MDo<&yV(T*QV0$4W|8ePUXE_LQcI6kFsUaLFt^U%I1~~mJJ81m5FG9!CWrkj}hjr z*iwUSlJY+;ttDkJNSO5*5yY|y$XR?}Kz>*%O}=AITM>Z8je^TmEE<5;@#5$WOd1M_ z8JE2pu0Z!p`-8LL4UmtyZ6ymLOS5RCaZ2XeEX9rCh3NjaT2|;lS{p6w0?R$j6Vf?d z@D)}omxeWjwG2ZBC%4nJ-7(vN-T2+Ob;JGZ2Bn)L@Ur&_S9v;LMKW(|#*4NL3A^1} zusKYgdVB~8DEAp^-dlId*=&7_YwP10Jgs^vYjSxPclxX*1P$tUI-TqP=sUwBlN3_7 zOIg1k-~O-3?}_kr0MsNWT%-RZ$d>>dQ@nbD{rby>*7z)DF%VLglOYQY`o14s0V>Qb z(CPGzo|eyg3%_yl1)Q$egQn=ZUZ&@X5caqG=PJ*jNT{+X?dIj|pOG=LbA*MYfVT`O zH-MYlqZVY3z1i3Z>j{ljZU=;F9YnX&O3|%Yz`X5u3F|?fL3}t29|on>6InydI=GJj z?JPw+wtqJsK}(;$vf2~Rrb)-GBy{I9<^q7A!XGS91>N9-P?&9bxs814+b2y|w0gO~ z*qbAj>mHI&27|slw@-Yv-%mr=8|tBLC&h=UdZ8Dq@hWlW>PYEEO?!{=qUBHhmzWbP z+%f30vK^92mF@St?rUmwBcokWUz4j7bF?@%6O;3aO6WC1Sph#4`B*yAkT)Ar8qWM_3&(SF#8WfGCbGI6 zH}@TA1N6XoN_87G3^7HBgg2F;@R+Tx%ek?MAT6A=LB=L|C}nCq=lJz_?)6`#cpwsV zxi}BSOzn&wd;zj?zSfXgUha(e8mcmeEL|R~fY2GQ9brQWp9?Mi9gMlKLIm-PQ)LlC z-em4_`Dwo;g*6+(I%t{cG{D5ntheHmgLMwf!AcNSdU#&adTpwuQc*%zo`G*(t;b#< zJYm@<%@P)A-PT31SkiIBeMG>u%5#JdcJ*+rFS$BhSWV1u`@g~Dqn%w1f?QjKpgi*ze~=Tb@JE)a=LK~#RAj3%EJ{FoH! zDGqKJqVvAW_`&4?`OHSNjLyl#Pk+0S=%T;YLn8%I8n25mC))$*6MOt0^qucigcm^N zgT#Rr!2x9{+sNX?(49wr9&BaH{u&pe)XSNbb+T5Fm!~W$Dw>y`Pg-jMV-djLAPIj+ zIgY4Myq|WnFcoOY*(#=FyngctGA$}ZwAe0z4=tb31)Zz8;%-uW02J7H&JVWD2j>~D z-&?m#7i7w3S%ekID>Ukwt4tFCOd}ThKmjZdQ*bg|rypv)eO{+v@{ZBAsJJ@7-?^8y z(!RS8Em8+P?h_1S{hdV?BQ`=Ok5nSuru&S`{V9xnw24nt~k@C2qk}xdB*|z z83(&S(79U`UGwC%qFUlpH?~k|Rhw>^#*o)-8rwXQzkSO@fCmU=kCV%F72dWT>+h<`>+&CP~C;<<`Y z_;x%<_e)YN_j)_`no?sFJ6_sf>%TpIjA`~2K|qdpFK#ay_gE;N!RpMyP6MvysL%dO z-<%81eb^=jtRTHHjPh`@KZMzQKZ01Q8k}rcun{O=swTd!c91)Z82PtusT<+hcfAHP=m9^oiRn z3{qJ&512~1Ugo*Bt>@}@g18fo2$&lnmIG`ZA5kzgJ|;UEy}#Zh`7!ru07;}e_dGn2 zP{;l2O>4%EtJDX&fv~M}fCINca&V@TyStUsbwgz>67!dMb7Bn)3&rrfw?F6|H#sD( z(dB+-lv8bDm=rsY2TpSQCrxVPD0_qopT_mTm7kIs=4dt9Wl3Z2UcM`4)wp_AI+z?P zSkt?MJm;n6f&TG5fm!DSU0-YxFP0;Cj=}%oGBHE}w6~f-8-80n=wg62v`XnDZs(JL z>6K9~2(?Jq^rlAXXQJQ@|L!1a$H2u@m!sw7GbBv;Y#6+!n-vwPoq4lvxNr} z+H?tT)C412=cvc2E4#wG~%Gj>%~Q>-qb#xk12b@qn`uR8s)d9DzI`h@WHs z;~Z|^L}zw(%{LO+Zmwu=EXf3AqIP7@&7gG>mz$!%Uv8aO7RugN(vZ!|i4Iq}54ou2 z_B0S-f4AwQ>*mhcswxs6TN;a0MgzpWCH6Z_sX7g77p@EamyeVp@?iVdGq@X6ziT@7 zZncdG-Gz85GT}|e`7H9G!F8L&dSDt}iZbnGf#(g}4iRy~t?a*Mx#H&m<|>4WI<|Vh zILYJ8w)QxTJNg@$L7C@HdwOs1vvb{Y7SHS3W?_iSozhB^C+8P|Xgupk1&cM6>JqZz zFc&r!7_b=xjusmMYn{Z=m!Y0i=o#q|5N<^<*=Zwl{Ji(2vU`svW)6HZ-++b})o-_~ zyAifM?NKl;!sWqk`ffxU1`jKbWu_w>57r^+3hS?$^x{ilSW!9{yRN8ZSVVnm5m{(# z5)Y3``P7u}cF!h^3DJOdtCyFFD1yOeBX}^VRPr)CZ(q}66!aSAjLEvv+`K_9$6Hg0 zU0e{pUL@!56*wX}RGD7tJAHNyS01CS9X#(zjLB5vn)p>B*ze3G)6JBPl62RiSm++X zUW@ZmiX*OM<0g(UMDm;~ob>QbX$vw$rjY0>7+F1xQzYVziJQmsL~rUrg2O9&#(DKum=%b|NcmWiPz2^URR4#j#-=sOh@tdiZq6=JdRpxIY7d zHmvULf^yN21_zpmdBA??D0NYVOKzFoN%rLd?xNo8+o3%`-P`S23K+Ol-RfYz-&1vA zW#b3KpX$v$HMAYylvg-fRSZ^h?m1lDE*nw-loPryhK7TdvdH3!G>)+kldqXsP~dJQ z1fIM2tp?XCG+kEfyMe)p{`};w<{EQi5Xv~#Z!|JAc6f_|ui)G6@w_@fY_msTtMc|=+=2XN z&E^R@r~!QKpE;*67chsZ>J%L|X@L9pHktb#nVrI>HdvUVy?ay;3!j;j^sO5{6G|Wp5m0jb# zDsDjG2^xWleY%MZLm_APwVaJdZBATJh>OCNv8~`8^x{lm`S=APcEYs#A`=95E^5!~ z8A3?rcG_lcPU5UTLCRYlTScMWpX0$EqYq!{bfjx886~Al6-#L3x-v)=i}vC|e0rZe zR)Hs^h!2nbDa~Kol~|SVF8SME^`*mNiWaCQf>nt$`)Qr{{0jWLMga(P6iy}|G_pZK zh1qJBe2Sd+X9sJVPJRmqy==lF2x9ZC{?Y`j@ME(pKA65K@2|~6&Mix#Som^xf?Z7e zF+pLgZQTw1L+>UlXQ9zEboV1}F&v%XUbu%0WZm4!3-B1b?-|;DK!8!)DCb4Y36^@( zs!Y)3P=h&hx-*HH80Xnigt_HZJV`}ek;ggIO_{7A9pB;({ypc(&*^~?Z9=@wK{j0g zE=(UKT;?3bK=_Dtr*q)ln>ADEVehCOeA5Z)($OQJb+2=M9?Q%l%Kck~(c+JLF4*H2 z?8(KieXs}-K|{we3XP`2G&rGhj#|ZW`CLUAQiLVAL-PSqkTb{5TK9LEQ=`X1|Ek2s z0qk8L^r>UghUT~W1rf=Op>2W0lF8C1gL;-I-S_y0O=(?!2S>m{W5IX2A5BU+>sRgny}a&fZ0@X;5vQOe#}1s8Rslz&8us^z*_rp6~N zmzR;U42|XVjL)t-;ReMUm~SXRzE5;402|<`M>YAYjW|v#Wp3j2RM~TiWTF|?(0B0P zvl;rO4N~Q#Z8_T%a5lP`e+_eR+HrQCnXajb>tk)TL+o`jE~j~TES&UTTNrk?_tst- z3%CqMMTB<$nz-degj3)@mR~T&D&f9uG1rumDqF^ z@vg&vU;qK_GaoY`MliStkkpd>-6_~iLG8%(1fA>=3ntu9eq#k4BesYx?b)zUml!3R z`J7!;zI$1`?x1+{%R@JP1jm;aX6k^5&jyDpM-$6PX}M^J(%F2j`DO*Sh`S9D899tc zcDZaIdJmH24wuINPUqwl(tFdS!xPJMI$Ap5t=TE0ia@wUWGPWL~?e46&De(gtqF9>S&#-u3oZR?_ zv^t0y|2*fbAA55ZJf%Lf%Jv-fn5V5FKv`D^6p?W(gbnEkWas1PKaR~ZC+c_O*Qv3-#YD;MT>&FQRX0Qv2us5ro z`*2?~EvA6~@ju5x(EF%!?h^aH$^B$Kpl}h{#k0u5Y1_Y9ScMEf62PuzOAi=Z{Us!O zz zknw`w8+KhLvS6xYukJdGc85Kwn0k9GgKBb5a59?cTnZxSi7^(PdMWs#%4nt!IDaQM zX962gcZ_@LpqV|BZm6;#(RoF=sY~jhGZ?R>jQtYsC_Rf0iq%`j9qx5Hl~x~}r=N^3 zH**=&f&6K4D6=dBQ$0OJf3BR3?jDDjok%ISLCHd+ous=M+6rW~1cvHGDA+m|w%^MPAAc+Jl$N_ax zhRSLeuj*`n@DCoi|9Z`~JwCxySn}QJSNW3CVkBOG2BM$rb-}=s!fWk(821nRz4Eg) zpzx5Ifqg3No$mc$EN(m+bFU-P;ns&!WwreK&xf}SI9g16JdH4?%Hu$iAj6-*+g7&+ zfLGJ;rw0**#*+(TGN5~L_2s*9efVHoYc_V&NSH@vn&ZzROy9lQ1y@GRi{4)bw!I&=T3}v^u&OKG1mweojrI|VXt2>sV@}Em*_jg}+1A`D5R<<2N+fBfS*7jWZUZxDH+nZxv}T7$dVKupG^byV)HEa5QRbo zr!QOZehz$L0OYU<&?S}JjvjCcUBjJYrY{hoA~3LFP80DgGqUG$m#}OLXQGCOn9c6~ zk($;MQJfB6`CV|*?bSd4B(~+T<$77Za*b# zp>tfOr&V)>euQ=Asm)N}c9$Rrcwd~w=7OQWS#y8^?nZ)Z!{J7uJ; zw3>i6y&8f#tzf^ho4f3OdL2VNTpUGo9{rSfu zdE2`zEpp#ZhKibwJkP(m4D4XiDryUgwf`9Z>B1f+A1T*tX#>$mM)TSpKm23rUuWv@ zu;ShK<`Ajy!6i@eoH=;=r2T47P()t^$Hr_e=FCZq4ptA5P{{3MWAU-~T)4Ps+d#rq zo)u~nA$1m#osYwVG!ZpL-*QP_jT8=LKApR3`#e*Yx2j|mneE`cQHl# zUO^#xYoC)h_u2X2s-Me_W>u4Jn}ByCN$$|TejEd12n|AFEnA+i)Q3#`=U=|aRp|e+ zZQ37;vk=7YPVD05@TQK$d-E67a*kDDzO<>Zq&Y(eyyj~{x{W#9T4i&mtt1XBOjdmxXg3- z+@p7g&aS%@-J5K@$4E7Es;7_*4-xnRp zEP8Tf0z}zVK8hKgBuV<~f9L1ui(UaNfSxx5(BGU!ryXU3F_dd&V=8TtYx4ATKBzVWsxZZeztU{we2Oz(hR96SmE+6lnS5%>_V8>xI%S*;PCpQ8YUJ^=V zrh`7l@3`igTXj;cw|wM8(zRhlq^EnP`*z27W7ad%Zw^F{YYbD#$mPwGx}sR6gW7Mb zcu9e8!l8{XDKD<_QgRB2`{!c*R66^FZAC=A{yhJSe!hoEGh$dtt`F=oQG?4WIk;|bX5xU zr8j||QI7@5{UN#VrFq`{eQr}msLVW}U`o`f$s#Gtry`RHcHrIlk#W)iQ#=gY=V)im zLd+w8Ch{fI$H@LlTZuRDNACh;_tmy<7zhos`xs8dU|x2ej>7E?fsS2Pyb@w#E=y!w z>`ukEt?6JVp8Y)zJ{OP_?hM)hJjiRWFOz3K_D4g##bUhoO-)0~+uq5z{h>(WH8`?6xq> zS}e7eA+$U}uLCpxz#Jr-P^VPeV(ObqR~`ImOrTR(u^!Azb7? z5USXHH;6z~u&<@#DaeX5q+%SMW%n~=)GD*L>=#jr1MWBU{D_!cl1{&34TS#DCU7H$ z2Is4QWwvdhECgkM3M?S|g6>lH4#f{RVW{OEQ)H}a1+#E=c7gVP(SJYMC&qyid}6dO zb}L?hT7jlT;NeBhviI7yPm2SZem*`nhYvcKU7g395fJXq_k8CTx<7!{obG%Qy8h30l2W0J)s8sUgAJ^@cx9c<0m1 z%7=CnpM@5k{`+6TDmQDFL>#AXmbWUQS2lUg1Ctemuyb`SelKE?Y~-P^$rHA5=3OfW z-Ix(c?4?(BT4@0(=S|r5xmjDJ`Al%|wVTEDBz5`n7pFIb*%j34ci2?iEHJy_tE%&h z%f+!!4muI(Vo)=?&Qf-*yqW=7eTHYIOT(Y~@P*ov)ld4o+THZux)$q3R~p?gcwhBT zjX${yr5if?6py?z!Q3pVF@75xc|D2k%ZKyB#j{N#^?2n?6|t}Wq}AzONDum6VWwBw zgKU_`cD>FPl6*iD>Q&*LIJ#8VQTvK}o}LD6Rj<4E7X7d}5_TiW{Xt{BZfuJ)o?A)8 znZql;poBgxDv|hPj&j#XHDkT^0lbm4OC_;H_x#`BQQY^JH^j@md==;fs^RLi=# zB-I`|3+|{mrD0E}VW!KC_`x_EezcDpo>*nemaM)l$TK8eF}w_(Vje=3l zAGtlGiyo9amH|kM&o!BDko@6Dzu}0S;2}1%o%2Sz%&dU``67 z0jkfi!Of$Gf8;jOoWwgT(vZ47O5av?W11hH3%R@TE>SA06uy4~fGI&@26u1o#%#aG zZCXRECLR>A6mea!;G^+&e{?OlpESEKBy!6$M>Td1vB0^17KSv~aY@;~@2FCv9ZU+< z@JH`!Wlg-O9iUW-d^78J`qKKnoov!qX6M zfUcm`xnnF1Tnr>3q%`kW5>8^@!QGvGRx1`zzr|dH`CbQ&41Kv z8IlVZfAI_1S>JDCnF(w`-n>QFR6yziOVGtn0(KE5`2GES;un(BXA6{4t53z$t1vH; zUZ}~v*k~z$2>&y+sY(Lm)E(!^*tTr>N&|Coeja0LHDC2-HjImu1tI;ZE=}V-+54tL zNYUueAY94*f-aZwpM_MHf%>ai<4srVOfT=h=(D0QTWd@2!@bZ|Ls)uem*II^mj-f3t`4-M^{p6;Bz{QIOYZ2?uZJUFXpoQu%&wl)RgzVB2rYe-^WzNI9M?_wgmw z#F9AU&sNEE#`P09%#J~S`@d*p?BH&!H~2)Lhg?=2k36W-{Qc()Y#Zun$|{- zTXVfUOq8d%UCio9>3QAo{3Y-FJP2?TdE>=Sp#S2MU38%I7wxCPW#GTxVU}HAH8{5gFE4f~%(kk4!O(9kB9PHl&KaTcYeI7qM zBK_%C9uX2K_q$craID0+roHF=eAyCnq87w?DenhHKd9ly5e`Ym`RxXI zXDn8W?J~Rbv#bY!tDXb^nl8Q-J36)GjSF>r*zV{MGsUb>KS2R^@=(b7s$@3Ha8%`c z(u=fQEMT2z6q~xe43!{|D2*VF9%SQij7z zAb+HtjK$hZ6Y)2(0ddW%wrp{_ara@Q-p2PZ2`zaNKA13$Uq#Vtg)PMYPOMuwroht~ z&+mF)vZCR4D~2K+BCYw}QZ#PF14-K4DS@{s)9&SlQWGUxBHrKgpuw~~bZbh9^?6an zxK3QTg?u#=L%J&_++`d2m(!>}t?MU6u&mr|oTxEXp&Khz$9AAlu9#%-{XDj!CDeLd zbL2yLpVbh-FH>!wU-Ca1sMA#W;7DWsq~^g@{^T!TZ-No%-phz6>Nh8!QnY;14UyZn zHD38DwN6@7nUiN0Dl>Pb`fc{m3}bAFdUUUs~b(>h;K)u*zJ zN!B*|ED$6@I=mKj#YQp54UOQGh-7xVKxLCE1; zm3^&oECMgq+6pnf*G2XB&PSdO%Ih}%kIzO~joA!lRu$jAU2@tQIg}Rj6y=Z;bB`g_ z>S-)_^jQ3iWC~&0;T!luL|L@W+ycO?{auU4*Ep!=@2BKsX8Lz~IJ=Ni+AiuLqJ=>` z5`7lo8FQ93^^Nj({ZAA`Wu&D{S+JXaqal1AIH|I!I_io$vrR}R)8bZTdnH89Xshpi zNU5=e^A4it-UXo>G_C&fSo>+m-1F31f8L^OOw@;Uuhp0HTr0|f7?Kyag3f%T1j>h# zoKBb@&UbyjxBEmb!@r(M;oC+Pym=yyDi)jIx7~ZJ3+$6%UjFJ_#QAuyp-*T6*!f>= zm;GOes<4;)Z{huzeL5XkWX$l{$&ahW!umBoGpZHp3vns5ZGL9-2cvcEK~QYBQc|S! z7;xvu>QD1!#6wTT2S0;j0)FLv;xOT>h-Hs&QVZZ}2vUU|mF=}TrZcIK2(ierh+XWQ zn6;uyKi0aQuQ4_e;(pe1DJe%ruY&9w%(~Konx643^5%%McuFn_*hcl+U4r%$sv*hc zkY0N|5n1Wg#$`Qy16Li3dN;P2XDJ$cQo%*a!f4~`1!MA&WZdPQOqhr1sNTURt0E=zphX*W~I?UiBm{D3uIB?5E#Obx#X*%WXqJGjP-2Xx6LHolw@U8nuutt+ zx;`Oe+N#kilMUcNx+9!!3x{9&H@qOV!VmHK^pu`2bn%MCr!B1CW zxjNf5!}D;p3l6@Y*2tTyZqa6EBKnm+PpIwPRk6SWiN~BpBz$igC&zMzqV!TK1o3J2 zzb{;hS#TR1Q{ktAhy1H2n4M)e`;wGCa9C+>NH(!Nfx!;rliLpo)(tKR&6PJNgG&I5 z&*b26WIY_C9_rE}i2ccyY*c-`e{p7h$;LiM83-rHeyjSn(CMD`ygcqka7bU zIT%c_zdHD%Eg-#fE#Q?o`<*DeQ3x_l0gf^we|R z`%TA4_#8)8FM8!+pC^~SG#DS+gVi{|scnS=tGK1BEp7f|eiZj-g5CDxlgt>Gf8X`# zB04mb+X`n*CuJ)do;x{~v<2;p)R^|sr~9#27IuA;sHoeYyKm1cdDefeY}q_&1a*7! zqZt-pfJRC8%a4tH)D?p_`*K3b-Bu@eq`uBp-`DAGb!gD$m}277I^#(!@_hFj>FG0cW0yI5%c^K3a)64ecZ&2n%Kz0Ob5wbZNBPcnut2@(FG5bxs)DgVm*4%L)!?yE^4nbH&6jcM9uE~= zinvKvdktdemJ|}c%Ui$emgWnVqPEOFyau%EX(!lxcZ#+fb{8-)$Zgkl_@y@?CC-}o z?vvU!DdSJKC=OO)%~*T}hDkL?ST3Y0h616^WWiaZ;(5!L^SIWUoA#ZD zPW=@34L5iy?&fpG(dp@hXS?LKcS$2|eGXA?zt$6hJE?BeJ)FeVx3%&?A3xh*y_}!w zYLtkckFhO@VOx)_gGPtS#*bPN;xcLjH_)@?3+XS6X)&=z_#DYY`wjFFwm6r{K~>QM zu=>GAs$EgpeG@rQ^Tzis?#Y_mqh+xyC5bJbW3zx^r=#8h-l@0LXq`sRx7zxvkB-C{ z{u7Sb01SX^`1ux*%h8MqYkrghOy>SyzYO6>%QLOebwdyo-(}#r1g;=|ZSu(Yx2s_+ z#D|67@(|oAKYT@V=lo^AO!6BcT6*K}qU8o3N>>fcp4_IBxk%NJ=0k6Xzjat?d^Srr zUHf3?t@&5>t@&EFnpX_&9_2s%I}-lr^VQ&FR_;V5M~j;tDZinwHQZWm@l1wj7B~^D z&_C|7BWSP17*y?5e^T*W!iyUlkc8hQ3wmvH3$Y7QiAbiCTBp0{%$ z0LA_?8BxWkO;7n^bDe1y)I2|>c}>4)4VF0QnZKkt3o4;inS zTlNFyy?!cbT0Y1cKsR!;Rh-1>exYADX6034tWy<-@UxH@F%FG%DpZ*2xmK>vpE$*6 zkCUr8tDR+&70DVa<&@>-Og&-KF>iUtvuf5ez6FoFeoJa@BYg7u;kZT3fMiVgjA`*% z7fSSFn(x?L(Do{kh&{5lS-!Jr{dpo@CL$63*1|q5J5K2*12(2UlO|y}Wti(XZ!SB{ z-}j05&o9y}Y!GR8x2vo)uZH)*$7eQ~ArbRmRPCY_a3FCE`$XR4~fP=~_64p6St zqKU+hro$>z#4J?*Zr~0_JJVF1bphSCT!OoUW#Dy7PxNW@PCXPceCCfvWQS#RuPW~<{sSjn3LCFhwR_~;MHdBq_AX6xBIeFG56W~gEN|kecPUU+OEy&F zN2ezX!#ugu*8*2ayX$dIo|Z(qF!8$-y?V?~GNQ6SPy9$J;We*JxTwc6Te9@HMG#Wmq4H;gLLNuF)66e~7+1dELD;+u`_uPV!`efOxBq)R zpygwzvHinAjuxVH1zk(Y^?kn>Tki|ax@V!v)ScG~XYGdqjJw+S3Fq?yr4#vaSxuhK zMp`BAH@M23_f>Zl!?`dl=@s5sh-=?8?n~_a?$WL=CX6kxeYX&{4u3ertM&sujq}B& zVO|6p(FWl!vz^D*HzfrKl*LvbEby`IrH4H1_L$NQ3v_hihM z{jw|cZbc<)vPY(Ocdp<5CiI50$bQr_SlgLZKVrs^l>1(ECq%B0V>8pU)uiZ@2NcU= z0Z({inWfT1jnJppp~ymS_pj#=|W@H?t6YSCT~~O-ZVKbKU;VV zGVMfE_O|y!U_bvTT?}f!uW>ffBM6<|6T1tXV2c`keT}sLYacpov@4?M4#PcbnxYmuy+ zauELHn`eej+=hVt#8}+u%TRN;ys79AA?MruJ=jZ zazmxP;@2O%w&9ywtXIsNMpR`S@Pu?4`_1!SydXzqnBM4`w+A$x%Ir8vx-T zn9xSEc@X(I^veJIaIN#jjS<0v1m&7Z1qo3INMvp(Ivp!1h)j}{G?liCI zH|65lI;P91AX?bHtm3#SluEB9`I2klFvJ0&6=;L^rH`v$8!LSNLQSMv;+@$_?Eae` z2ip3!D34cHMrIj#d{h2>Vv4ep4i91i70zFWJiN&ZZ=R42?fb3SjuI>4ZeEtMEX-Tq zcbm(xABwh}w5M{Bp+R^{#97BX*UZESiVydQPobf^NaR!fHy0V7j){~N8Ho7zS-$Sx z(R7oM_$BPYrk={VOeYIxQxvA4!gEp{k!Z?>K-|69pv(p{b^)n$(f0vs|Iy38$obsD zn60ZvP8U~!jvjS-4=5K3p;S#=N%w6hFV~ZN$oK`02G5s|`03hNeP3F5j03deKYZRQ zqtOz6%h4E8IKzUMb%J`;Gr6aVCBFReG5GA3?8t|v$}ZHfsk3m+)DUv^YpH7a*<(J~ z8x{2=i&LmbXktn5*w=nC*0@%t_r|IeQQ9=YTv(fCw-*NC5*ZIGs}%pMi~mH)DS2WO z4rt~84Mx8?(pKxZGhsO6+^)3sx7y8rHu!Ul?6XJgB-$P}NenBMSdEW~<9eo#E5kU{ z3A&Kgy!P`brj&u3t$BE|3&)Tz3=?9+79JrK2t9kCvK72W$zcG5L<*^f}2WVgZ zR3HATXs$xr*DEN2R_Hn>tT;a)@NpudR;8cy==|NZQaNh9=8Wd7Z=U3cffsb=nmVMX zJy!Cb(R*OO1MwBDNIPsxtw2-X7$5g4wDaY~km4{sI8BmOS!(#lFdg$mZ}$^8V{PP` z`)tAY8d18)f;d+L4Qc1^OFL^pnx3j1)#it8{GDcgCr+E25hG&KhW;o zZKgBL8Iw!Ne!-^Vb)%lOMHZDYnE&Rnxz#D1L!mpOYBfdE3r0RKM<$z}0X51M-y8^l zSXd@w_^7Uac>C%ecepEhSDNrpS)ENdV6|YP7G^Bc-OA^uZhJ9mp&)l}x?w8L!0ztO zSJ4*6&~Ll-P9f2SGzX!}`To=O`^(~xkNv~TQ+S85=_<=lOt1P`W(`GZPc1Z22={#? z&p`DbSzlH-5tm)H>4{y3H06c0d6W8W53Npg+l7dK+HS4Pve1pRM}sFS zd?n+4iwgt+-alJoA1k9Je~(6!!By08+&m)~*Ph8(#ZC|Tm>#VO7Hju$h?k<}d@F0j z4JM(_b9qr^fn(IMyXb&Z7tYWJ0X2jDGnPXQuUCY3g7j|gVJv8~Z2XU7+F;UeL8_17>d zf8`#3uKAV}SNb7pBWXR8K>c5xN9N+HuuGFnxTzfZg|567x2W+odpZgeH>lu1%& z!S8qNmt-MNc*TOdPJd8Y$_psBUzz+1DyBxhaPp_ip2hQDIR!}0Q%ser{rLK3dvN?d zz)j-g&+BS)`$dhMeE-@-$|s`xO;tZzqbwF`-8)3`!r!HLrcmj5q(QQT$jSOff4}WX zD^{oX&|qMuoq24-H1m~e{aGZHum)nIQ^2+UflJPDUiR*Hl(;qGbLjQ09A#3ue}{^V z&8zUwhuySY=tXYA=ECjo2_1Ue%E2mE+j=e6@zdHEb18wjHLg38hw+WFn6U4HN4(py zLwPIfeo^{I4%0kh%|o-yzTGfD!T~GUTCFBkVvJ|*Nc@7M29?b9XV1(xTB;Oe6EM-@ zOe!tG-V`+_^Q1S_Br0<2(5q&CaW+7+5j8Y#zg746R3W?MvH0vUR^VnW@SY;fIX|Io z`<`>_RsdQlFVy*WIG>{cS(!BKBU<#(;M=x2m6{^6v|?d4wt{m7wn~8YTn&v5q*z&B z5ec=~3~nwh)2a7@G%`~(p0=xnjWvqxweBUn(4k^HW|cxmO{H6YYk9!p*~`zis$%gh zQU1p@tH_pGyq0Kc^ID!l=chp5_uZ@Hk5`k&qdnW2pB^uO^-yDNE%>n>J(c0Tm#WiG z*0F+22A4lV2fLM|)_#yEF17^%%CCKyXx&v}Jud*ZQ6Img`Oq!Wf25~)-|fHE@T*Wx zpmX8p?ubp*GZA;aS4zhMkK7cN1xC3A<04Cey!Nu8-2NSj?;-;VazvNfi~qYPno;$I zfBIK$$_i0BaUvkyw=_fId+>AFCO%|2H~Ny{(THQ`;zb`PuC>L?oP}CpGqAW}U(38m zi7{&=yx^vK z<@qTizx@z`+x~|0Rk8xQX?>kRh1~7tI0x=zoArU>uA;~Dajkxe1jE($68)=VogENYv?$5 z0O-EjxYdow3;m%ka{TlDt3m3FbjfXgjj+%g4~o&-lC}s}?d+beGBQ(79-kKJV3l8i z?}iDY8LIJsad6Gf@W%F9OrTi%&@LW!s$-E<{vnW-{AN!9v$>NQh*?=xkoy)ISU$+< zO0db$s`Z_Z$-Iwi<@Ytb^7cRbTD%`67pd%d?4#nWCYd z)c>6;LMO9p8R7+za!1uir5{CGw`o9IdhFkMD3xR#5~NnKWzvoo@2jjboyf}XA8y~Q zj*kS@4G#q20k?BVS|3IeM``$*wP@KNT-+BP*<*${`KFo9LO!o`eY3zt<-LUit<&SQ^ zdnwNP8Xnr!u)plBYPVFHYzW6W}&2N;=`bDhP zkn91m0rrG#$GbGNJE~#fN5)=gedffzu%F_7twaM-uu=2j%AekV{w2>|i3fAuKHH`A zN_(vhD1D0YAV8uFrBh)`5q@bgUPop{vn96q3tQ>s7wm~Itvkm}aJd#AI_fky)cV$H zN`Is0svUf9u(H&<9gzMf&P#37Kg~<^l;s_=UNKnotRuUI`Oj3%pr&1~8EKWhYx02r zjUktM(OGIGXYUVC?2Wr<+?eS>A_7I4Rle*9PKsy&NO8H{ECJNQGlK?wb`B)HRw(|S zFA+)wpTIzlPb>|$(}8QviP}F2MUknGiDW!He}M{$(W&4j{_5Z=pe?*{ z$0qPqLp=j)VyM(9{^QA zs=qsMO>jyu2xGLm!5KZaQy4h^Q0uA26_&W-teSV2=AFP|Rhe~uPwM1YPT+FGOn>&2 zH+a=>7tIig6;;(NF%_H=`{^=vKs+jIuurTj=oBOV4AvoN;=_cQI z4aWh(uC`habb+S}{cJUdw%{=frc5c6#hIh=QOvp^{G_9pCFG7r{-#3`km-C9-)T^f zIxmMsx*RUxFd&b3fzsm%3X|)vA^+t#k0)dP{BwX0?>@nt_u#?P2ic5wsxAB84EYCp zQxGygdh`(;{(y%cKLq%LJWreVb9x7tpVKaXw|$wHr!Ntc3tH09LWxk5K#X4(N5?sC zMwXK3o-6VE*CK=?5) zA4v`Y*=atXh>1pC&FSD$c70`^Mr<-n>^a1^NirlUomXX+PFTp7*vsk(5NJzCrw#Yx z)1+4`58N6HbfsN`k==cK|FBRWd4=Sw=9%%ceyzgF@U!le{Fp1QxE`$&#Cvw~juf$F zDr5=}E;5PXc>){dB$-3;7~NQipDF798P3Ew;Tb}6nEI2|$F=F7wFBg-KvO@HFSkYP ztob54>ZCyL4EBOcDo(ppkt}6Q6voc3IBN0i@nbaOpTU%t7(=l#z&M8=dZ**cJXFhb zB+XHT0O}tPBLoXlIHBq6#?QlJZTj};T@TGzyS~^QND33DLB=B~U4Zth&_ zyalx?d7Gmn*V*=68MulVB4gV#;NQVEeY~qlAkwC;0OrTog<20T7HV+Nw&Yz&Bsh~s zK{sBLwk8PGLn56~TLP7yP>nsh{LGMCQQkIF6sjl_Ry_|o^~vrOPTfgQ3{7QWBRzQv z(Zj|ngrxmTVOMpbWf?zCY%%yr=|a20ZXq~kAt``3D(OK18CiwNaN4)5%zki~04r)HoE zAx!2=;>9;8E^`@}(b1M7G%SL}Z!Y6fNZQ~`1#W?Hto_uvS^7h?-4hd(9YQ8xB91Pd z=7mJTTS;T25ng4@mryI#UApHG88BV68uKEJ7s$~0&eTJI^DP`7<$Q?C$hg42i+6H7 z*@h?UCwv>UQR5?27{7@W;0LDM1P!8VnC>6k51&8%oDYAHM@4tAh-Ad;(SEl%UiRI^ zw(k!5o?P5;GloJEc6H243KkS;3MC3#k?F`Z|4Rc30i=VXWsO($k=@j~B!z-2E7!umul!s)(`T)3*)IOC!i}$Uwe5B+3}+&RL$L4mep0XE$J5!qxlo@s zO6n_<=ox5pGhKb@fKJTwG~ZR`Pf~a!rb=#ZxUWtc6ey98EN#B?xa`8P9eI01x8iNP zMTdel8t_nocG#~r7wg2H6pK~AO>4S`Xh0M5a=5YBjDNwGx1N4Ce((?fr}WAH^OJP{ zKisc|JNe9Wjz-r_KbRQ<6owo~GQNBFZa6tP3Ag@wD<0gYJMqvqd9mou(|J$+#@ox) zqRX3(nei66^AdS9GUGVV>CJ>pxmzsA_k`kC5c4H=Ow5>=a$+ZN3OvuM3$_K(3Oy#d zC{!G`tImtkoX=?czV#<{hKG{Aho3Ep_T=a|c|J#*tv{|MmBwfNcIWcX@vH01g?)Lh zsLxxn6JK2%^G>xlgHwAw!{rdSh z&d^F*r`F5#C1xDaGBo33^)QnbeMc_1j?ALTa{`%hBr^=@I4Nq-K<9e~KGKWdySPQ& z@zC{QODFHf#jsth`(a31c5&OndRW4p;Rue9JAXBfXX|vaygBlncmL@!-@k**SWn*l zP!$EGH*x~corVmg(1sI4;NJp#@$?IR|NQiMc=w>s6b0#EftF1;h@`6E?ZA2?D=r%X zKySrm!;l<>Wy>rY5C*Kk~il=n_Qb@;$UVpvL91%$l1|RyLv)fr^1${tW6BDG&gXSyapRUaRAbR z^34`!|2)%fTOYXZ=8<7L(x8^=;-^fri6#z?Ov-Y)t?Q<6fkq1Ob$dMK5GHN`Gzv5_U2X&}QcZAbOkA@&#* z-%2YJZ>KyhBNATdJbob;^-38xzA=mR&LN57hFEk!iv!&YCF&g3e$ccbXA4ndcII<| z*4{pEwwHi5Cl1F(js>JQ#_a<_fI5m361Tt2aEbj`zn5VtA>Ho(-F@*dekcLcRDSzG z4Ec>n#*_$mC>ckD4L*7Hhj?)3Al&-kyKZrM9O;76^XG^Cox5GUINkK!(W2j=$*td@ zM7$dM@f=kY5v5|(-UL|oxOy$1ZY15vy*59t`zlzRSzuUXkVtm!7uV=1)r@x#GsOi9q5JR@jS?NbC zV4ZIVW`u5mIjfOm;sRHGw>Yz=ie;RPOmXT;<@@76^LZvX^y6Uo3^3J6x4O+aSSk5( zd+Lz3m0`MiJg#==!rFFq;Q~f?I))vOk*j_yJ&qn85~{O4CskN%q{W&35@RgVVT;3d z7t-R)*-JWi$XFb|+}JdEC-Ar9m72L`xHOub^{8-j!}nEFJ9pZC6ga%T-4a_p`Opt) zHtAm7ENTj%lXheoj-R3%NhRv`It6^Aw zosQvuGptwZa`Nu!-KXj4)2I32!-qDbem>W>HmP)+*@#E0#@#2VH~vkI?=EvZUF39p zmcOHQp5ljcOyf(SbKg`pFEVd0=;AkyXD0t zgRKwr7~gaI_KsE;HS!pN7NZZ<%WzR2$+C_w`Ln_*CSnJ>ND^w+u=)g+LbT=*3ugXf zsY+lhgsry^MT0FcJo3!E636F| zelg8nPwAAS2d5)y42K zv0x16FHi(Tkud!Qck=JRa53b|XP5Z_Jjkq~c&McE2E^Jo#*9farYow+#f@D)E>H4s zvC93b&*>dR(O*+Od6x6}(J?MgJtFKoVZ@iTMO)-Pl1g}^r*8QFIPp8!@_lRUks|)Z zg!m1Gy;EOf+R{G|QV^y-oQEeABWrt+K1TO)(lnp1&3;eDm1E!(8Uv5NJb}fQKcan=W)+vN9a&V#9y5Y6=lvro(l_DK z^|qnUtaA-2%$#3z%&>zO!x_<}qqQ<0I7?zB7`LM?c1ce25GN0$BW9I}1X-nP&J)eU zo>4~u>m#T_LryS~doAB7xyb9qKo{5}Z#u|%wdJ}`j!*J7yr0IiFTt*rqeNFMJtR(C zq5r|@%|&fPL_YfH5%6kp4}YJ0Qpi7k`*lbstDMoC30a-oNF_56`xW0%2pZ>@rH{bz z4Y%sYP3JqwcT{vhi6!H}11k5F>UkfQh(l|L1t{V7%J0towz)SGwy$Aa6O^+cm|cfg?h>N^4{=>jzaZ%H$b{FAom{}JX5Kl|!* ziFX}rxXhEVkNf)bs>HshEJ>L)CsbG@!}aQE+AlQG>AU2eZo`$vuj}+h>sJx4)>X>p zE6atJW=ookf#YCJejW!ksws_?@y+ZBwmVNG+;c9H9($T4j%1xv1IuI%xirSHKKF0) z{=PaGU3MDxGN&Y|vx}^~v{&{9Lvko4Z}G_9RyhkdMw(%U%szdomj#dN?K9sbpXek5 z>5SuweTVb*A|EVoAag#->14?Hbd#T7JP#){hM#{9fBZk(&2V@>fA;h<@F6qbM0x|l z^)&H`aCLDz`0OB16t~08ciriD)V+6z^6$~2yFA}6I#~4EI4sDc;*dNl#E*bT>X|>yf?Dj&TlYyL18XWrxI}O6Wbt4-{f>bj4%hk zudn?LvwbJK$_OoPqDeIrO#~+DJU^v;yAY@SQ9WSMp$7ep#+Sve`_{BiEu8i~*S^`J z1?6Bti#t$wqQa6?M^2n0n)i-tQu-`AqS6-u%kVf$HFEZ@nqSjHm^ zyfuk&i)28u4J;_i?d^!?+l`giN?!;6N|Q*Epr^60wH{J-Rd_F*6RpA&qhALq?oP zumq0gMt3komY#X5$DS5>hZ!kseiEjF1=+~iZ_z=kk&E@UWMnCyR+fL8QDvvjC}Kro z6Kj@c|Gu1}W3Nq;h~pRUIbZd|5M{`?|MT-q3_H^WBXv;i-`qerB$0E%z?3HjpvZWVs} zUdm6`@8sKX24`fzJ52fF+jATM6n5!obWdB_1uDovqw~GlR}hPH`q75Fsa`bv_CTYNcl53Jcw& zlIqL_NY`vu5sb>b{I)jN1)X0ofk=!5$@{=Zy`^7NJ_L(D z+fkmXVyIMMI<_orkiTkI+`Yzf{I|@Fta|riR;j)aJokfa5j#IAvaD6!&eIuN9ziAw zpCdE>P}_=<%co5z>YGNzSGLiC6MBQ_i)qWsN1YRWQ4<_(j7H-JDy;?a%cb${f{q;< zPbIHPj$FUtgK$Hp2_ha|rrh|i)ndV$41%0JAVT1QWu;fZWelEbS0U# zkv$*0D;d#ZCv_^^)z^UBWUU=_x=}hUJ3_9YD|Lm^?=B~oJs8caCW4D`UxNAwk02l> zrSs8Zv;b%f@k&=>zmaheHHM6r&_>b|dNI~zo+WCdX=UQvjaciY(XZ;2Da}^<0d;v4 zdmW#>N$e_@*walMKe8Mj6n%^6UHGyEJ~xwCF`N&3R@yRq2Ace7`duvMQ#hPSEQw?|DJ#$X z4u4-;EqpW2=MKkQl_qM1Is8ELZhtjgk|%MC16S`=@Le1B1pCLZeFnPdvYKTIY$or$S)Fv{;^NeL^4EvuKzpb&a{w;&cYb<#5RNO3D2nm>KgIa_dN} z<4&xipg=ZssDpyb1(J+WT`|&~q=_YB++uGw$cC2?)^tN6vgl2R5;023+ePZP<8rax z!ge_BhjAN@h7l#mi{-^gDhl$X`0UPS>EV-yIs7Rkc!TMUUb_U!-07_LJ^c5FfBr+b zf9C)d-pE7OXs^W9Zmf>d+0diOc7xjCgM7Ie>fLC3oRPdL(6&cEhXM4+z3LL>qyR}T zbY)IQZbp&4`y#8(Sh_^z2Km^ifvf}`k@C`v89VrRs7k7Kx0k=4%o#p#O6 zv&Tv7oPn*u1JyGc?3}s+L-s+v*(fr_8~Ab#HqK*lGq@ggHI(a)TptxyNMVjIkP|6) zoyQ`Vm<$Del@|H8G6ElbrqnYxe$72~hI1(+Fm_CTL1CM|BX zw}#8it^uKV^s+0L>zBYK^>%D{gVKl2<$bh=>_&w>24ILVSxau~&vf{s9c_VH(cjCc~78Qws8(~@zp zlX&#M$B!RJIvV}%>AT(X^qaU$H@fp4MdE`lZr9tz$wA)@!-!Hbipqy58Kc&mBxB^o zOGNTArfv}yA{i&u8RzY=pgmpSST6~6&s|KUNu`5*9jojkbn`2?Ta~?Gz^u*_NkPAJ zo|)%9Z(%C**{u3jcCL*)fhVaKrRH&U?ZBw-e7{t0T_rN#Zj*mfr?s;WHx6$tF01dh zE9>!Q?Rgm5{x>-DZBN>eXI{FW;@*#s>+fv88vMe(JRaW-p7uV6U3!|}Qn43AFTXnu zzVD@ec{%B??_>LHjz%WQ(VB?(lhM=&-^fdLk9x z*l9u-D>GMOqa+oJz8Lrz9&v=QMY(t&10GtKP$*8@F^!v5SZ)&PjmN`bJ6^;svhmGg z*>6_|i|vcAhVkfRjZ*Q=bor~x;e+Rw34Zk=ef$|p#pKfV(3Fn(2gRfC=}k+<*>29^ z(|C6u!jsRQgyF`J`}f{QW^n)~7hO94?yGoob0s<&;=Bv;!=_6F6Z=fi3dP|Rk+p9( zbgy@oGtaEF?Lb3SvfnYeQL$?qDSgS4qZ1<@>=KS_!sh*l<+;6QX)&+@ib;o_vvZ6c zF;1#4)n}TAde458lN}u)L{`{I8<{PUtOram7HFkTejbvGv8wIL#xK@7JWNSHsp+Wg zMB8}gRD~5SS9InEm+Q|&IAMKpsylCcrfmT@SVL_~8`RCJ=J8|T+i!Nk(Y3KNU^WH~ zETGp9R6OR~))AX_J^T}ei5stik6ha>cy0PMDVuBCJIV#3FOu>cJbsLJ6fdn`Lhv{j zT1w#P2PSP#J!E1~9cvwj#PW2m9wm;pCS%|0`Ywk^Nni&gs!SwLqLkc(#bYUM| zRC;jx07&-|$LAp*-N2r%^Th^@ct>>nZjsg(sCg%7Hl(XSq-=X+v4f~Bh_*(x=+hRJ zjB1HTHn4gki~fLg7Ib2#U`TYMrdgU7m^18dGU|q#8DD3#m0ipLlhbnDl9w{#VO~|F zS!2u6v*-wz%O>^U@$HA8sN8|LYh)}4y46d&{p+s!bbX;OQ<$dtOQyX0oTiW5nlas8 z7DLnMD$lc&%TqD7{c79alO}o0AUM;PNtuR=czkqo_3l2iW5uEuH5FNG@-=-j8sK~* zkGq;7HMuc-W#4^Y^?TL1G(N%5h`UzSF;-t6k12}~VV3~ie3`{jLnmYm&m474<^#pC z7NKE&S8h1!>WU<%3e0fGMMq}HSp)|%d9no-G?)d8$$Z20K>ls4+(98OZ+WrAUjxN* zCga^8x)EeSS?qPFp5Va8IUgss7E_xa+#T|#7XW`ey`LXGyq_OEc?5RE0N!AFb8KBx z))8fO1xm+o_ilLd^e*2T{o%j-DJUo&MrOuJk7Dg0O0=jt$zgBJdY8U}PLcvZjV>K8^lg}LhL z=WyMY@$DE>=YA>v!F><2u(-t_scTl-7wz8;Ex0yX7zOs!;60kbYzO|GetGy6h^T-p%8ZA7(1rcdbCxSQU@aTFEBV!0mI7ef~hHj4!s?}p9x z;An~RvqWm!e0wtfwm%=Ayj*9BNAcjn1D5?waDS5w`Hf4)K@cR!M2jPx#=G|i$e*8n z4qtu=C9=+R}+qf#tdvRF!|Qumka!f2qeb@5xxOr}i_FvvKQ+Qa)l=Ihmz~f%_NK9Zl|Cd5 z17dw65)wsHbmIgQ80}m24PaNDByN==+1K$h$m@7X-Bqtzun=XRZFm~ReG{fW2yq7{ z0CDMy6Gmmfq(?Q0zr8Wx+MnQ{h4L=AHfXvvb~>34snTBHn<}SsA$wI+kU#&7(8vC! z*x#L(teD;|b4m~D`c%h3IY+%{- zX(VZQlhV=Q5zen|7B2rzmJ9j*2$z5OB*Q7N*RIBr&u>yiLFtV%<7s-te~j|KlwW3h^>yxk6IL%RgR!B(~vf%Z7$Re$we`*{bkwIhGrARp4h# zoUDJ4x+W?xdZ5I?rtO@YG|5_^jv8W7Ea;hC zHAEwz9-06yul&fmKQ-N6$WV2QgrJdWg+&uH z=hY$VwJ~Ajn`Tf*hKS}ox{96D8+k+SG(C#aTN+MQRS>Uvd3c%+(jxJ1R89Q$WRu|O zlYENLIXtlA#&0^kS=R1Sk&Zt`F zvFn$KR24Zcaggx)unJ*;7#fy1UZ~PQg-^EQ(Yc4r5&b%li)EsWPcGh;COuB(8Os~u zyE*Y&1)oXvzE-#)R?d>#WY9VqnlA^;QuD0PEorrLD#4B#5N0Py3$wujrYDakiBMf&vGzeSl{S+r zYboy;i*_!+3~kM{3lW+LQemIVGuMW_mmMsB;m=IoYa<&O$+A60ig83~Z%{#73ifBRm(J)UOLOkBj%44W0?W0tD& zVnJG-KFQW{%R&2c2}W)v(UB=Gs)rwq6-~yDx7vIeR*dXT}!L~i2P2n zEl-el#(93sY9ESdJ5@y#JT;%w?T;G=>yuYYP2fqe1D{54j~<6bbe`Z^6*8&xVuItW z^(KYI<1V{#=3lABeHj~oW-L73JRS-Z)8Fp>TZIN(HMkiu0m-%4HH-_YKh5w`DA)A!nN8bLa z`WM?R&=28Zp74SG3Z(jdjH;EO? zJ(H|i`_+`ouqz7B<4$?doaL~du#viT8zQuzmI9@piZcj>W?)JywV%`RFxr}0^ro~? z$_HW3Q!8Pd(7_xH>A38)KtG$E}~w~W&90*!d%rdx*fIBYjPO2&zT z1EKM5v%cIOoxDGcXMe?vWW4+B2*1KM?lZu=1ixu7irViVF||jdQTKu>i+l0u(r{{G3i75v8(+*z?EQ*dk`WP$Fv1d%zGP;M zY6_eiedN33>8Lbon<8iow;;q5(k>ThWntK1$n<>_16C5LMc9$%ofy#Cx_qq!PqWoZ zQl`|$uSF`$6aH_{Y?}LLev)U%zF$QTXwL)+_g-2MBg{PP91sT5t`W=OsNlfrXE(x^@|ww zSi8)JG(~evai!Q*Ka)y=ZcC-lEg$qCW(=sBK=lMRw8renjK@vv1AbC;wy^F{UBSno z`+mFHF1G1-i|qMuJ06aSZuWTb#fy>Lb3cCiasDxmK>PIL8t~NC#kYUJLwJIZ?!o7f zZjJfbGqlUyMAbwfJKmU{qq4j^T&6{r$dw{()mA6BPS9byfiE9qa^xL~%z_ANs3tE8 zStmKD5c`~nN4WZc1|L#Ww^nf)&5cMv@`Uo;SV+B7O`{H}Zk8EVt_%yH60zyMvePMw zZ?xY+i)&Cyrd}wFlDFvArW#8?b$=3ngG(zxXGJ&^A}>LIxT;i1T(-4}zu>m1ac4IW zldnVbc^t8qLnrU*b~A9Wp1N&@3RjY#IAU>CPZtel$9W&gp zi%)gNoE%*#ZMI`Hs(Y{~y`XrI=j3Rv9WWiUJkb@qxhgsZaOw^5>JAb?Nwz91l76dy1#9TIP|0Ym%lJ$N%NQY2FU2yjeUCFaP{9{}1o|59tNG zpp(S#@ZLiX^I&1m;YUb6o&itmW_J8hj-+q-!?Qm`QB}O?&ih+vrCWB(b2Q-HL_=P; zz0`L+t z{oETk$cEZ8>n1tZtNLtT_6)_SG@I8GB`*SA3+PveJ!wLkVB6~&9j(pdzE9lF0tC3K z)2{v^txP5?%o;uYyYgrb29P~MY&FfkaA@FcrMRqqwVclf(lPx?EMuF%2Tt14&)9rd zX>0;t$>8(GX_>ipT)*^^0hoAe=t8@1?Dma=$7#WBs$dmpXU3~Y{tAl)l9~-drEo?+ z$X>?)kVN7SmiHR%frBo-^j zwu)JOhI5(Ry7_c{pkFFsWI2k}PMmCV7z3U4e3a!f!Vl2v*+Z2>K*`==>senZ&>FcDdeTt6Q^<8ecuuz{8jJO~h#NWN* zOllOSZ#bQ_qa4e0u2Wb*7-0^j5s!_k2(jAqi43@WCBo|YE&Zr!3Ol>aQQYp`3lC54<|i-j=38)!ufC>z#*M=p>2m!| zK0H|90vZ$T8WyWX8abK=pcssLiv^@E@-m1zj8TLoyG?=}zx9$)@pp_mP?5b9)ayJ5 zArkMa+ai z!ZpHFLNX1S)Ets9Wg(!^wz{R?6^?A6q{;InY7N@L?dmAOEspe~>8~CPC~f%zB6-L= zst~KI!XPZlE<}4cq2>P(q<6xDmwqR3*8f zjo>ub#XhQfLV?L19kIIZW;5@Jqk0J+!$N22Qv&;PX-yP@0W|41R+)VkK z=P|#R^4TfkZ6QZ~*5hUBfi5Yvbxp!Oc3p>vqN7J$)|mjjYcVH@BB_{af&qvur5U5h z;wD2$-LZ5FD|%Vp?AKF4peoJE_;^xO7a=ulRN^*0oJxqG+h_^qlErZBCk}@*(axBp z%QUD52P|Mq)n|j&Y}z%@CsRqQa4#`QB@NDAmNN3Lw*DAC-Tm^SQ&(K-(U#Ju2w|cI2tpIlX;6~uFV~Ts4!kT_ z6P>K&8>?Tn;8TMfDUB&-Ra=L_%IY{qT!X?jWlgC`x!9lB^>XrFtWl-FSjr;Sw%Fjax^&SXk& z#XzdN0zUhf*@hqFm^qy&h`G3VPD!4;LI6 z%zAvg#pTpj)^r=Yb(_T9(#sTUM>bx>NI8 zam&HU8@iaz1%O%KWW|Xn^(?@7Lw7dkc}Vac&%l! z4Sd!<6~hL2oog;qPA=+KPuvM=Y*y3eIdhHqUAmp8q_U@sa>GPc7{b)g*wVz;*5L7a zZ4ZY|pyGq<;400Bst+%$WSXy-OB!BggBRLK@6At>e&;F~7nq=^bOdvTS68m>_rzBi z93R+&Z>aT`Hm=Aw{XMBygV@ZCt%JM3C&scJoX_=Z4yV3f5ad9Cl89bpQsU-n0IoVp zIk?+ZG#o2{!&ZBydy=Gl;l<^kR^_-JFFQW%e%=^egy~rMwRH{`KDBe8>7QA0n)Q>bx@z~LPGS@ic zv8prLBeS940^GZ#Q#vy2(FCffkVhSx3CtF6Be;4E_E_)+Ws95?hFI`eTovB0vU?rCs8_55&^*0~}z z(S}L|5Rz;I`&x6Ww2$fYD1?;7v#sNMJ~|TW2N@xXYuw|myTjc!g*hg7tknV9?8wx; zW=C3z+D0A%8BmS-3EH;q^DsX8Nf?*9>$#V-?wrF(IJ zdgBGa`ABD((SUae`Ebb*nP`uz5O1{Il4; zuWVutylJl5c73!9r%b!x4zpYZ)4ujgK8F`yP8OCLYk|grm`)5nrzB!FqYqClCF%u6 zb}K|vvc=PNrj*ZDxAC<;FY*QVOmC*hZ9gs5@dntJr{;@0`M~8ZI4sVE`^Tw12W6QO z$u4J=^urX-yO$aSZJVnwZ|(^^xoM~UzAuG2x|z@>FR6hY)k3lbBB`gA2m*3|2;{~b zSsq8;NXU0G_>%+NvPU_Zteq(>=_a>soANg1m#98IT;76oV~gVUQT`Op_k#0drk|h* zNh}?IWbHkUpT7G+ckt_jxPlj54~Jdfulm?6`ncFGHmP3@mlvqJK*MKPu$m&J?Li_n zMeYtzG(JEyAK;kC0T7U5(l}TP9G^ubb86T4 z<-8lKWMA^CtTyEap3+6Adf~ZpX{IL6lC9n{5%6Ye253(r_wKPt*$<68lW@SzDCA=*Tk#lFxY?kh3C--r$g;ngZ7Nd5N?A z5@~;p#_mfL_%A71+qfClhy4mw6_HdGsGiuOnqsm2248%5bh!QEWSi&+bQ?$>uD6W; zp!AbS#+--|KSImoqetNZ>MHL3dY${beg5F|PWtw{bH+DCZ@YMTf!o9dE@BG`G*4b8 zdC3ISB^gTEVDKSn^_QT-73yzfA&X51AoioE%KaF{GfT+dE_N09N`X{cgY6AL8ECfA z(0N1RoVlA#n2|E_A`xUGsVp2Mx0A_|NTTM>2Cl9mk;~lzEO}*R$maDbJWdw_UtWBe z#mm~m<>C)NFn=3E&pzle%ES0C>vp>oWeC(7K~U(os_cx_p%Y%HSt zt}uupEmXyl;Rsy6vh{{_A$d0+N4>T0nHOl`#C2P5PApUDciLw5@-J_`8l1_XhjvUr zLu(syTGZqTmZTn48Be6!Qh#puG<(>F+{rw-G1#?P2-Di~buG5u` z+9Ieeg4O46S4LmLWM{Rw(zW4wwH@cvBlRO)b(T3UK~zN^afp$xKS#lZF4`JVO@WwS zbmMwUuCsJdtj~w5!!#}r(oH%qy}r!wf-b|jM~1s>p^Il_lOG}dbds^70lKV|jz-`5 z-K}`=@*sY&JU~?T-D!8;ug}J1kDNFzM-CP=ZWBt!d4*^_j2y+SqvJ9M$bSz}HMBy; ze1PKb5)GzHtQsZcj=~a9$O~F%dOeHQv1U#J#Ym`4Iw+E3HAwg*b8)(X@&p<5-M(i< z&{i{9nbhw74>#{U4+N8dSqH0(e{*IEI-SYdd+ z*j%jAt2gUpCndHx@^C~4pG&zelk=&y2(^6#_uRwO;;kLqFq2>Uk#}Hj$JtU#OYQGD z%NFe7r?{TMo;(v8Y2XK#;%K5KDbnUVU3onDdcqas+Ki)F`{r=$*V;zaBZ5P-Xy>}L ziUq);vxP7~;&YV)Nyi+sSdKrhQL)Scfda+FMClkA^(D@H{Od2#Ot(Jh=-I(~(U04F zx!sKYVvEdpdu!MZ@TNSFcR6eqHVS7e!RjMbOI|VMY(;<)UWV z=+OwMiVK)bh$=KfEgSTI^|(ouVJGc1&w|^^>(SM0^%OzMNmSXxkZYT5H-dX!;4(Zl zxTuAyd|cqG-QFqE!et*jumiO6-;{FqHPpN{*!=?!?@T`g9;i6Wd8YlQZ((k{U`Gb@ zbTru>%y$<3^Zu2(Fave*!f4nbKYD(;OU4`yR*Ugx0E@v@SW%&xclG zX2DkwLKBvb#nIscX2|$rh!mj>kQqZp6$PK`-Gr{YVD&`mE{GYEH$@j0_=oC>Vcg)B zdc6!Cg`wDv$KB@Sf&h7E-*zKNo0ACJEMCSQyf&@C2ufeQDLPN$BvQ|ZQz&O6en5XAII9!Mw->*-jv z#_Pz+N)Mv9AYRP7xxhwSv*4?DvP=w?$7Ii??n=cyLe}J}E>+(gIZ$ObE=TJk>GFlo zdgw}8&kcKs0HKu{MSsaoO#pgSIypuX6;_U!0BU0fs6rgbrEUs;mV2oZn8$%q6`0&? zN(ePT1uwPbI>#cE10b!`&24bK)s2GT%cUQZg2JAi)G6D_AW~BSsEWm5vT|ivoQzg2BR@HC>@ocGhi`tbbZYO%x zqOEaeIdgUhp(4lSVVsC2O>sC!Q`%j(@Y|9f3*sH3xGL2F2R9VLwry(FJ{deZ`k|T* zpqOU7>t8T@7}C>pc=U)TV_O$DQ^Jw02l;O|%84okL;}rc0T>PZas)dMfewi=cgWk# zHg~H9iqARqgX)>*)fUe`pkXR_i@uLkcaZO#-^zgCF3Jsf{KvPbOWVGGf+rb^sEnL&Nmg=$Ju2L> z_8A0TvF=A@MTFljvU8Kb!>%$x@d5g$V+DLuyZmK|fX~lE$W!>h!>ix3d=ENSMjz4- z?GKH0;1l-@57U%fav=B)f=`YZs<=12Qkn8T$onWKPP!<+>681+9 zw(b~RIec(iK~k9?w2S5EJYTc;C1r7C3lf4WSZL3nkubP0a)pkEj1|qPBPYcq_NK$d zYNXf{`BH8bLV+*mn<;&_{Vu1oA>BQ=o8ZF_0sbI71l1F}>-dkHep<;`_i5Zw)K$RW zJ7Rut@`Cl-i2nz%H3I%f7VW(5^J2X{A^ z8tF9RuS^~pZ1!_!NiegYl)qhB)8w}ZVZ{KXevKmM>Q$x6 z;0DDHw_$egq=pWQjgfr&z&A^2sBL%tKV&Z)i5CYSG7-UH2QKe4O8J6Q+|h5QZIh{7 zfSsv~UF-7#YL>Vju1qoLC|)HhL8zPE$%etfs*|2Tj`^e|k^q6gOFqMtWF6 zxx7{C6TN6~V-F>k15}m&)F3#;DYu{8h$l08P4R40$|0)lAcmFzRzRu061P2~gOn#D zps;v)O1ev7K2&k6YTP0s^Qd{;Ss%S1tuS=p`Y(2I*Piv07bL1R>2n94qv5*o63M`7 z;usVXn~&l=+j19z><;BFcNKd%yo;WWq}Udn&NrTqEC~c#>Lof`M2<0rbe`!#Qeek` z5w__NZl~|YA>ZiVN!#OX{t~`~^Z#<5|M>6zIFW))I|V;M`iXhJq-<_(52mN_-v7<- z`qR_%p7h4uxLkB$WcRiqqRyDz+b#|k-RdBbz8DR7h#~wN4{=~tSm`R$^8`yA`K87> z?gJa~K(A#IsZBySW{U%^%+D*tV0uz$pTT9?sjIQszPHoK?c3IHsBQb3K3=2M-P9VD zen?&4FXg&hage+Y?)IfC3}|+}d|T%nUiY06yH-*)R~gOg;&lJGT)*ACL$9xH|8+-w z+P_yNPuDO*?K{a$vn+Q>u;cS6vjr6pKxe_|f=s$_G}Db9sCl4McX>@ZW2_ow-*Aa2 zxJa=(?^tIXP+uG_*V~ItkNfO#I9x9e7n^a7CcVR>VF+K1@BQj{fG=K*@Z>4B`5>_; z1NkGZ>cRbR%xRC)^SO#{yPY(C|N_Ookc+U|7XXfEg0lbc*H z$!mQQ|Iuo`+}}s-(ezdJ-eo@jp4uixpbVyu4{d9q9%`GwZmLM>t2}N`=)EeHF|P0! z9D*KBrw`kDzV9+?;;e)7%CW8OiLXZ}u=#g_8`XD%vm@|O z>vGKz6E#S#2rhalmbFgHsGY`@g*M6cA7qW_Ms9-``ew+Ryhw|qBiwSMqL@TAj?DNH zD8PC~o7Lz4{~>=!F>x?`{7-x{QTizvF{PiJ88b662gQ#+4s^d1c~zjDGp8H3^E=x< zzwEz81L!JkwurYIi!@N&{;^A>)#_1s&v&TkE|-IsWxl8_DX*xT<|O1TJ8fbUqJNVc zj+hXFt?{~d%vH0kb(HCD;jNv6DI29ik)dR|n@LHTrbfjOBNKQZ3uBAUIm{UfB)-g! z@t!rc7K+mR1*0AcVQ@n*SU{mKbtS97`Fl#h1I?!gUCN;sad@voR{N^ftm=Ll{IcNu zRD&}$3D*m{vsB=x%Lt8er4=iya8Zr}!vlQWwKN zQ+z%oDh*vDlrJtM`hZ67v6W#tnVKqrVqPoL&zh=RVS@JT2kcc)_> zx{lcA0!;%Wso-&?>%_W8Dk98>#=MT=Z$dHQNsxb?5_E>Y3zhB25d&&JD&q?3G#aWr z3Q$ju1YL`Dj+v~gzLufNAS`?ZV}87lE9VjN1-?ZYG$NQqA7is_xm~%+WJ;|fLKFen zC{kqyoxcW0-I{{))-^M~x^0%eXl7lK`1E=4h-r%OLjspjB$WH$kp$N@Ik_=8V zwQ;xk9t^6Y5RmIWD2E7uOlv%Oxy=}=_pM0@;^G2@V!&AVtPB?1IM$`XKx}lGwGHvS zP#no4IVxjq$y4dP_hU<8x-^=&pt7p1Cftq~^_bOq+N|ev8YZTTkI_!Z6VQXKbsAN% zF6N>EX8kc==>crGOK$HWhiHJ;P+rQ&^4F0Ua_Tz#j9cUrC>6(HOhZho%}F|o+q@#q z_XWWC-i~cDf3o;Gtq+PMhex)!JmTX4_)r zI;JEEF25}m!GLS=SIQLQV0H@u)ODa`J|0q^H&61(9>miMvneyhWpLDCXDkedlTE&{ zLdye<>mWc`?tJ^TE}ufJ&yVf2DF`!^GNswvV8GzByk$8Tn)0xOS~5)P_Q@D=uKl6^ zcXI7%R2D4GqiWZaIOIVtlF*SRW8J7*A-d^@u0M$!B}okYTpSs5Phpniw!93-$RRfP z`4Y2tyu*gy-gzH?e~=&l=g0X0pn&+Nhq=VggZ~vv#+HQYh#NlwxQmFt3-QbU^d;Or zMs-C$rZAxXreE<|$c`>O8bQ~P`kt0XvXA1pbUa`<0KEi`PO7P3zsDkfi#5hpSdpBF zerSZF61MT#~Ax=jAU0LhdmPNfG()mvVU==-82Q&{O)%8e7wkK z$4}q^swhx90b;z9F2PTjelBKQv{&5m2iWib1o^ki-zHc-P0!EHVqT%DqFW}oIHi!q z2^NrhWXdB&YfDf*LD(KMWx2eJxJKmRjePh3H2k1a0=u$>$QQSWhEW7OcCS$#VqxRJ z+(845D=RYU(v*y%)g0{CJ?Uk}!k#dr>DGUV4M!Bf! zlGiK8x)^{K2Jb7PFeKd$%EpqXNp|H;g0xksyyHrO%^Y3z)Fq{GG^mS*#@S-LCt)ix zr&68Bxt5dRX#(H}3-hSYs)`3d`@xsbhN+~OAy0My>O;uJBwGRXkWCXsGP`=R-hZgu zX1gs)IGi2{PNGiLc*50#%;8dp!p5_3AE<%ZB~NojhT$Yv`UA%ROMv`TXtR#1aXfa# ziAskoPeMyu{^9|{xwKs^(oCz#>5|>$1EMmDHSmg!q0&fDbNYm}S$uD>zNx-mqp>Aj z;zSorl`8EdVc4S86CYw`%b6}*7}P*6XL#ncq1wsm@_%JD4Hx11C6Vw1VQ2U## zb+vq%zeh4#Q7-W0Ci=USOxed!2QzjW{Ca}}!si=O1s`m(L4NtF`Bo83KIIZgew3mmR38Jjw`+4&HISE>eHuw8vB zoojy$Us{JL%!4637h?ji#Jm>Apj!ip)8fX;;hG6lzKh_H3ta@keFX_pvyLRaV^M-t z6(jJ(j+jHGp^(fFBUjvUb>d^Js<3QhLwmBU*D?gY#5AKqSmr!(3%OGkB(NCjjUl2a zJg{(#!X8Df!S5H?$cr)k_HN3beu^dk9VtvdMkU3Me+%@!6yRq}G|J@W#td1*Y94)f z)GePbyY~(j{mb!kv5CX-XnDLCE?*pkWxwQrLAg6Xlpf$tGH*&`i`$PeRNXC}ojJ(9kNjj#~)-8=6w-!~M&6Aui=t_3H%#v+g zOZiaD8DRbaFpnU!8bVX&WY>RX9a_)Mif=-*zROL;rKk!14t8jD%Mj3Jyj!s50he#K!Fia1Ydw41nZOAV=9{g8Bs6`gFii4TIMI3dv#S^4 z%=ekB6T)b#%sbz9I`RsJFv;#|-M8DoP&I63bZv0NV=$^VNOI_Im%_-?RT6w*^MLhi zu;do!_Zo%$H9lYC^GoFT7x?Z1$hSC;=g1$Yo&JU82Lqfw&hYpF`4{J(iy8lHI%7!z9zD`+;o}DY|K(FipQ5DnLC(+5 zWC1%kq}|6Q??UJzl|_%r<9=Zk5)mM{DJ?6m>5_$G z7I71%Mmf_;1|=4#J6Uk#R_J`{=#{FB9vVib+r{7thtg&QBTe34Rw9|sz2NHOuX9W$ zJC+$>I<0cil6&3*RhqSxO24RAFTWZjqPpJ1= z2A!SRCS#U6W=Iew@tu!4j?f8DfY?*WOuGCoZIFE|5=-DYqiB{dP+xrfZHDzhhA&Z~ z-h2XZ=jqSFfPMN|nQ@`ZM<^HLzX!iPNuQteVR5<0dGl?)aj;6~!yzJZla_}!#x0+f z9EXk!c)YQ@N;6FEt+T|2naX6j!b#qV81Cu=h-TO_bcrizG!4e288D{fSz?|O zR3v8+w5&}TjF2Z;?OmAO$EU63tcPY~D_RyDaCH|UPE~}-FFE>u#b30#&2VJ6)0%Z% zlRg;EWjNL5m#ddawk5|}DLBv3o=JS`RP9rtz*omMv|~HnL_{B_Jy$!N;9i+1tFY>Q$y_>&Yt`htO1?@F5;}!X|-QU;6pDg{X%vg0sfXZXEWZuj0>?C~n z{)hR?KYx<%9RGLuyXATAhEv>apdk-89&}qY#0BDclZGIQdb%BsJ=*9#5Kl~&X z#z7{c>=&JS@HrdblQ#kYm|>3T0yMU2%H`fY8~54{)Fm6T;=;kKV;zlb6#i%nafwkJ z<$?nnt62A8#n>1PRvpKZ$ElSH47LLa6Db^YXn9-6;~j0YRog30KH0``vQU;HMi*7z zUZ|`tsFgnWU35E;30zY=vm{OtoJL4`UPMiu;>nZh;DLl`N^-^t*eXGo%t^LhSr{^1 z8qbkxf;h9S=$fTU-Kjz0z9_I)D;Q@J4Dc<@E{_32r^I5_NYEtdVo`LGPDezDEzAktM#xjz_(e7NZH0b=zC zC+`vIjd5^}x)=|!zC$GU1N=?jR}`xP`S214dI=P>LWZ?xZ;C*Rsce#pQN{!Yzb_VG zTYYJfeCnwZWe>7t-ol>t?9+9?kc zSf;qD-(jbe)!#nzIMH{$)06gK9v;=#Pse2n2TV)MVPxk!%)ky)IGhl@vuA*-@KF2I zyeU;qao^^htG6y;EhKF_yYxLBpSCZP908zSH~>2sYHBlM0?)o&++QeOabkxl3LY;P z+imgL2Iuq!bFDG+8kzqkF2Uz0s$5`p)Eh@sY{K~f<3&u}d0Z~e(bRvL!+5z~51U1Y z9CP_f>xs1xJP}3xwnyu0yAa$m*p9)-~%g)`TROmg_Ugf zMdB29fo#zuSOZ~uRk7;toT;x~J6=C1cM{1yx_Abe@4+PAf)2HbMbmvZ6i*_qRlUv& z;U|?rZ6lqW&u}iM^q}}-sw7fRMX>->j-shVBt5CEun)cG$L2E&>RVjOIhd`VCF+vH zg~95%8dN4(eRHMPrV|a$$f!7h%2`#cQ}}`%Y?I|8fH7V35Rgjh*n_293B&TpZ*_+> zgOhrZg%+QFUGrmLf}tN*Kh~kt5e#>wlZr$0)wQ;j-m0HPeP31k9)Ho*Tj`Qj>NW+NQY7_UNqmdIrzn7+%6~dXzsw zh4TG7So5Di+-!fw^s_T#PDV+O@c+L>b;bMm`R6aw?cd!*9QNsK{VnQ{Im#;j^=Qc3 z(3xpE?no+$kuJMJKAiL{JL`}ndR|E4Cd;!TYe0DQ*yL3?3UAYxu(E+w?|$Vdsj`q_ z;7P{0j9geT9aZtDhfYAPNlq;+?MrR4Jyu1i1Y`#da_?LyLMcOX2iKk1ZL^#ZN};&0 z1@q_1<;Zys3Tsv%_3Q$law_o_s5KW5UdY~frgH1#_s7N;b1`UIU#oYP?h;ZJq3lpI zINazfFG&OebKa$qj?2u$U$qR^JjpWv$I8=ZOnBy+2iILJ^ISyq6{ z9LSsx4fv5y*Nw=47b8l=c|k{^DRxcYk6YvuJ*hJeQ@S`uD2@@j=PBP@ZPVq!J6Pi- z-2d`412N-|3K#m>(l3J<3nS+A3I4nP=`Da?ALOt9lJa|~Y{<7z&vQQHoB780a(F?P zKqDf%QG>pYtS3&S8ODBVgn?{Sy z>MqPfjY1+#W{U|>q-!Y!lc5%KIaG_k&NEpc3eT?AY?)9|+hi71+Sb)Wze_2*5L%V@yz10Y<{6OTl7FgE=DO^XzZOWgeFzxq9RaM6N2Zx;3hYC zB!H|Ppi*Ek^c9suk+2JDjmM;2-1~Qi1KlQv2}`eImkZO*m4`q^&%K?a`BW8EhFdX6IE+6FdYk*Z9(=4U67QSC=^1B}`!pg-$YfSlhmN?XvN7 zrAb3m(V>}UDT^IZ{l3|^*cMSXw3KKg`bU{lu}26&uzewroj&&+>M}+Y!a6!HR7 z8J89Gqa05E?leDndXVp(^_fFyzC#Y$V>&!sjhEj&?-#iB2)Q5m%m?55EUs;6)S_rX ze2sS$6BRMzBuAw6vTu`m5*yl--)4=g#*Sok2{<1aE88*#%%+vnVJN~gK&4n?i6Q}s z2CUixsyZ2<3OH5lhKU{QU+T${FR-$-G%J->p|5QCTyC- zEU<@CaaLtQSv|^BDg6K_3(8JEf@4p0`vIZKVb1^1Yag@Am&>>WSD!HkQ^ADF*gZ$& z?=`GtfnT*sRUhrxGB^cO?dt>1#P2 zBBF*WZh+-3iK>i@xF^Y&bQ>s?1-gw5H_0KP8WWcud^eyJya;(o=B4E(KRf+4-+A{S z!M_dp-fu4z-be6DNWTop7%E?S@bp1Ol}`SA`8gb(r2Oo!-=ev0MV=HnA0s2a$a$Mk zm)~{l7ttd#9%Yl7`1)sL#3M0hWW*yMt&4W7jE_8l-dwBFOi&(1#1U1R3&!xAxHXj! zWSgn(ib0QT0h@M}ED|kDr|8 zr~lK(@bKe@KfAt|(l3S?m-O++0RPvA`NRM6VTNBr`u6#!d^6YC;w38eQ6W!yV+#5~ zhd^-U8xY}iu?pQzN^2rrTFNI=?fMqx^Ei{_Hd7GWflPKG5B7Ph_p8+{Zz#MBpj_5D zaVb+_ROJGg=pQL1m?~PcqjL*BV}zbcSz|`EBxv2iF%kbAT(ilH(zz9EGGBL-DlAUN zS0|Kj)B0JC8f2TqY|4u*D)}6vFw<%gld8^J~{hvpHiRcVs+KEmjErSZ3@i-k$1A|;fGK!d3AxR zCI)5J<;!h)hJz3$M4>cceri)dMGl|Rk!Wm9AyxVhvt3c#=wS`2u3H^a%j{LZg$r59TihbhMK*r!X< z4Ur9XSRm5L+oj{HyE|BnboB?2{+JkaB((+Tb=$IvN>Cp)#DN~Vlf~NPqM-7mu-5E% ze*ioFm1SBnv(82NP>wuvfS}-*vzw{PG=;%ADORYD?=iJ_xwVLGDnrWz%ajVUq{Wja zx-BY%s?)P2OTUK+b2T9+O|;*&8_w9}-&cm`1ufTC({iS!rRkC&ZRK`R6X{@(i7W2Td<$P-|KQF726tPv3ljZ#~t`(S5Op< zyUH3ItxOgWH9!)STmFoiLRAsF{!`+!Q1Xb~jvdG3XA~Jcc3fx9JL72dK82S8L4YWN z6^`ItkfaNRhO@bMl;BUHm0XFb?KF@eTFBJ;@6+R`X?qmF{gqj~}r zjTFa*uT|Y({>2Iz@+RFtRp;~NvwVAj_NTijY~KYk+!f0Ix%I`AegW%2O=Y@&4Drd6 zC*3g|#}EIvhaDU&`_tiKae^9S*eq7-@oa@?Um^YuQAu=2pJ9L_9GT+~;}MYGF>vJ4 zV`TD&NM(l<%Oa7Va_CU!k(W3COZ;3QVbD#)eU!Tm#Sx2d`2~}Nqa#~yJkl8oRUEeY zStePTU7?iMx|Fo78m+*658w?t(|Q4XlVJj%)>^jl&d_6RSU*}7D zI<54Cy%_uzo}9t!hW&J()af87-zy9aj@o^K%Tvlq6BA|aT-&qXf*1U2o2CAua?tth z#>GKpErJ_|;2?1eiASH|u;AF*aJZkNLD!MG_6CRY?4FhH9$&8bRFNDiLMCGfFs14# zj#ZH!bcJVW#Z0Ya_Zb4+b(dklY#W@CYka-N=WBd^fzK|n@Hx)cGpy$v|IT9U&c?Jk z$ItUT!g<%hMIIws=i+6G+jWlH?NRDC@Zxa$)$Q&0{`2<-SYdnr)5i(^@nQNUFk(u- zC^ZFdcW9jc5#SP)>#OxDe|a(HgXiDm#Vxvj6m5B%^AzKP&)Jas3a)x%zwF7c4OPVv zC1e~>iA{k^ayM#ZJvmQC0!&ERuJ{#cJjvDPB69Gp>vm1J`EQ!vr)>GkBojKz%EHUJ zVyJ$WM1iS3bG)Lm0>2?QowZnvtC1>}SyH#(y1h0(Sg7%Bh0djLRij9&)!37pg_sly zse#E{y{gZsQ-7!wsi)AiPMAo0_RC}=b8$*Vysqu|(`C-5S8MAE^HhIUgN6mrR2fvo zaJIUBX((bb&h-Ux1f1_<+IE3%S4xW|&fu5W z(4E8d-FlNZ$0=_Qwh7grA{l?ly5e9PMfjQ1FNztnWc-K*<72r0C8{az9po>cy+C>Q zMn36pBsf6p=Vq1iV#uM-X}j6vB{F2Xq!fRT-Ovr>w1(>aLGJtDK)1wAM!p8XHeh9^ zn(df#;T>{sIYj3}%S*NS^w7Rqw`>f0&7Z~ix2x0Qv6bB;| zSC8TukQ{yrGYnOF3{L;t_EQgPKvq^Ty1q>hg*bh`!_ny8Sw7#-b^!xN6FHd2gTfyw zyC1%!$%IYLr?~2!paTE$oJJ>&3*a+%WQ85Ov14CjQsRpSuOD^%#-Q$R zk+qL9d5RTUoZ*8`PLf6Rcr?#yIm(}mxUyrMZf=?M$&y&E1~}n;S)|BNosPt_pzc^J zkIa+jpvDucThSy8#?)=WCXD^BAhW<*j4;77%Q|t*I2hCm!izg@D_S^!}6rG=h8XJX!**XC6sZn#mcqMt6TPiSBh19133Lg zF{nB;XnSUCR3Bbt%u_sQf6b8>ylTR;St-E8s4;&1ZeyC?Yt_qP6&q)$v}%iDZdUwk zA9d{$`cZwk&`Z`jDx)^0YHd{HDeYSS%`lw9R8Ld9M`W>*aLHMwBnSK|_C_1L$Ol2F zDn4(=E^TzuD@HkEka@XFBhO}J0y!R$xhRnb)?vTGI@bw~zD1@yDok|5JUa-<&;k(u3;iP$7ONv{60!oFl>i1koFFrihqa%#cZad;{` zQrB_N%i1N*e653dg>KdOp@>szo0nMj5Q>{SwPpDcjA3Luo+}s!IVC9;o@{Zw)aEJ& zUd+p^n3-g_loyFATJZyA^R24mTr{h0xQbB}g5fFasuX9Q8w|3j>VCuFQ`8D_I0K@M zF^>#mR_s$*u~mAOEs(uxd<=osme+A*PY;G4Io1?)sh9sHN6G4HX|!Q=MIB-*Aa-41 z#A3r1))}CN08rY6EXTx4;CZRNu2eiO?o!qYJeZkWIJQs$F;rb}ie^LyjU(fcB`{Io zc#erRcI<9Eii;arct*YVZlqg*HVHP7dBGW>=8PODkWa72{NXs{5C7f$43F{e--Gq; zXJ^EeetE8KmYyJj9w445kjEw3NKu7U-}L18 z9pgaGZKOY94@8aN1aeH8M?0E=La7H-HdL-1p%5e!Ss`+eQUT0`$hP376LarXx+d@E zBGt)cFcpX$G=MtY%sokUmZ8+=q$4|rH+sElFg>S0Y%sXQg}qa1y=7O0Is?KOn*O$Y zRHtm^{l?l3Z=P|tPMa{l@vdN}Iok6iZ(ibnt_`xJ2a z)}oLb{OsVxDQ~lGJ%h)C(wZh+?}~ZS!DDn2RDYnm89x@aPX)&8`=5iSWVYClT&%v@ zrf612mMV?#ogIA0Bk(q4Bri==6qA-2nekAv#vgj_C*3*eslE%d`1E9Hys>#7%%%Z#?6pSI zZ%^q@VNi{is#X}W!hth@TMh-U?7OVXsB8{w4$B`(Rb55{eH__vPl8vUDIUdH?z;u< zoasKMRl2dF;PF`ggWL2w!?O=F2PAule}7`C4B;1GyrcBXm5eQ^s^Y7!7ig^eHs9H< z65KjSu-?+nWrSg!`q0ye&^CuwO^s(vq4-d7G$a?nm>k5(0KnUD9_SK{E9j&PITk6b zM9#I?yLl>=XiVH-QfqdzElfU`+-!bIuy$c}&h2V{5?(NMgA&tTtkPcw@b4v)P7G0O zrtA(})Fy56n0;JNo$Bq=wy~eOOa*ID_Nf4_?`5W%{mDeUGTo+3sgX^j-r_*OI`JH5 z5oEgDf~IMu29v=t!N2aQbu4xnQq{?dL8{8?b(~Fft?aHyo7$B+{BF8W+7yOY%Ndg| zdw#>37shM%_R@{*M)J;T=V++F3A&OfOxixkj4Cu>&zx2&6g{)qF&qxd_iPswfbI;E zZC6at2~M}n@`b2-vV`+yhE2rC@n~p%tU)3Eq9Z~nh8;r-Q7hHtQ@FM(7PijH3fBc}ArXU4RpxOX?bf82*}|1ITHl#)-n z#3%7qt0hXuq!aGOKIUOWEm240gK7(8(?mui4_YE49vz&dydfty;W<@7v~H<{z=ASm z3yxNE%S1Je*hDr`##iM7Ez^N$9+I2H%J@y53guU=TQ`_c)F2XdyCHlt6IHVgsL0Gr zI6*zumi%cqYgJvAxZ{Bj0fbU#kzN3bRON(BI-DxTc2_q{`W77KoHD?AorA+cG}Wti zVJfeBTqWbSRqS(ZR}K?kvfvf`dns{;1?z7)k;V$$RBZ}V+*RDf!u<=#@?FXcSZu{G z>s;l5)ySH4BjIU4mo*(@F3<(_S_`Ince|h|i>UxP8nSv)S*oms9LiXf-g$bn}S_Dhj$1HqjbP60-OwYSdLFIMbRL z#c;d|(WsH_CKSmyN#MRJnd%&~9jt*Y0$hr9hT9FcQg>2nE0iDf3iUEA0DS#W$XW7% z)hWQr?;uyb816)(bFDs`GDLHAWE9jh$C9pEF- zS&Zx;LBL2Si~<)b|HqNFVst^szyZ%;8^#4rh0P!aeIT!jbc!`BM9uN9LnfEDd#L+_ zzkir3I)6DS!Y?&tily`jwGZi%kr*|H9)TjWX;NlL}Rfn>@ zaPWaCuLJmPf|><6=7|dq|s(qVR0q8_nhl&W zD*o<}?|t($eSA-Dfi4EvUr_pG>x^-H9)3i_`Ir^&zrFWc{QfkhuW>LI;x4>Oi*ds{ zpUlQPK#MAny9-cUV>*eKdAMk6lf{>jEwOA2U{-2j!-Su9IzT$dBh&)}5zJ_3l$afj zS3t9U1rn2I`+G;mP$UJ!7m2ratmI!A+M zS7$Y0FYLS@c9a1&4XtffzUtuwe(q>HxWfmzXz;{DYH7&sTJUr`AiOs`tCOI?LS{iAo+*nGW+iVerYNSO21fUoIN8URmC%WboP0EdVU6X@BTKue7VMf z=uv4uj7wOI+b!yjBUw{XBBm|OnEB>tI+4=>D5ECF@F3BjM2?lg50K4z3qqnQ*GP0X zwmq;*KEy(0Ces>AkQ8<(&{%?eFWSO#?6orTP@fm+gYyKaTEgH$mqTUz0NLa}nQ-7I z_4GTG_ifPhM?Sn|6V zkCQypw)r-|ByWWans?gITqD4#MIzT-O;Fcd4`aKG&$T!EJ%G|(p3UPaD(hCrr);s}BMcM+~`ul42DUG|33$a`%`Pv0&mip#VE#PxE^^ZA5r+`9hJW0GtI! zoVw~pJh=KIRJlUYwKF-}N$Q!nxX#YOS{a5hOkdBmTY0B#55I@aiWJ6K(9*)7B?373 zRASGfW6jeQW2f#Zkkj^?R`!2o_~oD4^yX)Qxta-bX=fyn{|&@%V>eY!}fG1S`3 zUi&Z+JUMfOYKXm>D(#CMu?%y4ocKUb@!8U0*n>s>f0mtFme^c2lWNCo`zX9uFvUuY zK%P*7$N8Bm0`VMuHIN9Xk@I9OgE<>%dVxZB@J@cwy*|9n5g zosWU9SNhX0Pb#MLi&j(EInIY<{UqPOJ2*6Fbejqp@Mtw8KjCFMh&`(+{+IUtWLc6U z%Mt|d71cM{geg2c9OTpq%JvK@a?9$CFPeJMlvu>Jmk6TzfvV5I!%x(rKOyi7u|R$R za?@$pq-Php${W!haEvy*K~?xR---D$3(I>31OT@|8F;3uq9V*JqRfXcpF3qzLV%d5 z31n_q!tjB{IaU(@KE9Vg)RO}7B)U3*Xi=fnS#C*`u?#m;rl7kZ=_oFoq!rg$m(TTt zIB$v@Dj!Hx_WJ%^QpNhD#NE`?tFd6GCAf5@2}a&bCsK22yg`AXvXm?MWv-U~dtc;f zMBP1CbG*A9BAEH(CooU?YD>T()W81_4}Dv?b(W>ev*H3bX3 zS-8sD!9CL#`^*m?;ZeHg!17rT;~w9cPv*y`J9_i%-VFcyH3&uVe!lvXM}+_Qk1r$; zb9wRYjCpu`n4jNg`4{__PYM2qUxUPv|2_lqX-a38$NS68v+YDj>F9*=PeW>REKVTm zp~D_|AVhK!GdEL{6&GnRssaor&|9tw5#>h8>7mQMSebmWT=Z2nEA3zfp?03*A5eu~u9-UWPxg~-c z%){<0$v0*LT6!3M0rjFs-MMBCm@IdCo<(_wn}sW}sMyaeUTuy~=1fcG;~Ai@ReyAm zC1iMz(*4Uh{Uuj;`7qIM*)*2Dc|SVO59s`bqbIz)=wPhE(RqH5ALn208-PDvU8dh% z`A8!es9jD{FOj9KOaX8j-*0g3andY*c0aoZ`LW4sI=5^LQ>STh${>$^x?F(+SX zvPi!aZ5tqN(#anj`1<1Y8l-g3TfwOQ5QdL+#X^5R_Q{^5^&!Zd&9)n3zo_)YK@fe7 zkSd96nLrN>HP!V(w=j-}xg5Rq;mFlJ1TPF7oeoM?LZ+K*%O5^`?|1 z$%LZV*mekAxdCO!t4EZxgZihFM0b&)r{vO#|GVG^sT?nKhqVznSban7gTT^`YUrud z17+e6HJpfO%bkBOv$oV7@vH|xJLaZ)RPo=HA3g`|ymH?*PYd%K7NsbK2Fx_bgaAg) zM^dxXt-_=|xAK9?`c;kS{CVov1=z8Zx|xK{%yw*$o?eFm~S7<$H}F*^$#Rv0XynGZD6r zv*~9n1Q37g#WO*`sBH5Sr?QxW4s81Y0IC$A%Z2@XMbb4~ zE{hOUO?JPt@t?GgQhlz~)X(lm2x~N*4T{CnB=c`#aVhI~V9yR7N%&$`%5V0YJfAtC z#FiEFDooETh+XW7&h{yNcQL0o&Jz9U>Hmj*d-vV+hqp2ie*rIincxL4#W4Gvf4Pt0 z(@#GIHsFTsE=e?|4W(!MXLNa$f%qtERylAGd*Q)u-ekfUwnuvs)9?()N$iaG8_luB z;LIj6@+w}WDq|YVf{UIM&{d|m#nV#j3gLE3R%ty)SN(GnH%0a}|5;sr>fwUgbRU@uhzX)|vo;%K7ED(PvHJ_p7V{ zG+umI#+i>ZxrkFvQ zmGmeMTf!4F;7Xiw(!fAC?e|>kb}N85CdK&)5#?OVUmUUA0x3?Sp> z@x>`Gc=v3}=H){kT%Szv@cjwC`C<#(C+IXTYYe0)VmCnvjfny2{bo|BSJ zo4fgUy_>f+ck_k!a%K0Y&2%qwOZT%@{a*gL^YL^q|HyapkA0e3ILogmc~G3>_eZ&9 zw%0fUarbN{7^pDRNvc)<|3iz*iAB)tJ}=L`sh;&?{rAt?-ye2g)%@zmU0>_D?U}B9 zSLMOm+vxlHQJhG4@N8(zhTayMUvnq^d+`ONd>5&mnKG@|T)yl;|>l z_bmTie zJA1f#HpBn;yBR*oZGVJS6a9jg7hf_~)RR969`xD!1mAp0!W&-_Jvh}k6>yccsk~+3 zKti;gx0}o>Wy*NNCS?He*9^OG&j30~~YI(&VF^E@D zJjW!)A{}FtoK4Cw$u!i7jlq;lGgab-BBf#94tO|Ce_#6++lHnevA?x%Q)sVlw`p-+ z*9UurA^|Pi>FXH%l{x?+kjn9T>?F0tvz7kRpziR#BoIJYJr5wodXcZsP!GY-y282Z}*3{e73s4$9&w$)ZeP`^G=HtJAdV- zu$Zt-_Q&%!PcE6Wd8fP2I=VcsIWEO+hW&NA<{DU6#L*k~q*$Bv*kz9%%N#%@M}ct28g!>2%nDSIVQPC~?#mNPe+n57u_+`R->~uq*)B zon72`!G8j9E7k7)ntBjoJ=C332=Vd|^x^pTQjY*#K%&38u9at1gg)?v+DC<6Sr>1> z<=u6U!vG7MakXknj|*uY^WvGl0o}4em3u|!KyI^(c0npn&Z+s>>6qOcjMrA%cYyW& zcU!}729;B(c_KPADwS;d8R31wOikGZTJy=U>V2N348*xi({|6^T@1)Fe}#&~`FNWt z$jeM^Fh#-EtEaj8&-2xHGL?Cf^-G`qj;sga4qwdj(txoUr-NjV{>@{O^dAp0c3$O& z|E5UBba`<>c$(5l2IVc~A8*<*zmz#*&HzGt`C<2oe_)RLrsgu7u+)Oln}#O&3T+DW zs+QA%j}>?eW<(kwPE8wsC>}^v4`ce|s@(`P9h!4QLI+DUR>EeMcc3!@1 z>=z0Wz7}JbtC9+o-PSv!_Ch~h))Js$yP<@qp>0$PsEC2hnWP;6jOXJtQ2~tlOs1RK zvo@FgEY-x{QLb(4)89b@n4nv1)L*VbaQXdQ3E1A-qGi(O52HITj~uH4QtzLNeS2Bw zF)lD=fmZp|q1T;8(C%3}fWBxhelarIx{4lHUeFitO)N^$_s2%nC%mS2fbe-KY`2-t(uXTI3 zP^F%ta8lc2b!Z6!8kLnL9FOp@ous}qe-~G0G{5)gZl^m!O4~kt{ z(8$R57GEItG1jGXG1xpqp-^<`aWD+sDc}uZoryh!CKyr+ar(ss4N1`6Aov0nK?<8Q zsdffO_k*x}mZe_?ru8?EXXrPz&tbGQPLTHNBVha6w>8#!pt*l9trI+SJt;w@nq$x{ z7gO_G%abUd<9(L*WgE7nzFfQ@V^T=wl^WYi*kVwsVn2zsQ_=HC#6{4QYH~dPGjI1< z`aL?H;UZ)BmVG84=fAgQ{%3t4NMJE;^_>3*Zrr83AmxQu;4KP2Ty_BYdmAW!$v?`s zvvNg~grQI%Ws?{F!8YRXG0&{XLy1daoKyb6^N&7dE(1k6#@X27WSJ|;1h{1Tw(_T2 zRq#n;J2Kl&#tEy+G}~%QF4Rc}JYh9E>R!RbQ9noPfN-q^CNFeCum>&0>jY>NC|2Sz zSMovWYcz{t$%slM8(!u^iWeVMbkf53zYuJaWz3h8#?Ct?#~?{DBS!$ zgHqN$$M5U7L%Wyu9@}SM@7Z=MP`60&SqJMO`_`l3*$&a3?L-0KCBmVbURQT?u;(N^ zv3(StSmMZtlLtyLFE9xiM5m*G%yV~xN20i6vo@LE>6%2)Vx`^gPVUWDNhpf9GDQKO zYLCz1#YbT)FO_6mdB5|lC4E1?{)*r|c8BKS%pN#rlK)EHi(B+YBeuzky0^H-Ti*Wc z^oM4r4-UOKY4CaGkI}d)bCp)%*j99M%^B%B-$?}RmTyHM)d^oCGw7+lmDgH4D7*PR zm-;Aht%df8dqBLQVQXh}6pB_V09bL^t%7R3zj}NUs|2cT7rl;NKx>l$dx^T;C8)p^ zrC$g_I61n^J!pMU<8;GL7KHO;Hx)xFFeU2foHBl)i~*QC-hU31)j&IF>K zcfcQ+s*oRC0?;SBOat^jfwNAiA8*Tht9Nzvq9_k5LFD^fI|C`5Zn%|9<_tG^V zJGXe|i*eI+&F+)JS_6gcQ4!o+o5`#wRJ!p{w!~7gC4)$;<56p;DeH9rcaqJ6=jUV; z2Ai`@nT|vb9-k%SI~klGf0?hiOK>;0!!gi50D_kUh`GE}V9cdR$4phQRmE4CtcN=Q z?*K>COV9RC>CVxy*d4NR#oc}b+Z}B39w$r3$kH%};G4wwTvuVz*cHT}EZL-0 znMZ0Yq=N@t*n=UwiT`dhD$kQgUhi4bg z!`{kd6>n_8l;>K*?+$M#QX1AS!P@if#!QgXdocB#P?I@&@Vl9q-7QMkJp*fj7Hh24 zu^eZ^-?)8drug+81G#IvepPr8&9b8*ZG|Tm>6mbyWL{2Y`#= z#B>J7qTs+l7a5T6KOnf5-+%jSCG8j=J^;WQ7LXUMymXv#QB`r_d{!L6{|$@ac6y)g zoSy2+dTP8e+b8a5E(!q>U-t~m!V~Y9L!JnCYTJl=1PRqAp*2xfY_`l09vKXfx#dP0 zG{mz3>z@#+)a8>Pd>8I${0GZ=OpCNQR^B`I0#^H9bZ}at*+M*9^cz}FbF1yzE;zC-zF71ufc$zlXjqe-m2iXZu`fd@ncjzm5_t&%&u>?Ca@P zbi!bvj?pdyhht(?XY(ve5B%TJ7>Q3bi28mE+dhIW3Rt`1CKo=|OnoUj7)BnOS2{06 zZzI5q{?);&JM3Hj}}`shIX0lsc7I75P1>M_#UI z$LEu#c+u53b5%&5D^H^bVBx>00>Ba!wA9bI1hjrI!{Ga_9^d>m#|Rhg67_1c|=8-GO18*6Ay4jjam6K_9A@ZDuPOD8iN?|H>d>xn{^z zaz_Ar#d^LuGz5S*`#FF@K7cE5&_Tpyr~*`I`bHH*!t_{zWLv5zMx8sF+S^i9>J=@y z{~!v(i|LBg13|FejiMhydwp|V>`Qap6=o$cs7t@5{G^tC(A+7$ra`zT?}J!4fLn|= z5219W^w&F48mMc}YO$ZHJcD`+Y;E&Cv|}Njs~fdAc1CSVfc#YXTB3!vRI$A(C88aB z^K9eu^zlV5EH`aJ1?4hssn%nk(ZUW$5@DtqfCV1riaB$8=7(iI+C1gY>;io~Z;rO= zsh4#>*Sjmu^PW!b5@&%<@D|Ves|25auDS01*N+J}JCKjvm!!OWrfmRK3;l>4KR(G@ zlPeN)mP_L7AL^gZfGmnUqbPWr!z(L?(?qtSm}FbT9MwddootQV;|FEERoh361DU9* z@LW2j9)ifsw`@pP=@JZauo0C@!3w;k9%V=LYYOKX5~BJT5O!!cz=DB5j0mAu{w92D z)h+r)O^8hIPx}zo`w~ECh*{+3flcr2_(EDNQm{S}&S>e+EVgYR7q7?uoMr!-UW9&O zK^V|C_5H1L9%CELy#`6U9}CU(<}`_&;_CDggr=ClqDg6O{f>4k>b`6e$gMI0Xe$ZosaRgK2?2FR?Mz_x&@r$z4~~d#r3#sox=O(+**$T zX_R`GQmike_S<6h$ms6Uf19a!U9RssCn;>?%$cd}F3vs4UcSr2r4EZN{Ch8z1CJbjnME0>k}AAI~$*%y0xDZ#iDe&Eav z@ejaM1qYDc@(=T!nzy0x#=Qy4W~f2BR4OJ_sOR58!xXT+@kFM;%T(ijYw4Bpl~>PHDtvQb@EA{{J zgTxUYiC!MQn9EBG#v%Y_f?lW!wkiB7Qx)%BC!s3dx~H~>EEQifw`&d{c(PX$nf&8! zCXK1eKRl3ci!wctGzdModo+b@l~NPtTkj)~tT)b$mEwcgCqUi7hp`$YKL0MtB{YzT zWBnzaa5xq|4BLnkt^sUnk40dG5dis?wWBN60K1pYit0V~7pintnhxzRb`22D`GLiM zn|_y4cNf}^+P$gtvj@z$5Je!rwGVL-ylHo}cKlb{g!G1S|D2fCE1FRr5F%JxG3;AL%Z4*i+}`s2jDatwa7joWEr7%J9Wfj>!@dG zmYwfD>wvz`dOwa#{y8`HFbPFr&*VT;{6a;@s}Dca5yX-FnYjP8Syg-sAgSM5zY4I^=s;f^{QRcjsfRcu`-|lPC!dq-ttA)U-G1N4XDdDTb!s z;ds+ll+OEeNB0KLC!sdn=S|PJ+j$g;un2xZ>g=S@_WE&Ynx4XRbbKCMv$kt$&WVdK zb#)PSzXNsBa$66E#lpv29D8xGR2?_EJ|(FZZ4!C{HOP;pJtNi65L1Sxvnj66uosgy z7M7BQ%sk41)SkWa@;p2B1RXP@B9%q!6 zM5Q9T~A?PtwOU zW+lRP9$`D0c6mF|i<%B|2+|bkbWdm~kxr6O^u`2M1K27a) zD?r>xZMR5lBT0O*)h&_|G*Z*3E?TJ@$Bhpc41dCXiTBlm9Zu7tokk|dD&cxv(4D(@ zMk^91g}&Eznv?3{gth&CER<#d))%3EQS7@HKy`6X-LY^ws31Ll_TDyiJF4*6i2-LQ zl1~oP7EA0GBHvx2$A1yCHWrK~;fck<>6$h1#o1$HbCx48%KSC2yA$qge*eGyOQt73 z&pYFX)|qpc%wM|l3V<md(#fU;&bGsvFtCpIs%ZzZ=)34fMo|d?Opjch8ju) zx+kyzAXr(ftlCo73c$z3u(qjpGo%_|P>AeNj24C)o;|KBg6(V2?zQ6;aYb^E-x*)5 z@5|swt`z~z|Dra=O8KciMyw@BT%fa*!{KaIVUGK}i!}wi19BdT#}cW{=JIu}^3GQT zcXuR#o9k^eNozsrmRTUBhxB08B>#fIG|H~T$a zCgG#hMOt_(5L35F-=iOMsshcTqQqU50S09z#jzbHcbM$u>%kTfT0rve;>74B)Y#hE zwtZCAM(RyI%L zKCaly%P$!hg7dsm6;I6pgxw@9S*cJJ=KQhU+)*GF3yOJm<((?+SRxJ%AVyWN##bl` zr7x1;a-rSGcx2zLMXQRS+3O^uB4L0}+;-wGfZVSeOwyrbOO-@vzX{LoIg0e&`NF|< zkxp6ky}XWU1z7VwrVcjZVz9O_4JBk~pJCi#G++;-KEU#O49dGjTlKmT;Mp5kYp9_F zU;yTwlo}}-?_f0+j0_et>)x`;#BuP^zUc`F4otBOJx?X{2$Pu?knGojHYL*e6 z2$*b+u?3S@F_GF8yV>bf9kwLD<*CP`$UENC2f731aGC7s@u+m-`3Ch1SY8d9f}g)^ zPcl{U{+F8n%41cqRmGdfN>w;-?0+0qleQY7PjhYQVBk2%AYOR3k`vPr68KtaV-F%E zzr9MxJ^scaK?cd4#5$bD-DqlLr!ZOLu_Cnu@iR)(J&=Tpmpvd_*4>>OCvruur9mnoM9>#Fy4alBvTsgrus64Kg5tUVT1R1;7vrmAM8qCU*EB4Gd&??#_X5^_P3`%S#W&6b-vS z_&{@Bv3oQpD;2Ysds+MXBsC5ouE+yZ-f?s&$>yRfbdpprS!pM+RLN2_sg#VU*$Ajg z0N?{qw@6D-Plb1c=h;r*w5~T2XaHX9zAuuDGj{&0%<`dp?&|L?5TK(`h6_oMR)>p) z{j=nbgFUr_NwW~N?KJls+U-jt?R5ol#S|=nYTcT*o`wGEi_@Y%(ApS}o^!vj*1pz$ z#6AQwh0=fOB-0T^)tA^-TtuIz9SFzdx-bTDfY?TtkcOLe3koRq`mB$kWK;#2T`^56 z2<5r9aUjmGd)mz!rQKtRL7yaABbSFSF965#@^i-S8qMS4JpX<6KBr{@ zIL^vC4y(zb^`^5nR>jsNV>WZk)I=t;G5}AuHOkx-x$>@Lr>)y8+k&BU#vVY3XHqJ% zOg9s;h?Bhp7J+XuqHYq@3h*NIR77(QHqWa4dU1LyF=6;?y49je144@~04(BWEhh2+ z#FrJ}a4{%U%s_Hm6zZS-QhJSBcE2V*k4O)UlzDbZdpx}M3PI?OLEz{|ziD&d(A-+n zhj`rYsqbsEo9eC_QBQqGs9iuUl#peQ2Iq@ek%wyMUmU4?PKhA2pC;OAf(Htov77z& zm~D$q>7D`kVj}grV~T84t^OmX03+eDm+KBJVE954Qa_ z4*|9_&RW;31<>sdQxqFj7VP))W@Cy224OOza|!7Oc^j1^!$2NjY~H4(ZJs<)R(nlj zro+7i(hiZXxL;I2xw@QogPf|;q)uw`*#rxY&x?IA0wI^;AYOaJIcuc{TAkZ8lmKz? zp@)atb_l&x=5@&N$X$D9ULnCpZIlG0#1*uSq^%3jQ@6FYu$6F=Q3enx;{S2X?9 z3(LaLmnBeD>32EF+avv=QTsjEK@=LH?N75f1RlHZW8445Q-i*zvF`qO{7|IdjvJ2D z&jRS6Kd_{FMs4?9t-oh#xZn62uRwdPj&4{aqcrc&*MQICduxx(j@WmNNh+0Gci@U} z6sk|6C5o_v?0rWXI+G!nP1-W2yq%3N-tulXgYuniqVFyfoaOp|mBIPDV@t0Dx)Xi{ z$}6J4(_K@cDjphD@kQR^?C;Ojs^UcBRj_~i@u_5*h0V_F9>oRI?2U1kW|GyLBwhte z%V-`!q*-ji{OeWJGtWHb$)FQ_7hIs-jRD-=PN0G0`6mxp*yJXx8dzyaxLgkcB$h~E8K2RG9nQE@ zC<(V_nk?5{Qr>v0^o0CfQM$`nd>&^V(Et86)eO)d*N69#msbXixhO?&u4XRmk@JpO zRa|{ToB;%m^D65ZK+rOPh}Kp!f24^@29R9cjwNGp01@CNi;ZlV35=#7WhZ(#Y>+}h zgsL=0b;?G*GZx>nKF=7tiNCZDwQcAoW0-X1+yXX(#u@+$eZ?OVFsSX@@;rZD?GuRi z5bN)OhE^owQb%p3^tb(OU{P;#SttD>*1Pr|M*u6=-Gs(;bDN=4rOo!a;p(;RZewLk z(Xt(i?O<#7u3|A@d1e+wD+@9N?q#PJu*a&!b^+yyC1fpXbhhNCY*@HrnQI%%(j&2D zj#UAF!n@pLfq~vj@CAp<%u4%@pt@nd#O0L&V<~Ln_V8nrJXl=Vs^Y=D8Q#37`Ld49 zJjP6C_A{H)s5W=<_^AkDO`(Is96;18$5!{^MO3$B%tuV>bp%mB^6eZ1DK45Y4JMTz z_d>Twy)-x{N@zW(V_QMf9>zahDiueZryXe8>-*w;tpK`mZaLmcbY*dh?RR|#Xr;n6 z2{krWsTf))8gKdyFdT0r;|RhXfZe#VV!VOn*EfxUxEKu2?H15sT~2v)hkSfNTyW7W zhxA6t#<<Axq5{n|w)r&l5pX{Dwx-rk; zi@ej_UMe7SVhPDG@$yp?TwYDdSjxwm0ffErxP1E{3E#w21zspkaYZv{oZV8|ZD87M zibSkN=Sh_eyJUk#XbLP@ZEdj0%oC41GwJb}>0+Y^kq&+a1TG}YDJ{rBIM#z$8M;g3MK^SrPrwbUgJU?ji>ouYNNDqWgjO&3$!&;@;!9uZEOkjCGjfCAT zOgAlRH$B(b=jFjxlI%KO%{lau-0>3;tDPM(oZ&C!GTV%`D2#DRhO^2&j6StU93 z3Kz}*!apE~)x5q>B?Cxu_vj7V9M2`i3#wK(f34}5Od`&kuN@YzArFqNTQSs-fWgG4 z6w;8cvURim>EWW>izmm4876kzYWG{sdf(%1``Xr(Zjg*yP{)NNM#J;;+qK1`zLtxd zD?MP)P%_o_#o>j*Z*$X5p}h}UJi}%eqX!np*Gf+Tm8F|jT&}w# zMBPFj+FrwZZznE-YwbX-+YRDDel_i2()R_7YnGhK8;d1HV!M4xRZ-5F**W`;hRK{Q zjAj!1VzGQ8r5CRfy?ybfI(jhu$j)6JF7p*BudZawq(1Y;{}RJ$ewDR7IvKl7`USO$fW1fq-<|WogEZt{~FXGCmj`m?84UWz--J$9tW$I6l7MUYC=n z2U0(_#zCU@r~B?EQ0k@kzRuXzlCNx!cU@f+2crhmZ4bXH;f*BZm1ZJk6K(`xh2J0X zu2|@z`d5G+mVF!12IF1NO)zZzX(*Zs%FSMD4UmZ%MeRb7ytas_sI0_X?RLqeuHv*P z1}eRm=SdyhG(<7&ew-a@33@%BgukQ$~dza@idGFwO+U?l<- zd934Pqf>#npLNEsxg^ps25s+QC;`#H`zwIA17I_$u}afDh>oQ2uED152o#Zf?j>KK z=Lr~O@5Ad&;O~9*&#SwM{u)|08>E#sDmaf9#=f0Goxos6LCZd@a>ocS_=n6Dv-jPzqX{0|Pw+UexF;Jm zC_kEJ$*08>#k8BNme&DTeCPLxZI2TuzXkak4vsx}ykm(`!FI?SEK~*O$D3SAjz|VB zAp=pj-JP`a)B$!7)S}E*C#fFwE&Kv#R_KHu@I1?Fk;Rtn(ex4AA+U^Y=acz$;T;VQUIt6E~Dp zEUbCuvat*x#Q}tk$}cSoi21^Eyb4*lXA2%gVpX9Og{|&HHP*3k$N6sp8-S?F3`@ia zE+@NW5w`ff^yv(RM`H8hzG(U($~r#5paR9%p z-7SoF9vFF!>gWNIbd1e8C)*{GTN;(nnH&Rro=hqRBFj0M0a-vf?>?EPVDDGlR=eUS zmm1V-e}}D}vcBj4l0+Hr;WE$Rhe;GKL3w4tSTODUBPvt{$2fk=Gk|(P|UIO;$Hv0>P?87O8~T=Avz#rA?dA_2H(eP!vnh0c6v_ zpo+LSRMD=~rFFEDUn7C`Tl||ON~rg;T*TsHQG1NtwYA&*Qn5~FE_Mzp=k&_8xFoIa zngCW8Nr0~Z#$)u0*5b0}GY04<4rf;lt$W?oBn@o4pC#ht^NatOC#I7c zXPl*DhH(~{{``$vLVfxcdZEbN_+&{I{LgY`wDKN4CSu0EE z4WH-+k2>pvzJxwO?UUbI0m{-Su2gt)FV}wGxQO-DjCM`sy!dQ7;kV&)^i{t^vz#Ca z+RZg+vR=;sJxPEd^H$XqOJ)|T4pgkXYf_-?)czQ4$I61zbT`3S(yTr2xbp4;d*rVc zU(Dr|24mgm*&t%BiH*erRq^E6_cgE9)zN&!l5yJXMVW_^B3vj6R_aZg%{AD{o+NTx zR!E3#WYQR|n!P}I#3boMMj}0hYjwFR^nB_5~Slw(93(+R?u9B&H3Gg zhZZ;+)2%L#+sK+BD1(}Fn|qbl+DYBz!|R1kJ(LzO*!gCbRU%S3bj{ zH_PwWK&?oBZZ@Y#)SW~NNp@7-no=qPMO`GqbFumhe@?CWS9>iC`_{C3OTS`U-=Qxs5S- zXju!L33KKy*qe2)$s4l5ZelMykMT0G(351Yv2|10WC1DHw>`-M(q27h@BEhFyWc7h zpTFEmM{g>xwlxKqoWegHd+cx)*|)Ehs$e5>x2iymn|j11H7p(Pm_MFWfyaNz0-2Zt z$RsPgdKD>P`ya7ArI`AtWNZUADys&PYk5!YglX=h-;S=72sVps!rk>Q)!p#yx=-tU zz(GG3^%W_)O4oD?APw)8Rw%;(5I0gYjvPh?K-#yvXv~zFLm-Bbv=f$f*%!K4)@$O9 zqP>PzcNpFmKYw)*188Wj(QP@3zT%K%CK<4(0Gr5luziC_f%N&J#-p0`PyCM)!cLe1RdZ^;{%$qxWkXQG!a_}{>#j+9+AkfQv$o9G39 zT?Oyb)#Wxlwh_o^dKVks76qN?2KyicuY= zEQEjt-I7EOv&A(QX;^ooVqbimPLI=k_kN}iuQ|Ba+Zq^%i^neZ4!?rsl?P*+0s8vE z2O4_s;d=>AL#zs3iLaiiCB@dCE$7se)>9^%wd#(FZkj?q&bJuI?eo*N>#DCLLZ;jtHqcs2#z{#paciwiXG zRKocZ@mPNeXCZL8R8lmBxQ=RUlpW#%Yf&)pBp8- zC5;fJ>3(u9;vg)li$D?LNWgeYyZ~Pq173e^sRPDk1Tv#%*Gt1aIF^7nunvOpd)t&R z>m6TEq|8|F=-Q|xTPSAzc=vtZ=bm=y+w8B2)K1%%@IF*VmaPWaZg^r(J25DBFf5r# z!Lr_vMnbe4lajDk=f+0E2qaKPj}2nwi+P^q9qI9rMQEE(W=XH)v5VOP$|;Ihyu21* zT*`;%C`tfcX&=9rl>@)hfb*Pk2~Rk?fN;l0OjWQI1qUwKPR4Ut)HV(_uiD|fY+Eqw zn9*R8=xwPe@W|A8T%4+?05K5Uo)?naQl(y8NV{d?hjZj3Pv%}ak9CIrD4?|M2`?O^ zvnaJwb4wjC(0D;XfOSeFUf7T>vh@OhSGe#--mit(vfZ}c=+=BiruJO>g#coMa67%xd$5iME1!6MLoi#AfG?@!@ z1Y)KGId-w6Ld!sWk~{HM9++?5p9@970#x6xSFpS`U@U{^qjL?d$t&$wEFJ%e;3BWS zQ(lQr^I*7>)IFL924|*qx&jT5IR@*L2Nh{-uZt*;l$q{0XCumWJAM z2VewUKTCgcX?oW3;;~Iy>uz(-;@+@}W;f`o1MET)9`rXJb4eBfZrKeDfV|^>n{yDB z_lvmT>d~@zP-DVQVYi1$O?Vs%)bvWZCQZcPfwZR0uB2C*SR)P^i=t#{r&KaPGeyDq zD*v3X6h{wBop!#uX?kVK>m?a;`7jR`QRIQfs$e@tH!|my`6#Kqqqt^XGbpP!o_ORL zRUryJyaqPe@eH><7-LE%MX3aC{p0(5+x+rB{X{G8x{0Y5(7Hs47|!Y@dRM0(i~R9z zWlie!??zHua~{>ZzO}V@!eC*!QQ{4}=Yod7R#N>jlGcdh_5kl|)JxNcmHM2o^}g5L zQ`^>!eH+wE-3evs=p}U;FVHsT%Fd38L?MTK*JoifO^;%_6v^r_k?B}?4$00k(-di6 zQY^U(w8t)Hih|3NS=*HKN;+>|Rj$~}>j%c?pzhIJn5tmE_bW?Q%2pL@=jf5#@Kjdv ztZz{BHcnV7mJ_zkQvZ8%hc=10CSPvX z@o;SenmuUUQXJ?b07XlWQdjIBR7;QB+M(_}4(_j>K+QHj_OF+oo5iH-`;RG&GIWi@ z2JD{odVNuP9^F@IbGRUPR1ho|1cX+Cj*|L-x~O|N>j~7KQeFPZg2?-rH=PNI-h=@c z%z}c2nAyS!OyX_F;pAassgyJB>SZL5+e=c#i<;NTF zrGeL-(OJ=Y!D6l`M@*I>2P}ka%n8X-ah?OyCcn7FXz`yHSqP#+FT- z{DB1|P9)4J(<}q@4}EqoV|nc)V~hbt-u;v$G~aLLBr#KYFx<(Cyd#UL%2pMYDY{x! zcvLsggr$;t+^GsP=TS|vhuRbgLTqBAM_#ettdg3(tShF%O*H3^zLq9d_*DqfcGE^! z6jTBmZ+BZ3p_SzQSOeAz5Uy)tk$g)RLLWlE2*%H1Rbq}U-5`!O--qX<3r^d{aM$9J zDlOgB8w!G21swGKq8mC0&p}ZjuI`+|fo9i);YQ;a^mF4r0(>I}7Qfg{*$Ob1R7+x8 zEbh;&wA+}SzNJ@^coeK0-#8PBGsV?yK8utc(= zveh#n=E93Z&-D#Ck4LS0*JU&DBa zVSv+k1)E%cddcc+GY&g9VE7ae6 zC&7RHPIr1W39Y?oUs&C_vkP4U=phewg=|uP?@T@mwBt>Ea9HImNyTYJ$Y!& zVwy9N4K_4SBQ!-sp(`SHj0wd%4~uQ4L5U;E+B{xNx>YI9Bs7;}q68GB-I1g?mc9q| zYhMBSdWaTu#7JUpTBBA{=9E(-SZx5v>}mr(t(Fm=9jTJYodT>&p1AUD4~%tTS@xm) z7Pqvwq>0EYhknO|;S^X|utp12qipRL{jwlpa8jzb2qgnFDF|b*qA-h!r0;h^;Z2qe zMWug5`M%Lj+GUw%#dTpNTL z(HnlI9#7Eg?NTgkV;>s6nx(%8%mFC7N`{E(67&MddTG>-`E!b|!@gR- z`Xc6p)ctnlJhXKj>mu2Ke|-+rNdF`0xlk9%q+ykW!TDm_)m0a0(qz1u3MLJosUZS1 zU*rZ%cuAc3Sp#q7^Y&RN*>dQC%e{KMo}6UP_&SLf>$e`e_%SI}eE!OM-1X(Pl#DA? z!R1r6XJng%$pey`G8hw zBgK$_cDUWWj(JpAPN)dJ5rEozA74KL`@SGT!*RFLA;E|`7||#$39t2w!slMPEa$Xn zvutDSKB9EF2E=xKl{drTaNSMCSJ_wtMtUIhVWE_3R$^H6pGIHy3s7?jHEYY7RNgj) zRV=sNoHZ_EnlzC@u^`H4YqAA0KxS#!qaAKdSvPU=-_3sO^xqLFUp$?u0-dcW-pKRN zDT?!Rxb;E5LglptV_9j7H(utA|L%7hR`brAnYJLcJLbP5a{x)n(!r<_qJ;kg17{w9 zqBVwnp(?OY6&64RlSa3SSc6d}c5$RabDX?kVpF$mjS8Yhliz{(Xe;eyNPk4GHB55s zzk{X39&V#tSHJ6RfV-eJ1Vt9A(psnkI?$mdY>w{pdHD1A41+wmdR7y-vAID{7OR-Ywq$n}i;67K;C?E! z-DJ8I+f{0emppf_gQG{%Fa*0Nx+`UYh;9G>kX!leeJc4YUz75ha>k%h+_-!O8mr>1 z-zs1A-91~WS&3))@z^~YPINH262cS|l6GA4;@K9>!)g|9Bp!%v5=6T7V+)H^lz2gd zrXRz^iLYLYG}TF<2rWoO9?*~WoN2s1e6a4cU_XMm7!7P;MF17tsPtR!Grlh14r@~_ zby>lvPz(V8qZLOiYsW_gZ~5E<lTk`+fSkrQz|enBW0Sp+v>v5X0o=tpLB2(37oUEseS_2<&ndf# z(gudc7Tb3imAcrBzmIf8OH;JxG_PJWR#|w&gZIzXIbvC_fmUgWq|4n@vRRsnI5 zj5ZUL1iWA_|2EDw4CZF4p=Uj&3;!KW`~AF2JIvhh2?vnBH zW3-jvx@1Z)mSX*$T-x`Offj(-gDZAz`#D28#qR~Np*uon+Sky7xL~Z&KfPs1{~Q*5 zqD2MzM}w8PJab%1y85m?9hOZL`l&8HQFBaX1twD4Vr@pPgEZ}u*cl^QtYS_{HqRP1 zfNhI6+aS2mygl0Nk36HtvkMIjB=aoqMxX7KqTpRBTRELOf%hDO$}3V{U&+|{+TTA? ziIu&5j^E9LA`iDSUa5`GVsE^ixNPb+Yod}7TK@9rn>JI;VnF5+Et+KmXZ6afQnFJO zpq_X|8i^Cv!z1FzeieqiVWW_ur8yJ~u8G&(_`D(|0WGU4%j=?W(6{VSYA?s3p3^KCums(>2srq*3#2}w_EuXNko+Dg1o?xu z#5)>GuLoC-FU~K``Bu2402=yZ1t{D4!qz*Ocg5q81J!EV z`yCZTT+~sn4ImW7FMp4rj?t577QNzxDGKzyH#c z!48E=zg_OHW|kJeSQKs(1F0n%wJ@<_qbSZEbKU}Sen<%upuyQdO+6)vuUSyAGu2T( zKIhlRyZo8ClR2QooXwnHC$tOp+DKjy9O za#+o8GDVTMQS3eBq5j-+sCeS(_G`)@oT$1<3wNCV2x1@=G~a#Y-=OSxWw3mUskGFlg_l5~cDO_`R1#{dGvmth5>P@HI5a z%8p^JzG1&tt{FW~Y}&7arc2?Ar3&gY`OG67(L96LZ*1aE2)m|Sp4t~v z-POr>CeHyml^k~xI4iSpGuz!K4?W9t#hgM;$^3VHth-Jw9E;+fb(n4bc`Ba6^ZyX9 zPIvAeA#V?<7G0 zP1xv0^STXeB{P6#3p^?jh(=oc_B>i%*Mn{VJAYlYzOpdfg0%%~si|sw5yCpkDrePXqgpVaI{%!I-qJ~YpYnL0G)#cJ2QX_24kFL7DA<#gm3LR)YEZ8I zSw7C`m41~(f&RrOs!)GT%WDnBTq+>jAb2Ogax7I2Si&YZ)2Z4-GF7pQ(s6M3AW$QB z@x}Mhnq=O47EGl`#vz<0Vd3SlSXPJ>L+ymFL_!4J(KflcH&|}z7m74#^*P2rj%}F> z*se*M)S7zHV5^OAvs8{)?;ikG7m7kbV6|L`l62`y2h<~&ZK0YLfV=D;G<}HAJ_hCY zb{p;)ZYZ?gkJa|!#v3ZuS`t{Jz@66G#Nz!RQX~sx94(<0XqXR?NpH2 zn)2=}OUB2!!PD(<8-_>Ytk^uyF)d|Ev*|XtFtO|FF4pfD2R4bRKA+bQ|lPC!_T^&e0 zLt0_*T@R+c3-fJ{sQfv|gzwhc?tvmo-D~HKsFk=l_1`yqtzO_?wEd6gA>K%zfV_GWH|H@KaL>z7S0<@Q!8?&^T$Gw&Md#!j`el(9LvWE?|hCQ;t8nH!-= z#boK0JgOmi_yAD*V%|-XMMCuSN^C{3yPNsrEby=^^#4Qn;v$*TYZ8wlmID}j`3RM& z_~v1jl0Vlp;aA^~IDpI-Bw;o0STJmM04ZTLry5q1jgf^j7Ap$jkF)TQ2d(AFBg>D+ zF<(V9T~eGIO4>Ftnz&I5K_dX`C$&yOsNZ$;LsSGlS84a$!&4R(2T(!hrt9LhjRNon z5bsf^P!C;wBhbGM_#>yv6^qvfbWO;jCVLPcRs?)uS`x=`Gz%(R_BII#E$ zN*{|!n?`CAYfPmhVh+a=yO^9aHqSdB>x~WmwB41IWk$};q373{ zkMh%MMIr3?Yvkwj(fUvg^^IRH>b?+2K0b)+Y1ndsF^XwlW z`S3P-wCvGrZ;YNlY%1XhH3zTl_SMu)dl9$v4cAF45;6qo5Q4eYij=%~zXnn*9|EH% zXxhh8Uk{9<62Y3N+d6lPQ0yx%Me!RY)S)CA=!AGK+)z*bup&9H@Y94{9eq1gyyDvn z7o{#T>kCTl%WabXfHIQ7QYbSUpP>+xV{F!%_ zYufKSb;0^}~;z)^qBKW&p<6D2Qcog!hymmm$r0Ztt!w{*pS<>0r+Ooq#Lz@i$D_k z9YKtsndtpi{I>TIa1hqPsesIoX28WlA#;8j549@Y*LIgJ)lZ9E0KsA#PF?-}EL%XO zHr0K{FGsp#Dapb@a&9a=nuR1RkBGxXw7nmK^&QJ{Ve;<8b9DW^1<&gJmLD;g_xK>x zF>($Oe((rHwmuq6I@bt z^pJ86E*ZmXSPo$97|7MJ;V85jfQsfSiV&P3^c>2+${A{ z^Wp$RiQ?fKCE3^#gCda|G9T$qwN|U24e$Ovcq<3ly;q>-sqYy0DY5$dW#X;Yn z?^s``JJ;KfXJEIZTJZNFrigxTJ479EYE1_o5J<)=a~BHA;>ZO1EFCi~r{h}`*es;r zUd=)GbN;WoPIFj+>r3T~IWW-o49b>X>F=$ZoV^{aAFp9KfH4RL>L}&lK`b5ra~?pS zXR3m&Dy}oH^=#HbbY%(%9$4ZcO`6k7(<@p8H%Uis**`d}AjhhhlczD~flXjrJ&AoR z;RuzgfU3aIBQ;=4l!02-Ac9B>HbuHF$FRAkSBw?FS^>UNXZLw2t@Z(NmfmJ-l6SPl zmFwyki#Gbtk*kJ*v|p;4mf<`5`@IbkZ{&!VEkeIz8MV+aRLgs`Z)s6`bI*}4j?cL< zdyC*q!J4OxLsUvlZ&a0bMz;ZY&O4MW&l;PB<5nnD=k&x@td3-!B%vudqX%bzW-FyT zUlIIer(2Ux0E#u!Yg`Us3<`b%faf+te*cNSa%|Q8{aLIk*c3;?Y97y`jM%6(#YVmI z_L@OjLTEBYk+*B$fXtEGb|e|3#Um-x6<|SDSn`-W93d5sLM5pJ&J~ns(es<{3yPGe zKvii42QB;oylDjK5&zjshQ)dVTB)OVKWA^&^uQmwKT|4@WT|2!5=!;FmGY7gQ zzJ`m!{m`)ezWANg#ije+$$)UdqVK)FU}`BHucy4m-vX+{9Diqu*XV`i3cEW!CCL{q z5u39IXaIQ*7Ec1iGwVnsY$lmmXZf4d1=>IJ+&Qxh&=MGE)`le}%qR63yoQQ9F9$G= zg{g{<&h!?ftVkLbpRbvCnFjI2O#Ke zj-DF!_f3Pgnm*LuGJ<#grn*T}*GQCRW7~S|QWEa(H(pbBGVv^T!!N6b-Vw=8G3k2? z1>n0mw<+d8@}6*%`C_shcdpnzQi@{7*G^ldDm(+U1P00!#luVma_nM`oOu5Fq*q!i z2Qco7^TuC%qRC3%5VvTOtySJ)Wl3wk!plV4H19MV;9P8uVZSRuwG-177C0yb4B}w( zLQ7D|{9)On%X===nA@%3QUs$?1|U;5qC`W9+0R*Ul&~zL?RiHal&X8Ft&K~J3y{&e z1_0B58ZEACD3dk%!WRXi#g@M7`r5~FX*;g~+COJ#e*-{-B^`vzg*7&@c<#86hHva< zuh7$fi#@LcvMre<$DPD4RL2Uu$appi;JF%cR@~DQ}`ABpt$LaJqOU2*i z8{`bo92=bH)uTt6+~M~hyw)J>4wv|I83K#@9#=XS!`0!+)XR;p{-^!8%kBk0r8W!u|W&<~-` z(R~dIj$u!Kp}NSGXWd*DIC@;x5G85B?09i^U$I?49B31ki*czcHqU0oMp4)()7=@V z3$(@I7H}2YA5F8wW)c=Q)~$!k$)n+oElL|p#jN~3&44W#px;bFQE=GW4=gg!bFF-@ zb~%7?Uu0061AOoSh{+8bq+c*qu{WxM(#dQ&@x(>?dKQI-aAYvgEE#*^Qr^Z%ZoFhM zj!C0iiDV3xx<)+lB=CIL-kNs1hs*eJIoW)>i!cZlLoLYOH1>x)q#@u!83q;b^$!~9 z{CVcs+BQGjKs~p69o7d`^7e%SZ=f*ZV$y%V0Op}YJqX?doiyC{oR;;6C3i^EGz(_D z7ox=iWk$ly_0%kKXhEtl3d`yh%8yQ*k}Mgon`Daa1H@WrLTXbil~^rV2x0eU4i2<6 zAf7Ym;*+en%hK@XFG=!EauVR*Jl3`k6or%n7ykl1j#i?qtQ<{oVhAYc*QNR=xCh^l=q z+g@5=MVY`IMG(u4vmi=cSleo(t-)oBelTFUHNfcn@Y(=NRCKLe)3!^CPB>tVu8W}N z03K-^9JIZ#x)^|XT<~x}F?gNzJLAg3^>D-e`2sRpsN(&!7Z*vIl#wVIpcQ~+0GVf~ z$KMv$XE1kuvJB9?3!JL6)5hXbY%C@P2L`&%LdxYeaj4A8t7qvcTO+aZj^`1Vzq=wy zI{LwZqVRG6<56kG@TVMtU!~%^cU2pl2bb7PauyH?C9i{W!=`Q$wF;T8xK`^562o|$ z#5ts7&J`e5gZf#NCCV`fsj0*rp_x)GgE9=1YE_!m8;G=l15D&;Zv)e&?*8#04k?Ck zg6*uw77nAbka!!)qXVGO4?A^ntbgAq_n`J|1e0ZPy8-C>`g;j?3Bb^tyS6|yi%{RP zFHD2>7j5`ozbhz>I1qbmDpe#~7ChmL$!v^KttafyGufD@DT6Xo6e1ZFY!A3|`ye+|;YqRWIHt3tVBaJT21 z0j@ENLu>#>vAUXdRY?$UtW&=TFOAd*twb3l=U&=et9!wD7Rk>4Z2u4eF!@fq)^St) z?fnKRzgsl?yB|`X=lrq&jA)?lwfRKhncH8ypS}%WK%0dH;(8=kqXTh~ijznHYGJ{_ zg3zpf#4<>{Ol60c05m2=iBvf2_)mM)pD-BjuQTZ0olnk=)7i;evrrUwNaqn3wxaj| zG<@w3d(^LNIe_s^g|)mMz@%gV$*cQ54?dQT#n+xqca*Bw%iv5FTz=B{6ccGEO&`2u z!RN`iI2rJgDOwHe4dzrh4t*I7Sz43MDkzR5x(KA<>IFzG3Wk^HOyMj@1Q%-C^R`y! zUDqCk2Fqem_x%fr&)b9nC>DSU3sV8ad>@6PSn$Jeqcq>tANw&n2SVTbW25sLi8$Q4 zc@LI=^UeKM1#RqGb8ot+FCMn+&fF7JlIj`|YusW>Jjz@#+8?M@1&{G$nV^{`#$DPu zUp!?Am|dgA>n^XH-)2FE=aDD>J(u5t;DE+b4q&`i*iZf=n;VZnwZ9yDmBVVDD@Q9S}UmkdNXD z#*t&#FLsNbX>-%<((Xmi z4q&`eO3;+zGyh(K(_g2W0fdd%^MDg2-r1gJi*1al2H9p#ErIgJc?4^oJXM6`3RN+J zP&0s(Kk0zxBJ(|J!7y5MxNoF=Sb-GgCY7qvvJf3a)}I=~8-c)N51=&aEf z&AAb0Mf#h{d%u^mpoD%FDRCf0kEF-gFMm(nB|}$`a1S(kZ|5vve3kpft`qCeCi31* z-ze^I7GtJfQZF@N_UzB7yEiNjN*;@XmDW4?W57Pk|a{%p_Fm}2|`PHbZN%*%2IYr7`L^6;Cr53pt`*WT#3Q*S$j${C9Q zK?=lKLQct2ifwSe*<=MCWK5pZe#;ca6={S+j^n~Y3tJ&w-#_Fwvd?f+8|8_~;%aNiOSYuQJ2$M#W;8cw%kemoCLUGlVs9~8SRmP` z*(XyJoFRufW0s6L12kvQ`4m*RIftbk=4)OKV0=^IG0VJ`xJUB{f0{%a%&YtpmX1#} zl?+=|csg=+0NErDE^iqSEK#EeQE|lwhJj8c1(Q*vC;?k+z5rkcYF!!gj@2gkHdCv3 ztzR>G97Vk9XpA))0CC)2t332C`u0N7P6Mv-U5o;|`!~xzsYJT$n@iVa7ct;x`+g1= z3>ZUnZ=+qL=0V@FYp3+z7M)?i()0GvpjcZzsH$x{i{%q)CJ%R1D)CmJCQK+}8M8V& z&xOs2>Pog|*2cV=pIq$qj@Q0FK3Gp?K&^9UuFn*qL4&ccWMH_rCDl8_#*iKKt(MAwgA=g6|I86Hkrl?Y$>{bO}W#i}KgPCzDOcoVM0ilG1ArL3^+Zb3S}2JnNMX#os%*W026?J+7UnXmLcoD&s#Yc|R* z<(CDl5#M!#(knWf1*7kmo}{0lr7r+mxAcW&OuTh(p9UF8{Q7$4VnYnnI`v1Lefui-Xg=--um3(-e7l@2-<^$114s9AT5TFLG^PJ&Ng- zh+fl-9&6r8f~EL;&4yRdJr#n3n`NwDqt=+)0Uqd$(9Y}FgWJm1Os4f`T!0nbph~W4puna zR>Sa^1Af1V^h&bcylYqj9ph53bE(jQ>uB+*bHFXw@P>Zh*5Yl~ zwD=zG&5&_%U-qlV-vGkz7GpLqipj!xVN-sX-`9vnwwh70)>UaI2@!%xTRxW5w%9o0 zd7hHRF5Ya^)Qvsy_IWOB*rbz_jb_CPXUKVnIK`4UQA-rW|K&WlbAABfK{-gqw-nh* zxxFz{6>hM;c_VMhGF9=+GZ;ZHP)$ zxD41x5!k$M`rB*qRcZ?oQsg@$r+~QFRxgxc6cksTGHO&t;8re&7VNtVm)B6+kG`(h z3N`2X6KvZo?YJbrb`L9Uj-=6Mchd0FEk!h>ihNNWJ`bqUJk$jV<2@{P9Qs$ly>4LC zn^P5a>H@8uGiuDe?m**GAY~wSdt>t~wcXx4brIUOHLJ(7%Q@Y9aF%zDUy%d`VlUSB z0VH1dp$y9bjBhPESw;H`AA@8j5URr5J26ugoWX!;iusCm7si> z{i1}UwxUXwmTh9!AM815v^W%0;Urb zew`I|=KR6#o*X!cj^-oW7H_1DxJe_Y0Z|3sv@wsRN%>;H5UZm6)j;!FT*R>sv5-9G z+9DW^l}YQ|t5ofX1-HYzg2vR+2L2tkq(^Vk73q@^haAnZhJB&#J_ddByZxzC7q3~v9>pkLu`+oLi)SqTM?#H@w z`l(IfJO$eL*(CSyesrxh4!3dP&FL_1BmORNC()l*d*CZ#_YCy{C>9@KM^YA4k-C?C zwslsWJJ47gH1}t5frenwBhE=;LBR<}lVq#0Fqsl_B?GX;_ns^%#KC=%Pm0TGXTUUwj2hMpHLGJZ9ZlKuUSAT*#1 zn)U$}G{sH*9hJpe5DzSP^5waMCs6v<&@! z5yp4XO7-31L{zp><*pTam6g`ptX4u)7X73YnT|nJV3ysQW`72?m-pDk$zpbM+OZ7X zl4wC7azI z+geIi1Rk_ZRitDAX*o$H1GL93ez#H-%MKojmjf6-XR$4w7PhM30rsc-o~eq*dGK*0 zw`23jVK6`Zwff&YpK&a0s0#@Ib z5%Ynav}~Oiwh^z5i%#4P^v9YyFt*f#`LfOaxkT=|tC`9bg*rESLL^}h4eJSUi{*rj z&1Cf1VUA1cMQSOA;D}8aD;9nkUdZk0s(Ob*m@%(_I zas{aq$oqLA`+xm0%eto%ym7jPtD`L(T^+;Ke3~`QC$LZXmCj(ZIm_64H*e?e!Upc; z!TKOe$M^Cezn^QlpM~N42Y2%XxSQ*~n+N`xTnCh|hhzQ2qx?Dl8U4cKa_L)v~#g#?ebQ1~HtvSoEc_dxuldtmo z%Y4B_K9~QV=I@{8^Pl90@;HBfl0Sc+&&luS{C;|zuX_r+`B@&8&+_Md&HgIWbNTQ3 z3g**Y{>xq-V)5ZW0P%V`fbkD3nmrn* zIDkC1SQXbY09B*x-gpI&8HhQ`8)-hg$qeU-la^-19-*f_cZp?2C@Iosp(oI@M=KD6 zi^EhUj2`S?3>1AdY6k`->Ktk5UR_VCz)wTqi*=5_Xb)q6ul`=B zQZj)GSS{SuL~tXD`27$x(r?^7ta0xBqF1l4(sJm^f=WTZwqFFiQs+1@;6JJJI8zj?^uBrRJQO&9@eeLh7L`?> zrQ?5>rQdBHfSasAK0TXDjAM2H;X%9G%@R0>la)?pXUxhFv8KS?$}wirZE6;VMt>j7#si3``*fn%{GxQ(vR z3z|0SHP9&4+SMblmFiXmyJfM367F~C8?W#U0LzO5X<_{WxyKGK2q&!1|nihs@0@tv=WRRw(S z!Gk<&t_7Fp^h-`tK#fy@WIFVB0!5)k zz~@DtR>EHvgpm$Fc<(i7y0y$m?Y2U;P7;JFEB7o3ZYqjBlDHHkImL8bCNst4h;250 z-CQ$|?cL7#;%Ay(iU00%tcpArvg!{$15M0;L5Mk&)p7viA5#k7nR#P&^L+R;!MpjR zQx!ZY&p4XfRued~Br$h^f+Q7F=8Q$5Cxc!UCK}OAr4)<_OTk@L#Tf)O9xQ+coUgnw zw32BrIbr{1AR*o~Ym9LXj{?V32Vzs3X&-AF)YZ|~*R|Qy+fgLL^FlkW05lTUzbLQ0 zMC*0Oe#O2*M-=pCb#Nny!%!k`+iw?A81-R=TI!CYueu^5PnNWxgll!hoduLqJSTDj91z*XrD6YQM#)YEbhCk*k>u^xoJzqJ1@sB8I zUerir`kM?l!)%?GKvt*=^lBpz9^(zKsIV%_5^5 za)D5^d$I4lE`9a&p-RND?Nu5lv>$rYo->eAdwzHX?D5=cVd6U&9JDmPwn)kC7f^i% z<-1f!ck%MD*u}-J9W|Q=l819OyLXQ;IPEuXMRCI8d8@AfoLGT(g40>j^h&=<@c2EY zC_Z4q`1}CG&sh#&{38o%LB!rzeC|I5v8v!aUw<~Mij$;)gLoUa-`e($jpU~iR#Sca zB^ZlIBcKYr$u!!|8=Hj%nJ+6eF)_`|YhUm(A9^<#l15mn?!{Cy~+e zyhiecfiyX;y57lx;(%7FN2u=1SnJU0TWQw!5d8vG+8#*yH%YU%73^O7c1B>{18ZMs z^nLw}NvRUGVFSyl2t^r8=6Poh9})|d_E_>Z&SrK=8Z;g!&+4H;g4nzC>U!3A6zp|p zfr0LPMesD&&#{ZyOZ5Xtx2`6KQpy30e{A7_e=Y+~^LlyE`8(_inyHFoR>{#^Ox$*E zo4MzKYwo6KW^PlFLPU|5R9ZnOf#-cfada)WKXyG{LzlMJQ&l?bH`l$S=iB*(bcgHP z;)X7WspyqJZnx&tEdZS~w*ciHAYpl5(DA4Xz$O@q`7U9X=d!d!D3a>(!j<~E{$X4Z zZYnDZz_oMAA%C5w@wwz&t+@19jBKSRY%Oy7D=7f0eeooUWd`02bH({@o=td=@w=b* zNdjS=9I2pj^-RY)$1diC3#`rlrYP&#PY||jBCFoxJy>TR1-Jdg33(n6;DOt zUEwVqbjx>xb9z)GzyDfEIqs4&{t%$)`QH^j*rohP$`l%);iQ`zsn^EJprvi%u}I^T z<10)|JS@%j3)2myT|DYDY$^=>vYTCWqCL&GEV7kSM3!4hPH}O{X3YexItp_*VoM*V zCEPK|T%hw9-4j)ZrgW($ZFej%5Rdu$960N@3BLHm!T12gKcF1I_(vAhxoLy#15H-? z*fM}{_`ql1DVO%l5|vJ7bIi(*S$X4xMdH}0R5D5SXet?_$?}mo5XZ2GHm7{QFP*AV z$cQ&B-vL0&-%ctx-5~ij0J7_Ojj0E-qpy#P+ zdCl5l&@V@^|Dz?Qc`n@|Nbz~mdc2PX9Rs1SSnKx^hd^t>M`}DmW}luHZ&}oFnz2b{ zAfT&~vBxczG0O|T1-8n7yv?uMFyv5(2zQ2|O^S@6l@ z&SR6j+UFuQkt?ejki;(jEky7dIEzFnx|}-#p|M$91lf502s~qZ{dbL7++e%j^VO~d zbIH95iM6j~Vd(C$@589n@2GhuVHIr79ras2P4Riw{TYLx3uuM2?>idGX*j!6pU4hJ~5~|-%$%qnz-r-`wf^f&((*X}!S}BnTniS|B zTKwsPw|oHg9%`_pYA&elB2LY-sf()iX|Q;RBy0~L`92C%R90_04cTgX2~_&Qg#mQ> zEPuB*&KS*J-km+3USM0cH$8ve?D&Fg3A@59PVb77pb{7mYdW3bglmmTzGD z$4pHeO_?Xw?b~JMk=exUhy!o)U{3q}w41k+DC#n0vDX0I9Lr0A6FZQSQ-j|(L;w^P}A5B>FGZ)X+ z`;6<3Bh>&7!h$33wSf|U&c=l&9_59ccWZ?1ap!jHd8~07u%xk3l9{wQMZt>b4aext z<8ZrYi=ZU#&pY1fT_vIBJn`tepQ2b&oS!d6|3kU493nC3y}05GgOx<+Qv`7Z z+jjfk1MiR)Sv-ODfbmu0cgmvDAw5!+`&(|56Q%8yI7@T;dqsz z(A}2AKViFeGo$3)ne5u!3zX)0wlOO1{MTwXKbiY8|M3pc0|R*=c@7NZ9;%1(+~okq zKShyYcb<1>ABV7-q(M`ds^Gz!JU<>Q@pfs?jv%rnB(b6p$#}!5nJh4i#HmP{7*eBY z>4fpj(He47I6+O!P(YbF`8eqJuzBxYF8~pxU0jjNs7kLb2;sO*Fwherv?jd9u3tlG zGPKi!Q?FoaxZ_T$rtY*)6?Ao%T}IDA zBlyNhJu%BVC7;Dn2q&~0i{^!gg__7BEsCk7I39^L1$YLU{bt(kWXwti=&g=lcJ&vE zBLATO$~(ZnF^VFW&%Pwhb$7txA6gDH#lNw5=4hEn=fK-Eg3s^f*DM{+8+QK4%Dks} zu-?zxx>>VF@6&#}Njs${*!>iC5+O?zCTMAyz|4vY5PQs7w-YszRwma}q$wnX0bl?u zLD#qP5l{+7b>}Y1V#`m9^CL~+cEIg-(D9$pPGXEfbo@|DDU|yNeQ90^0u>Uf23+hI zq60|_hOG=M&xoabYM+y~SE(1@X^a$jwLL7)F5V+`{Vj_hU(-Cxfqd;!GKi|KD)Fc| zddMP=s34rbRELjbCYL-OIW9$`yvyVEIv-2yd6%gQ+3{UxG2-h?Q9L6!;f6C`{QHL_ zp)*&8&7rK9gJk>@6p9w8oUD{HNAtGrZvLC^=I!5Uk`(4_mzgxR`5sve+0X8U2OiK{ zttWPBc+X~SCM8?&Z>q^kJr=D6?VhR@jjCr^p(6kW8|)x$g@bD{%@CXoAQs=@(vhNR zdjRs@9~eo!UH=`h;{8Qwyu9|^4fUb*fB6h>xNtyRdQx@6?m6t(M~n@3_o{WL3d|i% z()@;4BfRx|b?KNPJWJxo zp8<7;*NJ)K4G;G1RI(`~G`d1^j*0R8j@etn5^vqeX1bf- z=RdrY8_Iupnj1RJ%9i5{)0`vkC^yY{@wU8q&gV=vdn2w|H^(%>;&!0j?$;7P3~r$@ z*4ijaLKuubY}$XG(w*63=H)SPp1Udk&G00X zUr#cOKi$*(Y`Z;r25EPhwbNIy-(14c)ipf1+QY@a-@!Y7oZ+kA%@Q*6pG4|Dfbowg z2g&%SC~dfjgNemRB72qRf*jVc(?7roYA&!a}V?j`T%dPY@>>m)o}w11mj^s7I8DoWsaPi@0gg?K+%a!APxlF(8yfg9|j z#TU@Hv<*$6FE?YPPw2?aQm~eQf#S(dEEUtr78^`C70uP;rPNWujXE6h>s|W0i4wT! z_(%dCQUWV=#^=(U*DWARiw79@5rR}3&ZBy9+t*O%qHk3i4-XcpAo_&1P?uwDpKeM! zC<}a&D1ofJo7vudCpN~KFxOo2v(T{3V9bg;k4wRMX|BFe8t(JYH59YCn{xYc7Cn{^ZhRq{9m&$d*5PJNCuFn>acNXxx+RVbUuUe%+m3cI7Ws2xrZL9 zX^|u>RWmoL78SGF8-r`=Qt;bSCuxEOaE3ltDHMX_2e;D%x6%}$Ta8U{tf2HGh;n{D z1z;XE4zN(Vxm4=+vnJV6x0sY;Q4+_c{jm2By1JX=M5_|H?<$<85K@<_3kQaJmWonn zlzFjU{j;-Nuc={6Trv&{Uyqk3WqlU${J&(ArS@#Xsjf6VXMGszu57?9aM^WHs?GIrM*M2M-1jmL}i zbW9>0qqw9JgKjd#3!5YXd*)fj4+#{mbCsLMM!f9iMNzUXx9O3AtO_Wrapg9nMFRki zT5P4pm3sWUVljZN*IsnXj#Mdyddl@v1-1xo5bmu=l>wZag$T#qZ{9|{*K+6a+Agf6 zgKrV~7xgU{t>#)ViU@H8(g^L^BM%IP!m^AWx_dHf3Ul;8_F zi^vGXz0>N%*0wvMJ*fLGg!yagY)sc0UK(4AigFqQtusXglL+F=$A)9d zgX;H1dc<{QUzAcqN8x!&6fb+}yjng~059z=??#%$#Zg$$Lgn82{&qA?b6;rZxPV@F zFd;${5t@?_n4LPQd7D^SkVwOn$Hk<(t3J1*3bo=QfWv#6v-JH39(4h zfs3Wsq0nYqXZYMG_39Z7aK^r@)H_u6g}=pjksI;PxKj79#N>WQ624tG|W$ZB!AF+hIQI9*JD@?VQsSUWu6a|Nh z{VIR{%_n6Q#N}f@lpjzIVEhx8G9Z~l`|N#!|Mlh`#_&P)*T1u`XMOCwH=Ldl; ze+zw^T2WgEj>B5^^~bfN1Y;l?f-3d(tVqr`0b`ZCu~xd$M{N&=ZNy#`X_wmF#R$=g zQZgl9#i-u6)m{nqngO~b8`ZQ*2o?w^1MI}E_ZEYK6~hIH`E{q}Y)76p4B2VvasK06 zcO1Kz9X&uP3XLIqDF4QC0OOyd$jmsG1R#>E^z;0}$x4~3;8+z5#?!G5^8Iz%i*!t? z$!4#o%~Tb5VA^fciGnD3^OQSAahINP5~@O6T+#C5F#sEU3;>x{w%621v^_vKbby01 z!H@?Hmn~ZvNPi6gubkU*to1%zCT`5+Xc^^fB*7BgAVqh(hyMMdZ%x~^?nteS7BIS1 z$__gbyKktJa(O6dDY&q392OLag7+OS>S8^SEDN;9Ldmb2qg{zbaioF*;FY;PpQz5` z^nqFieI7b@eomzehw`J#AyClIQ3RxjRA6AL;xxh2Ey5dl5VL6WByqrb)lz54W1I58 zpLVRw+h-y|g9OcDbU%Y@xhK>Rn@m|`02ZnO&3IoGGwg+Dx^;B5QI9^Wfz(?;-}_J(hn1y-Xj$*TT4K?su3rm27=!T{Qe_Le zzPXv&Lh^Q+qo;O^&%utuXq2NX_t}|{5n94pa1dt82}|1r#RXbFCzFz8q34*zG+AUe z&0fBzdEV|oLu)3c(;HyAj6WBo%<0(<||~(5&NGaR$iTdr)T$znyDjs@8G#j?k7h|7c42{m zIE&32zviGoR?gv2ewuQSjDM!0yT&{XK9r9M-uWZKv%evD@RVS8XNHq24n-*HIdPHR zuo7jn-|&RU>b)!o??f`mk_*Q-7IQatUDfQ-8Zbz$D|9PrKuiL{)a}B{MqSJ-1iX@l zzKs%?bC^BQ_Mq$Mg%cnu>wsFt->43+hpL#_0#*F1$hj_|n@L8OuEN6I2mJEo`EZUeEc-&RaVc+ZK*J0qd5NaL1fMK3FOHBNC# z>hvKx30}yjNtJh!-NXLatZfqgMG}*^X%bz>w^!fLo9~80|x zcytR-T%3kVN<;k-s6%Ks*5&OiIAI4>=&`vWk|F+v)PC>swkq$`l#L`AjM7+^!b_b# zrpaPYxN{NOtBgGcX3KMz%u7@}Mwz0xo8IJbng4y(Ea>l-=f%0F*MFQtdG2xmQC! zGp{NOk*Ii+JYi{KpI9u}A1Vqo+w;(8ozd|oI(Wd=Q_s&?1Khqu(2YR13TkV0be|iF zAznL8i~2@(!V$P>K!Nl{t;^OIxMKM*SWp%V#sHwH1K+N7_Z=zL6j*maYDF=5%xhWP z2|Q$`D1tee!DLdfEbNwQ$sCU+ce{7bJF_ij0fGgI_pTHCT^209%r$+)wG$pB9;o9Z@1N1)`ly(#s|b&@qALJuP1{J{^FqEi zsaW}9=8bum#X*AD;mF4w>o7QhE?ZIDq4b1bIWQ0l5?sEq*u@+e=m5k&Svi35&slh& z@_=QV@PurEArs(VG&s{i{3@@ZnL*p()sd`Y0ANK{PS2`}Mqeb2Q z@o4vpww$$>^%8Pw?z>9hp-zBqQD|crH@gOG?#geLOw9I!MoXC@SIKH~_TaI>&O*W; zbCk9@@xnf<*PS?gY|$iRqsoMyP?vo+!z8gS&SUm3nPy{;(oaF%{WVV;(+i&mtU^(7EbKXb- zCKyVFqb+}PAHmEl*6DpNkVfq_5YF>@hYHK^soy-T5(+)wj;Iu?VfiGw#jU)EJ|LcM z0X@w7QdR@=v=hC8z9Jb#p=rDVSB$%Pp3LzhgKf&3@l{^%FOO!iE#4E|XNuz62inft znWFg3V}jp5B70T`IR1&s0gQj#d**a2mAVL7o!w2_@J6G!U zobHe+XgJ!YgAIj3UEhoKFQR#-wG#CbRB?Qd(6(8-wd8(PM@9gJH>O5XUsqNJPB}cM zuJJ)PsQX3|&L;oWRHSx`8ej&O?PMf&vC3BDo$qbqufF)S9hwYWgEAUBv@H%z!S z4z}T-yU(%o$~5~hlptM-FQ2=Au>-g<*wXORh{~Wr{}qEnOk}DwLPI7XF7G82-&HL8 zNVn4|dIZrUwjua-LnsPViyCp27q@u?^|ULJ@kRqtnR0j*>DVlD_}D%x=;){l2dFVs zBrp)iF8-IA>+Vo~+HwHnU!;g2p)=~AjjCX8CXRk}b~bAUkUa2rS1RGSnVVZvB-HJt zCo4tE{$cK|s@$`Tzd(g6geDNMb_6wQMS}traOwr6=K-jSqzLU6eFSO^IMUcbWQg;D z_Gr%S!M3}`&snn+>F=k%jz*RaeSagZ(GWI);(+>`{9YQM9@N#e5wGvhtxCe0np#!0 zPEVQVoqOG>30vMg&Eo#dV`&4`k|KYn18@WEwZRW??QDzXP~&SKrsWcw%UN*wr7=0N9mxP^~Cjk6?g|IAxu~ zMm_D=azX-9*B7%>?l@d#GTUMn5ZF`nDrt}_2@GVhi@V*`q5L%E0LH&S5!Qf* z?uYr02lGju3U9qjqM<(hmNXg`d*U5&41hc_wrtyJ$w$THNL{3v^V0zH?9M7wg>ZvR zQ=~8nRZ=1|q|gbPinvy~h`|s+9zKNc~N&UqL(Y+lCB|-(5OJ)xn3)R%o z7Wv>#kCp^?A57Y4Tlr!hk56T|Woh|WNgO>s{j|g`CO8BI`l-tSjDLY*ju+7IY>z(I z=vSNjN?A-c0XWXFIDkwXG-y`NxaPx?^f;n?F(phsZlN_*c_%K>8leltGJ^uQ=-QxG zA}pW`xGDwKd#NCc0IMAB!d7>nw7Q9J_H(^G0lAJ_#!!ExMtVt|!udT{>vZc)$b#Lg zY45|f)$CGH1k=9cz0(k_ zb9MM|<=vHLF~1Uk;AVN6n#F6bK^L!hnEIh#^qNiY&AmYLu0$HpI zs8of99kcip9&NKKrB=7@R#5~%Kc`$r)VvQB0o<_F?J7ky3GJ5kc`| z$axS!0s?_4@(|3!P84^O2LjSGUmMOs&f!?WcU}s{qP)w%ynDimygV*>*LLl(iwXYu z1Avb|paT~FJmo-B{F24fF})8UQLjG#93WlVG}Q=O z`77mN(#VEe^GG1moayd;O=RrC+^IWUWpaW@HD~0+|KXA zHsDZx@^X-jf59S~>5pVQC-^LX{QY}b0?x1Bex2Y~7i>W>=~nTIv)v_8`EnLwDE=;ov^4GMpAC0%@%Efp$2@3$}Pp6A|2~Xz+^e5 z6oJTy==O0*>%w>*^wwy>gbj<82GwSRlu4br8)9Ff7+4n|EOmC$IW&^CRUbeXD`60? zlYb|pcWR6E{`k7&0dpv_IdMHJK;4o*P!7hE!*i><1b2g0>m2c}BXW~QqpIBN&dl35 z%ec@JGIn4myDIkXjRaq0<=wmQa>z{mjSpP$ z&sGkS@h@1&C-X-@nvyB=Z*S%Ie>I9&#KA{kycJ{n*1{~B~&iC)b^Y!b>^BDBCJ|7zN-=0&fN2FplP)z3ft}!PvMa7bF{$o=| z$(d*-kD7GUV;4IpW3a5?+>88-Pd1v5@yg8Ft~r>MQxsf2@c|4&p6XD3l5(Iae#wGH zRh*M5q*>x%7t<$s(7%(?<2(uOZ%%aEn9SaoOu3Q)cr$Hwvsh4YY~$%#q+z7%T9fDPz}06?`Z;AM!ODfr3mvt9cZ;mTl1K1;a4-e)zG~+_ldk z8X-X2HZ>wda=_N4>yd|0tYYOxVEkA`)i_ z7e$?ztvSf%A<#8XjxxmqAsa2<FOsdv^)`)x7TB5?YOe$%Aq82SENA$^nf33Z-~2v4;9r4-kS=1$fSv7M_+vNhZ^ZJFZUc2mAY|v>O-raC! zI+KRMet(Z!k|pBA)-{rF^eVR`i?sqZ>lUW#yt+%C#Vs%Hbdtvn+Zj)~17nCkx|`d1 zlE>oJ3=iMSisgLlll=FOCKVqTZ;Y-A zF%+c^xSMteiai7MbyM3nuxHZXtW)0M)&N`gM7~ai+wLJzkj#5DCkXok;fq01X<0fY z6aeOh_nM{PysmN#z-s|u24V*3IlrIKq+_NkXt&8!1$z)}#Y*Q$BL${Sg3AoRn>_BO zqXcJf=8=;HgKu)Xk3IqLgml7gf~VBt0@^k{xoGk&aZhAoV}eV z#P^yXkG0&_lUP)2gcoEfIP=9DIu;4pCm=EqWBxr+L3o-_^LQ===}(tVNMS1v&~6ADVzoL5##^=8|6vdhKF+Kk2oIwc#R_1|PK!`>liS#A0<& zE7b;Ox*T-7y?DYxUhmfqx3Q~_72>0deWP-K6o_TTz(wb=f5zB?Uddmmk}>LPkXLV3 z)J<0m$f)3Zm8;0Fcx8ahw8V8*?y3tt*sdyb%3EI0chi2ixlTukgH+|y?r_GLDUZ9{ z7RN50-(wHaT;3Ne3OqkZ#XomBfbn0exWw~MALn-;fP~eAFE?%c0>o~u6~yfFJsEffu`~$jU}S={N!A|Y zxKkU}C^)1ER@(iL0i#-EggyodzVr{Ex)xWPC}4yTMqgrcSdhtxohp5 z)~EUGC?&O^m{cJLqMW+~Fd(M>6w+isQLvlYn$gi9B=nWSK?Zq^6pC) z{X3bWxc)Nl(6Sl;+?!ywHXSnGnJfUnXf z6@8ZXL9aC_ms&}_!XsAt!xsXRie(`v!hGZnLMi>E@(_xQj1;I9EP{MFJH9VK+(Ucp zqxyg7?Qy;UjzcZ6M$}%}EF;{ShFBV=48GH)P!dE}9BnEK($_LZgg0hoUfxM@i zCKV%ko&M?c0ygUuhvh=cJ1>VdS6-+nQcN z^a7OyhIkX8=S^BSS(0U=&Fy?N<^}?&hki{}c#aE}0-oo$LSe*Lh^zC3wOV#U;TP@2lHBo*$@*U#J|GyceKI0HJe}Qs4Pw=8ErZ;OcY> zceY#DU2Ng|{W09%9>bjfj^>k$zbCNUo#id)NuFe)Tog3s1VM>UB2-1@iWBXxC)ix%Up8~c`88#_0;l{sU&1E;?e+Z%djwi zojJVY1ji>?l3`cXEX`b}Jl8}sHf8B1!znA{633j#<}@OrIX-3CewHne+MMqtS?$cGj(L}~#p`K4x|-8IYk!gHiA-0p5|4LK{Kt0b znWESq?Jv^xe1^waI=-HZZSh;b->R2<7}dkN9)ujI+|@ zcL~1wJb%uUH^By>dPl{eQsEoI_n68EEBZF<5R!jyiJ&YL2TFu=wLnliW6=*8_@z`iT;IBTiQjRF-xr}Sss3M#>=GI$ zOpVk?23&$+g{wB2Ak|~qW=C0A@y`?`W0P8?{ctQn%OQi^N36&D?DypOx+WVIy24+B z)QeL9*@5Ig+dY>4ggV^@MHilAOBBb-OnHy9m&k3CWeb;>6g(dIm6diIr7ZSYT0Tx! zN@uZI+gVopK9d+H0>qq*^v!z-9)Fo&e>%gzat9wKaYQRQx2 zs85cWRK8Y!qcEJJy)mrzhaqn>S%l*594`*u$$8x%J=b&Edzq{cDYPd5Z~aQ$eKgNp zmRm7x%Zl100pS_NF=XmsM~+>7zhRTL47?MA?{p=en%haicr&y4+f|l|uP@Tm`79mn zV4JClCs%v8xR~MlH)eS7-3;$%F#caZCiwja92n>jO#T-v2QYp?3Vmpzodfb!{yX_% z1K&R0!11p)u(>?SoN)%z>n$8_vZR|qIGwV2+ewy|^LH79r~EfhOh@P+M{(Py?VP#d z&33a954|iybBGHCr_IFH$r>#;1Hg9DD8775qW%UzQmMHG4=)>god-7-L2z_!4|?8C z{LD@(-p9V(d8M9M_`LlM-#7OOOS|Z`dm&iwceMO)@SOzk>;3e7ocnr`0=DD}m1{T& z0cogAb>z|5)|TO!CF6}y7Q1~0;O)fpRQ{VX5QCUT=D!TWmopnyWbnR|X|F6DKg+wY zcb?7gU%yN6%^#AaS2~x>Ee9a}1a;Fxfo=hpE?bvZmyiET!crda394ck1~=B!2EOk0i#v&q77p6FRJoo3Q_-&6o|ftcIcg!49zE8+T5ruOY{mk_vMFTHskKNq>SuV5Sc zYakw36_JK_sL#AuUc{Id#OB4oKNvd!@q0}!nw4yOzM(7;=O1UAkL~xIBXPIg9`8g+ z$1y3k9E&2430BzM%bZR)GY>Pc9TUhV}qlU48*g= ztYF|2D+<=+F?yiHp4qT~eQnUPfd)*IAM+BxRupv`+qN6{Eu`ZBe!Q4)EObAQGq@dT zgx=Eh?CqKoa3pqf>@qQ?wqq39aUkEoxX;q|Y*MOer=&ik2KavCeN38V4mQd2ZBXrN zcMkhyuy^`G>P>oXInVmU_sCQ5XtrliAH zPZWnAodXy<90LCv!u}E&Hli*z9RlLVpdB3|m!MkrInUveR08bexF7%>JW+S$F zyL!z@OnDodCnY<8u*JmHoau~X4)n&>7aDAycz>JWLcn6L&K?44dG0bWw;;@t8U+Ox z6@-)1xJm~&`#k%X_A1xT21Gz=h_G?6(qKQkS=)i`dX>oaJAd_3q{>YN*Cfjgn_V|n z%F^%6v4MPOqlTbYpar{D`pk6%;O4RmeL&E}R=%*{R?lZ0DW4yF7{L=b>5mMxgq=h( z&VI822YX^^A7@qJFOrA*eFDCPMvhVgjr7QiAWU^$1sKL#wvw{~m_ z=Xu?H&Nj5=B0^eeZ_418_PA&}wy`KIvF@?l$LJos-?1b+H}==ttmk0UkNCXe=WSPi ze8$t@+R~-WJTU8ZxXDb|#57JNVvUA|5|e(nYiC|h zHyp`1`kr-!+~(}p9En2TBw)=!acr+%c3r)5sFU@Lvz@RxqG4YwG?HF(84iRxcj0i# z^_=Xm_939)WbN|3Z!G$Q*Ui>pN8x+4m>2WlUXHpp`)5^Hha&}ae}4SE)Dte6x;D6v z0{Adv6wM;`=;~ z9^~E7Z{JIB_qUq;S%U(RDlZPHmHry#u=KrPMa|sKm97v+kWUcay^rwEr}(G;+Z&tT zewRU&CFCa=D4sppz#DH*@aD4(e4hdMEdQkpwpUjy5u-%XWVV=g`Sm1Ag8A4P=qpF7 zV8EPB{Mlc-)JNqz0Rw(>ZM{3z^R~=oUSo6awO!kneHde0-|_LXEvvdnn|r9=Gl(T` zFTZj_5@{ny&7pfml9m40b+LGxO<(hc)3vr!>hIe+HpQu(dp)Q#mhQ1hzxIRqCii%p z+rFmKZu5+-AM+8(xy-Y3Klu1eDjjqFI+mC@+$v`m=Ya8(Dd*<9nS9RgzxawcEFip_ zf%uE-EKR>>JaPW}EdQAW1^4h^&i2Q8wBXF$GlFVEAzO%E(7=`ONsX~@LnTcG8pf! z@Dxw1)l>1)E1h6P(`7zKzSe!eb89#%}@#fF` zDg;n|k9^Gg$uVA zd_Nz8I)Zq4#P1(X@J^O;zsel%8}A`}_hsgeSqlDsf{Q$f-`Gw9qz@kC>GpIIVBv&3 zM+(GnC)aa*k?YAI#i=W|m-)L>lJ`d;tLN4w=6sCb@8fs*nu{}if0mVrd%pfs>-6Gv z?Yw^bUXJHZ>@HAF=X#~>3~;-zYaQi!2X$(twH@m9;O&R={5$Wv={uYDnuGa$d{ozMN+o{!b*&*3awe__}3^*qSuU)b}P?=J1WPD!YTXLkLuKc74K z_+yoVxlH$xNWxd7v9ZO7ai=kg-+7NyDdqD%1&b0$V!d--cL@i2;;&Z@VEh6WvakR$ zMb7OvVo+ui(BJ1*R_tBJuC|}GHSb8?e_x*SL`6yh=+1XB@))UX+ zHoY_cT`Yd>Rd=p`x3hZtI{bWZ1G@H}tX#vz`we!?@9|#W|8QSkPu~~lu8Vz!mGiw_ ze#ZRWHTUOn-pDXjk^eX=5~t}pwOAIL2N`(tF6r5y?Q;fUjyLgN{z&kD{~f_Ue@gHh z17RLak3Ntsm|IUE9rE1$HOt}Azo4Z6GE2uFY{PElTcZY+=uvAUDm3{Ucs&xi^4m!ivUzy~_ z$Gona%IKUsR)-(w&&T=ww=nLr-^#aLow4p%C!c@4(r#=gJ_E1o%|Sai-OCTX_i{Y{ zPFHUjXn&J`y4;bg%>Ukfli)A;(7k-l|CYh{*ZKW}nIy>6|H1FsTrtxTY$=fiVfcqE z5$m`yJHB%TVJioT_^)3MVElp?A_|epKqckREQzT*Nw>*ibI-y_e_k zpYr?P0(|#H{k`w~CBOgmvO%8E-y4wg*MEj_iQnB}pigx&`)97}%?<@cXKu^CFA8 zE%J8s0LFj)ascBOy@#rmlGP2aW80@M%n*w=qlN&4$7 zJ^hFL`M=q@Ywx|pYq)UIN|ws`^H=s=IoG~>JDdZ9`u{_ypX+!h*Ab8Zw{Y&;p^ezT zx4X8XyZ-I2-ka{x`wn*}xhCFctT&ebwsJqQoxU&eUi;G572kVb-Zs$XK=3U2auR3e zfqBcs;L8Kz16!>hRZ9sSLzbt?7W#wr#EVf5VEi%_3d%h%YzFtyc{`a{>Ny9`ucznp z#1zi?lPp<(sptRx1BCzliC*)c_@DPdKL00s^}^r%=k7hfio})cL5y-CW0)xsJZ?{5_j;`F9Y%4{gQc@i}~E z?UnL=y?41Dy7t38s)UM*XYAj7Y4`k}LcIX>Im`XNUw>5;t`9vBYN@1Y#Z zFI_Zsa0}36!F7nbtjFr`eNT{&@Z~7UJB=o+8DJRzwhsVRL@#Fr9U59zoEYG{^FP@W1|}bhjJ)~awvy# mD2H+=hjJ)~awso$`TqlF%K=qI0_YV00000, ) { - // 단일 티켓인 경우 디자인이 다름 - if (capsuleSteps.size == 1) { - HomeBigTicket(modifier = modifier, step = capsuleSteps.first()) - return - } - - val pagerState = rememberPagerState { capsuleSteps.size } - HorizontalPager( - modifier = modifier - .fillMaxWidth() - .height(460.dp), - state = pagerState, - contentPadding = PaddingValues(start = 27.dp, end = 31.dp), // 티켓 바깥 여백 - pageSpacing = (-84).dp, // 음수 간격이기 때문에 각 페이지가 해당 값 만큼 포개진다. - beyondViewportPageCount = 1, // 양 옆에도 보여야 하므로 해당 페이지 외 미리 로드 - ) { page -> - HomeMiddleTicket( - modifier = Modifier.deckPage(pagerState, page), - step = capsuleSteps[page], + Box(modifier = modifier) { + Box( + modifier = Modifier.fillMaxWidth(), + contentAlignment = Alignment.Center + ) { + MSText( + modifier = Modifier + .size(width = 132.dp, height = 43.dp) + .wavyStroke( + color = MSTheme.color.greyG5, + fillColor = MSTheme.color.white, + cornerRadius = 35.dp + ) + .wrapContentHeight(Alignment.CenterVertically), + text = "지금 열 수 있어요", + fontWeight = FontWeight.Bold, + fontSize = 16.dp, + color = MSTheme.color.black, + textAlign = TextAlign.Center + ) + Image( + modifier = Modifier.size(width = 132.dp, height = 43.dp), + painter = painterResource(R.drawable.bg_callout), + contentDescription = "bg_callout", + contentScale = ContentScale.FillBounds + ) + } + Image( + modifier = Modifier + .fillMaxWidth() + .height(290.dp) + .padding(horizontal = 28.dp) + .padding(top = 13.dp), + painter = painterResource(R.drawable.bg_light), + contentDescription = "bg_light", + contentScale = ContentScale.FillBounds ) + // 단일 티켓인 경우 디자인이 다름 + if (capsuleSteps.size == 1) { + HomeBigTicket( + modifier = Modifier.padding(top = 68.dp), + step = capsuleSteps.first() + ) + return + } + + val pagerState = rememberPagerState { capsuleSteps.size } + HorizontalPager( + modifier = Modifier + .fillMaxWidth() + .height(460.dp) + .padding(top = 68.dp), + state = pagerState, + contentPadding = PaddingValues(start = 27.dp, end = 31.dp), // 티켓 바깥 여백 + pageSpacing = (-84).dp, // 음수 간격이기 때문에 각 페이지가 해당 값 만큼 포개진다. + beyondViewportPageCount = 1, // 양 옆에도 보여야 하므로 해당 페이지 외 미리 로드 + ) { page -> + HomeMiddleTicket( + modifier = Modifier.deckPage(pagerState, page), + step = capsuleSteps[page], + ) + } } } From b1c1850509e5724e535522e97a10677c22ae9cba Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Mon, 14 Sep 2026 11:26:43 +0900 Subject: [PATCH 08/31] =?UTF-8?q?:sparkles:=20::=20=EC=98=A4=ED=94=88?= =?UTF-8?q?=EB=90=9C=20=ED=8B=B0=EC=BC=93=20=EB=B0=B0=EB=84=88=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 티켓 스와이프 중 스포트라이트 투명하게 변경 - 조건부로 표시되는 뷰 높이 간격 설정 - modifier 중복 전달되던 부분 수정 --- .../home/component/HomeOpenedBanner.kt | 27 ++++++++++++++----- .../idiotfrogs/home/component/HomeTicket.kt | 2 +- .../com/idiotfrogs/home/home/HomeScreen.kt | 14 +++++++--- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt index 7a782fd0..3f43426a 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt @@ -1,8 +1,11 @@ package com.idiotfrogs.home.component +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -12,8 +15,10 @@ import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource @@ -43,6 +48,8 @@ fun HomeOpenedBanner( modifier: Modifier = Modifier, capsuleSteps: List, ) { + val pagerState = rememberPagerState { capsuleSteps.size } + Box(modifier = modifier) { Box( modifier = Modifier.fillMaxWidth(), @@ -70,12 +77,21 @@ fun HomeOpenedBanner( contentScale = ContentScale.FillBounds ) } + val alpha by animateFloatAsState( + targetValue = if (pagerState.isScrollInProgress) 0f else 1f, + animationSpec = tween() + ) Image( modifier = Modifier .fillMaxWidth() - .height(290.dp) + .height( + if (capsuleSteps.size == 1) 490.dp else 290.dp + ) .padding(horizontal = 28.dp) - .padding(top = 13.dp), + .padding( + top = if (capsuleSteps.size == 1) 0.dp else 13.dp + ) + .alpha(alpha), painter = painterResource(R.drawable.bg_light), contentDescription = "bg_light", contentScale = ContentScale.FillBounds @@ -83,18 +99,17 @@ fun HomeOpenedBanner( // 단일 티켓인 경우 디자인이 다름 if (capsuleSteps.size == 1) { HomeBigTicket( - modifier = Modifier.padding(top = 68.dp), + modifier = Modifier.padding(top = 67.dp), step = capsuleSteps.first() ) + Spacer(modifier = Modifier.height(32.dp)) return } - - val pagerState = rememberPagerState { capsuleSteps.size } HorizontalPager( modifier = Modifier .fillMaxWidth() .height(460.dp) - .padding(top = 68.dp), + .padding(top = 56.dp), // 가운데 티켓 높이가 아닌 티켓 영역 기준 state = pagerState, contentPadding = PaddingValues(start = 27.dp, end = 31.dp), // 티켓 바깥 여백 pageSpacing = (-84).dp, // 음수 간격이기 때문에 각 페이지가 해당 값 만큼 포개진다. diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt index 31a79335..1a7c2a7f 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt @@ -62,7 +62,7 @@ fun HomeBigTicket( // 티켓 바디(헤더 + 사진). 가이드 이미지는 이 Box 하단을 기준으로 정렬된다. Box(modifier = modifier.fillMaxWidth()) { Column( - modifier = modifier + modifier = Modifier .fillMaxWidth() .padding(start = 20.dp, end = 21.dp) ) { diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt index 1ab1ae45..f9779eea 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt @@ -159,17 +159,23 @@ fun HomeScreen( columns = GridCells.Fixed(2), horizontalArrangement = Arrangement.spacedBy((-12).dp) // 줄기가 겹쳐지도록 ) { - if (true) { + val showOpenedBanner = true + val showRemindBanner = true + if (showOpenedBanner) { maxLineItem { HomeOpenedBanner( - capsuleSteps = listOf(1,2,3,4) + modifier = Modifier.padding(top = 12.dp), + capsuleSteps = listOf(1) ) } } - if (true) { // todo: 조건 변경 + if (showRemindBanner) { // todo: 조건 변경 maxLineItem { HomeRemindBanner( - modifier = Modifier.padding(20.dp), + modifier = Modifier.padding( + top = if (showOpenedBanner) 0.dp else 20.dp, + start = 20.dp, end = 20.dp, bottom = 20.dp + ), weather = Weather.AUTUMN ) } From 96214952bec56e6f819294536f903ac4f95fb953 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Tue, 15 Sep 2026 16:47:42 +0900 Subject: [PATCH 09/31] =?UTF-8?q?:sparkles:=20::=20=ED=99=88=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20=EA=B0=9C=ED=8E=B8=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../extension/LocalDateExtension.kt | 14 ++ .../com/idiotfrogs/di/DataSourceModule.kt | 7 + .../java/com/idiotfrogs/di/NetworkModule.kt | 6 + .../com/idiotfrogs/di/RepositoryModule.kt | 7 + .../model/home/SeasonBannerResponse.kt | 13 ++ .../idiotfrogs/network/service/HomeService.kt | 9 + .../data/datasource/home/HomeDataSource.kt | 7 + .../datasource/home/HomeDataSourceImpl.kt | 13 ++ .../data/repository/home/HomeRepository.kt | 7 + .../repository/home/HomeRepositoryImpl.kt | 13 ++ .../usecase/home/GetSeasonBannerUseCase.kt | 14 ++ .../timecapsule/GetMyTimeCapsuleUseCase.kt | 24 +- .../home/component/HomeRemindBanner.kt | 22 +- .../idiotfrogs/home/component/HomeTicket.kt | 26 +-- .../home/detail/HomeDetailScreen.kt | 14 +- .../com/idiotfrogs/home/home/HomeScreen.kt | 217 +++++++++++------- .../com/idiotfrogs/home/home/HomeViewModel.kt | 171 +++++++++++++- 17 files changed, 454 insertions(+), 130 deletions(-) create mode 100644 core/model/src/main/java/com/idiotfrogs/model/home/SeasonBannerResponse.kt create mode 100644 core/network/src/main/java/com/idiotfrogs/network/service/HomeService.kt create mode 100644 data/src/main/java/com/idiotfrogs/data/datasource/home/HomeDataSource.kt create mode 100644 data/src/main/java/com/idiotfrogs/data/datasource/home/HomeDataSourceImpl.kt create mode 100644 data/src/main/java/com/idiotfrogs/data/repository/home/HomeRepository.kt create mode 100644 data/src/main/java/com/idiotfrogs/data/repository/home/HomeRepositoryImpl.kt create mode 100644 domain/src/main/java/com/idiotfrogs/domain/usecase/home/GetSeasonBannerUseCase.kt diff --git a/common/extension/src/main/java/com/idiotfrogs/extension/LocalDateExtension.kt b/common/extension/src/main/java/com/idiotfrogs/extension/LocalDateExtension.kt index 5a5fef0f..abcfb19c 100644 --- a/common/extension/src/main/java/com/idiotfrogs/extension/LocalDateExtension.kt +++ b/common/extension/src/main/java/com/idiotfrogs/extension/LocalDateExtension.kt @@ -37,3 +37,17 @@ fun LocalDate?.toOpenRemainingText(): String { else -> "오픈" } } + +@OptIn(ExperimentalTime::class) +fun LocalDate?.toDdayCount(): String? { + if (this == null) return null + + val today = Clock.System.todayIn(TimeZone.of("Asia/Seoul")) + val diff = toEpochDays() - today.toEpochDays() + + return when { + diff > 0L -> "D-$diff" + diff == 0L -> "D-Day" + else -> null // 해당 케이스는 오류 상황이라 표시 x + } +} \ No newline at end of file diff --git a/core/di/src/main/java/com/idiotfrogs/di/DataSourceModule.kt b/core/di/src/main/java/com/idiotfrogs/di/DataSourceModule.kt index e39ac3e1..d275bc48 100644 --- a/core/di/src/main/java/com/idiotfrogs/di/DataSourceModule.kt +++ b/core/di/src/main/java/com/idiotfrogs/di/DataSourceModule.kt @@ -4,6 +4,8 @@ import com.idiotfrogs.local.LocalDataSource import com.idiotfrogs.local.LocalDataSourceImpl import com.idiotfrogs.data.datasource.auth.AuthDataSource import com.idiotfrogs.data.datasource.auth.AuthDataSourceImpl +import com.idiotfrogs.data.datasource.home.HomeDataSource +import com.idiotfrogs.data.datasource.home.HomeDataSourceImpl import com.idiotfrogs.data.datasource.timecapsule.TimeCapsuleDataSource import com.idiotfrogs.data.datasource.timecapsule.TimeCapsuleDataSourceImpl import com.idiotfrogs.data.datasource.user.UserDataSource @@ -35,4 +37,9 @@ interface DataSourceModule { fun bindsTimeCapsuleDataSource( timeCapsuleDataSourceImpl: TimeCapsuleDataSourceImpl ): TimeCapsuleDataSource + + @Binds + fun bindsHomeDataSource( + homeDataSourceImpl: HomeDataSourceImpl + ): HomeDataSource } \ No newline at end of file diff --git a/core/di/src/main/java/com/idiotfrogs/di/NetworkModule.kt b/core/di/src/main/java/com/idiotfrogs/di/NetworkModule.kt index 6c76c4ff..f8b931f8 100644 --- a/core/di/src/main/java/com/idiotfrogs/di/NetworkModule.kt +++ b/core/di/src/main/java/com/idiotfrogs/di/NetworkModule.kt @@ -2,6 +2,7 @@ package com.idiotfrogs.di import com.idiotfrogs.network.service.AuthService import com.idiotfrogs.network.interceptor.TokenInterceptor +import com.idiotfrogs.network.service.HomeService import com.idiotfrogs.network.service.TimeCapsuleService import com.idiotfrogs.network.service.UserService import com.idiotfrogs.network.util.BaseClient @@ -68,4 +69,9 @@ object NetworkModule { @Singleton fun providesTimeCapsuleService(retrofit: Retrofit): TimeCapsuleService = retrofit.create(TimeCapsuleService::class.java) + + @Provides + @Singleton + fun providesHomeService(retrofit: Retrofit): HomeService = + retrofit.create(HomeService::class.java) } \ No newline at end of file diff --git a/core/di/src/main/java/com/idiotfrogs/di/RepositoryModule.kt b/core/di/src/main/java/com/idiotfrogs/di/RepositoryModule.kt index 750df45e..444df75b 100644 --- a/core/di/src/main/java/com/idiotfrogs/di/RepositoryModule.kt +++ b/core/di/src/main/java/com/idiotfrogs/di/RepositoryModule.kt @@ -2,6 +2,8 @@ package com.idiotfrogs.di import com.idiotfrogs.data.repository.auth.AuthRepository import com.idiotfrogs.data.repository.auth.AuthRepositoryImpl +import com.idiotfrogs.data.repository.home.HomeRepository +import com.idiotfrogs.data.repository.home.HomeRepositoryImpl import com.idiotfrogs.data.repository.local.LocalRepository import com.idiotfrogs.data.repository.local.LocalRepositoryImpl import com.idiotfrogs.data.repository.timecapsule.TimeCapsuleRepository @@ -35,4 +37,9 @@ interface RepositoryModule { fun bindsLocalRepository( localRepositoryImpl: LocalRepositoryImpl, ): LocalRepository + + @Binds + fun bindsHomeRepository( + homeRepositoryImpl: HomeRepositoryImpl + ): HomeRepository } \ No newline at end of file diff --git a/core/model/src/main/java/com/idiotfrogs/model/home/SeasonBannerResponse.kt b/core/model/src/main/java/com/idiotfrogs/model/home/SeasonBannerResponse.kt new file mode 100644 index 00000000..85939f1e --- /dev/null +++ b/core/model/src/main/java/com/idiotfrogs/model/home/SeasonBannerResponse.kt @@ -0,0 +1,13 @@ +package com.idiotfrogs.model.home + +import kotlinx.serialization.Serializable + +/** 없을경우 빈 {}로 와서 기본 값 지정이 안되어 있으면 예외 발생 */ +@Serializable +data class SeasonBannerResponse( + val content: String = "", + val season: Season? = null, + val capsuleId: Long? = null, +) + +enum class Season { SPRING, SUMMER, FALL, WINTER } \ No newline at end of file diff --git a/core/network/src/main/java/com/idiotfrogs/network/service/HomeService.kt b/core/network/src/main/java/com/idiotfrogs/network/service/HomeService.kt new file mode 100644 index 00000000..0a11dce2 --- /dev/null +++ b/core/network/src/main/java/com/idiotfrogs/network/service/HomeService.kt @@ -0,0 +1,9 @@ +package com.idiotfrogs.network.service + +import com.idiotfrogs.model.home.SeasonBannerResponse +import retrofit2.http.GET + +interface HomeService { + @GET("banners/seasonal") + suspend fun getSeasonBanner(): SeasonBannerResponse? +} \ No newline at end of file diff --git a/data/src/main/java/com/idiotfrogs/data/datasource/home/HomeDataSource.kt b/data/src/main/java/com/idiotfrogs/data/datasource/home/HomeDataSource.kt new file mode 100644 index 00000000..4d1ed0b6 --- /dev/null +++ b/data/src/main/java/com/idiotfrogs/data/datasource/home/HomeDataSource.kt @@ -0,0 +1,7 @@ +package com.idiotfrogs.data.datasource.home + +import com.idiotfrogs.model.home.SeasonBannerResponse + +interface HomeDataSource { + suspend fun getSeasonBanner(): SeasonBannerResponse? +} \ No newline at end of file diff --git a/data/src/main/java/com/idiotfrogs/data/datasource/home/HomeDataSourceImpl.kt b/data/src/main/java/com/idiotfrogs/data/datasource/home/HomeDataSourceImpl.kt new file mode 100644 index 00000000..6b1832d9 --- /dev/null +++ b/data/src/main/java/com/idiotfrogs/data/datasource/home/HomeDataSourceImpl.kt @@ -0,0 +1,13 @@ +package com.idiotfrogs.data.datasource.home + +import com.idiotfrogs.model.home.SeasonBannerResponse +import com.idiotfrogs.network.service.HomeService +import javax.inject.Inject + +class HomeDataSourceImpl @Inject constructor( + private val service: HomeService +) : HomeDataSource { + override suspend fun getSeasonBanner(): SeasonBannerResponse? { + return service.getSeasonBanner() + } +} \ No newline at end of file diff --git a/data/src/main/java/com/idiotfrogs/data/repository/home/HomeRepository.kt b/data/src/main/java/com/idiotfrogs/data/repository/home/HomeRepository.kt new file mode 100644 index 00000000..34f6db0f --- /dev/null +++ b/data/src/main/java/com/idiotfrogs/data/repository/home/HomeRepository.kt @@ -0,0 +1,7 @@ +package com.idiotfrogs.data.repository.home + +import com.idiotfrogs.model.home.SeasonBannerResponse + +interface HomeRepository { + suspend fun getSeasonBanner(): SeasonBannerResponse? +} \ No newline at end of file diff --git a/data/src/main/java/com/idiotfrogs/data/repository/home/HomeRepositoryImpl.kt b/data/src/main/java/com/idiotfrogs/data/repository/home/HomeRepositoryImpl.kt new file mode 100644 index 00000000..dcaf210e --- /dev/null +++ b/data/src/main/java/com/idiotfrogs/data/repository/home/HomeRepositoryImpl.kt @@ -0,0 +1,13 @@ +package com.idiotfrogs.data.repository.home + +import com.idiotfrogs.data.datasource.home.HomeDataSource +import com.idiotfrogs.model.home.SeasonBannerResponse +import javax.inject.Inject + +class HomeRepositoryImpl @Inject constructor( + private val dataSource: HomeDataSource +) : HomeRepository { + override suspend fun getSeasonBanner(): SeasonBannerResponse? { + return dataSource.getSeasonBanner() + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/idiotfrogs/domain/usecase/home/GetSeasonBannerUseCase.kt b/domain/src/main/java/com/idiotfrogs/domain/usecase/home/GetSeasonBannerUseCase.kt new file mode 100644 index 00000000..e540c08c --- /dev/null +++ b/domain/src/main/java/com/idiotfrogs/domain/usecase/home/GetSeasonBannerUseCase.kt @@ -0,0 +1,14 @@ +package com.idiotfrogs.domain.usecase.home + +import com.idiotfrogs.data.repository.home.HomeRepository +import com.idiotfrogs.model.home.SeasonBannerResponse +import com.idiotfrogs.util.safeCatching +import javax.inject.Inject + +class GetSeasonBannerUseCase @Inject constructor( + private val repository: HomeRepository +) { + suspend fun invoke(): Result = safeCatching { + repository.getSeasonBanner() + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetMyTimeCapsuleUseCase.kt b/domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetMyTimeCapsuleUseCase.kt index 47011970..3eefe353 100644 --- a/domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetMyTimeCapsuleUseCase.kt +++ b/domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetMyTimeCapsuleUseCase.kt @@ -1,8 +1,7 @@ package com.idiotfrogs.domain.usecase.timecapsule import com.idiotfrogs.data.repository.timecapsule.TimeCapsuleRepository -import com.idiotfrogs.model.timecapsule.MyTimeCapsuleContent -import com.idiotfrogs.model.timecapsule.TimeCapsuleRole +import com.idiotfrogs.model.timecapsule.MyTimeCapsuleResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus import com.idiotfrogs.util.safeCatching import javax.inject.Inject @@ -10,17 +9,16 @@ import javax.inject.Inject class GetMyTimeCapsuleUseCase @Inject constructor( private val timeCapsuleRepository: TimeCapsuleRepository ) { - suspend operator fun invoke(): Result>> = + suspend operator fun invoke( + status: TimeCapsuleStatus, + page: Int, + size: Int + ): Result = safeCatching { - // FIXME: 임시 코드 - (timeCapsuleRepository.getMyTimeCapsule( - status = TimeCapsuleStatus.BURIED, - page = 0, - size = 50 - ).content + timeCapsuleRepository.getMyTimeCapsule( - status = TimeCapsuleStatus.BEFOREBURIED, - page = 0, - size = 50 - ).content).groupBy { it.role } + timeCapsuleRepository.getMyTimeCapsule( + status = status, + page = page, + size = size + ) } } \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt index 2cebe436..53fcfdfc 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt @@ -21,16 +21,23 @@ import androidx.compose.ui.unit.dp import com.idiotfrogs.designsystem.component.MSText import com.idiotfrogs.designsystem.theme.MSTheme import com.idiotfrogs.designsystem.util.wavyStroke +import com.idiotfrogs.model.home.Season import com.idiotfrogs.resource.R -enum class Weather(val text: String) { - SPRING("봄"), SUMMER("여름"), AUTUMN("가을"), WINTER("겨울") +private fun Season.getSeasonText(): String { + return when (this) { + Season.SPRING -> "봄" + Season.SUMMER -> "여름" + Season.FALL -> "가을" + Season.WINTER -> "겨울" + } } @Composable fun HomeRemindBanner( modifier: Modifier = Modifier, - weather: Weather + season: Season, + content: String ) { Column( modifier = modifier @@ -57,13 +64,13 @@ fun HomeRemindBanner( verticalArrangement = Arrangement.spacedBy(10.dp) ) { MSText( - text = "지난 ${weather.text} 우리", + text = "지난 ${season.getSeasonText()} 우리", fontWeight = FontWeight.Bold, fontSize = 20.dp, color = MSTheme.color.greyG5 ) MSText( - text = "티켓이름티켓이름티켓이름", + text = content, fontWeight = FontWeight.Medium, fontSize = 16.dp, color = MSTheme.color.greyG5 @@ -99,5 +106,8 @@ fun HomeRemindBanner( @Preview @Composable private fun HomeRemindBannerPreview() { - HomeRemindBanner(weather = Weather.AUTUMN) + HomeRemindBanner( + season = Season.FALL, + content = "내용내용내용내용내용" + ) } \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt index 1a7c2a7f..0d6b01f2 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt @@ -246,10 +246,10 @@ fun HomeMiddleTicket( @Composable fun HomeSmallTicket( modifier: Modifier = Modifier, - buried: Boolean, -// createdAt: String, -// title: String, -// imageUrl: String?, + dDayCount: String?, + createdAt: String, + title: String, + imageUrl: String?, step: Int, ) { Column(modifier = modifier.fillMaxWidth()) { @@ -273,7 +273,7 @@ fun HomeSmallTicket( .height(55.dp), contentAlignment = Alignment.CenterStart ) { - if (buried) { + if (dDayCount != null) { Row( modifier = Modifier .padding(start = 12.dp) @@ -291,7 +291,7 @@ fun HomeSmallTicket( contentDescription = "ic_shovels" ) MSText( - text = "D-12", + text = dDayCount, fontSize = 12.dp, fontWeight = FontWeight.SemiBold, color = MSTheme.color.greyG5 @@ -327,7 +327,7 @@ fun HomeSmallTicket( ) } }, - imageModel = { R.drawable.img_sample } + imageModel = { imageUrl ?: R.drawable.img_sample } ) } } @@ -351,14 +351,14 @@ fun HomeSmallTicket( ) { Spacer(modifier = Modifier.height(2.dp)) // 위에서 offset 준 만큼 원본에서 차감 MSText( - text = "제목입니다. 제목입니다.", + text = title, fontWeight = FontWeight.Bold, fontSize = 16.dp, color = MSTheme.color.greyG5 ) Spacer(modifier = Modifier.height(8.dp)) MSText( - text = "2027. 10. 24", + text = createdAt, fontWeight = FontWeight.Normal, fontSize = 12.dp, color = MSTheme.color.greyG5.copy(alpha = 0.6f) @@ -371,10 +371,10 @@ fun HomeSmallTicket( @Composable private fun HomeSmallTicketPreview() { HomeSmallTicket( - buried = true, -// createdAt = "2027. 10. 24.", -// title = "제목입니다.", -// imageUrl = null, + dDayCount = "D-15", + createdAt = "2027. 10. 24.", + title = "제목입니다.", + imageUrl = null, step = 1 ) } \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt index 4bc79ce0..060670a2 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt @@ -52,13 +52,13 @@ fun HomeDetailScreen(homeDetailType: HomeDetailType) { LazyVerticalGrid(columns = GridCells.Fixed(2)) { itemsIndexed(listOf(1, 1, 1, 1, 1, 1)) { index, item -> val isLastRow = index / 2 == 2 // 추후 하드코딩에서 변경 - HomeSmallTicket( - modifier = Modifier.padding( - bottom = if (isLastRow) 0.dp else 16.dp - ), - buried = index / 2 == 0, - step = index - ) +// HomeSmallTicket( +// modifier = Modifier.padding( +// bottom = if (isLastRow) 0.dp else 16.dp +// ), +// buried = index / 2 == 0, +// step = index +// ) } } } diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt index f9779eea..cd9cbb4a 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt @@ -4,18 +4,24 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.itemsIndexed +import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.text.input.rememberTextFieldState import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.pulltorefresh.PullToRefreshBox +import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf @@ -33,13 +39,15 @@ import com.idiotfrogs.designsystem.component.MSLoadingOverlay import com.idiotfrogs.designsystem.model.MSMenuFabModel import com.idiotfrogs.designsystem.theme.MSTheme import com.idiotfrogs.designsystem.util.DevicePreview +import com.idiotfrogs.designsystem.util.LoadNextPageEffect import com.idiotfrogs.designsystem.util.noRippleClickable +import com.idiotfrogs.extension.toDdayCount +import com.idiotfrogs.extension.toYearMonthDay import com.idiotfrogs.home.component.HomeHeader import com.idiotfrogs.home.component.HomeJoinContainer import com.idiotfrogs.navigation.LocalComposeMSNavigator import com.idiotfrogs.navigation.Routes import com.idiotfrogs.home.component.BottomMenu -import com.idiotfrogs.home.component.HomeBigTicket import com.idiotfrogs.home.component.HomeBottomBar import com.idiotfrogs.home.component.HomeEmptyScreen import com.idiotfrogs.home.component.HomeOpenedBanner @@ -47,7 +55,6 @@ import com.idiotfrogs.home.component.HomeRemindBanner import com.idiotfrogs.home.component.HomeSectionDivider import com.idiotfrogs.home.component.HomeSmallTicket import com.idiotfrogs.home.component.OpenedTicket -import com.idiotfrogs.home.component.Weather import com.idiotfrogs.home.component.maxLineItem import com.idiotfrogs.navigation.HomeDetailType import org.orbitmvi.orbit.compose.collectAsState @@ -131,6 +138,14 @@ fun HomeScreen( pagerState.animateScrollToPage(selectedMenu.ordinal) } + val lazyGridState = rememberLazyGridState() + + LoadNextPageEffect( + scrollableState = lazyGridState, + canLoadMore = data.opened.canLoadMore, + onLoadNextPage = { onAction(HomeAction.NextOpenedPageRequested) }, + ) + Box( modifier = Modifier .fillMaxSize() @@ -149,105 +164,147 @@ fun HomeScreen( ) { page -> when (page) { BottomMenu.HOME.ordinal -> { - if (false) { + if (data.buried.isEmpty() && data.beforeBuried.isEmpty()) { HomeEmptyScreen( modifier = Modifier.padding(bottom = BOTTOM_BAR_SIZE), selectedMenu = BottomMenu.HOME ) } else { - LazyVerticalGrid( - columns = GridCells.Fixed(2), - horizontalArrangement = Arrangement.spacedBy((-12).dp) // 줄기가 겹쳐지도록 + val refreshState = rememberPullToRefreshState() + PullToRefreshBox( + isRefreshing = isRefreshing, + state = refreshState, + onRefresh = { onAction.invoke(HomeAction.RefreshHome) } ) { - val showOpenedBanner = true - val showRemindBanner = true - if (showOpenedBanner) { - maxLineItem { - HomeOpenedBanner( - modifier = Modifier.padding(top = 12.dp), - capsuleSteps = listOf(1) - ) + LazyVerticalGrid( + columns = GridCells.Fixed(2), + horizontalArrangement = Arrangement.spacedBy((-12).dp) // 줄기가 겹쳐지도록 + ) { + val showOpenedBanner = true + if (showOpenedBanner) { + maxLineItem { + HomeOpenedBanner( + modifier = Modifier.padding(top = 12.dp), + capsuleSteps = listOf(1) + ) + } } - } - if (showRemindBanner) { // todo: 조건 변경 - maxLineItem { - HomeRemindBanner( - modifier = Modifier.padding( - top = if (showOpenedBanner) 0.dp else 20.dp, - start = 20.dp, end = 20.dp, bottom = 20.dp - ), - weather = Weather.AUTUMN - ) + if (data.seasonBanner != null) { + maxLineItem { + HomeRemindBanner( + modifier = Modifier + .padding( + top = if (showOpenedBanner) 0.dp else 20.dp, + start = 20.dp, end = 20.dp, bottom = 20.dp + ) + .noRippleClickable { + data.seasonBanner.capsuleId?.let { + onAction.invoke(HomeAction.TimeCapsuleClicked(it)) + } + }, + season = data.seasonBanner.season ?: return@maxLineItem, + content = data.seasonBanner.content + ) + } } - } - maxLineItem { - HomeSectionDivider( - modifier = Modifier - .noRippleClickable { - onAction.invoke( - HomeAction.HomeDetailClicked( - HomeDetailType.BEFORE_BURIED + if (data.beforeBuried.isNotEmpty()) { + maxLineItem { + HomeSectionDivider( + modifier = Modifier + .noRippleClickable { + onAction.invoke( + HomeAction.HomeDetailClicked( + HomeDetailType.BEFORE_BURIED + ) + ) + } + .padding(horizontal = (22.5).dp, vertical = 20.dp), + sectionName = "타임 티켓" + ) + } + itemsIndexed(data.beforeBuried) { index, item -> + val isLastRow = index / 2 == data.beforeBuried.lastIndex / 2 + HomeSmallTicket( + modifier = Modifier + .padding( + bottom = if (isLastRow) 0.dp else 16.dp ) - ) - } - .padding(horizontal = (22.5).dp, vertical = 20.dp), - sectionName = "타임 티켓" - ) - } - itemsIndexed(listOf(1, 1, 1, 1, 1, 1)) { index, item -> - val isLastRow = index / 2 == 2 // 추후 하드코딩에서 변경 - HomeSmallTicket( - modifier = Modifier.padding( - bottom = if (isLastRow) 0.dp else 16.dp - ), - buried = index / 2 == 0, - step = index - ) - } - maxLineItem { - HomeSectionDivider( - modifier = Modifier - .noRippleClickable { - onAction.invoke( - HomeAction.HomeDetailClicked( - HomeDetailType.BURIED + .noRippleClickable { + onAction.invoke(HomeAction.TimeCapsuleClicked(item.timeCapsuleId)) + }, + dDayCount = item.openedAt?.toDdayCount(), + createdAt = item.createdAt.toYearMonthDay(), + title = item.title, + imageUrl = item.mainImageUrl, + step = item.stage + ) + } + } + // 만약 묻은 티켓이 없다면 하단에 공간 홛보 + if (data.buried.isEmpty()) { + maxLineItem { Spacer(modifier = Modifier.height(112.dp)) } + } else { + maxLineItem { + HomeSectionDivider( + modifier = Modifier + .noRippleClickable { + onAction.invoke( + HomeAction.HomeDetailClicked( + HomeDetailType.BURIED + ) + ) + } + .padding(horizontal = (22.5).dp) + .padding(top = 40.dp, bottom = 15.dp), + sectionName = "오픈 예정 티켓" + ) + } + itemsIndexed(data.buried) { index, item -> + val isLastRow = index / 2 == data.buried.lastIndex / 2 + HomeSmallTicket( + modifier = Modifier + .padding( + bottom = if (isLastRow) 0.dp else 16.dp ) - ) - } - .padding(horizontal = (22.5).dp) - .padding(top = 40.dp, bottom = 15.dp), - sectionName = "오픈 예정 티켓" - ) - } - itemsIndexed(listOf(1, 1, 1, 1, 1, 1)) { index, item -> - val isLastRow = index / 2 == 2 // 추후 하드코딩에서 변경 - HomeSmallTicket( - modifier = Modifier.padding( - bottom = if (isLastRow) 0.dp else 16.dp - ), - buried = index / 2 == 0, - step = index - ) + .noRippleClickable { + onAction.invoke(HomeAction.TimeCapsuleClicked(item.timeCapsuleId)) + }, + dDayCount = item.openedAt?.toDdayCount(), + createdAt = item.createdAt.toYearMonthDay(), + title = item.title, + imageUrl = item.mainImageUrl, + step = item.stage + ) + } + maxLineItem { Spacer(modifier = Modifier.height(112.dp)) } + } } } } } BottomMenu.OPENED.ordinal -> { - if (false) { + if (data.opened.items.isEmpty()) { HomeEmptyScreen( modifier = Modifier.padding(bottom = BOTTOM_BAR_SIZE), selectedMenu = BottomMenu.OPENED ) } else { - LazyVerticalGrid( - modifier = Modifier.padding(horizontal = 20.dp), - columns = GridCells.Fixed(2), - horizontalArrangement = Arrangement.spacedBy(16.dp), - verticalArrangement = Arrangement.spacedBy(24.dp), - contentPadding = PaddingValues(top = 20.dp, bottom = BOTTOM_BAR_SIZE) + val refreshState = rememberPullToRefreshState() + PullToRefreshBox( + isRefreshing = isRefreshing, + state = refreshState, + onRefresh = { onAction.invoke(HomeAction.RefreshOpened) } ) { - items(10) { - OpenedTicket() + LazyVerticalGrid( + modifier = Modifier.padding(horizontal = 20.dp), + columns = GridCells.Fixed(2), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalArrangement = Arrangement.spacedBy(24.dp), + contentPadding = PaddingValues(top = 20.dp, bottom = BOTTOM_BAR_SIZE) + ) { + items(data.opened.items) { + OpenedTicket() + } } } } diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt index acfde52d..4f5474ea 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt @@ -1,18 +1,24 @@ package com.idiotfrogs.home.home +import android.util.Log import androidx.compose.runtime.Immutable import com.idiotfrogs.domain.usecase.auth.PutFcmTokenUseCase +import com.idiotfrogs.domain.usecase.home.GetSeasonBannerUseCase import com.idiotfrogs.domain.usecase.timecapsule.GetMyTimeCapsuleUseCase import com.idiotfrogs.domain.usecase.timecapsule.RequestCollaboratorUseCase import com.idiotfrogs.domain.usecase.user.GetMyProfileUseCase +import com.idiotfrogs.home.home.HomeSideEffect.* +import com.idiotfrogs.model.home.SeasonBannerResponse import com.idiotfrogs.model.timecapsule.MyTimeCapsuleContent +import com.idiotfrogs.model.timecapsule.MyTimeCapsuleResponse import com.idiotfrogs.model.timecapsule.PendingCollaboratorsRequest -import com.idiotfrogs.model.timecapsule.TimeCapsuleRole +import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus import com.idiotfrogs.model.user.ProfileResponse import com.idiotfrogs.navigation.HomeDetailType import com.idiotfrogs.notification.FcmTokenProvider import com.idiotfrogs.util.base.DataUiState import com.idiotfrogs.util.base.BaseViewModel +import com.idiotfrogs.util.paging.PaginationState import com.idiotfrogs.util.sideEffect.RefreshEvent import com.idiotfrogs.util.sideEffect.RefreshSideEffect import dagger.hilt.android.lifecycle.HiltViewModel @@ -20,6 +26,7 @@ import kotlinx.coroutines.async import org.orbitmvi.orbit.Container import org.orbitmvi.orbit.viewmodel.container import javax.inject.Inject +import kotlin.collections.emptyList @HiltViewModel class HomeViewModel @Inject constructor( @@ -28,14 +35,21 @@ class HomeViewModel @Inject constructor( private val requestCollaboratorUseCase: RequestCollaboratorUseCase, private val fcmTokenProvider: FcmTokenProvider, private val putFcmTokenUseCase: PutFcmTokenUseCase, + private val getSeasonBannerUseCase: GetSeasonBannerUseCase ): BaseViewModel() { override val container: Container = container( initialState = HomeUiState(), onCreate = { fetchHome() + fetchOpened() syncFcmToken() - RefreshSideEffect.events.collect { if (it is RefreshEvent.Home) fetchHome() } + RefreshSideEffect.events.collect { + if (it is RefreshEvent.Home) { + fetchHome() + fetchOpened() + } + } } ) @@ -53,24 +67,39 @@ class HomeViewModel @Inject constructor( intent { reduce { state.copy(isLoading = true) } } val userDeferred = async { getMyProfileUseCase() } - val capsulesDeferred = async { getMyTimeCapsuleUseCase() } + val beforeBuriedDeferred = async { + getMyTimeCapsuleUseCase( + status = TimeCapsuleStatus.BEFOREBURIED, page = 0, size = 6 + ) + } + val buriedDeferred = async { + getMyTimeCapsuleUseCase( + status = TimeCapsuleStatus.BURIED, page = 0, size = 6 + ) + } + val seasonBannerDeferred = async { getSeasonBannerUseCase.invoke() } val userResult = userDeferred.await() - val capsulesResult = capsulesDeferred.await() + val beforeBuriedResult = beforeBuriedDeferred.await() + val buriedResult = buriedDeferred.await() + val seasonBannerResponse = seasonBannerDeferred.await() - val results = listOf(userResult, capsulesResult) + val results = listOf(userResult, beforeBuriedResult, buriedResult, seasonBannerResponse) intent { if (results.any { it.isFailure }) { val errorMessage = results.first { it.isFailure }.exceptionOrNull()?.message + Log.d("TTT", errorMessage.toString()) reduce { state.copy(isLoading = false, errorMessage = errorMessage) } } else { reduce { state.copy( data = HomeData( user = userResult.getOrNull(), - capsules = capsulesResult.getOrNull() ?: emptyMap(), + beforeBuried = beforeBuriedResult.getOrNull()?.content ?: emptyList(), + buried = buriedResult.getOrNull()?.content ?: emptyList(), + seasonBanner = seasonBannerResponse.getOrNull() ), isLoading = false, errorMessage = null, @@ -81,6 +110,110 @@ class HomeViewModel @Inject constructor( } } + private fun fetchOpened() = intent { + intent { reduce { state.copy(isLoading = true) } } + + getMyTimeCapsuleUseCase( + status = TimeCapsuleStatus.OPENED, + page = 0, + size = 10, + ).onSuccess { + val latestData = state.data ?: return@onSuccess + intent { + reduce { + state.copy( + data = latestData.copy( + opened = PaginationState().addPage(it) + ), + isLoading = false, + errorMessage = null, + ) + } + } + }.onFailure { + intent { + reduce { + state.copy( + isLoading = false, + errorMessage = it.message + ) + } + } + } + } + + private fun loadNextOpened() = intent { + val currentData = state.data ?: return@intent + val opened = currentData.opened + + if (state.isLoading || !opened.canLoadMore) return@intent + + val currentPage = opened.currentPage + val nextPage = currentPage + 1 + + reduce { + state.copy( + data = currentData.copy( + opened = opened.setLoadingMore(true), + ), + ) + } + + getMyTimeCapsuleUseCase( + status = TimeCapsuleStatus.OPENED, + page = nextPage, + size = 10, + ).onSuccess { response -> + val latestData = state.data ?: return@onSuccess + val latestOpened = latestData.opened + val isCurrentRequest = latestOpened.currentPage == currentPage && + latestOpened.isLoadingMore + + if (!isCurrentRequest) return@onSuccess + + reduce { + state.copy( + data = latestData.copy( + opened = latestOpened.addPage(response), + ), + errorMessage = null, + ) + } + }.onFailure { error -> + val latestData = state.data ?: return@onFailure + val latestOpened = latestData.opened + val isCurrentRequest = latestOpened.currentPage == currentPage && + latestOpened.isLoadingMore + + if (!isCurrentRequest) return@onFailure + + reduce { + state.copy( + data = latestData.copy( + opened = latestOpened.setLoadingMore(false), + ), + errorMessage = error.message, + ) + } + } + } + + private fun refreshOpened() { + intent { + val homeData = state.data + val seasonBanner = getSeasonBannerUseCase.invoke() + reduce { + state.copy( + data = homeData?.copy( + opened = PaginationState(), + seasonBanner = seasonBanner.getOrNull() + ) + ) + } + } + loadNextOpened() + } + private fun requestCollaborator(body: PendingCollaboratorsRequest) = safeLaunch { intent { reduce { state.copy(isLoading = true) } } @@ -100,10 +233,12 @@ class HomeViewModel @Inject constructor( when (action) { HomeAction.CreateClicked -> postSideEffect(HomeSideEffect.NavigateToCreate) HomeAction.ProfileClicked -> postSideEffect(HomeSideEffect.NavigateToProfile) - is HomeAction.TimeCapsuleClicked -> postSideEffect(HomeSideEffect.NavigateToDetail(action.id)) + is HomeAction.TimeCapsuleClicked -> postSideEffect(NavigateToDetail(action.id)) is HomeAction.JoinCodeSubmitted -> requestCollaborator(PendingCollaboratorsRequest(action.code)) - HomeAction.Refresh -> fetchHome() - is HomeAction.HomeDetailClicked -> postSideEffect(HomeSideEffect.NavigateToHomeDetail(action.homeDetailType)) + HomeAction.RefreshHome -> fetchHome() + is HomeAction.HomeDetailClicked -> postSideEffect(NavigateToHomeDetail(action.homeDetailType)) + HomeAction.NextOpenedPageRequested -> loadNextOpened() + HomeAction.RefreshOpened -> refreshOpened() } } } @@ -119,7 +254,19 @@ data class HomeUiState( @Immutable data class HomeData( val user: ProfileResponse? = null, - val capsules: Map> = emptyMap() + val beforeBuried: List = emptyList(), + val buried: List = emptyList(), + val opened: PaginationState = PaginationState(), + val seasonBanner: SeasonBannerResponse? = null, +) + +internal fun PaginationState.addPage( + response: MyTimeCapsuleResponse, +): PaginationState = addPage( + newItems = response.content, + page = response.number, + totalElements = response.totalElements, + isLast = response.last, ) sealed interface HomeAction { @@ -127,7 +274,9 @@ sealed interface HomeAction { data object ProfileClicked : HomeAction data class TimeCapsuleClicked(val id: Long) : HomeAction data class JoinCodeSubmitted(val code: String) : HomeAction - data object Refresh : HomeAction + data object RefreshHome : HomeAction + data object RefreshOpened : HomeAction + data object NextOpenedPageRequested : HomeAction data class HomeDetailClicked(val homeDetailType: HomeDetailType) : HomeAction } From 1404f1b9969c285ff6429a48eb337abb31e62837 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Tue, 15 Sep 2026 17:28:20 +0900 Subject: [PATCH 10/31] =?UTF-8?q?:sparkles:=20::=20develop=20=EB=B3=91?= =?UTF-8?q?=ED=95=A9=20=ED=9B=84=20=EC=88=98=EC=A0=95=EC=82=AC=ED=95=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/timecapsule/MyTimeCapsuleResponse.kt | 9 --------- .../com/idiotfrogs/network/service/TimeCapsuleService.kt | 1 + .../java/com/idiotfrogs/home/component/HomeTicket.kt | 9 +++++---- .../src/main/java/com/idiotfrogs/home/home/HomeScreen.kt | 6 +++++- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/core/model/src/main/java/com/idiotfrogs/model/timecapsule/MyTimeCapsuleResponse.kt b/core/model/src/main/java/com/idiotfrogs/model/timecapsule/MyTimeCapsuleResponse.kt index 8a2fe9af..0c7dc5ce 100644 --- a/core/model/src/main/java/com/idiotfrogs/model/timecapsule/MyTimeCapsuleResponse.kt +++ b/core/model/src/main/java/com/idiotfrogs/model/timecapsule/MyTimeCapsuleResponse.kt @@ -3,15 +3,6 @@ package com.idiotfrogs.model.timecapsule import kotlinx.datetime.LocalDate import kotlinx.serialization.Serializable -@Serializable -data class MyTimeCapsuleListResponse( - val content: List, - val totalPages: Int, - val totalElements: Int, - val number: Int, - val last: Boolean, -) - @Serializable data class MyTimeCapsuleResponse( val content: List, diff --git a/core/network/src/main/java/com/idiotfrogs/network/service/TimeCapsuleService.kt b/core/network/src/main/java/com/idiotfrogs/network/service/TimeCapsuleService.kt index 6129b0d5..71185e9a 100644 --- a/core/network/src/main/java/com/idiotfrogs/network/service/TimeCapsuleService.kt +++ b/core/network/src/main/java/com/idiotfrogs/network/service/TimeCapsuleService.kt @@ -4,6 +4,7 @@ import com.idiotfrogs.model.timecapsule.BuryTimeCapsuleRequest import com.idiotfrogs.model.timecapsule.CapsuleContentsData import com.idiotfrogs.model.timecapsule.JoinRequestResponse import com.idiotfrogs.model.timecapsule.MyCapsuleContentsData +import com.idiotfrogs.model.timecapsule.MyTimeCapsuleResponse import com.idiotfrogs.model.timecapsule.PendingCollaboratorsRequest import com.idiotfrogs.model.timecapsule.TimeCapsuleCollaboratorsResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleContentResponse diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt index 0d6b01f2..f5d3f2ea 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt @@ -37,7 +37,8 @@ import com.idiotfrogs.designsystem.theme.MSTheme import com.idiotfrogs.designsystem.util.wavyStroke import com.idiotfrogs.resource.R import com.skydoves.landscapist.glide.GlideImage - +// 0단계, 1단계 보정 값 +private const val INDEX_ADJUST_VALUE = 2 /** 사진 영역에 준 offset. 가이드 이미지도 동일하게 올려 바디 하단선에 맞춘다. */ private val BODY_OFFSET_Y = (-10).dp @@ -133,7 +134,7 @@ fun HomeBigTicket( ) } } - DefaultGuideItem.entries.getOrNull(step - 1)?.let { + DefaultGuideItem.entries.getOrNull(step - INDEX_ADJUST_VALUE)?.let { Image( modifier = Modifier .align(Alignment.BottomCenter) @@ -228,7 +229,7 @@ fun HomeMiddleTicket( ) } } - DefaultGuideItem.entries.getOrNull(step - 1)?.let { + DefaultGuideItem.entries.getOrNull(step - INDEX_ADJUST_VALUE)?.let { Image( modifier = Modifier .align(Alignment.BottomCenter) @@ -331,7 +332,7 @@ fun HomeSmallTicket( ) } } - SmallGuideItem.entries.getOrNull(step - 1)?.let { + SmallGuideItem.entries.getOrNull(step - INDEX_ADJUST_VALUE)?.let { Image( modifier = Modifier .align(Alignment.BottomCenter) diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt index cd9cbb4a..869628f2 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt @@ -255,7 +255,11 @@ fun HomeScreen( ) } .padding(horizontal = (22.5).dp) - .padding(top = 40.dp, bottom = 15.dp), + .padding( + // 만약 묻기전 티켓이 없다면 맨 위이므로 패딩 값이 없다 + top = if (data.beforeBuried.isEmpty()) 0.dp else 40.dp, + bottom = 15.dp + ), sectionName = "오픈 예정 티켓" ) } From 9e67fe7e40739c437719ce4ca416536485781fef Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Wed, 16 Sep 2026 09:57:23 +0900 Subject: [PATCH 11/31] =?UTF-8?q?:sparkles:=20::=20=EC=98=A4=ED=94=88?= =?UTF-8?q?=EB=90=9C=20=ED=8B=B0=EC=BC=93=20=EA=B4=80=EB=A0=A8=20=EC=9E=91?= =?UTF-8?q?=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../idiotfrogs/home/component/OpenedTicket.kt | 20 ++++++++++++++----- .../com/idiotfrogs/home/home/HomeScreen.kt | 11 ++++++++-- .../com/idiotfrogs/home/home/HomeViewModel.kt | 7 +++++-- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt index 59a9d4e9..b0c56973 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt @@ -29,7 +29,12 @@ import com.idiotfrogs.resource.R import com.skydoves.landscapist.glide.GlideImage @Composable -fun OpenedTicket() { +fun OpenedTicket( + title: String, + createAt: String, + openedAt: String, + imageUrl: String?, +) { Column( modifier = Modifier .fillMaxWidth() @@ -74,19 +79,19 @@ fun OpenedTicket() { ) } }, - imageModel = { R.drawable.img_sample } + imageModel = { imageUrl ?: R.drawable.img_sample } ) } Spacer(modifier = Modifier.height(12.dp)) MSText( - text = "제목입니다. 제목입니다.", + text = title, fontWeight = FontWeight.Bold, fontSize = 16.dp, color = MSTheme.color.greyG5 ) Spacer(modifier = Modifier.height(8.dp)) MSText( - text = "2027. 10. 24 ~ 2027. 10. 24 ", + text = "$createAt ~ $openedAt", fontWeight = FontWeight.Normal, fontSize = 12.dp, color = MSTheme.color.greyG5.copy(alpha = 0.6f) @@ -97,5 +102,10 @@ fun OpenedTicket() { @Preview(widthDp = 160, heightDp = 286) @Composable fun OpenedTicketPreview() { - OpenedTicket() + OpenedTicket( + title = "테스트트", + createAt = "2026. 09. 15", + openedAt = "2026. 09. 16", + imageUrl = null + ) } \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt index 869628f2..d8924a53 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt @@ -300,14 +300,21 @@ fun HomeScreen( onRefresh = { onAction.invoke(HomeAction.RefreshOpened) } ) { LazyVerticalGrid( - modifier = Modifier.padding(horizontal = 20.dp), + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 20.dp), columns = GridCells.Fixed(2), horizontalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(24.dp), contentPadding = PaddingValues(top = 20.dp, bottom = BOTTOM_BAR_SIZE) ) { items(data.opened.items) { - OpenedTicket() + OpenedTicket( + title = it.title, + createAt = it.createdAt.toYearMonthDay(), + openedAt = it.openedAt.toYearMonthDay(), + imageUrl = it.mainImageUrl + ) } } } diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt index 4f5474ea..9e6d3813 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt @@ -93,9 +93,11 @@ class HomeViewModel @Inject constructor( Log.d("TTT", errorMessage.toString()) reduce { state.copy(isLoading = false, errorMessage = errorMessage) } } else { + // 비동기로 여러 API 호출하므로 실행 시점에 데이터 있는지 파악 + val latestData = state.data ?: HomeData() reduce { state.copy( - data = HomeData( + data = latestData.copy( user = userResult.getOrNull(), beforeBuried = beforeBuriedResult.getOrNull()?.content ?: emptyList(), buried = buriedResult.getOrNull()?.content ?: emptyList(), @@ -118,7 +120,8 @@ class HomeViewModel @Inject constructor( page = 0, size = 10, ).onSuccess { - val latestData = state.data ?: return@onSuccess + // 비동기로 여러 API 호출하므로 실행 시점에 데이터 있는지 파악 + val latestData = state.data ?: HomeData() intent { reduce { state.copy( From 84b9ee1d633c589f5e2224d6aa10d550e58aa746 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Wed, 16 Sep 2026 15:10:10 +0900 Subject: [PATCH 12/31] =?UTF-8?q?:sparkles:=20::=20=EC=98=A4=ED=94=88?= =?UTF-8?q?=EB=90=9C=20=ED=8B=B0=EC=BC=93=20=EC=95=A0=EB=8B=88=EB=A9=94?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=B2=98=EB=A6=AC=20=EC=9E=91=EC=97=85=20?= =?UTF-8?q?=EB=B0=8F=20API=20=EC=9D=91=EB=8B=B5=EA=B0=92=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../idiotfrogs/memoryseal/MainViewModel.kt | 4 +- .../model/timecapsule/TimeCapsuleResponse.kt | 1 + .../timecapsule/TimeCapsuleUnopenedContent.kt | 12 ++++++ .../network/service/TimeCapsuleService.kt | 4 ++ .../timecapsule/TimeCapsuleDataSource.kt | 3 ++ .../timecapsule/TimeCapsuleDataSourceImpl.kt | 5 +++ .../timecapsule/TimeCapsuleRepository.kt | 3 ++ .../timecapsule/TimeCapsuleRepositoryImpl.kt | 7 +++- .../GetOpenedMyTimeCapsuleUseCase.kt | 19 ---------- .../usecase/timecapsule/GetUnopenedUseCase.kt | 11 ++++++ .../com/idiotfrogs/detail/DetailScreen.kt | 1 + .../com/idiotfrogs/detail/DetailViewModel.kt | 23 +++++++----- .../java/com/idiotfrogs/home/HomeScreen.kt | 0 .../java/com/idiotfrogs/home/HomeViewModel.kt | 0 .../home/component/HomeOpenedBanner.kt | 37 ++++++++++++++----- .../idiotfrogs/home/component/HomeTicket.kt | 18 ++++++--- .../com/idiotfrogs/home/home/HomeScreen.kt | 8 ++-- .../com/idiotfrogs/home/home/HomeViewModel.kt | 11 +++++- .../java/com/idiotfrogs/open/OpenScreen.kt | 5 ++- .../java/com/idiotfrogs/open/OpenViewModel.kt | 4 +- 20 files changed, 119 insertions(+), 57 deletions(-) create mode 100644 core/model/src/main/java/com/idiotfrogs/model/timecapsule/TimeCapsuleUnopenedContent.kt delete mode 100644 domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetOpenedMyTimeCapsuleUseCase.kt create mode 100644 domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetUnopenedUseCase.kt delete mode 100644 feature/home/src/main/java/com/idiotfrogs/home/HomeScreen.kt delete mode 100644 feature/home/src/main/java/com/idiotfrogs/home/HomeViewModel.kt diff --git a/app/src/main/java/com/idiotfrogs/memoryseal/MainViewModel.kt b/app/src/main/java/com/idiotfrogs/memoryseal/MainViewModel.kt index 4d2facfd..1701dcf4 100644 --- a/app/src/main/java/com/idiotfrogs/memoryseal/MainViewModel.kt +++ b/app/src/main/java/com/idiotfrogs/memoryseal/MainViewModel.kt @@ -54,8 +54,8 @@ class MainViewModel @Inject constructor( val event = when (action) { "member" -> MainNavigationEvent.NavigateToFriend(id) - "detail" -> MainNavigationEvent.NavigateToDetail(id) - "open" -> MainNavigationEvent.NavigateToMemory(id) + // 오픈도 detail에서 열람 이력 확인 후 애니메이션 노출 여부 결정 + "detail", "open" -> MainNavigationEvent.NavigateToDetail(id) else -> return } diff --git a/core/model/src/main/java/com/idiotfrogs/model/timecapsule/TimeCapsuleResponse.kt b/core/model/src/main/java/com/idiotfrogs/model/timecapsule/TimeCapsuleResponse.kt index 183af780..03379b1a 100644 --- a/core/model/src/main/java/com/idiotfrogs/model/timecapsule/TimeCapsuleResponse.kt +++ b/core/model/src/main/java/com/idiotfrogs/model/timecapsule/TimeCapsuleResponse.kt @@ -15,4 +15,5 @@ data class TimeCapsuleResponse( val userRole: TimeCapsuleRole, val myContentCount: Int, val myImageCount: Int, + val animationShown: Boolean, ) \ No newline at end of file diff --git a/core/model/src/main/java/com/idiotfrogs/model/timecapsule/TimeCapsuleUnopenedContent.kt b/core/model/src/main/java/com/idiotfrogs/model/timecapsule/TimeCapsuleUnopenedContent.kt new file mode 100644 index 00000000..4cc71ef7 --- /dev/null +++ b/core/model/src/main/java/com/idiotfrogs/model/timecapsule/TimeCapsuleUnopenedContent.kt @@ -0,0 +1,12 @@ +package com.idiotfrogs.model.timecapsule + +import kotlinx.datetime.LocalDate +import kotlinx.serialization.Serializable + +@Serializable +data class TimeCapsuleUnopenedContent( + val timeCapsuleId: Long, + val title: String, + val openedAt: LocalDate, + val mainImageUrl: String +) \ No newline at end of file diff --git a/core/network/src/main/java/com/idiotfrogs/network/service/TimeCapsuleService.kt b/core/network/src/main/java/com/idiotfrogs/network/service/TimeCapsuleService.kt index 71185e9a..23e993d4 100644 --- a/core/network/src/main/java/com/idiotfrogs/network/service/TimeCapsuleService.kt +++ b/core/network/src/main/java/com/idiotfrogs/network/service/TimeCapsuleService.kt @@ -13,6 +13,7 @@ import com.idiotfrogs.model.timecapsule.TimeCapsuleCreateResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleInviteCodeResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus +import com.idiotfrogs.model.timecapsule.TimeCapsuleUnopenedContent import com.idiotfrogs.model.timecapsule.WateringResponse import okhttp3.MultipartBody import okhttp3.RequestBody @@ -137,4 +138,7 @@ interface TimeCapsuleService { suspend fun watering( @Path("capsuleId") capsuleId: Long ) + + @GET("time-capsules/unopened") + suspend fun getUnopened(): List } diff --git a/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSource.kt b/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSource.kt index 20f37ffa..e80c6cc9 100644 --- a/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSource.kt +++ b/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSource.kt @@ -13,6 +13,7 @@ import com.idiotfrogs.model.timecapsule.TimeCapsuleCreateResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleInviteCodeResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus +import com.idiotfrogs.model.timecapsule.TimeCapsuleUnopenedContent import com.idiotfrogs.model.timecapsule.WateringResponse import okhttp3.MultipartBody import okhttp3.RequestBody @@ -92,4 +93,6 @@ interface TimeCapsuleDataSource { suspend fun getWatering(capsuleId: Long, page: Int, size: Int, sort: String): WateringResponse suspend fun watering(capsuleId: Long) + + suspend fun getUnopened(): List } diff --git a/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSourceImpl.kt b/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSourceImpl.kt index d9cc89cb..f9d335be 100644 --- a/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSourceImpl.kt +++ b/data/src/main/java/com/idiotfrogs/data/datasource/timecapsule/TimeCapsuleDataSourceImpl.kt @@ -13,6 +13,7 @@ import com.idiotfrogs.model.timecapsule.TimeCapsuleCreateResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleInviteCodeResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus +import com.idiotfrogs.model.timecapsule.TimeCapsuleUnopenedContent import com.idiotfrogs.model.timecapsule.WateringResponse import com.idiotfrogs.network.service.TimeCapsuleService import okhttp3.MultipartBody @@ -172,4 +173,8 @@ class TimeCapsuleDataSourceImpl @Inject constructor( override suspend fun watering(capsuleId: Long) { return timeCapsuleService.watering(capsuleId) } + + override suspend fun getUnopened(): List { + return timeCapsuleService.getUnopened() + } } \ No newline at end of file diff --git a/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepository.kt b/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepository.kt index 2ea96852..2c19f9df 100644 --- a/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepository.kt +++ b/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepository.kt @@ -13,6 +13,7 @@ import com.idiotfrogs.model.timecapsule.TimeCapsuleCreateResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleInviteCodeResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus +import com.idiotfrogs.model.timecapsule.TimeCapsuleUnopenedContent import com.idiotfrogs.model.timecapsule.WateringResponse import java.io.File @@ -96,4 +97,6 @@ interface TimeCapsuleRepository { ): WateringResponse suspend fun watering(capsuleId: Long) + + suspend fun getUnopened(): List } diff --git a/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepositoryImpl.kt b/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepositoryImpl.kt index 4a60d842..b72e5541 100644 --- a/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepositoryImpl.kt +++ b/data/src/main/java/com/idiotfrogs/data/repository/timecapsule/TimeCapsuleRepositoryImpl.kt @@ -14,9 +14,9 @@ import com.idiotfrogs.model.timecapsule.TimeCapsuleCreateResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleInviteCodeResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleResponse import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus +import com.idiotfrogs.model.timecapsule.TimeCapsuleUnopenedContent import com.idiotfrogs.util.exception.AlreadyContributorException import com.idiotfrogs.model.timecapsule.WateringResponse -import com.idiotfrogs.network.service.TimeCapsuleService import okhttp3.MediaType.Companion.toMediaType import okhttp3.MultipartBody import okhttp3.RequestBody.Companion.asRequestBody @@ -26,7 +26,6 @@ import java.io.File import javax.inject.Inject class TimeCapsuleRepositoryImpl @Inject constructor( - private val timeCapsuleService: TimeCapsuleService, private val timeCapsuleDataSource: TimeCapsuleDataSource ) : TimeCapsuleRepository { override suspend fun createTimeCapsule( @@ -191,6 +190,10 @@ class TimeCapsuleRepositoryImpl @Inject constructor( return timeCapsuleDataSource.watering(capsuleId) } + override suspend fun getUnopened(): List { + return timeCapsuleDataSource.getUnopened() + } + companion object { private const val ALREADY_CONTRIBUTOR_STATUS_CODE = 409 diff --git a/domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetOpenedMyTimeCapsuleUseCase.kt b/domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetOpenedMyTimeCapsuleUseCase.kt deleted file mode 100644 index 65edf24c..00000000 --- a/domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetOpenedMyTimeCapsuleUseCase.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.idiotfrogs.domain.usecase.timecapsule - -import com.idiotfrogs.data.repository.timecapsule.TimeCapsuleRepository -import com.idiotfrogs.model.timecapsule.MyTimeCapsuleResponse -import com.idiotfrogs.model.timecapsule.TimeCapsuleRole -import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus -import com.idiotfrogs.util.safeCatching -import javax.inject.Inject - -class GetOpenedMyTimeCapsuleUseCase @Inject constructor( - private val timeCapsuleRepository: TimeCapsuleRepository -) { - suspend operator fun invoke(): Result>> = - safeCatching { - timeCapsuleRepository.getMyTimeCapsule() - .filter { it.timeCapsuleStatus == TimeCapsuleStatus.OPENED } - .groupBy { it.role } - } -} \ No newline at end of file diff --git a/domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetUnopenedUseCase.kt b/domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetUnopenedUseCase.kt new file mode 100644 index 00000000..331d1481 --- /dev/null +++ b/domain/src/main/java/com/idiotfrogs/domain/usecase/timecapsule/GetUnopenedUseCase.kt @@ -0,0 +1,11 @@ +package com.idiotfrogs.domain.usecase.timecapsule + +import com.idiotfrogs.data.repository.timecapsule.TimeCapsuleRepository +import com.idiotfrogs.util.safeCatching +import javax.inject.Inject + +class GetUnopenedUseCase @Inject constructor( + private val timeCapsuleRepository: TimeCapsuleRepository +) { + suspend fun invoke() = safeCatching { timeCapsuleRepository.getUnopened() } +} \ No newline at end of file diff --git a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt index 6b9891d6..5f0eacba 100644 --- a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt +++ b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt @@ -107,6 +107,7 @@ fun DetailRoute( ) ) is DetailSideEffect.NavigateToWatering -> navigator.navigate(Routes.Watering(event.id)) + is DetailSideEffect.NavigateToOpen -> navigator.navigate(Routes.Open(event.id)) DetailSideEffect.ShowToast -> showToast = true } } diff --git a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt index 45cdf813..1efde954 100644 --- a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt +++ b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt @@ -60,15 +60,19 @@ class DetailViewModel @AssistedInject constructor( reduce { state.copy(isLoading = false, errorMessage = errorMessage) } } else { - reduce { - state.copy( - data = TimeCapsuleData( - capsule = capsuleResult.getOrNull(), - collaborators = collaboratorsResult.getOrNull(), - ), - isLoading = false, - errorMessage = null, - ) + if (capsuleResult.getOrNull()?.animationShown == false) { + postSideEffect(DetailSideEffect.NavigateToOpen(capsuleId)) + } else { + reduce { + state.copy( + data = TimeCapsuleData( + capsule = capsuleResult.getOrNull(), + collaborators = collaboratorsResult.getOrNull(), + ), + isLoading = false, + errorMessage = null, + ) + } } } } @@ -160,5 +164,6 @@ sealed interface DetailSideEffect { data class NavigateToManagement(val id: Long, val title: String) : DetailSideEffect data class NavigateToWatering(val id: Long) : DetailSideEffect data object NavigateToBack : DetailSideEffect + data class NavigateToOpen(val id: Long) : DetailSideEffect data object ShowToast : DetailSideEffect } diff --git a/feature/home/src/main/java/com/idiotfrogs/home/HomeScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/HomeScreen.kt deleted file mode 100644 index e69de29b..00000000 diff --git a/feature/home/src/main/java/com/idiotfrogs/home/HomeViewModel.kt b/feature/home/src/main/java/com/idiotfrogs/home/HomeViewModel.kt deleted file mode 100644 index e69de29b..00000000 diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt index 3f43426a..c146e618 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt @@ -30,7 +30,10 @@ import androidx.compose.ui.util.lerp import androidx.compose.ui.zIndex import com.idiotfrogs.designsystem.component.MSText import com.idiotfrogs.designsystem.theme.MSTheme +import com.idiotfrogs.designsystem.util.noRippleClickable import com.idiotfrogs.designsystem.util.wavyStroke +import com.idiotfrogs.extension.toYearMonthDay +import com.idiotfrogs.model.timecapsule.TimeCapsuleUnopenedContent import com.idiotfrogs.resource.R import kotlin.math.absoluteValue @@ -46,9 +49,10 @@ private val SIDE_OFFSET_Y = 22.dp @Composable fun HomeOpenedBanner( modifier: Modifier = Modifier, - capsuleSteps: List, + unopenedList: List, + onClick: (capsuleId: Long) -> Unit, ) { - val pagerState = rememberPagerState { capsuleSteps.size } + val pagerState = rememberPagerState { unopenedList.size } Box(modifier = modifier) { Box( @@ -85,11 +89,11 @@ fun HomeOpenedBanner( modifier = Modifier .fillMaxWidth() .height( - if (capsuleSteps.size == 1) 490.dp else 290.dp + if (unopenedList.size == 1) 490.dp else 290.dp ) .padding(horizontal = 28.dp) .padding( - top = if (capsuleSteps.size == 1) 0.dp else 13.dp + top = if (unopenedList.size == 1) 0.dp else 13.dp ) .alpha(alpha), painter = painterResource(R.drawable.bg_light), @@ -97,10 +101,15 @@ fun HomeOpenedBanner( contentScale = ContentScale.FillBounds ) // 단일 티켓인 경우 디자인이 다름 - if (capsuleSteps.size == 1) { + if (unopenedList.size == 1) { HomeBigTicket( - modifier = Modifier.padding(top = 67.dp), - step = capsuleSteps.first() + modifier = Modifier + .noRippleClickable { onClick.invoke(unopenedList.first().timeCapsuleId) } + .padding(top = 67.dp), + title = unopenedList.first().title, + openedAt = unopenedList.first().openedAt.toYearMonthDay(), + imageUrl = unopenedList.first().mainImageUrl, + step = 1, ) Spacer(modifier = Modifier.height(32.dp)) return @@ -116,8 +125,13 @@ fun HomeOpenedBanner( beyondViewportPageCount = 1, // 양 옆에도 보여야 하므로 해당 페이지 외 미리 로드 ) { page -> HomeMiddleTicket( - modifier = Modifier.deckPage(pagerState, page), - step = capsuleSteps[page], + modifier = Modifier + .noRippleClickable { onClick.invoke(unopenedList[page].timeCapsuleId) } + .deckPage(pagerState, page), + title = unopenedList[page].title, + openedAt = unopenedList[page].openedAt.toYearMonthDay(), + imageUrl = unopenedList[page].mainImageUrl, + step = 1, ) } } @@ -145,5 +159,8 @@ private fun Modifier.deckPage(state: PagerState, page: Int): Modifier { @Preview(showBackground = true, heightDp = 520) @Composable private fun HomeOpenedBannerPreview() { - HomeOpenedBanner(capsuleSteps = listOf(2, 3, 4)) + HomeOpenedBanner( + unopenedList = emptyList(), + onClick = {} + ) } \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt index f5d3f2ea..0468cf4b 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt @@ -58,6 +58,9 @@ enum class SmallGuideItem(val imgRes: Int, val height: Dp) { @Composable fun HomeBigTicket( modifier: Modifier = Modifier, + title: String, + openedAt: String, + imageUrl: String?, step: Int, ) { // 티켓 바디(헤더 + 사진). 가이드 이미지는 이 Box 하단을 기준으로 정렬된다. @@ -88,13 +91,13 @@ fun HomeBigTicket( verticalArrangement = Arrangement.spacedBy(8.dp) ) { MSText( - text = "제목입니다. 제목입니다.", + text = title, fontWeight = FontWeight.Bold, fontSize = 24.dp, color = MSTheme.color.greyG5 ) MSText( - text = "2027. 10. 24.", + text = openedAt, fontWeight = FontWeight.Normal, fontSize = 14.dp, color = MSTheme.color.greyG5.copy(alpha = 0.6f) @@ -130,7 +133,7 @@ fun HomeBigTicket( ) } }, - imageModel = { R.drawable.img_sample } + imageModel = { imageUrl ?: R.drawable.img_sample } ) } } @@ -151,6 +154,9 @@ fun HomeBigTicket( @Composable fun HomeMiddleTicket( modifier: Modifier = Modifier, + title: String, + openedAt: String, + imageUrl: String?, step: Int ) { // 티켓 바디(헤더 + 사진). 가이드 이미지는 이 Box 하단을 기준으로 정렬된다. @@ -183,13 +189,13 @@ fun HomeMiddleTicket( verticalArrangement = Arrangement.spacedBy(8.dp) ) { MSText( - text = "제목입니다. 제목입니다.", + text = title, fontWeight = FontWeight.Bold, fontSize = 20.dp, color = MSTheme.color.greyG5 ) MSText( - text = "2027. 10. 24.", + text = openedAt, fontWeight = FontWeight.Normal, fontSize = 14.dp, color = MSTheme.color.greyG5.copy(alpha = 0.6f) @@ -225,7 +231,7 @@ fun HomeMiddleTicket( ) } }, - imageModel = { R.drawable.img_sample } + imageModel = { imageUrl ?: R.drawable.img_sample } ) } } diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt index d8924a53..9e9ad13d 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt @@ -180,12 +180,12 @@ fun HomeScreen( columns = GridCells.Fixed(2), horizontalArrangement = Arrangement.spacedBy((-12).dp) // 줄기가 겹쳐지도록 ) { - val showOpenedBanner = true - if (showOpenedBanner) { + if (!data.unopenedBanner.isNullOrEmpty()) { maxLineItem { HomeOpenedBanner( modifier = Modifier.padding(top = 12.dp), - capsuleSteps = listOf(1) + unopenedList = data.unopenedBanner, + onClick = { onAction.invoke(HomeAction.TimeCapsuleClicked(it)) } ) } } @@ -194,7 +194,7 @@ fun HomeScreen( HomeRemindBanner( modifier = Modifier .padding( - top = if (showOpenedBanner) 0.dp else 20.dp, + top = if (!data.unopenedBanner.isNullOrEmpty()) 0.dp else 20.dp, start = 20.dp, end = 20.dp, bottom = 20.dp ) .noRippleClickable { diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt index 9e6d3813..6a998f97 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt @@ -5,6 +5,7 @@ import androidx.compose.runtime.Immutable import com.idiotfrogs.domain.usecase.auth.PutFcmTokenUseCase import com.idiotfrogs.domain.usecase.home.GetSeasonBannerUseCase import com.idiotfrogs.domain.usecase.timecapsule.GetMyTimeCapsuleUseCase +import com.idiotfrogs.domain.usecase.timecapsule.GetUnopenedUseCase import com.idiotfrogs.domain.usecase.timecapsule.RequestCollaboratorUseCase import com.idiotfrogs.domain.usecase.user.GetMyProfileUseCase import com.idiotfrogs.home.home.HomeSideEffect.* @@ -13,6 +14,7 @@ import com.idiotfrogs.model.timecapsule.MyTimeCapsuleContent import com.idiotfrogs.model.timecapsule.MyTimeCapsuleResponse import com.idiotfrogs.model.timecapsule.PendingCollaboratorsRequest import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus +import com.idiotfrogs.model.timecapsule.TimeCapsuleUnopenedContent import com.idiotfrogs.model.user.ProfileResponse import com.idiotfrogs.navigation.HomeDetailType import com.idiotfrogs.notification.FcmTokenProvider @@ -32,6 +34,7 @@ import kotlin.collections.emptyList class HomeViewModel @Inject constructor( private val getMyTimeCapsuleUseCase: GetMyTimeCapsuleUseCase, private val getMyProfileUseCase: GetMyProfileUseCase, + private val getUnopenedUseCase: GetUnopenedUseCase, private val requestCollaboratorUseCase: RequestCollaboratorUseCase, private val fcmTokenProvider: FcmTokenProvider, private val putFcmTokenUseCase: PutFcmTokenUseCase, @@ -78,13 +81,15 @@ class HomeViewModel @Inject constructor( ) } val seasonBannerDeferred = async { getSeasonBannerUseCase.invoke() } + val unopenedDeferred = async { getUnopenedUseCase.invoke() } val userResult = userDeferred.await() val beforeBuriedResult = beforeBuriedDeferred.await() val buriedResult = buriedDeferred.await() val seasonBannerResponse = seasonBannerDeferred.await() + val unopenedResponse = unopenedDeferred.await() - val results = listOf(userResult, beforeBuriedResult, buriedResult, seasonBannerResponse) + val results = listOf(userResult, beforeBuriedResult, buriedResult, seasonBannerResponse, unopenedResponse) intent { if (results.any { it.isFailure }) { @@ -101,7 +106,8 @@ class HomeViewModel @Inject constructor( user = userResult.getOrNull(), beforeBuried = beforeBuriedResult.getOrNull()?.content ?: emptyList(), buried = buriedResult.getOrNull()?.content ?: emptyList(), - seasonBanner = seasonBannerResponse.getOrNull() + seasonBanner = seasonBannerResponse.getOrNull(), + unopenedBanner = unopenedResponse.getOrNull() ), isLoading = false, errorMessage = null, @@ -261,6 +267,7 @@ data class HomeData( val buried: List = emptyList(), val opened: PaginationState = PaginationState(), val seasonBanner: SeasonBannerResponse? = null, + val unopenedBanner: List? = null ) internal fun PaginationState.addPage( diff --git a/feature/open/src/main/java/com/idiotfrogs/open/OpenScreen.kt b/feature/open/src/main/java/com/idiotfrogs/open/OpenScreen.kt index d452470d..83c367c8 100644 --- a/feature/open/src/main/java/com/idiotfrogs/open/OpenScreen.kt +++ b/feature/open/src/main/java/com/idiotfrogs/open/OpenScreen.kt @@ -39,7 +39,10 @@ fun OpenRoute( viewModel.collectSideEffect { event -> when (event) { - is OpenSideEffect.NavigateToDetail -> navigator.navigate(Routes.Detail(event.capsuleId)) + is OpenSideEffect.NavigateToMemory -> { + navigator.popBackStack() + navigator.navigate(Routes.Memory(event.capsuleId)) + } } } diff --git a/feature/open/src/main/java/com/idiotfrogs/open/OpenViewModel.kt b/feature/open/src/main/java/com/idiotfrogs/open/OpenViewModel.kt index 811e5551..3bb33f1d 100644 --- a/feature/open/src/main/java/com/idiotfrogs/open/OpenViewModel.kt +++ b/feature/open/src/main/java/com/idiotfrogs/open/OpenViewModel.kt @@ -23,7 +23,7 @@ class OpenViewModel @AssistedInject constructor( override fun onAction(action: OpenAction) { when (action) { - OpenAction.DoneClick -> intent { postSideEffect(OpenSideEffect.NavigateToDetail(capsuleId)) } + OpenAction.DoneClick -> intent { postSideEffect(OpenSideEffect.NavigateToMemory(capsuleId)) } } } @@ -56,5 +56,5 @@ sealed interface OpenAction { } sealed interface OpenSideEffect { - data class NavigateToDetail(val capsuleId: Long) : OpenSideEffect + data class NavigateToMemory(val capsuleId: Long) : OpenSideEffect } From d80a51f4c11f1fb64e11364723f7ff4db8e09254 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Wed, 16 Sep 2026 15:18:24 +0900 Subject: [PATCH 13/31] =?UTF-8?q?:sparkles:=20::=20=EC=95=A0=EB=8B=88?= =?UTF-8?q?=EB=A9=94=EC=9D=B4=EC=85=98=20=EC=B2=B4=ED=81=AC=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95=20=EB=B0=8F?= =?UTF-8?q?=20=EC=98=A4=ED=94=88=EB=90=9C=20=ED=8B=B0=EC=BC=93=20=ED=84=B0?= =?UTF-8?q?=EC=B9=98=20=EC=95=A1=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/idiotfrogs/detail/DetailViewModel.kt | 4 +++- .../java/com/idiotfrogs/home/component/OpenedTicket.kt | 3 ++- .../src/main/java/com/idiotfrogs/home/home/HomeScreen.kt | 8 ++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt index 1efde954..096de277 100644 --- a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt +++ b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt @@ -60,7 +60,9 @@ class DetailViewModel @AssistedInject constructor( reduce { state.copy(isLoading = false, errorMessage = errorMessage) } } else { - if (capsuleResult.getOrNull()?.animationShown == false) { + val capsule = capsuleResult.getOrNull() + // 반드시 애니메이션 재생 여부와 오픈 여부를 함께 검사해야 한다 + if (capsule?.animationShown == false && capsule.timeCapsuleStatus == TimeCapsuleStatus.OPENED) { postSideEffect(DetailSideEffect.NavigateToOpen(capsuleId)) } else { reduce { diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt index b0c56973..b4f48828 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/OpenedTicket.kt @@ -30,13 +30,14 @@ import com.skydoves.landscapist.glide.GlideImage @Composable fun OpenedTicket( + modifier: Modifier = Modifier, title: String, createAt: String, openedAt: String, imageUrl: String?, ) { Column( - modifier = Modifier + modifier = modifier .fillMaxWidth() .wrapContentHeight() ) { diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt index 9e9ad13d..c3527640 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt @@ -177,6 +177,7 @@ fun HomeScreen( onRefresh = { onAction.invoke(HomeAction.RefreshHome) } ) { LazyVerticalGrid( + modifier = Modifier.fillMaxSize(), columns = GridCells.Fixed(2), horizontalArrangement = Arrangement.spacedBy((-12).dp) // 줄기가 겹쳐지도록 ) { @@ -310,6 +311,13 @@ fun HomeScreen( ) { items(data.opened.items) { OpenedTicket( + modifier = Modifier.noRippleClickable { + onAction.invoke( + HomeAction.TimeCapsuleClicked( + it.timeCapsuleId + ) + ) + }, title = it.title, createAt = it.createdAt.toYearMonthDay(), openedAt = it.openedAt.toYearMonthDay(), From 90ad22f055d5e2200a9925d8bf2b5c6607d8f616 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Wed, 16 Sep 2026 16:20:31 +0900 Subject: [PATCH 14/31] =?UTF-8?q?:sparkles:=20::=20=ED=99=88=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=ED=99=94=EB=A9=B4=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../home/detail/HomeDetailScreen.kt | 90 ++++++++-- .../home/detail/HomeDetailViewModel.kt | 158 ++++++++++++++++++ 2 files changed, 234 insertions(+), 14 deletions(-) create mode 100644 feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailViewModel.kt diff --git a/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt index 060670a2..b7ea28f2 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt @@ -12,25 +12,73 @@ import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.itemsIndexed +import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import com.idiotfrogs.designsystem.component.MSLoadingOverlay +import com.idiotfrogs.designsystem.util.LoadNextPageEffect +import com.idiotfrogs.designsystem.util.noRippleClickable +import com.idiotfrogs.extension.toDdayCount +import com.idiotfrogs.extension.toYearMonthDay import com.idiotfrogs.home.component.HomeSmallTicket import com.idiotfrogs.navigation.HomeDetailType +import com.idiotfrogs.navigation.LocalComposeMSNavigator +import com.idiotfrogs.navigation.Routes.* import com.idiotfrogs.resource.R +import org.orbitmvi.orbit.compose.collectAsState +import org.orbitmvi.orbit.compose.collectSideEffect @Composable fun HomeDetailRoute( - homeDetailType: HomeDetailType + homeDetailType: HomeDetailType, + viewModel: HomeDetailViewModel = + hiltViewModel( + key = homeDetailType.name + ) { + it.create(homeDetailType) + }, ) { - HomeDetailScreen(homeDetailType) + val navigator = LocalComposeMSNavigator.current + val uiState by viewModel.collectAsState() + + viewModel.collectSideEffect { + when (it) { + is HomeDetailSideEffect.NavigateToDetail -> navigator.navigate(Detail(it.id)) + HomeDetailSideEffect.NavigateToBack -> navigator.popBackStack() + } + } + + Box(modifier = Modifier.fillMaxSize()) { + uiState.data?.let { data -> + HomeDetailScreen( + data = data, + onAction = viewModel::onAction + ) + } + + MSLoadingOverlay(visible = uiState.data != null && uiState.isLoading) + } } @Composable -fun HomeDetailScreen(homeDetailType: HomeDetailType) { +fun HomeDetailScreen( + data: HomeDetailData, + onAction: (HomeDetailAction) -> Unit, +) { + val lazyGridState = rememberLazyGridState() + + LoadNextPageEffect( + scrollableState = lazyGridState, + canLoadMore = data.detailItems.canLoadMore, + onLoadNextPage = { onAction(HomeDetailAction.NextItemRequested) }, + ) + Column( modifier = Modifier .fillMaxSize() @@ -44,21 +92,32 @@ fun HomeDetailScreen(homeDetailType: HomeDetailType) { contentAlignment = Alignment.CenterStart ) { Image( - modifier = Modifier.size(24.dp), + modifier = Modifier + .noRippleClickable { onAction.invoke(HomeDetailAction.BackClicked) } + .size(24.dp), painter = painterResource(R.drawable.ic_chevron_left), contentDescription = "ic_chevron_left" ) } LazyVerticalGrid(columns = GridCells.Fixed(2)) { - itemsIndexed(listOf(1, 1, 1, 1, 1, 1)) { index, item -> - val isLastRow = index / 2 == 2 // 추후 하드코딩에서 변경 -// HomeSmallTicket( -// modifier = Modifier.padding( -// bottom = if (isLastRow) 0.dp else 16.dp -// ), -// buried = index / 2 == 0, -// step = index -// ) + itemsIndexed(data.detailItems.items) { index, item -> + val isLastRow = index / 2 == data.detailItems.items.lastIndex / 2 + HomeSmallTicket( + modifier = Modifier + .padding( + bottom = if (isLastRow) 0.dp else 16.dp + ) + .noRippleClickable { + onAction.invoke( + HomeDetailAction.CapsuleClicked(item.timeCapsuleId) + ) + }, + dDayCount = item.openedAt?.toDdayCount(), + createdAt = item.createdAt.toYearMonthDay(), + title = item.title, + imageUrl = item.mainImageUrl, + step = item.stage + ) } } } @@ -67,5 +126,8 @@ fun HomeDetailScreen(homeDetailType: HomeDetailType) { @Preview @Composable fun HomeDetailScreenPreview() { - HomeDetailScreen(homeDetailType = HomeDetailType.BEFORE_BURIED) + HomeDetailScreen( + data = HomeDetailData(), + onAction = {} + ) } \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailViewModel.kt b/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailViewModel.kt new file mode 100644 index 00000000..ab0b9604 --- /dev/null +++ b/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailViewModel.kt @@ -0,0 +1,158 @@ +package com.idiotfrogs.home.detail + +import androidx.compose.runtime.Immutable +import com.idiotfrogs.domain.usecase.timecapsule.GetMyTimeCapsuleUseCase +import com.idiotfrogs.home.detail.HomeDetailSideEffect.* +import com.idiotfrogs.home.home.addPage +import com.idiotfrogs.model.timecapsule.MyTimeCapsuleContent +import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus +import com.idiotfrogs.navigation.HomeDetailType +import com.idiotfrogs.util.base.BaseViewModel +import com.idiotfrogs.util.base.DataUiState +import com.idiotfrogs.util.paging.PaginationState +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import dagger.hilt.android.lifecycle.HiltViewModel +import org.orbitmvi.orbit.Container +import org.orbitmvi.orbit.viewmodel.container + +@HiltViewModel(assistedFactory = HomeDetailViewModel.Factory::class) +class HomeDetailViewModel @AssistedInject constructor( + @Assisted private val homeDetailType: HomeDetailType, + private val getMyTimeCapsuleUseCase: GetMyTimeCapsuleUseCase +) : BaseViewModel() { + override val container: Container = container( + initialState = HomeDetailUiState(), + onCreate = { fetchItem() } + ) + + override fun onAction(action: HomeDetailAction) { + when (action) { + is HomeDetailAction.CapsuleClicked -> intent { postSideEffect(NavigateToDetail(action.id)) } + HomeDetailAction.NextItemRequested -> loadMoreItem() + HomeDetailAction.BackClicked -> intent { postSideEffect(NavigateToBack) } + } + } + + private fun fetchItem() = intent { + intent { reduce { state.copy(isLoading = true) } } + + getMyTimeCapsuleUseCase( + status = when (homeDetailType) { + HomeDetailType.BURIED -> TimeCapsuleStatus.BURIED + HomeDetailType.BEFORE_BURIED -> TimeCapsuleStatus.BEFOREBURIED + }, + page = 0, + size = 10, + ).onSuccess { + intent { + reduce { + state.copy( + data = HomeDetailData( + detailItems = PaginationState().addPage(it) + ), + isLoading = false, + errorMessage = null, + ) + } + } + }.onFailure { + intent { + reduce { + state.copy( + isLoading = false, + errorMessage = it.message + ) + } + } + } + } + + private fun loadMoreItem() = intent { + val currentData = state.data ?: return@intent + val items = currentData.detailItems + + if (state.isLoading || !items.canLoadMore) return@intent + + val currentPage = items.currentPage + val nextPage = currentPage + 1 + + reduce { + state.copy( + data = currentData.copy( + detailItems = items.setLoadingMore(true), + ), + ) + } + + getMyTimeCapsuleUseCase( + status = when (homeDetailType) { + HomeDetailType.BURIED -> TimeCapsuleStatus.BURIED + HomeDetailType.BEFORE_BURIED -> TimeCapsuleStatus.BEFOREBURIED + }, + page = nextPage, + size = 10, + ).onSuccess { response -> + val latestData = state.data ?: return@onSuccess + val latestOpened = latestData.detailItems + val isCurrentRequest = latestOpened.currentPage == currentPage && + latestOpened.isLoadingMore + + if (!isCurrentRequest) return@onSuccess + + reduce { + state.copy( + data = latestData.copy( + detailItems = latestOpened.addPage(response), + ), + errorMessage = null, + ) + } + }.onFailure { error -> + val latestData = state.data ?: return@onFailure + val latestOpened = latestData.detailItems + val isCurrentRequest = latestOpened.currentPage == currentPage && + latestOpened.isLoadingMore + + if (!isCurrentRequest) return@onFailure + + reduce { + state.copy( + data = latestData.copy( + detailItems = latestOpened.setLoadingMore(false), + ), + errorMessage = error.message, + ) + } + } + } + + @AssistedFactory + interface Factory { + fun create(homeDetailType: HomeDetailType): HomeDetailViewModel + } +} + +@Immutable +data class HomeDetailUiState( + override val data: HomeDetailData? = null, + override val isLoading: Boolean = false, + override val errorMessage: String? = null, +) : DataUiState + +@Immutable +data class HomeDetailData( + val detailItems: PaginationState = PaginationState(), +) + +sealed interface HomeDetailAction { + data class CapsuleClicked(val id: Long) : HomeDetailAction + data object BackClicked : HomeDetailAction + data object NextItemRequested : HomeDetailAction +} + +sealed interface HomeDetailSideEffect { + data object NavigateToBack : HomeDetailSideEffect + data class NavigateToDetail(val id: Long) : HomeDetailSideEffect +} From e40366501be6c53c87ed04d525399dee2fd756a7 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Wed, 16 Sep 2026 16:32:28 +0900 Subject: [PATCH 15/31] =?UTF-8?q?:bug:=20::=20=EB=A6=AC=ED=94=84=EB=A0=88?= =?UTF-8?q?=EC=8B=9C=20=EC=9D=B4=ED=9B=84=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EC=95=88=20=EB=B6=88=EB=9F=AC=EC=98=A4=EB=8A=94=20=EB=B2=84?= =?UTF-8?q?=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/idiotfrogs/home/home/HomeViewModel.kt | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt index 6a998f97..650a4365 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt @@ -207,22 +207,6 @@ class HomeViewModel @Inject constructor( } } - private fun refreshOpened() { - intent { - val homeData = state.data - val seasonBanner = getSeasonBannerUseCase.invoke() - reduce { - state.copy( - data = homeData?.copy( - opened = PaginationState(), - seasonBanner = seasonBanner.getOrNull() - ) - ) - } - } - loadNextOpened() - } - private fun requestCollaborator(body: PendingCollaboratorsRequest) = safeLaunch { intent { reduce { state.copy(isLoading = true) } } @@ -247,7 +231,7 @@ class HomeViewModel @Inject constructor( HomeAction.RefreshHome -> fetchHome() is HomeAction.HomeDetailClicked -> postSideEffect(NavigateToHomeDetail(action.homeDetailType)) HomeAction.NextOpenedPageRequested -> loadNextOpened() - HomeAction.RefreshOpened -> refreshOpened() + HomeAction.RefreshOpened -> fetchOpened() } } } From e6ea7c4502878a1d8ebf7414c623bf2a01d39509 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Wed, 16 Sep 2026 16:57:00 +0900 Subject: [PATCH 16/31] =?UTF-8?q?:sparkles:=20::=20=EA=B3=84=EC=A0=88=20?= =?UTF-8?q?=ED=91=B8=EC=8B=9C=20=EB=B0=8F=20=ED=99=88=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=20=EA=B0=B1=EC=8B=A0=20=ED=8A=B8=EB=A6=AC=EA=B1=B0=20=EC=9E=91?= =?UTF-8?q?=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/idiotfrogs/memoryseal/MainActivity.kt | 9 +++++++-- .../main/java/com/idiotfrogs/memoryseal/MainViewModel.kt | 2 ++ .../src/main/java/com/idiotfrogs/navigation/Routes.kt | 2 +- .../src/main/java/com/idiotfrogs/detail/DetailScreen.kt | 6 +++++- .../main/java/com/idiotfrogs/detail/DetailViewModel.kt | 6 +++++- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt b/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt index 8c24840c..11444383 100644 --- a/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt +++ b/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt @@ -100,7 +100,7 @@ class MainActivity : ComponentActivity() { navigator.navigate(Routes.Friend(event.capsuleId)) } is MainNavigationEvent.NavigateToDetail -> { - navigator.navigate(Routes.Detail(event.capsuleId)) + navigator.navigate(Routes.Detail(event.capsuleId, refreshHome = event.refreshHome)) event.toastMessage?.let { message -> Toast.makeText( this@MainActivity, @@ -140,7 +140,12 @@ class MainActivity : ComponentActivity() { entry { CreateRoute() } entry { ProfileRoute() } entry { EditProfileRoute() } - entry { DetailRoute(capsuleId = it.id) } + entry { + DetailRoute( + capsuleId = it.id, + refreshHome = it.refreshHome + ) + } entry { MessageRoute(capsuleId = it.id) } entry { PreviewRoute(capsuleId = it.id) } entry { MemoryRoute(capsuleId = it.id) } diff --git a/app/src/main/java/com/idiotfrogs/memoryseal/MainViewModel.kt b/app/src/main/java/com/idiotfrogs/memoryseal/MainViewModel.kt index 1701dcf4..b8f36665 100644 --- a/app/src/main/java/com/idiotfrogs/memoryseal/MainViewModel.kt +++ b/app/src/main/java/com/idiotfrogs/memoryseal/MainViewModel.kt @@ -56,6 +56,7 @@ class MainViewModel @Inject constructor( "member" -> MainNavigationEvent.NavigateToFriend(id) // 오픈도 detail에서 열람 이력 확인 후 애니메이션 노출 여부 결정 "detail", "open" -> MainNavigationEvent.NavigateToDetail(id) + "season" -> MainNavigationEvent.NavigateToDetail(id, refreshHome = true) else -> return } @@ -133,6 +134,7 @@ sealed interface MainNavigationEvent { data class NavigateToDetail( val capsuleId: Long, val toastMessage: String? = null, + val refreshHome: Boolean = false ) : MainNavigationEvent data class NavigateToMemory(val capsuleId: Long) : MainNavigationEvent } diff --git a/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt b/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt index 5e1779df..78f73ac4 100644 --- a/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt +++ b/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt @@ -25,7 +25,7 @@ sealed interface Routes: NavKey { @Serializable data class Friend(val id: Long) : Routes @Serializable - data class Detail(val id: Long) : Routes + data class Detail(val id: Long, val refreshHome: Boolean = false) : Routes @Serializable data class Message(val id: Long) : Routes @Serializable diff --git a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt index 5f0eacba..128bdc62 100644 --- a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt +++ b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt @@ -82,7 +82,11 @@ import kotlin.time.ExperimentalTime @Composable fun DetailRoute( capsuleId: Long, - viewModel: DetailViewModel = hiltViewModel(key = capsuleId.toString()) { it.create(capsuleId) }, + refreshHome: Boolean, + viewModel: DetailViewModel = + hiltViewModel( + key = capsuleId.toString() + ) { it.create(capsuleId, refreshHome) }, ) { val navigator = LocalComposeMSNavigator.current val uiState by viewModel.collectAsState() diff --git a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt index 096de277..865031b2 100644 --- a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt +++ b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt @@ -24,6 +24,7 @@ import org.orbitmvi.orbit.viewmodel.container @HiltViewModel(assistedFactory = DetailViewModel.Factory::class) class DetailViewModel @AssistedInject constructor( @Assisted private val capsuleId: Long, + @Assisted private val refreshHome: Boolean, private val getTimeCapsuleUseCase: GetTimeCapsuleUseCase, private val getTimeCapsuleCollaboratorsUseCase: GetTimeCapsuleCollaboratorsUseCase, private val buryTimeCapsuleUseCase: BuryTimeCapsuleUseCase, @@ -65,6 +66,8 @@ class DetailViewModel @AssistedInject constructor( if (capsule?.animationShown == false && capsule.timeCapsuleStatus == TimeCapsuleStatus.OPENED) { postSideEffect(DetailSideEffect.NavigateToOpen(capsuleId)) } else { + // 만약 디테일 로드 이후 홈이 리프레시 되어야 한다면 + if (refreshHome) RefreshSideEffect.tryEmit(RefreshEvent.Home) reduce { state.copy( data = TimeCapsuleData( @@ -89,6 +92,7 @@ class DetailViewModel @AssistedInject constructor( capsuleId = capsuleId, body = BuryTimeCapsuleRequest(openedAt), ).onSuccess { response -> + RefreshSideEffect.tryEmit(RefreshEvent.Home) intent { reduce { val currentData = state.data ?: TimeCapsuleData() @@ -132,7 +136,7 @@ class DetailViewModel @AssistedInject constructor( @AssistedFactory interface Factory { - fun create(capsuleId: Long): DetailViewModel + fun create(capsuleId: Long, refreshHome: Boolean): DetailViewModel } } From 6a9b4526a6dc80b010ca62f9b317c04232e5aa14 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Wed, 16 Sep 2026 17:39:08 +0900 Subject: [PATCH 17/31] =?UTF-8?q?:sparkles:=20::=20=EC=97=B4=EB=A6=B0=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=20stage=20=EA=B0=92=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20=EA=B3=84=EC=A0=88=20=EB=B0=B0=EB=84=88=20API=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=EA=B0=92=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/home/SeasonBannerResponse.kt | 2 ++ .../timecapsule/TimeCapsuleUnopenedContent.kt | 3 +- .../home/component/HomeOpenedBanner.kt | 4 +-- .../home/component/HomeRemindBanner.kt | 31 +++++++------------ .../com/idiotfrogs/home/home/HomeScreen.kt | 3 +- .../com/idiotfrogs/home/home/HomeViewModel.kt | 1 - 6 files changed, 19 insertions(+), 25 deletions(-) diff --git a/core/model/src/main/java/com/idiotfrogs/model/home/SeasonBannerResponse.kt b/core/model/src/main/java/com/idiotfrogs/model/home/SeasonBannerResponse.kt index 85939f1e..e2859c83 100644 --- a/core/model/src/main/java/com/idiotfrogs/model/home/SeasonBannerResponse.kt +++ b/core/model/src/main/java/com/idiotfrogs/model/home/SeasonBannerResponse.kt @@ -6,6 +6,8 @@ import kotlinx.serialization.Serializable @Serializable data class SeasonBannerResponse( val content: String = "", + val title: String = "", + val mainImageUrl: String = "", val season: Season? = null, val capsuleId: Long? = null, ) diff --git a/core/model/src/main/java/com/idiotfrogs/model/timecapsule/TimeCapsuleUnopenedContent.kt b/core/model/src/main/java/com/idiotfrogs/model/timecapsule/TimeCapsuleUnopenedContent.kt index 4cc71ef7..ea7817b2 100644 --- a/core/model/src/main/java/com/idiotfrogs/model/timecapsule/TimeCapsuleUnopenedContent.kt +++ b/core/model/src/main/java/com/idiotfrogs/model/timecapsule/TimeCapsuleUnopenedContent.kt @@ -8,5 +8,6 @@ data class TimeCapsuleUnopenedContent( val timeCapsuleId: Long, val title: String, val openedAt: LocalDate, - val mainImageUrl: String + val mainImageUrl: String, + val stage: Int ) \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt index c146e618..d9007682 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt @@ -109,7 +109,7 @@ fun HomeOpenedBanner( title = unopenedList.first().title, openedAt = unopenedList.first().openedAt.toYearMonthDay(), imageUrl = unopenedList.first().mainImageUrl, - step = 1, + step = unopenedList.first().stage, ) Spacer(modifier = Modifier.height(32.dp)) return @@ -131,7 +131,7 @@ fun HomeOpenedBanner( title = unopenedList[page].title, openedAt = unopenedList[page].openedAt.toYearMonthDay(), imageUrl = unopenedList[page].mainImageUrl, - step = 1, + step = unopenedList[page].stage, ) } } diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt index 53fcfdfc..c908d846 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeRemindBanner.kt @@ -21,23 +21,15 @@ import androidx.compose.ui.unit.dp import com.idiotfrogs.designsystem.component.MSText import com.idiotfrogs.designsystem.theme.MSTheme import com.idiotfrogs.designsystem.util.wavyStroke -import com.idiotfrogs.model.home.Season import com.idiotfrogs.resource.R - -private fun Season.getSeasonText(): String { - return when (this) { - Season.SPRING -> "봄" - Season.SUMMER -> "여름" - Season.FALL -> "가을" - Season.WINTER -> "겨울" - } -} +import com.skydoves.landscapist.glide.GlideImage @Composable fun HomeRemindBanner( modifier: Modifier = Modifier, - season: Season, - content: String + title: String, + content: String, + mainImageUrl: String, ) { Column( modifier = modifier @@ -64,13 +56,13 @@ fun HomeRemindBanner( verticalArrangement = Arrangement.spacedBy(10.dp) ) { MSText( - text = "지난 ${season.getSeasonText()} 우리", + text = content, fontWeight = FontWeight.Bold, fontSize = 20.dp, color = MSTheme.color.greyG5 ) MSText( - text = content, + text = title, fontWeight = FontWeight.Medium, fontSize = 16.dp, color = MSTheme.color.greyG5 @@ -84,11 +76,9 @@ fun HomeRemindBanner( clipContent = true ) ) { - Image( + GlideImage( modifier = Modifier.fillMaxSize(), - painter = painterResource(R.drawable.img_sample), - contentScale = ContentScale.Crop, - contentDescription = "img_ticket" + imageModel = { mainImageUrl.takeIf { it.isNotEmpty() } ?: R.drawable.img_sample }, ) } } @@ -107,7 +97,8 @@ fun HomeRemindBanner( @Composable private fun HomeRemindBannerPreview() { HomeRemindBanner( - season = Season.FALL, - content = "내용내용내용내용내용" + title = "제목제목제목제목", + content = "내용내용내용내용내용", + mainImageUrl = "" ) } \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt index c3527640..17bde9ff 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt @@ -203,7 +203,8 @@ fun HomeScreen( onAction.invoke(HomeAction.TimeCapsuleClicked(it)) } }, - season = data.seasonBanner.season ?: return@maxLineItem, + title = data.seasonBanner.title, + mainImageUrl = data.seasonBanner.mainImageUrl, content = data.seasonBanner.content ) } diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt index 650a4365..eebb42d7 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt @@ -95,7 +95,6 @@ class HomeViewModel @Inject constructor( if (results.any { it.isFailure }) { val errorMessage = results.first { it.isFailure }.exceptionOrNull()?.message - Log.d("TTT", errorMessage.toString()) reduce { state.copy(isLoading = false, errorMessage = errorMessage) } } else { // 비동기로 여러 API 호출하므로 실행 시점에 데이터 있는지 파악 From f40d100673122963cec08431ccd36170dce7d3d6 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Wed, 16 Sep 2026 17:49:00 +0900 Subject: [PATCH 18/31] =?UTF-8?q?:sparkles:=20::=20=EC=8B=9C=EC=A6=8C=20?= =?UTF-8?q?=EB=B0=B0=EB=84=88=20=EA=B2=80=EC=A6=9D=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/idiotfrogs/model/home/SeasonBannerResponse.kt | 5 ++++- .../src/main/java/com/idiotfrogs/home/home/HomeScreen.kt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/model/src/main/java/com/idiotfrogs/model/home/SeasonBannerResponse.kt b/core/model/src/main/java/com/idiotfrogs/model/home/SeasonBannerResponse.kt index e2859c83..c0aae308 100644 --- a/core/model/src/main/java/com/idiotfrogs/model/home/SeasonBannerResponse.kt +++ b/core/model/src/main/java/com/idiotfrogs/model/home/SeasonBannerResponse.kt @@ -10,6 +10,9 @@ data class SeasonBannerResponse( val mainImageUrl: String = "", val season: Season? = null, val capsuleId: Long? = null, -) +) { + val isValid: Boolean + get() = content.isNotBlank() && title.isNotBlank() && mainImageUrl.isNotBlank() && capsuleId != null +} enum class Season { SPRING, SUMMER, FALL, WINTER } \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt index 17bde9ff..9ec7a407 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt @@ -190,7 +190,7 @@ fun HomeScreen( ) } } - if (data.seasonBanner != null) { + if (data.seasonBanner != null && data.seasonBanner.isValid) { maxLineItem { HomeRemindBanner( modifier = Modifier From deb659f4ab048f3aedb7a3fbf8cfed1be31cc1b5 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Wed, 16 Sep 2026 19:54:23 +0900 Subject: [PATCH 19/31] =?UTF-8?q?:bug:=20::=20=EB=94=94=ED=85=8C=EC=9D=BC?= =?UTF-8?q?=20=ED=99=94=EB=A9=B4=EC=97=90=EC=84=9C=20=EC=98=A4=ED=94=88=20?= =?UTF-8?q?=EC=95=A0=EB=8B=88=EB=A9=94=EC=9D=B4=EC=85=98=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EC=8B=9C=20=EB=B0=B1=EC=8A=A4=ED=83=9D=20=EB=82=A8?= =?UTF-8?q?=EA=B8=B0=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt index 128bdc62..485752db 100644 --- a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt +++ b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt @@ -111,7 +111,7 @@ fun DetailRoute( ) ) is DetailSideEffect.NavigateToWatering -> navigator.navigate(Routes.Watering(event.id)) - is DetailSideEffect.NavigateToOpen -> navigator.navigate(Routes.Open(event.id)) + is DetailSideEffect.NavigateToOpen -> navigator.replace(Routes.Open(event.id)) DetailSideEffect.ShowToast -> showToast = true } } From 320063c33cc09be18776c2c00d5b7699e40c1868 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Wed, 16 Sep 2026 19:57:16 +0900 Subject: [PATCH 20/31] =?UTF-8?q?:bug:=20::=20=EC=98=A4=ED=94=88=20?= =?UTF-8?q?=EC=95=A0=EB=8B=88=EB=A9=94=EC=9D=B4=EC=85=98=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8=20=ED=9B=84=20=ED=99=88=20=EA=B0=B1=EC=8B=A0=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/idiotfrogs/detail/DetailViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt index 865031b2..aad423ec 100644 --- a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt +++ b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt @@ -65,6 +65,7 @@ class DetailViewModel @AssistedInject constructor( // 반드시 애니메이션 재생 여부와 오픈 여부를 함께 검사해야 한다 if (capsule?.animationShown == false && capsule.timeCapsuleStatus == TimeCapsuleStatus.OPENED) { postSideEffect(DetailSideEffect.NavigateToOpen(capsuleId)) + RefreshSideEffect.tryEmit(RefreshEvent.Home) } else { // 만약 디테일 로드 이후 홈이 리프레시 되어야 한다면 if (refreshHome) RefreshSideEffect.tryEmit(RefreshEvent.Home) From 862c56c9473b17dad4a56a197da2799851f26408 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Thu, 17 Sep 2026 08:58:08 +0900 Subject: [PATCH 21/31] =?UTF-8?q?:sparkles:=20::=20step5=20=EA=B0=80?= =?UTF-8?q?=EC=9D=B4=EB=93=9C=20=EB=86=92=EC=9D=B4=20=EA=B0=92=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/idiotfrogs/home/component/HomeTicket.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt index 0468cf4b..48a7675a 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeTicket.kt @@ -46,7 +46,7 @@ enum class DefaultGuideItem(val imgRes: Int, val bigHeight: Dp, val midHeight: D STEP_2(imgRes = R.drawable.img_ticket_guide_step2, bigHeight = 328.dp, midHeight = 302.dp), STEP_3(imgRes = R.drawable.img_ticket_guide_step3, bigHeight = 328.dp, midHeight = 302.dp), STEP_4(imgRes = R.drawable.img_ticket_guide_step4, bigHeight = 328.dp, midHeight = 302.dp), - STEP_5(imgRes = R.drawable.img_ticket_guide_step5, bigHeight = 442.dp, midHeight = 316.dp) + STEP_5(imgRes = R.drawable.img_ticket_guide_step5, bigHeight = 442.dp, midHeight = 390.dp) } enum class SmallGuideItem(val imgRes: Int, val height: Dp) { From 8ad4abc19638c64303b7545fc41edd927b372834 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Thu, 17 Sep 2026 08:58:39 +0900 Subject: [PATCH 22/31] =?UTF-8?q?:sparkles:=20::=20=ED=83=88=ED=87=B4=20?= =?UTF-8?q?=EB=B0=94=ED=85=80=20=EC=8B=9C=ED=8A=B8=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/MSActionContainer.kt | 121 ++++++++++++++++++ .../profile/profile/ProfileScreen.kt | 48 ++++--- 2 files changed, 150 insertions(+), 19 deletions(-) diff --git a/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSActionContainer.kt b/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSActionContainer.kt index fad4d5c7..39e0fbaa 100644 --- a/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSActionContainer.kt +++ b/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSActionContainer.kt @@ -16,6 +16,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.idiotfrogs.designsystem.component.button.MSButton @@ -120,4 +121,124 @@ fun MSActionContainer( } } } +} + +@Composable +fun MSActionContainer( + title: String, + subtitle: String, + content: String, + hint: String, + textFieldState: TextFieldState, + primaryButtonText: String, + primaryWavyStrokeColor: Color, + secondaryWavyStrokeColor: Color, + onPrimaryClick: () -> Unit, + onSecondaryClick: () -> Unit, + modifier: Modifier = Modifier, + primaryButtonEnabled: Boolean = textFieldState.text.isNotEmpty(), + secondaryButtonText: String= "취소", + primaryButtonWeight: Float = 1f, + secondaryButtonWeight: Float = 1f, + focusedBorderColor: Color = MSTheme.color.primaryNormal, + unfocusedBorderColor: Color = MSTheme.color.greyG1, + primaryButtonColors: ButtonColors = ButtonDefaults.buttonColors( + containerColor = MSTheme.color.primaryNormal, + disabledContainerColor = MSTheme.color.primaryLight, + ), + primaryPressColors: ButtonColors = ButtonDefaults.buttonColors( + containerColor = MSTheme.color.primaryDark, + disabledContainerColor = MSTheme.color.primaryLight, + ), + primaryTextColor: Color = MSTheme.color.white, + secondaryButtonColors: ButtonColors = ButtonDefaults.buttonColors( + containerColor = MSTheme.color.greyG1, + disabledContainerColor = MSTheme.color.greyG1, + ), + secondaryPressColors: ButtonColors = ButtonDefaults.buttonColors( + containerColor = MSTheme.color.greyG1, + disabledContainerColor = MSTheme.color.greyG1, + ), + secondaryTextColor: Color = MSTheme.color.greyG5, +) { + Column( + modifier = modifier + .fillMaxWidth() + .background( + color = MSTheme.color.white, + shape = RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp), + ) + .padding(horizontal = 20.dp, vertical = 24.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + MSText( + modifier = Modifier.fillMaxWidth(), + text = title, + fontSize = 20.dp, + fontWeight = FontWeight.Bold, + color = MSTheme.color.greyG5 + ) + Spacer(modifier = Modifier.height(8.dp)) + MSText( + modifier = Modifier.fillMaxWidth(), + text = subtitle, + fontSize = 16.dp, + fontWeight = FontWeight.Normal, + color = MSTheme.color.greyG5, + ) + Spacer(modifier = Modifier.height(8.dp)) + MSText( + modifier = Modifier.fillMaxWidth(), + text = content, + fontSize = 14.dp, + fontWeight = FontWeight.Normal, + color = MSTheme.color.greyG3, + ) + Spacer(modifier = Modifier.height(24.dp)) + MSTextField( + modifier = Modifier.fillMaxWidth(), + textFieldState = textFieldState, + hint = hint, + focusedBorderColor = focusedBorderColor, + unfocusedBorderColor = unfocusedBorderColor, + ) + Spacer(modifier = Modifier.height(24.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + MSButton( + modifier = Modifier + .weight(secondaryButtonWeight) + .height(48.dp), + onClick = onSecondaryClick, + colors = secondaryButtonColors, + pressColors = secondaryPressColors, + wavyStrokeColor = secondaryWavyStrokeColor, + ) { + MSText( + text = secondaryButtonText, + fontSize = 16.dp, + color = secondaryTextColor, + ) + } + MSButton( + modifier = Modifier + .weight(primaryButtonWeight) + .height(48.dp), + enabled = primaryButtonEnabled, + onClick = onPrimaryClick, + colors = primaryButtonColors, + pressColors = primaryPressColors, + wavyStrokeColor = primaryWavyStrokeColor, + ) { + MSText( + text = primaryButtonText, + fontSize = 16.dp, + color = primaryTextColor, + ) + } + } + } } \ No newline at end of file diff --git a/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt b/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt index a16cc394..6dca4af0 100644 --- a/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt +++ b/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt @@ -15,6 +15,8 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.foundation.text.input.rememberTextFieldState +import androidx.compose.material3.ButtonDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -30,6 +32,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import com.idiotfrogs.designsystem.component.MSActionContainer import com.idiotfrogs.designsystem.component.MSLoadingOverlay import com.idiotfrogs.designsystem.component.MSText import com.idiotfrogs.designsystem.component.MSTitleDialog @@ -84,7 +87,9 @@ fun ProfileScreen( onAction: (ProfileAction) -> Unit ) { var showLogoutDialog by remember { mutableStateOf(false) } - var showWithdrawDialog by remember { mutableStateOf(false) } + var showWithdrawSheet by remember { mutableStateOf(false) } + + val textFieldState = rememberTextFieldState() if (showLogoutDialog) { MSTitleDialog( @@ -109,26 +114,31 @@ fun ProfileScreen( ) } - if (showWithdrawDialog) { - MSTitleDialog( + if (showWithdrawSheet) { + MSActionContainer( title = "회원탈퇴", - confirmText = "탈퇴", - cancelText = "취소", - onConfirm = { - showWithdrawDialog = false + subtitle = "", + content = "", + textFieldState = textFieldState, + hint = "", + primaryButtonEnabled = textFieldState.text.isNotEmpty(), + primaryButtonText = "탈퇴", + primaryWavyStrokeColor = if (textFieldState.text.isNotEmpty()) { + MSTheme.color.red + } else { + Color(0xFFF3BBBB) + }, + primaryButtonColors = ButtonDefaults.buttonColors( + containerColor = MSTheme.color.red, + disabledContainerColor = Color(0xFFF3BBBB) + ), + secondaryWavyStrokeColor = MSTheme.color.greyG1, + secondaryButtonText = "취소", + onPrimaryClick = { + showWithdrawSheet = false onAction.invoke(ProfileAction.WithdrawConfirmed) }, - onCancel = { showWithdrawDialog = false }, - content = { - Spacer(modifier = Modifier.height(8.dp)) - MSText( - text = "메실 회원을 탈퇴하시겠습니까?\n티켓에 저장된 내용은 삭제되지 않습니다.", - fontWeight = FontWeight.Normal, - fontSize = 16.dp, - color = MSTheme.color.greyG5 - ) - Spacer(modifier = Modifier.height(24.dp)) - } + onSecondaryClick = { showWithdrawSheet = false } ) } @@ -232,7 +242,7 @@ fun ProfileScreen( modifier = Modifier .fillMaxWidth() .height(56.dp) - .noRippleClickable { showWithdrawDialog = true }, + .noRippleClickable { showWithdrawSheet = true }, horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { From 51bb9b01fef0c6134238ac2e96d3c086e9798fbe Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Thu, 17 Sep 2026 09:43:31 +0900 Subject: [PATCH 23/31] =?UTF-8?q?:bug:=20::=20=ED=83=88=ED=87=B4=20?= =?UTF-8?q?=EB=B0=94=ED=85=80=20=EC=8B=9C=ED=8A=B8=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/ProfileWithdrawBottomSheet.kt | 61 +++++++++++++++++++ .../profile/profile/ProfileScreen.kt | 43 +++++-------- 2 files changed, 76 insertions(+), 28 deletions(-) create mode 100644 feature/profile/src/main/java/com/idiotfrogs/profile/component/ProfileWithdrawBottomSheet.kt diff --git a/feature/profile/src/main/java/com/idiotfrogs/profile/component/ProfileWithdrawBottomSheet.kt b/feature/profile/src/main/java/com/idiotfrogs/profile/component/ProfileWithdrawBottomSheet.kt new file mode 100644 index 00000000..ab1438f2 --- /dev/null +++ b/feature/profile/src/main/java/com/idiotfrogs/profile/component/ProfileWithdrawBottomSheet.kt @@ -0,0 +1,61 @@ +package com.idiotfrogs.profile.component + +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.text.input.TextFieldState +import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd +import androidx.compose.material3.ButtonDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.graphics.Color +import com.idiotfrogs.designsystem.component.MSActionContainer +import com.idiotfrogs.designsystem.theme.MSTheme + +@Composable +fun BoxScope.ProfileWithdrawBottomSheet( + isShow: Boolean, + textFieldState: TextFieldState, + onWithdraw: () -> Unit, + onCancel: () -> Unit, +) { + val focusRequester = remember { FocusRequester() } + + LaunchedEffect(isShow) { + if (isShow) { + textFieldState.setTextAndPlaceCursorAtEnd("") + focusRequester.requestFocus() + } + } + + if (isShow) { + MSActionContainer( + modifier = Modifier + .align(Alignment.BottomCenter) + .focusRequester(focusRequester), + title = "회원탈퇴", + subtitle = "메실 회원을 탈퇴를 위해 \"회원탈퇴\"를 입력해주세요.", + content = "티켓에 저장된 내용은 삭제되지 않습니다.", + textFieldState = textFieldState, + hint = "", + primaryButtonEnabled = textFieldState.text == "회원탈퇴", + primaryButtonText = "탈퇴", + primaryWavyStrokeColor = if (textFieldState.text == "회원탈퇴") { + MSTheme.color.red + } else { + Color(0xFFF3BBBB) + }, + primaryButtonColors = ButtonDefaults.buttonColors( + containerColor = MSTheme.color.red, + disabledContainerColor = Color(0xFFF3BBBB) + ), + secondaryWavyStrokeColor = MSTheme.color.greyG1, + secondaryButtonText = "취소", + onPrimaryClick = onWithdraw, + onSecondaryClick = onCancel + ) + } +} \ No newline at end of file diff --git a/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt b/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt index 6dca4af0..ce6e81a9 100644 --- a/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt +++ b/feature/profile/src/main/java/com/idiotfrogs/profile/profile/ProfileScreen.kt @@ -33,6 +33,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import com.idiotfrogs.designsystem.component.MSActionContainer +import com.idiotfrogs.designsystem.component.MSDim import com.idiotfrogs.designsystem.component.MSLoadingOverlay import com.idiotfrogs.designsystem.component.MSText import com.idiotfrogs.designsystem.component.MSTitleDialog @@ -45,6 +46,7 @@ import com.idiotfrogs.navigation.LocalComposeMSNavigator import com.idiotfrogs.navigation.Routes import com.idiotfrogs.profile.component.ProfileCard import com.idiotfrogs.profile.component.ProfileHeader +import com.idiotfrogs.profile.component.ProfileWithdrawBottomSheet import com.idiotfrogs.resource.R import org.orbitmvi.orbit.compose.collectAsState import org.orbitmvi.orbit.compose.collectSideEffect @@ -114,34 +116,6 @@ fun ProfileScreen( ) } - if (showWithdrawSheet) { - MSActionContainer( - title = "회원탈퇴", - subtitle = "", - content = "", - textFieldState = textFieldState, - hint = "", - primaryButtonEnabled = textFieldState.text.isNotEmpty(), - primaryButtonText = "탈퇴", - primaryWavyStrokeColor = if (textFieldState.text.isNotEmpty()) { - MSTheme.color.red - } else { - Color(0xFFF3BBBB) - }, - primaryButtonColors = ButtonDefaults.buttonColors( - containerColor = MSTheme.color.red, - disabledContainerColor = Color(0xFFF3BBBB) - ), - secondaryWavyStrokeColor = MSTheme.color.greyG1, - secondaryButtonText = "취소", - onPrimaryClick = { - showWithdrawSheet = false - onAction.invoke(ProfileAction.WithdrawConfirmed) - }, - onSecondaryClick = { showWithdrawSheet = false } - ) - } - Box( modifier = Modifier .fillMaxSize() @@ -260,6 +234,19 @@ fun ProfileScreen( } } } + MSDim( + visible = showWithdrawSheet, + onDismiss = { showWithdrawSheet = false } + ) + ProfileWithdrawBottomSheet( + isShow = showWithdrawSheet, + textFieldState = textFieldState, + onCancel = { showWithdrawSheet = false }, + onWithdraw = { + showWithdrawSheet = false + onAction.invoke(ProfileAction.WithdrawConfirmed) + }, + ) } } From 4db6c66ff126d2d5a5c3e0747952764fed9c1a38 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Thu, 17 Sep 2026 09:52:13 +0900 Subject: [PATCH 24/31] =?UTF-8?q?:memo:=20::=20stability=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stability/designsystem-debug.stability | 32 +++++++++++++- .../stability/designsystem-release.stability | 32 +++++++++++++- .../detail/stability/detail-debug.stability | 3 +- .../detail/stability/detail-release.stability | 3 +- feature/home/stability/home-debug.stability | 43 +++++++++---------- feature/home/stability/home-release.stability | 43 +++++++++---------- .../profile/stability/profile-debug.stability | 10 +++++ .../stability/profile-release.stability | 10 +++++ 8 files changed, 126 insertions(+), 50 deletions(-) diff --git a/core/designsystem/stability/designsystem-debug.stability b/core/designsystem/stability/designsystem-debug.stability index e19a735f..81a81737 100644 --- a/core/designsystem/stability/designsystem-debug.stability +++ b/core/designsystem/stability/designsystem-debug.stability @@ -45,6 +45,35 @@ public fun com.idiotfrogs.designsystem.component.MSActionContainer(title: kotlin - secondaryPressColors: STABLE (marked @Stable or @Immutable) - secondaryTextColor: STABLE (marked @Stable or @Immutable) +@Composable +public fun com.idiotfrogs.designsystem.component.MSActionContainer(title: kotlin.String, subtitle: kotlin.String, content: kotlin.String, hint: kotlin.String, textFieldState: androidx.compose.foundation.text.input.TextFieldState, primaryButtonText: kotlin.String, primaryWavyStrokeColor: androidx.compose.ui.graphics.Color, secondaryWavyStrokeColor: androidx.compose.ui.graphics.Color, onPrimaryClick: kotlin.Function0, onSecondaryClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier, primaryButtonEnabled: kotlin.Boolean, secondaryButtonText: kotlin.String, primaryButtonWeight: kotlin.Float, secondaryButtonWeight: kotlin.Float, focusedBorderColor: androidx.compose.ui.graphics.Color, unfocusedBorderColor: androidx.compose.ui.graphics.Color, primaryButtonColors: androidx.compose.material3.ButtonColors, primaryPressColors: androidx.compose.material3.ButtonColors, primaryTextColor: androidx.compose.ui.graphics.Color, secondaryButtonColors: androidx.compose.material3.ButtonColors, secondaryPressColors: androidx.compose.material3.ButtonColors, secondaryTextColor: androidx.compose.ui.graphics.Color): kotlin.Unit + skippable: true + restartable: true + params: + - title: STABLE (String is immutable) + - subtitle: STABLE (String is immutable) + - content: STABLE (String is immutable) + - hint: STABLE (String is immutable) + - textFieldState: STABLE (marked @Stable or @Immutable) + - primaryButtonText: STABLE (String is immutable) + - primaryWavyStrokeColor: STABLE (marked @Stable or @Immutable) + - secondaryWavyStrokeColor: STABLE (marked @Stable or @Immutable) + - onPrimaryClick: STABLE (function type) + - onSecondaryClick: STABLE (function type) + - modifier: STABLE (marked @Stable or @Immutable) + - primaryButtonEnabled: STABLE (primitive type) + - secondaryButtonText: STABLE (String is immutable) + - primaryButtonWeight: STABLE (primitive type) + - secondaryButtonWeight: STABLE (primitive type) + - focusedBorderColor: STABLE (marked @Stable or @Immutable) + - unfocusedBorderColor: STABLE (marked @Stable or @Immutable) + - primaryButtonColors: STABLE (marked @Stable or @Immutable) + - primaryPressColors: STABLE (marked @Stable or @Immutable) + - primaryTextColor: STABLE (marked @Stable or @Immutable) + - secondaryButtonColors: STABLE (marked @Stable or @Immutable) + - secondaryPressColors: STABLE (marked @Stable or @Immutable) + - secondaryTextColor: STABLE (marked @Stable or @Immutable) + @Composable public fun com.idiotfrogs.designsystem.component.MSAnnotatedText(text: androidx.compose.ui.text.AnnotatedString, modifier: androidx.compose.ui.Modifier, fontSize: androidx.compose.ui.unit.Dp, color: androidx.compose.ui.graphics.Color, fontFamily: androidx.compose.ui.text.font.FontFamily, fontWeight: androidx.compose.ui.text.font.FontWeight, letterSpacing: androidx.compose.ui.unit.TextUnit, textDecoration: androidx.compose.ui.text.style.TextDecoration?, textAlign: androidx.compose.ui.text.style.TextAlign?, lineHeight: androidx.compose.ui.unit.TextUnit, overflow: androidx.compose.ui.text.style.TextOverflow, softWrap: kotlin.Boolean, maxLines: kotlin.Int, minLines: kotlin.Int, style: androidx.compose.ui.text.TextStyle): kotlin.Unit skippable: true @@ -116,10 +145,11 @@ public fun com.idiotfrogs.designsystem.component.MSDialog(title: kotlin.String, - cancelTextColor: STABLE (marked @Stable or @Immutable) @Composable -public fun com.idiotfrogs.designsystem.component.MSDim(visible: kotlin.Boolean, onDismiss: kotlin.Function0, color: androidx.compose.ui.graphics.Color, animationSpec: androidx.compose.animation.core.FiniteAnimationSpec): kotlin.Unit +public fun com.idiotfrogs.designsystem.component.MSDim(modifier: androidx.compose.ui.Modifier, visible: kotlin.Boolean, onDismiss: kotlin.Function0, color: androidx.compose.ui.graphics.Color, animationSpec: androidx.compose.animation.core.FiniteAnimationSpec): kotlin.Unit skippable: false restartable: true params: + - modifier: STABLE (marked @Stable or @Immutable) - visible: STABLE (primitive type) - onDismiss: STABLE (function type) - color: STABLE (marked @Stable or @Immutable) diff --git a/core/designsystem/stability/designsystem-release.stability b/core/designsystem/stability/designsystem-release.stability index e19a735f..81a81737 100644 --- a/core/designsystem/stability/designsystem-release.stability +++ b/core/designsystem/stability/designsystem-release.stability @@ -45,6 +45,35 @@ public fun com.idiotfrogs.designsystem.component.MSActionContainer(title: kotlin - secondaryPressColors: STABLE (marked @Stable or @Immutable) - secondaryTextColor: STABLE (marked @Stable or @Immutable) +@Composable +public fun com.idiotfrogs.designsystem.component.MSActionContainer(title: kotlin.String, subtitle: kotlin.String, content: kotlin.String, hint: kotlin.String, textFieldState: androidx.compose.foundation.text.input.TextFieldState, primaryButtonText: kotlin.String, primaryWavyStrokeColor: androidx.compose.ui.graphics.Color, secondaryWavyStrokeColor: androidx.compose.ui.graphics.Color, onPrimaryClick: kotlin.Function0, onSecondaryClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier, primaryButtonEnabled: kotlin.Boolean, secondaryButtonText: kotlin.String, primaryButtonWeight: kotlin.Float, secondaryButtonWeight: kotlin.Float, focusedBorderColor: androidx.compose.ui.graphics.Color, unfocusedBorderColor: androidx.compose.ui.graphics.Color, primaryButtonColors: androidx.compose.material3.ButtonColors, primaryPressColors: androidx.compose.material3.ButtonColors, primaryTextColor: androidx.compose.ui.graphics.Color, secondaryButtonColors: androidx.compose.material3.ButtonColors, secondaryPressColors: androidx.compose.material3.ButtonColors, secondaryTextColor: androidx.compose.ui.graphics.Color): kotlin.Unit + skippable: true + restartable: true + params: + - title: STABLE (String is immutable) + - subtitle: STABLE (String is immutable) + - content: STABLE (String is immutable) + - hint: STABLE (String is immutable) + - textFieldState: STABLE (marked @Stable or @Immutable) + - primaryButtonText: STABLE (String is immutable) + - primaryWavyStrokeColor: STABLE (marked @Stable or @Immutable) + - secondaryWavyStrokeColor: STABLE (marked @Stable or @Immutable) + - onPrimaryClick: STABLE (function type) + - onSecondaryClick: STABLE (function type) + - modifier: STABLE (marked @Stable or @Immutable) + - primaryButtonEnabled: STABLE (primitive type) + - secondaryButtonText: STABLE (String is immutable) + - primaryButtonWeight: STABLE (primitive type) + - secondaryButtonWeight: STABLE (primitive type) + - focusedBorderColor: STABLE (marked @Stable or @Immutable) + - unfocusedBorderColor: STABLE (marked @Stable or @Immutable) + - primaryButtonColors: STABLE (marked @Stable or @Immutable) + - primaryPressColors: STABLE (marked @Stable or @Immutable) + - primaryTextColor: STABLE (marked @Stable or @Immutable) + - secondaryButtonColors: STABLE (marked @Stable or @Immutable) + - secondaryPressColors: STABLE (marked @Stable or @Immutable) + - secondaryTextColor: STABLE (marked @Stable or @Immutable) + @Composable public fun com.idiotfrogs.designsystem.component.MSAnnotatedText(text: androidx.compose.ui.text.AnnotatedString, modifier: androidx.compose.ui.Modifier, fontSize: androidx.compose.ui.unit.Dp, color: androidx.compose.ui.graphics.Color, fontFamily: androidx.compose.ui.text.font.FontFamily, fontWeight: androidx.compose.ui.text.font.FontWeight, letterSpacing: androidx.compose.ui.unit.TextUnit, textDecoration: androidx.compose.ui.text.style.TextDecoration?, textAlign: androidx.compose.ui.text.style.TextAlign?, lineHeight: androidx.compose.ui.unit.TextUnit, overflow: androidx.compose.ui.text.style.TextOverflow, softWrap: kotlin.Boolean, maxLines: kotlin.Int, minLines: kotlin.Int, style: androidx.compose.ui.text.TextStyle): kotlin.Unit skippable: true @@ -116,10 +145,11 @@ public fun com.idiotfrogs.designsystem.component.MSDialog(title: kotlin.String, - cancelTextColor: STABLE (marked @Stable or @Immutable) @Composable -public fun com.idiotfrogs.designsystem.component.MSDim(visible: kotlin.Boolean, onDismiss: kotlin.Function0, color: androidx.compose.ui.graphics.Color, animationSpec: androidx.compose.animation.core.FiniteAnimationSpec): kotlin.Unit +public fun com.idiotfrogs.designsystem.component.MSDim(modifier: androidx.compose.ui.Modifier, visible: kotlin.Boolean, onDismiss: kotlin.Function0, color: androidx.compose.ui.graphics.Color, animationSpec: androidx.compose.animation.core.FiniteAnimationSpec): kotlin.Unit skippable: false restartable: true params: + - modifier: STABLE (marked @Stable or @Immutable) - visible: STABLE (primitive type) - onDismiss: STABLE (function type) - color: STABLE (marked @Stable or @Immutable) diff --git a/feature/detail/stability/detail-debug.stability b/feature/detail/stability/detail-debug.stability index 5fbf4fe5..35618bd1 100644 --- a/feature/detail/stability/detail-debug.stability +++ b/feature/detail/stability/detail-debug.stability @@ -5,11 +5,12 @@ // ./gradlew :detail:stabilityDump @Composable -public fun com.idiotfrogs.detail.DetailRoute(capsuleId: kotlin.Long, viewModel: com.idiotfrogs.detail.DetailViewModel): kotlin.Unit +public fun com.idiotfrogs.detail.DetailRoute(capsuleId: kotlin.Long, refreshHome: kotlin.Boolean, viewModel: com.idiotfrogs.detail.DetailViewModel): kotlin.Unit skippable: false restartable: true params: - capsuleId: STABLE (primitive type) + - refreshHome: STABLE (primitive type) - viewModel: UNSTABLE (has mutable properties or unstable members) @Composable diff --git a/feature/detail/stability/detail-release.stability b/feature/detail/stability/detail-release.stability index 5fbf4fe5..35618bd1 100644 --- a/feature/detail/stability/detail-release.stability +++ b/feature/detail/stability/detail-release.stability @@ -5,11 +5,12 @@ // ./gradlew :detail:stabilityDump @Composable -public fun com.idiotfrogs.detail.DetailRoute(capsuleId: kotlin.Long, viewModel: com.idiotfrogs.detail.DetailViewModel): kotlin.Unit +public fun com.idiotfrogs.detail.DetailRoute(capsuleId: kotlin.Long, refreshHome: kotlin.Boolean, viewModel: com.idiotfrogs.detail.DetailViewModel): kotlin.Unit skippable: false restartable: true params: - capsuleId: STABLE (primitive type) + - refreshHome: STABLE (primitive type) - viewModel: UNSTABLE (has mutable properties or unstable members) @Composable diff --git a/feature/home/stability/home-debug.stability b/feature/home/stability/home-debug.stability index 270fd239..e5aaa72b 100644 --- a/feature/home/stability/home-debug.stability +++ b/feature/home/stability/home-debug.stability @@ -5,29 +5,15 @@ // ./gradlew :home:stabilityDump @Composable -public fun com.idiotfrogs.home.HomeRoute(viewModel: com.idiotfrogs.home.HomeViewModel): kotlin.Unit - skippable: false - restartable: true - params: - - viewModel: UNSTABLE (has mutable properties or unstable members) - -@Composable -public fun com.idiotfrogs.home.HomeScreen(showToast: kotlin.Boolean, data: com.idiotfrogs.home.HomeData, isRefreshing: kotlin.Boolean, onAction: kotlin.Function1): kotlin.Unit - skippable: true - restartable: true - params: - - showToast: STABLE (primitive type) - - data: STABLE (marked @Stable or @Immutable) - - isRefreshing: STABLE (primitive type) - - onAction: STABLE (function type) - -@Composable -public fun com.idiotfrogs.home.component.HomeHeader(profileUrl: kotlin.String?, navigateToProfile: kotlin.Function0): kotlin.Unit +public fun com.idiotfrogs.home.component.HomeBigTicket(modifier: androidx.compose.ui.Modifier, title: kotlin.String, openedAt: kotlin.String, imageUrl: kotlin.String?, step: kotlin.Int): kotlin.Unit skippable: true restartable: true params: - - profileUrl: STABLE (class with no mutable properties) - - navigateToProfile: STABLE (function type) + - modifier: STABLE (marked @Stable or @Immutable) + - title: STABLE (String is immutable) + - openedAt: STABLE (String is immutable) + - imageUrl: STABLE (class with no mutable properties) + - step: STABLE (primitive type) @Composable public fun com.idiotfrogs.home.component.HomeJoinContainer(isShow: kotlin.Boolean, textFieldState: androidx.compose.foundation.text.input.TextFieldState, onCancel: kotlin.Function0, onJoin: kotlin.Function0): kotlin.Unit @@ -40,14 +26,25 @@ public fun com.idiotfrogs.home.component.HomeJoinContainer(isShow: kotlin.Boolea - onJoin: STABLE (function type) @Composable -public fun com.idiotfrogs.home.component.HomeTicket(buried: kotlin.Boolean, createdAt: kotlin.String, title: kotlin.String, imageUrl: kotlin.String?, step: kotlin.Int, modifier: androidx.compose.ui.Modifier): kotlin.Unit +public fun com.idiotfrogs.home.component.HomeMiddleTicket(modifier: androidx.compose.ui.Modifier, title: kotlin.String, openedAt: kotlin.String, imageUrl: kotlin.String?, step: kotlin.Int): kotlin.Unit skippable: true restartable: true params: - - buried: STABLE (primitive type) - - createdAt: STABLE (String is immutable) + - modifier: STABLE (marked @Stable or @Immutable) - title: STABLE (String is immutable) + - openedAt: STABLE (String is immutable) - imageUrl: STABLE (class with no mutable properties) - step: STABLE (primitive type) + +@Composable +public fun com.idiotfrogs.home.component.HomeSmallTicket(modifier: androidx.compose.ui.Modifier, dDayCount: kotlin.String?, createdAt: kotlin.String, title: kotlin.String, imageUrl: kotlin.String?, step: kotlin.Int): kotlin.Unit + skippable: true + restartable: true + params: - modifier: STABLE (marked @Stable or @Immutable) + - dDayCount: STABLE (class with no mutable properties) + - createdAt: STABLE (String is immutable) + - title: STABLE (String is immutable) + - imageUrl: STABLE (class with no mutable properties) + - step: STABLE (primitive type) diff --git a/feature/home/stability/home-release.stability b/feature/home/stability/home-release.stability index 270fd239..e5aaa72b 100644 --- a/feature/home/stability/home-release.stability +++ b/feature/home/stability/home-release.stability @@ -5,29 +5,15 @@ // ./gradlew :home:stabilityDump @Composable -public fun com.idiotfrogs.home.HomeRoute(viewModel: com.idiotfrogs.home.HomeViewModel): kotlin.Unit - skippable: false - restartable: true - params: - - viewModel: UNSTABLE (has mutable properties or unstable members) - -@Composable -public fun com.idiotfrogs.home.HomeScreen(showToast: kotlin.Boolean, data: com.idiotfrogs.home.HomeData, isRefreshing: kotlin.Boolean, onAction: kotlin.Function1): kotlin.Unit - skippable: true - restartable: true - params: - - showToast: STABLE (primitive type) - - data: STABLE (marked @Stable or @Immutable) - - isRefreshing: STABLE (primitive type) - - onAction: STABLE (function type) - -@Composable -public fun com.idiotfrogs.home.component.HomeHeader(profileUrl: kotlin.String?, navigateToProfile: kotlin.Function0): kotlin.Unit +public fun com.idiotfrogs.home.component.HomeBigTicket(modifier: androidx.compose.ui.Modifier, title: kotlin.String, openedAt: kotlin.String, imageUrl: kotlin.String?, step: kotlin.Int): kotlin.Unit skippable: true restartable: true params: - - profileUrl: STABLE (class with no mutable properties) - - navigateToProfile: STABLE (function type) + - modifier: STABLE (marked @Stable or @Immutable) + - title: STABLE (String is immutable) + - openedAt: STABLE (String is immutable) + - imageUrl: STABLE (class with no mutable properties) + - step: STABLE (primitive type) @Composable public fun com.idiotfrogs.home.component.HomeJoinContainer(isShow: kotlin.Boolean, textFieldState: androidx.compose.foundation.text.input.TextFieldState, onCancel: kotlin.Function0, onJoin: kotlin.Function0): kotlin.Unit @@ -40,14 +26,25 @@ public fun com.idiotfrogs.home.component.HomeJoinContainer(isShow: kotlin.Boolea - onJoin: STABLE (function type) @Composable -public fun com.idiotfrogs.home.component.HomeTicket(buried: kotlin.Boolean, createdAt: kotlin.String, title: kotlin.String, imageUrl: kotlin.String?, step: kotlin.Int, modifier: androidx.compose.ui.Modifier): kotlin.Unit +public fun com.idiotfrogs.home.component.HomeMiddleTicket(modifier: androidx.compose.ui.Modifier, title: kotlin.String, openedAt: kotlin.String, imageUrl: kotlin.String?, step: kotlin.Int): kotlin.Unit skippable: true restartable: true params: - - buried: STABLE (primitive type) - - createdAt: STABLE (String is immutable) + - modifier: STABLE (marked @Stable or @Immutable) - title: STABLE (String is immutable) + - openedAt: STABLE (String is immutable) - imageUrl: STABLE (class with no mutable properties) - step: STABLE (primitive type) + +@Composable +public fun com.idiotfrogs.home.component.HomeSmallTicket(modifier: androidx.compose.ui.Modifier, dDayCount: kotlin.String?, createdAt: kotlin.String, title: kotlin.String, imageUrl: kotlin.String?, step: kotlin.Int): kotlin.Unit + skippable: true + restartable: true + params: - modifier: STABLE (marked @Stable or @Immutable) + - dDayCount: STABLE (class with no mutable properties) + - createdAt: STABLE (String is immutable) + - title: STABLE (String is immutable) + - imageUrl: STABLE (class with no mutable properties) + - step: STABLE (primitive type) diff --git a/feature/profile/stability/profile-debug.stability b/feature/profile/stability/profile-debug.stability index 52332bc8..8c129db9 100644 --- a/feature/profile/stability/profile-debug.stability +++ b/feature/profile/stability/profile-debug.stability @@ -51,6 +51,16 @@ public fun com.idiotfrogs.profile.component.ProfileTicketCard(imageUrl: kotlin.S - date: STABLE (String is immutable) - onClick: STABLE (function type) +@Composable +public fun com.idiotfrogs.profile.component.ProfileWithdrawBottomSheet(isShow: kotlin.Boolean, textFieldState: androidx.compose.foundation.text.input.TextFieldState, onWithdraw: kotlin.Function0, onCancel: kotlin.Function0): kotlin.Unit + skippable: true + restartable: true + params: + - isShow: STABLE (primitive type) + - textFieldState: STABLE (marked @Stable or @Immutable) + - onWithdraw: STABLE (function type) + - onCancel: STABLE (function type) + @Composable public fun com.idiotfrogs.profile.editprofile.EditProfileRoute(viewModel: com.idiotfrogs.profile.editprofile.EditProfileViewModel): kotlin.Unit skippable: false diff --git a/feature/profile/stability/profile-release.stability b/feature/profile/stability/profile-release.stability index 52332bc8..8c129db9 100644 --- a/feature/profile/stability/profile-release.stability +++ b/feature/profile/stability/profile-release.stability @@ -51,6 +51,16 @@ public fun com.idiotfrogs.profile.component.ProfileTicketCard(imageUrl: kotlin.S - date: STABLE (String is immutable) - onClick: STABLE (function type) +@Composable +public fun com.idiotfrogs.profile.component.ProfileWithdrawBottomSheet(isShow: kotlin.Boolean, textFieldState: androidx.compose.foundation.text.input.TextFieldState, onWithdraw: kotlin.Function0, onCancel: kotlin.Function0): kotlin.Unit + skippable: true + restartable: true + params: + - isShow: STABLE (primitive type) + - textFieldState: STABLE (marked @Stable or @Immutable) + - onWithdraw: STABLE (function type) + - onCancel: STABLE (function type) + @Composable public fun com.idiotfrogs.profile.editprofile.EditProfileRoute(viewModel: com.idiotfrogs.profile.editprofile.EditProfileViewModel): kotlin.Unit skippable: false From f160b43fb2e42df27091466504a40909bf772f44 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Thu, 17 Sep 2026 10:04:26 +0900 Subject: [PATCH 25/31] =?UTF-8?q?:memo:=20::=20stability=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=88=84=EB=9D=BD=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/home/stability/home-debug.stability | 101 ++++++++++++++++++ feature/home/stability/home-release.stability | 101 ++++++++++++++++++ 2 files changed, 202 insertions(+) diff --git a/feature/home/stability/home-debug.stability b/feature/home/stability/home-debug.stability index e5aaa72b..3657bb3c 100644 --- a/feature/home/stability/home-debug.stability +++ b/feature/home/stability/home-debug.stability @@ -15,6 +15,37 @@ public fun com.idiotfrogs.home.component.HomeBigTicket(modifier: androidx.compos - imageUrl: STABLE (class with no mutable properties) - step: STABLE (primitive type) +@Composable +public fun com.idiotfrogs.home.component.HomeBottomBar(modifier: androidx.compose.ui.Modifier, expanded: kotlin.Boolean, showDim: kotlin.Boolean, fabMenuList: kotlin.collections.List, selectedMenu: com.idiotfrogs.home.component.BottomMenu, onSelectChange: kotlin.Function1, onExpandChange: kotlin.Function1, onClickDim: kotlin.Function0): kotlin.Unit + skippable: false + restartable: true + params: + - modifier: STABLE (marked @Stable or @Immutable) + - expanded: STABLE (primitive type) + - showDim: STABLE (primitive type) + - fabMenuList: RUNTIME (requires runtime check) + - selectedMenu: STABLE (class with no mutable properties) + - onSelectChange: STABLE (function type) + - onExpandChange: STABLE (function type) + - onClickDim: STABLE (function type) + +@Composable +public fun com.idiotfrogs.home.component.HomeEmptyScreen(modifier: androidx.compose.ui.Modifier, selectedMenu: com.idiotfrogs.home.component.BottomMenu): kotlin.Unit + skippable: true + restartable: true + params: + - modifier: STABLE (marked @Stable or @Immutable) + - selectedMenu: STABLE (class with no mutable properties) + +@Composable +public fun com.idiotfrogs.home.component.HomeHeader(selectedMenu: com.idiotfrogs.home.component.BottomMenu, profileUrl: kotlin.String?, navigateToProfile: kotlin.Function0): kotlin.Unit + skippable: true + restartable: true + params: + - selectedMenu: STABLE (class with no mutable properties) + - profileUrl: STABLE (class with no mutable properties) + - navigateToProfile: STABLE (function type) + @Composable public fun com.idiotfrogs.home.component.HomeJoinContainer(isShow: kotlin.Boolean, textFieldState: androidx.compose.foundation.text.input.TextFieldState, onCancel: kotlin.Function0, onJoin: kotlin.Function0): kotlin.Unit skippable: true @@ -36,6 +67,33 @@ public fun com.idiotfrogs.home.component.HomeMiddleTicket(modifier: androidx.com - imageUrl: STABLE (class with no mutable properties) - step: STABLE (primitive type) +@Composable +public fun com.idiotfrogs.home.component.HomeOpenedBanner(modifier: androidx.compose.ui.Modifier, unopenedList: kotlin.collections.List, onClick: kotlin.Function1<@[ParameterName(name = \): kotlin.Unit + skippable: false + restartable: true + params: + - modifier: STABLE (marked @Stable or @Immutable) + - unopenedList: RUNTIME (requires runtime check) + - onClick: STABLE (function type) + +@Composable +public fun com.idiotfrogs.home.component.HomeRemindBanner(modifier: androidx.compose.ui.Modifier, title: kotlin.String, content: kotlin.String, mainImageUrl: kotlin.String): kotlin.Unit + skippable: true + restartable: true + params: + - modifier: STABLE (marked @Stable or @Immutable) + - title: STABLE (String is immutable) + - content: STABLE (String is immutable) + - mainImageUrl: STABLE (String is immutable) + +@Composable +public fun com.idiotfrogs.home.component.HomeSectionDivider(modifier: androidx.compose.ui.Modifier, sectionName: kotlin.String): kotlin.Unit + skippable: true + restartable: true + params: + - modifier: STABLE (marked @Stable or @Immutable) + - sectionName: STABLE (String is immutable) + @Composable public fun com.idiotfrogs.home.component.HomeSmallTicket(modifier: androidx.compose.ui.Modifier, dDayCount: kotlin.String?, createdAt: kotlin.String, title: kotlin.String, imageUrl: kotlin.String?, step: kotlin.Int): kotlin.Unit skippable: true @@ -48,3 +106,46 @@ public fun com.idiotfrogs.home.component.HomeSmallTicket(modifier: androidx.comp - imageUrl: STABLE (class with no mutable properties) - step: STABLE (primitive type) +@Composable +public fun com.idiotfrogs.home.component.OpenedTicket(modifier: androidx.compose.ui.Modifier, title: kotlin.String, createAt: kotlin.String, openedAt: kotlin.String, imageUrl: kotlin.String?): kotlin.Unit + skippable: true + restartable: true + params: + - modifier: STABLE (marked @Stable or @Immutable) + - title: STABLE (String is immutable) + - createAt: STABLE (String is immutable) + - openedAt: STABLE (String is immutable) + - imageUrl: STABLE (class with no mutable properties) + +@Composable +public fun com.idiotfrogs.home.detail.HomeDetailRoute(homeDetailType: com.idiotfrogs.navigation.HomeDetailType, viewModel: com.idiotfrogs.home.detail.HomeDetailViewModel): kotlin.Unit + skippable: false + restartable: true + params: + - homeDetailType: STABLE (class with no mutable properties) + - viewModel: UNSTABLE (has mutable properties or unstable members) + +@Composable +public fun com.idiotfrogs.home.detail.HomeDetailScreen(data: com.idiotfrogs.home.detail.HomeDetailData, onAction: kotlin.Function1): kotlin.Unit + skippable: true + restartable: true + params: + - data: STABLE (marked @Stable or @Immutable) + - onAction: STABLE (function type) + +@Composable +public fun com.idiotfrogs.home.home.HomeRoute(viewModel: com.idiotfrogs.home.home.HomeViewModel): kotlin.Unit + skippable: false + restartable: true + params: + - viewModel: UNSTABLE (has mutable properties or unstable members) + +@Composable +public fun com.idiotfrogs.home.home.HomeScreen(data: com.idiotfrogs.home.home.HomeData, isRefreshing: kotlin.Boolean, onAction: kotlin.Function1): kotlin.Unit + skippable: true + restartable: true + params: + - data: STABLE (marked @Stable or @Immutable) + - isRefreshing: STABLE (primitive type) + - onAction: STABLE (function type) + diff --git a/feature/home/stability/home-release.stability b/feature/home/stability/home-release.stability index e5aaa72b..3657bb3c 100644 --- a/feature/home/stability/home-release.stability +++ b/feature/home/stability/home-release.stability @@ -15,6 +15,37 @@ public fun com.idiotfrogs.home.component.HomeBigTicket(modifier: androidx.compos - imageUrl: STABLE (class with no mutable properties) - step: STABLE (primitive type) +@Composable +public fun com.idiotfrogs.home.component.HomeBottomBar(modifier: androidx.compose.ui.Modifier, expanded: kotlin.Boolean, showDim: kotlin.Boolean, fabMenuList: kotlin.collections.List, selectedMenu: com.idiotfrogs.home.component.BottomMenu, onSelectChange: kotlin.Function1, onExpandChange: kotlin.Function1, onClickDim: kotlin.Function0): kotlin.Unit + skippable: false + restartable: true + params: + - modifier: STABLE (marked @Stable or @Immutable) + - expanded: STABLE (primitive type) + - showDim: STABLE (primitive type) + - fabMenuList: RUNTIME (requires runtime check) + - selectedMenu: STABLE (class with no mutable properties) + - onSelectChange: STABLE (function type) + - onExpandChange: STABLE (function type) + - onClickDim: STABLE (function type) + +@Composable +public fun com.idiotfrogs.home.component.HomeEmptyScreen(modifier: androidx.compose.ui.Modifier, selectedMenu: com.idiotfrogs.home.component.BottomMenu): kotlin.Unit + skippable: true + restartable: true + params: + - modifier: STABLE (marked @Stable or @Immutable) + - selectedMenu: STABLE (class with no mutable properties) + +@Composable +public fun com.idiotfrogs.home.component.HomeHeader(selectedMenu: com.idiotfrogs.home.component.BottomMenu, profileUrl: kotlin.String?, navigateToProfile: kotlin.Function0): kotlin.Unit + skippable: true + restartable: true + params: + - selectedMenu: STABLE (class with no mutable properties) + - profileUrl: STABLE (class with no mutable properties) + - navigateToProfile: STABLE (function type) + @Composable public fun com.idiotfrogs.home.component.HomeJoinContainer(isShow: kotlin.Boolean, textFieldState: androidx.compose.foundation.text.input.TextFieldState, onCancel: kotlin.Function0, onJoin: kotlin.Function0): kotlin.Unit skippable: true @@ -36,6 +67,33 @@ public fun com.idiotfrogs.home.component.HomeMiddleTicket(modifier: androidx.com - imageUrl: STABLE (class with no mutable properties) - step: STABLE (primitive type) +@Composable +public fun com.idiotfrogs.home.component.HomeOpenedBanner(modifier: androidx.compose.ui.Modifier, unopenedList: kotlin.collections.List, onClick: kotlin.Function1<@[ParameterName(name = \): kotlin.Unit + skippable: false + restartable: true + params: + - modifier: STABLE (marked @Stable or @Immutable) + - unopenedList: RUNTIME (requires runtime check) + - onClick: STABLE (function type) + +@Composable +public fun com.idiotfrogs.home.component.HomeRemindBanner(modifier: androidx.compose.ui.Modifier, title: kotlin.String, content: kotlin.String, mainImageUrl: kotlin.String): kotlin.Unit + skippable: true + restartable: true + params: + - modifier: STABLE (marked @Stable or @Immutable) + - title: STABLE (String is immutable) + - content: STABLE (String is immutable) + - mainImageUrl: STABLE (String is immutable) + +@Composable +public fun com.idiotfrogs.home.component.HomeSectionDivider(modifier: androidx.compose.ui.Modifier, sectionName: kotlin.String): kotlin.Unit + skippable: true + restartable: true + params: + - modifier: STABLE (marked @Stable or @Immutable) + - sectionName: STABLE (String is immutable) + @Composable public fun com.idiotfrogs.home.component.HomeSmallTicket(modifier: androidx.compose.ui.Modifier, dDayCount: kotlin.String?, createdAt: kotlin.String, title: kotlin.String, imageUrl: kotlin.String?, step: kotlin.Int): kotlin.Unit skippable: true @@ -48,3 +106,46 @@ public fun com.idiotfrogs.home.component.HomeSmallTicket(modifier: androidx.comp - imageUrl: STABLE (class with no mutable properties) - step: STABLE (primitive type) +@Composable +public fun com.idiotfrogs.home.component.OpenedTicket(modifier: androidx.compose.ui.Modifier, title: kotlin.String, createAt: kotlin.String, openedAt: kotlin.String, imageUrl: kotlin.String?): kotlin.Unit + skippable: true + restartable: true + params: + - modifier: STABLE (marked @Stable or @Immutable) + - title: STABLE (String is immutable) + - createAt: STABLE (String is immutable) + - openedAt: STABLE (String is immutable) + - imageUrl: STABLE (class with no mutable properties) + +@Composable +public fun com.idiotfrogs.home.detail.HomeDetailRoute(homeDetailType: com.idiotfrogs.navigation.HomeDetailType, viewModel: com.idiotfrogs.home.detail.HomeDetailViewModel): kotlin.Unit + skippable: false + restartable: true + params: + - homeDetailType: STABLE (class with no mutable properties) + - viewModel: UNSTABLE (has mutable properties or unstable members) + +@Composable +public fun com.idiotfrogs.home.detail.HomeDetailScreen(data: com.idiotfrogs.home.detail.HomeDetailData, onAction: kotlin.Function1): kotlin.Unit + skippable: true + restartable: true + params: + - data: STABLE (marked @Stable or @Immutable) + - onAction: STABLE (function type) + +@Composable +public fun com.idiotfrogs.home.home.HomeRoute(viewModel: com.idiotfrogs.home.home.HomeViewModel): kotlin.Unit + skippable: false + restartable: true + params: + - viewModel: UNSTABLE (has mutable properties or unstable members) + +@Composable +public fun com.idiotfrogs.home.home.HomeScreen(data: com.idiotfrogs.home.home.HomeData, isRefreshing: kotlin.Boolean, onAction: kotlin.Function1): kotlin.Unit + skippable: true + restartable: true + params: + - data: STABLE (marked @Stable or @Immutable) + - isRefreshing: STABLE (primitive type) + - onAction: STABLE (function type) + From 6cd43ef4559e67319737744a95b3c002a8db07b6 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Thu, 17 Sep 2026 11:17:01 +0900 Subject: [PATCH 26/31] =?UTF-8?q?:bug:=20::=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/idiotfrogs/navigation/Routes.kt | 4 +- .../home/component/HomeBottomBar.kt | 10 +++-- .../home/component/HomeOpenedBanner.kt | 41 ++++++++++--------- .../home/detail/HomeDetailScreen.kt | 4 +- .../com/idiotfrogs/home/home/HomeScreen.kt | 24 ++++++----- .../com/idiotfrogs/home/home/HomeViewModel.kt | 4 +- 6 files changed, 46 insertions(+), 41 deletions(-) diff --git a/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt b/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt index 78f73ac4..3da967f5 100644 --- a/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt +++ b/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt @@ -13,9 +13,7 @@ sealed interface Routes: NavKey { @Serializable data object Home : Routes @Serializable - data class HomeDetail( - val homeDetailType: HomeDetailType - ): Routes + data class HomeDetail(val homeDetailType: HomeDetailType): Routes @Serializable data object Create : Routes @Serializable diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeBottomBar.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeBottomBar.kt index ff419a0c..224acac2 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeBottomBar.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeBottomBar.kt @@ -19,6 +19,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -41,12 +42,15 @@ import com.idiotfrogs.resource.R enum class BottomMenu { HOME, OPENED } +@Immutable +data class FabMenuList(val menus: List) + @Composable fun HomeBottomBar( modifier: Modifier = Modifier, expanded: Boolean, showDim: Boolean, - fabMenuList: List, + fabMenuList: FabMenuList, selectedMenu: BottomMenu, onSelectChange: (BottomMenu) -> Unit, onExpandChange: (Boolean) -> Unit, @@ -187,7 +191,7 @@ fun HomeBottomBar( expanded = expanded, hasFab = true, offset = DpOffset(x = 0.dp, y = (-16).dp), - menuList = fabMenuList, + menuList = fabMenuList.menus, onClick = { onExpandChange.invoke(!expanded) }, onDismiss = { onExpandChange.invoke(false) }, ) @@ -209,7 +213,7 @@ private fun HomeBottomBarPreview() { ) } HomeBottomBar( - fabMenuList = menuList, + fabMenuList = FabMenuList(menuList), showDim = showDim, expanded = expanded, selectedMenu = selectedMenu, diff --git a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt index d9007682..5fc576f7 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/component/HomeOpenedBanner.kt @@ -15,6 +15,7 @@ import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -46,13 +47,16 @@ private const val SIDE_ALPHA = 0.12f // 좌우 티켓을 중앙에 대비해서 아래로 내릴 크기 private val SIDE_OFFSET_Y = 22.dp +@Immutable +data class UnopenedList(val contents: List) + @Composable fun HomeOpenedBanner( modifier: Modifier = Modifier, - unopenedList: List, + unopenedList: UnopenedList, onClick: (capsuleId: Long) -> Unit, ) { - val pagerState = rememberPagerState { unopenedList.size } + val pagerState = rememberPagerState { unopenedList.contents.size } Box(modifier = modifier) { Box( @@ -88,12 +92,11 @@ fun HomeOpenedBanner( Image( modifier = Modifier .fillMaxWidth() - .height( - if (unopenedList.size == 1) 490.dp else 290.dp - ) - .padding(horizontal = 28.dp) + .height(if (unopenedList.contents.size == 1) 490.dp else 290.dp) .padding( - top = if (unopenedList.size == 1) 0.dp else 13.dp + top = if (unopenedList.contents.size == 1) 0.dp else 13.dp, + start = 28.dp, + end = 28.dp ) .alpha(alpha), painter = painterResource(R.drawable.bg_light), @@ -101,15 +104,15 @@ fun HomeOpenedBanner( contentScale = ContentScale.FillBounds ) // 단일 티켓인 경우 디자인이 다름 - if (unopenedList.size == 1) { + if (unopenedList.contents.size == 1) { HomeBigTicket( modifier = Modifier - .noRippleClickable { onClick.invoke(unopenedList.first().timeCapsuleId) } + .noRippleClickable { onClick.invoke(unopenedList.contents.first().timeCapsuleId) } .padding(top = 67.dp), - title = unopenedList.first().title, - openedAt = unopenedList.first().openedAt.toYearMonthDay(), - imageUrl = unopenedList.first().mainImageUrl, - step = unopenedList.first().stage, + title = unopenedList.contents.first().title, + openedAt = unopenedList.contents.first().openedAt.toYearMonthDay(), + imageUrl = unopenedList.contents.first().mainImageUrl, + step = unopenedList.contents.first().stage, ) Spacer(modifier = Modifier.height(32.dp)) return @@ -126,12 +129,12 @@ fun HomeOpenedBanner( ) { page -> HomeMiddleTicket( modifier = Modifier - .noRippleClickable { onClick.invoke(unopenedList[page].timeCapsuleId) } + .noRippleClickable { onClick.invoke(unopenedList.contents[page].timeCapsuleId) } .deckPage(pagerState, page), - title = unopenedList[page].title, - openedAt = unopenedList[page].openedAt.toYearMonthDay(), - imageUrl = unopenedList[page].mainImageUrl, - step = unopenedList[page].stage, + title = unopenedList.contents[page].title, + openedAt = unopenedList.contents[page].openedAt.toYearMonthDay(), + imageUrl = unopenedList.contents[page].mainImageUrl, + step = unopenedList.contents[page].stage, ) } } @@ -160,7 +163,7 @@ private fun Modifier.deckPage(state: PagerState, page: Int): Modifier { @Composable private fun HomeOpenedBannerPreview() { HomeOpenedBanner( - unopenedList = emptyList(), + unopenedList = UnopenedList(emptyList()), onClick = {} ) } \ No newline at end of file diff --git a/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt index b7ea28f2..29282ad6 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/detail/HomeDetailScreen.kt @@ -40,9 +40,7 @@ fun HomeDetailRoute( viewModel: HomeDetailViewModel = hiltViewModel( key = homeDetailType.name - ) { - it.create(homeDetailType) - }, + ) { it.create(homeDetailType) }, ) { val navigator = LocalComposeMSNavigator.current val uiState by viewModel.collectAsState() diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt index 9ec7a407..58bb15c9 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt @@ -48,6 +48,7 @@ import com.idiotfrogs.home.component.HomeJoinContainer import com.idiotfrogs.navigation.LocalComposeMSNavigator import com.idiotfrogs.navigation.Routes import com.idiotfrogs.home.component.BottomMenu +import com.idiotfrogs.home.component.FabMenuList import com.idiotfrogs.home.component.HomeBottomBar import com.idiotfrogs.home.component.HomeEmptyScreen import com.idiotfrogs.home.component.HomeOpenedBanner @@ -55,6 +56,7 @@ import com.idiotfrogs.home.component.HomeRemindBanner import com.idiotfrogs.home.component.HomeSectionDivider import com.idiotfrogs.home.component.HomeSmallTicket import com.idiotfrogs.home.component.OpenedTicket +import com.idiotfrogs.home.component.UnopenedList import com.idiotfrogs.home.component.maxLineItem import com.idiotfrogs.navigation.HomeDetailType import org.orbitmvi.orbit.compose.collectAsState @@ -109,15 +111,17 @@ fun HomeScreen( val menuList by remember { mutableStateOf( - listOf( - MSMenuFabModel("새 티켓 생성하기") { - expanded = false - onAction.invoke(HomeAction.CreateClicked) - }, - MSMenuFabModel("참여코드로 합류하기") { - expanded = false - showJoinContainer = true - }, + FabMenuList( + listOf( + MSMenuFabModel("새 티켓 생성하기") { + expanded = false + onAction.invoke(HomeAction.CreateClicked) + }, + MSMenuFabModel("참여코드로 합류하기") { + expanded = false + showJoinContainer = true + }, + ) ) ) } @@ -185,7 +189,7 @@ fun HomeScreen( maxLineItem { HomeOpenedBanner( modifier = Modifier.padding(top = 12.dp), - unopenedList = data.unopenedBanner, + unopenedList = UnopenedList(data.unopenedBanner), onClick = { onAction.invoke(HomeAction.TimeCapsuleClicked(it)) } ) } diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt index eebb42d7..e3a215e6 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt @@ -130,9 +130,7 @@ class HomeViewModel @Inject constructor( intent { reduce { state.copy( - data = latestData.copy( - opened = PaginationState().addPage(it) - ), + data = latestData.copy(opened = PaginationState().addPage(it)), isLoading = false, errorMessage = null, ) From e4111ce725f437085cd35f6388571894a9968b42 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Thu, 17 Sep 2026 11:23:22 +0900 Subject: [PATCH 27/31] =?UTF-8?q?:memo:=20::=20stability=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/home/stability/home-debug.stability | 12 ++++++------ feature/home/stability/home-release.stability | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/feature/home/stability/home-debug.stability b/feature/home/stability/home-debug.stability index 3657bb3c..968d4743 100644 --- a/feature/home/stability/home-debug.stability +++ b/feature/home/stability/home-debug.stability @@ -16,14 +16,14 @@ public fun com.idiotfrogs.home.component.HomeBigTicket(modifier: androidx.compos - step: STABLE (primitive type) @Composable -public fun com.idiotfrogs.home.component.HomeBottomBar(modifier: androidx.compose.ui.Modifier, expanded: kotlin.Boolean, showDim: kotlin.Boolean, fabMenuList: kotlin.collections.List, selectedMenu: com.idiotfrogs.home.component.BottomMenu, onSelectChange: kotlin.Function1, onExpandChange: kotlin.Function1, onClickDim: kotlin.Function0): kotlin.Unit - skippable: false +public fun com.idiotfrogs.home.component.HomeBottomBar(modifier: androidx.compose.ui.Modifier, expanded: kotlin.Boolean, showDim: kotlin.Boolean, fabMenuList: com.idiotfrogs.home.component.FabMenuList, selectedMenu: com.idiotfrogs.home.component.BottomMenu, onSelectChange: kotlin.Function1, onExpandChange: kotlin.Function1, onClickDim: kotlin.Function0): kotlin.Unit + skippable: true restartable: true params: - modifier: STABLE (marked @Stable or @Immutable) - expanded: STABLE (primitive type) - showDim: STABLE (primitive type) - - fabMenuList: RUNTIME (requires runtime check) + - fabMenuList: STABLE (marked @Stable or @Immutable) - selectedMenu: STABLE (class with no mutable properties) - onSelectChange: STABLE (function type) - onExpandChange: STABLE (function type) @@ -68,12 +68,12 @@ public fun com.idiotfrogs.home.component.HomeMiddleTicket(modifier: androidx.com - step: STABLE (primitive type) @Composable -public fun com.idiotfrogs.home.component.HomeOpenedBanner(modifier: androidx.compose.ui.Modifier, unopenedList: kotlin.collections.List, onClick: kotlin.Function1<@[ParameterName(name = \): kotlin.Unit - skippable: false +public fun com.idiotfrogs.home.component.HomeOpenedBanner(modifier: androidx.compose.ui.Modifier, unopenedList: com.idiotfrogs.home.component.UnopenedList, onClick: kotlin.Function1<@[ParameterName(name = \): kotlin.Unit + skippable: true restartable: true params: - modifier: STABLE (marked @Stable or @Immutable) - - unopenedList: RUNTIME (requires runtime check) + - unopenedList: STABLE (marked @Stable or @Immutable) - onClick: STABLE (function type) @Composable diff --git a/feature/home/stability/home-release.stability b/feature/home/stability/home-release.stability index 3657bb3c..968d4743 100644 --- a/feature/home/stability/home-release.stability +++ b/feature/home/stability/home-release.stability @@ -16,14 +16,14 @@ public fun com.idiotfrogs.home.component.HomeBigTicket(modifier: androidx.compos - step: STABLE (primitive type) @Composable -public fun com.idiotfrogs.home.component.HomeBottomBar(modifier: androidx.compose.ui.Modifier, expanded: kotlin.Boolean, showDim: kotlin.Boolean, fabMenuList: kotlin.collections.List, selectedMenu: com.idiotfrogs.home.component.BottomMenu, onSelectChange: kotlin.Function1, onExpandChange: kotlin.Function1, onClickDim: kotlin.Function0): kotlin.Unit - skippable: false +public fun com.idiotfrogs.home.component.HomeBottomBar(modifier: androidx.compose.ui.Modifier, expanded: kotlin.Boolean, showDim: kotlin.Boolean, fabMenuList: com.idiotfrogs.home.component.FabMenuList, selectedMenu: com.idiotfrogs.home.component.BottomMenu, onSelectChange: kotlin.Function1, onExpandChange: kotlin.Function1, onClickDim: kotlin.Function0): kotlin.Unit + skippable: true restartable: true params: - modifier: STABLE (marked @Stable or @Immutable) - expanded: STABLE (primitive type) - showDim: STABLE (primitive type) - - fabMenuList: RUNTIME (requires runtime check) + - fabMenuList: STABLE (marked @Stable or @Immutable) - selectedMenu: STABLE (class with no mutable properties) - onSelectChange: STABLE (function type) - onExpandChange: STABLE (function type) @@ -68,12 +68,12 @@ public fun com.idiotfrogs.home.component.HomeMiddleTicket(modifier: androidx.com - step: STABLE (primitive type) @Composable -public fun com.idiotfrogs.home.component.HomeOpenedBanner(modifier: androidx.compose.ui.Modifier, unopenedList: kotlin.collections.List, onClick: kotlin.Function1<@[ParameterName(name = \): kotlin.Unit - skippable: false +public fun com.idiotfrogs.home.component.HomeOpenedBanner(modifier: androidx.compose.ui.Modifier, unopenedList: com.idiotfrogs.home.component.UnopenedList, onClick: kotlin.Function1<@[ParameterName(name = \): kotlin.Unit + skippable: true restartable: true params: - modifier: STABLE (marked @Stable or @Immutable) - - unopenedList: RUNTIME (requires runtime check) + - unopenedList: STABLE (marked @Stable or @Immutable) - onClick: STABLE (function type) @Composable From 6fc85a08c6b606cde06f9b46f8fbfdc070971373 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Thu, 17 Sep 2026 15:34:09 +0900 Subject: [PATCH 28/31] =?UTF-8?q?:art:=20::=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/idiotfrogs/memoryseal/MainActivity.kt | 9 ++---- .../java/com/idiotfrogs/navigation/Routes.kt | 2 +- .../com/idiotfrogs/detail/DetailScreen.kt | 3 +- .../com/idiotfrogs/detail/DetailViewModel.kt | 5 +--- .../com/idiotfrogs/home/home/HomeScreen.kt | 27 ++++++++--------- .../com/idiotfrogs/home/home/HomeViewModel.kt | 30 ++++++++++++++++++- 6 files changed, 47 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt b/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt index 11444383..8c24840c 100644 --- a/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt +++ b/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt @@ -100,7 +100,7 @@ class MainActivity : ComponentActivity() { navigator.navigate(Routes.Friend(event.capsuleId)) } is MainNavigationEvent.NavigateToDetail -> { - navigator.navigate(Routes.Detail(event.capsuleId, refreshHome = event.refreshHome)) + navigator.navigate(Routes.Detail(event.capsuleId)) event.toastMessage?.let { message -> Toast.makeText( this@MainActivity, @@ -140,12 +140,7 @@ class MainActivity : ComponentActivity() { entry { CreateRoute() } entry { ProfileRoute() } entry { EditProfileRoute() } - entry { - DetailRoute( - capsuleId = it.id, - refreshHome = it.refreshHome - ) - } + entry { DetailRoute(capsuleId = it.id) } entry { MessageRoute(capsuleId = it.id) } entry { PreviewRoute(capsuleId = it.id) } entry { MemoryRoute(capsuleId = it.id) } diff --git a/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt b/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt index 3da967f5..8a5a282f 100644 --- a/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt +++ b/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt @@ -23,7 +23,7 @@ sealed interface Routes: NavKey { @Serializable data class Friend(val id: Long) : Routes @Serializable - data class Detail(val id: Long, val refreshHome: Boolean = false) : Routes + data class Detail(val id: Long) : Routes @Serializable data class Message(val id: Long) : Routes @Serializable diff --git a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt index 485752db..6268cd96 100644 --- a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt +++ b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailScreen.kt @@ -82,11 +82,10 @@ import kotlin.time.ExperimentalTime @Composable fun DetailRoute( capsuleId: Long, - refreshHome: Boolean, viewModel: DetailViewModel = hiltViewModel( key = capsuleId.toString() - ) { it.create(capsuleId, refreshHome) }, + ) { it.create(capsuleId) }, ) { val navigator = LocalComposeMSNavigator.current val uiState by viewModel.collectAsState() diff --git a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt index aad423ec..a4a72548 100644 --- a/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt +++ b/feature/detail/src/main/java/com/idiotfrogs/detail/DetailViewModel.kt @@ -24,7 +24,6 @@ import org.orbitmvi.orbit.viewmodel.container @HiltViewModel(assistedFactory = DetailViewModel.Factory::class) class DetailViewModel @AssistedInject constructor( @Assisted private val capsuleId: Long, - @Assisted private val refreshHome: Boolean, private val getTimeCapsuleUseCase: GetTimeCapsuleUseCase, private val getTimeCapsuleCollaboratorsUseCase: GetTimeCapsuleCollaboratorsUseCase, private val buryTimeCapsuleUseCase: BuryTimeCapsuleUseCase, @@ -67,8 +66,6 @@ class DetailViewModel @AssistedInject constructor( postSideEffect(DetailSideEffect.NavigateToOpen(capsuleId)) RefreshSideEffect.tryEmit(RefreshEvent.Home) } else { - // 만약 디테일 로드 이후 홈이 리프레시 되어야 한다면 - if (refreshHome) RefreshSideEffect.tryEmit(RefreshEvent.Home) reduce { state.copy( data = TimeCapsuleData( @@ -137,7 +134,7 @@ class DetailViewModel @AssistedInject constructor( @AssistedFactory interface Factory { - fun create(capsuleId: Long, refreshHome: Boolean): DetailViewModel + fun create(capsuleId: Long): DetailViewModel } } diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt index 58bb15c9..21619ced 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeScreen.kt @@ -185,26 +185,14 @@ fun HomeScreen( columns = GridCells.Fixed(2), horizontalArrangement = Arrangement.spacedBy((-12).dp) // 줄기가 겹쳐지도록 ) { - if (!data.unopenedBanner.isNullOrEmpty()) { - maxLineItem { - HomeOpenedBanner( - modifier = Modifier.padding(top = 12.dp), - unopenedList = UnopenedList(data.unopenedBanner), - onClick = { onAction.invoke(HomeAction.TimeCapsuleClicked(it)) } - ) - } - } if (data.seasonBanner != null && data.seasonBanner.isValid) { maxLineItem { HomeRemindBanner( modifier = Modifier - .padding( - top = if (!data.unopenedBanner.isNullOrEmpty()) 0.dp else 20.dp, - start = 20.dp, end = 20.dp, bottom = 20.dp - ) + .padding(top = 12.dp, start = 20.dp, end = 20.dp, bottom = 20.dp) .noRippleClickable { data.seasonBanner.capsuleId?.let { - onAction.invoke(HomeAction.TimeCapsuleClicked(it)) + onAction.invoke(HomeAction.RemindBannerClicked(it)) } }, title = data.seasonBanner.title, @@ -213,6 +201,17 @@ fun HomeScreen( ) } } + if (!data.unopenedBanner.isNullOrEmpty()) { + maxLineItem { + HomeOpenedBanner( + modifier = Modifier.padding( + top = if (data.seasonBanner != null && data.seasonBanner.isValid) 0.dp else 20.dp + ), + unopenedList = UnopenedList(data.unopenedBanner), + onClick = { onAction.invoke(HomeAction.TimeCapsuleClicked(it)) } + ) + } + } if (data.beforeBuried.isNotEmpty()) { maxLineItem { HomeSectionDivider( diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt index e3a215e6..04d6a6f1 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt @@ -1,6 +1,5 @@ package com.idiotfrogs.home.home -import android.util.Log import androidx.compose.runtime.Immutable import com.idiotfrogs.domain.usecase.auth.PutFcmTokenUseCase import com.idiotfrogs.domain.usecase.home.GetSeasonBannerUseCase @@ -9,10 +8,12 @@ import com.idiotfrogs.domain.usecase.timecapsule.GetUnopenedUseCase import com.idiotfrogs.domain.usecase.timecapsule.RequestCollaboratorUseCase import com.idiotfrogs.domain.usecase.user.GetMyProfileUseCase import com.idiotfrogs.home.home.HomeSideEffect.* +import com.idiotfrogs.model.home.Season import com.idiotfrogs.model.home.SeasonBannerResponse import com.idiotfrogs.model.timecapsule.MyTimeCapsuleContent import com.idiotfrogs.model.timecapsule.MyTimeCapsuleResponse import com.idiotfrogs.model.timecapsule.PendingCollaboratorsRequest +import com.idiotfrogs.model.timecapsule.TimeCapsuleRole import com.idiotfrogs.model.timecapsule.TimeCapsuleStatus import com.idiotfrogs.model.timecapsule.TimeCapsuleUnopenedContent import com.idiotfrogs.model.user.ProfileResponse @@ -25,10 +26,13 @@ import com.idiotfrogs.util.sideEffect.RefreshEvent import com.idiotfrogs.util.sideEffect.RefreshSideEffect import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.async +import kotlinx.datetime.TimeZone +import kotlinx.datetime.todayIn import org.orbitmvi.orbit.Container import org.orbitmvi.orbit.viewmodel.container import javax.inject.Inject import kotlin.collections.emptyList +import kotlin.time.Clock @HiltViewModel class HomeViewModel @Inject constructor( @@ -112,6 +116,19 @@ class HomeViewModel @Inject constructor( errorMessage = null, ) } +// reduce { +// state.copy( +// data = latestData.copy( +// user = userResult.getOrNull(), +// beforeBuried = beforeBuriedResult.getOrNull()?.content ?: emptyList(), +// buried = buriedResult.getOrNull()?.content ?: emptyList(), +// seasonBanner = seasonBannerResponse.getOrNull(), +// unopenedBanner = unopenedResponse.getOrNull() +// ), +// isLoading = false, +// errorMessage = null, +// ) +// } } } } @@ -218,12 +235,22 @@ class HomeViewModel @Inject constructor( } } + private fun remindBannerClicked(id: Long) = intent { + // 진입 전 낙관적으로 배너를 업데이트 한다 + reduce { + val latestData = state.data + state.copy(data = latestData?.copy(seasonBanner = null)) + } + postSideEffect(HomeSideEffect.NavigateToDetail(id)) + } + override fun onAction(action: HomeAction) { intent { when (action) { HomeAction.CreateClicked -> postSideEffect(HomeSideEffect.NavigateToCreate) HomeAction.ProfileClicked -> postSideEffect(HomeSideEffect.NavigateToProfile) is HomeAction.TimeCapsuleClicked -> postSideEffect(NavigateToDetail(action.id)) + is HomeAction.RemindBannerClicked -> remindBannerClicked(action.id) is HomeAction.JoinCodeSubmitted -> requestCollaborator(PendingCollaboratorsRequest(action.code)) HomeAction.RefreshHome -> fetchHome() is HomeAction.HomeDetailClicked -> postSideEffect(NavigateToHomeDetail(action.homeDetailType)) @@ -264,6 +291,7 @@ sealed interface HomeAction { data object CreateClicked : HomeAction data object ProfileClicked : HomeAction data class TimeCapsuleClicked(val id: Long) : HomeAction + data class RemindBannerClicked(val id: Long) : HomeAction data class JoinCodeSubmitted(val code: String) : HomeAction data object RefreshHome : HomeAction data object RefreshOpened : HomeAction From fa26c905826302c17f373b1f9c35f2e0b48bc2c7 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Thu, 17 Sep 2026 16:19:04 +0900 Subject: [PATCH 29/31] =?UTF-8?q?:memo:=20::=20stability=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/detail/stability/detail-debug.stability | 3 +-- feature/detail/stability/detail-release.stability | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/feature/detail/stability/detail-debug.stability b/feature/detail/stability/detail-debug.stability index 35618bd1..5fbf4fe5 100644 --- a/feature/detail/stability/detail-debug.stability +++ b/feature/detail/stability/detail-debug.stability @@ -5,12 +5,11 @@ // ./gradlew :detail:stabilityDump @Composable -public fun com.idiotfrogs.detail.DetailRoute(capsuleId: kotlin.Long, refreshHome: kotlin.Boolean, viewModel: com.idiotfrogs.detail.DetailViewModel): kotlin.Unit +public fun com.idiotfrogs.detail.DetailRoute(capsuleId: kotlin.Long, viewModel: com.idiotfrogs.detail.DetailViewModel): kotlin.Unit skippable: false restartable: true params: - capsuleId: STABLE (primitive type) - - refreshHome: STABLE (primitive type) - viewModel: UNSTABLE (has mutable properties or unstable members) @Composable diff --git a/feature/detail/stability/detail-release.stability b/feature/detail/stability/detail-release.stability index 35618bd1..5fbf4fe5 100644 --- a/feature/detail/stability/detail-release.stability +++ b/feature/detail/stability/detail-release.stability @@ -5,12 +5,11 @@ // ./gradlew :detail:stabilityDump @Composable -public fun com.idiotfrogs.detail.DetailRoute(capsuleId: kotlin.Long, refreshHome: kotlin.Boolean, viewModel: com.idiotfrogs.detail.DetailViewModel): kotlin.Unit +public fun com.idiotfrogs.detail.DetailRoute(capsuleId: kotlin.Long, viewModel: com.idiotfrogs.detail.DetailViewModel): kotlin.Unit skippable: false restartable: true params: - capsuleId: STABLE (primitive type) - - refreshHome: STABLE (primitive type) - viewModel: UNSTABLE (has mutable properties or unstable members) @Composable From 8ffe0b77544c2d97aa5c023888e4116fda935bc3 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Thu, 17 Sep 2026 17:12:01 +0900 Subject: [PATCH 30/31] =?UTF-8?q?:memo:=20::=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/idiotfrogs/home/home/HomeViewModel.kt | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt index 04d6a6f1..018c1495 100644 --- a/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt +++ b/feature/home/src/main/java/com/idiotfrogs/home/home/HomeViewModel.kt @@ -116,19 +116,6 @@ class HomeViewModel @Inject constructor( errorMessage = null, ) } -// reduce { -// state.copy( -// data = latestData.copy( -// user = userResult.getOrNull(), -// beforeBuried = beforeBuriedResult.getOrNull()?.content ?: emptyList(), -// buried = buriedResult.getOrNull()?.content ?: emptyList(), -// seasonBanner = seasonBannerResponse.getOrNull(), -// unopenedBanner = unopenedResponse.getOrNull() -// ), -// isLoading = false, -// errorMessage = null, -// ) -// } } } } From b94916923f20ba6d6d8a1a5d29bf0bc2c735bc70 Mon Sep 17 00:00:00 2001 From: hyeonseo Date: Thu, 17 Sep 2026 18:02:16 +0900 Subject: [PATCH 31/31] =?UTF-8?q?:bug:=20::=20pressedColor=20=EB=AA=85?= =?UTF-8?q?=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../profile/component/ProfileWithdrawBottomSheet.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/feature/profile/src/main/java/com/idiotfrogs/profile/component/ProfileWithdrawBottomSheet.kt b/feature/profile/src/main/java/com/idiotfrogs/profile/component/ProfileWithdrawBottomSheet.kt index ab1438f2..65df65df 100644 --- a/feature/profile/src/main/java/com/idiotfrogs/profile/component/ProfileWithdrawBottomSheet.kt +++ b/feature/profile/src/main/java/com/idiotfrogs/profile/component/ProfileWithdrawBottomSheet.kt @@ -48,6 +48,10 @@ fun BoxScope.ProfileWithdrawBottomSheet( } else { Color(0xFFF3BBBB) }, + primaryPressColors = ButtonDefaults.buttonColors( + containerColor = MSTheme.color.red, + disabledContainerColor = Color(0xFFF3BBBB) + ), primaryButtonColors = ButtonDefaults.buttonColors( containerColor = MSTheme.color.red, disabledContainerColor = Color(0xFFF3BBBB)