Skip to content

Commit 453ccdf

Browse files
committed
[BOOK-354] feat: 알림 설정 화면 UI 구현
1 parent 22073c5 commit 453ccdf

File tree

4 files changed

+197
-0
lines changed

4 files changed

+197
-0
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.ninecraft.booket.feature.settings.notification
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.getValue
5+
import androidx.compose.runtime.mutableStateOf
6+
import androidx.compose.runtime.setValue
7+
import com.ninecraft.booket.feature.screens.NotificationScreen
8+
import com.slack.circuit.codegen.annotations.CircuitInject
9+
import com.slack.circuit.retained.rememberRetained
10+
import com.slack.circuit.runtime.Navigator
11+
import com.slack.circuit.runtime.presenter.Presenter
12+
import dagger.assisted.Assisted
13+
import dagger.assisted.AssistedFactory
14+
import dagger.assisted.AssistedInject
15+
import dagger.hilt.android.components.ActivityRetainedComponent
16+
17+
class NotificationPresenter @AssistedInject constructor(
18+
@Assisted val navigator: Navigator,
19+
) : Presenter<NotificationUiState> {
20+
@Composable
21+
override fun present(): NotificationUiState {
22+
var isNotificationEnabled by rememberRetained { mutableStateOf(false) }
23+
24+
fun handleEvent(event: NotificationUiEvent) {
25+
when (event) {
26+
is NotificationUiEvent.OnBackClick -> {
27+
navigator.pop()
28+
}
29+
30+
is NotificationUiEvent.OnNotificationToggle -> {
31+
isNotificationEnabled = !isNotificationEnabled
32+
}
33+
}
34+
}
35+
return NotificationUiState(
36+
isNotificationEnabled = isNotificationEnabled,
37+
eventSink = ::handleEvent,
38+
)
39+
}
40+
41+
@CircuitInject(NotificationScreen::class, ActivityRetainedComponent::class)
42+
@AssistedFactory
43+
fun interface Factory {
44+
fun create(navigator: Navigator): NotificationPresenter
45+
}
46+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package com.ninecraft.booket.feature.settings.notification
2+
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.layout.Arrangement
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.Row
7+
import androidx.compose.foundation.layout.Spacer
8+
import androidx.compose.foundation.layout.fillMaxSize
9+
import androidx.compose.foundation.layout.fillMaxWidth
10+
import androidx.compose.foundation.layout.height
11+
import androidx.compose.foundation.layout.padding
12+
import androidx.compose.foundation.shape.RoundedCornerShape
13+
import androidx.compose.material3.Icon
14+
import androidx.compose.material3.Text
15+
import androidx.compose.runtime.Composable
16+
import androidx.compose.ui.Alignment
17+
import androidx.compose.ui.Modifier
18+
import androidx.compose.ui.graphics.vector.ImageVector
19+
import androidx.compose.ui.res.stringResource
20+
import androidx.compose.ui.res.vectorResource
21+
import com.ninecraft.booket.core.designsystem.DevicePreview
22+
import com.ninecraft.booket.core.designsystem.theme.ReedTheme
23+
import com.ninecraft.booket.core.designsystem.theme.White
24+
import com.ninecraft.booket.core.ui.ReedScaffold
25+
import com.ninecraft.booket.core.ui.component.ReedBackTopAppBar
26+
import com.ninecraft.booket.feature.screens.NotificationScreen
27+
import com.ninecraft.booket.feature.settings.R
28+
import com.ninecraft.booket.feature.settings.component.ReedSwitch
29+
import com.slack.circuit.codegen.annotations.CircuitInject
30+
import dagger.hilt.android.components.ActivityRetainedComponent
31+
import com.ninecraft.booket.core.designsystem.R as designR
32+
33+
@CircuitInject(NotificationScreen::class, ActivityRetainedComponent::class)
34+
@Composable
35+
internal fun NotificationUi(
36+
state: NotificationUiState,
37+
modifier: Modifier = Modifier,
38+
) {
39+
ReedScaffold(
40+
modifier = modifier.fillMaxSize(),
41+
containerColor = White,
42+
) { innerPadding ->
43+
Column(
44+
modifier = modifier
45+
.fillMaxSize()
46+
.padding(innerPadding),
47+
) {
48+
ReedBackTopAppBar(
49+
modifier = modifier.fillMaxWidth(),
50+
title = stringResource(R.string.settings_notification),
51+
onBackClick = {
52+
state.eventSink(NotificationUiEvent.OnBackClick)
53+
},
54+
)
55+
Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing2))
56+
Row(
57+
modifier = modifier
58+
.padding(horizontal = ReedTheme.spacing.spacing5)
59+
.fillMaxWidth()
60+
.background(
61+
color = ReedTheme.colors.baseSecondary,
62+
shape = RoundedCornerShape(ReedTheme.radius.md),
63+
)
64+
.padding(
65+
vertical = ReedTheme.spacing.spacing6,
66+
horizontal = ReedTheme.spacing.spacing5,
67+
),
68+
verticalAlignment = Alignment.CenterVertically,
69+
horizontalArrangement = Arrangement.SpaceBetween,
70+
) {
71+
Column {
72+
Text(
73+
text = stringResource(R.string.notification_enable_title),
74+
color = ReedTheme.colors.contentBrand,
75+
style = ReedTheme.typography.body1SemiBold,
76+
)
77+
Text(
78+
text = stringResource(R.string.notification_enable_description),
79+
color = ReedTheme.colors.contentTertiary,
80+
style = ReedTheme.typography.label2Regular,
81+
)
82+
}
83+
Icon(
84+
imageVector = ImageVector.vectorResource(designR.drawable.ic_chevron_right),
85+
contentDescription = "Chevron Right Icon",
86+
tint = ReedTheme.colors.contentBrand,
87+
)
88+
}
89+
Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing4))
90+
Row(
91+
modifier = modifier
92+
.fillMaxWidth()
93+
.padding(
94+
vertical = ReedTheme.spacing.spacing4,
95+
horizontal = ReedTheme.spacing.spacing5,
96+
),
97+
verticalAlignment = Alignment.CenterVertically,
98+
horizontalArrangement = Arrangement.SpaceBetween,
99+
) {
100+
Column {
101+
Text(
102+
text = stringResource(R.string.notification_toggle_title),
103+
color = ReedTheme.colors.contentPrimary,
104+
style = ReedTheme.typography.body1Medium,
105+
)
106+
Text(
107+
text = stringResource(R.string.notification_toggle_description),
108+
color = ReedTheme.colors.contentTertiary,
109+
style = ReedTheme.typography.label1Medium,
110+
)
111+
}
112+
ReedSwitch(
113+
checked = state.isNotificationEnabled,
114+
onCheckedChange = {
115+
state.eventSink(NotificationUiEvent.OnNotificationToggle)
116+
},
117+
)
118+
}
119+
}
120+
}
121+
}
122+
123+
@DevicePreview
124+
@Composable
125+
private fun NotificationUiPreview() {
126+
ReedTheme {
127+
NotificationUi(
128+
state = NotificationUiState(
129+
eventSink = {},
130+
),
131+
)
132+
}
133+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.ninecraft.booket.feature.settings.notification
2+
3+
import com.slack.circuit.runtime.CircuitUiEvent
4+
import com.slack.circuit.runtime.CircuitUiState
5+
6+
data class NotificationUiState(
7+
val isNotificationEnabled: Boolean = false,
8+
val eventSink: (NotificationUiEvent) -> Unit,
9+
) : CircuitUiState
10+
11+
sealed interface NotificationUiEvent : CircuitUiEvent {
12+
data object OnBackClick : NotificationUiEvent
13+
data object OnNotificationToggle : NotificationUiEvent
14+
}

feature/settings/src/main/res/values/strings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,8 @@
2020
<string name="settings_optional_update_button_text">업데이트하기</string>
2121
<string name="settings_login">로그인</string>
2222
<string name="settings_notification">알림</string>
23+
<string name="notification_enable_title">알림을 켜주세요.</string>
24+
<string name="notification_enable_description">기기 설정에서 Reed 알림을 설정하세요.\n독서 기록에 도움되는 알림을 받을 수 있어요.</string>
25+
<string name="notification_toggle_title">알림 받기</string>
26+
<string name="notification_toggle_description">리드에서 알림을 보내드려요.</string>
2327
</resources>

0 commit comments

Comments
 (0)