Skip to content

Commit

Permalink
Merge pull request #67 from snuhcs-course/feat/android-emoji-pagination
Browse files Browse the repository at this point in the history
feat: emoji pagination
  • Loading branch information
yangchanhk98 authored Nov 24, 2023
2 parents 5e22410 + 552b61e commit f5c4e99
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 45 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.goliath.emojihub.data_sources

import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.goliath.emojihub.data_sources.api.EmojiApi
import com.goliath.emojihub.models.EmojiDto
import javax.inject.Inject

class EmojiPagingSource @Inject constructor(
private val api: EmojiApi
): PagingSource<Int, EmojiDto>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, EmojiDto> {
val cursor = params.key ?: 1
val count = params.loadSize
return try {
val response = api.fetchEmojiList(1, cursor, count).body()
val data = response ?: listOf()
LoadResult.Page(
data = data,
prevKey = if (cursor == 1) null else cursor - 1,
nextKey = if (data.isEmpty()) null else cursor + 1
)
} catch (exception: Exception) {
LoadResult.Error(exception)
}
}

override fun getRefreshKey(state: PagingState<Int, EmojiDto>): Int? {
return state.anchorPosition?.let { anchorPosition ->
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package com.goliath.emojihub.repositories.remote

import android.util.Log
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.goliath.emojihub.data_sources.EmojiPagingSource
import com.goliath.emojihub.data_sources.PostPagingSource
import com.goliath.emojihub.data_sources.api.EmojiApi
import com.goliath.emojihub.models.EmojiDto
import com.goliath.emojihub.models.FetchEmojiListDto
import com.goliath.emojihub.models.PostDto
import com.goliath.emojihub.models.UploadEmojiDto
import com.google.gson.Gson
import kotlinx.coroutines.flow.Flow
import okhttp3.MediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody
Expand All @@ -17,7 +24,7 @@ import javax.inject.Inject
import javax.inject.Singleton

interface EmojiRepository {
suspend fun fetchEmojiList(numLimit: Int): List<EmojiDto>
suspend fun fetchEmojiList(): Flow<PagingData<EmojiDto>>
suspend fun getEmojiWithId(id: String): EmojiDto?
suspend fun uploadEmoji(videoFile: File, emojiDto: UploadEmojiDto): Boolean
suspend fun saveEmoji(id: String): Response<Unit>
Expand All @@ -29,22 +36,11 @@ interface EmojiRepository {
class EmojiRepositoryImpl @Inject constructor(
private val emojiApi: EmojiApi
): EmojiRepository {
override suspend fun fetchEmojiList(numLimit: Int): List<EmojiDto> {
// val fetchEmojiListDto = FetchEmojiListDto(1, 0, 10)
try {
val response = emojiApi.fetchEmojiList(1, 1, 10)

if(response.isSuccessful && response.body() != null) {
Log.d("Fetch_E_L", "Successfully fetched ${response.body()!!.size} emojis")
return response.body()!!
} else {
val errorBody = response.errorBody()?.string() ?: "Unknown error"
Log.d("Fetch_E_L", "Failed to fetch emojis: $errorBody")
}
} catch(e: Exception) {
Log.e("Fetch_E_L", "Error fetching emojis", e)
}
return listOf()
override suspend fun fetchEmojiList(): Flow<PagingData<EmojiDto>> {
return Pager(
config = PagingConfig(pageSize = 10, initialLoadSize = 10, enablePlaceholders = false),
pagingSourceFactory = { EmojiPagingSource(emojiApi) }
).flow
}

override suspend fun getEmojiWithId(id: String): EmojiDto? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,30 @@ package com.goliath.emojihub.usecases

import android.net.Uri
import android.util.Log
import androidx.paging.PagingData
import androidx.paging.map
import com.goliath.emojihub.data_sources.ApiErrorController
import com.goliath.emojihub.models.CreatedEmoji
import com.goliath.emojihub.models.Emoji
import com.goliath.emojihub.models.EmojiDto
import com.goliath.emojihub.models.Post

import com.goliath.emojihub.models.UploadEmojiDto
import com.goliath.emojihub.repositories.local.X3dRepository
import com.goliath.emojihub.repositories.remote.EmojiRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.map
import java.io.File
import javax.inject.Inject
import javax.inject.Singleton

interface EmojiUseCase {
val emojiListState: StateFlow<List<EmojiDto>>
suspend fun fetchEmojiList(numInt: Int)
val emojiList: StateFlow<PagingData<Emoji>>
suspend fun updateEmojiList(data: PagingData<Emoji>)
suspend fun fetchEmojiList(): Flow<PagingData<Emoji>>
suspend fun createEmoji(videoUri: Uri, topK: Int): List<CreatedEmoji>
suspend fun uploadEmoji(emojiUnicode: String, emojiLabel: String, videoFile: File): Boolean
suspend fun saveEmoji(id: String): Boolean
Expand All @@ -32,18 +39,15 @@ class EmojiUseCaseImpl @Inject constructor(
private val errorController: ApiErrorController
): EmojiUseCase {

private val _emojiListState = MutableStateFlow<List<EmojiDto>>(emptyList())
override val emojiListState: StateFlow<List<EmojiDto>>
get() = _emojiListState.asStateFlow()
private val _emojiList = MutableStateFlow<PagingData<Emoji>>(PagingData.empty())
override val emojiList: StateFlow<PagingData<Emoji>>
get() = _emojiList

override suspend fun fetchEmojiList(numInt: Int) {
try{
val emojiList = emojiRepository.fetchEmojiList(numInt)
_emojiListState.emit(emojiList)
Log.d("Fetch_E_L", "USECASE DONE: $emojiList")
} catch (e: Exception) {
errorController.setErrorState(-1)
}
override suspend fun updateEmojiList(data: PagingData<Emoji>) {
_emojiList.emit(data)
}
override suspend fun fetchEmojiList(): Flow<PagingData<Emoji>> {
return emojiRepository.fetchEmojiList().map { it.map { dto -> Emoji(dto) } }
}

override suspend fun createEmoji(videoUri: Uri, topK: Int): List<CreatedEmoji> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.cachedIn
import com.goliath.emojihub.models.CreatedEmoji
import com.goliath.emojihub.models.Emoji
import com.goliath.emojihub.usecases.EmojiUseCase
Expand All @@ -28,19 +29,18 @@ class EmojiViewModel @Inject constructor(
var currentEmoji: Emoji? = null
var isBottomSheetShown by mutableStateOf(false)

private val _emojiList = MutableStateFlow<List<Emoji>>(emptyList())
val emojiList: StateFlow<List<Emoji>> = _emojiList.asStateFlow()
val emojiList = emojiUseCase.emojiList

private val _topK = 3

fun fetchEmojiList(numInt: Int)
fun fetchEmojiList()
{
viewModelScope.launch {
emojiUseCase.fetchEmojiList(numInt)

val emojis = emojiUseCase.emojiListState.value.map { dto -> Emoji(dto) }
_emojiList.emit(emojis)
Log.d("Fetch_E_L", "VIEWMODEL DONE: $emojis")
emojiUseCase.fetchEmojiList()
.cachedIn(viewModelScope)
.collect {
emojiUseCase.updateEmojiList(it)
}
}
}

Expand Down
17 changes: 10 additions & 7 deletions android/app/src/main/java/com/goliath/emojihub/views/EmojiPage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import androidx.core.content.ContextCompat
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.paging.compose.collectAsLazyPagingItems
import com.goliath.emojihub.LocalNavController
import com.goliath.emojihub.NavigationDestination
import com.goliath.emojihub.models.createDummyEmoji
Expand Down Expand Up @@ -64,13 +65,13 @@ fun EmojiPage(
}
}

val emojiList = viewModel.emojiList.collectAsLazyPagingItems()

LaunchedEffect(Unit)
{
viewModel.fetchEmojiList(10)
viewModel.fetchEmojiList()
}

val emojiList = viewModel.emojiList.collectAsState().value

Column(Modifier.background(White)) {
TopNavigationBar("Emoji", shouldNavigate = false) {
IconButton(onClick = {
Expand Down Expand Up @@ -107,10 +108,12 @@ fun EmojiPage(
horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalArrangement = Arrangement.spacedBy(4.dp),
) {
items(emojiList, key = { it.id }) { emoji ->
EmojiCell(emoji = emoji) {
viewModel.currentEmoji = emoji
navController.navigate(NavigationDestination.PlayEmojiVideo)
items(emojiList.itemCount) { index ->
emojiList[index]?.let{
EmojiCell(emoji = it) { selectedEmoji ->
viewModel.currentEmoji = selectedEmoji
navController.navigate(NavigationDestination.PlayEmojiVideo)
}
}
}
}
Expand Down

0 comments on commit f5c4e99

Please sign in to comment.