Skip to content

Commit 02c20a1

Browse files
authored
Merge pull request #482 from BCSDLab/develop
Update v4.0.8
2 parents ad31847 + fdcb31a commit 02c20a1

File tree

63 files changed

+2120
-371
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+2120
-371
lines changed

core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/snackbar/CustomSnackBarHost.kt

Lines changed: 56 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import androidx.compose.foundation.layout.fillMaxSize
99
import androidx.compose.foundation.layout.fillMaxWidth
1010
import androidx.compose.foundation.layout.padding
1111
import androidx.compose.foundation.layout.width
12-
import androidx.compose.foundation.layout.wrapContentHeight
13-
import androidx.compose.foundation.layout.wrapContentWidth
1412
import androidx.compose.foundation.shape.RoundedCornerShape
1513
import androidx.compose.material3.SnackbarDuration
1614
import androidx.compose.material3.SnackbarHost
@@ -22,6 +20,7 @@ import androidx.compose.ui.Modifier
2220
import androidx.compose.ui.draw.clip
2321
import androidx.compose.ui.graphics.Color
2422
import androidx.compose.ui.text.TextStyle
23+
import androidx.compose.ui.text.style.TextAlign
2524
import androidx.compose.ui.tooling.preview.Preview
2625
import androidx.compose.ui.unit.Dp
2726
import androidx.compose.ui.unit.dp
@@ -32,35 +31,46 @@ import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
3231
@Composable
3332
fun CustomSnackBarHost(
3433
hotState: SnackbarHostState,
35-
radius: Dp = 0.dp,
36-
messageTextStyle: TextStyle = KoinTheme.typography.regular12.copy(
37-
color = Color.White
34+
modifier: Modifier = Modifier,
35+
radius: Dp = 6.dp,
36+
37+
messageTextStyle: TextStyle =KoinTheme.typography.regular14.copy(
38+
color = KoinTheme.colors.neutral0
3839
),
39-
actionLabelTextStyle: TextStyle = KoinTheme.typography.regular12.copy(
40-
color = Color.White
40+
actionLabelTextStyle: TextStyle = KoinTheme.typography.regular14.copy(
41+
color = KoinTheme.colors.sub500
4142
),
42-
background: Color = Color.Black,
43+
background: Color = KoinTheme.colors.primary700,
4344
alignment: Alignment = Alignment.BottomCenter,
4445
paddingValues: PaddingValues = PaddingValues(bottom = 20.dp, start = 10.dp, end = 10.dp),
45-
innerPaddingValues: PaddingValues = PaddingValues(horizontal = 10.dp, vertical = 16.dp)
46+
innerPaddingValues: PaddingValues = PaddingValues(horizontal = 16.dp, vertical = 20.dp),
47+
onAction: (() -> Unit)? = null
4648
) {
47-
SnackbarHost(
48-
hostState = hotState,
49-
) { snackbarData ->
50-
SnackBarContent(
51-
messageText = snackbarData.visuals.message,
52-
actionLabelText = snackbarData.visuals.actionLabel ?: "",
53-
radius = radius,
54-
background = background,
55-
messageTextStyle = messageTextStyle,
56-
actionLabelTextStyle = actionLabelTextStyle,
57-
alignment = alignment,
58-
paddingValues = paddingValues,
59-
innerPaddingValues = innerPaddingValues,
60-
onAction = { snackbarData.dismiss() }
61-
)
62-
}
49+
Box(
50+
modifier = modifier
51+
.fillMaxSize()
52+
.padding(paddingValues),
53+
contentAlignment = alignment
54+
) {
55+
SnackbarHost(
56+
hostState = hotState,
57+
) { snackbarData ->
58+
SnackBarContent(
59+
messageText = snackbarData.visuals.message,
60+
actionLabelText = snackbarData.visuals.actionLabel ?: "",
61+
radius = radius,
62+
background = background,
63+
messageTextStyle = messageTextStyle,
64+
actionLabelTextStyle = actionLabelTextStyle,
65+
innerPaddingValues = innerPaddingValues,
66+
onAction = {
67+
onAction?.invoke()
68+
snackbarData.dismiss()
69+
}
70+
)
71+
}
6372

73+
}
6474
}
6575

6676
@Composable
@@ -76,42 +86,35 @@ private fun SnackBarContent(
7686
actionLabelTextStyle: TextStyle = KoinTheme.typography.regular12.copy(
7787
color = Color.White
7888
),
79-
alignment: Alignment = Alignment.BottomCenter,
80-
paddingValues: PaddingValues = PaddingValues(bottom = 20.dp, start = 10.dp, end = 10.dp),
8189
innerPaddingValues: PaddingValues = PaddingValues(horizontal = 10.dp, vertical = 16.dp),
8290
onAction: () -> Unit = {}
8391
) {
8492
Box(
8593
modifier = modifier
86-
.fillMaxSize()
87-
.padding(paddingValues),
88-
contentAlignment = alignment
94+
.fillMaxWidth()
95+
.clip(RoundedCornerShape(radius))
96+
.background(background)
97+
.padding(innerPaddingValues)
8998
) {
90-
Box(
91-
modifier = modifier
92-
.fillMaxWidth()
93-
.clip(RoundedCornerShape(radius))
94-
.background(background)
95-
.padding(innerPaddingValues)
99+
Row(
100+
verticalAlignment = Alignment.CenterVertically,
96101
) {
97-
Row(
98-
verticalAlignment = Alignment.CenterVertically,
99-
) {
100-
Spacer(modifier = Modifier.width(4.dp))
102+
Spacer(modifier = Modifier.width(4.dp))
103+
Text(
104+
text = messageText,
105+
style = messageTextStyle,
106+
modifier = Modifier.weight(1f),
107+
)
108+
Spacer(modifier = Modifier.weight(0.05f))
109+
if (actionLabelText.isNotEmpty()) {
101110
Text(
102-
text = messageText,
103-
style = messageTextStyle,
104-
modifier = Modifier.weight(1f),
111+
modifier = Modifier
112+
.weight(0.2f)
113+
.noRippleClickable { onAction() },
114+
text = actionLabelText,
115+
style = actionLabelTextStyle,
116+
textAlign = TextAlign.End
105117
)
106-
Spacer(modifier = Modifier.weight(0.05f))
107-
if (actionLabelText.isNotEmpty()) {
108-
Text(
109-
text = actionLabelText,
110-
style = actionLabelTextStyle,
111-
modifier = Modifier.weight(0.1f).noRippleClickable { onAction() }
112-
)
113-
}
114-
115118
}
116119
}
117120
}
@@ -143,4 +146,4 @@ private fun SnackBarContentPreview() {
143146
messageText = "스낵바 메시지",
144147
actionLabelText = "닫기",
145148
)
146-
}
149+
}

core/src/main/java/in/koreatech/koin/core/abtest/Experiment.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ enum class Experiment(
77

88
BENEFIT_STORE("Benefit", ExperimentGroup.A, ExperimentGroup.B),
99
DINING_SHARE("campus_share_v1", ExperimentGroup.SHARE_ORIGINAL, ExperimentGroup.SHARE_NEW),
10-
MAIN_DINING_SEE_MORE("c_main_dining_v1", ExperimentGroup.MAIN_DINING_ORIGINAL, ExperimentGroup.MAIN_DINING_NEW);
10+
MAIN_DINING_SEE_MORE("c_main_dining_v1", ExperimentGroup.MAIN_DINING_ORIGINAL, ExperimentGroup.MAIN_DINING_NEW),
11+
MAIN_ARTICLE_KEYWORD_BANNER("c_keyword_ banner_v1", ExperimentGroup.MAIN_BANNER_ORIGINAL, ExperimentGroup.MAIN_BANNER_NEW);
1112

1213
init {
1314
require(experimentGroups.isNotEmpty()) { "Experiment should have at least one group" }
@@ -23,4 +24,7 @@ object ExperimentGroup {
2324

2425
const val MAIN_DINING_ORIGINAL = "main_dining_original"
2526
const val MAIN_DINING_NEW = "main_dining_new"
27+
28+
const val MAIN_BANNER_ORIGINAL = "banner_original"
29+
const val MAIN_BANNER_NEW = "banner_new"
2630
}

core/src/main/java/in/koreatech/koin/core/constant/AnalyticsConstant.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ object AnalyticsConstant {
9999

100100
const val CAMPUS_DINING_1 = "CAMPUS_dining_1"
101101
const val CAMPUS_NOTICE_1 = "CAMPUS_notice_1"
102+
const val POPULAR_NOTICE_BANNER = "popular_notice_banner"
103+
const val TO_MANAGE_KEYWORD = "to_manage_keyword"
102104
}
103105

104106
const val PREVIOUS_PAGE = "previous_page"
Loading
Loading
Loading

core/src/main/res/values/colors.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@
142142
<color name="primary_100">#CFF1F9</color>
143143
<!-- Sub -->
144144
<color name="sub_sub500">#F7941E</color>
145+
<color name="sub_sub600">#D47415</color>
145146
<!-- Neutral -->
146147
<color name="neutral_800">#000000</color>
147148
<color name="neutral_700">#1F1F1F</color>

data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ interface TimetableAuthApi {
4747
): TimetableFrameResponse
4848

4949
@DELETE("/v2/timetables/frame")
50-
suspend fun deleteTimetableFrame()
50+
suspend fun deleteTimetableFrame(
51+
@Query("id") frameId: Int
52+
): Response<Unit>
5153

5254
@GET("/v2/timetables/frames")
5355
suspend fun getTimetableFrames(
@@ -71,5 +73,7 @@ interface TimetableAuthApi {
7173
): Response<Unit>
7274

7375
@DELETE("/v2/all/timetables/frame")
74-
suspend fun deleteAllTimetableFrame()
76+
suspend fun deleteAllTimetableFrame(
77+
@Query("semester") semester: String,
78+
): Response<Unit>
7579
}

data/src/main/java/in/koreatech/koin/data/constant/Constant.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ const val BUS_REQUEST_TIME_FORMAT = "HH:mm"
66

77
const val STORE_OPEN_TIME_FORMAT = "HH:mm"
88
const val STORE_CLOSE_TIME_FORMAT = "HH:mm"
9-
const val STORE_UPDATED_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss" // 2018-03-23 20:25:24
9+
const val STORE_UPDATED_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss" // 2018-03-23 20:25:24
10+
11+
const val WEEK_IN_MILLIS = 7 * 24 * 60 * 60 * 1000L

data/src/main/java/in/koreatech/koin/data/repository/ArticleRepositoryImpl.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import `in`.koreatech.koin.data.source.local.ArticleLocalDataSource
55
import `in`.koreatech.koin.data.source.remote.ArticleRemoteDataSource
66
import `in`.koreatech.koin.domain.model.article.Article
77
import `in`.koreatech.koin.domain.model.article.ArticleHeader
8+
import `in`.koreatech.koin.domain.model.article.ArticleNoti
89
import `in`.koreatech.koin.domain.model.article.ArticlePagination
10+
import `in`.koreatech.koin.domain.model.article.articleNotiContent
911
import `in`.koreatech.koin.domain.model.user.User
1012
import `in`.koreatech.koin.domain.repository.ArticleRepository
1113
import `in`.koreatech.koin.domain.repository.UserRepository
@@ -149,6 +151,18 @@ class ArticleRepositoryImpl @Inject constructor(
149151
}
150152
}
151153

154+
override fun fetchKeywordNoti(): Flow<ArticleNoti> {
155+
return flow {
156+
emit(articleNotiContent[articleLocalDataSource.fetchKeywordNotiIndex()])
157+
}
158+
}
159+
160+
override fun saveKeywordNotiIndex(): Flow<Unit> {
161+
return flow {
162+
emit(articleLocalDataSource.saveKeywordNotiIndex())
163+
}
164+
}
165+
152166
override fun fetchSearchedArticles(
153167
query: String,
154168
boardId: Int,

data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,26 @@ package `in`.koreatech.koin.data.repository
33
import com.google.gson.Gson
44
import com.google.gson.reflect.TypeToken
55
import `in`.koreatech.koin.data.request.timetable.LecturesQueryRequest
6+
import `in`.koreatech.koin.data.request.timetable.TimetableFrameCreateQueryRequest
7+
import `in`.koreatech.koin.data.request.timetable.TimetableFrameQueryRequest
68
import `in`.koreatech.koin.data.request.timetable.toCustomLectureQueryRequest
79
import `in`.koreatech.koin.data.request.timetable.toLectureQueryRequest
810
import `in`.koreatech.koin.data.request.timetable.toTimetableLecturesQueryRequest
911
import `in`.koreatech.koin.data.source.datastore.TimetableDataStore
1012
import `in`.koreatech.koin.data.source.remote.TimetableRemoteDataSource
13+
import `in`.koreatech.koin.data.util.getErrorResponse
1114
import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameCreateQuery
1215
import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameQuery
1316
import `in`.koreatech.koin.domain.model.timetable.request.TimetableLecturesQuery
1417
import `in`.koreatech.koin.domain.model.timetable.response.Lecture
1518
import `in`.koreatech.koin.domain.model.timetable.response.TimetableFrame
19+
import `in`.koreatech.koin.domain.model.timetable.response.TimetableLecture
1620
import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures
1721
import `in`.koreatech.koin.domain.repository.TimetableRepository
1822
import kotlinx.coroutines.flow.Flow
1923
import kotlinx.coroutines.flow.firstOrNull
2024
import kotlinx.coroutines.flow.flow
25+
import retrofit2.HttpException
2126
import javax.inject.Inject
2227

2328
class TimetableRepositoryImpl @Inject constructor(
@@ -46,7 +51,7 @@ class TimetableRepositoryImpl @Inject constructor(
4651
timetableRemoteDataSource.getTimetableLectures(timetableFrameId).toTimetableLectures()
4752
}
4853

49-
override suspend fun getTimetableLectures(semester: String): Result<TimetableLectures> = runCatching{
54+
override suspend fun getTimetableLectures(semester: String): Result<TimetableLectures> = runCatching {
5055
val timetableLecturesString = timetableDataStore.getString(semester).firstOrNull().orEmpty()
5156
val timetableLecturesType = object : TypeToken<TimetableLectures>() {}.type
5257
try {
@@ -56,8 +61,9 @@ class TimetableRepositoryImpl @Inject constructor(
5661
}
5762
}
5863

59-
override suspend fun putTimetableLectures(lectures: TimetableLecturesQuery): TimetableLectures =
64+
override suspend fun putTimetableLectures(lectures: TimetableLecturesQuery): Result<TimetableLectures> = runCatching {
6065
timetableRemoteDataSource.putTimetableLectures(lectures.toTimetableLecturesQueryRequest()).toTimetableLectures()
66+
}
6167

6268
override suspend fun putTimetableLectures(key: String, value: TimetableLectures): Result<TimetableLectures> = runCatching {
6369
timetableDataStore.putString(key, gson.toJson(value))
@@ -68,8 +74,14 @@ class TimetableRepositoryImpl @Inject constructor(
6874
}
6975
}
7076

71-
override suspend fun putTimetableFrame(id: Int, frame: TimetableFrameQuery): TimetableFrame {
72-
TODO("Not yet implemented")
77+
override suspend fun putTimetableFrame(id: Int, frame: TimetableFrameQuery): Result<TimetableFrame> = runCatching {
78+
timetableRemoteDataSource.putTimetableFrame(
79+
id,
80+
TimetableFrameQueryRequest(
81+
frame.timetableName,
82+
frame.isMain
83+
)
84+
).toTimetableFrameResponse()
7385
}
7486

7587
override suspend fun postTimetableLectures(frameId: Int, lectures: List<Lecture>): Result<TimetableLectures> = runCatching {
@@ -86,13 +98,37 @@ class TimetableRepositoryImpl @Inject constructor(
8698
)).toTimetableLectures()
8799
}
88100

101+
override suspend fun postTimetableBasicLectures(frameId: Int, lectures: List<TimetableLecture>): Result<TimetableLectures> = runCatching {
102+
val queryLectures = lectures.map {
103+
if (it.lectureId == 0) {
104+
it.toCustomLectureQueryRequest()
105+
} else {
106+
it.toLectureQueryRequest()
107+
}
108+
}
89109

90-
override suspend fun postTimetableFrame(frame: TimetableFrameCreateQuery): TimetableFrame {
91-
TODO("Not yet implemented")
110+
timetableRemoteDataSource.postTimetableLectures(LecturesQueryRequest(
111+
timetableFrameId = frameId,
112+
timetableLecture = queryLectures
113+
)).toTimetableLectures()
92114
}
93115

94-
override suspend fun deleteTimetableFrame() {
95-
TODO("Not yet implemented")
116+
117+
override suspend fun postTimetableFrame(frame: TimetableFrameCreateQuery): Result<TimetableFrame> = runCatching {
118+
timetableRemoteDataSource.postTimetableFrame(
119+
TimetableFrameCreateQueryRequest(
120+
semester = frame.semester,
121+
timetableName = frame.timetableName
122+
)
123+
).toTimetableFrameResponse()
124+
}.recoverCatching {
125+
if(it is HttpException) throw Exception(it.getErrorResponse().message ?: "")
126+
else throw it
127+
}
128+
129+
130+
override suspend fun deleteTimetableFrame(frameId: Int): Result<Unit> = runCatching {
131+
timetableRemoteDataSource.deleteTimetableFrame(frameId)
96132
}
97133

98134
override suspend fun deleteTimetableLecture(id: Int): Result<Unit> = runCatching {
@@ -107,7 +143,7 @@ class TimetableRepositoryImpl @Inject constructor(
107143
timetableRemoteDataSource.deleteTimetableLectures(lectureIds)
108144
}
109145

110-
override suspend fun deleteAllTimetableFrame() {
111-
TODO("Not yet implemented")
146+
override suspend fun deleteAllTimetableFrame(semester: String): Result<Unit> = runCatching {
147+
timetableRemoteDataSource.deleteAllTimetableFrame(semester)
112148
}
113149
}

0 commit comments

Comments
 (0)