From 9056f9ce1ea7e0a9aa9ee4e517d99418ed4603e1 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Tue, 26 Dec 2023 20:53:57 +0900 Subject: [PATCH 01/26] feat/#73 : MyInfoScreen UI --- .../com/suwiki/feature/myinfo/MyInfoScreen.kt | 262 +++++++++++++++++- .../main/res/drawable/ic_my_info_comment.xml | 10 + .../main/res/drawable/ic_my_info_notice.xml | 10 + .../main/res/drawable/ic_my_info_point.xml | 14 + .../main/res/drawable/ic_my_info_setting.xml | 10 + .../myinfo/src/main/res/values/strings.xml | 19 ++ 6 files changed, 320 insertions(+), 5 deletions(-) create mode 100644 feature/myinfo/src/main/res/drawable/ic_my_info_comment.xml create mode 100644 feature/myinfo/src/main/res/drawable/ic_my_info_notice.xml create mode 100644 feature/myinfo/src/main/res/drawable/ic_my_info_point.xml create mode 100644 feature/myinfo/src/main/res/drawable/ic_my_info_setting.xml create mode 100644 feature/myinfo/src/main/res/values/strings.xml diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt index 33409b651..45d27fb4b 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt @@ -1,28 +1,280 @@ package com.suwiki.feature.myinfo +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.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.width +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text +import androidx.compose.material3.VerticalDivider 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.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.suwiki.core.designsystem.component.bottomsheet.SuwikiBottomSheetItem +import com.suwiki.core.designsystem.shadow.cardShadow +import com.suwiki.core.designsystem.theme.Black +import com.suwiki.core.designsystem.theme.Gray6A +import com.suwiki.core.designsystem.theme.Gray95 +import com.suwiki.core.designsystem.theme.GrayF6 import com.suwiki.core.designsystem.theme.SuwikiTheme +import com.suwiki.core.designsystem.theme.White +import com.suwiki.core.ui.extension.suwikiClickable +import okhttp3.internal.immutableListOf @Composable fun MyInfoScreen( padding: PaddingValues, + isLogin: Boolean = false, ) { - Text( - modifier = Modifier.padding(padding), - text = "내 정보", + val loginList = immutableListOf( + R.string.my_info_point, + R.string.my_info_ban_history ) + val serviceList = immutableListOf( + R.string.my_info_send_feedback, + R.string.my_info_use_terms, + R.string.my_info_privacy_policy, + R.string.my_info_open_source_library + ) + Column( + modifier = Modifier.padding(padding) + ) { + Box( + modifier = Modifier.background(if (isLogin) GrayF6 else White) + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + if (isLogin) { + LoginMyInfo() + } else { + LogoutMyInfo() + } + Row( + horizontalArrangement = Arrangement.spacedBy(24.dp), + modifier = Modifier + .padding(vertical = 28.dp, horizontal = 41.dp) + .wrapContentWidth() + .height(49.dp) + ) { + MyInfoMenuItem( + title = stringResource(R.string.my_info_notice), + iconId = R.drawable.ic_my_info_notice + ) + VerticalDivider( + modifier = Modifier + .width(1.dp) + .padding(vertical = 5.dp) + ) + MyInfoMenuItem( + title = stringResource(R.string.my_info_contact), + iconId = R.drawable.ic_my_info_comment + ) + VerticalDivider( + modifier = Modifier + .width(1.dp) + .padding(vertical = 5.dp), + ) + MyInfoMenuItem( + title = stringResource(R.string.my_info_account_manage), + iconId = R.drawable.ic_my_info_setting + ) + } + } + } + Column( + modifier = Modifier + .background(White) + .fillMaxSize() + ) { + if (isLogin) { + LazyColumn { + item { + SuwikiBottomSheetItem(title = stringResource(R.string.my_info_my)) + } + items(items = loginList) { title -> + MyInfoListItem(title = stringResource(title)) + } + } + } + LazyColumn { + item { + SuwikiBottomSheetItem(title = stringResource(R.string.my_info_service)) + } + items(items = serviceList) { title -> + MyInfoListItem(title = stringResource(title)) + } + } + } + } +} + +@Composable +fun LogoutMyInfo( + onClickLogin: () -> Unit = {}, +) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(top = 52.dp, start = 24.dp, end = 24.dp) + .background( + color = GrayF6, + shape = RoundedCornerShape(10.dp), + ) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .padding(top = 19.dp, start = 16.dp) + .suwikiClickable(onClick = onClickLogin), + ) { + Text( + text = stringResource(R.string.my_info_login), + style = SuwikiTheme.typography.header2, + color = Black + ) + Image( + painter = painterResource(id = R.drawable.ic_arrow_gray_right), + contentDescription = "", + ) + } + Text( + modifier = Modifier.padding(start = 16.dp, bottom = 19.dp), + text = stringResource(R.string.my_info_check_mine), + style = SuwikiTheme.typography.body4, + color = Gray95, + ) + } +} + +@Composable +fun LoginMyInfo( + onClickMyPost: () -> Unit = {}, +) { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + modifier = Modifier + .fillMaxWidth() + .padding(top = 52.dp, start = 24.dp, end = 24.dp) + .cardShadow() + .background( + color = White, + shape = RoundedCornerShape(10.dp), + ) + ) { + Column { + Text( + modifier = Modifier.padding(top = 19.dp, start = 16.dp), + text = stringResource(R.string.my_info_test_nickname), + style = SuwikiTheme.typography.header2, + color = Black, + ) + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(start = 16.dp, bottom = 19.dp), + ) { + Image( + modifier = Modifier + .padding(end = 4.dp), + painter = painterResource(id = R.drawable.ic_my_info_point), + contentDescription = "", + ) + Text( + text = stringResource(R.string.my_info_test_point), + style = SuwikiTheme.typography.body4, + color = Black, + ) + } + } + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .padding(top = 31.dp, end = 6.dp) + .suwikiClickable(onClick = onClickMyPost), + ) { + Text( + text = stringResource(R.string.my_info_my_post), + style = SuwikiTheme.typography.caption1, + color = Black, + ) + Image( + painter = painterResource(id = R.drawable.ic_arrow_gray_right), + contentDescription = "", + ) + } + } +} + +@Composable +private fun MyInfoMenuItem( + title: String = "", + iconId: Int, + onClickItem: () -> Unit = {}, +) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .suwikiClickable(onClick = onClickItem), + ) { + Image( + painter = painterResource(id = iconId), + contentDescription = "", + ) + Text( + text = title, + style = SuwikiTheme.typography.caption2, + ) + } +} + +@Composable +private fun MyInfoListItem( + title: String = "", + onClick: () -> Unit = {}, +) { + Box( + modifier = Modifier + .background(White) + .fillMaxWidth() + .wrapContentHeight() + .suwikiClickable( + onClick = onClick, + rippleColor = Gray6A, + ), + ) { + Text( + text = title, + style = SuwikiTheme.typography.body2, + modifier = Modifier + .align(Alignment.CenterStart) + .padding(top = 13.dp, bottom = 14.dp, start = 24.dp, end = 52.dp), + ) + } } -@Preview +@Preview(showSystemUi = true) @Composable fun MyInfoScreenScreenPreview() { SuwikiTheme { - MyInfoScreen(padding = PaddingValues(0.dp)) + MyInfoScreen( + padding = PaddingValues(0.dp), + isLogin = true, + ) } } diff --git a/feature/myinfo/src/main/res/drawable/ic_my_info_comment.xml b/feature/myinfo/src/main/res/drawable/ic_my_info_comment.xml new file mode 100644 index 000000000..0ca3c7910 --- /dev/null +++ b/feature/myinfo/src/main/res/drawable/ic_my_info_comment.xml @@ -0,0 +1,10 @@ + + + diff --git a/feature/myinfo/src/main/res/drawable/ic_my_info_notice.xml b/feature/myinfo/src/main/res/drawable/ic_my_info_notice.xml new file mode 100644 index 000000000..6592792f0 --- /dev/null +++ b/feature/myinfo/src/main/res/drawable/ic_my_info_notice.xml @@ -0,0 +1,10 @@ + + + diff --git a/feature/myinfo/src/main/res/drawable/ic_my_info_point.xml b/feature/myinfo/src/main/res/drawable/ic_my_info_point.xml new file mode 100644 index 000000000..db5ee6c6c --- /dev/null +++ b/feature/myinfo/src/main/res/drawable/ic_my_info_point.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/feature/myinfo/src/main/res/drawable/ic_my_info_setting.xml b/feature/myinfo/src/main/res/drawable/ic_my_info_setting.xml new file mode 100644 index 000000000..376568e40 --- /dev/null +++ b/feature/myinfo/src/main/res/drawable/ic_my_info_setting.xml @@ -0,0 +1,10 @@ + + + diff --git a/feature/myinfo/src/main/res/values/strings.xml b/feature/myinfo/src/main/res/values/strings.xml new file mode 100644 index 000000000..072ee6c77 --- /dev/null +++ b/feature/myinfo/src/main/res/values/strings.xml @@ -0,0 +1,19 @@ + + + suwikikiki + 180 + 내 포인트 + 이용제한 내역 + 피드백 전송 + 이용약관 + 개인정보처리방침 + 오픈소스 라이선스 + 공지사항 + 문의하기 + 계정관리 + My + 서비스 + 로그인하세요 + 내 글과 포인트, 구매 내역을 확인해 보세요. + 내 글 관리 + From 920620740ae2b45417c5026a64c1700addc7d230 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Wed, 27 Dec 2023 01:02:24 +0900 Subject: [PATCH 02/26] feat/#73 : NoticeScreen UI --- .../com/suwiki/feature/notice/NoticeScreen.kt | 101 ++++++++++++++++++ .../notice/src/main/res/values/strings.xml | 4 + 2 files changed, 105 insertions(+) create mode 100644 feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt create mode 100644 feature/notice/src/main/res/values/strings.xml diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt new file mode 100644 index 000000000..cee9f7e9e --- /dev/null +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt @@ -0,0 +1,101 @@ +package com.suwiki.feature.notice + +import android.annotation.SuppressLint +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.Icon +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.suwiki.core.designsystem.component.container.SuwikiNoticeContainer +import com.suwiki.core.designsystem.theme.Gray95 +import com.suwiki.core.designsystem.theme.SuwikiTheme +import com.suwiki.core.designsystem.theme.White +import com.suwiki.core.ui.extension.suwikiClickable +import okhttp3.internal.immutableListOf + +@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") +@Composable +fun NoticeScreen() { + // TODO REMOVE + val sampleNoticeTitle = immutableListOf( + "회원가입 필독", + "2023년 04월 17일 데이터베이스 문제", + "개인정보 처리방침 개정 안내", + "아이폰 유저 시간표 반영 주의사항" + ) + Scaffold( + topBar = { NoticeScreenAppBar(title = stringResource(R.string.notice)) }, + content = { appBarPadding -> + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(appBarPadding) + .background(White) + ) { + items(items = sampleNoticeTitle) { title -> + SuwikiNoticeContainer( + titleText = title, + dateText = "2023.04.17", + onClick = { /*TODO*/ } + ) + } + } + }, + ) +} + +@Composable +private fun NoticeScreenAppBar( + title: String = "", + onClickBack: () -> Unit = {}, +) { + Row( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .background(White) + .padding(top = 15.dp, bottom = 15.dp, start = 18.dp, end = 24.dp), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Icon( + painter = painterResource(id = R.drawable.ic_appbar_arrow_left), + contentDescription = "", + tint = Gray95, + modifier = Modifier + .size(24.dp) + .clip(CircleShape) + .suwikiClickable(onClick = onClickBack) + .padding(vertical = 2.dp, horizontal = 6.5.dp), + ) + Text( + text = title, + style = SuwikiTheme.typography.header6, + ) + Spacer(modifier = Modifier.size(24.dp)) + } +} + +@Preview +@Composable +fun NoticeScreenPreview() { + SuwikiTheme { + NoticeScreen() + } +} diff --git a/feature/notice/src/main/res/values/strings.xml b/feature/notice/src/main/res/values/strings.xml new file mode 100644 index 000000000..17ab86898 --- /dev/null +++ b/feature/notice/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + 공지사항 + From e4e96ef553224506a13dd9a986949b87aec36435 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Wed, 27 Dec 2023 01:55:08 +0900 Subject: [PATCH 03/26] feat/#73 : NoticeDetailScreen UI --- .../feature/notice/NoticeDetailScreen.kt | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt new file mode 100644 index 000000000..1a26b1b73 --- /dev/null +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt @@ -0,0 +1,145 @@ +package com.suwiki.feature.notice + +import androidx.compose.foundation.background +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.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.Icon +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +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.drawBehind +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.suwiki.core.designsystem.theme.Black +import com.suwiki.core.designsystem.theme.Gray95 +import com.suwiki.core.designsystem.theme.GrayF6 +import com.suwiki.core.designsystem.theme.SuwikiTheme +import com.suwiki.core.designsystem.theme.White +import com.suwiki.core.ui.extension.suwikiClickable + +@Composable +fun NoticeDetailScreen( + title: String, + date: String, + content: String, +) { + Scaffold( + topBar = { + NoticeDetailScreenAppBar() + }, + content = { appBarPadding -> + Column( + modifier = Modifier + .padding(appBarPadding) + .background(White) + .fillMaxSize() + ) { + NoticeDetailTitleContainer( + modifier = Modifier + .drawBehind { + drawLine( + color = GrayF6, + Offset(0f, size.height), + Offset(size.width, size.height), + strokeWidth = 4.dp.toPx() + ) + }, + title = title, + date = date, + ) + Spacer(modifier = Modifier.height(24.dp)) + Text( + modifier = Modifier + .padding(24.dp), + text = content, + style = SuwikiTheme.typography.body7 + ) + } + }, + ) +} + +@Composable +private fun NoticeDetailScreenAppBar( + onClickBack: () -> Unit = {}, +) { + Box( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .background(White) + .padding(top = 15.dp, bottom = 15.dp, start = 18.dp), + ) { + Icon( + painter = painterResource(id = R.drawable.ic_appbar_arrow_left), + contentDescription = "", + tint = Gray95, + modifier = Modifier + .size(24.dp) + .clip(CircleShape) + .suwikiClickable(onClick = onClickBack) + .padding(vertical = 2.dp, horizontal = 6.5.dp) + .align(Alignment.CenterStart), + ) + } +} + +@Composable +private fun NoticeDetailTitleContainer( + modifier: Modifier = Modifier, + title: String = "", + date: String = "", +) { + Column( + modifier = modifier + .fillMaxWidth() + .background(White) + .padding(24.dp, 15.dp), + ) { + Text( + text = title, + style = SuwikiTheme.typography.header6, + color = Black, + ) + Spacer(modifier = Modifier.height(2.dp)) + Text( + text = date, + style = SuwikiTheme.typography.caption6, + color = Gray95, + ) + } +} + +@Preview +@Composable +fun NoticeDetailScreenPreview() { + SuwikiTheme { + NoticeDetailScreen( + title = "2023년 04월 17일 데이터베이스 문제", + date = "2023.04.17", + content = "데이터 베이스의 불문명현 원인으로 인해 특정 되돌리는 풀백을 수행했습니다. \n" + + "\n" + + "이로 인해 회원가입을 진행해주셨으나 회원가입 처리가 \n" + + "되어있지 않는 현상 및 \n" + + "강의평가 시험정보 작성을 하였으나 등록되지 않는 \n" + + "경우가 발생할 수 있습니다\n" + + "\n" + + "양해부탁드립니다. \n" + + "\n" + + "감사합니다." + ) + } +} From 6c2a3791061cde4e2fa7e79249016c341766809a Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Wed, 27 Dec 2023 17:56:04 +0900 Subject: [PATCH 04/26] =?UTF-8?q?feat/#73=20:=20my=20=ED=99=88=20->=20Noti?= =?UTF-8?q?ce=20->=20NoticeDetail=20=EC=9D=B4=EB=8F=99=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/suwiki/feature/myinfo/MyInfoScreen.kt | 17 +++++++- ...ationNavigation.kt => MyInfoNavigation.kt} | 8 +++- .../suwiki/feature/navigator/MainNavigator.kt | 10 +++++ .../suwiki/feature/navigator/MainScreen.kt | 7 +++ .../feature/notice/NoticeDetailScreen.kt | 2 +- .../com/suwiki/feature/notice/NoticeScreen.kt | 21 +++++++-- .../notice/navigation/NoticeNavigation.kt | 43 +++++++++++++++++++ 7 files changed, 100 insertions(+), 8 deletions(-) rename feature/myinfo/src/main/java/com/suwiki/feature/myinfo/navigation/{LectureEvaluationNavigation.kt => MyInfoNavigation.kt} (76%) create mode 100644 feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt index 45d27fb4b..601a9c986 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt @@ -37,10 +37,21 @@ import com.suwiki.core.designsystem.theme.White import com.suwiki.core.ui.extension.suwikiClickable import okhttp3.internal.immutableListOf +@Composable +fun MyInfoRoute( + padding: PaddingValues, + navigateNotice: () -> Unit, +) { + MyInfoScreen( + padding = padding, + navigateNotice = navigateNotice, + ) +} @Composable fun MyInfoScreen( padding: PaddingValues, - isLogin: Boolean = false, + isLogin: Boolean = true, + navigateNotice: () -> Unit, ) { val loginList = immutableListOf( R.string.my_info_point, @@ -75,7 +86,8 @@ fun MyInfoScreen( ) { MyInfoMenuItem( title = stringResource(R.string.my_info_notice), - iconId = R.drawable.ic_my_info_notice + iconId = R.drawable.ic_my_info_notice, + onClickItem = navigateNotice, ) VerticalDivider( modifier = Modifier @@ -275,6 +287,7 @@ fun MyInfoScreenScreenPreview() { MyInfoScreen( padding = PaddingValues(0.dp), isLogin = true, + navigateNotice = {}, ) } } diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/navigation/LectureEvaluationNavigation.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/navigation/MyInfoNavigation.kt similarity index 76% rename from feature/myinfo/src/main/java/com/suwiki/feature/myinfo/navigation/LectureEvaluationNavigation.kt rename to feature/myinfo/src/main/java/com/suwiki/feature/myinfo/navigation/MyInfoNavigation.kt index 16d59ce58..e46140f19 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/navigation/LectureEvaluationNavigation.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/navigation/MyInfoNavigation.kt @@ -5,7 +5,7 @@ import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import androidx.navigation.compose.composable -import com.suwiki.feature.myinfo.MyInfoScreen +import com.suwiki.feature.myinfo.MyInfoRoute fun NavController.navigateMyInfo(navOptions: NavOptions) { navigate(MyInfoRoute.route, navOptions) @@ -13,9 +13,13 @@ fun NavController.navigateMyInfo(navOptions: NavOptions) { fun NavGraphBuilder.myInfoNavGraph( padding: PaddingValues, + navigateNotice: () -> Unit = {}, ) { composable(route = MyInfoRoute.route) { - MyInfoScreen(padding) + MyInfoRoute( + padding = padding, + navigateNotice = navigateNotice, + ) } } diff --git a/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainNavigator.kt b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainNavigator.kt index 291833e9d..2fe0c3867 100644 --- a/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainNavigator.kt +++ b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainNavigator.kt @@ -10,6 +10,8 @@ import androidx.navigation.compose.rememberNavController import androidx.navigation.navOptions import com.suwiki.feature.lectureevaluation.viewerreporter.navigation.navigateLectureEvaluation import com.suwiki.feature.myinfo.navigation.navigateMyInfo +import com.suwiki.feature.notice.navigation.navigateNotice +import com.suwiki.feature.notice.navigation.navigateNoticeDetail import com.suwiki.feature.timetable.navigation.TimetableRoute import com.suwiki.feature.timetable.navigation.navigateTimetable @@ -43,6 +45,14 @@ internal class MainNavigator( } } + fun navigateNotice() { + navController.navigateNotice() + } + + fun navigateNoticeDetail() { + navController.navigateNoticeDetail() + } + fun popBackStackIfNotHome() { if (!isSameCurrentDestination(TimetableRoute.route)) { navController.popBackStack() diff --git a/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainScreen.kt b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainScreen.kt index 189ba451a..c0ed57ad8 100644 --- a/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainScreen.kt +++ b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainScreen.kt @@ -41,6 +41,7 @@ import com.suwiki.core.designsystem.theme.White import com.suwiki.core.ui.extension.suwikiClickable import com.suwiki.feature.lectureevaluation.viewerreporter.navigation.lectureEvaluationNavGraph import com.suwiki.feature.myinfo.navigation.myInfoNavGraph +import com.suwiki.feature.notice.navigation.noticeNavGraph import com.suwiki.feature.timetable.navigation.timetableNavGraph import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList @@ -96,6 +97,12 @@ internal fun MainScreen( myInfoNavGraph( padding = innerPadding, + navigateNotice = navigator::navigateNotice + ) + + noticeNavGraph( + padding = innerPadding, + navigateNoticeDetail = navigator::navigateNoticeDetail ) } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt index 1a26b1b73..1a776e505 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt @@ -139,7 +139,7 @@ fun NoticeDetailScreenPreview() { "\n" + "양해부탁드립니다. \n" + "\n" + - "감사합니다." + "감사합니다.", ) } } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt index cee9f7e9e..d7bbdcd32 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt @@ -3,6 +3,7 @@ package com.suwiki.feature.notice import android.annotation.SuppressLint import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -30,9 +31,23 @@ import com.suwiki.core.designsystem.theme.White import com.suwiki.core.ui.extension.suwikiClickable import okhttp3.internal.immutableListOf +@Composable +fun NoticeRoute( + padding: PaddingValues, + navigateNoticeDetail: () -> Unit, +) { + NoticeScreen( + padding = padding, + navigateNoticeDetail = navigateNoticeDetail, + ) +} + @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") @Composable -fun NoticeScreen() { +fun NoticeScreen( + padding: PaddingValues, + navigateNoticeDetail: () -> Unit, +) { // TODO REMOVE val sampleNoticeTitle = immutableListOf( "회원가입 필독", @@ -53,7 +68,7 @@ fun NoticeScreen() { SuwikiNoticeContainer( titleText = title, dateText = "2023.04.17", - onClick = { /*TODO*/ } + onClick = navigateNoticeDetail, ) } } @@ -96,6 +111,6 @@ private fun NoticeScreenAppBar( @Composable fun NoticeScreenPreview() { SuwikiTheme { - NoticeScreen() +// NoticeScreen(padding = PaddingValues(0.dp)) } } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt new file mode 100644 index 000000000..b7dda0ec1 --- /dev/null +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt @@ -0,0 +1,43 @@ +package com.suwiki.feature.notice.navigation + +import androidx.compose.foundation.layout.PaddingValues +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable +import com.suwiki.feature.notice.NoticeDetailScreen +import com.suwiki.feature.notice.NoticeRoute + +fun NavController.navigateNotice() { + navigate(NoticeRoute.route) +} + +fun NavController.navigateNoticeDetail() { + navigate(NoticeDetailRoute.route) +} + +fun NavGraphBuilder.noticeNavGraph( + padding: PaddingValues, + navigateNoticeDetail: () -> Unit = {}, +) { + composable(route = NoticeRoute.route) { + NoticeRoute( + padding = padding, + navigateNoticeDetail = navigateNoticeDetail, + ) + } + composable(route = NoticeDetailRoute.route) { + NoticeDetailScreen( + title = "asd", + date = "2030.03.12", + content = "adsasdasd\nsadasd\nasd\n\nasdasd", + ) + } +} + +object NoticeRoute { + const val route = "notice" +} + +object NoticeDetailRoute { + const val route = "notice-detail" +} From 05149e1d626149b8ab07d5725fa972ef6965bf95 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Thu, 28 Dec 2023 01:50:34 +0900 Subject: [PATCH 05/26] =?UTF-8?q?feat/#73=20:MyInfo,=20Notice,=20NoticeDet?= =?UTF-8?q?ail=20=EC=83=81=ED=83=9C=20=EA=B4=80=EB=A6=AC=20TODO(ViewModel?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9=20=EC=8B=9C=20=EB=B0=9C=EC=83=9D=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0=20=ED=95=84?= =?UTF-8?q?=EC=9A=94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../suwiki/feature/myinfo/MyInfoContract.kt | 9 +++ .../com/suwiki/feature/myinfo/MyInfoScreen.kt | 41 ++++++++--- .../suwiki/feature/myinfo/MyInfoViewModel.kt | 36 ++++++++++ .../suwiki/feature/notice/NoticeContract.kt | 9 +++ .../feature/notice/NoticeDetailContract.kt | 9 +++ .../feature/notice/NoticeDetailScreen.kt | 68 +++++++++++++++---- .../feature/notice/NoticeDetailViewModel.kt | 31 +++++++++ .../com/suwiki/feature/notice/NoticeScreen.kt | 20 ++++++ .../suwiki/feature/notice/NoticeViewModel.kt | 32 +++++++++ .../notice/navigation/NoticeNavigation.kt | 7 +- gradle/libs.versions.toml | 2 +- 11 files changed, 236 insertions(+), 28 deletions(-) create mode 100644 feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoContract.kt create mode 100644 feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt create mode 100644 feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt create mode 100644 feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt create mode 100644 feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt create mode 100644 feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoContract.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoContract.kt new file mode 100644 index 000000000..7647dfea8 --- /dev/null +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoContract.kt @@ -0,0 +1,9 @@ +package com.suwiki.feature.myinfo + +data class MyInfoState( + val isLoggedIn: Boolean = false, +) + +sealed interface MyInfoSideEffect { + data object NavigateNotice : MyInfoSideEffect +} diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt index 601a9c986..96d2cc1ce 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt @@ -40,18 +40,37 @@ import okhttp3.internal.immutableListOf @Composable fun MyInfoRoute( padding: PaddingValues, +// viewModel: MyInfoViewModel = hiltViewModel(), navigateNotice: () -> Unit, ) { +// val uiState = viewModel.collectAsState().value +// viewModel.collectSideEffect { sideEffect -> +// when (sideEffect) { +// MyInfoSideEffect.NavigateNotice -> navigateNotice() +// } +// } +// +// LaunchedEffect(key1 = viewModel) { +// viewModel.checkLoggedIn() +// } +// +// MyInfoScreen( +// padding = padding, +// uiState = uiState, +// onClickNoticeButton = { viewModel.navigateNotice() }, +// ) MyInfoScreen( padding = padding, - navigateNotice = navigateNotice, + uiState = MyInfoState(), + onClickNoticeButton = { }, ) } + @Composable fun MyInfoScreen( padding: PaddingValues, - isLogin: Boolean = true, - navigateNotice: () -> Unit, + uiState: MyInfoState, + onClickNoticeButton: () -> Unit, ) { val loginList = immutableListOf( R.string.my_info_point, @@ -67,12 +86,12 @@ fun MyInfoScreen( modifier = Modifier.padding(padding) ) { Box( - modifier = Modifier.background(if (isLogin) GrayF6 else White) + modifier = Modifier.background(if (uiState.isLoggedIn) GrayF6 else White) ) { Column( horizontalAlignment = Alignment.CenterHorizontally ) { - if (isLogin) { + if (uiState.isLoggedIn) { LoginMyInfo() } else { LogoutMyInfo() @@ -87,7 +106,7 @@ fun MyInfoScreen( MyInfoMenuItem( title = stringResource(R.string.my_info_notice), iconId = R.drawable.ic_my_info_notice, - onClickItem = navigateNotice, + onClickItem = onClickNoticeButton, ) VerticalDivider( modifier = Modifier @@ -115,7 +134,7 @@ fun MyInfoScreen( .background(White) .fillMaxSize() ) { - if (isLogin) { + if (uiState.isLoggedIn) { LazyColumn { item { SuwikiBottomSheetItem(title = stringResource(R.string.my_info_my)) @@ -284,9 +303,13 @@ private fun MyInfoListItem( @Composable fun MyInfoScreenScreenPreview() { SuwikiTheme { - MyInfoScreen( +// MyInfoScreen( +// padding = PaddingValues(0.dp), +// uiState = MyInfoState(), +// onClickNoticeButton = {}, +// ) + MyInfoRoute( padding = PaddingValues(0.dp), - isLogin = true, navigateNotice = {}, ) } diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt new file mode 100644 index 000000000..74c6027d4 --- /dev/null +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt @@ -0,0 +1,36 @@ +package com.suwiki.feature.myinfo + +import androidx.lifecycle.ViewModel +import com.suwiki.domain.user.usecase.GetUserInfoUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import org.orbitmvi.orbit.Container +import org.orbitmvi.orbit.ContainerHost +import org.orbitmvi.orbit.syntax.simple.intent +import org.orbitmvi.orbit.syntax.simple.postSideEffect +import org.orbitmvi.orbit.syntax.simple.reduce +import org.orbitmvi.orbit.viewmodel.container +import javax.inject.Inject + +@HiltViewModel +class MyInfoViewModel @Inject constructor( + private val getUserInfoUseCase: GetUserInfoUseCase, +) : ContainerHost, ViewModel() { + override val container: Container = container(MyInfoState()) + + private var isLoggedIn: Boolean = false + + fun checkLoggedIn() { + // TODO(사용자 정보 받아서 로그인 여부 판단하는 로직으로 변경) + + if (isLoggedIn) { + showMyService() + } else { + hideMyService() + } + } + + private fun showMyService() = intent { reduce { state.copy(isLoggedIn = true) } } + private fun hideMyService() = intent { reduce { state.copy(isLoggedIn = false) } } + + fun navigateNotice() = intent { postSideEffect(MyInfoSideEffect.NavigateNotice) } +} diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt new file mode 100644 index 000000000..18c6f50ac --- /dev/null +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt @@ -0,0 +1,9 @@ +package com.suwiki.feature.notice + +data class NoticeState( + val isLoading: Boolean = false, +) + +sealed interface NoticeSideEffect { + data object NavigateNoticeDetail : NoticeSideEffect +} diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt new file mode 100644 index 000000000..66a6e3f13 --- /dev/null +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt @@ -0,0 +1,9 @@ +package com.suwiki.feature.notice + +data class NoticeDetailState( + val isLoading: Boolean = false +) + +sealed interface NoticeDetailSideEffect { + data object NavigateBack : NoticeDetailSideEffect +} diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt index 1a776e505..7a7672f28 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt @@ -3,6 +3,7 @@ package com.suwiki.feature.notice import androidx.compose.foundation.background 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.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -23,6 +24,7 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel import com.suwiki.core.designsystem.theme.Black import com.suwiki.core.designsystem.theme.Gray95 import com.suwiki.core.designsystem.theme.GrayF6 @@ -30,11 +32,49 @@ import com.suwiki.core.designsystem.theme.SuwikiTheme import com.suwiki.core.designsystem.theme.White import com.suwiki.core.ui.extension.suwikiClickable +@Composable +fun NoticeDetailRoute( + padding: PaddingValues, +// viewModel: NoticeDetailViewModel = hiltViewModel(), + navigateBack: () -> Unit = {}, +) { +// val uiState = viewModel.collectAsState().value +// viewModel.collectSideEffect { sideEffect -> +// when (sideEffect) { +// NoticeDetailSideEffect.NavigateBack -> navigateBack() +// } +// } +// +// LaunchedEffect(key1 = viewModel) { +// viewModel.checkNoticeDetailLoaded() +// } +// +// NoticeDetailScreen( +// padding = padding, +// uiState = uiState, +// title = "asd", +// date = "2030.03.12", +// content = "adsasdasd\nsadasd\nasd\n\nasdasd", +// navigateBack = { viewModel.navigateNoticeDetail() } +// ) + NoticeDetailScreen( + padding = padding, + uiState = NoticeDetailState(), + title = "asd", + date = "2030.03.12", + content = "adsasdasd\nsadasd\nasd\n\nasdasd", + navigateBack = navigateBack + ) +} + @Composable fun NoticeDetailScreen( + padding: PaddingValues, + uiState: NoticeDetailState, // TODO(progress bar visible에 사용할 예정) title: String, date: String, content: String, + navigateBack: () -> Unit, ) { Scaffold( topBar = { @@ -127,19 +167,19 @@ private fun NoticeDetailTitleContainer( @Composable fun NoticeDetailScreenPreview() { SuwikiTheme { - NoticeDetailScreen( - title = "2023년 04월 17일 데이터베이스 문제", - date = "2023.04.17", - content = "데이터 베이스의 불문명현 원인으로 인해 특정 되돌리는 풀백을 수행했습니다. \n" + - "\n" + - "이로 인해 회원가입을 진행해주셨으나 회원가입 처리가 \n" + - "되어있지 않는 현상 및 \n" + - "강의평가 시험정보 작성을 하였으나 등록되지 않는 \n" + - "경우가 발생할 수 있습니다\n" + - "\n" + - "양해부탁드립니다. \n" + - "\n" + - "감사합니다.", - ) +// NoticeDetailScreen( +// title = "2023년 04월 17일 데이터베이스 문제", +// date = "2023.04.17", +// content = "데이터 베이스의 불문명현 원인으로 인해 특정 되돌리는 풀백을 수행했습니다. \n" + +// "\n" + +// "이로 인해 회원가입을 진행해주셨으나 회원가입 처리가 \n" + +// "되어있지 않는 현상 및 \n" + +// "강의평가 시험정보 작성을 하였으나 등록되지 않는 \n" + +// "경우가 발생할 수 있습니다\n" + +// "\n" + +// "양해부탁드립니다. \n" + +// "\n" + +// "감사합니다.", +// ) } } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt new file mode 100644 index 000000000..20dedd45f --- /dev/null +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt @@ -0,0 +1,31 @@ +package com.suwiki.feature.notice + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import org.orbitmvi.orbit.Container +import org.orbitmvi.orbit.ContainerHost +import org.orbitmvi.orbit.syntax.simple.intent +import org.orbitmvi.orbit.syntax.simple.postSideEffect +import org.orbitmvi.orbit.syntax.simple.reduce +import org.orbitmvi.orbit.viewmodel.container +import javax.inject.Inject + +@HiltViewModel +class NoticeDetailViewModel @Inject constructor() : ContainerHost, ViewModel() { + override val container: Container = container(NoticeDetailState()) + + private var isLoading: Boolean = false + fun checkNoticeDetailLoaded() { + // TODO(공지사항 상세정보 로딩 완료 확인) + + if (isLoading) { + showProgressBar() + } else { + hideProgressBar() + } + } + + private fun showProgressBar() = intent { reduce { state.copy(isLoading = false) } } + private fun hideProgressBar() = intent { reduce { state.copy(isLoading = true) } } + fun navigateNoticeDetail() = intent { postSideEffect(NoticeDetailSideEffect.NavigateBack) } +} diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt index d7bbdcd32..680acca8c 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt @@ -34,10 +34,29 @@ import okhttp3.internal.immutableListOf @Composable fun NoticeRoute( padding: PaddingValues, +// viewModel: NoticeViewModel = hiltViewModel(), navigateNoticeDetail: () -> Unit, ) { +// val uiState = viewModel.collectAsState().value +// viewModel.collectSideEffect { sideEffect -> +// when (sideEffect) { +// NoticeSideEffect.NavigateNoticeDetail -> navigateNoticeDetail() +// } +// } +// +// LaunchedEffect(key1 = viewModel) { +// viewModel.checkNoticeListLoaded() +// } +// +// NoticeScreen( +// padding = padding, +// uiState = uiState, +// navigateNoticeDetail = { viewModel.navigateNoticeDetail() }, +// ) + NoticeScreen( padding = padding, + uiState = NoticeState(), navigateNoticeDetail = navigateNoticeDetail, ) } @@ -46,6 +65,7 @@ fun NoticeRoute( @Composable fun NoticeScreen( padding: PaddingValues, + uiState: NoticeState, // TODO(progress bar visible에 사용할 예정) navigateNoticeDetail: () -> Unit, ) { // TODO REMOVE diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt new file mode 100644 index 000000000..bf1cddd76 --- /dev/null +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt @@ -0,0 +1,32 @@ +package com.suwiki.feature.notice + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import org.orbitmvi.orbit.Container +import org.orbitmvi.orbit.ContainerHost +import org.orbitmvi.orbit.syntax.simple.intent +import org.orbitmvi.orbit.syntax.simple.postSideEffect +import org.orbitmvi.orbit.syntax.simple.reduce +import org.orbitmvi.orbit.viewmodel.container +import javax.inject.Inject + +@HiltViewModel +class NoticeViewModel @Inject constructor() : ContainerHost, ViewModel() { + + override val container: Container = container(NoticeState()) + + private var isLoading: Boolean = false + fun checkNoticeListLoaded() { + // TODO(공지사항 리스트 로딩 완료 확인) + + if (isLoading) { + showProgressBar() + } else { + hideProgressBar() + } + } + + private fun showProgressBar() = intent { reduce { state.copy(isLoading = false) } } + private fun hideProgressBar() = intent { reduce { state.copy(isLoading = true) } } + fun navigateNoticeDetail() = intent { postSideEffect(NoticeSideEffect.NavigateNoticeDetail) } +} diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt index b7dda0ec1..6b4e40c7f 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable +import com.suwiki.feature.notice.NoticeDetailRoute import com.suwiki.feature.notice.NoticeDetailScreen import com.suwiki.feature.notice.NoticeRoute @@ -26,10 +27,8 @@ fun NavGraphBuilder.noticeNavGraph( ) } composable(route = NoticeDetailRoute.route) { - NoticeDetailScreen( - title = "asd", - date = "2030.03.12", - content = "adsasdasd\nsadasd\nasd\n\nasdasd", + NoticeDetailRoute( + padding = padding, ) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0f34bb570..23399d2a0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -189,7 +189,7 @@ firebase = ["firebase-analytics", "firebase-database"] androidx-lifecycle = ["androidx-lifecycle-runtime-ktx", "androidx-lifecycle-viewmodel-ktx"] androidx-navigation = ["navigation-fragment-ktx", "navigation-ui-ktx"] coroutine = ["kotlinx-coroutines-android", "kotlinx-coroutines-core"] -compose = ["ui", "ui-graphics", "ui-tooling-preview", "material3-compose", "coil-compose", "ui-foundation", "activity-compose", "lifecycle-compose", "navigation-compose"] +compose = ["ui", "ui-graphics", "ui-tooling-preview", "material3-compose", "coil-compose", "ui-foundation", "activity-compose", "lifecycle-compose", "navigation-compose", "hilt-navigation-compose"] compose-debug = ["ui-tooling", "ui-test-manifest"] orbit = ["orbit-core", "orbit-viewmodel", "orbit-compose"] From 49a4524a02fb1555f746cc4b27153eed4bbdc95a Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Thu, 28 Dec 2023 17:44:15 +0900 Subject: [PATCH 06/26] =?UTF-8?q?comment/#73=20:=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20=ED=95=B4=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/suwiki/feature/myinfo/MyInfoScreen.kt | 47 +++++------- .../suwiki/feature/navigator/MainScreen.kt | 5 +- .../feature/notice/NoticeDetailContract.kt | 2 +- .../feature/notice/NoticeDetailScreen.kt | 76 +++++++++---------- .../feature/notice/NoticeDetailViewModel.kt | 2 +- .../com/suwiki/feature/notice/NoticeScreen.kt | 42 +++++----- .../notice/navigation/NoticeNavigation.kt | 3 +- 7 files changed, 87 insertions(+), 90 deletions(-) diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt index 96d2cc1ce..cfff58bda 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt @@ -20,12 +20,14 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel import com.suwiki.core.designsystem.component.bottomsheet.SuwikiBottomSheetItem import com.suwiki.core.designsystem.shadow.cardShadow import com.suwiki.core.designsystem.theme.Black @@ -36,33 +38,30 @@ import com.suwiki.core.designsystem.theme.SuwikiTheme import com.suwiki.core.designsystem.theme.White import com.suwiki.core.ui.extension.suwikiClickable import okhttp3.internal.immutableListOf +import org.orbitmvi.orbit.compose.collectAsState +import org.orbitmvi.orbit.compose.collectSideEffect @Composable fun MyInfoRoute( padding: PaddingValues, -// viewModel: MyInfoViewModel = hiltViewModel(), + viewModel: MyInfoViewModel = hiltViewModel(), navigateNotice: () -> Unit, ) { -// val uiState = viewModel.collectAsState().value -// viewModel.collectSideEffect { sideEffect -> -// when (sideEffect) { -// MyInfoSideEffect.NavigateNotice -> navigateNotice() -// } -// } -// -// LaunchedEffect(key1 = viewModel) { -// viewModel.checkLoggedIn() -// } -// -// MyInfoScreen( -// padding = padding, -// uiState = uiState, -// onClickNoticeButton = { viewModel.navigateNotice() }, -// ) + val uiState = viewModel.collectAsState().value + viewModel.collectSideEffect { sideEffect -> + when (sideEffect) { + MyInfoSideEffect.NavigateNotice -> navigateNotice() + } + } + + LaunchedEffect(key1 = viewModel) { + viewModel.checkLoggedIn() + } + MyInfoScreen( padding = padding, - uiState = MyInfoState(), - onClickNoticeButton = { }, + uiState = uiState, + onClickNoticeButton = { viewModel.navigateNotice() }, ) } @@ -303,14 +302,10 @@ private fun MyInfoListItem( @Composable fun MyInfoScreenScreenPreview() { SuwikiTheme { -// MyInfoScreen( -// padding = PaddingValues(0.dp), -// uiState = MyInfoState(), -// onClickNoticeButton = {}, -// ) - MyInfoRoute( + MyInfoScreen( padding = PaddingValues(0.dp), - navigateNotice = {}, + uiState = MyInfoState(true), + onClickNoticeButton = {}, ) } } diff --git a/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainScreen.kt b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainScreen.kt index 1add1b2f5..d5a46d561 100644 --- a/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainScreen.kt +++ b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainScreen.kt @@ -80,12 +80,13 @@ internal fun MainScreen( myInfoNavGraph( padding = innerPadding, - navigateNotice = navigator::navigateNotice + navigateNotice = navigator::navigateNotice, ) noticeNavGraph( padding = innerPadding, - navigateNoticeDetail = navigator::navigateNoticeDetail + popBackStack = navigator::popBackStackIfNotHome, + navigateNoticeDetail = navigator::navigateNoticeDetail, ) } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt index 66a6e3f13..82c05cb37 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt @@ -5,5 +5,5 @@ data class NoticeDetailState( ) sealed interface NoticeDetailSideEffect { - data object NavigateBack : NoticeDetailSideEffect + data object PopBackStack : NoticeDetailSideEffect } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt index 7a7672f28..a1a2071c3 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt @@ -16,6 +16,7 @@ import androidx.compose.material3.Icon import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -31,39 +32,33 @@ import com.suwiki.core.designsystem.theme.GrayF6 import com.suwiki.core.designsystem.theme.SuwikiTheme import com.suwiki.core.designsystem.theme.White import com.suwiki.core.ui.extension.suwikiClickable +import org.orbitmvi.orbit.compose.collectAsState +import org.orbitmvi.orbit.compose.collectSideEffect @Composable fun NoticeDetailRoute( padding: PaddingValues, -// viewModel: NoticeDetailViewModel = hiltViewModel(), - navigateBack: () -> Unit = {}, + viewModel: NoticeDetailViewModel = hiltViewModel(), + popBackStack: () -> Unit = {}, ) { -// val uiState = viewModel.collectAsState().value -// viewModel.collectSideEffect { sideEffect -> -// when (sideEffect) { -// NoticeDetailSideEffect.NavigateBack -> navigateBack() -// } -// } -// -// LaunchedEffect(key1 = viewModel) { -// viewModel.checkNoticeDetailLoaded() -// } -// -// NoticeDetailScreen( -// padding = padding, -// uiState = uiState, -// title = "asd", -// date = "2030.03.12", -// content = "adsasdasd\nsadasd\nasd\n\nasdasd", -// navigateBack = { viewModel.navigateNoticeDetail() } -// ) + val uiState = viewModel.collectAsState().value + viewModel.collectSideEffect { sideEffect -> + when (sideEffect) { + NoticeDetailSideEffect.PopBackStack -> popBackStack() + } + } + + LaunchedEffect(key1 = viewModel) { + viewModel.checkNoticeDetailLoaded() + } + NoticeDetailScreen( padding = padding, - uiState = NoticeDetailState(), + uiState = uiState, title = "asd", date = "2030.03.12", content = "adsasdasd\nsadasd\nasd\n\nasdasd", - navigateBack = navigateBack + popBackStack = { viewModel.popBackStack() } ) } @@ -74,11 +69,11 @@ fun NoticeDetailScreen( title: String, date: String, content: String, - navigateBack: () -> Unit, + popBackStack: () -> Unit, ) { Scaffold( topBar = { - NoticeDetailScreenAppBar() + NoticeDetailScreenAppBar(onClickBack = popBackStack) }, content = { appBarPadding -> Column( @@ -167,19 +162,22 @@ private fun NoticeDetailTitleContainer( @Composable fun NoticeDetailScreenPreview() { SuwikiTheme { -// NoticeDetailScreen( -// title = "2023년 04월 17일 데이터베이스 문제", -// date = "2023.04.17", -// content = "데이터 베이스의 불문명현 원인으로 인해 특정 되돌리는 풀백을 수행했습니다. \n" + -// "\n" + -// "이로 인해 회원가입을 진행해주셨으나 회원가입 처리가 \n" + -// "되어있지 않는 현상 및 \n" + -// "강의평가 시험정보 작성을 하였으나 등록되지 않는 \n" + -// "경우가 발생할 수 있습니다\n" + -// "\n" + -// "양해부탁드립니다. \n" + -// "\n" + -// "감사합니다.", -// ) + NoticeDetailScreen( + padding = PaddingValues(0.dp), + title = "2023년 04월 17일 데이터베이스 문제", + date = "2023.04.17", + content = "데이터 베이스의 불문명현 원인으로 인해 특정 되돌리는 풀백을 수행했습니다. \n" + + "\n" + + "이로 인해 회원가입을 진행해주셨으나 회원가입 처리가 \n" + + "되어있지 않는 현상 및 \n" + + "강의평가 시험정보 작성을 하였으나 등록되지 않는 \n" + + "경우가 발생할 수 있습니다\n" + + "\n" + + "양해부탁드립니다. \n" + + "\n" + + "감사합니다.", + uiState = NoticeDetailState(), + popBackStack = {}, + ) } } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt index 20dedd45f..34b4d6abe 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt @@ -27,5 +27,5 @@ class NoticeDetailViewModel @Inject constructor() : ContainerHost Unit, ) { -// val uiState = viewModel.collectAsState().value -// viewModel.collectSideEffect { sideEffect -> -// when (sideEffect) { -// NoticeSideEffect.NavigateNoticeDetail -> navigateNoticeDetail() -// } -// } -// -// LaunchedEffect(key1 = viewModel) { -// viewModel.checkNoticeListLoaded() -// } -// -// NoticeScreen( -// padding = padding, -// uiState = uiState, -// navigateNoticeDetail = { viewModel.navigateNoticeDetail() }, -// ) + val uiState = viewModel.collectAsState().value + viewModel.collectSideEffect { sideEffect -> + when (sideEffect) { + NoticeSideEffect.NavigateNoticeDetail -> navigateNoticeDetail() + } + } + + LaunchedEffect(key1 = viewModel) { + viewModel.checkNoticeListLoaded() + } NoticeScreen( padding = padding, - uiState = NoticeState(), - navigateNoticeDetail = navigateNoticeDetail, + uiState = uiState, + navigateNoticeDetail = { viewModel.navigateNoticeDetail() }, ) } @@ -131,6 +129,10 @@ private fun NoticeScreenAppBar( @Composable fun NoticeScreenPreview() { SuwikiTheme { -// NoticeScreen(padding = PaddingValues(0.dp)) + NoticeScreen( + padding = PaddingValues(0.dp), + uiState = NoticeState(), + navigateNoticeDetail = {}, + ) } } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt index 6b4e40c7f..e34f88454 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt @@ -5,7 +5,6 @@ import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable import com.suwiki.feature.notice.NoticeDetailRoute -import com.suwiki.feature.notice.NoticeDetailScreen import com.suwiki.feature.notice.NoticeRoute fun NavController.navigateNotice() { @@ -18,6 +17,7 @@ fun NavController.navigateNoticeDetail() { fun NavGraphBuilder.noticeNavGraph( padding: PaddingValues, + popBackStack: () -> Unit = {}, navigateNoticeDetail: () -> Unit = {}, ) { composable(route = NoticeRoute.route) { @@ -29,6 +29,7 @@ fun NavGraphBuilder.noticeNavGraph( composable(route = NoticeDetailRoute.route) { NoticeDetailRoute( padding = padding, + popBackStack = popBackStack ) } } From 2a9e13ede0bd4352aff08df1d499aa77f344d938 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Thu, 28 Dec 2023 17:48:28 +0900 Subject: [PATCH 07/26] feat/#73 : Notice, NoticeDetail Loading Screen --- .../java/com/suwiki/feature/notice/NoticeDetailScreen.kt | 7 ++++++- .../main/java/com/suwiki/feature/notice/NoticeScreen.kt | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt index a1a2071c3..7fe1b8c51 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import com.suwiki.core.designsystem.component.loading.LoadingScreen import com.suwiki.core.designsystem.theme.Black import com.suwiki.core.designsystem.theme.Gray95 import com.suwiki.core.designsystem.theme.GrayF6 @@ -105,6 +106,10 @@ fun NoticeDetailScreen( } }, ) + + if (uiState.isLoading) { + LoadingScreen() + } } @Composable @@ -176,7 +181,7 @@ fun NoticeDetailScreenPreview() { "양해부탁드립니다. \n" + "\n" + "감사합니다.", - uiState = NoticeDetailState(), + uiState = NoticeDetailState(true), popBackStack = {}, ) } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt index 658181f3b..27c577325 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt @@ -27,6 +27,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.suwiki.core.designsystem.component.container.SuwikiNoticeContainer +import com.suwiki.core.designsystem.component.loading.LoadingScreen import com.suwiki.core.designsystem.theme.Gray95 import com.suwiki.core.designsystem.theme.SuwikiTheme import com.suwiki.core.designsystem.theme.White @@ -92,6 +93,10 @@ fun NoticeScreen( } }, ) + + if (uiState.isLoading) { + LoadingScreen() + } } @Composable @@ -131,7 +136,7 @@ fun NoticeScreenPreview() { SuwikiTheme { NoticeScreen( padding = PaddingValues(0.dp), - uiState = NoticeState(), + uiState = NoticeState(false), navigateNoticeDetail = {}, ) } From 81dbf8c7459727e3a05c31f9711a55883ce254e6 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Thu, 28 Dec 2023 20:40:18 +0900 Subject: [PATCH 08/26] =?UTF-8?q?feat/#73=20:=20UseCase=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 --- .../com/suwiki/core/model/notice/Notice.kt | 6 +-- .../suwiki/core/model/notice/NoticeDetail.kt | 8 ++-- .../com/suwiki/feature/myinfo/MyInfoScreen.kt | 26 +++++----- .../suwiki/feature/myinfo/MyInfoViewModel.kt | 18 ++++--- .../suwiki/feature/notice/NoticeContract.kt | 1 + .../feature/notice/NoticeDetailContract.kt | 2 +- .../feature/notice/NoticeDetailScreen.kt | 22 ++++----- .../feature/notice/NoticeDetailViewModel.kt | 32 +++++++++---- .../com/suwiki/feature/notice/NoticeScreen.kt | 47 +++++++++++-------- .../suwiki/feature/notice/NoticeViewModel.kt | 32 +++++++++---- .../notice/navigation/NoticeNavigation.kt | 3 +- 11 files changed, 117 insertions(+), 80 deletions(-) diff --git a/core/model/src/main/java/com/suwiki/core/model/notice/Notice.kt b/core/model/src/main/java/com/suwiki/core/model/notice/Notice.kt index 9bf48ccf2..34867be7c 100644 --- a/core/model/src/main/java/com/suwiki/core/model/notice/Notice.kt +++ b/core/model/src/main/java/com/suwiki/core/model/notice/Notice.kt @@ -3,7 +3,7 @@ package com.suwiki.core.model.notice import java.time.LocalDateTime data class Notice( - val id: Long, - val title: String, - val date: LocalDateTime?, + val id: Long = 0, + val title: String = "", + val date: LocalDateTime? = null, ) diff --git a/core/model/src/main/java/com/suwiki/core/model/notice/NoticeDetail.kt b/core/model/src/main/java/com/suwiki/core/model/notice/NoticeDetail.kt index 56612fbba..e70c156c4 100644 --- a/core/model/src/main/java/com/suwiki/core/model/notice/NoticeDetail.kt +++ b/core/model/src/main/java/com/suwiki/core/model/notice/NoticeDetail.kt @@ -3,8 +3,8 @@ package com.suwiki.core.model.notice import java.time.LocalDateTime data class NoticeDetail( - val id: Long, - val title: String, - val date: LocalDateTime?, - val content: String, + val id: Long = 0, + val title: String = "", + val date: LocalDateTime? = null, + val content: String = "", ) diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt index cfff58bda..1828fee3a 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt @@ -73,22 +73,22 @@ fun MyInfoScreen( ) { val loginList = immutableListOf( R.string.my_info_point, - R.string.my_info_ban_history + R.string.my_info_ban_history, ) val serviceList = immutableListOf( R.string.my_info_send_feedback, R.string.my_info_use_terms, R.string.my_info_privacy_policy, - R.string.my_info_open_source_library + R.string.my_info_open_source_library, ) Column( - modifier = Modifier.padding(padding) + modifier = Modifier.padding(padding), ) { Box( - modifier = Modifier.background(if (uiState.isLoggedIn) GrayF6 else White) + modifier = Modifier.background(if (uiState.isLoggedIn) GrayF6 else White), ) { Column( - horizontalAlignment = Alignment.CenterHorizontally + horizontalAlignment = Alignment.CenterHorizontally, ) { if (uiState.isLoggedIn) { LoginMyInfo() @@ -100,7 +100,7 @@ fun MyInfoScreen( modifier = Modifier .padding(vertical = 28.dp, horizontal = 41.dp) .wrapContentWidth() - .height(49.dp) + .height(49.dp), ) { MyInfoMenuItem( title = stringResource(R.string.my_info_notice), @@ -110,11 +110,11 @@ fun MyInfoScreen( VerticalDivider( modifier = Modifier .width(1.dp) - .padding(vertical = 5.dp) + .padding(vertical = 5.dp), ) MyInfoMenuItem( title = stringResource(R.string.my_info_contact), - iconId = R.drawable.ic_my_info_comment + iconId = R.drawable.ic_my_info_comment, ) VerticalDivider( modifier = Modifier @@ -123,7 +123,7 @@ fun MyInfoScreen( ) MyInfoMenuItem( title = stringResource(R.string.my_info_account_manage), - iconId = R.drawable.ic_my_info_setting + iconId = R.drawable.ic_my_info_setting, ) } } @@ -131,7 +131,7 @@ fun MyInfoScreen( Column( modifier = Modifier .background(White) - .fillMaxSize() + .fillMaxSize(), ) { if (uiState.isLoggedIn) { LazyColumn { @@ -166,7 +166,7 @@ fun LogoutMyInfo( .background( color = GrayF6, shape = RoundedCornerShape(10.dp), - ) + ), ) { Row( verticalAlignment = Alignment.CenterVertically, @@ -177,7 +177,7 @@ fun LogoutMyInfo( Text( text = stringResource(R.string.my_info_login), style = SuwikiTheme.typography.header2, - color = Black + color = Black, ) Image( painter = painterResource(id = R.drawable.ic_arrow_gray_right), @@ -206,7 +206,7 @@ fun LoginMyInfo( .background( color = White, shape = RoundedCornerShape(10.dp), - ) + ), ) { Column { Text( diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt index 74c6027d4..803099f38 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt @@ -1,8 +1,12 @@ package com.suwiki.feature.myinfo import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.suwiki.domain.user.usecase.GetUserInfoUseCase import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.lastOrNull +import kotlinx.coroutines.launch import org.orbitmvi.orbit.Container import org.orbitmvi.orbit.ContainerHost import org.orbitmvi.orbit.syntax.simple.intent @@ -19,13 +23,15 @@ class MyInfoViewModel @Inject constructor( private var isLoggedIn: Boolean = false - fun checkLoggedIn() { - // TODO(사용자 정보 받아서 로그인 여부 판단하는 로직으로 변경) + suspend fun checkLoggedIn() { + viewModelScope.launch { + isLoggedIn = getUserInfoUseCase().catch { }.lastOrNull()?.isLoggedIn == true - if (isLoggedIn) { - showMyService() - } else { - hideMyService() + if (isLoggedIn) { + showMyService() + } else { + hideMyService() + } } } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt index 18c6f50ac..92a30828c 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt @@ -6,4 +6,5 @@ data class NoticeState( sealed interface NoticeSideEffect { data object NavigateNoticeDetail : NoticeSideEffect + data object PopBackStack : NoticeSideEffect } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt index 82c05cb37..10a3b902f 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt @@ -1,7 +1,7 @@ package com.suwiki.feature.notice data class NoticeDetailState( - val isLoading: Boolean = false + val isLoading: Boolean = false, ) sealed interface NoticeDetailSideEffect { diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt index 7fe1b8c51..73f3d4f3e 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt @@ -16,7 +16,6 @@ import androidx.compose.material3.Icon import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -49,30 +48,27 @@ fun NoticeDetailRoute( } } - LaunchedEffect(key1 = viewModel) { - viewModel.checkNoticeDetailLoaded() - } - NoticeDetailScreen( padding = padding, uiState = uiState, - title = "asd", - date = "2030.03.12", - content = "adsasdasd\nsadasd\nasd\n\nasdasd", - popBackStack = { viewModel.popBackStack() } + title = viewModel.noticeDetail.title, + date = viewModel.noticeDetail.date.toString(), + content = viewModel.noticeDetail.content, + popBackStack = { viewModel.popBackStack() }, ) } @Composable fun NoticeDetailScreen( padding: PaddingValues, - uiState: NoticeDetailState, // TODO(progress bar visible에 사용할 예정) + uiState: NoticeDetailState, title: String, date: String, content: String, popBackStack: () -> Unit, ) { Scaffold( + modifier = Modifier.padding(padding), topBar = { NoticeDetailScreenAppBar(onClickBack = popBackStack) }, @@ -81,7 +77,7 @@ fun NoticeDetailScreen( modifier = Modifier .padding(appBarPadding) .background(White) - .fillMaxSize() + .fillMaxSize(), ) { NoticeDetailTitleContainer( modifier = Modifier @@ -90,7 +86,7 @@ fun NoticeDetailScreen( color = GrayF6, Offset(0f, size.height), Offset(size.width, size.height), - strokeWidth = 4.dp.toPx() + strokeWidth = 4.dp.toPx(), ) }, title = title, @@ -101,7 +97,7 @@ fun NoticeDetailScreen( modifier = Modifier .padding(24.dp), text = content, - style = SuwikiTheme.typography.body7 + style = SuwikiTheme.typography.body7, ) } }, diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt index 34b4d6abe..b6b244cd7 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt @@ -1,7 +1,12 @@ package com.suwiki.feature.notice import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.suwiki.core.model.notice.Notice +import com.suwiki.core.model.notice.NoticeDetail +import com.suwiki.domain.notice.usecase.GetNoticeDetailUseCase import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch import org.orbitmvi.orbit.Container import org.orbitmvi.orbit.ContainerHost import org.orbitmvi.orbit.syntax.simple.intent @@ -11,21 +16,28 @@ import org.orbitmvi.orbit.viewmodel.container import javax.inject.Inject @HiltViewModel -class NoticeDetailViewModel @Inject constructor() : ContainerHost, ViewModel() { +class NoticeDetailViewModel @Inject constructor( + private val getNoticeDetailUseCase: GetNoticeDetailUseCase, +) : ContainerHost, ViewModel() { override val container: Container = container(NoticeDetailState()) - private var isLoading: Boolean = false - fun checkNoticeDetailLoaded() { - // TODO(공지사항 상세정보 로딩 완료 확인) + private var _noticeDetail = NoticeDetail() + val noticeDetail = _noticeDetail - if (isLoading) { - showProgressBar() - } else { - hideProgressBar() + init { + viewModelScope.launch { + getNoticeDetailUseCase(1) + .onSuccess { + _noticeDetail = it + hideProgressBar() + } + .onFailure { + showProgressBar() + } } } - private fun showProgressBar() = intent { reduce { state.copy(isLoading = false) } } - private fun hideProgressBar() = intent { reduce { state.copy(isLoading = true) } } + private fun showProgressBar() = intent { reduce { state.copy(isLoading = true) } } + private fun hideProgressBar() = intent { reduce { state.copy(isLoading = false) } } fun popBackStack() = intent { postSideEffect(NoticeDetailSideEffect.PopBackStack) } } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt index 27c577325..5b1c841a2 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt @@ -18,7 +18,6 @@ import androidx.compose.material3.Icon import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.painterResource @@ -31,32 +30,33 @@ import com.suwiki.core.designsystem.component.loading.LoadingScreen import com.suwiki.core.designsystem.theme.Gray95 import com.suwiki.core.designsystem.theme.SuwikiTheme import com.suwiki.core.designsystem.theme.White +import com.suwiki.core.model.notice.Notice import com.suwiki.core.ui.extension.suwikiClickable -import okhttp3.internal.immutableListOf import org.orbitmvi.orbit.compose.collectAsState import org.orbitmvi.orbit.compose.collectSideEffect +import java.time.LocalDateTime @Composable fun NoticeRoute( padding: PaddingValues, viewModel: NoticeViewModel = hiltViewModel(), navigateNoticeDetail: () -> Unit, + popBackStack: () -> Unit, ) { val uiState = viewModel.collectAsState().value viewModel.collectSideEffect { sideEffect -> when (sideEffect) { NoticeSideEffect.NavigateNoticeDetail -> navigateNoticeDetail() + NoticeSideEffect.PopBackStack -> popBackStack() } } - LaunchedEffect(key1 = viewModel) { - viewModel.checkNoticeListLoaded() - } - NoticeScreen( padding = padding, + noticeList = viewModel.noticeList, uiState = uiState, navigateNoticeDetail = { viewModel.navigateNoticeDetail() }, + popBackStack = { viewModel.popBackStack() }, ) } @@ -64,29 +64,30 @@ fun NoticeRoute( @Composable fun NoticeScreen( padding: PaddingValues, - uiState: NoticeState, // TODO(progress bar visible에 사용할 예정) + noticeList: List, + uiState: NoticeState, navigateNoticeDetail: () -> Unit, + popBackStack: () -> Unit, ) { - // TODO REMOVE - val sampleNoticeTitle = immutableListOf( - "회원가입 필독", - "2023년 04월 17일 데이터베이스 문제", - "개인정보 처리방침 개정 안내", - "아이폰 유저 시간표 반영 주의사항" - ) Scaffold( - topBar = { NoticeScreenAppBar(title = stringResource(R.string.notice)) }, + modifier = Modifier.padding(padding), + topBar = { + NoticeScreenAppBar( + title = stringResource(R.string.notice), + onClickBack = popBackStack, + ) + }, content = { appBarPadding -> LazyColumn( modifier = Modifier .fillMaxSize() .padding(appBarPadding) - .background(White) + .background(White), ) { - items(items = sampleNoticeTitle) { title -> + items(items = noticeList) { notice -> SuwikiNoticeContainer( - titleText = title, - dateText = "2023.04.17", + titleText = notice.title, + dateText = notice.date.toString(), onClick = navigateNoticeDetail, ) } @@ -133,11 +134,19 @@ private fun NoticeScreenAppBar( @Preview @Composable fun NoticeScreenPreview() { + val sampleNoticeList = listOf( + Notice(id = 1, title = "회원가입 필독", date = LocalDateTime.now()), + Notice(id = 2, title = "2023년 04월 17일 데이터베이스 문제", date = LocalDateTime.now()), + Notice(id = 3, title = "개인정보 처리방침 개정 안내", date = LocalDateTime.now()), + Notice(id = 4, title = "아이폰 유저 시간표 반영 주의사항", date = LocalDateTime.now()), + ) SuwikiTheme { NoticeScreen( padding = PaddingValues(0.dp), uiState = NoticeState(false), + noticeList = sampleNoticeList, navigateNoticeDetail = {}, + popBackStack = {}, ) } } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt index bf1cddd76..5547382f0 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt @@ -1,7 +1,11 @@ package com.suwiki.feature.notice import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.suwiki.core.model.notice.Notice +import com.suwiki.domain.notice.usecase.GetNoticeListUseCase import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch import org.orbitmvi.orbit.Container import org.orbitmvi.orbit.ContainerHost import org.orbitmvi.orbit.syntax.simple.intent @@ -11,22 +15,30 @@ import org.orbitmvi.orbit.viewmodel.container import javax.inject.Inject @HiltViewModel -class NoticeViewModel @Inject constructor() : ContainerHost, ViewModel() { +class NoticeViewModel @Inject constructor( + private val getNoticeListUseCase: GetNoticeListUseCase, +) : ContainerHost, ViewModel() { override val container: Container = container(NoticeState()) - private var isLoading: Boolean = false - fun checkNoticeListLoaded() { - // TODO(공지사항 리스트 로딩 완료 확인) + private var _noticeList: List = listOf() + val noticeList = _noticeList - if (isLoading) { - showProgressBar() - } else { - hideProgressBar() + init { + viewModelScope.launch { + getNoticeListUseCase(1) + .onSuccess { notices -> + _noticeList = notices + hideProgressBar() + } + .onFailure { + showProgressBar() + } } } - private fun showProgressBar() = intent { reduce { state.copy(isLoading = false) } } - private fun hideProgressBar() = intent { reduce { state.copy(isLoading = true) } } + private fun showProgressBar() = intent { reduce { state.copy(isLoading = true) } } + private fun hideProgressBar() = intent { reduce { state.copy(isLoading = false) } } fun navigateNoticeDetail() = intent { postSideEffect(NoticeSideEffect.NavigateNoticeDetail) } + fun popBackStack() = intent { postSideEffect(NoticeSideEffect.PopBackStack) } } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt index e34f88454..8ea6b0d04 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/navigation/NoticeNavigation.kt @@ -24,12 +24,13 @@ fun NavGraphBuilder.noticeNavGraph( NoticeRoute( padding = padding, navigateNoticeDetail = navigateNoticeDetail, + popBackStack = popBackStack, ) } composable(route = NoticeDetailRoute.route) { NoticeDetailRoute( padding = padding, - popBackStack = popBackStack + popBackStack = popBackStack, ) } } From 95538fcae728ac918b22031b405d0102fe5500f9 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Thu, 28 Dec 2023 20:41:42 +0900 Subject: [PATCH 09/26] chore/#73 : ktlint --- .../main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt index b6b244cd7..556751c62 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt @@ -2,7 +2,6 @@ package com.suwiki.feature.notice import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.suwiki.core.model.notice.Notice import com.suwiki.core.model.notice.NoticeDetail import com.suwiki.domain.notice.usecase.GetNoticeDetailUseCase import dagger.hilt.android.lifecycle.HiltViewModel From 7c4eaa4c9992b6bc5c34a85ec82e8ef6d815b2bf Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Fri, 29 Dec 2023 02:50:15 +0900 Subject: [PATCH 10/26] =?UTF-8?q?refactor/#73=20:=20MyInfo=20State=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 --- .../java/com/suwiki/feature/myinfo/MyInfoContract.kt | 3 ++- .../java/com/suwiki/feature/myinfo/MyInfoScreen.kt | 10 +++++++--- .../java/com/suwiki/feature/myinfo/MyInfoViewModel.kt | 8 ++++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoContract.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoContract.kt index 7647dfea8..896d2dbc8 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoContract.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoContract.kt @@ -1,7 +1,8 @@ package com.suwiki.feature.myinfo data class MyInfoState( - val isLoggedIn: Boolean = false, + val showMyInfoCard: Boolean = false, + val isLoading: Boolean = false, ) sealed interface MyInfoSideEffect { diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt index 1828fee3a..949908533 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt @@ -29,6 +29,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.suwiki.core.designsystem.component.bottomsheet.SuwikiBottomSheetItem +import com.suwiki.core.designsystem.component.loading.LoadingScreen import com.suwiki.core.designsystem.shadow.cardShadow import com.suwiki.core.designsystem.theme.Black import com.suwiki.core.designsystem.theme.Gray6A @@ -85,12 +86,12 @@ fun MyInfoScreen( modifier = Modifier.padding(padding), ) { Box( - modifier = Modifier.background(if (uiState.isLoggedIn) GrayF6 else White), + modifier = Modifier.background(if (uiState.showMyInfoCard) GrayF6 else White), ) { Column( horizontalAlignment = Alignment.CenterHorizontally, ) { - if (uiState.isLoggedIn) { + if (uiState.showMyInfoCard) { LoginMyInfo() } else { LogoutMyInfo() @@ -133,7 +134,7 @@ fun MyInfoScreen( .background(White) .fillMaxSize(), ) { - if (uiState.isLoggedIn) { + if (uiState.showMyInfoCard) { LazyColumn { item { SuwikiBottomSheetItem(title = stringResource(R.string.my_info_my)) @@ -152,6 +153,9 @@ fun MyInfoScreen( } } } + if (uiState.isLoading) { + LoadingScreen() + } } } diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt index 803099f38..2da726f70 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt @@ -25,6 +25,7 @@ class MyInfoViewModel @Inject constructor( suspend fun checkLoggedIn() { viewModelScope.launch { + showProgressBar() isLoggedIn = getUserInfoUseCase().catch { }.lastOrNull()?.isLoggedIn == true if (isLoggedIn) { @@ -32,11 +33,14 @@ class MyInfoViewModel @Inject constructor( } else { hideMyService() } + hideProgressBar() } } - private fun showMyService() = intent { reduce { state.copy(isLoggedIn = true) } } - private fun hideMyService() = intent { reduce { state.copy(isLoggedIn = false) } } + private fun showMyService() = intent { reduce { state.copy(showMyInfoCard = true) } } + private fun hideMyService() = intent { reduce { state.copy(showMyInfoCard = false) } } + private fun showProgressBar() = intent { reduce { state.copy(isLoading = true) } } + private fun hideProgressBar() = intent { reduce { state.copy(isLoading = false) } } fun navigateNotice() = intent { postSideEffect(MyInfoSideEffect.NavigateNotice) } } From 548c043c87862d02f4bd0c6c1189e7fed69974e2 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Fri, 29 Dec 2023 03:29:34 +0900 Subject: [PATCH 11/26] =?UTF-8?q?fix/#73=20:=20=ED=8F=B0=ED=8A=B8=20?= =?UTF-8?q?=ED=81=AC=EA=B8=B0=EC=97=90=20=EB=94=B0=EB=9D=BC=20MyInfoScreen?= =?UTF-8?q?=20=EB=82=B4=EB=B6=80=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8?= =?UTF-8?q?=EB=93=A4=EC=9D=B4=20=EC=9E=98=EB=A6=AC=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/suwiki/feature/myinfo/MyInfoScreen.kt | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt index 949908533..eaca9e2ad 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt @@ -5,6 +5,7 @@ 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.IntrinsicSize import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize @@ -62,7 +63,7 @@ fun MyInfoRoute( MyInfoScreen( padding = padding, uiState = uiState, - onClickNoticeButton = { viewModel.navigateNotice() }, + onClickNoticeButton = viewModel::navigateNotice, ) } @@ -72,7 +73,7 @@ fun MyInfoScreen( uiState: MyInfoState, onClickNoticeButton: () -> Unit, ) { - val loginList = immutableListOf( + val myList = immutableListOf( R.string.my_info_point, R.string.my_info_ban_history, ) @@ -97,11 +98,11 @@ fun MyInfoScreen( LogoutMyInfo() } Row( - horizontalArrangement = Arrangement.spacedBy(24.dp), + horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier .padding(vertical = 28.dp, horizontal = 41.dp) - .wrapContentWidth() - .height(49.dp), + .fillMaxWidth() + .height(IntrinsicSize.Min), ) { MyInfoMenuItem( title = stringResource(R.string.my_info_notice), @@ -110,8 +111,9 @@ fun MyInfoScreen( ) VerticalDivider( modifier = Modifier - .width(1.dp) .padding(vertical = 5.dp), + thickness = 1.dp, + color = GrayF6, ) MyInfoMenuItem( title = stringResource(R.string.my_info_contact), @@ -119,8 +121,9 @@ fun MyInfoScreen( ) VerticalDivider( modifier = Modifier - .width(1.dp) .padding(vertical = 5.dp), + thickness = 1.dp, + color = GrayF6, ) MyInfoMenuItem( title = stringResource(R.string.my_info_account_manage), @@ -129,26 +132,24 @@ fun MyInfoScreen( } } } - Column( + LazyColumn( modifier = Modifier .background(White) .fillMaxSize(), ) { if (uiState.showMyInfoCard) { - LazyColumn { - item { - SuwikiBottomSheetItem(title = stringResource(R.string.my_info_my)) - } - items(items = loginList) { title -> + item { + SuwikiBottomSheetItem(title = stringResource(R.string.my_info_my)) + + myList.forEach { title -> MyInfoListItem(title = stringResource(title)) } } } - LazyColumn { - item { - SuwikiBottomSheetItem(title = stringResource(R.string.my_info_service)) - } - items(items = serviceList) { title -> + item { + SuwikiBottomSheetItem(title = stringResource(R.string.my_info_service)) + + serviceList.forEach { title -> MyInfoListItem(title = stringResource(title)) } } From 6eae87b62d087d9dc238f08ee6e9cc17eeee439c Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Fri, 29 Dec 2023 03:32:35 +0900 Subject: [PATCH 12/26] rename/#73 : SuwikiBottomSheetItem -> SuwikiMenuItem --- .../component/bottomsheet/SuwikiBottomSheet.kt | 2 +- .../main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/bottomsheet/SuwikiBottomSheet.kt b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/bottomsheet/SuwikiBottomSheet.kt index acbadcd80..f9b4c9638 100644 --- a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/bottomsheet/SuwikiBottomSheet.kt +++ b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/bottomsheet/SuwikiBottomSheet.kt @@ -45,7 +45,7 @@ fun SuwikiBottomSheet( } @Composable -fun SuwikiBottomSheetItem( +fun SuwikiMenuItem( modifier: Modifier = Modifier, title: String, ) { diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt index eaca9e2ad..7fd6762fa 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt @@ -12,11 +12,8 @@ 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.width import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.material3.VerticalDivider @@ -29,7 +26,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel -import com.suwiki.core.designsystem.component.bottomsheet.SuwikiBottomSheetItem +import com.suwiki.core.designsystem.component.bottomsheet.SuwikiMenuItem import com.suwiki.core.designsystem.component.loading.LoadingScreen import com.suwiki.core.designsystem.shadow.cardShadow import com.suwiki.core.designsystem.theme.Black @@ -139,7 +136,7 @@ fun MyInfoScreen( ) { if (uiState.showMyInfoCard) { item { - SuwikiBottomSheetItem(title = stringResource(R.string.my_info_my)) + SuwikiMenuItem(title = stringResource(R.string.my_info_my)) myList.forEach { title -> MyInfoListItem(title = stringResource(title)) @@ -147,7 +144,7 @@ fun MyInfoScreen( } } item { - SuwikiBottomSheetItem(title = stringResource(R.string.my_info_service)) + SuwikiMenuItem(title = stringResource(R.string.my_info_service)) serviceList.forEach { title -> MyInfoListItem(title = stringResource(title)) From de5b7911c1f4e8fa29500689797831573d55aa5b Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Fri, 29 Dec 2023 03:35:05 +0900 Subject: [PATCH 13/26] rename/#73 : LoginMyInfo, LogoutMyInfo -> LoginMyInfoCard, LogoutMyInfoCard --- .../main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt index 7fd6762fa..285bec617 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt @@ -90,9 +90,9 @@ fun MyInfoScreen( horizontalAlignment = Alignment.CenterHorizontally, ) { if (uiState.showMyInfoCard) { - LoginMyInfo() + LoginMyInfoCard() } else { - LogoutMyInfo() + LogoutMyInfoCard() } Row( horizontalArrangement = Arrangement.SpaceBetween, @@ -158,7 +158,7 @@ fun MyInfoScreen( } @Composable -fun LogoutMyInfo( +fun LogoutMyInfoCard( onClickLogin: () -> Unit = {}, ) { Column( @@ -196,7 +196,7 @@ fun LogoutMyInfo( } @Composable -fun LoginMyInfo( +fun LoginMyInfoCard( onClickMyPost: () -> Unit = {}, ) { Row( From b154a769cc56d3b1076708a7924663b8294a02a1 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Fri, 29 Dec 2023 04:00:04 +0900 Subject: [PATCH 14/26] =?UTF-8?q?refactor/#73=20:=20NoticeDetailScreen=20S?= =?UTF-8?q?caffold=20->=20Column=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../myinfo/src/main/res/values/strings.xml | 2 +- .../feature/notice/NoticeDetailScreen.kt | 65 ++++++++----------- 2 files changed, 28 insertions(+), 39 deletions(-) diff --git a/feature/myinfo/src/main/res/values/strings.xml b/feature/myinfo/src/main/res/values/strings.xml index 072ee6c77..d9c0c4d70 100644 --- a/feature/myinfo/src/main/res/values/strings.xml +++ b/feature/myinfo/src/main/res/values/strings.xml @@ -11,7 +11,7 @@ 공지사항 문의하기 계정관리 - My + MY 서비스 로그인하세요 내 글과 포인트, 구매 내역을 확인해 보세요. diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt index 73f3d4f3e..79ba84d7b 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.Scaffold import androidx.compose.material3.Text @@ -19,8 +20,6 @@ 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.drawBehind -import androidx.compose.ui.geometry.Offset import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -54,7 +53,7 @@ fun NoticeDetailRoute( title = viewModel.noticeDetail.title, date = viewModel.noticeDetail.date.toString(), content = viewModel.noticeDetail.content, - popBackStack = { viewModel.popBackStack() }, + popBackStack = viewModel::popBackStack, ) } @@ -67,42 +66,32 @@ fun NoticeDetailScreen( content: String, popBackStack: () -> Unit, ) { - Scaffold( - modifier = Modifier.padding(padding), - topBar = { - NoticeDetailScreenAppBar(onClickBack = popBackStack) - }, - content = { appBarPadding -> - Column( - modifier = Modifier - .padding(appBarPadding) - .background(White) - .fillMaxSize(), - ) { - NoticeDetailTitleContainer( - modifier = Modifier - .drawBehind { - drawLine( - color = GrayF6, - Offset(0f, size.height), - Offset(size.width, size.height), - strokeWidth = 4.dp.toPx(), - ) - }, - title = title, - date = date, - ) - Spacer(modifier = Modifier.height(24.dp)) - Text( - modifier = Modifier - .padding(24.dp), - text = content, - style = SuwikiTheme.typography.body7, - ) - } - }, - ) + Column( + modifier = Modifier + .padding(padding) + .background(White) + .fillMaxSize() + ) { + NoticeDetailScreenAppBar(onClickBack = popBackStack) + Column { + NoticeDetailTitleContainer( + title = title, + date = date, + ) + HorizontalDivider( + thickness = 4.dp, + color = GrayF6, + ) + Spacer(modifier = Modifier.height(24.dp)) + Text( + modifier = Modifier + .padding(24.dp), + text = content, + style = SuwikiTheme.typography.body7, + ) + } + } if (uiState.isLoading) { LoadingScreen() } From e244dad9429eeebbeca0af830eae50b880fc1726 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Fri, 29 Dec 2023 04:18:50 +0900 Subject: [PATCH 15/26] refactor/#73 : SuwikiAppBarWithTitle --- .../component/appbar/SuwikiAppBarWithTitle.kt | 53 ++++++++++++------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/appbar/SuwikiAppBarWithTitle.kt b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/appbar/SuwikiAppBarWithTitle.kt index a0ccb0ed6..3669dd9a9 100644 --- a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/appbar/SuwikiAppBarWithTitle.kt +++ b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/appbar/SuwikiAppBarWithTitle.kt @@ -3,6 +3,7 @@ package com.suwiki.core.designsystem.component.appbar import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -28,6 +29,8 @@ fun SuwikiAppBarWithTitle( title: String = "", onClickBack: () -> Unit = {}, onClickRemove: () -> Unit = {}, + enabledBack: Boolean, + enabledRemove: Boolean, ) { Row( modifier = modifier @@ -37,30 +40,38 @@ fun SuwikiAppBarWithTitle( .padding(top = 15.dp, bottom = 15.dp, start = 18.dp, end = 24.dp), horizontalArrangement = Arrangement.SpaceBetween, ) { - Icon( - painter = painterResource(id = R.drawable.ic_appbar_arrow_left), - contentDescription = "", - tint = Gray95, - modifier = Modifier - .size(24.dp) - .clip(CircleShape) - .suwikiClickable(onClick = onClickBack) - .padding(vertical = 2.dp, horizontal = 6.5.dp), - ) + if (enabledBack) { + Icon( + painter = painterResource(id = R.drawable.ic_appbar_arrow_left), + contentDescription = "", + tint = Gray95, + modifier = Modifier + .size(24.dp) + .clip(CircleShape) + .suwikiClickable(onClick = onClickBack) + .padding(vertical = 2.dp, horizontal = 6.5.dp), + ) + } else { + Spacer(modifier = Modifier.size(24.dp)) + } Text( text = title, style = SuwikiTheme.typography.header6, ) - Icon( - painter = painterResource(id = R.drawable.ic_appbar_close_mark), - contentDescription = "", - tint = Gray95, - modifier = Modifier - .size(24.dp) - .clip(CircleShape) - .suwikiClickable(onClick = onClickRemove) - .padding(3.dp), - ) + if (enabledRemove) { + Icon( + painter = painterResource(id = R.drawable.ic_appbar_close_mark), + contentDescription = "", + tint = Gray95, + modifier = Modifier + .size(24.dp) + .clip(CircleShape) + .suwikiClickable(onClick = onClickRemove) + .padding(3.dp), + ) + } else { + Spacer(modifier = Modifier.size(24.dp)) + } } } @@ -72,6 +83,8 @@ fun SuwikiAppBarPreview() { title = "타이틀", onClickBack = { /*TODO*/ }, onClickRemove = { /*TODO*/ }, + enabledBack = true, + enabledRemove = true, ) } } From d2e0fcdf661e34abade127aba6020f5d3379b48f Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Fri, 29 Dec 2023 04:20:48 +0900 Subject: [PATCH 16/26] refactor/#73 : NoticeDetailScreen AppBar --- .../feature/notice/NoticeDetailScreen.kt | 43 +++---------------- 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt index 79ba84d7b..552f26c50 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt @@ -1,7 +1,6 @@ package com.suwiki.feature.notice import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer @@ -9,28 +8,20 @@ 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.wrapContentHeight -import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon -import androidx.compose.material3.Scaffold import androidx.compose.material3.Text 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.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import com.suwiki.core.designsystem.component.appbar.SuwikiAppBarWithTitle import com.suwiki.core.designsystem.component.loading.LoadingScreen import com.suwiki.core.designsystem.theme.Black import com.suwiki.core.designsystem.theme.Gray95 import com.suwiki.core.designsystem.theme.GrayF6 import com.suwiki.core.designsystem.theme.SuwikiTheme import com.suwiki.core.designsystem.theme.White -import com.suwiki.core.ui.extension.suwikiClickable import org.orbitmvi.orbit.compose.collectAsState import org.orbitmvi.orbit.compose.collectSideEffect @@ -72,7 +63,12 @@ fun NoticeDetailScreen( .background(White) .fillMaxSize() ) { - NoticeDetailScreenAppBar(onClickBack = popBackStack) + SuwikiAppBarWithTitle( + title = "", + onClickBack = popBackStack, + enabledBack = true, + enabledRemove = false, + ) Column { NoticeDetailTitleContainer( @@ -97,31 +93,6 @@ fun NoticeDetailScreen( } } -@Composable -private fun NoticeDetailScreenAppBar( - onClickBack: () -> Unit = {}, -) { - Box( - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight() - .background(White) - .padding(top = 15.dp, bottom = 15.dp, start = 18.dp), - ) { - Icon( - painter = painterResource(id = R.drawable.ic_appbar_arrow_left), - contentDescription = "", - tint = Gray95, - modifier = Modifier - .size(24.dp) - .clip(CircleShape) - .suwikiClickable(onClick = onClickBack) - .padding(vertical = 2.dp, horizontal = 6.5.dp) - .align(Alignment.CenterStart), - ) - } -} - @Composable private fun NoticeDetailTitleContainer( modifier: Modifier = Modifier, From a76a209d4685a19e8f1422bb008344fb59d951c2 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Fri, 29 Dec 2023 04:31:20 +0900 Subject: [PATCH 17/26] refactor/#73 : NoticeScreen --- .../com/suwiki/feature/notice/NoticeScreen.kt | 95 +++++-------------- 1 file changed, 24 insertions(+), 71 deletions(-) diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt index 5b1c841a2..320b97a56 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt @@ -2,36 +2,24 @@ package com.suwiki.feature.notice import android.annotation.SuppressLint import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.Icon -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import com.suwiki.core.designsystem.component.appbar.SuwikiAppBarWithTitle import com.suwiki.core.designsystem.component.container.SuwikiNoticeContainer import com.suwiki.core.designsystem.component.loading.LoadingScreen -import com.suwiki.core.designsystem.theme.Gray95 import com.suwiki.core.designsystem.theme.SuwikiTheme import com.suwiki.core.designsystem.theme.White import com.suwiki.core.model.notice.Notice -import com.suwiki.core.ui.extension.suwikiClickable import org.orbitmvi.orbit.compose.collectAsState import org.orbitmvi.orbit.compose.collectSideEffect import java.time.LocalDateTime @@ -56,7 +44,7 @@ fun NoticeRoute( noticeList = viewModel.noticeList, uiState = uiState, navigateNoticeDetail = { viewModel.navigateNoticeDetail() }, - popBackStack = { viewModel.popBackStack() }, + popBackStack = viewModel::popBackStack, ) } @@ -69,65 +57,30 @@ fun NoticeScreen( navigateNoticeDetail: () -> Unit, popBackStack: () -> Unit, ) { - Scaffold( - modifier = Modifier.padding(padding), - topBar = { - NoticeScreenAppBar( - title = stringResource(R.string.notice), - onClickBack = popBackStack, - ) - }, - content = { appBarPadding -> - LazyColumn( - modifier = Modifier - .fillMaxSize() - .padding(appBarPadding) - .background(White), - ) { - items(items = noticeList) { notice -> - SuwikiNoticeContainer( - titleText = notice.title, - dateText = notice.date.toString(), - onClick = navigateNoticeDetail, - ) - } - } - }, - ) - - if (uiState.isLoading) { - LoadingScreen() - } -} - -@Composable -private fun NoticeScreenAppBar( - title: String = "", - onClickBack: () -> Unit = {}, -) { - Row( + Column( modifier = Modifier - .fillMaxWidth() - .wrapContentHeight() - .background(White) - .padding(top = 15.dp, bottom = 15.dp, start = 18.dp, end = 24.dp), - horizontalArrangement = Arrangement.SpaceBetween, + .padding(padding) + .fillMaxSize() + .background(White), ) { - Icon( - painter = painterResource(id = R.drawable.ic_appbar_arrow_left), - contentDescription = "", - tint = Gray95, - modifier = Modifier - .size(24.dp) - .clip(CircleShape) - .suwikiClickable(onClick = onClickBack) - .padding(vertical = 2.dp, horizontal = 6.5.dp), - ) - Text( - text = title, - style = SuwikiTheme.typography.header6, + SuwikiAppBarWithTitle( + title = stringResource(R.string.notice), + onClickBack = popBackStack, + enabledBack = true, + enabledRemove = false, ) - Spacer(modifier = Modifier.size(24.dp)) + LazyColumn { + items(items = noticeList) { notice -> + SuwikiNoticeContainer( + titleText = notice.title, + dateText = notice.date.toString(), + onClick = navigateNoticeDetail, + ) + } + } + if (uiState.isLoading) { + LoadingScreen() + } } } From 4b8f1c2c62e524831490ab289bccd37944c90b60 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Fri, 29 Dec 2023 18:52:12 +0900 Subject: [PATCH 18/26] refactor/#73 : MyInfoScreen LazyColumn -> Column --- .../com/suwiki/feature/myinfo/MyInfoScreen.kt | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt index 285bec617..cc2bb5989 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt @@ -1,6 +1,7 @@ package com.suwiki.feature.myinfo import androidx.compose.foundation.Image +import androidx.compose.foundation.ScrollState import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -13,8 +14,9 @@ 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.foundation.lazy.LazyColumn +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Text import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.Composable @@ -46,6 +48,7 @@ fun MyInfoRoute( viewModel: MyInfoViewModel = hiltViewModel(), navigateNotice: () -> Unit, ) { + val scrollState = rememberScrollState() val uiState = viewModel.collectAsState().value viewModel.collectSideEffect { sideEffect -> when (sideEffect) { @@ -60,6 +63,7 @@ fun MyInfoRoute( MyInfoScreen( padding = padding, uiState = uiState, + scrollState = scrollState, onClickNoticeButton = viewModel::navigateNotice, ) } @@ -68,6 +72,7 @@ fun MyInfoRoute( fun MyInfoScreen( padding: PaddingValues, uiState: MyInfoState, + scrollState: ScrollState, onClickNoticeButton: () -> Unit, ) { val myList = immutableListOf( @@ -129,26 +134,23 @@ fun MyInfoScreen( } } } - LazyColumn( + Column( modifier = Modifier .background(White) - .fillMaxSize(), + .fillMaxSize() + .verticalScroll(scrollState), ) { if (uiState.showMyInfoCard) { - item { - SuwikiMenuItem(title = stringResource(R.string.my_info_my)) + SuwikiMenuItem(title = stringResource(R.string.my_info_my)) - myList.forEach { title -> - MyInfoListItem(title = stringResource(title)) - } + myList.forEach { title -> + MyInfoListItem(title = stringResource(title)) } } - item { - SuwikiMenuItem(title = stringResource(R.string.my_info_service)) + SuwikiMenuItem(title = stringResource(R.string.my_info_service)) - serviceList.forEach { title -> - MyInfoListItem(title = stringResource(title)) - } + serviceList.forEach { title -> + MyInfoListItem(title = stringResource(title)) } } if (uiState.isLoading) { @@ -303,10 +305,13 @@ private fun MyInfoListItem( @Preview(showSystemUi = true) @Composable fun MyInfoScreenScreenPreview() { + val scrollState = rememberScrollState() + SuwikiTheme { MyInfoScreen( padding = PaddingValues(0.dp), uiState = MyInfoState(true), + scrollState = scrollState, onClickNoticeButton = {}, ) } From c7940f4553a3c32fc3b3dec22de2e95571dc21d2 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Fri, 29 Dec 2023 21:08:43 +0900 Subject: [PATCH 19/26] =?UTF-8?q?refactor/#73=20:=20ViewModel=20init=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=A0=9C=EA=B1=B0,=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD,=20uiState=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../suwiki/feature/myinfo/MyInfoViewModel.kt | 8 ++++---- .../suwiki/feature/notice/NoticeContract.kt | 4 ++++ .../feature/notice/NoticeDetailContract.kt | 3 +++ .../feature/notice/NoticeDetailScreen.kt | 11 ++++++++--- .../feature/notice/NoticeDetailViewModel.kt | 18 +++++++----------- .../com/suwiki/feature/notice/NoticeScreen.kt | 7 ++++++- .../suwiki/feature/notice/NoticeViewModel.kt | 16 ++++++---------- 7 files changed, 38 insertions(+), 29 deletions(-) diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt index 2da726f70..d363adc70 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoViewModel.kt @@ -25,7 +25,7 @@ class MyInfoViewModel @Inject constructor( suspend fun checkLoggedIn() { viewModelScope.launch { - showProgressBar() + showLoadingScreen() isLoggedIn = getUserInfoUseCase().catch { }.lastOrNull()?.isLoggedIn == true if (isLoggedIn) { @@ -33,14 +33,14 @@ class MyInfoViewModel @Inject constructor( } else { hideMyService() } - hideProgressBar() + hideLoadingScreen() } } private fun showMyService() = intent { reduce { state.copy(showMyInfoCard = true) } } private fun hideMyService() = intent { reduce { state.copy(showMyInfoCard = false) } } - private fun showProgressBar() = intent { reduce { state.copy(isLoading = true) } } - private fun hideProgressBar() = intent { reduce { state.copy(isLoading = false) } } + private fun showLoadingScreen() = intent { reduce { state.copy(isLoading = true) } } + private fun hideLoadingScreen() = intent { reduce { state.copy(isLoading = false) } } fun navigateNotice() = intent { postSideEffect(MyInfoSideEffect.NavigateNotice) } } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt index 92a30828c..417f0c06a 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt @@ -1,7 +1,11 @@ package com.suwiki.feature.notice +import com.suwiki.core.model.notice.Notice + data class NoticeState( val isLoading: Boolean = false, + val noticeList: List = listOf(), + ) sealed interface NoticeSideEffect { diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt index 10a3b902f..cf4a19a70 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt @@ -1,7 +1,10 @@ package com.suwiki.feature.notice +import com.suwiki.core.model.notice.NoticeDetail + data class NoticeDetailState( val isLoading: Boolean = false, + val noticeDetail: NoticeDetail = NoticeDetail() ) sealed interface NoticeDetailSideEffect { diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt index 552f26c50..7a8f470ff 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -38,12 +39,16 @@ fun NoticeDetailRoute( } } + LaunchedEffect(key1 = viewModel) { + viewModel.loadNoticeDetail() + } + NoticeDetailScreen( padding = padding, uiState = uiState, - title = viewModel.noticeDetail.title, - date = viewModel.noticeDetail.date.toString(), - content = viewModel.noticeDetail.content, + title = uiState.noticeDetail.title, + date = uiState.noticeDetail.date.toString(), + content = uiState.noticeDetail.content, popBackStack = viewModel::popBackStack, ) } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt index 556751c62..22c785772 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt @@ -2,7 +2,6 @@ package com.suwiki.feature.notice import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.suwiki.core.model.notice.NoticeDetail import com.suwiki.domain.notice.usecase.GetNoticeDetailUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch @@ -20,23 +19,20 @@ class NoticeDetailViewModel @Inject constructor( ) : ContainerHost, ViewModel() { override val container: Container = container(NoticeDetailState()) - private var _noticeDetail = NoticeDetail() - val noticeDetail = _noticeDetail - - init { + suspend fun loadNoticeDetail() { viewModelScope.launch { getNoticeDetailUseCase(1) - .onSuccess { - _noticeDetail = it - hideProgressBar() + .onSuccess { noticeDetail -> + intent { reduce { state.copy(noticeDetail = noticeDetail) } } + hideLoadingScreen() } .onFailure { - showProgressBar() + showLoadingScreen() } } } - private fun showProgressBar() = intent { reduce { state.copy(isLoading = true) } } - private fun hideProgressBar() = intent { reduce { state.copy(isLoading = false) } } + private fun showLoadingScreen() = intent { reduce { state.copy(isLoading = true) } } + private fun hideLoadingScreen() = intent { reduce { state.copy(isLoading = false) } } fun popBackStack() = intent { postSideEffect(NoticeDetailSideEffect.PopBackStack) } } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt index 320b97a56..bfab81b5f 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -39,9 +40,13 @@ fun NoticeRoute( } } + LaunchedEffect(key1 = viewModel) { + viewModel.loadNoticeList() + } + NoticeScreen( padding = padding, - noticeList = viewModel.noticeList, + noticeList = uiState.noticeList, uiState = uiState, navigateNoticeDetail = { viewModel.navigateNoticeDetail() }, popBackStack = viewModel::popBackStack, diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt index 5547382f0..d77cd71eb 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt @@ -2,7 +2,6 @@ package com.suwiki.feature.notice import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.suwiki.core.model.notice.Notice import com.suwiki.domain.notice.usecase.GetNoticeListUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch @@ -21,24 +20,21 @@ class NoticeViewModel @Inject constructor( override val container: Container = container(NoticeState()) - private var _noticeList: List = listOf() - val noticeList = _noticeList - - init { + suspend fun loadNoticeList() { viewModelScope.launch { getNoticeListUseCase(1) .onSuccess { notices -> - _noticeList = notices - hideProgressBar() + intent { reduce { state.copy(noticeList = notices) } } + hideLoadingScreen() } .onFailure { - showProgressBar() + showLoadingScreen() } } } - private fun showProgressBar() = intent { reduce { state.copy(isLoading = true) } } - private fun hideProgressBar() = intent { reduce { state.copy(isLoading = false) } } + private fun showLoadingScreen() = intent { reduce { state.copy(isLoading = true) } } + private fun hideLoadingScreen() = intent { reduce { state.copy(isLoading = false) } } fun navigateNoticeDetail() = intent { postSideEffect(NoticeSideEffect.NavigateNoticeDetail) } fun popBackStack() = intent { postSideEffect(NoticeSideEffect.PopBackStack) } } From 1ba12a608bdd198e6c114b198b651d28336cbca5 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Fri, 29 Dec 2023 21:11:53 +0900 Subject: [PATCH 20/26] chore/#73 : ktlint --- .../main/java/com/suwiki/feature/notice/NoticeDetailContract.kt | 2 +- .../main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt index cf4a19a70..5ff138fe5 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt @@ -4,7 +4,7 @@ import com.suwiki.core.model.notice.NoticeDetail data class NoticeDetailState( val isLoading: Boolean = false, - val noticeDetail: NoticeDetail = NoticeDetail() + val noticeDetail: NoticeDetail = NoticeDetail(), ) sealed interface NoticeDetailSideEffect { diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt index 7a8f470ff..19d8e8ff9 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt @@ -66,7 +66,7 @@ fun NoticeDetailScreen( modifier = Modifier .padding(padding) .background(White) - .fillMaxSize() + .fillMaxSize(), ) { SuwikiAppBarWithTitle( title = "", From 279852840198a82cac0f0c23997441f384e7489c Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Sat, 30 Dec 2023 15:40:29 +0900 Subject: [PATCH 21/26] =?UTF-8?q?refactor/#73=20:=2075=EB=B2=88=20?= =?UTF-8?q?=EB=B8=8C=EB=9E=9C=EC=B9=98=20SuwikiAppBarWithTitle=EB=A1=9C=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/appbar/SuwikiAppBarWithTitle.kt | 57 +++++++++---------- .../feature/notice/NoticeDetailScreen.kt | 4 +- .../com/suwiki/feature/notice/NoticeScreen.kt | 4 +- 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/appbar/SuwikiAppBarWithTitle.kt b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/appbar/SuwikiAppBarWithTitle.kt index 3669dd9a9..d88e32763 100644 --- a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/appbar/SuwikiAppBarWithTitle.kt +++ b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/appbar/SuwikiAppBarWithTitle.kt @@ -1,9 +1,7 @@ package com.suwiki.core.designsystem.component.appbar import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -12,6 +10,7 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Icon import androidx.compose.material3.Text 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.res.painterResource @@ -26,51 +25,53 @@ import com.suwiki.core.ui.extension.suwikiClickable @Composable fun SuwikiAppBarWithTitle( modifier: Modifier = Modifier, - title: String = "", + title: String? = null, + showCloseIcon: Boolean = true, + showBackIcon: Boolean = true, onClickBack: () -> Unit = {}, - onClickRemove: () -> Unit = {}, - enabledBack: Boolean, - enabledRemove: Boolean, + onClickClose: () -> Unit = {}, ) { - Row( + Box( modifier = modifier .fillMaxWidth() .wrapContentHeight() .background(White) .padding(top = 15.dp, bottom = 15.dp, start = 18.dp, end = 24.dp), - horizontalArrangement = Arrangement.SpaceBetween, ) { - if (enabledBack) { + if (showBackIcon) { Icon( - painter = painterResource(id = R.drawable.ic_appbar_arrow_left), - contentDescription = "", - tint = Gray95, modifier = Modifier + .align(Alignment.CenterStart) .size(24.dp) .clip(CircleShape) .suwikiClickable(onClick = onClickBack) .padding(vertical = 2.dp, horizontal = 6.5.dp), + painter = painterResource(id = R.drawable.ic_appbar_arrow_left), + contentDescription = "", + tint = Gray95, ) - } else { - Spacer(modifier = Modifier.size(24.dp)) } - Text( - text = title, - style = SuwikiTheme.typography.header6, - ) - if (enabledRemove) { + + if (title != null) { + Text( + modifier = Modifier.align(Alignment.Center), + text = title, + style = SuwikiTheme.typography.header6, + ) + } + + if (showCloseIcon) { Icon( - painter = painterResource(id = R.drawable.ic_appbar_close_mark), - contentDescription = "", - tint = Gray95, modifier = Modifier + .align(Alignment.CenterEnd) .size(24.dp) .clip(CircleShape) - .suwikiClickable(onClick = onClickRemove) + .suwikiClickable(onClick = onClickClose) .padding(3.dp), + painter = painterResource(id = R.drawable.ic_appbar_close_mark), + contentDescription = "", + tint = Gray95, ) - } else { - Spacer(modifier = Modifier.size(24.dp)) } } } @@ -82,9 +83,7 @@ fun SuwikiAppBarPreview() { SuwikiAppBarWithTitle( title = "타이틀", onClickBack = { /*TODO*/ }, - onClickRemove = { /*TODO*/ }, - enabledBack = true, - enabledRemove = true, + onClickClose = { /*TODO*/ }, ) } } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt index 19d8e8ff9..328715c47 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt @@ -71,8 +71,8 @@ fun NoticeDetailScreen( SuwikiAppBarWithTitle( title = "", onClickBack = popBackStack, - enabledBack = true, - enabledRemove = false, + showBackIcon = true, + showCloseIcon = false, ) Column { diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt index bfab81b5f..9d647aa9f 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt @@ -71,8 +71,8 @@ fun NoticeScreen( SuwikiAppBarWithTitle( title = stringResource(R.string.notice), onClickBack = popBackStack, - enabledBack = true, - enabledRemove = false, + showBackIcon = true, + showCloseIcon = false, ) LazyColumn { items(items = noticeList) { notice -> From 7844f0910e41366c595df8d635e1586adcbcac67 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Sat, 30 Dec 2023 16:14:07 +0900 Subject: [PATCH 22/26] =?UTF-8?q?refactor/#73=20:=20Column=20Scroll=20?= =?UTF-8?q?=EB=B2=94=EC=9C=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt index cc2bb5989..73fb35abb 100644 --- a/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt +++ b/feature/myinfo/src/main/java/com/suwiki/feature/myinfo/MyInfoScreen.kt @@ -86,7 +86,9 @@ fun MyInfoScreen( R.string.my_info_open_source_library, ) Column( - modifier = Modifier.padding(padding), + modifier = Modifier + .padding(padding) + .verticalScroll(scrollState), ) { Box( modifier = Modifier.background(if (uiState.showMyInfoCard) GrayF6 else White), @@ -137,8 +139,7 @@ fun MyInfoScreen( Column( modifier = Modifier .background(White) - .fillMaxSize() - .verticalScroll(scrollState), + .fillMaxSize(), ) { if (uiState.showMyInfoCard) { SuwikiMenuItem(title = stringResource(R.string.my_info_my)) From 3814d36fa670e0cc5858ff2d7f56665a93b235c5 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Sat, 30 Dec 2023 17:18:30 +0900 Subject: [PATCH 23/26] =?UTF-8?q?refactor/#73=20:=20noticeList=20type=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 --- .../main/java/com/suwiki/feature/notice/NoticeContract.kt | 5 +++-- .../src/main/java/com/suwiki/feature/notice/NoticeScreen.kt | 6 ++++-- .../main/java/com/suwiki/feature/notice/NoticeViewModel.kt | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt index 417f0c06a..aa2edf332 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeContract.kt @@ -1,11 +1,12 @@ package com.suwiki.feature.notice import com.suwiki.core.model.notice.Notice +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf data class NoticeState( val isLoading: Boolean = false, - val noticeList: List = listOf(), - + val noticeList: PersistentList = persistentListOf(), ) sealed interface NoticeSideEffect { diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt index 9d647aa9f..5391430f7 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeScreen.kt @@ -21,6 +21,8 @@ import com.suwiki.core.designsystem.component.loading.LoadingScreen import com.suwiki.core.designsystem.theme.SuwikiTheme import com.suwiki.core.designsystem.theme.White import com.suwiki.core.model.notice.Notice +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.toPersistentList import org.orbitmvi.orbit.compose.collectAsState import org.orbitmvi.orbit.compose.collectSideEffect import java.time.LocalDateTime @@ -57,7 +59,7 @@ fun NoticeRoute( @Composable fun NoticeScreen( padding: PaddingValues, - noticeList: List, + noticeList: PersistentList, uiState: NoticeState, navigateNoticeDetail: () -> Unit, popBackStack: () -> Unit, @@ -102,7 +104,7 @@ fun NoticeScreenPreview() { NoticeScreen( padding = PaddingValues(0.dp), uiState = NoticeState(false), - noticeList = sampleNoticeList, + noticeList = sampleNoticeList.toPersistentList(), navigateNoticeDetail = {}, popBackStack = {}, ) diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt index d77cd71eb..e3c0fe557 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.suwiki.domain.notice.usecase.GetNoticeListUseCase import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.launch import org.orbitmvi.orbit.Container import org.orbitmvi.orbit.ContainerHost @@ -24,7 +25,7 @@ class NoticeViewModel @Inject constructor( viewModelScope.launch { getNoticeListUseCase(1) .onSuccess { notices -> - intent { reduce { state.copy(noticeList = notices) } } + intent { reduce { state.copy(noticeList = notices.toPersistentList()) } } hideLoadingScreen() } .onFailure { From f16d7bb2aef8334df142434ec6cdd8521fd6776a Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Sat, 30 Dec 2023 17:36:48 +0900 Subject: [PATCH 24/26] =?UTF-8?q?refactor/#73=20:=20noticeDetail=20Stable?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/notice/NoticeDetailContract.kt | 2 + .../feature/notice/NoticeDetailScreen.kt | 46 ++++++++++--------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt index 5ff138fe5..c04ed0650 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailContract.kt @@ -1,9 +1,11 @@ package com.suwiki.feature.notice +import androidx.compose.runtime.Stable import com.suwiki.core.model.notice.NoticeDetail data class NoticeDetailState( val isLoading: Boolean = false, + @Stable val noticeDetail: NoticeDetail = NoticeDetail(), ) diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt index 328715c47..c56f31355 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt @@ -23,8 +23,10 @@ import com.suwiki.core.designsystem.theme.Gray95 import com.suwiki.core.designsystem.theme.GrayF6 import com.suwiki.core.designsystem.theme.SuwikiTheme import com.suwiki.core.designsystem.theme.White +import com.suwiki.core.model.notice.NoticeDetail import org.orbitmvi.orbit.compose.collectAsState import org.orbitmvi.orbit.compose.collectSideEffect +import java.time.LocalDateTime @Composable fun NoticeDetailRoute( @@ -46,9 +48,6 @@ fun NoticeDetailRoute( NoticeDetailScreen( padding = padding, uiState = uiState, - title = uiState.noticeDetail.title, - date = uiState.noticeDetail.date.toString(), - content = uiState.noticeDetail.content, popBackStack = viewModel::popBackStack, ) } @@ -57,9 +56,6 @@ fun NoticeDetailRoute( fun NoticeDetailScreen( padding: PaddingValues, uiState: NoticeDetailState, - title: String, - date: String, - content: String, popBackStack: () -> Unit, ) { Column( @@ -77,8 +73,8 @@ fun NoticeDetailScreen( Column { NoticeDetailTitleContainer( - title = title, - date = date, + title = uiState.noticeDetail.title, + date = uiState.noticeDetail.date.toString(), ) HorizontalDivider( thickness = 4.dp, @@ -88,7 +84,7 @@ fun NoticeDetailScreen( Text( modifier = Modifier .padding(24.dp), - text = content, + text = uiState.noticeDetail.content, style = SuwikiTheme.typography.body7, ) } @@ -127,22 +123,28 @@ private fun NoticeDetailTitleContainer( @Preview @Composable fun NoticeDetailScreenPreview() { + val sampleNoticeDetail = NoticeDetail( + title = "2023년 04월 17일 데이터베이스 문제", + date = LocalDateTime.now(), + content = "데이터 베이스의 불문명현 원인으로 인해 특정 되돌리는 풀백을 수행했습니다. \n" + + "\n" + + "이로 인해 회원가입을 진행해주셨으나 회원가입 처리가 \n" + + "되어있지 않는 현상 및 \n" + + "강의평가 시험정보 작성을 하였으나 등록되지 않는 \n" + + "경우가 발생할 수 있습니다\n" + + "\n" + + "양해부탁드립니다. \n" + + "\n" + + "감사합니다.", + ) SuwikiTheme { NoticeDetailScreen( padding = PaddingValues(0.dp), - title = "2023년 04월 17일 데이터베이스 문제", - date = "2023.04.17", - content = "데이터 베이스의 불문명현 원인으로 인해 특정 되돌리는 풀백을 수행했습니다. \n" + - "\n" + - "이로 인해 회원가입을 진행해주셨으나 회원가입 처리가 \n" + - "되어있지 않는 현상 및 \n" + - "강의평가 시험정보 작성을 하였으나 등록되지 않는 \n" + - "경우가 발생할 수 있습니다\n" + - "\n" + - "양해부탁드립니다. \n" + - "\n" + - "감사합니다.", - uiState = NoticeDetailState(true), + uiState = NoticeDetailState( + isLoading = false, + noticeDetail = + sampleNoticeDetail + ), popBackStack = {}, ) } From e0e6cecb8c914c2dcd36bb410fcc7a6a79ba7919 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Sat, 30 Dec 2023 18:27:05 +0900 Subject: [PATCH 25/26] =?UTF-8?q?feat/#73=20:=20=EC=84=9C=EB=B2=84=20?= =?UTF-8?q?=ED=86=B5=EC=8B=A0=20=EC=8B=A4=ED=8C=A8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/suwiki/feature/notice/NoticeDetailViewModel.kt | 5 ++++- .../main/java/com/suwiki/feature/notice/NoticeViewModel.kt | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt index 22c785772..f640fa8db 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt @@ -2,6 +2,8 @@ package com.suwiki.feature.notice import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.suwiki.core.model.exception.NetworkException +import com.suwiki.core.model.notice.NoticeDetail import com.suwiki.domain.notice.usecase.GetNoticeDetailUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch @@ -21,13 +23,14 @@ class NoticeDetailViewModel @Inject constructor( suspend fun loadNoticeDetail() { viewModelScope.launch { + showLoadingScreen() getNoticeDetailUseCase(1) .onSuccess { noticeDetail -> intent { reduce { state.copy(noticeDetail = noticeDetail) } } hideLoadingScreen() } .onFailure { - showLoadingScreen() + intent { reduce { state.copy(noticeDetail = NoticeDetail()) } } } } } diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt index e3c0fe557..97e387d4a 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt @@ -2,8 +2,11 @@ package com.suwiki.feature.notice import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.suwiki.core.model.notice.Notice import com.suwiki.domain.notice.usecase.GetNoticeListUseCase import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.launch import org.orbitmvi.orbit.Container @@ -22,6 +25,7 @@ class NoticeViewModel @Inject constructor( override val container: Container = container(NoticeState()) suspend fun loadNoticeList() { + showLoadingScreen() viewModelScope.launch { getNoticeListUseCase(1) .onSuccess { notices -> @@ -29,7 +33,7 @@ class NoticeViewModel @Inject constructor( hideLoadingScreen() } .onFailure { - showLoadingScreen() + intent { reduce { state.copy(noticeList = persistentListOf(Notice())) } } } } } From 9e026b0b4ab2f28fad12e1ac8d0602ce71174bb7 Mon Sep 17 00:00:00 2001 From: BEEEAM-J Date: Sat, 30 Dec 2023 18:34:29 +0900 Subject: [PATCH 26/26] chore/#73 : ktlint --- .../main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt | 2 +- .../java/com/suwiki/feature/notice/NoticeDetailViewModel.kt | 1 - .../src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt index c56f31355..8730eed5f 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailScreen.kt @@ -143,7 +143,7 @@ fun NoticeDetailScreenPreview() { uiState = NoticeDetailState( isLoading = false, noticeDetail = - sampleNoticeDetail + sampleNoticeDetail, ), popBackStack = {}, ) diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt index f640fa8db..68fcad6c9 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeDetailViewModel.kt @@ -2,7 +2,6 @@ package com.suwiki.feature.notice import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.suwiki.core.model.exception.NetworkException import com.suwiki.core.model.notice.NoticeDetail import com.suwiki.domain.notice.usecase.GetNoticeDetailUseCase import dagger.hilt.android.lifecycle.HiltViewModel diff --git a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt index 97e387d4a..5d25ff3ee 100644 --- a/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt +++ b/feature/notice/src/main/java/com/suwiki/feature/notice/NoticeViewModel.kt @@ -5,7 +5,6 @@ import androidx.lifecycle.viewModelScope import com.suwiki.core.model.notice.Notice import com.suwiki.domain.notice.usecase.GetNoticeListUseCase import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.launch