Skip to content
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
2 changes: 2 additions & 0 deletions .github/workflows/pr_checker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ jobs:

- name: Set up Android SDK
uses: android-actions/setup-android@v3
with:
packages: 'platform-tools'

- name: Create local.properties
env:
Expand Down
8 changes: 0 additions & 8 deletions app/src/main/java/com/flint/android/data/api/SearchApi.kt
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
package com.flint.android.data.api

import com.flint.android.data.dto.base.BaseResponse
import com.flint.android.data.dto.search.SearchBookmarkedContentsResponseDto
import com.flint.android.data.dto.search.SearchContentsResponseDto
import retrofit2.http.GET
import retrofit2.http.Query

interface SearchApi {
@GET("/api/v1/search/bookmarked-contents")
suspend fun getBookmarkedContentList(
@Query("keyword") keyword: String,
@Query("cursor") cursor: Int,
@Query("size") size: Int
) : BaseResponse<SearchBookmarkedContentsResponseDto>

@GET("/api/v1/contents/search")
suspend fun getSearchContentList(
@Query("keyword") keyword: String? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ data class BookmarkedContentResponseDto(
val id: String,
@SerialName("title")
val title: String,
// 영화 감독 또는 TV creator. 정보가 없으면 null
@SerialName("author")
val author: String? = null,
@SerialName("year")
val year: Int,
@SerialName("imageUrl")
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ package com.flint.android.domain.mapper.content
import com.flint.android.data.dto.content.response.BookmarkedContentListResponseDto
import com.flint.android.data.dto.content.response.BookmarkedContentResponseDto
import com.flint.android.data.dto.content.response.OttSimpleResponseDto
import com.flint.android.data.dto.search.SearchBookmarkedContentsResponseDto
import com.flint.android.domain.model.content.BookmarkedContentItemModel
import com.flint.android.domain.model.content.BookmarkedContentListModel
import com.flint.android.domain.model.content.ContentModel
import com.flint.android.domain.type.OttType
import kotlinx.collections.immutable.toImmutableList
import timber.log.Timber
Expand All @@ -23,6 +21,7 @@ fun BookmarkedContentResponseDto.toModel() : BookmarkedContentItemModel {
return BookmarkedContentItemModel(
id = id,
title = title,
author = author,
year = year,
imageUrl = imageUrl,
bookmarkCount = bookmarkCount,
Expand All @@ -34,16 +33,3 @@ fun BookmarkedContentResponseDto.toModel() : BookmarkedContentItemModel {
}
)
}

fun SearchBookmarkedContentsResponseDto.toModel() : List<ContentModel> {
return data.map {
ContentModel(
bookmarkId = it.bookmarkId,
contentId = it.contentId,
title = it.title,
author = it.author,
posterImage = it.posterUrl,
year = it.year
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,3 @@ private fun SearchContentsResponseDto.Content.toModel(): SearchContentItemModel{
}



Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import kotlinx.collections.immutable.persistentListOf

data class BookmarkedContentListModel(
val totalCount: Int = 0,
val contents: ImmutableList<BookmarkedContentItemModel> = persistentListOf()
val contents: ImmutableList<BookmarkedContentItemModel> = persistentListOf(),
val nextCursor: String? = null,
) {
companion object {
val FakeList = BookmarkedContentListModel(
Expand All @@ -33,6 +34,7 @@ data class BookmarkedContentListModel(
data class BookmarkedContentItemModel(
val id: String = "",
val title: String = "",
val author: String? = null,
val year: Int = 0,
val imageUrl: String = "",
val bookmarkCount: Int = 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package com.flint.android.domain.repository

import com.flint.android.core.common.util.suspendRunCatching
import com.flint.android.data.api.ContentApi
import com.flint.android.domain.mapper.content.toModel
import com.flint.android.domain.mapper.ott.toModel
import com.flint.android.domain.model.content.BookmarkedContentListModel
import com.flint.android.domain.model.ott.OttListModel
import kotlinx.collections.immutable.toImmutableList
import javax.inject.Inject

class ContentRepository @Inject constructor(
Expand All @@ -13,5 +16,19 @@ class ContentRepository @Inject constructor(
suspend fun getOttListPerContent(contentId: String) : Result<OttListModel> =
suspendRunCatching { apiService.getOttListPerContent(contentId).data.toModel() }

// 내 북마크한 콘텐츠 목록 한 페이지 조회 (커서 페이지네이션, 무한 스크롤용)
suspend fun getBookmarkedContentList(cursor: String?, size: Int): Result<BookmarkedContentListModel> =
suspendRunCatching {
val page = apiService.getBookmarkedContentList(cursor = cursor, size = size).data
BookmarkedContentListModel(
contents = page.data.map { it.toModel() }.toImmutableList(),
nextCursor = page.meta.nextCursor,
)
}

// 내 북마크한 콘텐츠 전체 개수 조회
suspend fun getBookmarkedContentCount(): Result<Int> =
suspendRunCatching { apiService.getBookmarkedContentCount().data.totalCount }

// 콘텐츠 검색
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,13 @@ package com.flint.android.domain.repository

import com.flint.android.core.common.util.suspendRunCatching
import com.flint.android.data.api.SearchApi
import com.flint.android.domain.mapper.content.toModel
import com.flint.android.domain.mapper.search.toModel
import com.flint.android.domain.model.content.ContentModel
import com.flint.android.domain.model.search.SearchContentListModel
import javax.inject.Inject

class SearchRepository @Inject constructor(
private val apiService: SearchApi,
) {
suspend fun getBookmarkedContentList(keyword: String, cursor: Int, size: Int): Result<List<ContentModel>> =
suspendRunCatching { apiService.getBookmarkedContentList(keyword, cursor, size).data.toModel() }

suspend fun getSearchContentList(
keyword: String? = null,
genres: List<String>? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ 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.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
Expand All @@ -16,9 +17,11 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand Down Expand Up @@ -63,6 +66,7 @@ fun AddContentRoute(
onSearchTextChanged = viewModel::updateSearch,
onToggleContent = viewModel::toggleContent,
onRemoveContent = viewModel::removeContent,
onLoadMore = viewModel::loadMoreBookmarkedContents,
onBackClick = {
viewModel.resetSearchText()
navigateUp()
Expand All @@ -83,6 +87,7 @@ fun AddContentScreen(
onSearchTextChanged: (String) -> Unit = {},
onToggleContent: (SearchContentItemModel) -> Unit = {},
onRemoveContent: (SearchContentItemModel) -> Unit,
onLoadMore: () -> Unit = {},
onBackClick: () -> Unit,
onActionClick: () -> Unit,
modifier: Modifier = Modifier
Expand All @@ -102,6 +107,21 @@ fun AddContentScreen(

val isEmptyViewShown = contentList.isEmpty() && uiState.searchText.isNotBlank()

val shouldLoadMore by remember {
derivedStateOf {
val layoutInfo = lazyColumnState.layoutInfo
val totalItems = layoutInfo.totalItemsCount
val lastVisible = layoutInfo.visibleItemsInfo.lastOrNull() ?: return@derivedStateOf false
totalItems > 5 && lastVisible.index >= totalItems - 5
}
}

LaunchedEffect(shouldLoadMore, uiState.searchText, uiState.nextCursor) {
if (shouldLoadMore && uiState.searchText.isBlank()) {
onLoadMore()
}
}

Box(
modifier = modifier
.fillMaxSize()
Expand Down Expand Up @@ -179,11 +199,35 @@ fun AddContentScreen(
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
if (uiState.searchText.isBlank()) {
item {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.Bottom,
) {
Text(
text = "저장한 작품",
color = FlintTheme.colors.white,
style = FlintTheme.typography.head3M18,
)
uiState.savedContentCount?.let { count ->
Text(
text = "총 ${count}개",
color = FlintTheme.colors.gray300,
style = FlintTheme.typography.body1M16,
)
}
}
}
}

items(
items = contentList,
key = { it.id },
) { content ->
val isSelected = selectedContents.any { it.id == content.id }
val isMaxReached = selectedContents.size >= MAX_CONTENT_COUNT

AddContentSelectItem(
onCheckClick = {
Expand All @@ -197,6 +241,7 @@ fun AddContentScreen(
} else onToggleContent(content)
},
isSelected = isSelected,
isMaxReached = isMaxReached,
posterImageUrl = content.posterUrl,
title = content.title,
director = content.author,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ fun CollectionCreateRoute(
}

var pendingContentId by rememberSaveable { mutableStateOf<String?>(null) }
var contentImageLimitReachedCount by remember { mutableStateOf(0) }

val onContentImagesPicked: (List<Uri>) -> Unit = { uris ->
pendingContentId?.let { contentId -> viewModel.addContentImageUris(contentId, uris) }
Expand Down Expand Up @@ -161,11 +162,7 @@ fun CollectionCreateRoute(
val remainingSlots = (uiState.contentDetailsMap[contentId] ?: ContentDetail()).remainingImageSlots
val imageOnlyRequest = PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
when {
remainingSlots == 0 -> Toast.makeText(
context,
"작품 이미지는 최대 ${MAX_CONTENT_IMAGE_COUNT}개까지 추가할 수 있어요",
Toast.LENGTH_SHORT,
).show()
remainingSlots == 0 -> contentImageLimitReachedCount++

remainingSlots == 1 -> {
pendingContentId = contentId
Expand All @@ -180,6 +177,7 @@ fun CollectionCreateRoute(
},
onRemoveExistingContentImage = viewModel::removeExistingContentImageUrl,
onRemoveContentImage = viewModel::removeContentImageUri,
contentImageLimitReachedCount = contentImageLimitReachedCount,
modifier = Modifier.padding(paddingValues),
)
}
Expand All @@ -202,6 +200,7 @@ fun CollectionCreateScreen(
onSelectContentImage: (contentId: String) -> Unit = {},
onRemoveExistingContentImage: (contentId: String, index: Int) -> Unit = { _, _ -> },
onRemoveContentImage: (contentId: String, index: Int) -> Unit = { _, _ -> },
contentImageLimitReachedCount: Int = 0,
modifier: Modifier = Modifier,
) {
var isModalVisible by remember { mutableStateOf(false) }
Expand Down Expand Up @@ -234,6 +233,12 @@ fun CollectionCreateScreen(
}
}

LaunchedEffect(contentImageLimitReachedCount) {
if (contentImageLimitReachedCount > 0) {
showToast("작품 이미지는 최대 ${MAX_CONTENT_IMAGE_COUNT}개까지 추가할 수 있어요")
}
}

val lazyListState = rememberLazyListState()
val coroutineScope = rememberCoroutineScope()

Expand Down Expand Up @@ -403,8 +408,7 @@ fun CollectionCreateScreen(
key = toastRequestId,
imageVector = ImageVector.vectorResource(R.drawable.ic_toast_error),
paddingValues = PaddingValues.Zero,
yOffset = 120.dp,
imeYOffset = 16.dp,
yOffset = 16.dp,
hide = { toastMessage = null },
)
}
Expand Down
Loading
Loading