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

선호학과 정보 저장 #366

Merged
merged 14 commits into from
Oct 25, 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
10 changes: 10 additions & 0 deletions app/src/main/java/com/wafflestudio/snutt2/data/SNUTTStorage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,16 @@ class SNUTTStorage @Inject constructor(
),
)

val recentSearchedDepartments = PrefValue<List<TagDto>>(
prefContext,
PrefListValueMetaData(
domain = DOMAIN_SCOPE_LOGIN,
key = "recent_searched_departments",
type = TagDto::class.java,
defaultValue = listOf(),
),
)

fun clearLoginScope() {
prefContext.clear(DOMAIN_SCOPE_LOGIN)
prefContext.clear(DOMAIN_SCOPE_CURRENT_VERSION)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import com.wafflestudio.snutt2.lib.network.dto.core.LectureDto
import com.wafflestudio.snutt2.model.SearchTimeDto
import com.wafflestudio.snutt2.model.TagDto
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow

interface LectureSearchRepository {

val recentSearchedDepartments: StateFlow<List<TagDto>>

fun getLectureSearchResultStream(
year: Long,
semester: Long,
Expand All @@ -23,4 +26,8 @@ interface LectureSearchRepository {
suspend fun getBuildings(
places: String,
): List<LectureBuildingDto>

fun storeRecentSearchedDepartment(tag: TagDto)
JuTaK97 marked this conversation as resolved.
Show resolved Hide resolved

fun removeRecentSearchedDepartment(tag: TagDto)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.wafflestudio.snutt2.data.lecture_search
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.wafflestudio.snutt2.data.SNUTTStorage
import com.wafflestudio.snutt2.lib.SnuttUrls
import com.wafflestudio.snutt2.lib.network.SNUTTRestApi
import com.wafflestudio.snutt2.lib.network.dto.core.LectureBuildingDto
Expand All @@ -18,8 +19,11 @@ import javax.inject.Singleton
class LectureSearchRepositoryImpl @Inject constructor(
private val api: SNUTTRestApi,
private val snuttUrls: SnuttUrls,
private val storage: SNUTTStorage,
) : LectureSearchRepository {

override val recentSearchedDepartments = storage.recentSearchedDepartments.asStateFlow()

override fun getLectureSearchResultStream(
year: Long,
semester: Long,
Expand Down Expand Up @@ -66,6 +70,19 @@ class LectureSearchRepositoryImpl @Inject constructor(
return response.content
}

override fun storeRecentSearchedDepartment(tag: TagDto) {
val previousStoredTags = storage.recentSearchedDepartments.get()

storage.recentSearchedDepartments.update(
(previousStoredTags.filter { it != tag } + tag).takeLast(5),
)
}

override fun removeRecentSearchedDepartment(tag: TagDto) {
val previousStoredTags = storage.recentSearchedDepartments.get()
storage.recentSearchedDepartments.update(previousStoredTags - tag)
}

companion object {
const val LECTURES_LOAD_PAGE_SIZE = 30
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,13 @@ fun SearchPage(
launchSuspendApi(apiOnProgress, apiOnError) {
searchViewModel.query()
}
searchViewModel.storeRecentSearchedDepartments()
}
scope.launch { bottomSheet.hide() }
},
hideBottomSheet = {
scope.launch { bottomSheet.hide() }
},
draggedTimeBlock = draggedTimeBlock,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
Expand Down Expand Up @@ -88,6 +89,8 @@ class SearchViewModel @Inject constructor(
// 검색 쿼리에 들어가는 시간대 검색 시간대 목록
private val _searchTimeList = MutableStateFlow<List<SearchTimeDto>?>(null)

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

init {
viewModelScope.launch {
semesterChange.distinctUntilChanged().collectLatest {
Expand All @@ -113,6 +116,19 @@ class SearchViewModel @Inject constructor(
.map { it.toDataWithState(selectedTags.contains(it)) }
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())

val selectableRecentSearchedDepartments: StateFlow<List<Selectable<TagDto>>> = combine(
tagsByTagType, recentSearchedDepartments, _selectedTags,
) { tagsByTagType, recentDepartments, selectedTags ->
val tagItemsByTagType = tagsByTagType.map { tag -> tag.item }
recentDepartments.filter { recentDepartment ->
tagItemsByTagType.contains(recentDepartment)
}.map { it.toDataWithState(selectedTags.contains(it)) }
}.stateIn(
viewModelScope,
SharingStarted.Eagerly,
emptyList(),
)

val bookmarkList = combine(
_getBookmarkListSignal.flatMapLatest {
try {
Expand Down Expand Up @@ -254,6 +270,16 @@ class SearchViewModel @Inject constructor(
}
}

fun storeRecentSearchedDepartments() {
_selectedTags.value.filter { it.type == TagType.DEPARTMENT }.forEach { tag ->
lectureSearchRepository.storeRecentSearchedDepartment(tag)
}
}

fun removeRecentSearchedDepartment(tag: TagDto) {
lectureSearchRepository.removeRecentSearchedDepartment(tag)
}

private suspend fun clear() {
_searchTitle.emit("")
_selectedLecture.emit(null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.wafflestudio.snutt2.views.logged_in.home.search.search_option

import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
Expand All @@ -14,7 +15,10 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.SubcomposeLayout
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.wafflestudio.snutt2.components.compose.ExitIcon
import com.wafflestudio.snutt2.components.compose.clicks
import com.wafflestudio.snutt2.model.TagDto
import com.wafflestudio.snutt2.ui.SNUTTColors
import com.wafflestudio.snutt2.views.logged_in.home.search.SearchViewModel
Expand All @@ -28,11 +32,13 @@ private enum class OptionSheetMode {
@Composable
fun SearchOptionSheet(
applyOption: () -> Unit,
hideBottomSheet: () -> Unit,
draggedTimeBlock: State<List<List<Boolean>>>,
) {
val viewModel = hiltViewModel<SearchViewModel>()
val tagsByTagType by viewModel.tagsByTagType.collectAsState()
val selectedTagType by viewModel.selectedTagType.collectAsState()
val recentSearchedDepartments by viewModel.selectableRecentSearchedDepartments.collectAsState()
val scope = rememberCoroutineScope()

var optionSheetMode by remember {
Expand Down Expand Up @@ -79,6 +85,7 @@ fun SearchOptionSheet(
// tag column의 높이를 tagType column의 높이로 설정
height = tagTypePlaceable.height.toDp(),
),
recentSearchedDepartments = recentSearchedDepartments,
tagsByTagType = tagsByTagType,
selectedTimes = draggedTimeBlock,
baseAnimatedFloat = baseAnimatedFloat,
Expand All @@ -92,6 +99,9 @@ fun SearchOptionSheet(
viewModel.toggleTag(it)
}
},
onRemoveRecent = {
viewModel.removeRecentSearchedDepartment(it)
},
openTimeSelectSheet = {
optionSheetMode = OptionSheetMode.TimeSelect
},
Expand Down Expand Up @@ -128,6 +138,14 @@ fun SearchOptionSheet(
SearchOptionConfirmButton(baseAnimatedFloat, applyOption)
}.first().measure(constraints)

val closeBottomSheetPlaceable = subcompose(slotId = 5) {
Row(
modifier = Modifier.clicks { hideBottomSheet() },
) {
ExitIcon()
}
}.first().measure(constraints)

// 한번만 계산, 할당
if (normalSheetHeightPx == 0 && maxSheetHeightPx == 0) {
normalSheetHeightPx =
Expand All @@ -153,6 +171,10 @@ fun SearchOptionSheet(
tagTypePlaceable.height + SearchOptionSheetConstants.TopMargin.toPx()
.roundToInt(),
)
closeBottomSheetPlaceable.placeRelative(
tagTypePlaceable.width + tagListPlaceable.width - 52.dp.toPx().roundToInt(),
(SearchOptionSheetConstants.TopMargin.toPx().roundToInt() - 32.dp.toPx().roundToInt()) / 2,
)
if (baseAnimatedFloat.value != 0f) dragSheetPlaceable.placeRelative(0, 0)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import com.wafflestudio.snutt2.ui.isDarkMode
object SearchOptionSheetConstants {
const val TagColumnWidthDp = 120
const val MaxHeightRatio = 0.85f
val TopMargin = 40.dp
val TopMargin = 68.dp
val AnimationSpec = spring(
visibilityThreshold = 1f,
stiffness = 200f,
Expand Down
Loading
Loading