Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added NationalPark.mp4
Binary file not shown.
5 changes: 4 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,7 @@ dependencies {
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
}
implementation 'com.codepath.libraries:asynchttpclient:2.2.0'
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
}
10 changes: 8 additions & 2 deletions app/src/main/java/com/codepath/nationalparks/NationalPark.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,14 @@ class NationalPark {
@SerializedName("states")
var location: String? = null

//TODO parkImageUrl
@SerializedName("images")
var images: List<Image>? = null

// Convenience property to access the first image’s URL
val imageUrl: String? get() = images?.firstOrNull()?.url

//TODO-STRETCH-GOALS
class Image {
@SerializedName("url")
var url: String? = null
}
}
137 changes: 78 additions & 59 deletions app/src/main/java/com/codepath/nationalparks/NationalParksFragment.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.codepath.nationalparks

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
Expand All @@ -9,36 +10,42 @@ import androidx.core.widget.ContentLoadingProgressBar
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.codepath.asynchttpclient.AsyncHttpClient
import com.codepath.asynchttpclient.RequestParams
import com.codepath.asynchttpclient.callback.JsonHttpResponseHandler
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import okhttp3.Headers
import org.json.JSONArray


// --------------------------------//
// CHANGE THIS TO BE YOUR API KEY //
// --------------------------------//
private const val API_KEY = "<YOUR-API-KEY-HERE>"
private const val API_KEY = "0uZ6uWEVVJjaWWdR8T0ZgGi8rCNu6QHmWa1WN3cl"

/*
* The class for the only fragment in the app, which contains the progress bar,
* recyclerView, and performs the network calls to the National Parks API.

*/
class NationalParksFragment : Fragment(), OnListFragmentInteractionListener {
/*
/*
* Constructing the view
*/
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_national_parks_list, container, false)
val progressBar = view.findViewById<View>(R.id.progress) as ContentLoadingProgressBar
val recyclerView = view.findViewById<View>(R.id.list) as RecyclerView
val context = view.context

recyclerView.layoutManager = LinearLayoutManager(context)

updateAdapter(progressBar, recyclerView)
return view
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_national_parks_list, container, false)
val progressBar = view.findViewById<View>(R.id.progress) as ContentLoadingProgressBar
val recyclerView = view.findViewById<View>(R.id.list) as RecyclerView
val context = view.context

recyclerView.layoutManager = LinearLayoutManager(context)

updateAdapter(progressBar, recyclerView)
return view
}

/*
* Updates the RecyclerView adapter with new data. This is where the
Expand All @@ -48,53 +55,65 @@ class NationalParksFragment : Fragment(), OnListFragmentInteractionListener {
progressBar.show()

// Create and set up an AsyncHTTPClient() here
val client = AsyncHttpClient()
val params = RequestParams()
params["api_key"] = API_KEY

// Using the client, perform the HTTP request
client[
"https://developer.nps.gov/api/v1/parks",
params,
object : JsonHttpResponseHandler() {
/*
* The onSuccess function gets called when
* HTTP response status is "200 OK"
*/
override fun onSuccess(
statusCode: Int,
headers: Headers,
json: JsonHttpResponseHandler.JSON
) {
// The wait for a response is over
progressBar.hide()

val dataJSON = json.jsonObject.get("data") as JSONArray
val parksRawJSON = dataJSON.toString()

// Create a Gson instance to help parse the raw JSON
val gson = Gson()

// Tell Gson what type we’re expecting (a list of NationalPark objects)
val arrayParkType = object : TypeToken<List<NationalPark>>() {}.type

// Convert the raw JSON string into a list of actual NationalPark data models
val models: List<NationalPark> = gson.fromJson(parksRawJSON, arrayParkType)

recyclerView.adapter = NationalParksRecyclerViewAdapter(models, this@NationalParksFragment)

// Look for this in Logcat:
Log.d("NationalParksFragment", "response successful")
}

/* Uncomment me once you complete the above sections!
{
/*
* The onSuccess function gets called when
* HTTP response status is "200 OK"
*/
override fun onSuccess(
statusCode: Int,
headers: Headers,
json: JsonHttpResponseHandler.JSON
) {
// The wait for a response is over
progressBar.hide()

//TODO - Parse JSON into Models

val models : List<NationalPark> = mutableListOf() // Fix me!
recyclerView.adapter = NationalParksRecyclerViewAdapter(models, this@NationalParksFragment)

// Look for this in Logcat:
Log.d("NationalParksFragment", "response successful")
}

/*
* The onFailure function gets called when
* HTTP response status is "4XX" (eg. 401, 403, 404)
*/
override fun onFailure(
statusCode: Int,
headers: Headers?,
errorResponse: String,
t: Throwable?
) {
// The wait for a response is over
progressBar.hide()

// If the error is not null, log it!
t?.message?.let {
Log.e("NationalParksFragment", errorResponse)
/*
* The onFailure function gets called when
* HTTP response status is "4XX" (eg. 401, 403, 404)
*/
override fun onFailure(
statusCode: Int,
headers: Headers?,
errorResponse: String,
t: Throwable?
) {
// The wait for a response is over
progressBar.hide()

// If the error is not null, log it!
t?.message?.let {
Log.e("NationalParksFragment", errorResponse)
}
}
}
}]
*/

]
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ package com.codepath.nationalparks
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.codepath.nationalparks.R.id
import com.bumptech.glide.Glide

/**
* [RecyclerView.Adapter] that can display a [NationalPark] and makes a call to the
Expand All @@ -27,9 +28,10 @@ class NationalParksRecyclerViewAdapter(
inner class ParkViewHolder(val mView: View) : RecyclerView.ViewHolder(mView) {
var mItem: NationalPark? = null

// TODO: Step 4a - Add references for remaining views from XML
val mParkName: TextView = mView.findViewById(id.park_name) as TextView
val mParkDescription: TextView = mView.findViewById(id.park_description) as TextView
val mParkImage: ImageView = mView.findViewById(R.id.park_image) as ImageView
val mParkName: TextView = mView.findViewById(R.id.park_name) as TextView
val mParkLocation: TextView = mView.findViewById(R.id.park_location) as TextView
val mParkDescription: TextView = mView.findViewById(R.id.park_description) as TextView

override fun toString(): String {
return mParkName.toString() + " '" + mParkDescription.text + "'"
Expand All @@ -39,13 +41,16 @@ class NationalParksRecyclerViewAdapter(
override fun onBindViewHolder(holder: ParkViewHolder, position: Int) {
val park = parks[position]

// TODO: Step 4b - Bind the park data to the views
holder.mItem = park
holder.mParkName.text = park.name
holder.mParkLocation.text = park.location
holder.mParkDescription.text = park.description

// TODO: Step 4c - Use Glide to load the first image

val imageUrl = park.imageUrl
Glide.with(holder.mView)
.load(imageUrl)
.centerInside()
.into(holder.mParkImage)

// Sets up click listener for this park item
holder.mView.setOnClickListener {
Expand Down
60 changes: 45 additions & 15 deletions app/src/main/res/layout/fragment_national_park.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,62 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="6dp">
android:padding="12dp">

<ImageView
android:id="@+id/park_image"
android:layout_width="100dp"
android:layout_height="100dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
tools:srcCompat="@tools:sample/backgrounds/scenic" />

<!-- Park Name -->
<TextView
android:id="@+id/park_name"
android:text="Park Name"
android:textAppearance="?attr/textAppearanceListItem"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />
android:layout_marginStart="16dp"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/park_image"
app:layout_constraintTop_toTopOf="@+id/park_image"
tools:text="Yellowstone National Park" />

<!-- Park Description -->
<TextView
android:id="@+id/park_description"
android:text="Park Description"
android:textAppearance="?attr/textAppearanceListItem"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:ellipsize="end"
android:maxLines="3"
android:textColor="#666666"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/park_image"
app:layout_constraintTop_toBottomOf="@+id/park_name"
app:layout_constraintStart_toStartOf="parent" />
tools:text="Visit Yellowstone and experience the world's first national park." />

<!-- TODO: Add park image -->
<!-- TODO: Add location or other details -->
<TextView
android:id="@+id/park_location"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:textColor="#888888"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/park_image"
app:layout_constraintTop_toBottomOf="@+id/park_description"
app:layout_constraintVertical_bias="0.0"
tools:text="WY, MT, ID" />

</androidx.constraintlayout.widget.ConstraintLayout>