WIP implementing infinte scroll
This commit is contained in:
parent
eaff3a4965
commit
d470f7e968
@ -46,6 +46,7 @@ dependencies {
|
|||||||
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
|
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
|
||||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||||
|
implementation 'com.squareup.picasso:picasso:2.8'
|
||||||
testImplementation 'junit:junit:4.+'
|
testImplementation 'junit:junit:4.+'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.SubitoBeers">
|
android:theme="@style/Theme.SubitoBeers">
|
||||||
<activity android:name=".MainActivity">
|
<activity android:name=".MainActivity"
|
||||||
|
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
@ -2,19 +2,23 @@ package it.danieleverducci.subitobeers
|
|||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import com.squareup.picasso.Picasso
|
||||||
|
|
||||||
import it.danieleverducci.subitobeers.databinding.FragmentBeersListitemBinding
|
import it.danieleverducci.subitobeers.databinding.FragmentBeersListitemBinding
|
||||||
import it.danieleverducci.subitobeers.entities.Beer
|
import it.danieleverducci.subitobeers.entities.Beer
|
||||||
|
|
||||||
class BeerRecyclerAdapter : RecyclerView.Adapter<BeerRecyclerAdapter.ViewHolder>() {
|
class BeerRecyclerAdapter : RecyclerView.Adapter<BeerRecyclerAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
var listener: Listener? = null
|
||||||
private val items: ArrayList<Beer> = ArrayList()
|
private val items: ArrayList<Beer> = ArrayList()
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
// Create viewholder
|
||||||
return ViewHolder(
|
val vh = ViewHolder(
|
||||||
FragmentBeersListitemBinding.inflate(
|
FragmentBeersListitemBinding.inflate(
|
||||||
LayoutInflater.from(parent.context),
|
LayoutInflater.from(parent.context),
|
||||||
parent,
|
parent,
|
||||||
@ -22,12 +26,37 @@ class BeerRecyclerAdapter : RecyclerView.Adapter<BeerRecyclerAdapter.ViewHolder>
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Register click listener
|
||||||
|
vh.root.setOnClickListener(object: View.OnClickListener{
|
||||||
|
override fun onClick(v: View?) {
|
||||||
|
if (v != null) {
|
||||||
|
listener?.OnItemClicked(v.getTag() as Beer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return vh
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val item = items[position]
|
val item = items[position]
|
||||||
|
|
||||||
|
// Attach item to view to retrieve in case of click
|
||||||
|
holder.root.setTag(item)
|
||||||
|
|
||||||
|
// Fill layout with data
|
||||||
holder.name.text = item.name
|
holder.name.text = item.name
|
||||||
holder.descr.text = item.tagline
|
holder.descr.text = item.tagline
|
||||||
|
Picasso.get()
|
||||||
|
.load(item.imageUrl)
|
||||||
|
.placeholder(R.drawable.ic_launcher_foreground)
|
||||||
|
.error(R.drawable.ic_launcher_foreground)
|
||||||
|
.into(holder.pic)
|
||||||
|
|
||||||
|
// If we are drawing the last element, notify
|
||||||
|
if (position == items.size - 1)
|
||||||
|
listener?.OnLastItemScrolled()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addItems(ni: List<Beer>) {
|
fun addItems(ni: List<Beer>) {
|
||||||
@ -38,8 +67,15 @@ class BeerRecyclerAdapter : RecyclerView.Adapter<BeerRecyclerAdapter.ViewHolder>
|
|||||||
override fun getItemCount(): Int = items.size
|
override fun getItemCount(): Int = items.size
|
||||||
|
|
||||||
inner class ViewHolder(binding: FragmentBeersListitemBinding) : RecyclerView.ViewHolder(binding.root) {
|
inner class ViewHolder(binding: FragmentBeersListitemBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
val root: View = binding.root
|
||||||
val name: TextView = binding.beerItemName
|
val name: TextView = binding.beerItemName
|
||||||
val descr: TextView = binding.beerItemDescr
|
val descr: TextView = binding.beerItemDescr
|
||||||
|
val pic: ImageView = binding.beerItemPic
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
fun OnItemClicked(item: Beer)
|
||||||
|
fun OnLastItemScrolled()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -13,9 +13,11 @@ import it.danieleverducci.subitobeers.entities.Beer
|
|||||||
/**
|
/**
|
||||||
* A fragment representing a list of Items.
|
* A fragment representing a list of Items.
|
||||||
*/
|
*/
|
||||||
class BeersFragment : Fragment(), BeersRepository.Listener {
|
class BeersFragment : Fragment(), BeersRepository.Listener, BeerRecyclerAdapter.Listener {
|
||||||
|
|
||||||
private val rvAdapter = BeerRecyclerAdapter()
|
private val rvAdapter = BeerRecyclerAdapter()
|
||||||
|
private val repo = BeersRepository()
|
||||||
|
private var page = 1
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
@ -30,6 +32,10 @@ class BeersFragment : Fragment(), BeersRepository.Listener {
|
|||||||
adapter = rvAdapter
|
adapter = rvAdapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register for recyclerview adapter events
|
||||||
|
rvAdapter.listener = this
|
||||||
|
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,9 +43,11 @@ class BeersFragment : Fragment(), BeersRepository.Listener {
|
|||||||
super.onStart()
|
super.onStart()
|
||||||
|
|
||||||
// Load beers from network
|
// Load beers from network
|
||||||
val repo = BeersRepository()
|
|
||||||
repo.listener = this
|
repo.listener = this
|
||||||
repo.getBeers(1)
|
|
||||||
|
// TODO: evitare che ogni volta ricarichi gli stessi elementi
|
||||||
|
page = 1
|
||||||
|
repo.getBeers(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBeersObtained(beers: List<Beer>) {
|
override fun onBeersObtained(beers: List<Beer>) {
|
||||||
@ -50,4 +58,20 @@ class BeersFragment : Fragment(), BeersRepository.Listener {
|
|||||||
Toast.makeText(context, R.string.network_error, Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, R.string.network_error, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an item is clicked in the list
|
||||||
|
*/
|
||||||
|
override fun OnItemClicked(item: Beer) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when last list item is displayed.
|
||||||
|
* Used to fetch more elements
|
||||||
|
*/
|
||||||
|
override fun OnLastItemScrolled() {
|
||||||
|
page++;
|
||||||
|
repo.getBeers(page)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -29,7 +29,7 @@ class BeersRepository {
|
|||||||
|
|
||||||
override fun onFailure(call: Call<List<Beer>>, t: Throwable) {
|
override fun onFailure(call: Call<List<Beer>>, t: Throwable) {
|
||||||
if (t.message != null)
|
if (t.message != null)
|
||||||
Log.e(TAG, "Unable to obtain beers: ${t.message!!}")
|
Log.e(TAG, "Unable to obtain beers: ${t}")
|
||||||
listener?.onFailure()
|
listener?.onFailure()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,27 +1,21 @@
|
|||||||
package it.danieleverducci.subitobeers.entities
|
package it.danieleverducci.subitobeers.entities
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class Beer {
|
class Beer// Parse date
|
||||||
val id: Int
|
@Throws(JSONException::class) constructor() {
|
||||||
val name: String
|
val id: Int = 0
|
||||||
val tagline: String
|
val name: String = ""
|
||||||
val description: String
|
val tagline: String = ""
|
||||||
val firstBrewed: LocalDate
|
val description: String = ""
|
||||||
|
@SerializedName("image_url")
|
||||||
|
val imageUrl: String = ""
|
||||||
|
// @SerializedName("first_brewed")
|
||||||
|
// val firstBrewed: Date? = null
|
||||||
|
|
||||||
@Throws(JSONException::class)
|
|
||||||
constructor(jo: JSONObject) {
|
|
||||||
this.id = jo.getInt("id")
|
|
||||||
this.name = jo.getString("name")
|
|
||||||
this.tagline = jo.getString("tagline")
|
|
||||||
this.description = jo.getString("description")
|
|
||||||
|
|
||||||
// Parse date
|
|
||||||
val formatter = DateTimeFormatter.ofPattern("mm/yyyy", Locale.ENGLISH)
|
|
||||||
this.firstBrewed = LocalDate.parse(jo.getString("first_brewed"), formatter)
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package it.danieleverducci.subitobeers.networking
|
package it.danieleverducci.subitobeers.networking
|
||||||
|
|
||||||
|
import com.google.gson.FieldNamingPolicy
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
import it.danieleverducci.subitobeers.Config
|
import it.danieleverducci.subitobeers.Config
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
@ -7,9 +7,8 @@
|
|||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/beer_item_pic"
|
android:id="@+id/beer_item_pic"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="60dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="100dp"
|
||||||
android:layout_marginStart="10dp"
|
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginBottom="10dp"
|
android:layout_marginBottom="10dp"
|
||||||
android:src="@mipmap/ic_launcher"
|
android:src="@mipmap/ic_launcher"
|
||||||
@ -23,13 +22,15 @@
|
|||||||
android:id="@+id/beer_item_name"
|
android:id="@+id/beer_item_name"
|
||||||
style="@style/Widget.AppCompat.TextView"
|
style="@style/Widget.AppCompat.TextView"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="19dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="20dp"
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
android:layout_marginEnd="10dp"
|
android:layout_marginEnd="10dp"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:text="Beer name"
|
android:text="Beer name"
|
||||||
|
android:textSize="20sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/beer_item_descr"
|
app:layout_constraintBottom_toTopOf="@+id/beer_item_descr"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
@ -39,12 +40,12 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/beer_item_descr"
|
android:id="@+id/beer_item_descr"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="21dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="20dp"
|
android:layout_marginStart="20dp"
|
||||||
android:layout_marginEnd="10dp"
|
android:layout_marginEnd="10dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:lines="1"
|
android:maxLines="3"
|
||||||
android:maxLines="1"
|
|
||||||
android:text="Beer description lorem ipsum dolor sit amet"
|
android:text="Beer description lorem ipsum dolor sit amet"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
Loading…
Reference in New Issue
Block a user