diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 05b3f3e..8de65f7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -78,6 +78,8 @@ dependencies { implementation("androidx.constraintlayout:constraintlayout:2.1.4") implementation("androidx.navigation:navigation-fragment-ktx:2.7.7") implementation("androidx.navigation:navigation-ui-ktx:2.7.7") + implementation("androidx.benchmark:benchmark-macro:1.2.4") + implementation("com.google.android.engage:engage-core:1.5.1") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") diff --git a/app/src/main/java/com/example/remind/app/MainActivity.kt b/app/src/main/java/com/example/remind/app/MainActivity.kt index 607a257..aed6403 100644 --- a/app/src/main/java/com/example/remind/app/MainActivity.kt +++ b/app/src/main/java/com/example/remind/app/MainActivity.kt @@ -1,19 +1,12 @@ package com.example.remind.app -import android.graphics.Color import android.os.Bundle import android.util.Log -import android.view.View import androidx.activity.ComponentActivity -import androidx.activity.SystemBarStyle import androidx.activity.compose.setContent -import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.Surface -import androidx.compose.material.TopAppBar import androidx.compose.ui.Modifier -import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen -import androidx.core.view.WindowCompat import com.example.remind.core.designsystem.theme.RemindTheme import com.google.firebase.Firebase import dagger.hilt.android.AndroidEntryPoint @@ -35,15 +28,6 @@ class MainActivity : ComponentActivity() { } } } - //곧 지워질 코드 - Firebase.messaging.token.addOnCompleteListener { task -> - if(!task.isSuccessful) { - Log.e("tagg", "failed") - } else { - val token = task.result - Log.d("taag", "$token") - } - } } } diff --git a/app/src/main/java/com/example/remind/app/Screens.kt b/app/src/main/java/com/example/remind/app/Screens.kt index fa7c3a1..e614690 100644 --- a/app/src/main/java/com/example/remind/app/Screens.kt +++ b/app/src/main/java/com/example/remind/app/Screens.kt @@ -7,6 +7,11 @@ sealed class Screens(val route: String) { object Register: Screens("register") { object Login: Screens("login") object SelectType: Screens("selecttype") + object OnBoardingPatience: Screens("patience_onboarding") + object OnBoardingCheckDoctor: Screens("doctor_1") + object OnBoardingLoadingDoctor: Screens("doctor_2") + object OnBoardingCenter: Screens("center_onboarding") + object OnBoardingFinal: Screens("final_onboarding") } object Doctor: Screens("doctor") { diff --git a/app/src/main/java/com/example/remind/core/common/component/BasicButton.kt b/app/src/main/java/com/example/remind/core/common/component/BasicButton.kt index 3916361..09b36ac 100644 --- a/app/src/main/java/com/example/remind/core/common/component/BasicButton.kt +++ b/app/src/main/java/com/example/remind/core/common/component/BasicButton.kt @@ -9,6 +9,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -18,36 +19,26 @@ import com.example.remind.core.designsystem.theme.RemindTheme fun BasicButton( modifier: Modifier = Modifier, text: String, + RoundedCorner: Dp, backgroundColor: Color, textColor: Color, verticalPadding: Dp, - onClick: () -> Unit + onClick: () -> Unit, + textStyle: TextStyle ) { Button( - modifier = modifier.fillMaxWidth(), + modifier = modifier, onClick = onClick, - shape = RoundedCornerShape(20.dp), + shape = RoundedCornerShape(RoundedCorner), + contentPadding = PaddingValues(vertical = verticalPadding), colors = ButtonDefaults.buttonColors( containerColor = backgroundColor, contentColor = textColor ), - contentPadding = PaddingValues(vertical = verticalPadding), ) { Text( text = text, - style = RemindTheme.typography.c1Medium + style = textStyle ) } } - -@Composable -@Preview -fun BasicButtonPreview() { - BasicButton( - text = "삭제", - backgroundColor = RemindTheme.colors.main_6, - onClick = {}, - verticalPadding = 0.dp, - textColor = RemindTheme.colors.text - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/core/common/component/BasicOnBoardingAppBar.kt b/app/src/main/java/com/example/remind/core/common/component/BasicOnBoardingAppBar.kt new file mode 100644 index 0000000..7e4a9b9 --- /dev/null +++ b/app/src/main/java/com/example/remind/core/common/component/BasicOnBoardingAppBar.kt @@ -0,0 +1,52 @@ +package com.example.remind.core.common.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +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.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.example.remind.R +import com.example.remind.core.designsystem.theme.RemindTheme + +@Composable +fun BasicOnBoardingAppBar( + modifier : Modifier = Modifier, + weight: Float, + title: String +) { + Column( + modifier = modifier.fillMaxWidth() + ) { + Text( + modifier = modifier.padding(top = 20.dp, bottom = 16.dp), + textAlign = TextAlign.Center, + text = title, + style = RemindTheme.typography.b1Bold.copy(color = RemindTheme.colors.text) + ) + Row( + modifier = Modifier + .fillMaxWidth() + ) { + Box( + modifier = modifier + .weight(weight) + .height(4.dp) + .padding(start = 0.dp) + .clip(shape = RoundedCornerShape(23.dp)) + .background(color = RemindTheme.colors.main_6) + ) + Spacer(modifier = modifier.weight(0.7f)) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/core/common/component/BasicTextButton.kt b/app/src/main/java/com/example/remind/core/common/component/BasicTextButton.kt new file mode 100644 index 0000000..9c71b0c --- /dev/null +++ b/app/src/main/java/com/example/remind/core/common/component/BasicTextButton.kt @@ -0,0 +1,53 @@ +package com.example.remind.core.common.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +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.graphics.Color +import androidx.compose.ui.text.PlatformTextStyle +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.LineHeightStyle +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.remind.core.designsystem.theme.Pretendard +import com.example.remind.core.designsystem.theme.RemindTheme + +@Composable +fun BasicTextButton( + modifier: Modifier = Modifier, + backgroundColor: Color, + text: String, + textColor: Color, + onClick: () -> Unit, + verticalPadding: Dp, + enable: Boolean +) { + Box( + modifier = modifier + .fillMaxWidth() + .clip(RoundedCornerShape(12.dp)) + .background(color = backgroundColor) + .clickable( + enabled = enable, + onClick = onClick + ) + ) { + Text( + modifier = modifier + .padding(vertical = verticalPadding), + text = text, + textAlign = TextAlign.Center, + style = RemindTheme.typography.c1Medium.copy(color = textColor) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/core/common/component/MedicineItem.kt b/app/src/main/java/com/example/remind/core/common/component/MedicineItem.kt new file mode 100644 index 0000000..a7329a1 --- /dev/null +++ b/app/src/main/java/com/example/remind/core/common/component/MedicineItem.kt @@ -0,0 +1,108 @@ +package com.example.remind.core.common.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +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.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.remind.R +import com.example.remind.core.designsystem.theme.RemindTheme + +@Composable +fun MedicineItem( + modifier: Modifier = Modifier, + time: String, + score: Float, + doseClick: () -> Unit, + unadministeredClick: () -> Unit, +) { + Box( + modifier = modifier + .background(color = RemindTheme.colors.slate_50, shape = RoundedCornerShape(12.dp)) + ) { + Column( + horizontalAlignment = Alignment.Start, + ) { + Text( + modifier = modifier.padding(start = 12.dp, top = 7.dp), + text = time, + style = RemindTheme.typography.b3Bold.copy(color = RemindTheme.colors.slate_600) + ) + Row( + modifier = modifier.padding( + start = 12.dp, + end = 12.dp, + top = 2.dp, + bottom = 4.dp + ) + ) { + Text( + text = stringResource(id = R.string.중요도), + style = RemindTheme.typography.c3Medium.copy(color = RemindTheme.colors.slate_400) + ) + Spacer(modifier = modifier.width(6.dp)) + StarRatingBar( + rating = score, + onRatingChanged = {} + ) + } + Spacer(modifier = modifier.height(4.dp)) + Row() { + //시간이 정해져있을 경우 바꿔지도록 하기 + Text( + modifier = modifier + .weight(0.5f) + .background( + color = RemindTheme.colors.main_6, + shape = RoundedCornerShape(bottomStart = 12.dp) + ) + .clickable { doseClick }, + text = stringResource(id = R.string.복용), + textAlign= TextAlign.Center, + style = RemindTheme.typography.c1Bold.copy( + color = RemindTheme.colors.white, + lineHeight = 20.sp + ) + ) + Spacer(modifier = modifier.width(2.dp)) + Text( + modifier = modifier + .weight(0.5f) + .background( + color = RemindTheme.colors.main_5, + shape = RoundedCornerShape(bottomEnd = 12.dp) + ) + .clickable { unadministeredClick }, + text = stringResource(id = R.string.미복용), + textAlign= TextAlign.Center, + style = RemindTheme.typography.c1Bold.copy( + color = RemindTheme.colors.white, + lineHeight = 20.sp + ) + ) + } + } + } +} + +@Preview +@Composable +fun ItemPreview() { + //MedicineItem(time = "아침", score= 2.0, doseClick = {}, unadministeredClick = {}) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/core/common/component/StarRatingBar.kt b/app/src/main/java/com/example/remind/core/common/component/StarRatingBar.kt new file mode 100644 index 0000000..b00a519 --- /dev/null +++ b/app/src/main/java/com/example/remind/core/common/component/StarRatingBar.kt @@ -0,0 +1,58 @@ +package com.example.remind.core.common.component + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.selection.selectable +import androidx.compose.foundation.selection.selectableGroup +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import com.example.remind.R +import com.example.remind.core.designsystem.theme.RemindTheme + +@Composable +fun StarRatingBar( + maxStars: Int = 3, + rating: Float, + onRatingChanged: (Float) -> Unit +) { + val density = LocalDensity.current.density + val starSize = (12f * density).dp + val starSpacing = (0.5f * density).dp + + Row( + modifier = Modifier.selectableGroup(), + verticalAlignment = Alignment.CenterVertically + ) { + for (i in 1..maxStars) { + val isSelected = i <= rating + val icon = if (isSelected) R.drawable.ic_star_fill else R.drawable.ic_star_unfill + val iconTintColor = if (isSelected) RemindTheme.colors.main_4 else RemindTheme.colors.slate_200 + Icon( + painter = painterResource(id = icon), + contentDescription = null, + tint = iconTintColor, + modifier = Modifier + .selectable( + selected = isSelected, + onClick = { + onRatingChanged(i.toFloat()) + } + ) + .width(starSize) + .height(starSize) + ) + + if (i < maxStars) { + Spacer(modifier = Modifier.width(starSpacing)) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/core/common/component/StepComponent.kt b/app/src/main/java/com/example/remind/core/common/component/StepComponent.kt new file mode 100644 index 0000000..1fd8d27 --- /dev/null +++ b/app/src/main/java/com/example/remind/core/common/component/StepComponent.kt @@ -0,0 +1,47 @@ +package com.example.remind.core.common.component + +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +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.drawBehind +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.min +import com.example.remind.core.designsystem.theme.RemindTheme +@Composable +fun StepComponent( + modifier: Modifier = Modifier, + text: Int, + backgroundColor: Color, + textColor: Color +) { + Box( + modifier = modifier + .size(28.dp) + .background(color = backgroundColor, shape = RoundedCornerShape(100.dp)), + contentAlignment = Alignment.Center + ) { + Text( + modifier = modifier, + text = text.toString(), + style = RemindTheme.typography.b3Bold.copy(color = textColor) + ) + } +} + +@Preview +@Composable +fun StepComponentPreview() { + StepComponent(text = 1, backgroundColor = RemindTheme.colors.main_6, textColor = RemindTheme.colors.white) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/core/designsystem/theme/RemindColors.kt b/app/src/main/java/com/example/remind/core/designsystem/theme/RemindColors.kt index 5cd0f41..b2743b3 100644 --- a/app/src/main/java/com/example/remind/core/designsystem/theme/RemindColors.kt +++ b/app/src/main/java/com/example/remind/core/designsystem/theme/RemindColors.kt @@ -34,6 +34,7 @@ class RemindColors ( val grayscale_2: Color = Color(0xFFEEEEEE), val grayscale_1: Color = Color(0xFFF3F4F6), val white: Color = Color(0xFFFFFFFF), + val black: Color = Color(0xFF000000), ) diff --git a/app/src/main/java/com/example/remind/core/designsystem/theme/RemindTypography.kt b/app/src/main/java/com/example/remind/core/designsystem/theme/RemindTypography.kt index 62944e7..780e357 100644 --- a/app/src/main/java/com/example/remind/core/designsystem/theme/RemindTypography.kt +++ b/app/src/main/java/com/example/remind/core/designsystem/theme/RemindTypography.kt @@ -308,6 +308,32 @@ data class RemindTypography( trim = LineHeightStyle.Trim.None ) ), + val onBoardingFont: TextStyle = TextStyle( + fontFamily = Pretendard, + fontWeight = FontWeight.Bold, + fontSize = 24.sp, + lineHeight = 48.sp, + platformStyle = PlatformTextStyle( + includeFontPadding = false + ), + lineHeightStyle = LineHeightStyle( + alignment = LineHeightStyle.Alignment.Center, + trim = LineHeightStyle.Trim.None + ) + ), + val onSplashFont: TextStyle = TextStyle( + fontFamily = Pretendard, + fontWeight = FontWeight.SemiBold, + fontSize = 15.sp, + lineHeight = 3.sp, + platformStyle = PlatformTextStyle( + includeFontPadding = false + ), + lineHeightStyle = LineHeightStyle( + alignment = LineHeightStyle.Alignment.Center, + trim = LineHeightStyle.Trim.None + ) + ) ) val LocalTypography = staticCompositionLocalOf { RemindTypography() } diff --git a/app/src/main/java/com/example/remind/core/util/Constants.kt b/app/src/main/java/com/example/remind/core/util/Constants.kt index df7d48a..4b0fa26 100644 --- a/app/src/main/java/com/example/remind/core/util/Constants.kt +++ b/app/src/main/java/com/example/remind/core/util/Constants.kt @@ -9,4 +9,5 @@ object Constants { val ACCESS_TOKEN = stringPreferencesKey("access_token") val REFRESH_TOKEN = stringPreferencesKey("refresh_token") val USER_TYPE = stringPreferencesKey("user_type") + val USER_NAME = stringPreferencesKey("user_name") } \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/data/di/NetworkModule.kt b/app/src/main/java/com/example/remind/data/di/NetworkModule.kt index d7a2868..3dcc884 100644 --- a/app/src/main/java/com/example/remind/data/di/NetworkModule.kt +++ b/app/src/main/java/com/example/remind/data/di/NetworkModule.kt @@ -7,6 +7,8 @@ import com.example.remind.data.network.interceptor.AuthInterceptor import com.example.remind.data.network.service.AuthService import com.example.remind.data.repository.auth.AuthRepository import com.example.remind.data.repository.auth.AuthRepositoryImpl +import com.example.remind.data.repository.auth.TokenRepository +import com.example.remind.data.repository.auth.TokenRepositoryImpl import dagger.Binds import dagger.Module import dagger.Provides @@ -63,5 +65,9 @@ object NetworkModule { @Singleton @Binds abstract fun providesAuthRepository(authRepositoryImpl: AuthRepositoryImpl): AuthRepository + @Singleton + @Binds + abstract fun providesTokenRepository(tokenRepositoryImpl: TokenRepositoryImpl): TokenRepository } + } \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/data/model/CalendarUiModel.kt b/app/src/main/java/com/example/remind/data/model/CalendarUiModel.kt new file mode 100644 index 0000000..baa1459 --- /dev/null +++ b/app/src/main/java/com/example/remind/data/model/CalendarUiModel.kt @@ -0,0 +1,24 @@ +package com.example.remind.data.model + +import android.os.Build +import androidx.annotation.RequiresApi +import java.time.LocalDate +import java.time.format.DateTimeFormatter +import java.util.Date + +data class CalendarUiModel( + val selectedDate: Date, + val visibleDates: List +) { + val startDate: Date = visibleDates.first() + val endDate: Date = visibleDates.last() + + data class Date( + val date: LocalDate, + val isSelected: Boolean, + val isToday: Boolean + ) { + @RequiresApi(Build.VERSION_CODES.O) + val day: String = date.format(DateTimeFormatter.ofPattern("E")) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/data/model/request/OnBoardingRequest.kt b/app/src/main/java/com/example/remind/data/model/request/OnBoardingRequest.kt new file mode 100644 index 0000000..df1d99c --- /dev/null +++ b/app/src/main/java/com/example/remind/data/model/request/OnBoardingRequest.kt @@ -0,0 +1,13 @@ +package com.example.remind.data.model.request + +import kotlinx.serialization.Serializable + +@Serializable +data class OnBoardingRequest( + val centerName: String, + val city: String, + val district: String, + val protectorPhoneNumber: String, + val rolesType: String, + val fcmToken: String +) \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/data/model/response/OnBoardingResponse.kt b/app/src/main/java/com/example/remind/data/model/response/OnBoardingResponse.kt new file mode 100644 index 0000000..d9b0758 --- /dev/null +++ b/app/src/main/java/com/example/remind/data/model/response/OnBoardingResponse.kt @@ -0,0 +1,15 @@ +package com.example.remind.data.model.response + +import kotlinx.serialization.Serializable + +@Serializable +data class OnBoardingResponse( + val code: Int, + val message: String, + val data: SuccessResponse +) +@Serializable +data class SuccessResponse( + val userId: Int, + val roles_type: String +) \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/data/model/response/SocialLoginResponse.kt b/app/src/main/java/com/example/remind/data/model/response/SocialLoginResponse.kt index 14ba968..3fb57cb 100644 --- a/app/src/main/java/com/example/remind/data/model/response/SocialLoginResponse.kt +++ b/app/src/main/java/com/example/remind/data/model/response/SocialLoginResponse.kt @@ -1,14 +1,17 @@ package com.example.remind.data.model.response +import kotlinx.serialization.Serializable + +@Serializable data class SocialLoginResponse( val code: Int, val data: MemberInfo, val message: String ) - +@Serializable data class MemberInfo( val accessToken: String, - val isMemberFinishedOnboarding: Boolean, + val rolesType: String, val name: String, val refreshToken: String ) \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/data/network/interceptor/AuthInterceptor.kt b/app/src/main/java/com/example/remind/data/network/interceptor/AuthInterceptor.kt index fac838d..af1264f 100644 --- a/app/src/main/java/com/example/remind/data/network/interceptor/AuthInterceptor.kt +++ b/app/src/main/java/com/example/remind/data/network/interceptor/AuthInterceptor.kt @@ -41,20 +41,20 @@ class AuthInterceptor @Inject constructor( val originalRequest = chain.request() val authenticationRequest = accessToken?.let { originalRequest.newBuilder() - .addHeader(AUTHORIZATION, it) + .addHeader(AUTHORIZATION, "Bearer $accessToken") .build() } val response = authenticationRequest?.let { chain.proceed(it) } if(response?.code == 401 && refreshToken.isNotEmpty()) { Timber.d("들어옴") - val newToken = runBlocking { updateToken(refreshToken, context) } + val newToken = runBlocking { updateToken(accessToken,refreshToken, context) } if(newToken is ApiResult.Success) { val newAccessToken = newToken.data.data.accessToken val refreshToken = newToken.data.data.refreshToken runBlocking { tokenManager.saveAccessToken(newAccessToken,refreshToken ) } response.close() val newAuthenticationRequest = originalRequest.newBuilder() - .header("X-AUTH-TOKEN", newAccessToken) + .header(AUTHORIZATION, "Bearer $newAccessToken") .build() return chain.proceed(newAuthenticationRequest) } else { @@ -66,13 +66,14 @@ class AuthInterceptor @Inject constructor( } private suspend fun updateToken( + accessToken: String, refreshToken: String, context: Context ): ApiResult { val retrofit = Retrofit.Builder() .baseUrl(BuildConfig.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) - .client(createOkHttpClient(refreshToken, context)) + .client(createOkHttpClient(accessToken, context)) .build() val service = retrofit.create(AuthService::class.java) @@ -96,7 +97,7 @@ private fun createOkHttpClient( .addInterceptor { chain -> val originalRequest = chain.request() val modifiedRequest = originalRequest.newBuilder() - .header(AUTHORIZATION, refreshToken) + .header(AUTHORIZATION, "Bearer $refreshToken") .build() chain.proceed(modifiedRequest) diff --git a/app/src/main/java/com/example/remind/data/network/interceptor/TokenManager.kt b/app/src/main/java/com/example/remind/data/network/interceptor/TokenManager.kt index 8d83e66..05e7874 100644 --- a/app/src/main/java/com/example/remind/data/network/interceptor/TokenManager.kt +++ b/app/src/main/java/com/example/remind/data/network/interceptor/TokenManager.kt @@ -1,10 +1,12 @@ package com.example.remind.data.network.interceptor +import android.util.Log import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import com.example.remind.core.util.Constants.ACCESS_TOKEN import com.example.remind.core.util.Constants.REFRESH_TOKEN +import com.example.remind.core.util.Constants.USER_NAME import com.example.remind.core.util.Constants.USER_TYPE import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map @@ -37,7 +39,18 @@ class TokenManager @Inject constructor( prefs[ACCESS_TOKEN] = accessToken prefs[REFRESH_TOKEN] = refreshToken } - Timber.d("액세스: $accessToken 리프레시: $refreshToken") + Log.d("TokenManager","액세스: $accessToken 리프레시: $refreshToken") + } + + suspend fun saveUserName(userName: String) { + datastore.edit { prefs -> + prefs[USER_NAME] = userName + } + } + fun getUserName(): Flow { + return datastore.data.map { prefs-> + prefs[USER_NAME] + } } suspend fun saveUserType(userType: String) { diff --git a/app/src/main/java/com/example/remind/data/network/service/AuthService.kt b/app/src/main/java/com/example/remind/data/network/service/AuthService.kt index 6a62d15..a8e6227 100644 --- a/app/src/main/java/com/example/remind/data/network/service/AuthService.kt +++ b/app/src/main/java/com/example/remind/data/network/service/AuthService.kt @@ -1,7 +1,9 @@ package com.example.remind.data.network.service import com.example.remind.data.model.request.KakaoLoginRequest +import com.example.remind.data.model.request.OnBoardingRequest import com.example.remind.data.model.request.TokenRequest +import com.example.remind.data.model.response.OnBoardingResponse import com.example.remind.data.model.response.SocialLoginResponse import com.example.remind.data.model.response.TokenResponse import com.example.remind.data.network.adapter.ApiResult @@ -19,4 +21,9 @@ interface AuthService { suspend fun KakaoLogin( @Body body: KakaoLoginRequest ): ApiResult + + @POST("/member/onboarding") + suspend fun OnBoarding( + @Body body: OnBoardingRequest + ): ApiResult } \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/data/repository/CalendarDataSource.kt b/app/src/main/java/com/example/remind/data/repository/CalendarDataSource.kt new file mode 100644 index 0000000..4334077 --- /dev/null +++ b/app/src/main/java/com/example/remind/data/repository/CalendarDataSource.kt @@ -0,0 +1,55 @@ +package com.example.remind.data.repository + +import android.os.Build +import androidx.annotation.RequiresApi +import com.example.remind.data.model.CalendarUiModel +import java.time.DayOfWeek +import java.time.LocalDate +import java.time.temporal.ChronoUnit +import java.util.stream.Collectors +import java.util.stream.Stream + +class CalendarDataSource { + val today: LocalDate + @RequiresApi(Build.VERSION_CODES.O) + get() { + return LocalDate.now() + } + @RequiresApi(Build.VERSION_CODES.O) + fun getData(startDate: LocalDate = today, lastSelectedDate: LocalDate): CalendarUiModel { + val firstDayOfWeek = startDate.with(DayOfWeek.MONDAY) + val endDayOfWeek = firstDayOfWeek.plusDays(7) + val visibleDates = getDateBetween(firstDayOfWeek,endDayOfWeek) + return toUiModel(visibleDates, lastSelectedDate) + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun getDateBetween(startDate: LocalDate, endDate: LocalDate): List { + val numOfDays = ChronoUnit.DAYS.between(startDate, endDate) + return Stream.iterate(startDate) { date -> + date.plusDays(1) + } + .limit(numOfDays) + .collect(Collectors.toList()) + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun toUiModel( + dateList: List, + lastSelectedDate: LocalDate + ): CalendarUiModel { + return CalendarUiModel( + selectedDate = toItemUiModel(lastSelectedDate, true), + visibleDates = dateList.map { + toItemUiModel(it, it.isEqual(lastSelectedDate)) + } + ) + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun toItemUiModel(date: LocalDate, isSelectedDate: Boolean) = CalendarUiModel.Date( + isSelected = isSelectedDate, + isToday = date.isEqual(today), + date = date + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/data/repository/auth/AuthRepository.kt b/app/src/main/java/com/example/remind/data/repository/auth/AuthRepository.kt index 458480f..17666b4 100644 --- a/app/src/main/java/com/example/remind/data/repository/auth/AuthRepository.kt +++ b/app/src/main/java/com/example/remind/data/repository/auth/AuthRepository.kt @@ -1,7 +1,9 @@ package com.example.remind.data.repository.auth import com.example.remind.data.model.request.KakaoLoginRequest +import com.example.remind.data.model.request.OnBoardingRequest import com.example.remind.data.model.request.TokenRequest +import com.example.remind.data.model.response.OnBoardingResponse import com.example.remind.data.model.response.SocialLoginResponse import com.example.remind.data.model.response.TokenResponse import com.example.remind.data.network.adapter.ApiResult @@ -9,4 +11,5 @@ import retrofit2.http.Body interface AuthRepository { suspend fun getTokenFromKakao(body: KakaoLoginRequest): ApiResult + suspend fun postOnBoardingInfo(body: OnBoardingRequest): ApiResult } \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/data/repository/auth/AuthRepositoryImpl.kt b/app/src/main/java/com/example/remind/data/repository/auth/AuthRepositoryImpl.kt index e5cb377..0d77597 100644 --- a/app/src/main/java/com/example/remind/data/repository/auth/AuthRepositoryImpl.kt +++ b/app/src/main/java/com/example/remind/data/repository/auth/AuthRepositoryImpl.kt @@ -1,7 +1,9 @@ package com.example.remind.data.repository.auth import com.example.remind.data.model.request.KakaoLoginRequest +import com.example.remind.data.model.request.OnBoardingRequest import com.example.remind.data.model.request.TokenRequest +import com.example.remind.data.model.response.OnBoardingResponse import com.example.remind.data.model.response.SocialLoginResponse import com.example.remind.data.model.response.TokenResponse import com.example.remind.data.network.adapter.ApiResult @@ -15,4 +17,9 @@ class AuthRepositoryImpl @Inject constructor( override suspend fun getTokenFromKakao(kakaoLoginRequest: KakaoLoginRequest): ApiResult { return service.KakaoLogin(kakaoLoginRequest) } + + override suspend fun postOnBoardingInfo(body: OnBoardingRequest): ApiResult { + return service.OnBoarding(body) + } + } \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/data/repository/auth/TokenRepository.kt b/app/src/main/java/com/example/remind/data/repository/auth/TokenRepository.kt new file mode 100644 index 0000000..848a9e3 --- /dev/null +++ b/app/src/main/java/com/example/remind/data/repository/auth/TokenRepository.kt @@ -0,0 +1,5 @@ +package com.example.remind.data.repository.auth + +interface TokenRepository { + suspend fun getFCMToken(): String +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/data/repository/auth/TokenRepositoryImpl.kt b/app/src/main/java/com/example/remind/data/repository/auth/TokenRepositoryImpl.kt new file mode 100644 index 0000000..45d193c --- /dev/null +++ b/app/src/main/java/com/example/remind/data/repository/auth/TokenRepositoryImpl.kt @@ -0,0 +1,14 @@ +package com.example.remind.data.repository.auth + +import android.util.Log +import com.google.firebase.Firebase +import com.google.firebase.messaging.FirebaseMessaging +import com.google.firebase.messaging.messaging +import kotlinx.coroutines.tasks.await +import javax.inject.Inject + +class TokenRepositoryImpl @Inject constructor(): TokenRepository { + override suspend fun getFCMToken(): String { + return FirebaseMessaging.getInstance().token.await() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/domain/usecase/onboarding_usecase/FcmTokenUseCase.kt b/app/src/main/java/com/example/remind/domain/usecase/onboarding_usecase/FcmTokenUseCase.kt new file mode 100644 index 0000000..58a14b6 --- /dev/null +++ b/app/src/main/java/com/example/remind/domain/usecase/onboarding_usecase/FcmTokenUseCase.kt @@ -0,0 +1,12 @@ +package com.example.remind.domain.usecase.onboarding_usecase + +import com.example.remind.data.repository.auth.TokenRepository +import javax.inject.Inject + +class FcmTokenUseCase @Inject constructor( + private val tokenRepository: TokenRepository +) { + suspend operator fun invoke() : String { + return tokenRepository.getFCMToken() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/domain/usecase/KakaoTokenUseCase.kt b/app/src/main/java/com/example/remind/domain/usecase/onboarding_usecase/KakaoTokenUseCase.kt similarity index 77% rename from app/src/main/java/com/example/remind/domain/usecase/KakaoTokenUseCase.kt rename to app/src/main/java/com/example/remind/domain/usecase/onboarding_usecase/KakaoTokenUseCase.kt index 2e07f05..df4bc89 100644 --- a/app/src/main/java/com/example/remind/domain/usecase/KakaoTokenUseCase.kt +++ b/app/src/main/java/com/example/remind/domain/usecase/onboarding_usecase/KakaoTokenUseCase.kt @@ -1,9 +1,7 @@ -package com.example.remind.domain.usecase +package com.example.remind.domain.usecase.onboarding_usecase import com.example.remind.data.model.request.KakaoLoginRequest -import com.example.remind.data.model.request.TokenRequest import com.example.remind.data.model.response.SocialLoginResponse -import com.example.remind.data.model.response.TokenResponse import com.example.remind.data.network.adapter.ApiResult import com.example.remind.data.repository.auth.AuthRepository import javax.inject.Inject diff --git a/app/src/main/java/com/example/remind/domain/usecase/onboarding_usecase/OnBoardingUserCase.kt b/app/src/main/java/com/example/remind/domain/usecase/onboarding_usecase/OnBoardingUserCase.kt new file mode 100644 index 0000000..21b9a2a --- /dev/null +++ b/app/src/main/java/com/example/remind/domain/usecase/onboarding_usecase/OnBoardingUserCase.kt @@ -0,0 +1,15 @@ +package com.example.remind.domain.usecase.onboarding_usecase + +import com.example.remind.data.model.request.OnBoardingRequest +import com.example.remind.data.model.response.OnBoardingResponse +import com.example.remind.data.network.adapter.ApiResult +import com.example.remind.data.repository.auth.AuthRepository +import javax.inject.Inject + +class OnBoardingUserCase @Inject constructor( + private val authRepository: AuthRepository +) { + suspend operator fun invoke(requestBody: OnBoardingRequest): ApiResult { + return authRepository.postOnBoardingInfo(requestBody) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/domain/usecase/UpdateTokenUseCase.kt b/app/src/main/java/com/example/remind/domain/usecase/onboarding_usecase/UpdateTokenUseCase.kt similarity index 89% rename from app/src/main/java/com/example/remind/domain/usecase/UpdateTokenUseCase.kt rename to app/src/main/java/com/example/remind/domain/usecase/onboarding_usecase/UpdateTokenUseCase.kt index aa14fec..dbba648 100644 --- a/app/src/main/java/com/example/remind/domain/usecase/UpdateTokenUseCase.kt +++ b/app/src/main/java/com/example/remind/domain/usecase/onboarding_usecase/UpdateTokenUseCase.kt @@ -1,4 +1,4 @@ -package com.example.remind.domain.usecase +package com.example.remind.domain.usecase.onboarding_usecase import com.example.remind.data.model.request.TokenRequest import com.example.remind.data.model.response.TokenResponse diff --git a/app/src/main/java/com/example/remind/feature/screens/auth/AuthGraph.kt b/app/src/main/java/com/example/remind/feature/screens/auth/AuthGraph.kt index fc34784..1ef18af 100644 --- a/app/src/main/java/com/example/remind/feature/screens/auth/AuthGraph.kt +++ b/app/src/main/java/com/example/remind/feature/screens/auth/AuthGraph.kt @@ -9,6 +9,11 @@ import com.example.remind.feature.screens.auth.login.LoginViewModel import androidx.hilt.navigation.compose.hiltViewModel import com.example.remind.feature.screens.auth.login.LoginScreen +import com.example.remind.feature.screens.auth.onboarding.OnBoardingCenterScreen +import com.example.remind.feature.screens.auth.onboarding.OnBoardingCheckDoctorScreen +import com.example.remind.feature.screens.auth.onboarding.OnBoardingFinalScreen +import com.example.remind.feature.screens.auth.onboarding.OnBoardingLoadingDoctorScreen +import com.example.remind.feature.screens.auth.onboarding.OnBoardingPatienceScreen import com.example.remind.feature.screens.auth.onboarding.SelectTypeScreen @@ -20,11 +25,25 @@ fun NavGraphBuilder.RegisterGraph( startDestination = Screens.Register.Login.route ) { composable(route = Screens.Register.Login.route) { - val viewModel: LoginViewModel = hiltViewModel() - LoginScreen(viewModel,navHostController) + LoginScreen(navHostController) } composable(route = Screens.Register.SelectType.route) { SelectTypeScreen(navHostController) } + composable(route = Screens.Register.OnBoardingPatience.route) { + OnBoardingPatienceScreen(navHostController) + } + composable(route = Screens.Register.OnBoardingCheckDoctor.route) { + OnBoardingCheckDoctorScreen() + } + composable(route = Screens.Register.OnBoardingLoadingDoctor.route) { + OnBoardingLoadingDoctorScreen() + } + composable(route = Screens.Register.OnBoardingCenter.route) { + OnBoardingCenterScreen() + } + composable(route = Screens.Register.OnBoardingFinal.route) { + OnBoardingFinalScreen(navHostController) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/feature/screens/auth/login/LoginContract.kt b/app/src/main/java/com/example/remind/feature/screens/auth/login/LoginContract.kt index dad21e9..62133d3 100644 --- a/app/src/main/java/com/example/remind/feature/screens/auth/login/LoginContract.kt +++ b/app/src/main/java/com/example/remind/feature/screens/auth/login/LoginContract.kt @@ -8,7 +8,7 @@ import com.example.remind.core.base.UiState class LoginContract { data class State( - val isLoading: Boolean = false + val isLoading: Boolean = false, ): UiState sealed class Event: UiEvent { @@ -20,5 +20,6 @@ class LoginContract { val destinaton: String, val navOptions: NavOptions? = null ): Effect() + data class Toastmessage(val message: String): Effect() } } \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/feature/screens/auth/login/LoginScreen.kt b/app/src/main/java/com/example/remind/feature/screens/auth/login/LoginScreen.kt index d9868f2..5c411a4 100644 --- a/app/src/main/java/com/example/remind/feature/screens/auth/login/LoginScreen.kt +++ b/app/src/main/java/com/example/remind/feature/screens/auth/login/LoginScreen.kt @@ -1,23 +1,47 @@ package com.example.remind.feature.screens.auth.login +import android.content.Context +import android.widget.Toast +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext +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 androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController +import com.example.remind.R +import com.example.remind.core.common.component.BasicButton +import com.example.remind.core.designsystem.theme.RemindTheme +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.collectLatest @Composable fun LoginScreen( - viewModel: LoginViewModel, navController: NavHostController ){ - val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val viewModel: LoginViewModel = hiltViewModel() val effectFlow = viewModel.effect val context = LocalContext.current @@ -27,16 +51,58 @@ fun LoginScreen( is LoginContract.Effect.NavigateTo -> { navController.navigate(effect.destinaton, effect.navOptions) } + is LoginContract.Effect.Toastmessage -> { + Toast.makeText(context, effect.message, Toast.LENGTH_SHORT).show() + } else->{} } } } - Column() { - Button(onClick = { - viewModel.setEvent(LoginContract.Event.KakaoLoginButtonClicked(context)) - }) { - Text(text = "로그인") + RemindTheme { + Column() { + Box( + modifier = Modifier + .fillMaxSize() + ) { + Image( + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight(), + painter = painterResource(R.drawable.img_background), + contentDescription = null, + contentScale = ContentScale.FillBounds + ) + Text( + modifier = Modifier + .align(Alignment.TopStart) + .padding(start = 22.dp, top = 117.dp), + text = stringResource(id = R.string.스스로를_돌아볼_수_있는), + style = RemindTheme.typography.onBoardingFont.copy(color = RemindTheme.colors.white) + ) + Image( + modifier = Modifier + .align(Alignment.TopStart) + .padding(top = 338.dp), + painter = painterResource(R.drawable.ic_loginimg), + contentDescription = null + ) + BasicButton( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.BottomCenter) + .padding(bottom = 32.dp, start = 20.dp, end = 20.dp), + text = stringResource(id = R.string.카카오로_로그인하기), + RoundedCorner = 12.dp, + backgroundColor = Color(0xFFF9E217), + textColor = Color(0xFF13151B), + verticalPadding = 13.dp, + onClick = { + viewModel.setEvent(LoginContract.Event.KakaoLoginButtonClicked(context)) + }, + textStyle = RemindTheme.typography.b2Bold + ) + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/feature/screens/auth/login/LoginViewModel.kt b/app/src/main/java/com/example/remind/feature/screens/auth/login/LoginViewModel.kt index 3d68e8a..c7e355c 100644 --- a/app/src/main/java/com/example/remind/feature/screens/auth/login/LoginViewModel.kt +++ b/app/src/main/java/com/example/remind/feature/screens/auth/login/LoginViewModel.kt @@ -7,9 +7,9 @@ import androidx.navigation.navOptions import com.example.remind.app.Screens import com.example.remind.core.base.BaseViewModel import com.example.remind.data.model.request.KakaoLoginRequest -import com.example.remind.data.network.adapter.onSuccess +import com.example.remind.data.network.adapter.ApiResult import com.example.remind.data.network.interceptor.TokenManager -import com.example.remind.domain.usecase.KakaoTokenUseCase +import com.example.remind.domain.usecase.onboarding_usecase.KakaoTokenUseCase import com.kakao.sdk.auth.model.OAuthToken import com.kakao.sdk.common.model.ClientError import com.kakao.sdk.common.model.ClientErrorCause @@ -34,12 +34,11 @@ class LoginViewModel @Inject constructor( is LoginContract.Event.KakaoLoginButtonClicked -> { KakaoLogin(event.context) } - + else->{} } } } private fun KakaoLogin(context : Context) { - val callback: (OAuthToken?, Throwable?) -> Unit = { token, error -> if(error != null) { Log.e("kakao", "카카오 로그인 실패") @@ -69,25 +68,43 @@ class LoginViewModel @Inject constructor( } } - private fun socialLogin(token: String) { - viewModelScope.launch { - authUseCase.invoke(KakaoLoginRequest(token)) - .onSuccess { - runBlocking { tokenManager.saveAccessToken( - it.data.accessToken, - it.data.refreshToken - ) } - postEffect( - LoginContract.Effect.NavigateTo( + +private fun socialLogin(token: String) { + viewModelScope.launch { + val result = authUseCase.invoke(KakaoLoginRequest(token)) + when(result) { + is ApiResult.Success -> { + runBlocking { tokenManager.saveAccessToken( + result.data.data.accessToken, + result.data.data.refreshToken + ) + tokenManager.saveUserName(result.data.data.name) + } + postEffect( + LoginContract.Effect.NavigateTo( destinaton = Screens.Register.SelectType.route, navOptions = navOptions { - popUpTo(Screens.Register.Login.route) { - inclusive = true - } + popUpTo( + Screens.Register.Login.route + ) } - )) - } + ) + ) + Timber.d("${tokenManager.getAccessToken()} ||| ${tokenManager.getRefreshToken()}") + } + is ApiResult.Failure.UnknownApiError -> { + postEffect(LoginContract.Effect.Toastmessage("리마인드 서버 관리자에게 문의하세요")) + } + is ApiResult.Failure.NetworkError -> { + postEffect(LoginContract.Effect.Toastmessage("네트워크 설정을 확인해주세요")) + } + is ApiResult.Failure.HttpError -> { + postEffect(LoginContract.Effect.Toastmessage("Http 오류가 발생했습니다")) + } + else -> {} } } +} + } \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingCenter.kt b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingCenter.kt new file mode 100644 index 0000000..077b434 --- /dev/null +++ b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingCenter.kt @@ -0,0 +1,13 @@ +package com.example.remind.feature.screens.auth.onboarding + +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import com.example.remind.core.designsystem.theme.RemindTheme + +@Composable +fun OnBoardingCenterScreen() { + RemindTheme { + Text(text = "센터용") + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingCheckDoctor.kt b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingCheckDoctor.kt new file mode 100644 index 0000000..cc33fc2 --- /dev/null +++ b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingCheckDoctor.kt @@ -0,0 +1,13 @@ +package com.example.remind.feature.screens.auth.onboarding + +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import com.example.remind.core.designsystem.theme.RemindTheme + +@Composable +fun OnBoardingCheckDoctorScreen() { + RemindTheme { + Text(text = "의사용") + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingContract.kt b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingContract.kt index 79c9fbc..e058b7b 100644 --- a/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingContract.kt +++ b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingContract.kt @@ -6,16 +6,23 @@ import androidx.navigation.NavOptionsBuilder import com.example.remind.core.base.UiEffect import com.example.remind.core.base.UiEvent import com.example.remind.core.base.UiState +import com.example.remind.data.model.request.OnBoardingRequest +import com.example.remind.feature.screens.auth.login.LoginContract class OnBoardingContract { data class State( - val blah: String? = null + val selectedType: String? = null, + val moveAble: Boolean = false, + val fcmToken: String = "" ): UiState sealed class Event: UiEvent { data class DoctorButtonClicked(val context: Context): Event() data class CenterButtonClicked(val context: Context): Event() data class PatienceButtonClicked(val context: Context): Event() + data class NextButtonClicked(val context: Context): Event() + data class NextButtonFinal(val onBoardingData: OnBoardingRequest): Event() + data class NextButtonToPatience(val context: Context): Event() } sealed class Effect: UiEffect { @@ -24,5 +31,6 @@ class OnBoardingContract { val navOptions: NavOptions? = null, val builder: NavOptionsBuilder.() -> Unit = {} ): Effect() + data class Toastmessage(val message: String): Effect() } } \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingFinal.kt b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingFinal.kt new file mode 100644 index 0000000..66b6e31 --- /dev/null +++ b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingFinal.kt @@ -0,0 +1,128 @@ +package com.example.remind.feature.screens.auth.onboarding + +import android.graphics.Paint +import android.widget.Toast +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +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 androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavHostController +import com.example.remind.R +import com.example.remind.core.common.component.BasicButton +import com.example.remind.core.designsystem.theme.RemindTheme +import kotlinx.coroutines.flow.collectLatest + +@Composable +fun OnBoardingFinalScreen( + navController: NavHostController +) { + val viewModel: OnBoardingViewModel = hiltViewModel() + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val effectFlow = viewModel.effect + val context = LocalContext.current + + LaunchedEffect(true) { + effectFlow.collectLatest { effect -> + when(effect) { + is OnBoardingContract.Effect.NavigateTo -> { + navController.navigate(effect.destination, effect.navOptions) + } + is OnBoardingContract.Effect.Toastmessage -> { + Toast.makeText(context, effect.message, Toast.LENGTH_SHORT).show() + } + } + } + } + + RemindTheme { + PatienceFinal( + name = "배예진", + onClick = { + viewModel.setEvent(OnBoardingContract.Event.NextButtonToPatience(context)) + } + ) + } +} + +@Composable +fun PatienceFinal( + modifier: Modifier = Modifier, + name: String, + onClick: () -> Unit +) { + var title = stringResource(id = R.string.반가워요_환자님, name) + Box( + modifier = modifier.fillMaxSize() + ) { + Image( + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight(), + painter = painterResource(R.drawable.img_background), + contentDescription = null, + contentScale = ContentScale.FillBounds + ) + Column( + modifier = modifier.align(Alignment.TopStart) + ) { + Text( + modifier = modifier + .padding(top = 95.dp, start = 20.dp, end = 20.dp, bottom = 12.dp), + text = title, + style = RemindTheme.typography.h1Bold.copy(color = RemindTheme.colors.white) + ) + Text( + modifier = modifier + .padding(start = 20.dp, end = 20.dp), + text = stringResource(id = R.string.오늘_하루의_통합적_기분을_선택해주세요), + style = RemindTheme.typography.b1Medium.copy(color = RemindTheme.colors.white) + ) + } + Image( + modifier = modifier + .align(Alignment.Center), + painter = painterResource(id = R.drawable.ic_patience_onboarding), + contentDescription = null + ) + BasicButton( + modifier = modifier + .fillMaxWidth() + .padding(start = 20.dp, end = 20.dp, bottom = 32.dp) + .align(Alignment.BottomCenter), + text = stringResource(id = R.string.시작하기), + RoundedCorner = 12.dp, + backgroundColor = RemindTheme.colors.main_6, + textColor = RemindTheme.colors.white, + verticalPadding = 13.dp, + onClick = onClick, + textStyle = RemindTheme.typography.b2Bold + ) + } +} +@Preview +@Composable +fun FinalPreview() { + PatienceFinal( + name = "배예진", + onClick = {} + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingLoadingDoctor.kt b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingLoadingDoctor.kt new file mode 100644 index 0000000..6ee5ca8 --- /dev/null +++ b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingLoadingDoctor.kt @@ -0,0 +1,8 @@ +package com.example.remind.feature.screens.auth.onboarding + +import androidx.compose.runtime.Composable + +@Composable +fun OnBoardingLoadingDoctorScreen() { + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingPatience.kt b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingPatience.kt new file mode 100644 index 0000000..8833888 --- /dev/null +++ b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingPatience.kt @@ -0,0 +1,192 @@ +package com.example.remind.feature.screens.auth.onboarding + +import android.widget.Toast +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +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.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Checkbox +import androidx.compose.material3.CheckboxDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.PlatformTextStyle +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.LineHeightStyle +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavHostController +import com.example.remind.R +import com.example.remind.core.common.component.BasicOnBoardingAppBar +import com.example.remind.core.designsystem.theme.Pretendard +import com.example.remind.core.designsystem.theme.RemindTheme +import com.example.remind.data.model.request.OnBoardingRequest +import kotlinx.coroutines.flow.collectLatest + +@Composable +fun OnBoardingPatienceScreen( + navController: NavHostController +) { + val viewModel: OnBoardingViewModel = hiltViewModel() + val effectFlow = viewModel.effect + val context = LocalContext.current + var isChecked by remember{ mutableStateOf(false) } + + LaunchedEffect(true) { + effectFlow.collectLatest { effect -> + when(effect) { + is OnBoardingContract.Effect.NavigateTo -> { + navController.navigate(effect.destination, effect.navOptions) + } + is OnBoardingContract.Effect.Toastmessage -> { + Toast.makeText(context, effect.message, Toast.LENGTH_SHORT).show() + } + } + } + } + + RemindTheme { + Column( + modifier = Modifier.fillMaxSize() + ) { + BasicOnBoardingAppBar( + modifier = Modifier.fillMaxWidth(), + weight = 0.5f, + title = stringResource(id = R.string.사용자_정보) + ) + Text( + modifier = Modifier.padding(start = 20.dp, top = 35.dp, end = 20.dp), + textAlign = TextAlign.Start, + text = stringResource(id = R.string.보호자_정보_입력), + style = RemindTheme.typography.h1Bold.copy(color = RemindTheme.colors.text) + ) + Text( + modifier = Modifier.padding(start = 20.dp, top = 12.dp, end = 20.dp), + textAlign = TextAlign.Start, + text = stringResource(id = R.string.긴급_시_연락할_수_있는), + style = TextStyle( + fontFamily = Pretendard, + fontWeight = FontWeight.Medium, + fontSize = 16.82.sp, + lineHeight = 32.sp, + platformStyle = PlatformTextStyle( + includeFontPadding = false + ), + lineHeightStyle = LineHeightStyle( + alignment = LineHeightStyle.Alignment.Center, + trim = LineHeightStyle.Trim.None + ) + ), + ) + Spacer(modifier = Modifier.height(56.dp)) + Image( + modifier = Modifier + .fillMaxWidth() + .padding(start = 20.dp, end = 20.dp), + painter = painterResource(id = R.drawable.ic_example1), + contentDescription = null + ) + Spacer(modifier = Modifier.height(12.dp)) + CheckReading( + modifier = Modifier.fillMaxWidth(), + checked = isChecked, + onCheckedChange = {isChecked = it} + ) + Spacer(modifier = Modifier.weight(1f)) + typeButton( + modifier = Modifier + .fillMaxWidth() + .padding(start = 20.dp, end = 20.dp), + backgroundColor = RemindTheme.colors.main_6, + text = stringResource(id = R.string.다음), + onClick = { + viewModel.setEvent(OnBoardingContract.Event.NextButtonFinal( + OnBoardingRequest( + centerName = "", + city = "", + district = "", + protectorPhoneNumber = "01088644622", + rolesType = "ROLE_PATIENT", + fcmToken = "" + ) + )) + }, + textColor = RemindTheme.colors.white, + enable = true + ) + Spacer(modifier = Modifier.height(32.dp)) + } + } +} + +@Composable +fun CheckReading( + modifier: Modifier = Modifier, + checked: Boolean, + onCheckedChange: (Boolean) -> Unit +) { + Row( + modifier = modifier + .fillMaxWidth() + .padding(start = 20.dp, end = 20.dp), + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically + ) { + Checkbox( + checked = checked, + colors = CheckboxDefaults.colors( + checkedColor = RemindTheme.colors.main_6, + uncheckedColor = Color(0xFF6B7280), + checkmarkColor = RemindTheme.colors.white + ), + onCheckedChange = onCheckedChange + ) + Spacer(modifier = Modifier.width(9.dp)) + Column() { + Text( + text = stringResource(id = R.string.긴급_상황_발생_시_보호자에게_연락), + style = RemindTheme.typography.b3Medium.copy(color = RemindTheme.colors.black) + ) + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = stringResource(id = R.string.긴급_상황_발생시_담당자가_보호자에게), + style = RemindTheme.typography.c1Regular.copy(color = RemindTheme.colors.grayscale_3, lineHeight = 6.sp) + ) + } + } +} + +@Preview +@Composable +fun OnBoardingPreview() { + Column( + modifier = Modifier.fillMaxSize() + ) { + BasicOnBoardingAppBar( + modifier = Modifier.fillMaxWidth(), + weight = 0.5f, + title = stringResource(id = R.string.사용자_정보) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingViewModel.kt b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingViewModel.kt index f085a25..9e81f8c 100644 --- a/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingViewModel.kt +++ b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/OnBoardingViewModel.kt @@ -4,9 +4,12 @@ import androidx.lifecycle.viewModelScope import androidx.navigation.navOptions import com.example.remind.app.Screens import com.example.remind.core.base.BaseViewModel +import com.example.remind.data.model.request.OnBoardingRequest +import com.example.remind.data.network.adapter.ApiResult import com.example.remind.data.network.interceptor.TokenManager -import com.example.remind.feature.screens.auth.login.LoginContract -import com.example.remind.feature.screens.auth.splash.SplashContract +import com.example.remind.data.repository.auth.TokenRepository +import com.example.remind.domain.usecase.onboarding_usecase.FcmTokenUseCase +import com.example.remind.domain.usecase.onboarding_usecase.OnBoardingUserCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -14,6 +17,8 @@ import javax.inject.Inject @HiltViewModel class OnBoardingViewModel @Inject constructor( + private val onBoardingUserCase: OnBoardingUserCase, + private val tokenUseCase: FcmTokenUseCase, private val tokenManager: TokenManager ): BaseViewModel( initialState = OnBoardingContract.State() @@ -21,17 +26,26 @@ class OnBoardingViewModel @Inject constructor( override fun reduceState(event: OnBoardingContract.Event) { when(event) { is OnBoardingContract.Event.DoctorButtonClicked -> { - saveUserType("Doctor") - navigateToDoctor() + updateState(currentState.copy("ROLE_DOCTOR")) } is OnBoardingContract.Event.CenterButtonClicked -> { - saveUserType("Center") - navigateToCenter() + updateState(currentState.copy("ROLE_CENTER")) } - else -> { - saveUserType("Patience") + is OnBoardingContract.Event.PatienceButtonClicked -> { + updateState(currentState.copy("ROLE_PATIENT")) + } + is OnBoardingContract.Event.NextButtonFinal -> { + getFcmToken() + postOnBoarding(event.onBoardingData.copy(fcmToken = currentState.fcmToken)) + if(currentState.moveAble == true) navigateToFinal() + } + is OnBoardingContract.Event.NextButtonToPatience -> { navigateToPatience() } + else -> { + saveUserType(currentState.selectedType!!) + navigateToNext(currentState.selectedType!!) + } } } @@ -41,39 +55,86 @@ class OnBoardingViewModel @Inject constructor( } } - fun navigateToDoctor() { - postEffect( - OnBoardingContract.Effect.NavigateTo( - destination = Screens.Doctor.DoctorMain.route, - navOptions = navOptions { - popUpTo(Screens.Register.SelectType.route) { - inclusive = true + fun navigateToNext(selectType: String) { + if(selectType == "ROLE_DOCTOR") { + postEffect( + OnBoardingContract.Effect.NavigateTo( + destination = Screens.Register.OnBoardingCheckDoctor.route, + navOptions = navOptions { + popUpTo(Screens.Register.SelectType.route) { + inclusive = true + } } - } - )) + )) + } + if(selectType == "ROLE_PATIENT") { + postEffect( + OnBoardingContract.Effect.NavigateTo( + destination = Screens.Register.OnBoardingPatience.route, + navOptions = navOptions { + popUpTo(Screens.Register.SelectType.route) { + inclusive = true + } + } + )) + } + if(selectType == "ROLE_CENTER") { + postEffect( + OnBoardingContract.Effect.NavigateTo( + destination = Screens.Register.OnBoardingCenter.route, + navOptions = navOptions { + popUpTo(Screens.Register.SelectType.route) { + inclusive = true + } + } + )) + } } - - fun navigateToCenter() { + fun navigateToFinal() { postEffect( OnBoardingContract.Effect.NavigateTo( - destination = Screens.Center.CenterMain.route, + destination = Screens.Register.OnBoardingFinal.route, navOptions = navOptions { - popUpTo(Screens.Register.SelectType.route) { - inclusive = true - } + } )) } - fun navigateToPatience() { postEffect( OnBoardingContract.Effect.NavigateTo( destination = Screens.Patience.route, navOptions = navOptions { - popUpTo(Screens.Register.SelectType.route) { + popUpTo(Screens.Register.OnBoardingFinal.route) { inclusive = true } } )) } + + private fun getFcmToken() { + viewModelScope.launch { + val fcmToken = tokenUseCase.invoke() + updateState(currentState.copy(fcmToken = fcmToken)) + } + } + + private fun postOnBoarding(data: OnBoardingRequest) { + viewModelScope.launch { + val result = onBoardingUserCase.invoke(data) + when(result) { + is ApiResult.Success -> { + updateState(currentState.copy(moveAble = true)) + } + is ApiResult.Failure.UnknownApiError -> { + postEffect(OnBoardingContract.Effect.Toastmessage("리마인드 서버 관리자에게 문의하세요")) + } + is ApiResult.Failure.NetworkError -> { + postEffect(OnBoardingContract.Effect.Toastmessage("네트워크 설정을 확인해주세요")) + } + is ApiResult.Failure.HttpError -> { + postEffect(OnBoardingContract.Effect.Toastmessage("Http 오류가 발생했습니다")) + } + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/SelectTypeScreen.kt b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/SelectTypeScreen.kt index 14be364..bc08bad 100644 --- a/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/SelectTypeScreen.kt +++ b/app/src/main/java/com/example/remind/feature/screens/auth/onboarding/SelectTypeScreen.kt @@ -1,13 +1,41 @@ package com.example.remind.feature.screens.auth.onboarding +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.material3.Button +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.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.PlatformTextStyle +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.LineHeightStyle +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController +import com.example.remind.R +import com.example.remind.core.common.component.BasicOnBoardingAppBar +import com.example.remind.core.designsystem.theme.Pretendard +import com.example.remind.core.designsystem.theme.RemindTheme import kotlinx.coroutines.flow.collectLatest @Composable @@ -15,6 +43,7 @@ fun SelectTypeScreen( navController: NavHostController ){ val viewModel: OnBoardingViewModel = hiltViewModel() + val uiState by viewModel.uiState.collectAsStateWithLifecycle() val effectFlow = viewModel.effect val context = LocalContext.current @@ -24,26 +53,142 @@ fun SelectTypeScreen( is OnBoardingContract.Effect.NavigateTo -> { navController.navigate(effect.destination, effect.navOptions) } + + else -> {} } } } - - Column() { - Text("선택유") - Button(onClick = { - viewModel.setEvent(OnBoardingContract.Event.PatienceButtonClicked(context)) - }) { - Text("환자") - } - Button(onClick = { - viewModel.setEvent(OnBoardingContract.Event.CenterButtonClicked(context)) - }) { - Text("센터") - } - Button(onClick = { - viewModel.setEvent(OnBoardingContract.Event.DoctorButtonClicked(context)) - }) { - Text("의사") + RemindTheme { + Column( + modifier = Modifier.fillMaxSize() + ) { + BasicOnBoardingAppBar( + modifier = Modifier.fillMaxWidth(), + weight = 0.3f, + title = stringResource(id = R.string.환자_관리) + ) + Text( + modifier = Modifier.padding(start = 20.dp, top = 31.dp), + textAlign = TextAlign.Start, + text = stringResource(id = R.string.사용_입장_선택), + style = RemindTheme.typography.h1Bold.copy(color = RemindTheme.colors.text) + ) + Text( + modifier = Modifier.padding(start = 20.dp, top = 12.dp), + textAlign = TextAlign.Start, + text = stringResource(id = R.string.어떤_입장에서_사용하실지_선택해주세요), + style = RemindTheme.typography.b2Medium.copy(color = RemindTheme.colors.grayscale_3) + ) + Spacer(modifier = Modifier.weight(1f)) + Column( + modifier = Modifier + .fillMaxWidth() + .padding(start = 60.dp, end = 60.dp), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + typeButton( + modifier = Modifier + .fillMaxWidth(), + backgroundColor = if(uiState.selectedType == "ROLE_PATIENT") RemindTheme.colors.main_4 else RemindTheme.colors.slate_100, + text = stringResource(id = R.string.환자용), + onClick = { + viewModel.setEvent(OnBoardingContract.Event.PatienceButtonClicked(context)) + }, + textColor = RemindTheme.colors.slate_700, + enable = true + ) + Spacer(modifier = Modifier.height(22.dp)) + typeButton( + modifier = Modifier + .fillMaxWidth(), + backgroundColor = if(uiState.selectedType == "ROLE_DOCTOR") RemindTheme.colors.main_4 else RemindTheme.colors.slate_100, + text = stringResource(id = R.string.의사용), + onClick = { + viewModel.setEvent(OnBoardingContract.Event.DoctorButtonClicked(context)) + }, + textColor = RemindTheme.colors.slate_700, + enable = true + ) + Spacer(modifier = Modifier.height(22.dp)) + typeButton( + modifier = Modifier + .fillMaxWidth(), + backgroundColor = if(uiState.selectedType == "ROLE_CENTER") RemindTheme.colors.main_4 else RemindTheme.colors.slate_100, + text = stringResource(id = R.string.센터용), + onClick = { + viewModel.setEvent(OnBoardingContract.Event.CenterButtonClicked(context)) + }, + textColor = RemindTheme.colors.slate_700, + enable = true + ) + } + Spacer(modifier = Modifier.weight(1f)) + typeButton( + modifier = Modifier + .fillMaxWidth() + .padding(start = 20.dp, end = 20.dp), + backgroundColor = if(uiState.selectedType == null) RemindTheme.colors.slate_100 else RemindTheme.colors.main_6, + text = stringResource(id = R.string.다음), + onClick = { + viewModel.setEvent(OnBoardingContract.Event.NextButtonClicked(context)) + }, + textColor = if(uiState.selectedType == null) RemindTheme.colors.slate_300 else RemindTheme.colors.white, + enable = uiState.selectedType != null + ) + Spacer(modifier = Modifier.height(32.dp)) } } +} + +@Composable +fun typeButton( + modifier: Modifier = Modifier, + backgroundColor: Color, + text: String, + textColor: Color, + onClick: () -> Unit, + enable: Boolean +) { + Box( + modifier = modifier + .fillMaxWidth() + .clip(RoundedCornerShape(12.dp)) + .background(color = backgroundColor) + .clickable( + enabled = enable, + onClick = onClick + ) + ) { + Text( + modifier = modifier + .padding(vertical = 12.dp), + text = text, + textAlign = TextAlign.Center, + style = TextStyle( + fontFamily = Pretendard, + fontWeight = FontWeight.SemiBold, + fontSize = 16.sp, + lineHeight = 8.sp, + platformStyle = PlatformTextStyle( + includeFontPadding = false + ), + lineHeightStyle = LineHeightStyle( + alignment = LineHeightStyle.Alignment.Center, + trim = LineHeightStyle.Trim.None + ), + color = textColor + ), + ) + } +} + +@Preview(showBackground = false) +@Composable +fun SelectTypePreview() { + BasicOnBoardingAppBar( + //modifier = Modifier.fillMaxWidth(), + weight = 0.3f, + title = stringResource(id = R.string.환자_관리) + ) } \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/feature/screens/auth/splash/SplashScreen.kt b/app/src/main/java/com/example/remind/feature/screens/auth/splash/SplashScreen.kt index 3fdfc8e..ea36e60 100644 --- a/app/src/main/java/com/example/remind/feature/screens/auth/splash/SplashScreen.kt +++ b/app/src/main/java/com/example/remind/feature/screens/auth/splash/SplashScreen.kt @@ -1,12 +1,22 @@ package com.example.remind.feature.screens.auth.splash import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +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.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController import com.example.remind.R @@ -26,9 +36,34 @@ fun SplashScreen( modifier = Modifier .fillMaxSize() ) { - Image(painter = painterResource( - id = R.drawable.ic_logo), - contentDescription = null) + Box( + modifier = Modifier + .fillMaxSize(), + ) { + Box( + modifier = Modifier + .fillMaxSize() + .background(color = RemindTheme.colors.main_6) + ) + Column( + modifier = Modifier + .align(Alignment.Center), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Image( + modifier = Modifier + .width(139.dp) + .height(83.dp), + painter = painterResource(id = R.drawable.ic_logo_splash), + contentDescription = null, + ) + Text( + modifier = Modifier.padding(top = 24.dp), + text = stringResource(id = R.string.진료실_밖_일상을_더하다), + style = RemindTheme.typography.onSplashFont.copy(color = RemindTheme.colors.white) + ) + } + } } } diff --git a/app/src/main/java/com/example/remind/feature/screens/auth/splash/SplashViewModel.kt b/app/src/main/java/com/example/remind/feature/screens/auth/splash/SplashViewModel.kt index b6df9fb..8b6b662 100644 --- a/app/src/main/java/com/example/remind/feature/screens/auth/splash/SplashViewModel.kt +++ b/app/src/main/java/com/example/remind/feature/screens/auth/splash/SplashViewModel.kt @@ -1,19 +1,13 @@ package com.example.remind.feature.screens.auth.splash -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.navigation.navOptions import com.example.remind.app.Screens import com.example.remind.core.base.BaseViewModel import com.example.remind.data.network.interceptor.TokenManager -import com.example.remind.feature.screens.auth.login.LoginContract import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking import javax.inject.Inject @HiltViewModel @@ -39,9 +33,9 @@ class SplashViewModel @Inject constructor( fun checkUserState() { val userType = currentState.userType when(userType) { - "Doctor" -> navigateToDoctor() - "Center" -> navigateToCenter() - "Patience" -> navigateToPatience() + "ROLE_DOCTOR" -> navigateToDoctor() + "ROLE_CENTER" -> navigateToCenter() + "ROLE_PATIENT" -> navigateToPatience() else -> navigateToLogin() } } diff --git a/app/src/main/java/com/example/remind/feature/screens/doctor/DoctorMainScreen.kt b/app/src/main/java/com/example/remind/feature/screens/doctor/DoctorMainScreen.kt index fccec1b..a0a4fc9 100644 --- a/app/src/main/java/com/example/remind/feature/screens/doctor/DoctorMainScreen.kt +++ b/app/src/main/java/com/example/remind/feature/screens/doctor/DoctorMainScreen.kt @@ -212,20 +212,24 @@ fun StickyHeaderComponent( .padding(start = 4.dp) .weight(1f), text = stringResource(id = R.string.삭제), + RoundedCorner= 20.dp, backgroundColor = RemindTheme.colors.main_4, textColor = RemindTheme.colors.white, - verticalPadding = 0.dp, - onClick = {} + verticalPadding = 13.dp, + onClick = {}, + textStyle = RemindTheme.typography.b1Bold ) BasicButton( modifier = Modifier .padding(start = 4.dp) .weight(1f), text = stringResource(id = R.string.추가하기), + RoundedCorner= 20.dp, backgroundColor = RemindTheme.colors.main_6, textColor = RemindTheme.colors.white, - verticalPadding =0.dp, - onClick = onRegisterClicked + verticalPadding =13.dp, + onClick = onRegisterClicked, + textStyle = RemindTheme.typography.b1Bold ) } } diff --git a/app/src/main/java/com/example/remind/feature/screens/doctor/DoctorRegisterScreen.kt b/app/src/main/java/com/example/remind/feature/screens/doctor/DoctorRegisterScreen.kt index 003fce0..f0d8a1a 100644 --- a/app/src/main/java/com/example/remind/feature/screens/doctor/DoctorRegisterScreen.kt +++ b/app/src/main/java/com/example/remind/feature/screens/doctor/DoctorRegisterScreen.kt @@ -120,9 +120,11 @@ fun RequestListItem( BasicButton( text = stringResource(id = R.string.수락), backgroundColor = RemindTheme.colors.main_6, + RoundedCorner = 20.dp, textColor = RemindTheme.colors.white, verticalPadding = 18.dp, - onClick = onClick + onClick = onClick, + textStyle = RemindTheme.typography.b2Bold ) } Spacer(modifier = modifier.height(10.dp)) @@ -159,9 +161,11 @@ fun RequestListItem( BasicButton( text = stringResource(id = R.string.수락), backgroundColor = RemindTheme.colors.main_6, + RoundedCorner = 20.dp, textColor = RemindTheme.colors.white, verticalPadding = 5.dp, - onClick = onClick + onClick = onClick, + textStyle = RemindTheme.typography.b2Bold ) } Box( diff --git a/app/src/main/java/com/example/remind/feature/screens/patience/CheeringScreen.kt b/app/src/main/java/com/example/remind/feature/screens/patience/CheeringScreen.kt new file mode 100644 index 0000000..341a6ab --- /dev/null +++ b/app/src/main/java/com/example/remind/feature/screens/patience/CheeringScreen.kt @@ -0,0 +1,28 @@ +package com.example.remind.feature.screens.patience + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import com.example.remind.R +import com.example.remind.core.designsystem.theme.RemindTheme + +@Composable +fun CheeringScreen(){ + RemindTheme { + Image( + modifier = Modifier.fillMaxSize(), + painter = painterResource(id = R.drawable.img_example_cheer), + contentDescription = null + ) + } +} + +@Preview +@Composable +fun CheeringPreview() { + CheeringScreen() +} \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/feature/screens/patience/HomeScreen.kt b/app/src/main/java/com/example/remind/feature/screens/patience/HomeScreen.kt index 08dde4e..9565119 100644 --- a/app/src/main/java/com/example/remind/feature/screens/patience/HomeScreen.kt +++ b/app/src/main/java/com/example/remind/feature/screens/patience/HomeScreen.kt @@ -1,38 +1,390 @@ package com.example.remind.feature.screens.patience +import android.os.Build +import androidx.annotation.RequiresApi import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.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.width -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.example.remind.R +import com.example.remind.core.common.component.BasicButton import com.example.remind.core.common.component.BasicListItem import com.example.remind.core.designsystem.theme.RemindTheme +import com.example.remind.data.model.CalendarUiModel +import com.example.remind.data.repository.CalendarDataSource import com.example.remind.feature.viewmodel.CustomViewModel +@RequiresApi(Build.VERSION_CODES.O) @Composable fun HomeScreen(){ + val dataSource = CalendarDataSource() + var calendarUiModel by remember { mutableStateOf(dataSource.getData(lastSelectedDate = dataSource.today)) } + val scrollState = rememberScrollState() + RemindTheme { + Column( + modifier = Modifier + .fillMaxSize() + .background(color = RemindTheme.colors.white) + ) { + HomeTopBar(onClick = {}) + DateSelectHeader(previousBtn = {}, nextBtn = {}, calendarBtn = {}) + Content( + modifier = Modifier.fillMaxWidth(), + data = calendarUiModel, + onDateClicked = { date -> + calendarUiModel = calendarUiModel.copy( + selectedDate = date, + visibleDates = calendarUiModel.visibleDates.map { + it.copy( + isSelected = it.date.isEqual(date.date) + ) + } + ) + } + ) + Spacer(modifier = Modifier.height(10.dp)) + Box( + modifier = Modifier + .fillMaxWidth() + .shadow( + shape = RoundedCornerShape( + topStart = 20.dp, + topEnd = 20.dp, + bottomStart = 0.dp, + bottomEnd = 0.dp + ), + elevation = 2.dp, + ambientColor = Color(0xFF042340).copy(alpha = 0.4f), + ) + .background( + shape = RoundedCornerShape( + topStart = 20.dp, + topEnd = 20.dp, + bottomStart = 0.dp, + bottomEnd = 0.dp + ), + color = RemindTheme.colors.white, + ) + ) { + Column( + modifier = Modifier + .padding(horizontal = 20.dp) + .verticalScroll(scrollState), + horizontalAlignment = Alignment.Start + ) { + Spacer(modifier = Modifier.height(20.dp)) + Text( + text = stringResource(id = R.string.약_복용_체크), + style = RemindTheme.typography.b2Bold.copy(color = Color(0xFF1F2937)) + ) + Spacer(modifier = Modifier.height(10.dp)) + EmptyMedicineList() + Spacer(modifier = Modifier.height(23.dp)) + Text( + text = stringResource(id = R.string.오늘_하루_기분이_어떠셨나요), + style = RemindTheme.typography.b2Bold.copy(color = Color(0xFF1F2937)) + ) + Spacer(modifier = Modifier.height(2.dp)) + Text( + text = stringResource(id = R.string.당신의_하루가_궁금해요), + style = RemindTheme.typography.b3Medium.copy(color = Color(0xFF9B9B9B)) + ) + Spacer(modifier = Modifier.height(10.dp)) + EmptyTodayMoodContainer(clickToWrite = {}) + Spacer(modifier = Modifier.height(80.dp)) + } + } + } + } +} + +@Composable +fun HomeTopBar( + modifier: Modifier = Modifier, + onClick: () -> Unit +) { + Row( + modifier = modifier + .fillMaxWidth() + .background(color = RemindTheme.colors.white) + .padding(start = 20.dp, end = 20.dp, top = 23.6.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(id = R.drawable.ic_logo), + contentDescription = null, + modifier = modifier + .size( + width = 37.dp, + height = 22.dp + ) + ) + Spacer(Modifier.weight(1f)) + IconButton( + onClick = onClick, + ) { + Icon( + painter = painterResource(id = R.drawable.ic_sos), + contentDescription = null, + modifier = modifier + .size(width = 24.dp, height = 32.dp), + tint = RemindTheme.colors.sub_3 + ) + } + } +} + +@Composable +fun DateSelectHeader( + modifier: Modifier = Modifier, + previousBtn: () -> Unit, + nextBtn: () -> Unit, + calendarBtn: () -> Unit +) { + Row( + modifier = modifier + .fillMaxWidth() + .background(color = RemindTheme.colors.white) + .padding(start = 20.dp, end = 20.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "2024년 4월 1주차", + style = RemindTheme.typography.c1Medium.copy(color = RemindTheme.colors.grayscale_3) + ) + Spacer(modifier = modifier.weight(1f)) + IconButton( + onClick = nextBtn, + ) { + Icon( + painter = painterResource(id = R.drawable.ic_calendar_previous), + contentDescription = null, + modifier = Modifier + .size(width = 17.dp, height = 17.dp), + tint = RemindTheme.colors.slate_400 + ) + } + IconButton( + onClick = calendarBtn, + ) { + Icon( + painter = painterResource(id = R.drawable.ic_calendar_next), + contentDescription = null, + modifier = modifier + .size(width = 17.dp, height = 17.dp), + tint = RemindTheme.colors.slate_400 + ) + } + IconButton( + onClick = calendarBtn, + ) { + Icon( + painter = painterResource(id = R.drawable.ic_calendar), + contentDescription = null, + modifier = modifier + .size(width = 14.dp, height = 14.dp), + tint = RemindTheme.colors.slate_500 + ) + } + } +} +@RequiresApi(Build.VERSION_CODES.O) +@Composable +fun Content( + modifier: Modifier = Modifier, + data: CalendarUiModel, + onDateClicked: (CalendarUiModel.Date) -> Unit +) { + LazyRow( + modifier = modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + items(items = data.visibleDates) { date -> + DayItem( + date = date, + onDateClicked = onDateClicked + ) + } + } } +@RequiresApi(Build.VERSION_CODES.O) +@Composable +fun DayItem( + modifier: Modifier = Modifier, + date: CalendarUiModel.Date, + onDateClicked: (CalendarUiModel.Date) -> Unit +) { + Card( + modifier = modifier + .clickable { + onDateClicked(date) + }, + colors = CardDefaults.cardColors( + containerColor = if (date.isSelected) RemindTheme.colors.main_6 else RemindTheme.colors.white + ) + ) { + Column( + ) { + Text( + text = date.day, + modifier = Modifier + .align(Alignment.CenterHorizontally) + .padding(top = 6.dp, bottom = 7.dp), + style = RemindTheme.typography.b2Medium.copy( + color = if(date.isSelected) RemindTheme.colors.white else RemindTheme.colors.slate_800 + ) + ) + Text( + text = date.date.dayOfMonth.toString(), + modifier = Modifier + .align(Alignment.CenterHorizontally) + .padding(vertical = 1.dp, horizontal = 7.dp) + .background(color = RemindTheme.colors.white, shape = CircleShape), + style = RemindTheme.typography.b2Medium.copy(color = RemindTheme.colors.slate_800) + ) + Spacer(modifier = modifier.height(3.dp)) + } + } +} +@Composable +fun EmptyMedicineList( + modifier: Modifier = Modifier +) { + Box( + modifier = modifier + .fillMaxWidth() + .border( + width = 1.dp, + color = RemindTheme.colors.grayscale_1, + shape = RoundedCornerShape(12.dp) + ) + ) { + Text( + modifier = modifier + .align(Alignment.Center) + .padding(vertical = 30.dp), + text = stringResource(id = R.string.등록된_약이_없어요), + style = RemindTheme.typography.c1Medium.copy(color = RemindTheme.colors.slate_400) + ) + } +} + +@Composable +fun EmptyTodayMoodContainer( + modifier: Modifier = Modifier, + clickToWrite: () -> Unit +) { + Box( + modifier = modifier + .fillMaxWidth() + .border( + width = 1.dp, + color = RemindTheme.colors.grayscale_1, + shape = RoundedCornerShape(12.dp) + ) + ) { + Image( + modifier = modifier + .padding( + start = 50.dp, + end = 50.dp, + top = 21.dp, + bottom = 70.dp + ) + .align(Alignment.Center), + painter = painterResource(id = R.drawable.img_emptymood), + contentDescription = null + ) + BasicButton( + modifier = modifier + .align(Alignment.BottomCenter) + .fillMaxWidth() + .padding(start = 53.dp, end = 54.dp, bottom = 31.dp), + text = stringResource(id = R.string.오늘의_기분_기록하기), + RoundedCorner = 29.dp, + backgroundColor = RemindTheme.colors.main_6, + textColor = RemindTheme.colors.white, + verticalPadding = 10.dp, + onClick = clickToWrite, + textStyle = RemindTheme.typography.b2Bold + ) + } +} +//다이얼로그 +@Composable +fun DialogContent() { + Column { + Spacer( + modifier = Modifier + .height(9.dp) + .fillMaxWidth() + ) + Text( + text = stringResource(id = R.string.약_미복용_사유), + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .wrapContentSize() + .padding(top = 9.dp), + style = RemindTheme.typography.b1Bold.copy(color = RemindTheme.colors.text) + ) + Spacer( + modifier = Modifier + .height(29.dp) + .fillMaxWidth() + ) + + } +} + + + +@RequiresApi(Build.VERSION_CODES.O) +@Preview +@Composable +fun HomePreview() { + EmptyTodayMoodContainer(clickToWrite = {}) +} diff --git a/app/src/main/java/com/example/remind/feature/screens/patience/MedicineScreen.kt b/app/src/main/java/com/example/remind/feature/screens/patience/MedicineScreen.kt index aaf729c..5affb14 100644 --- a/app/src/main/java/com/example/remind/feature/screens/patience/MedicineScreen.kt +++ b/app/src/main/java/com/example/remind/feature/screens/patience/MedicineScreen.kt @@ -4,16 +4,35 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.sp - +import com.example.remind.core.designsystem.theme.RemindTheme +import com.patrykandpatrick.vico.compose.style.ChartStyle +import com.patrykandpatrick.vico.core.chart.line.LineChart +import com.patrykandpatrick.vico.core.entry.ChartEntryModelProducer +import com.patrykandpatrick.vico.core.entry.FloatEntry +import com.patrykandpatrick.vico.views.chart.line.lineSpec +//그래프 연습용 @Composable fun MedicineScreen(){ - Box(modifier = Modifier - .fillMaxSize(), - contentAlignment = Alignment.Center){ - Text(text = "ThirdScreen", - fontSize = 22.sp) - } +// val refreshDataset = remember { mutableIntStateOf(0) } +// val modelProducer = remember {ChartEntryModelProducer()} +// val datasetForModel = remember { mutableStateListOf() } +// val datasetLineSpec = remember{ arrayListOf() } +// LaunchedEffect(refreshDataset.intValue) { +// datasetForModel.clear() +// datasetLineSpec.clear() +// var xPos = 0f +// val dataPoints = arrayListOf() +// datasetLineSpec.add( +// ) +// } +// RemindTheme { +// +// } } \ No newline at end of file diff --git a/app/src/main/java/com/example/remind/feature/screens/patience/MoodChartScreen.kt b/app/src/main/java/com/example/remind/feature/screens/patience/MoodChartScreen.kt index 396255c..40cc517 100644 --- a/app/src/main/java/com/example/remind/feature/screens/patience/MoodChartScreen.kt +++ b/app/src/main/java/com/example/remind/feature/screens/patience/MoodChartScreen.kt @@ -2,19 +2,103 @@ package com.example.remind.feature.screens.patience import android.content.Context import android.util.Log +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.example.remind.R +import com.example.remind.core.common.component.BasicButton +import com.example.remind.core.common.component.BasicTextButton +import com.example.remind.core.designsystem.theme.RemindTheme +import com.example.remind.feature.screens.auth.onboarding.typeButton import com.kakao.sdk.auth.model.OAuthToken import com.kakao.sdk.common.model.ClientError import com.kakao.sdk.common.model.ClientErrorCause import com.kakao.sdk.user.UserApiClient +import com.patrykandpatrick.vico.compose.chart.Chart +import com.patrykandpatrick.vico.compose.style.ChartStyle +import com.patrykandpatrick.vico.views.chart.line.lineChart @Composable -fun MoodChartScreen(){ - val context = LocalContext.current - Column() { +fun MoodChartScreen() { + val scrollState = rememberScrollState() + RemindTheme { + Column( + modifier = Modifier + .padding(horizontal = 20.dp) + .verticalScroll(scrollState) + ) { + Spacer(modifier = Modifier.height(19.6.dp)) + Text( + text = stringResource(id = R.string.무드_차트), + style = RemindTheme.typography.h2Bold.copy(Color(0xFF303030)) + ) + Spacer(modifier = Modifier.height(22.dp)) + BasicTextButton( + modifier = Modifier.fillMaxWidth(), + backgroundColor = RemindTheme.colors.slate_600, + text = "17일째 연속으로 기록 중이에요! 파이팅:)", + textColor = RemindTheme.colors.slate_100, + onClick = { }, + verticalPadding = 6.dp, + enable = false + ) + Spacer(modifier = Modifier.height(12.dp)) + Text( + text = stringResource(id = R.string.주간_차트_기록), + style = RemindTheme.typography.b1Bold.copy(color = RemindTheme.colors.slate_800,) + ) + Spacer(modifier = Modifier.height(8.dp)) + BasicButton( + text = "기록 확인", + RoundedCorner = 12.dp, + backgroundColor = RemindTheme.colors.main_6, + textColor = RemindTheme.colors.white, + verticalPadding = 18.dp, + onClick = { }, + textStyle = RemindTheme.typography.b3Bold + ) } } +} + +//@Composable +//fun MoodChart( +// modifier: Modifier = Modifier +//) { +// Box( +// modifier = modifier +// .background(RemindTheme.colors.white, shape = RoundedCornerShape(12.dp)) +// .border(width = 1.dp, color = RemindTheme.colors.grayscale_2, shape = RoundedCornerShape(12.dp)) +// ) { +// Chart( +// modifier = modifier.align(Alignment.Center), +// chart = lineChart(), +// chartModelProducer = +// ) +// } +//} + +@Preview +@Composable +fun ChartPreview() { + +} diff --git a/app/src/main/java/com/example/remind/feature/screens/patience/PatienceGraph.kt b/app/src/main/java/com/example/remind/feature/screens/patience/PatienceGraph.kt index b191d1a..d294def 100644 --- a/app/src/main/java/com/example/remind/feature/screens/patience/PatienceGraph.kt +++ b/app/src/main/java/com/example/remind/feature/screens/patience/PatienceGraph.kt @@ -1,12 +1,15 @@ package com.example.remind.feature.screens.patience +import android.os.Build +import androidx.annotation.RequiresApi import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.navigation.compose.NavHost import androidx.navigation.NavHostController import com.example.remind.app.Screens import androidx.navigation.compose.composable +@RequiresApi(Build.VERSION_CODES.O) @Composable fun PatienceGraph( navController: NavHostController, diff --git a/app/src/main/java/com/example/remind/feature/screens/patience/PatienceScreen.kt b/app/src/main/java/com/example/remind/feature/screens/patience/PatienceScreen.kt index dd10aa9..f31c68d 100644 --- a/app/src/main/java/com/example/remind/feature/screens/patience/PatienceScreen.kt +++ b/app/src/main/java/com/example/remind/feature/screens/patience/PatienceScreen.kt @@ -65,7 +65,7 @@ fun PatienceScreen() { RemindTheme.colors.main_6 } else { RemindTheme.colors.slate_300 - } + }, ) }, label = { @@ -80,9 +80,9 @@ fun PatienceScreen() { ) }, colors = NavigationBarItemDefaults.colors( - indicatorColor = RemindTheme.colors.main_6 - ) + indicatorColor = Color.Transparent ) + ) } } } diff --git a/app/src/main/java/com/example/remind/feature/screens/patience/writing/WritingMoodStep1.kt b/app/src/main/java/com/example/remind/feature/screens/patience/writing/WritingMoodStep1.kt new file mode 100644 index 0000000..e472ec8 --- /dev/null +++ b/app/src/main/java/com/example/remind/feature/screens/patience/writing/WritingMoodStep1.kt @@ -0,0 +1,4 @@ +package com.example.remind.feature.screens.patience.writing + +class WritingMoodStep1 { +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrowleft.xml b/app/src/main/res/drawable/ic_arrowleft.xml index fa2f19f..0f60e98 100644 --- a/app/src/main/res/drawable/ic_arrowleft.xml +++ b/app/src/main/res/drawable/ic_arrowleft.xml @@ -3,9 +3,6 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - + + diff --git a/app/src/main/res/drawable/ic_calendar_previous.xml b/app/src/main/res/drawable/ic_calendar_previous.xml new file mode 100644 index 0000000..fc4136b --- /dev/null +++ b/app/src/main/res/drawable/ic_calendar_previous.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/drawable/ic_center_onboarding.xml b/app/src/main/res/drawable/ic_center_onboarding.xml new file mode 100644 index 0000000..ed58da6 --- /dev/null +++ b/app/src/main/res/drawable/ic_center_onboarding.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_close.xml b/app/src/main/res/drawable/ic_close.xml new file mode 100644 index 0000000..0394d31 --- /dev/null +++ b/app/src/main/res/drawable/ic_close.xml @@ -0,0 +1,20 @@ + + + + diff --git a/app/src/main/res/drawable/ic_doctor_onboarding.xml b/app/src/main/res/drawable/ic_doctor_onboarding.xml new file mode 100644 index 0000000..479f9f9 --- /dev/null +++ b/app/src/main/res/drawable/ic_doctor_onboarding.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_example1.xml b/app/src/main/res/drawable/ic_example1.xml new file mode 100644 index 0000000..111a34e --- /dev/null +++ b/app/src/main/res/drawable/ic_example1.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_loginimg.xml b/app/src/main/res/drawable/ic_loginimg.xml new file mode 100644 index 0000000..f88ab2f --- /dev/null +++ b/app/src/main/res/drawable/ic_loginimg.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_logo_splash.xml b/app/src/main/res/drawable/ic_logo_splash.xml new file mode 100644 index 0000000..16df44a --- /dev/null +++ b/app/src/main/res/drawable/ic_logo_splash.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_patience_onboarding.xml b/app/src/main/res/drawable/ic_patience_onboarding.xml new file mode 100644 index 0000000..1fb73bc --- /dev/null +++ b/app/src/main/res/drawable/ic_patience_onboarding.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_phone_fill.xml b/app/src/main/res/drawable/ic_phone_fill.xml new file mode 100644 index 0000000..37b91eb --- /dev/null +++ b/app/src/main/res/drawable/ic_phone_fill.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_sos.xml b/app/src/main/res/drawable/ic_sos.xml new file mode 100644 index 0000000..c170146 --- /dev/null +++ b/app/src/main/res/drawable/ic_sos.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_star_fill.xml b/app/src/main/res/drawable/ic_star_fill.xml new file mode 100644 index 0000000..8c48fbc --- /dev/null +++ b/app/src/main/res/drawable/ic_star_fill.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_star_unfill.xml b/app/src/main/res/drawable/ic_star_unfill.xml new file mode 100644 index 0000000..5be32c7 --- /dev/null +++ b/app/src/main/res/drawable/ic_star_unfill.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/img_background.xml b/app/src/main/res/drawable/img_background.xml new file mode 100644 index 0000000..321df7c --- /dev/null +++ b/app/src/main/res/drawable/img_background.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/img_emptymood.png b/app/src/main/res/drawable/img_emptymood.png new file mode 100644 index 0000000..759dfa5 Binary files /dev/null and b/app/src/main/res/drawable/img_emptymood.png differ diff --git a/app/src/main/res/drawable/img_example_cheer.xml b/app/src/main/res/drawable/img_example_cheer.xml new file mode 100644 index 0000000..9344325 --- /dev/null +++ b/app/src/main/res/drawable/img_example_cheer.xml @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c4c170e..0d7e2fb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -7,6 +7,41 @@ Next Previous + 스스로를 돌아볼 수 있는\n당신만의 공간으로 초대합니다. + 카카오로 로그인하기 + 진료실 밖 일상을 더하다 + 환자용 + 의사용 + 센터용 + 다음 + 사용자 정보 + 보호자 정보 입력 + 긴급 시 연락할 수 있는\n보호자의 전화번호를 입력해 주세요! + 긴급 상황 발생 시 보호자에게 연락 + 긴급 상황 발생 시 담당자가 보호자에게 연락 할 수 있습니다. + 반가워요, %1$s님! + 오늘 하루의 통합적 기분을 선택해주세요! + 반갑습니다.\n%1$s 담당자 님! + 반갑습니다. %1$s님! + 시작하기 + 중요도 + 복용 + 미복용 + 약 미복용 사유 + + 무드 차트 + 주간 차트 기록 + + + 약 복용 체크 + 등록된 약이 없어요! + 오늘 하루 기분이 어떠셨나요? + 당신의 하루가 궁금해요 + 오늘의 기분 기록하기 + + 사용 입장 선택 + 어떤 입장에서 사용하실지 선택해주세요! + 김말랑 님, 좋은 하루 되세요! 관리 중인 환자