Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#138: 로그인후 이용제한 확인하기 #144

Merged
merged 8 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 182 additions & 2 deletions app/src/main/kotlin/com/bff/wespot/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.annotation.StringRes
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
Expand All @@ -17,6 +18,7 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxSize
Expand All @@ -29,6 +31,7 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
Expand All @@ -38,10 +41,12 @@ import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
Expand All @@ -52,28 +57,34 @@ import androidx.navigation.compose.rememberNavController
import com.bff.wespot.analytic.AnalyticsHelper
import com.bff.wespot.analytic.LocalAnalyticsHelper
import com.bff.wespot.designsystem.R
import com.bff.wespot.designsystem.component.button.WSButton
import com.bff.wespot.designsystem.component.button.WSButtonType
import com.bff.wespot.designsystem.component.header.WSTopBar
import com.bff.wespot.designsystem.theme.StaticTypeScale
import com.bff.wespot.designsystem.theme.WeSpotTheme
import com.bff.wespot.designsystem.theme.WeSpotThemeManager
import com.bff.wespot.entire.screen.destinations.SettingScreenDestination
import com.bff.wespot.model.ToastState
import com.bff.wespot.model.common.RestrictionType
import com.bff.wespot.model.notification.NotificationType
import com.bff.wespot.model.notification.convertNotificationType
import com.bff.wespot.navigation.Navigator
import com.bff.wespot.navigation.util.EXTRA_DATE
import com.bff.wespot.navigation.util.EXTRA_TARGET_ID
import com.bff.wespot.navigation.util.EXTRA_TYPE
import com.bff.wespot.notification.screen.NotificationNavigator
import com.bff.wespot.state.MainAction
import com.bff.wespot.state.MainUiState
import com.bff.wespot.R.string
import com.bff.wespot.ui.TopToast
import com.bff.wespot.state.MainAction
import com.bff.wespot.ui.WSBottomSheet
import com.bff.wespot.util.clickableSingle
import com.bff.wespot.viewmodel.MainViewModel
import com.ramcosta.composedestinations.dynamic.within
import com.ramcosta.composedestinations.navigation.navigate
import com.ramcosta.composedestinations.spec.NavGraphSpec
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.orbitmvi.orbit.compose.collectAsState
import timber.log.Timber
import javax.inject.Inject
Expand Down Expand Up @@ -274,6 +285,19 @@ private fun MainScreen(
toast = toast.copy(show = false)
}

if (state.restriction.restrictionType != RestrictionType.NONE) {
RestrictionBottomSheet(
content = when (state.restriction.restrictionType) {
RestrictionType.TEMPORARY_BAN_MESSAGE_REPORT -> RestrictionContent.TYPE1
RestrictionType.PERMANENT_BAN_MESSAGE_REPORT -> RestrictionContent.TYPE2
RestrictionType.PERMANENT_BAN_VOTE_REPORT -> RestrictionContent.TYPE3
else -> RestrictionContent.TYPE1
},
state = state,
navigator = navigator,
)
}

LaunchedEffect(Unit) {
action(MainAction.OnMainScreenEntered)
}
Expand Down Expand Up @@ -390,7 +414,10 @@ private fun RowScope.TabItem(
}
}

private fun navigateScreenFromNavArgs(navArgs: MainScreenNavArgs, navigator: NotificationNavigator) {
private fun navigateScreenFromNavArgs(
navArgs: MainScreenNavArgs,
navigator: NotificationNavigator
) {
when (navArgs.type) {
NotificationType.MESSAGE -> {
navigator.navigateToReceiverSelectionScreen()
Expand Down Expand Up @@ -423,3 +450,156 @@ private fun NavController.navigateToNavGraph(navGraph: NavGraphSpec) {
popUpTo([email protected]().id)
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun RestrictionBottomSheet(
content: RestrictionContent,
state: MainUiState,
navigator: Navigator,
) {
val context = LocalContext.current
val bottomSheetState = rememberModalBottomSheetState()
val coroutineScope = rememberCoroutineScope()

WSBottomSheet(
sheetState = bottomSheetState,
closeSheet = {
coroutineScope.launch {
bottomSheetState.hide()
}
}
) {
Column(
modifier = Modifier.padding(28.dp),
verticalArrangement = Arrangement.spacedBy(6.dp),
) {
Text(
text = stringResource(content.title),
style = StaticTypeScale.Default.body1,
modifier = Modifier.padding(bottom = 10.dp),
color = WeSpotThemeManager.colors.txtTitleColor,
)

BulletPoint(text = stringResource(content.body1))

BulletPoint(
text = stringResource(
content.body2,
state.restriction.toKoreanDate()
),
)

BulletPoint(text = stringResource(content.body3))

if (content.body4 != null) {
BulletPoint(text = stringResource(content.body4))
}

if (content.buttonNumber == 1) {
WSButton(
onClick = {
coroutineScope.launch {
bottomSheetState.hide()
}
},
text = stringResource(com.bff.wespot.auth.R.string.confirm),
paddingValues = PaddingValues(
start = 0.dp,
end = 0.dp,
top = 24.dp,
bottom = 10.dp
),
) {
it.invoke()
}
} else {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 20.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp),
) {
Box(modifier = Modifier.weight(1f)) {
WSButton(
onClick = {
coroutineScope.launch {
bottomSheetState.hide()
}
},
buttonType = WSButtonType.Secondary,
text = stringResource(R.string.close),
paddingValues = PaddingValues(0.dp),
) {
it()
}
}

Box(modifier = Modifier.weight(1f)) {
WSButton(
onClick = {
navigator.navigateToWebLink(context, state.kakaoChannel)
},
text = stringResource(com.bff.wespot.R.string.one_on_one),
paddingValues = PaddingValues(0.dp),
) {
it()
}
}
}
}
}
}
}

@Composable
private fun BulletPoint(text: String) {
Row(
horizontalArrangement = Arrangement.spacedBy(6.dp)
) {
Text(
text = "•",
style = StaticTypeScale.Default.body6,
color = WeSpotThemeManager.colors.txtSubColor,
)

Text(
text = text,
style = StaticTypeScale.Default.body6,
color = WeSpotThemeManager.colors.txtSubColor,
)
}
}

private enum class RestrictionContent(
@StringRes val title: Int,
@StringRes val body1: Int,
@StringRes val body2: Int,
@StringRes val body3: Int,
@StringRes val body4: Int? = null,
val buttonNumber: Int = 1,
) {
TYPE1(
com.bff.wespot.R.string.restriction_title,
com.bff.wespot.R.string.restriction_type1_body1,
com.bff.wespot.R.string.restriction_type1_body2,
com.bff.wespot.R.string.restriction_type1_body3,
com.bff.wespot.R.string.restriction_type1_body4,
),

TYPE2(
com.bff.wespot.R.string.restriction_title,
com.bff.wespot.R.string.restriction_type1_body1,
com.bff.wespot.R.string.restriction_type2_body2,
com.bff.wespot.R.string.restriction_type2_body3,
),

TYPE3(
com.bff.wespot.R.string.restriction_title,
com.bff.wespot.R.string.restriction_type1_body1,
com.bff.wespot.R.string.restriction_type3_body2,
com.bff.wespot.R.string.restriction_type3_body3,
null,
2,
);
}
Comment on lines +453 to +605
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MainActivity가 계속계속 커지는 느낌이라, 따로 앱 모듈 내에 component 패키지 만들어서 컴포저블 함수 옮기는 건 어떨까요 ??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

귀찮으니 다음에 해야겠다

4 changes: 4 additions & 0 deletions app/src/main/kotlin/com/bff/wespot/state/MainUiState.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.bff.wespot.state

import com.bff.wespot.model.common.Restriction

data class MainUiState (
val isPushNotificationNavigation: Boolean = true,
val userId: String = "",
val restriction: Restriction = Restriction.Empty,
val kakaoChannel: String,
)
17 changes: 15 additions & 2 deletions app/src/main/kotlin/com/bff/wespot/viewmodel/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package com.bff.wespot.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.bff.wespot.domain.repository.CommonRepository
import com.bff.wespot.domain.repository.DataStoreRepository
import com.bff.wespot.domain.repository.RemoteConfigRepository
import com.bff.wespot.domain.repository.user.UserRepository
import com.bff.wespot.domain.usecase.CacheProfileUseCase
import com.bff.wespot.domain.util.DataStoreKey
import com.bff.wespot.domain.util.RemoteConfigKey
import com.bff.wespot.model.user.response.NotificationSetting
import com.bff.wespot.state.MainAction
import com.bff.wespot.state.MainSideEffect
Expand All @@ -28,8 +31,12 @@ class MainViewModel @Inject constructor(
private val dataStoreRepository: DataStoreRepository,
private val userRepository: UserRepository,
private val coroutineDispatcher: CoroutineDispatcher,
private val commonRepository: CommonRepository,
private val remoteConfigRepository: RemoteConfigRepository,
) : ViewModel(), ContainerHost<MainUiState, MainSideEffect> {
override val container = container<MainUiState, MainSideEffect>(MainUiState())
override val container = container<MainUiState, MainSideEffect>(MainUiState(
kakaoChannel = remoteConfigRepository.fetchFromRemoteConfig(RemoteConfigKey.WESPOT_KAKAO_CHANNEL_URL)
))

init {
viewModelScope.launch {
Expand All @@ -53,9 +60,15 @@ class MainViewModel @Inject constructor(
}
}

private fun handleMainScreenEntered() {
private fun handleMainScreenEntered() = intent {
viewModelScope.launch(coroutineDispatcher) {
cacheProfileUseCase()
commonRepository.getRestriction()
.onSuccess {
reduce {
state.copy(restriction = it)
}
}
}
}

Expand Down
10 changes: 10 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@
<string name="app_name">WeSpot</string>
<string name="top_bar_animated_content_label">Top Bar Animated content</string>
<string name="bottom_bar_animated_content_label">bottom bar animated content label</string>
<string name="restriction_title">서비스 이용 제한 안내</string>
<string name="restriction_type1_body1">자동 신고 처리 시스템에 의한 신고 누적으로 서비스 이용이 제한되었습니다</string>
<string name="restriction_type1_body2">[이용 제한 기한]\n%1$s까지</string>
<string name="restriction_type1_body3">이용 제한은 기한이 종료된 다음 날 오전에 해제됩니다</string>
<string name="restriction_type1_body4">신고 누적 시 차후 영구적으로 이용 정지 될 수 있습니다</string>
<string name="restriction_type2_body2">[이용 제한 기한]\n영구 이용 제한</string>
<string name="restriction_type2_body3">요청에 따라 신고 사유를 확인해 드리거나, 이용 제한을 해제해 드리는 것은 불가능합니다</string>
<string name="restriction_type3_body2">[이용 제한 기한]\n학교·학년·반 정보 오기입</string>
<string name="restriction_type3_body3">이용 제한은 \'1:1 문의하기\'를 통한 개인 정보 수정 이후 해제됩니다</string>
<string name="one_on_one">1:1 문의하기</string>
</resources>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.bff.wespot.model.common

import java.time.LocalDate

data class Restriction(
val restrictionType: RestrictionType,
val releaseDate: LocalDate,
) {
fun toKoreanDate(): String {
return "${releaseDate.year}년 ${releaseDate.monthValue}월 ${releaseDate.dayOfMonth}일"
}

companion object {
val Empty = Restriction(
restrictionType = RestrictionType.NONE,
releaseDate = LocalDate.now(),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.bff.wespot.model.common

enum class RestrictionType {
NONE,
PERMANENT_BAN_VOTE_REPORT,
TEMPORARY_BAN_MESSAGE_REPORT,
PERMANENT_BAN_MESSAGE_REPORT,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.bff.wespot.data.remote.model.common

import com.bff.wespot.data.remote.extensions.toLocalDateFromDashPattern
import com.bff.wespot.model.common.Restriction
import com.bff.wespot.model.common.RestrictionType
import kotlinx.serialization.Serializable

@Serializable
data class RestrictionDto(
val restrictionType: String,
val releaseDate: String,
) {
fun toRestriction(): Restriction = Restriction(
restrictionType = RestrictionType.valueOf(restrictionType),
releaseDate = releaseDate.toLocalDateFromDashPattern(),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.bff.wespot.data.remote.model.common.EditProfileDto
import com.bff.wespot.data.remote.model.common.KakaoContentDto
import com.bff.wespot.data.remote.model.common.ProfanityDto
import com.bff.wespot.data.remote.model.common.ReportDto
import com.bff.wespot.data.remote.model.common.RestrictionDto

interface CommonDataSource {
suspend fun checkProfanity(content: ProfanityDto): Result<Unit>
Expand All @@ -17,4 +18,6 @@ interface CommonDataSource {
): Result<Unit>

suspend fun getKakaoContent(type: String): Result<KakaoContentDto>

suspend fun checkRestriction(): Result<RestrictionDto>
}
Loading
Loading