Skip to content

Commit

Permalink
25학번 이전 교양영역 보여주는 기능 추가 (#392)
Browse files Browse the repository at this point in the history
  • Loading branch information
plgafhd authored Feb 1, 2025
1 parent e85fbac commit dac329f
Show file tree
Hide file tree
Showing 16 changed files with 67 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class LectureSearchPagingSource(
academic_year = tags.extractTagString(TagType.ACADEMIC_YEAR),
department = tags.extractTagString(TagType.DEPARTMENT),
category = tags.extractTagString(TagType.CATEGORY),
categoryPre2025 = tags.extractTagString(TagType.CATEGORY_PRE2025),
times = times,
timesToExclude = timesToExclude,
etc = tags.mapNotNull {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class LectureSearchRepositoryImpl @Inject constructor(
addAll(response.academicYear.map { TagDto(TagType.ACADEMIC_YEAR, it) })
addAll(response.credit.map { TagDto(TagType.CREDIT, it) })
addAll(response.category.map { TagDto(TagType.CATEGORY, it) })
addAll(response.categoryPre2025.map { TagDto(TagType.CATEGORY_PRE2025, it) })
addAll(response.sortCriteria.map { TagDto(TagType.SORT_CRITERIA, it) })
}
return list
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/com/wafflestudio/snutt2/lib/ModelExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ fun TagType.color(): androidx.compose.ui.graphics.Color {
TagType.CREDIT -> SNUTTColors.Sky
TagType.TIME -> SNUTTColors.Blue
TagType.CATEGORY -> SNUTTColors.NavyBlue
TagType.CATEGORY_PRE2025 -> SNUTTColors.NavyBlue
TagType.ETC -> SNUTTColors.Violet
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ data class GetTagListResults(
@Json(name = "credit") val credit: List<String>,
@Json(name = "instructor") val instructor: List<String>,
@Json(name = "category") val category: List<String>,
@Json(name = "categoryPre2025") val categoryPre2025: List<String>,
@Json(name = "sortCriteria") val sortCriteria: List<String>,
)
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ data class PostCustomLectureParams(
@Json(name = "enrollment") var enrollment: Long? = null,
@Json(name = "remark") var remark: String? = null,
@Json(name = "category") var category: String? = null,
@Json(name = "categoryPre2025") var categoryPre2025: String? = null,
@Json(name = "colorIndex") var colorIndex: Long? = null, // 색상
@Json(name = "color") var color: ColorDto? = null,
@Json(name = "is_forced") var isForced: Boolean? = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ data class PostSearchQueryParams(
@Json(name = "academic_year") val academic_year: List<String>? = null,
@Json(name = "department") val department: List<String>? = null,
@Json(name = "category") val category: List<String>? = null,
@Json(name = "categoryPre2025") val categoryPre2025: List<String>? = null,
@Json(name = "etc") val etc: List<String>? = null,
@Json(name = "times") val times: List<SearchTimeDto>?,
@Json(name = "timesToExclude") val timesToExclude: List<SearchTimeDto>?,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,3 @@
package com.wafflestudio.snutt2.lib.network.dto

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.wafflestudio.snutt2.lib.network.dto.core.ClassTimeDto
import com.wafflestudio.snutt2.lib.network.dto.core.ColorDto

@JsonClass(generateAdapter = true)
data class PutLectureParams(
@Json(name = "id") var id: String? = null,
@Json(name = "classification") var classification: String? = null,
@Json(name = "department") var department: String? = null,
@Json(name = "academic_year") var academic_year: String? = null,
@Json(name = "course_number") var course_number: String? = null,
@Json(name = "lecture_number") var lecture_number: String? = null,
@Json(name = "course_title") var course_title: String? = null,
@Json(name = "credit") var credit: Long? = null,
@Json(name = "class_time") var class_time: String? = null, // lecture 검색시 띄어주는 class time
@Json(name = "class_time_json") var class_time_json: List<ClassTimeDto>? = null,
@Json(name = "location") var location: String? = null,
@Json(name = "instructor") var instructor: String? = null,
@Json(name = "quota") var quota: Long? = null,
@Json(name = "enrollment") var enrollment: Long? = null,
@Json(name = "remark") var remark: String? = null,
@Json(name = "category") var category: String? = null,
@Json(name = "colorIndex") var colorIndex: Long? = null, // 색상
@Json(name = "color") var color: ColorDto? = null,
@Json(name = "is_forced") var isForced: Boolean? = false,
)
typealias PutLectureParams = PostCustomLectureParams
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ data class LectureDto(
@Json(name = "freshmanQuota") val freshmanQuota: Long?,
@Json(name = "remark") val remark: String,
@Json(name = "category") val category: String?,
@Json(name = "categoryPre2025") val categoryPre2025: String?,
@Json(name = "colorIndex") val colorIndex: Long = 0, // 색상
@Json(name = "color") val color: ColorDto = ColorDto(),
@Json(name = "registrationCount") val registrationCount: Long = 0,
Expand All @@ -41,6 +42,7 @@ data class LectureDto(
academic_year = null,
credit = 0,
category = null,
categoryPre2025 = null,
classification = null,
course_number = null,
lecture_number = null,
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/com/wafflestudio/snutt2/model/TagType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ enum class TagType(val isExclusive: Boolean) {
CREDIT(false),
TIME(false),
CATEGORY(false),
CATEGORY_PRE2025(false),
ETC(false),
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.wafflestudio.snutt2.R
import com.wafflestudio.snutt2.components.compose.CloseIcon
import com.wafflestudio.snutt2.components.compose.clicks
import com.wafflestudio.snutt2.lib.color
import com.wafflestudio.snutt2.model.TagDto
import com.wafflestudio.snutt2.model.TagType
import com.wafflestudio.snutt2.ui.SNUTTColors
import com.wafflestudio.snutt2.ui.SNUTTTypography

Expand All @@ -36,17 +39,16 @@ fun LazyItemScope.TagCell(
) {
Spacer(modifier = Modifier.width(10.dp))
Text(
text = tagDto.name,
style = SNUTTTypography.body1.copy(fontSize = 15.sp, color = SNUTTColors.AllWhite),
text = (if (tagDto.type == TagType.CATEGORY_PRE2025) stringResource(R.string.search_option_tag_type_general_pre2025) + " " else "") + tagDto.name,
style = SNUTTTypography.body1.copy(fontSize = 14.sp, color = SNUTTColors.AllWhite),
textAlign = TextAlign.Center,
)
CloseIcon(
modifier = Modifier
.size(20.dp)
.padding(2.5.dp)
.width(20.dp) // 스펙 상 15dp이나, CloseIcon이 자체적으로 갖는 여백으로 인해 20dp로 설정
.clicks { onClick() },
colorFilter = ColorFilter.tint(SNUTTColors.AllWhite),
)
Spacer(modifier = Modifier.width(10.dp))
Spacer(modifier = Modifier.width(5.dp)) // 스펙 상 5dp이나, CloseIcon이 자체적으로 갖는 여백으로 인해 10dp로 설정
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
Expand Down Expand Up @@ -63,11 +64,11 @@ class SearchViewModel @Inject constructor(
private val _selectedTags = MutableStateFlow(listOf<TagDto>())
val selectedTags = _selectedTags.asStateFlow()

private val _searchTagList = MutableStateFlow(listOf<TagDto>())
private val _searchTagListFlow = MutableStateFlow(listOf<TagDto>())

private val currentTable = currentTableRepository.currentTable

private val semesterChange =
val semesterChange =
currentTable
.filterNotNull()
.map { it.year * 10 + it.semester } // .distinctUntilChanged()
Expand All @@ -91,6 +92,16 @@ class SearchViewModel @Inject constructor(

val recentSearchedDepartments: StateFlow<List<TagDto>> = lectureSearchRepository.recentSearchedDepartments

private val timeTags = listOf(TagDto.TIME_EMPTY, TagDto.TIME_SELECT)
private val etcTags = listOf(TagDto.ETC_ENG, TagDto.ETC_MILITARY)

// 2025년 이전 학기에는 "구) 교양분류" 타입의 태그가 내려오지 않는다.
val tagTypesNotEmpty: StateFlow<List<TagType>> = _searchTagListFlow
.map { tags ->
(tags + etcTags + timeTags).map { it.type }.toSet().toList()
}
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())

init {
viewModelScope.launch {
semesterChange.distinctUntilChanged().collectLatest {
Expand All @@ -104,13 +115,18 @@ class SearchViewModel @Inject constructor(
}
}
}
viewModelScope.launch {
// 25년 이후에서 구) 교양분류를 선택한 상태로 25년 이전으로 이동하면, 태그 선택지가 사라져서, 빈 sheet가 뜨게 된다. 이를 방지.
combine(tagTypesNotEmpty, _selectedTagType) { tagTypes, selectedTagType ->
!tagTypes.contains(selectedTagType)
}.distinctUntilChanged().filter { it }.collectLatest {
setTagType(TagType.SORT_CRITERIA)
}
}
}

private val timeTags = listOf(TagDto.TIME_EMPTY, TagDto.TIME_SELECT)
private val etcTags = listOf(TagDto.ETC_ENG, TagDto.ETC_MILITARY)

val tagsByTagType: StateFlow<List<Selectable<TagDto>>> = combine(
_searchTagList, _selectedTagType, _selectedTags,
_searchTagListFlow, _selectedTagType, _selectedTags,
) { tags, selectedTagType, selectedTags ->
(tags + etcTags + timeTags).filter { it.type == selectedTagType }
.map { it.toDataWithState(selectedTags.contains(it)) }
Expand Down Expand Up @@ -283,7 +299,7 @@ class SearchViewModel @Inject constructor(
private suspend fun clear() {
_searchTitle.emit("")
_selectedLecture.emit(null)
_searchTagList.emit(emptyList())
_searchTagListFlow.emit(emptyList())
_selectedTags.emit(emptyList())
lazyListState = LazyListState(0, 0)
/* TODO
Expand All @@ -294,7 +310,7 @@ class SearchViewModel @Inject constructor(

private suspend fun fetchSearchTagList() {
val currentTable = currentTable.filterNotNull().first()
_searchTagList.emit(
_searchTagListFlow.emit(
lectureSearchRepository.getSearchTags(
currentTable.year, currentTable.semester,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ fun SearchOptionSheet(
val tagsByTagType by viewModel.tagsByTagType.collectAsState()
val selectedTagType by viewModel.selectedTagType.collectAsState()
val recentSearchedDepartments by viewModel.selectableRecentSearchedDepartments.collectAsState()
val tagTypesNotEmpty by viewModel.tagTypesNotEmpty.collectAsState()
val scope = rememberCoroutineScope()

var optionSheetMode by remember {
Expand All @@ -55,8 +56,8 @@ fun SearchOptionSheet(
label = "baseAnimatedFloat",
)

var normalSheetHeightPx = remember { 0 } // 태그 선택 sheet의 높이
var maxSheetHeightPx = remember { 0 } // 시간대 선택 sheet의 높이
var normalSheetHeightPx by remember { mutableStateOf(0) } // 태그 선택 sheet의 높이
var maxSheetHeightPx by remember { mutableStateOf(0) } // 시간대 선택 sheet의 높이
val sheetHeightAnimatedPx = remember {
derivedStateOf {
// 태그 선택 sheet의 높이 ~ 시간대 선택 sheet의 높이까지 baseAnimatedFloat에 따라 변하는 값
Expand All @@ -69,6 +70,7 @@ fun SearchOptionSheet(
) { constraints ->
val tagTypePlaceable = subcompose(slotId = 1) {
TagTypeColumn(
tagTypesNotEmpty = tagTypesNotEmpty,
selectedTagType = selectedTagType,
baseAnimatedFloat = baseAnimatedFloat,
) {
Expand Down Expand Up @@ -146,13 +148,10 @@ fun SearchOptionSheet(
}
}.first().measure(constraints)

// 한번만 계산, 할당
if (normalSheetHeightPx == 0 && maxSheetHeightPx == 0) {
normalSheetHeightPx =
tagTypePlaceable.height + SearchOptionSheetConstants.TopMargin.toPx()
.roundToInt() + confirmButtonPlaceable.height
maxSheetHeightPx = dragSheetPlaceable.height
}
normalSheetHeightPx =
tagTypePlaceable.height + SearchOptionSheetConstants.TopMargin.toPx()
.roundToInt() + confirmButtonPlaceable.height
maxSheetHeightPx = dragSheetPlaceable.height

layout(
width = tagTypePlaceable.width + tagListPlaceable.width,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import kotlinx.coroutines.launch

@Composable
fun TagTypeColumn(
tagTypesNotEmpty: List<TagType>,
selectedTagType: TagType,
baseAnimatedFloat: State<Float>,
onSelectTagType: (TagType) -> Unit,
Expand All @@ -38,6 +39,7 @@ fun TagTypeColumn(
context.getString(R.string.search_option_tag_type_credit) to TagType.CREDIT,
context.getString(R.string.search_option_tag_type_time) to TagType.TIME,
context.getString(R.string.search_option_tag_type_general_category) to TagType.CATEGORY,
context.getString(R.string.search_option_tag_type_general_category_pre2025) to TagType.CATEGORY_PRE2025,
context.getString(R.string.search_option_tag_type_etc) to TagType.ETC,
)
}
Expand All @@ -53,7 +55,7 @@ fun TagTypeColumn(
.offset(x = offsetXAnimatedDp)
.padding(start = 20.dp, bottom = 10.dp),
) {
tagTypeList.forEach { (name, type) ->
tagTypeList.filter { tagTypesNotEmpty.contains(it.second) }.forEach { (name, type) ->
Text(
text = name,
style = SNUTTTypography.h2.copy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ fun LectureDetailPage(
val disableMapFeature by LocalRemoteConfig.current.disableMapFeature.collectAsState(true) // NOTE: config를 받아오기 전까지는 지도를 숨긴다.
var creditText by remember { mutableStateOf(editingLectureDetail.credit.toString()) }
val editingLectureReview by vm.editingLectureReview.collectAsState()
val semesterChange by searchViewModel.semesterChange.collectAsState(0)
/* 현재 LectureDto 타입의 editingLectureDetail 플로우를 변경해 가면서 API 부를 때도 쓰고 화면에 정보 표시할 때도 쓰고 있는데,
* credit은 Long 타입이라서 학점 입력하는 editText에 빈 문자열을 넣었을 때(=다 지웠을 때) 문제가 발생한다. 그래서 credit만 별도의 MutableState<String>을 둬서 운용한다.
* 이때 다른 정보들은 editingLectureDetail 따라서 바뀌니까 모드가 바뀌어도 따로 할 게 없는데, 얘는 편집모드->일반모드로 바뀔 때 따로 변경해 줘야 한다. 그것이 아래의 코드.
Expand Down Expand Up @@ -423,6 +424,14 @@ fun LectureDetailPage(
onValueChange = { vm.editLectureDetail(editingLectureDetail.copy(category = it)) },
enabled = modeType is ModeType.Editing,
)
if (semesterChange > 20250L) {
LectureDetailItem(
title = stringResource(R.string.lecture_detail_categoryPre2025),
value = editingLectureDetail.categoryPre2025 ?: "",
onValueChange = { vm.editLectureDetail(editingLectureDetail.copy(categoryPre2025 = it)) },
enabled = modeType is ModeType.Editing,
)
}
LectureDetailItem(
title = stringResource(R.string.lecture_detail_course_number),
value = editingLectureDetail.course_number ?: "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ class LectureDetailViewModel @Inject constructor(
credit = _editingLectureDetail.value.credit,
classification = _editingLectureDetail.value.classification,
category = _editingLectureDetail.value.category,
categoryPre2025 = _editingLectureDetail.value.categoryPre2025,
remark = _editingLectureDetail.value.remark,
class_time_json = _editingLectureDetail.value.class_time_json,
)
Expand Down
7 changes: 5 additions & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,9 @@
<string name="search_option_tag_type_credit">학점</string>
<string name="search_option_tag_type_time">시간</string>
<string name="search_option_tag_type_department">학과</string>
<string name="search_option_tag_type_general_category">교양분류</string>
<string name="search_option_tag_type_general_category">교양영역</string>
<string name="search_option_tag_type_general_category_pre2025">구) 교양영역</string>
<string name="search_option_tag_type_general_pre2025">구)</string>
<string name="search_option_tag_type_sort_criteria">정렬 기준</string>
<string name="search_option_tag_type_etc">기타</string>
<string name="search_option_apply_button">필터 적용</string>
Expand Down Expand Up @@ -486,7 +488,8 @@
<string name="lecture_detail_academic_year">학년</string>
<string name="lecture_detail_credit">학점</string>
<string name="lecture_detail_classification">분류</string>
<string name="lecture_detail_category">구분</string>
<string name="lecture_detail_category">교양영역</string>
<string name="lecture_detail_categoryPre2025">구) 교양영역</string>
<string name="lecture_detail_course_number">강좌번호</string>
<string name="lecture_detail_lecture_number">분반번호</string>
<string name="lecture_detail_quota">정원</string>
Expand Down

0 comments on commit dac329f

Please sign in to comment.