diff --git a/app/build.gradle b/app/build.gradle index 6b0bc2f..a77e89c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -46,6 +46,7 @@ dependencies { implementation 'com.squareup.retrofit2:converter-gson:2.4.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.recyclerview:recyclerview:1.2.1' + implementation 'com.squareup.picasso:picasso:2.8' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cd6b0ed..62cf7b2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,7 +11,8 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.SubitoBeers"> - + diff --git a/app/src/main/java/it/danieleverducci/subitobeers/BeerRecyclerAdapter.kt b/app/src/main/java/it/danieleverducci/subitobeers/BeerRecyclerAdapter.kt index c4250cc..fcf61da 100644 --- a/app/src/main/java/it/danieleverducci/subitobeers/BeerRecyclerAdapter.kt +++ b/app/src/main/java/it/danieleverducci/subitobeers/BeerRecyclerAdapter.kt @@ -2,19 +2,23 @@ package it.danieleverducci.subitobeers import androidx.recyclerview.widget.RecyclerView import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup +import android.widget.ImageView import android.widget.TextView +import com.squareup.picasso.Picasso import it.danieleverducci.subitobeers.databinding.FragmentBeersListitemBinding import it.danieleverducci.subitobeers.entities.Beer class BeerRecyclerAdapter : RecyclerView.Adapter() { - + + var listener: Listener? = null private val items: ArrayList = ArrayList() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - - return ViewHolder( + // Create viewholder + val vh = ViewHolder( FragmentBeersListitemBinding.inflate( LayoutInflater.from(parent.context), parent, @@ -22,12 +26,37 @@ class BeerRecyclerAdapter : RecyclerView.Adapter ) ) + // 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) { 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.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) { @@ -38,8 +67,15 @@ class BeerRecyclerAdapter : RecyclerView.Adapter override fun getItemCount(): Int = items.size inner class ViewHolder(binding: FragmentBeersListitemBinding) : RecyclerView.ViewHolder(binding.root) { + val root: View = binding.root val name: TextView = binding.beerItemName val descr: TextView = binding.beerItemDescr + val pic: ImageView = binding.beerItemPic + } + + interface Listener { + fun OnItemClicked(item: Beer) + fun OnLastItemScrolled() } } \ No newline at end of file diff --git a/app/src/main/java/it/danieleverducci/subitobeers/BeersFragment.kt b/app/src/main/java/it/danieleverducci/subitobeers/BeersFragment.kt index 5b6b06f..d4f8918 100644 --- a/app/src/main/java/it/danieleverducci/subitobeers/BeersFragment.kt +++ b/app/src/main/java/it/danieleverducci/subitobeers/BeersFragment.kt @@ -13,9 +13,11 @@ import it.danieleverducci.subitobeers.entities.Beer /** * 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 repo = BeersRepository() + private var page = 1 override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -30,6 +32,10 @@ class BeersFragment : Fragment(), BeersRepository.Listener { adapter = rvAdapter } } + + // Register for recyclerview adapter events + rvAdapter.listener = this + return view } @@ -37,9 +43,11 @@ class BeersFragment : Fragment(), BeersRepository.Listener { super.onStart() // Load beers from network - val repo = BeersRepository() 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) { @@ -50,4 +58,20 @@ class BeersFragment : Fragment(), BeersRepository.Listener { 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) + } + } \ No newline at end of file diff --git a/app/src/main/java/it/danieleverducci/subitobeers/BeersRepository.kt b/app/src/main/java/it/danieleverducci/subitobeers/BeersRepository.kt index 5f6caa3..187ca8b 100644 --- a/app/src/main/java/it/danieleverducci/subitobeers/BeersRepository.kt +++ b/app/src/main/java/it/danieleverducci/subitobeers/BeersRepository.kt @@ -29,7 +29,7 @@ class BeersRepository { override fun onFailure(call: Call>, t: Throwable) { if (t.message != null) - Log.e(TAG, "Unable to obtain beers: ${t.message!!}") + Log.e(TAG, "Unable to obtain beers: ${t}") listener?.onFailure() } }) diff --git a/app/src/main/java/it/danieleverducci/subitobeers/entities/Beer.kt b/app/src/main/java/it/danieleverducci/subitobeers/entities/Beer.kt index db5cce4..2bf3e4a 100644 --- a/app/src/main/java/it/danieleverducci/subitobeers/entities/Beer.kt +++ b/app/src/main/java/it/danieleverducci/subitobeers/entities/Beer.kt @@ -1,27 +1,21 @@ package it.danieleverducci.subitobeers.entities +import com.google.gson.annotations.SerializedName import org.json.JSONException import org.json.JSONObject import java.time.LocalDate import java.time.format.DateTimeFormatter import java.util.* -class Beer { - val id: Int - val name: String - val tagline: String - val description: String - val firstBrewed: LocalDate +class Beer// Parse date +@Throws(JSONException::class) constructor() { + val id: Int = 0 + val name: String = "" + val tagline: String = "" + 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) - } } \ No newline at end of file diff --git a/app/src/main/java/it/danieleverducci/subitobeers/networking/RetrofitProvider.kt b/app/src/main/java/it/danieleverducci/subitobeers/networking/RetrofitProvider.kt index ea35e7a..bd6757e 100644 --- a/app/src/main/java/it/danieleverducci/subitobeers/networking/RetrofitProvider.kt +++ b/app/src/main/java/it/danieleverducci/subitobeers/networking/RetrofitProvider.kt @@ -1,5 +1,6 @@ package it.danieleverducci.subitobeers.networking +import com.google.gson.FieldNamingPolicy import com.google.gson.GsonBuilder import it.danieleverducci.subitobeers.Config import okhttp3.OkHttpClient diff --git a/app/src/main/res/layout/fragment_beers_listitem.xml b/app/src/main/res/layout/fragment_beers_listitem.xml index c4116b0..314ba57 100644 --- a/app/src/main/res/layout/fragment_beers_listitem.xml +++ b/app/src/main/res/layout/fragment_beers_listitem.xml @@ -7,9 +7,8 @@