Skip to content

Commit 6dab535

Browse files
committed
pagination completed
1 parent 8f4b2d2 commit 6dab535

File tree

7 files changed

+128
-14
lines changed

7 files changed

+128
-14
lines changed

app/src/main/java/com/sijanneupane/mvvmnews/adapters/NewsAdapter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class NewsAdapter : RecyclerView.Adapter<NewsAdapter.ArticleViewHolder>() {
4747
val article= differ.currentList[position]
4848
holder.itemView.apply {
4949
Glide.with(this).load(article.urlToImage).into(ivArticleImage)
50-
tvSource.text= article.source.name;
50+
tvSource.text= article.source?.name
5151
tvTitle.text= article.title
5252
tvDescription.text= article.description
5353
tvPublishedAt.text= article.publishedAt

app/src/main/java/com/sijanneupane/mvvmnews/models/Article.kt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ Here article will be the whole table and with columns
1616
data class Article(
1717
@PrimaryKey(autoGenerate = true) //adding id as primary key to the table and the class
1818
var id: Int?= null, //not all articles will have id, so setting it to null
19-
val author: String,
20-
val content: String,
21-
val description: String,
22-
val publishedAt: String,
23-
val source: Source,
24-
val title: String,
25-
val url: String,
26-
val urlToImage: String
19+
val author: String?,
20+
val content: String?,
21+
val description: String?,
22+
val publishedAt: String?,
23+
val source: Source?,
24+
val title: String?,
25+
val url: String?,
26+
val urlToImage: String?
2727
) : Serializable
2828
//serializing to send whole class with bundle

app/src/main/java/com/sijanneupane/mvvmnews/models/NewsResponse.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package com.sijanneupane.mvvmnews.models
33
import com.sijanneupane.mvvmnews.models.Article
44

55
data class NewsResponse(
6-
val articles: List<Article>,
6+
val articles: MutableList<Article>,
77
val status: String,
88
val totalResults: Int
99
)

app/src/main/java/com/sijanneupane/mvvmnews/ui/NewsViewModel.kt

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ class NewsViewModel(
2121
//Pagination
2222
var breakingNewsPage= 1
2323
var searchNewsPage= 1
24+
var breakingNewsResponse : NewsResponse? = null
25+
var searchNewsResponse : NewsResponse? = null
26+
2427

2528
init {
2629
getBreakingNews("in")
@@ -55,7 +58,15 @@ class NewsViewModel(
5558
private fun handleBreakingNewsResponse(response: Response<NewsResponse>): Resource<NewsResponse>{
5659
if (response.isSuccessful){
5760
response.body()?.let { resultResponse ->
58-
return Resource.Success(resultResponse)
61+
breakingNewsPage++
62+
if (breakingNewsResponse== null){
63+
breakingNewsResponse= resultResponse //if first page save the result to the response
64+
}else{
65+
val oldArticles= breakingNewsResponse?.articles //else, add all articles to old
66+
val newArticle= resultResponse.articles //add new response to new
67+
oldArticles?.addAll(newArticle) //add new articles to old articles
68+
}
69+
return Resource.Success(breakingNewsResponse ?: resultResponse)
5970
}
6071
}
6172
return Resource.Error(response.message())
@@ -64,7 +75,15 @@ class NewsViewModel(
6475
private fun handleSearchNewsResponse(response: Response<NewsResponse>): Resource<NewsResponse>{
6576
if (response.isSuccessful){
6677
response.body()?.let { resultResponse ->
67-
return Resource.Success(resultResponse)
78+
searchNewsPage++
79+
if (searchNewsResponse== null){
80+
searchNewsResponse= resultResponse //if first page save the result to the response
81+
}else{
82+
val oldArticles= searchNewsResponse?.articles //else, add all articles to old
83+
val newArticle= resultResponse.articles //add new response to new
84+
oldArticles?.addAll(newArticle) //add new articles to old articles
85+
}
86+
return Resource.Success(searchNewsResponse ?: resultResponse)
6887
}
6988
}
7089
return Resource.Error(response.message())

app/src/main/java/com/sijanneupane/mvvmnews/ui/fragments/BreakingNewsFragment.kt

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@ package com.sijanneupane.mvvmnews.ui.fragments
33
import android.os.Bundle
44
import android.util.Log
55
import android.view.View
6+
import android.widget.AbsListView
67
import android.widget.LinearLayout
78
import androidx.fragment.app.Fragment
89
import androidx.lifecycle.Observer
910
import androidx.lifecycle.viewModelScope
1011
import androidx.navigation.fragment.findNavController
1112
import androidx.recyclerview.widget.LinearLayoutManager
13+
import androidx.recyclerview.widget.RecyclerView
1214
import com.sijanneupane.mvvmnews.R
1315
import com.sijanneupane.mvvmnews.adapters.NewsAdapter
1416
import com.sijanneupane.mvvmnews.ui.MainActivity
1517
import com.sijanneupane.mvvmnews.ui.NewsViewModel
18+
import com.sijanneupane.mvvmnews.utils.Constants.Companion.QUERY_PAGE_SIZE
1619
import com.sijanneupane.mvvmnews.utils.Resource
1720
import kotlinx.android.synthetic.main.fragment_breaking_news.*
1821

@@ -49,7 +52,12 @@ class BreakingNewsFragment : Fragment(R.layout.fragment_breaking_news) {
4952
hideProgressBar()
5053
//check null
5154
response.data?.let { newsResponse ->
52-
newsAdapter.differ.submitList(newsResponse.articles)
55+
newsAdapter.differ.submitList(newsResponse.articles.toList())
56+
val totalPages= newsResponse.totalResults / QUERY_PAGE_SIZE + 2
57+
isLastPage= viewModel.breakingNewsPage == totalPages
58+
if (isLastPage){
59+
rvBreakingNews.setPadding(0,0,0,0)
60+
}
5361
}
5462
}
5563
is Resource.Error->{
@@ -70,12 +78,51 @@ class BreakingNewsFragment : Fragment(R.layout.fragment_breaking_news) {
7078
rvBreakingNews.apply {
7179
adapter = newsAdapter
7280
layoutManager = LinearLayoutManager(activity)
81+
addOnScrollListener(this@BreakingNewsFragment.scrollListener)
82+
7383
}
7484
}
7585
private fun hideProgressBar(){
7686
paginationProgressBar.visibility= View.INVISIBLE
87+
isLoading= false
7788
}
7889
private fun showProgressBar(){
7990
paginationProgressBar.visibility= View.VISIBLE
91+
isLoading= true
92+
}
93+
94+
var isLoading= false
95+
var isLastPage= false
96+
var isScrolling= false
97+
98+
val scrollListener= object : RecyclerView.OnScrollListener(){
99+
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
100+
super.onScrolled(recyclerView, dx, dy)
101+
102+
//manually calculating payout numbers for pagination
103+
val layoutManager= recyclerView.layoutManager as LinearLayoutManager
104+
val firstVisibleItemPosition= layoutManager.findFirstVisibleItemPosition()
105+
val visibleItemCount= layoutManager.childCount
106+
val totalItemCount= layoutManager.itemCount
107+
108+
val isNotLoadingAndNotLastPage= !isLoading && !isLastPage
109+
val isAtLastItem= firstVisibleItemPosition+ visibleItemCount >= totalItemCount
110+
val isNotAtBeginning= firstVisibleItemPosition >= 0
111+
val isTotalMoreThanVisible= totalItemCount >= QUERY_PAGE_SIZE
112+
113+
val shouldPaginate = isNotLoadingAndNotLastPage && isAtLastItem && isNotAtBeginning && isTotalMoreThanVisible && isScrolling
114+
115+
if (shouldPaginate){
116+
viewModel.getBreakingNews("in")
117+
isScrolling= false
118+
}
119+
}
120+
121+
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
122+
super.onScrollStateChanged(recyclerView, newState)
123+
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL){
124+
isScrolling= true
125+
}
126+
}
80127
}
81128
}

app/src/main/java/com/sijanneupane/mvvmnews/ui/fragments/SearchNewsFragment.kt

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,23 @@ package com.sijanneupane.mvvmnews.ui.fragments
33
import android.os.Bundle
44
import android.util.Log
55
import android.view.View
6+
import android.widget.AbsListView
67
import androidx.core.widget.addTextChangedListener
78
import androidx.fragment.app.Fragment
89
import androidx.lifecycle.Observer
910
import androidx.navigation.fragment.findNavController
1011
import androidx.recyclerview.widget.LinearLayoutManager
12+
import androidx.recyclerview.widget.RecyclerView
1113
import com.sijanneupane.mvvmnews.R
1214
import com.sijanneupane.mvvmnews.adapters.NewsAdapter
1315
import com.sijanneupane.mvvmnews.ui.MainActivity
1416
import com.sijanneupane.mvvmnews.ui.NewsViewModel
17+
import com.sijanneupane.mvvmnews.utils.Constants
1518
import com.sijanneupane.mvvmnews.utils.Constants.Companion.SEARCH_DELAY
1619
import com.sijanneupane.mvvmnews.utils.Resource
20+
import kotlinx.android.synthetic.main.fragment_breaking_news.*
1721
import kotlinx.android.synthetic.main.fragment_search_news.*
22+
import kotlinx.android.synthetic.main.fragment_search_news.paginationProgressBar
1823
import kotlinx.coroutines.Job
1924
import kotlinx.coroutines.MainScope
2025
import kotlinx.coroutines.delay
@@ -69,7 +74,9 @@ class SearchNewsFragment : Fragment (R.layout.fragment_search_news) {
6974
hideProgressBar()
7075
//check null
7176
response.data?.let { newsResponse ->
72-
newsAdapter.differ.submitList(newsResponse.articles)
77+
newsAdapter.differ.submitList(newsResponse.articles.toList())
78+
val totalPages= newsResponse.totalResults / Constants.QUERY_PAGE_SIZE + 2
79+
isLastPage= viewModel.searchNewsPage == totalPages
7380
}
7481
}
7582
is Resource.Error->{
@@ -90,12 +97,52 @@ class SearchNewsFragment : Fragment (R.layout.fragment_search_news) {
9097
rvSearchNews.apply {
9198
adapter = newsAdapter
9299
layoutManager = LinearLayoutManager(activity)
100+
addOnScrollListener(this@SearchNewsFragment.scrollListener)
93101
}
94102
}
95103
private fun hideProgressBar(){
96104
paginationProgressBar.visibility= View.INVISIBLE
105+
isLoading= false
97106
}
98107
private fun showProgressBar(){
99108
paginationProgressBar.visibility= View.VISIBLE
109+
isLoading= false
110+
}
111+
112+
113+
var isLoading= false
114+
var isLastPage= false
115+
var isScrolling= false
116+
val scrollListener= object : RecyclerView.OnScrollListener(){
117+
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
118+
super.onScrolled(recyclerView, dx, dy)
119+
120+
//manually calculating payout numbers for pagination
121+
val layoutManager= recyclerView.layoutManager as LinearLayoutManager
122+
val firstVisibleItemPosition= layoutManager.findFirstVisibleItemPosition()
123+
val visibleItemCount= layoutManager.childCount
124+
val totalItemCount= layoutManager.itemCount
125+
126+
val isNotLoadingAndNotLastPage= !isLoading && !isLastPage
127+
val isAtLastItem= firstVisibleItemPosition+ visibleItemCount >= totalItemCount
128+
val isNotAtBeginning= firstVisibleItemPosition >= 0
129+
val isTotalMoreThanVisible= totalItemCount >= Constants.QUERY_PAGE_SIZE
130+
131+
val shouldPaginate = isNotLoadingAndNotLastPage && isAtLastItem && isNotAtBeginning && isTotalMoreThanVisible && isScrolling
132+
133+
if (shouldPaginate){
134+
viewModel.searchNews(etSearch.toString())
135+
isScrolling= false
136+
}else{
137+
rvSearchNews.setPadding(0,0,0,0)
138+
}
139+
}
140+
141+
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
142+
super.onScrollStateChanged(recyclerView, newState)
143+
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL){
144+
isScrolling= true
145+
}
146+
}
100147
}
101148
}

app/src/main/java/com/sijanneupane/mvvmnews/utils/Constants.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ class Constants {
55
const val API_KEY= "a7ebed0b55b041e7a20fc6ef542c5322"
66
const val BASE_URL= "https://newsapi.org"
77
const val SEARCH_DELAY= 500L
8+
const val QUERY_PAGE_SIZE= 20
89
}
910
}

0 commit comments

Comments
 (0)