Skip to content

Commit

Permalink
Merge pull request #12 from harisheoran/ep_loading_bug
Browse files Browse the repository at this point in the history
Ep loading bug
  • Loading branch information
harisheoran authored Jul 10, 2023
2 parents 2fea276 + 59e21a8 commit f4bb78d
Show file tree
Hide file tree
Showing 23 changed files with 422 additions and 148 deletions.
6 changes: 5 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ android {

buildFeatures {
viewBinding = true
dataBinding = true
}
}

Expand All @@ -55,7 +56,7 @@ dependencies {
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

implementation 'androidx.recyclerview:recyclerview:1.2.1'
// networking
implementation 'com.squareup.moshi:moshi:1.14.0'
implementation 'com.squareup.moshi:moshi-kotlin:1.14.0'
Expand Down Expand Up @@ -95,6 +96,9 @@ dependencies {
implementation("com.google.firebase:firebase-crashlytics-ktx")
implementation("com.google.firebase:firebase-analytics-ktx")

// lottie
implementation 'com.airbnb.android:lottie:6.0.0'

implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01"

}
Binary file removed app/src/main/ic_launcher-playstore.png
Binary file not shown.
16 changes: 16 additions & 0 deletions app/src/main/java/com/example/rickmorty/BindingAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.example.rickmorty

import android.widget.ImageView
import androidx.databinding.BindingAdapter
import com.squareup.picasso.Picasso


//In Kotlin, the let function is a scoping function that allows you to perform operations on a non-null object within a safe context.
// It is particularly useful for executing a block of code only if the object is not null.
@BindingAdapter("setImage")
fun bindImage(imgView: ImageView, imgUrl: String?) {
// it will only execute if imageUrl is non null
imgUrl?.let {
Picasso.get().load(imgUrl).into(imgView)
}
}
13 changes: 13 additions & 0 deletions app/src/main/java/com/example/rickmorty/HomeActivity.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.example.rickmorty

import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.drawerlayout.widget.DrawerLayout
Expand Down Expand Up @@ -42,8 +44,19 @@ class HomeActivity : AppCompatActivity() {
navController.graph.startDestinationId
)


// about dev menu item
val menu = findViewById<NavigationView>(R.id.nav_view).menu
val aboutDev = menu.findItem(R.id.about_dev)
aboutDev?.setOnMenuItemClickListener {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://harisheoran.github.io"))
startActivity(intent)
true
}
}



// support back navigation
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp(appBarConfiguration)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.example.rickmorty.characters

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.example.rickmorty.databinding.ModelCharacterListItemBinding
import com.example.rickmorty.network.response.GetCharacterByIdResponse

class CharacterListAdapter(private val onCharacterClick: (Int) -> Unit) :
PagingDataAdapter<GetCharacterByIdResponse, RecyclerView.ViewHolder>(DiffCallback) {

class CharacterViewHolder(var binding: ModelCharacterListItemBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(onCharacterClick: (Int) -> Unit, character: GetCharacterByIdResponse) {
binding.character = character
binding.executePendingBindings()
binding.root.setOnClickListener {
onCharacterClick(character.id)
}
}
}



override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view = CharacterViewHolder(ModelCharacterListItemBinding.inflate(LayoutInflater.from(parent.context)))
return view
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val myCharacter = getItem(position)
(holder as? CharacterViewHolder)?.bind(onCharacterClick, myCharacter!!)
}

companion object DiffCallback : DiffUtil.ItemCallback<GetCharacterByIdResponse>() {
override fun areItemsTheSame(oldItem: GetCharacterByIdResponse, newItem: GetCharacterByIdResponse): Boolean {
return oldItem.name == newItem.name
}

override fun areContentsTheSame(oldItem: GetCharacterByIdResponse, newItem: GetCharacterByIdResponse): Boolean {
return oldItem.name == newItem.name
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.core.widget.ContentLoadingProgressBar
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.airbnb.epoxy.EpoxyRecyclerView
import com.airbnb.lottie.LottieAnimationView
import androidx.paging.LoadState
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.example.rickmorty.NetworkViewModel
import com.example.rickmorty.R
import com.google.android.material.button.MaterialButton
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch

Expand All @@ -25,6 +29,8 @@ class CharacterListFragment : Fragment() {
ViewModelProvider(this).get(CharacterListViewModel::class.java)
}

private lateinit var characterAdapter: CharacterListAdapter

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
Expand All @@ -35,39 +41,55 @@ class CharacterListFragment : Fragment() {

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<LottieAnimationView>(R.id.loading).visibility = View.VISIBLE
view.findViewById<LottieAnimationView>(R.id.no_internet).visibility = View.GONE

networkViewModel = ViewModelProvider(this).get(NetworkViewModel::class.java)


networkViewModel.getNetworkState().observe(viewLifecycleOwner, {
if (it) {
view.findViewById<LottieAnimationView>(R.id.loading).visibility = View.GONE
view.findViewById<EpoxyRecyclerView>(R.id.epoxy_character_recycler_view).visibility = View.VISIBLE
view.findViewById<LottieAnimationView>(R.id.no_internet).visibility = View.GONE
lifecycleScope.launch {
viewModel.pagingDataFlow.collectLatest {
epoxyController.submitData(it)
}
}
} else {
view.findViewById<LottieAnimationView>(R.id.loading).visibility = View.GONE
view.findViewById<EpoxyRecyclerView>(R.id.epoxy_character_recycler_view).visibility = View.GONE
view.findViewById<LottieAnimationView>(R.id.no_internet).visibility = View.VISIBLE
characterAdapter = CharacterListAdapter(::onCharacterClicked)

initViewModelData()
initRecyclerView()

}

private fun initViewModelData() {
lifecycleScope.launch {
viewModel.pagingDataFlow.collectLatest {
characterAdapter.submitData(it)
}
})
}
}


private fun initRecyclerView() {
view?.findViewById<RecyclerView>(R.id.character_recycler_view)?.adapter =
characterAdapter.withLoadStateHeaderAndFooter(
header = PagingLoadStateAdapter { characterAdapter.retry() },
footer = PagingLoadStateAdapter { characterAdapter.retry() }
)


characterAdapter.addLoadStateListener { loadState ->
view?.findViewById<SwipeRefreshLayout>(R.id.swipe_refresh)?.isRefreshing =
loadState.refresh is LoadState.Loading
view?.findViewById<RecyclerView>(R.id.character_recycler_view)?.isVisible =
loadState.source.refresh is LoadState.NotLoading
view?.findViewById<ContentLoadingProgressBar>(R.id.progress_bar)?.isVisible =
loadState.source.refresh is LoadState.Loading
view?.findViewById<MaterialButton>(R.id.retry_button)?.isVisible =
loadState.source.refresh is LoadState.Error

}

view?.findViewById<SwipeRefreshLayout>(R.id.swipe_refresh)?.setOnRefreshListener {
characterAdapter.refresh()
}

view?.findViewById<MaterialButton>(R.id.retry_button)?.setOnClickListener {
characterAdapter.retry()
}

view.findViewById<EpoxyRecyclerView>(R.id.epoxy_character_recycler_view)
.setController(epoxyController)
}

private fun onCharacterClicked(characterId: Int) {

val action = CharacterListFragmentDirections.actionCharacterListFragmentToCharacterFragment(
characterId
)
private fun onCharacterClicked(characterId: Int) {
val action = CharacterListFragmentDirections.actionCharacterListFragmentToCharacterFragment(characterId)
findNavController().navigate(action)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ class CharacterListPagingDataSource(
}

override fun getRefreshKey(state: PagingState<Int, GetCharacterByIdResponse>): Int? {
TODO("Not yet implemented")
return state.anchorPosition?.let { anchorPosition ->
val anchorPage = state.closestPageToPosition(anchorPosition)
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,4 @@ class CharacterListViewModel : ViewModel() {

val pagingDataFlow: Flow<PagingData<GetCharacterByIdResponse>> = pager.flow.cachedIn(viewModelScope)


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.example.rickmorty.characters

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.core.widget.ContentLoadingProgressBar
import androidx.paging.LoadState
import androidx.paging.LoadStateAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.rickmorty.R
import com.google.android.material.button.MaterialButton
import com.google.android.material.textview.MaterialTextView

class PagingLoadStateAdapter(val retryCallback: () -> Unit) :
LoadStateAdapter<PagingLoadStateAdapter.LoadStateViewHolder>() {

class LoadStateViewHolder(itemView: View, retry: () -> Unit) : RecyclerView.ViewHolder(itemView) {

init {
itemView.findViewById<MaterialButton>(R.id.retry_button).setOnClickListener {
retry.invoke()
}
}

val progressBar = itemView.findViewById<ContentLoadingProgressBar>(R.id.progress_bar)
val errorText = itemView.findViewById<MaterialTextView>(R.id.error_msg)
fun bind(loadState: LoadState) {
if (loadState is LoadState.Error) {
errorText.text = "Try Again later..."
}
progressBar.isVisible = loadState is LoadState.Loading
itemView.findViewById<MaterialButton>(R.id.retry_button).isVisible = loadState !is LoadState.Error
errorText.isVisible = loadState !is LoadState.Loading
}
}

override fun onBindViewHolder(holder: LoadStateViewHolder, loadState: LoadState) {
holder.bind(loadState)
}

override fun onCreateViewHolder(parent: ViewGroup, loadState: LoadState): LoadStateViewHolder {
return LoadStateViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.model_network_state, parent, false),
retry = retryCallback
)
}
}
Binary file removed app/src/main/res/drawable/appicon.jpg
Binary file not shown.
2 changes: 1 addition & 1 deletion app/src/main/res/drawable/episode_number_bg.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<solid android:color="@color/md_theme_light_secondary"/> <!-- Replace "#FF0000" with your desired color -->
<solid android:color="?colorTertiary"/> <!-- Replace "#FF0000" with your desired color -->

<!-- Optional: Add corner radius to round the corners -->
<corners android:bottomLeftRadius="8dp" />
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/res/drawable/info_24.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"/>
</vector>
Binary file added app/src/main/res/drawable/main.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion app/src/main/res/layout/activity_home.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
android:fitsSystemWindows="false"
app:headerLayout="@layout/header_drawer_layout"
app:menu="@menu/menu_drawer"/>

Expand Down
Loading

0 comments on commit f4bb78d

Please sign in to comment.