diff options
author | Jelena Petrovic <jelenapetrovic.7119@gmail.com> | 2022-11-18 02:40:29 +0100 |
---|---|---|
committer | Jelena Petrovic <jelenapetrovic.7119@gmail.com> | 2022-11-18 02:40:29 +0100 |
commit | 7b3b8988f5abb87c17d1459ab80d129b4985fe4f (patch) | |
tree | 76328370f613f966ba418a73adfa201d25894390 /Client | |
parent | d49c17b695f131f9faf2e419e163df80dde37a88 (diff) |
delimicno odradjeno stranicenje #36
Diffstat (limited to 'Client')
9 files changed, 201 insertions, 39 deletions
diff --git a/Client/BrzoDoLokacije/app/build.gradle b/Client/BrzoDoLokacije/app/build.gradle index db4ed1b..e1ad943 100644 --- a/Client/BrzoDoLokacije/app/build.gradle +++ b/Client/BrzoDoLokacije/app/build.gradle @@ -52,6 +52,9 @@ dependencies { implementation 'com.google.android.gms:play-services-location:21.0.1' implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.recyclerview:recyclerview:1.2.1' + implementation "androidx.paging:paging-runtime:3.0.0-alpha03" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1" + testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Adapters/ShowPostsAdapter.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Adapters/ShowPostsAdapter.kt index bbcf9e4..a827dcb 100644 --- a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Adapters/ShowPostsAdapter.kt +++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Adapters/ShowPostsAdapter.kt @@ -8,6 +8,8 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.ViewGroup import android.widget.Toast +import androidx.paging.PagingDataAdapter +import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import com.example.brzodolokacije.Activities.ActivitySinglePost @@ -25,10 +27,23 @@ import retrofit2.Response class ShowPostsAdapter (val activity:Activity,val items : MutableList<PostPreview>) - : RecyclerView.Adapter<ShowPostsAdapter.ViewHolder>() { + : PagingDataAdapter<PostPreview, ShowPostsAdapter.ViewHolder>(REPO_COMPARATOR) { private lateinit var token: String private lateinit var imageApi: IBackendApi + companion object{ + private val REPO_COMPARATOR=object:DiffUtil.ItemCallback<PostPreview>(){ + override fun areContentsTheSame(oldItem: PostPreview, newItem: PostPreview): Boolean { + return oldItem._id==newItem._id + } + + override fun areItemsTheSame(oldItem: PostPreview, newItem: PostPreview): Boolean { + return oldItem._id==newItem._id + } + } + } + + //constructer has one argument - list of objects that need to be displayed //it is bound to xml of single item private lateinit var binding: PostPreviewBinding @@ -42,20 +57,18 @@ class ShowPostsAdapter (val activity:Activity,val items : MutableList<PostPrevie override fun onBindViewHolder(holder: ViewHolder, position: Int) { //sets components of particular item - holder.bind(items[position]) + holder.bind(getItem(position)!!) holder.itemView.setOnClickListener { //Toast.makeText(activity,item._id,Toast.LENGTH_LONG).show() - val intent:Intent = Intent(activity,ActivitySinglePost::class.java) - var b=Bundle() - items[position].location.type=LocationType.ADA - b.putParcelable("selectedPost", items[position]) - intent.putExtras(b) - activity.startActivity(intent) +// val intent:Intent = Intent(activity,ActivitySinglePost::class.java) +// var b=Bundle() +// items[position].location.type=LocationType.ADA +// b.putParcelable("selectedPost", items[position]) +// intent.putExtras(b) +// activity.startActivity(intent) } } - - override fun getItemCount() = items.size inner class ViewHolder(itemView: PostPreviewBinding) : RecyclerView.ViewHolder(itemView.root) { fun bind(item: PostPreview) { binding.apply { diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Fragments/FragmentShowPosts.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Fragments/FragmentShowPosts.kt index 83f6429..84df389 100644 --- a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Fragments/FragmentShowPosts.kt +++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Fragments/FragmentShowPosts.kt @@ -10,6 +10,10 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageButton import android.widget.Toast +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.paging.PagingDataAdapter +import androidx.paging.cachedIn import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -23,8 +27,14 @@ import com.example.brzodolokacije.Services.RetrofitHelper import com.example.brzodolokacije.Services.SharedPreferencesHelper import com.example.brzodolokacije.databinding.FragmentHomeBinding import com.example.brzodolokacije.databinding.FragmentShowPostsBinding +import com.example.brzodolokacije.paging.SearchPostsRepository +import com.example.brzodolokacije.paging.SearchPostsViewModel +import com.example.brzodolokacije.paging.SearchPostsViewModelFactory import kotlinx.android.synthetic.main.fragment_show_posts.* import kotlinx.android.synthetic.main.fragment_show_posts.view.* +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.launch import okhttp3.ResponseBody import retrofit2.Call import retrofit2.Response @@ -35,13 +45,15 @@ class FragmentShowPosts : Fragment(), SwipeRefreshLayout.OnRefreshListener { private lateinit var binding: FragmentShowPostsBinding private var posts : MutableList<PostPreview> = mutableListOf() private var linearManagerVar: RecyclerView.LayoutManager? = null - private var adapterVar: RecyclerView.Adapter<ShowPostsAdapter.ViewHolder>? = null + private var adapterVar: ShowPostsAdapter? = null private var recyclerView: RecyclerView?=null private var gridManagerVar: RecyclerView.LayoutManager?=null private var swipeRefreshLayout:SwipeRefreshLayout?=null + private lateinit var searchPostsViewModel:SearchPostsViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + setUpViewModel() binding=FragmentShowPostsBinding.inflate(layoutInflater) //instantiate adapter and linearLayout adapterVar=ShowPostsAdapter(requireActivity(),posts) @@ -49,6 +61,11 @@ class FragmentShowPosts : Fragment(), SwipeRefreshLayout.OnRefreshListener { gridManagerVar=GridLayoutManager(activity,2) } + private fun setUpViewModel() { + val factory=SearchPostsViewModelFactory(RetrofitHelper.getInstance(),requireActivity()) + searchPostsViewModel=ViewModelProvider(this@FragmentShowPosts,factory).get(SearchPostsViewModel::class.java) + } + fun setUpListeners(rootView: View?){ rootView?.findViewById<ImageButton>(R.id.btnGridLayout)?.setOnClickListener() { if(recyclerView?.layoutManager!=gridManagerVar){ @@ -66,32 +83,38 @@ class FragmentShowPosts : Fragment(), SwipeRefreshLayout.OnRefreshListener { } fun requestToBack(){ - val postApi= RetrofitHelper.getInstance() - val token=SharedPreferencesHelper.getValue("jwt", requireActivity()) - val request=postApi.getPosts("Bearer "+token) - request.enqueue(object : retrofit2.Callback<MutableList<PostPreview>?> { - override fun onResponse(call: Call<MutableList<PostPreview>?>, response: Response<MutableList<PostPreview>?>) { - if(response.isSuccessful){ - posts=response.body()!! - recyclerView?.adapter=ShowPostsAdapter(requireActivity(),posts) - Toast.makeText( - activity, "prosao zahtev", Toast.LENGTH_LONG - ).show() - swipeRefreshLayout?.isRefreshing=false - }else{ - if(response.errorBody()!=null) - Toast.makeText(activity, response.errorBody()!!.string(), Toast.LENGTH_LONG).show(); - } - - + lifecycleScope.launch{ + searchPostsViewModel.fetchPosts().distinctUntilChanged().collectLatest { + adapterVar?.submitData(it) + swipeRefreshLayout?.isRefreshing=false } - - override fun onFailure(call: Call<MutableList<PostPreview>?>, t: Throwable) { - Toast.makeText( - activity, t.toString(), Toast.LENGTH_LONG - ).show(); - } - }) + } +// val postApi= RetrofitHelper.getInstance() +// val token=SharedPreferencesHelper.getValue("jwt", requireActivity()) +// val request=postApi.getPosts("Bearer "+token) +// request.enqueue(object : retrofit2.Callback<MutableList<PostPreview>?> { +// override fun onResponse(call: Call<MutableList<PostPreview>?>, response: Response<MutableList<PostPreview>?>) { +// if(response.isSuccessful){ +// posts=response.body()!! +// recyclerView?.adapter=ShowPostsAdapter(requireActivity(),posts) +// Toast.makeText( +// activity, "prosao zahtev", Toast.LENGTH_LONG +// ).show() +// swipeRefreshLayout?.isRefreshing=false +// }else{ +// if(response.errorBody()!=null) +// Toast.makeText(activity, response.errorBody()!!.string(), Toast.LENGTH_LONG).show(); +// } +// +// +// } +// +// override fun onFailure(call: Call<MutableList<PostPreview>?>, t: Throwable) { +// Toast.makeText( +// activity, t.toString(), Toast.LENGTH_LONG +// ).show(); +// } +// }) } override fun onCreateView( @@ -115,14 +138,16 @@ class FragmentShowPosts : Fragment(), SwipeRefreshLayout.OnRefreshListener { R.color.purple_700 ) swipeRefreshLayout?.post(kotlinx.coroutines.Runnable { - swipeRefreshLayout?.isRefreshing=true + //swipeRefreshLayout?.isRefreshing=true requestToBack() }) return rootView } override fun onRefresh() { - requestToBack() + //requestToBack() + adapterVar!!.notifyDataSetChanged() + Log.d("main",adapterVar!!.itemCount.toString()) } }
\ No newline at end of file diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Interfaces/IBackendApi.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Interfaces/IBackendApi.kt index 2f5cff1..6d09251 100644 --- a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Interfaces/IBackendApi.kt +++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Interfaces/IBackendApi.kt @@ -54,6 +54,13 @@ interface IBackendApi { @GET("/api/user/posts") fun getMyPosts(@Header("Authorization") authHeader:String):Call<MutableList<PostPreview>> + @GET("/api/post/locations/{id}/posts") + suspend fun getPagedPosts(@Header("Authorization") authHeader: String, + @Path("id") locationId:String, + @Query("page") page:Int, + @Query("sorttype") sorttype:Int, + @Query("filterdate") filterdate:Int + ):PagedPosts //@POST("putanja") //fun add(@Body obj:Post,@Header("Authorization") authHeader:String):Call<Post> }
\ No newline at end of file diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Models/Post.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Models/Post.kt index 3bbcc0c..f990133 100644 --- a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Models/Post.kt +++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Models/Post.kt @@ -71,4 +71,12 @@ data class Rating( data class RatingReceive( var rating:Int, var postId:String -)
\ No newline at end of file +) + +data class PagedPosts( + var page:Int, + var index:Int, + var totalpages:Int, + var totalposts:Int, + var posts:MutableList<PostPreview> +) diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/paging/SearchPostsPagingSource.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/paging/SearchPostsPagingSource.kt new file mode 100644 index 0000000..2f69a7a --- /dev/null +++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/paging/SearchPostsPagingSource.kt @@ -0,0 +1,36 @@ +package com.example.brzodolokacije.paging + +import android.app.Activity +import android.util.Log +import androidx.paging.PagingSource +import com.example.brzodolokacije.Interfaces.IBackendApi +import com.example.brzodolokacije.Models.PagedPosts +import com.example.brzodolokacije.Models.PostPreview +import com.example.brzodolokacije.Services.SharedPreferencesHelper +import retrofit2.HttpException +import java.io.IOException + +class SearchPostsPagingSource( + val backend: IBackendApi, + val activity: Activity +):PagingSource<Int,PostPreview>() { + override suspend fun load(params: LoadParams<Int>): LoadResult<Int, PostPreview> { + val page=params.key?:0 + val token=SharedPreferencesHelper.getValue("jwt", activity) + return try{ + val response=backend.getPagedPosts("Bearer "+token,"6375784fe84e2d53df32bf03", + page,1,1 + ) + Log.d("main",page.toString()) + LoadResult.Page( + response.posts,prevKey=if(page==0) null else page-1, + nextKey=if(response.posts.isEmpty()) null else page+1 + ) + }catch(exception:IOException){ + return LoadResult.Error(exception) + }catch(exception:HttpException){ + return LoadResult.Error(exception) + } + } + +}
\ No newline at end of file diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/paging/SearchPostsRepository.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/paging/SearchPostsRepository.kt new file mode 100644 index 0000000..ae3a684 --- /dev/null +++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/paging/SearchPostsRepository.kt @@ -0,0 +1,30 @@ +package com.example.brzodolokacije.paging + +import android.app.Activity +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.PagingData +import androidx.paging.cachedIn +import com.example.brzodolokacije.Models.PostPreview +import com.example.brzodolokacije.Services.RetrofitHelper +import kotlinx.coroutines.flow.Flow + +class SearchPostsRepository(val activity: Activity) { + companion object{ + const val DEFAULT_PAGE_SIZE=20 + const val DEFAULT_PAGE_INDEX=1 + + fun getInstance(activity: Activity)=SearchPostsRepository(activity) + } + + fun letSearchedPostsFlow(pagingConfig: PagingConfig=getDefaultPageConfig()): Flow<PagingData<PostPreview>> { + return Pager( + config=pagingConfig, + pagingSourceFactory = {SearchPostsPagingSource(RetrofitHelper.getInstance(),activity)} + ).flow + } + + private fun getDefaultPageConfig(): PagingConfig { + return PagingConfig(pageSize= DEFAULT_PAGE_SIZE, enablePlaceholders = false) + } +}
\ No newline at end of file diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/paging/SearchPostsViewModel.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/paging/SearchPostsViewModel.kt new file mode 100644 index 0000000..d0bf3ef --- /dev/null +++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/paging/SearchPostsViewModel.kt @@ -0,0 +1,25 @@ +package com.example.brzodolokacije.paging + +import android.app.Activity +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 com.example.brzodolokacije.Interfaces.IBackendApi +import com.example.brzodolokacije.Models.PostPreview +import kotlinx.coroutines.flow.Flow + +class SearchPostsViewModel( + private val api:IBackendApi, + val activity:Activity +): ViewModel() { + val posts = + Pager(config = PagingConfig(pageSize = 10), pagingSourceFactory = { + SearchPostsPagingSource(api,activity) + }).flow.cachedIn(viewModelScope) + fun fetchPosts(): Flow<PagingData<PostPreview>>{ + return SearchPostsRepository.getInstance(activity).letSearchedPostsFlow().cachedIn(viewModelScope) + } +}
\ No newline at end of file diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/paging/SearchPostsViewModelFactory.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/paging/SearchPostsViewModelFactory.kt new file mode 100644 index 0000000..cddea54 --- /dev/null +++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/paging/SearchPostsViewModelFactory.kt @@ -0,0 +1,15 @@ +package com.example.brzodolokacije.paging + +import android.app.Activity +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.example.brzodolokacije.Interfaces.IBackendApi + +class SearchPostsViewModelFactory( + val api:IBackendApi, + val activity: Activity +):ViewModelProvider.NewInstanceFactory() { + override fun <T : ViewModel> create(modelClass: Class<T>): T { + return SearchPostsViewModel(api,activity) as T + } +}
\ No newline at end of file |