Skip to content

Commit

Permalink
πŸ”€ resolve conflicts from an/dev
Browse files Browse the repository at this point in the history
  • Loading branch information
kmkim2689 committed Jul 26, 2024
1 parent a9e0cbe commit ca9dcfc
Show file tree
Hide file tree
Showing 16 changed files with 258 additions and 38 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package net.pengcook.android.data.datasource

import androidx.paging.PagingSource
import androidx.paging.PagingState
import net.pengcook.android.presentation.core.model.Recipe

class CategoryFeedPagingSource(
private val initialPageNumber: Int = 0,
private val category: String,
private val fetchFeeds: suspend (pageNumber: Int, size: Int, category: String) -> Result<List<Recipe>>,
) : PagingSource<Int, Recipe>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Recipe> {
val pageNumber = params.key ?: initialPageNumber
return runCatching {
val feeds = fetchFeeds(pageNumber, params.loadSize, category)
val pageData = feeds.getOrNull() ?: emptyList()
val nextKey = if (pageData.size < params.loadSize) null else pageNumber + 1
LoadResult.Page(
data = pageData,
prevKey = if (pageNumber == initialPageNumber) null else pageNumber - 1,
nextKey = nextKey,
)
}.onFailure { throwable ->
LoadResult.Error<Int, Recipe>(throwable)
}.getOrThrow()
}

override fun getRefreshKey(state: PagingState<Int, Recipe>): Int? {
return state.anchorPosition?.let { anchorPosition ->
state.closestPageToPosition(anchorPosition)?.prevKey
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ data class Category(
val id: Long,
val title: String,
val imageUrl: String,
val code: String? = null,
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package net.pengcook.android.presentation.category

interface CategoryEventListener {
fun onCategorySelect(categoryId: Long)
fun onCategorySelect(categoryCode: String)
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,70 @@ class CategoryFragment : Fragment() {
) {
super.onViewCreated(view, savedInstanceState)
binding.adapter = adapter
val categories =
List(17) { id ->
Category(
id.toLong(),
"category ${id + 1}",
"https://www.alphafoodie.com/wp-content/uploads/2021/06/Authentic-Kimchi-1-of-1-2.jpeg",
)
}
adapter.submitList(categories)
val spacingInPixels = resources.getDimensionPixelSize(R.dimen.item_spacing_category)
binding.rvCategory.addItemDecoration(GridSpacingItemDecoration(3, spacingInPixels))
setUpCategories()
observeEvents()
}

override fun onDestroyView() {
super.onDestroyView()
_binding = null
}

private fun observeEvents() {
viewModel.uiEvent.observe(viewLifecycleOwner) { event ->
val uiEvent = event.getContentIfNotHandled() ?: return@observe
when (uiEvent) {
is CategoryUiEvent.NavigateToList -> {
// TODO Navigation
}
}
}
}

private fun setUpCategories() {
val categories = categories()
adapter.submitList(categories)
val spacingInPixels = resources.getDimensionPixelSize(R.dimen.item_spacing_category)
binding.rvCategory.addItemDecoration(GridSpacingItemDecoration(3, spacingInPixels))
}

private fun categories() =
listOf(
Category(
1,
"Dessert",
"https://flexible.img.hani.co.kr/flexible/normal/640/427/imgdb/original/2024/0522/20240522501170.jpg",
"dessert",
),
Category(
2,
"Chicken",
"https://flexible.img.hani.co.kr/flexible/normal/640/427/imgdb/original/2024/0522/20240522501170.jpg",
"chicken",
),
Category(
3,
"Vegetarian",
"https://flexible.img.hani.co.kr/flexible/normal/640/427/imgdb/original/2024/0522/20240522501170.jpg",
"vegetarian",
),
Category(
4,
"Miscellaneous",
"https://flexible.img.hani.co.kr/flexible/normal/640/427/imgdb/original/2024/0522/20240522501170.jpg",
"miscellaneous",
),
Category(
5,
"Seafood",
"https://flexible.img.hani.co.kr/flexible/normal/640/427/imgdb/original/2024/0522/20240522501170.jpg",
"seafood",
),
Category(
6,
"French",
"https://flexible.img.hani.co.kr/flexible/normal/640/427/imgdb/original/2024/0522/20240522501170.jpg",
"french",
),
)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
package net.pengcook.android.presentation.category

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import net.pengcook.android.presentation.core.util.Event

class CategoryViewModel : ViewModel(), CategoryEventListener {
override fun onCategorySelect(categoryId: Long) {
private val _uiEvent: MutableLiveData<Event<CategoryUiEvent>> = MutableLiveData()
val uiEvent: LiveData<Event<CategoryUiEvent>>
get() = _uiEvent

override fun onCategorySelect(categoryCode: String) {
_uiEvent.value = Event(CategoryUiEvent.NavigateToList(categoryCode))
}
}

sealed interface CategoryUiEvent {
data class NavigateToList(val categoryCode: String) : CategoryUiEvent
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ package net.pengcook.android.presentation.category.list

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import net.pengcook.android.databinding.ItemFeedBinding
import net.pengcook.android.presentation.core.model.Feed
import net.pengcook.android.presentation.core.model.Recipe
import net.pengcook.android.presentation.home.FeedRecyclerViewAdapter

class CategoryFeedListAdapter :
ListAdapter<Feed, FeedRecyclerViewAdapter.ViewHolder>(diffCallback) {
PagingDataAdapter<Recipe, FeedRecyclerViewAdapter.ViewHolder>(diffCallback) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int,
): FeedRecyclerViewAdapter.ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = ItemFeedBinding.inflate(layoutInflater)
val binding = ItemFeedBinding.inflate(layoutInflater, parent, false)
return FeedRecyclerViewAdapter.ViewHolder(binding)
}

Expand All @@ -29,17 +29,17 @@ class CategoryFeedListAdapter :

companion object {
val diffCallback =
object : DiffUtil.ItemCallback<Feed>() {
object : DiffUtil.ItemCallback<Recipe>() {
override fun areItemsTheSame(
oldItem: Feed,
newItem: Feed,
oldItem: Recipe,
newItem: Recipe,
): Boolean {
return oldItem.id == newItem.id
return oldItem.recipeId == newItem.recipeId
}

override fun areContentsTheSame(
oldItem: Feed,
newItem: Feed,
oldItem: Recipe,
newItem: Recipe,
): Boolean {
return oldItem == newItem
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,26 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import net.pengcook.android.data.datasource.feed.DefaultFeedRemoteDataSource
import net.pengcook.android.data.remote.api.FeedService
import net.pengcook.android.data.repository.feed.DefaultFeedRepository
import net.pengcook.android.data.util.network.RetrofitClient
import net.pengcook.android.databinding.FragmentCategoryFeedListBinding

class CategoryFeedListFragment : Fragment() {
private var _binding: FragmentCategoryFeedListBinding? = null
private val binding: FragmentCategoryFeedListBinding
get() = _binding!!
private val viewModel: CategoryFeedListViewModel by viewModels()
private val viewModel: CategoryFeedListViewModel by viewModels {
CategoryFeedListViewModelFactory(
DefaultFeedRepository(DefaultFeedRemoteDataSource(RetrofitClient.service(FeedService::class.java))),
"Dessert",
)
}
private val adapter: CategoryFeedListAdapter by lazy {
CategoryFeedListAdapter()
}
Expand All @@ -22,7 +35,7 @@ class CategoryFeedListFragment : Fragment() {
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
_binding = FragmentCategoryFeedListBinding.inflate(inflater)
_binding = FragmentCategoryFeedListBinding.inflate(inflater, container, false)
return binding.root
}

Expand All @@ -31,12 +44,43 @@ class CategoryFeedListFragment : Fragment() {
savedInstanceState: Bundle?,
) {
super.onViewCreated(view, savedInstanceState)
binding.viewModel = viewModel
binding.categoryName = "smapleCategory"
setUpBindingVariables()
observeFeedData()
observeEvent()
}

override fun onDestroyView() {
super.onDestroyView()
_binding = null
}

private fun setUpBindingVariables() {
binding.viewModel = viewModel
binding.categoryName = "Dessert"
binding.adapter = adapter
}

private fun observeFeedData() {
viewModel.feedData.observe(viewLifecycleOwner) { pagingData ->
lifecycleScope.launch {
withContext(Dispatchers.Main) {
adapter.submitData(pagingData)
}
}
}
}

private fun observeEvent() {
viewModel.uiEvent.observe(viewLifecycleOwner) { event ->
val newEvent = event.getContentIfNotHandled() ?: return@observe
when (newEvent) {
is CategoryFeedListUiEvent.NavigateBack -> {
// TODO implement navigation
}
is CategoryFeedListUiEvent.NavigateToDetail -> {
// TODO implement navigation
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package net.pengcook.android.presentation.category.list

import net.pengcook.android.presentation.core.model.Recipe

sealed interface CategoryFeedListUiEvent {
data object NavigateBack : CategoryFeedListUiEvent

data class NavigateToDetail(val recipe: Recipe) : CategoryFeedListUiEvent
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,51 @@
package net.pengcook.android.presentation.category.list

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.cachedIn
import androidx.paging.liveData
import net.pengcook.android.data.datasource.CategoryFeedPagingSource
import net.pengcook.android.data.repository.feed.FeedRepository
import net.pengcook.android.presentation.core.listener.AppbarActionEventListener
import net.pengcook.android.presentation.core.model.Recipe
import net.pengcook.android.presentation.core.util.Event
import net.pengcook.android.presentation.home.listener.FeedItemEventListener

class CategoryFeedListViewModel(
private val feedRepository: FeedRepository,
private val category: String,
) : ViewModel(), AppbarActionEventListener, FeedItemEventListener {
private val _uiEvent: MutableLiveData<Event<CategoryFeedListUiEvent>> = MutableLiveData()
val uiEvent: LiveData<Event<CategoryFeedListUiEvent>>
get() = _uiEvent

val feedData: LiveData<PagingData<Recipe>> =
Pager(
config = PagingConfig(pageSize = PAGE_SIZE, enablePlaceholders = false),
pagingSourceFactory = {
CategoryFeedPagingSource(
category = category,
fetchFeeds = feedRepository::fetchRecipesByCategory,
)
},
)
.liveData
.cachedIn(viewModelScope)

class CategoryFeedListViewModel : ViewModel(), AppbarActionEventListener {
override fun onNavigateBack() {
_uiEvent.value = Event(CategoryFeedListUiEvent.NavigateBack)
}

override fun onNavigateToDetail(recipe: Recipe) {
_uiEvent.value = Event(CategoryFeedListUiEvent.NavigateToDetail(recipe))
}

companion object {
private const val PAGE_SIZE = 10
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package net.pengcook.android.presentation.category.list

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import net.pengcook.android.data.repository.feed.FeedRepository

class CategoryFeedListViewModelFactory(
private val feedRepository: FeedRepository,
private val category: String,
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(CategoryFeedListViewModel::class.java)) {
return CategoryFeedListViewModel(feedRepository, category) as T
}
throw IllegalArgumentException()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class SearchFragment : Fragment() {
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
_binding = FragmentSearchBinding.inflate(inflater)
_binding = FragmentSearchBinding.inflate(inflater, container, false)
return binding.root
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class SignUpFragment : Fragment() {
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
_binding = FragmentSignUpBinding.inflate(inflater)
_binding = FragmentSignUpBinding.inflate(inflater, container, false)
binding.viewModel = viewModel
binding.lifecycleOwner = this
return binding.root
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ class SignUpViewModel :
val imageUri: LiveData<Uri>
get() = _imageUri

private var _signUpUiState: MutableLiveData<SignUpUiState> = MutableLiveData(SignUpUiState())
private val _signUpUiState: MutableLiveData<SignUpUiState> = MutableLiveData(SignUpUiState())
val signUpUiState: LiveData<SignUpUiState>
get() = _signUpUiState

private var _signUpEvent: MutableLiveData<Event<SignUpEvent>> = MutableLiveData()
private val _signUpEvent: MutableLiveData<Event<SignUpEvent>> = MutableLiveData()
val signUpEvent: LiveData<Event<SignUpEvent>>
get() = _signUpEvent

Expand Down
Loading

0 comments on commit ca9dcfc

Please sign in to comment.