Added API calls and detailed fragment

This commit is contained in:
Vladislav Khorev 2017-06-10 21:58:30 +03:00
parent 437a4359f8
commit 1a6611c087
22 changed files with 610 additions and 113 deletions

View File

@ -1,8 +0,0 @@
package fishrungames.yelpmapapp
/**
* Created by mephi on 10.06.2017.
*/
data class CoordinatesRecord(val latitude: Double,
val longitude: Double)

View File

@ -1,19 +1,87 @@
package fishrungames.yelpmapapp
import android.content.Context
import android.os.Handler
import com.koushikdutta.ion.Ion
import fishrungames.yelpmapapp.asyncTasks.HandleBusinessDetailResponseAsyncTask
import fishrungames.yelpmapapp.asyncTasks.HandleMapMarkersResponseAsyncTask
import fishrungames.yelpmapapp.asyncTasks.HandleReviewListResponseAsyncTask
import fishrungames.yelpmapapp.records.BusinessDetailRecord
import fishrungames.yelpmapapp.records.MapMarkerRecord
import fishrungames.yelpmapapp.records.ReviewListRecord
import java.util.*
/**
* Created by mephi on 09.06.2017.
*/
class DataProvider(val context: Context, val onUpdateMapMarkers : ((Map<String, MapMarkerRecord>) -> Unit)) {
class DataProvider(
val context: Context,
val onUpdateMapMarkers : ((Map<String, MapMarkerRecord>) -> Unit),
val onUpdateBusinessDetail : ((BusinessDetailRecord) -> Unit),
val onUpdateReviewList : ((Pair<String, ReviewListRecord>) -> Unit)
) {
val yelpApiKey = "TFhv6H25FV25ETpIC64TmN1sZ98yLIK3-4IZ7-CFSaRIyO6Xo97n1uI5207vo3JA-gLgu1f_7dw4LLWrpAcVAELSVFwHxYDL2FEfwaheJ9WvjbgEbjd3ADWAkt46WXYx"
fun requestData(lat : Double, lon : Double, radius : Int)
val businessDetailCache = mutableMapOf<String, BusinessDetailRecord>()
val reviewListCache = mutableMapOf<String, Pair<String, ReviewListRecord>>()
val handler = Handler()
var latestRequestDate : Date? = null
var requestScheduled : Boolean = false
var nextLocationToRequest : Pair<Double, Double>? = null
fun requestMapMarkerData(lat : Double, lon : Double)
{
nextLocationToRequest = Pair<Double, Double>(lat, lon)
val requestLimitInMs = 2000L
val newDate = Date()
if (latestRequestDate == null)
{
innerRequestMapMarkerData()
}
else {
if (!requestScheduled) {
requestScheduled = true
val timeDiffMs = newDate.time - latestRequestDate!!.time
if (timeDiffMs >= requestLimitInMs) {
innerRequestMapMarkerData()
} else {
handler.postDelayed({ innerRequestMapMarkerData() }, requestLimitInMs - timeDiffMs)
}
}
}
}
fun innerRequestMapMarkerData()
{
if (nextLocationToRequest == null)
{
return
}
val lat = nextLocationToRequest!!.first
val lon = nextLocationToRequest!!.second
val radius = 2000
latestRequestDate = Date()
requestScheduled = false
Ion.with(context)
.load("https://api.yelp.com/v3/businesses/search?latitude=${lat}&longitude=${lon}&radius=${radius}")
@ -31,10 +99,77 @@ class DataProvider(val context: Context, val onUpdateMapMarkers : ((Map<String,
return@setCallback
}
HandleResponseAsyncTask(onUpdateMapMarkers).execute(result)
HandleMapMarkersResponseAsyncTask(onUpdateMapMarkers).execute(result)
};
}
fun requestBusinessDetail(id: String)
{
Ion.with(context)
.load("https://api.yelp.com/v3/businesses/${id}")
.addHeader("Authorization", "Bearer " + yelpApiKey)
.asJsonObject()
.setCallback { e, result ->
if (e != null)
{
return@setCallback
}
if (result == null)
{
return@setCallback
}
HandleBusinessDetailResponseAsyncTask(this::handleUpdateBusinessDetail).execute(result)
};
}
fun requestReviewList(id: String)
{
Ion.with(context)
.load("https://api.yelp.com/v3/businesses/${id}/reviews")
.addHeader("Authorization", "Bearer " + yelpApiKey)
.asJsonObject()
.setCallback { e, result ->
if (e != null)
{
return@setCallback
}
if (result == null)
{
return@setCallback
}
HandleReviewListResponseAsyncTask(id, this::handleUpdateReviewList).execute(result)
};
}
fun handleUpdateBusinessDetail(businessDetailRecord : BusinessDetailRecord?)
{
if (businessDetailRecord != null && businessDetailRecord.id != null)
{
businessDetailCache[businessDetailRecord.id] = businessDetailRecord
onUpdateBusinessDetail(businessDetailRecord)
}
}
fun handleUpdateReviewList(reviewListRecordPair : Pair<String, ReviewListRecord>?)
{
if (reviewListRecordPair != null) {
reviewListCache[reviewListRecordPair.first] = reviewListRecordPair
onUpdateReviewList(reviewListRecordPair)
}
}

View File

@ -2,13 +2,16 @@ package fishrungames.yelpmapapp
import android.support.v4.app.Fragment
import android.os.Bundle
import android.support.v7.widget.LinearLayoutCompat
import android.support.v7.widget.LinearLayoutManager
import android.view.ViewGroup
import android.view.LayoutInflater
import android.view.View
import fishrungames.yelpmapapp.records.BusinessDetailRecord
import fishrungames.yelpmapapp.records.ReviewListRecord
import android.support.v7.widget.RecyclerView
import fishrungames.yelpmapapp.records.MapMarkerRecord
/**
@ -17,10 +20,42 @@ import android.view.View
class DetailFragment : Fragment()
{
var detailRecyclerAdapter : DetailRecyclerAdapter? = null
var mapMarkerRecord : MapMarkerRecord? = null
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val rootView = inflater!!.inflate(R.layout.detail_fragment, container, false)
val detailRecyclerView = rootView.findViewById(R.id.detailRecyclerView) as RecyclerView
detailRecyclerView.layoutManager = LinearLayoutManager(this.context)
mapMarkerRecord = arguments?.getSerializable("mapMarkerRecord") as? MapMarkerRecord
if (mapMarkerRecord != null && mapMarkerRecord!!.id != null) {
detailRecyclerAdapter = DetailRecyclerAdapter()
detailRecyclerView.adapter = detailRecyclerAdapter
(activity as? YelpMapActivity)?.dataProvider?.requestBusinessDetail(mapMarkerRecord!!.id!!)
(activity as? YelpMapActivity)?.dataProvider?.requestReviewList(mapMarkerRecord!!.id!!)
}
return rootView
}
fun updateBusinessDetail(businessDetailRecord : BusinessDetailRecord)
{
detailRecyclerAdapter?.notifyDataSetChanged()
}
fun updateReviewList(reviewListRecordPair : Pair<String, ReviewListRecord>)
{
detailRecyclerAdapter?.notifyDataSetChanged()
}
}

View File

@ -0,0 +1,73 @@
package fishrungames.yelpmapapp
import android.support.v7.widget.RecyclerView
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.view.LayoutInflater
/**
* Created by mephi on 10.06.2017.
*/
class DetailRecyclerAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
internal class PhoneViewHolder(v: View) : RecyclerView.ViewHolder(v) {
var phoneTextView: TextView = v.findViewById(R.id.phoneTextView) as TextView
}
internal class AddressViewHolder(v: View) : RecyclerView.ViewHolder(v) {
var addressTextView: TextView = v.findViewById(R.id.addressTextView) as TextView
}
override fun getItemViewType(position: Int): Int {
// Just as an example, return 0 or 2 depending on position
// Note that unlike in ListView adapters, types don't have to be contiguous
return position % 2
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
when (viewType) {
0 -> {
val v = LayoutInflater.from(parent.context).inflate(R.layout.recycler_phone, parent, false)
return PhoneViewHolder(v)
}
else -> {
val v = LayoutInflater.from(parent.context).inflate(R.layout.recycler_address, parent, false)
return AddressViewHolder(v)
}
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder.itemViewType) {
0 -> {
val phoneViewHolder = holder as PhoneViewHolder
phoneViewHolder.phoneTextView.text = "+86 15000929180"
}
1 -> {
val addressViewHolder = holder as AddressViewHolder
addressViewHolder.addressTextView.text = "555 First avenue"
}
}
}
override fun getItemCount(): Int {
return 2
}
}

View File

@ -2,18 +2,34 @@ package fishrungames.yelpmapapp
import com.google.maps.android.clustering.ClusterItem
import com.google.android.gms.maps.model.LatLng
import fishrungames.yelpmapapp.records.MapMarkerRecord
/**
* Created by mephi on 10.06.2017.
*/
class MapMarkerClusterItem(inMapMarkerRecord : MapMarkerRecord) : ClusterItem
class MapMarkerClusterItem(val mapMarkerRecord: MapMarkerRecord) : ClusterItem
{
private val mPosition = LatLng(inMapMarkerRecord.coordinates.latitude, inMapMarkerRecord.coordinates.longitude)
private val mPosition : LatLng
val mapMarkerRecord = inMapMarkerRecord
init {
val lat = mapMarkerRecord.coordinates?.latitude
val lon = mapMarkerRecord.coordinates?.longitude
if (lat != null && lon != null)
{
mPosition = LatLng(lat, lon)
}
else
{
mPosition = LatLng(0.0, 0.0)
}
}
override fun getPosition(): LatLng {
return mPosition

View File

@ -1,14 +0,0 @@
package fishrungames.yelpmapapp
/**
* Created by mephi on 09.06.2017.
*/
data class MapMarkerRecord (
val id: String,
val name: String,
val image_url: String,
val coordinates: CoordinatesRecord
)

View File

@ -1,14 +1,17 @@
package fishrungames.yelpmapapp
import android.location.Location
import android.os.Bundle
import android.os.Handler
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.Marker
import com.google.maps.android.clustering.Cluster
import java.util.*
import com.google.maps.android.clustering.ClusterManager
import fishrungames.yelpmapapp.google.MapsActivity
import fishrungames.yelpmapapp.records.BusinessDetailRecord
import fishrungames.yelpmapapp.records.MapMarkerRecord
import fishrungames.yelpmapapp.records.ReviewListRecord
/**
@ -16,12 +19,14 @@ import com.google.maps.android.clustering.ClusterManager
*/
class YelpMapActivity : MapsActivity(), GoogleMap.OnInfoWindowClickListener
class YelpMapActivity : MapsActivity(), ClusterManager.OnClusterItemInfoWindowClickListener<MapMarkerClusterItem>, ClusterManager.OnClusterItemClickListener<MapMarkerClusterItem>, GoogleMap.OnInfoWindowClickListener
{
val handler = Handler()
val dataProvider = DataProvider(this, this::handleMarkersUpdated)
val dataProvider = DataProvider(this,
this::handleMarkersUpdated,
this::handleUpdateBusinessDetail,
this::handleUpdateReviewList)
var yelpInfoWindowProvider : YelpInfoWindowProvider? = null
@ -29,24 +34,22 @@ class YelpMapActivity : MapsActivity(), GoogleMap.OnInfoWindowClickListener
val markerMap = mutableMapOf<String, MapMarkerClusterItem>()
var latestRequestDate : Date? = null
var requestScheduled : Boolean = false
var lastClickedMapMarker : MapMarkerClusterItem? = null
override fun onMapReady(googleMap: GoogleMap) {
super.onMapReady(googleMap)
googleMap.setOnCameraMoveListener {
tryRequestData(googleMap.cameraPosition.target.latitude, googleMap.cameraPosition.target.longitude)
dataProvider.requestMapMarkerData(googleMap.cameraPosition.target.latitude, googleMap.cameraPosition.target.longitude)
}
googleMap.setOnInfoWindowClickListener(this)
yelpInfoWindowProvider = YelpInfoWindowProvider(this)
//yelpInfoWindowProvider = YelpInfoWindowProvider(this)
googleMap.setInfoWindowAdapter(yelpInfoWindowProvider)
//googleMap.setInfoWindowAdapter(yelpInfoWindowProvider)
setUpClusterer(googleMap)
}
@ -54,7 +57,7 @@ class YelpMapActivity : MapsActivity(), GoogleMap.OnInfoWindowClickListener
override fun onLocationChanged(location: Location) {
super.onLocationChanged(location)
tryRequestData(location.latitude, location.longitude)
dataProvider.requestMapMarkerData(location.latitude, location.longitude)
}
fun handleMarkersUpdated(newMarkerMap: Map<String, MapMarkerRecord>)
@ -74,58 +77,20 @@ class YelpMapActivity : MapsActivity(), GoogleMap.OnInfoWindowClickListener
{
val mapMarkerRecord = newMarkerMap[key] as MapMarkerRecord
val mapMarkerClusterItem = MapMarkerClusterItem(mapMarkerRecord)
if (mapMarkerRecord.coordinates != null && mapMarkerRecord.coordinates.latitude != null && mapMarkerRecord.coordinates.longitude != null ) {
clusterManager.addItem(mapMarkerClusterItem)
markerMap[key] = mapMarkerClusterItem
}
}
}
val mapMarkerClusterItem = MapMarkerClusterItem(mapMarkerRecord)
clusterManager.addItem(mapMarkerClusterItem)
fun tryRequestData(lat : Double, lon : Double) {
val requestLimitInMs = 2000L
val newDate = Date()
if (latestRequestDate == null)
{
innerRequestData(lat, lon)
}
else {
if (!requestScheduled) {
requestScheduled = true
val timeDiffMs = newDate.time - latestRequestDate!!.time
if (timeDiffMs > requestLimitInMs) {
innerRequestData(lat, lon)
} else {
handler.postDelayed({ innerRequestData(lat, lon) }, requestLimitInMs - timeDiffMs)
markerMap[key] = mapMarkerClusterItem
}
}
}
}
fun innerRequestData(lat : Double, lon : Double)
{
val radius = 2000
latestRequestDate = Date()
dataProvider.requestData(lat, lon, radius)
requestScheduled = false
}
private fun setUpClusterer(googleMap: GoogleMap) {
@ -135,13 +100,77 @@ class YelpMapActivity : MapsActivity(), GoogleMap.OnInfoWindowClickListener
googleMap.setOnCameraIdleListener(mClusterManager)
googleMap.setOnMarkerClickListener(mClusterManager)
googleMap.setInfoWindowAdapter(mClusterManager?.markerManager)
yelpInfoWindowProvider = YelpInfoWindowProvider(this)
mClusterManager?.markerCollection?.setOnInfoWindowAdapter(yelpInfoWindowProvider)
//mClusterManager?.markerCollection?.setOnInfoWindowClickListener(this)
//mClusterManager?.setOnClusterItemInfoWindowClickListener(this)
mClusterManager?.setOnClusterItemClickListener(this)
}
override fun onInfoWindowClick(marker: Marker) {
val detailFragment = DetailFragment()
override fun onInfoWindowClick(item: Marker?) {
supportFragmentManager.beginTransaction().add(R.id.container, detailFragment).addToBackStack("detailFragment").commit()
if (lastClickedMapMarker != null)
{
val detailFragment = DetailFragment()
val bundle = Bundle()
bundle.putSerializable("mapMarkerRecord", lastClickedMapMarker!!.mapMarkerRecord)
detailFragment.arguments = bundle
supportFragmentManager.beginTransaction().add(R.id.container, detailFragment, "detailFragment").addToBackStack("detailFragment").commit()
}
}
override fun onClusterItemInfoWindowClick(item: MapMarkerClusterItem?) {
if (item != null) {
val detailFragment = DetailFragment()
val bundle = Bundle()
bundle.putSerializable("mapMarkerRecord", item.mapMarkerRecord)
detailFragment.arguments = bundle
supportFragmentManager.beginTransaction().add(R.id.container, detailFragment, "detailFragment").addToBackStack("detailFragment").commit()
}
}
override fun onClusterItemClick(item: MapMarkerClusterItem): Boolean {
// Does nothing, but you could go into the user's profile page, for example.
lastClickedMapMarker = item
return false
}
fun handleUpdateBusinessDetail(businessDetailRecord : BusinessDetailRecord)
{
val detailFragment = supportFragmentManager.findFragmentByTag("detailFragment") as? DetailFragment
detailFragment?.updateBusinessDetail(businessDetailRecord)
}
fun handleUpdateReviewList(reviewListRecordPair : Pair<String, ReviewListRecord>)
{
val detailFragment = supportFragmentManager.findFragmentByTag("detailFragment") as? DetailFragment
detailFragment?.updateReviewList(reviewListRecordPair)
}

View File

@ -0,0 +1,47 @@
package fishrungames.yelpmapapp.asyncTasks
import android.os.AsyncTask
import com.google.gson.JsonObject
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import fishrungames.yelpmapapp.records.BusinessDetailRecord
import fishrungames.yelpmapapp.records.MapMarkerRecord
/**
* Created by mephi on 10.06.2017.
*/
class HandleBusinessDetailResponseAsyncTask(val onUpdateBusinessDetail : ((BusinessDetailRecord?) -> Unit)) : AsyncTask<JsonObject, Int, BusinessDetailRecord?>()
{
override fun doInBackground(vararg response : JsonObject): BusinessDetailRecord? {
var result : BusinessDetailRecord? = null
try {
val recordType = object : TypeToken<BusinessDetailRecord?>() {}.type
result = Gson().fromJson<BusinessDetailRecord?>(response[0], recordType)
}
catch (e : Exception)
{
e.printStackTrace()
}
return result
}
override fun onPostExecute(result: BusinessDetailRecord?) {
super.onPostExecute(result)
onUpdateBusinessDetail(result)
}
}

View File

@ -1,9 +1,10 @@
package fishrungames.yelpmapapp
package fishrungames.yelpmapapp.asyncTasks
import android.os.AsyncTask
import com.google.gson.JsonObject
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import fishrungames.yelpmapapp.records.MapMarkerRecord
/**
@ -11,7 +12,7 @@ import com.google.gson.reflect.TypeToken
*/
class HandleResponseAsyncTask(val onUpdateMapMarkers : ((Map<String, MapMarkerRecord>) -> Unit)) : AsyncTask<JsonObject, Int, Map<String, MapMarkerRecord>>()
class HandleMapMarkersResponseAsyncTask(val onUpdateMapMarkers : ((Map<String, MapMarkerRecord>) -> Unit)) : AsyncTask<JsonObject, Int, Map<String, MapMarkerRecord>>()
{
@ -27,8 +28,10 @@ class HandleResponseAsyncTask(val onUpdateMapMarkers : ((Map<String, MapMarkerRe
val mapMarkerRecord = Gson().fromJson<MapMarkerRecord>(businessElement, mapMarkerRecordType)
newMapMarkers[mapMarkerRecord.name] = mapMarkerRecord
if (mapMarkerRecord.id != null) {
newMapMarkers[mapMarkerRecord.id] = mapMarkerRecord
}
}
}
@ -42,6 +45,7 @@ class HandleResponseAsyncTask(val onUpdateMapMarkers : ((Map<String, MapMarkerRe
}
override fun onPostExecute(result: Map<String, MapMarkerRecord>) {
super.onPostExecute(result)
onUpdateMapMarkers(result)

View File

@ -0,0 +1,53 @@
package fishrungames.yelpmapapp.asyncTasks
import android.os.AsyncTask
import com.google.gson.JsonObject
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import fishrungames.yelpmapapp.records.BusinessDetailRecord
import fishrungames.yelpmapapp.records.MapMarkerRecord
import fishrungames.yelpmapapp.records.ReviewListRecord
/**
* Created by mephi on 10.06.2017.
*/
class HandleReviewListResponseAsyncTask(val id: String, val onUpdateReviewList : ((Pair<String, ReviewListRecord>?) -> Unit)) : AsyncTask<JsonObject, Int, Pair<String, ReviewListRecord>?>()
{
override fun doInBackground(vararg response : JsonObject): Pair<String, ReviewListRecord>? {
var resultPair : Pair<String, ReviewListRecord>? = null
try {
val recordType = object : TypeToken<BusinessDetailRecord?>() {}.type
val result = Gson().fromJson<ReviewListRecord?>(response[0], recordType)
if (result != null)
{
resultPair = Pair<String, ReviewListRecord>(id, result);
}
}
catch (e : Exception)
{
e.printStackTrace()
}
return resultPair
}
override fun onPostExecute(result: Pair<String, ReviewListRecord>?) {
super.onPostExecute(result)
onUpdateReviewList(result)
}
}

View File

@ -1,4 +1,4 @@
package fishrungames.yelpmapapp
package fishrungames.yelpmapapp.google
import android.Manifest
import android.content.pm.PackageManager
@ -25,7 +25,7 @@ import android.support.v4.app.ActivityCompat
import android.content.DialogInterface
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import fishrungames.yelpmapapp.R
open class MapsActivity : AppCompatActivity(), OnMapReadyCallback, LocationListener,
@ -46,10 +46,6 @@ open class MapsActivity : AppCompatActivity(), OnMapReadyCallback, LocationListe
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
//val mapFragment = SupportMapFragment()
//supportFragmentManager.beginTransaction().add(R.id.container, mapFragment).commit()
mapFragment.getMapAsync(this)
}

View File

@ -0,0 +1,23 @@
package fishrungames.yelpmapapp.records
/**
* Created by mephi on 10.06.2017.
*/
data class BusinessDetailRecord(
val id: String?,
val name: String?,
val image_url: String?,
val is_claimed : Boolean?,
val is_closed : Boolean?,
val url : String?,
val phone : String?,
val display_phone : String?,
val review_count : Int?,
val categories : List<CategoryRecord>?,
val rating : Double?,
val location : LocationRecord?,
val coordinates: CoordinatesRecord?,
val photos : List<String>?
)

View File

@ -0,0 +1,8 @@
package fishrungames.yelpmapapp.records
/**
* Created by mephi on 10.06.2017.
*/
data class CategoryRecord(val alias: String?,
val title: String?)

View File

@ -0,0 +1,8 @@
package fishrungames.yelpmapapp.records
/**
* Created by mephi on 10.06.2017.
*/
data class CoordinatesRecord(val latitude: Double?,
val longitude: Double?)

View File

@ -0,0 +1,17 @@
package fishrungames.yelpmapapp.records
/**
* Created by mephi on 10.06.2017.
*/
data class LocationRecord(
val address1: String?,
val address2: String?,
val address3: String?,
val city: String?,
val zip_code: String?,
val country: String?,
val state: String?,
val display_address: List<String>?,
val cross_streets: String?
)

View File

@ -0,0 +1,18 @@
package fishrungames.yelpmapapp.records
import java.io.Serializable
import com.google.gson.annotations.SerializedName
/**
* Created by mephi on 09.06.2017.
*/
data class MapMarkerRecord (
@SerializedName("id") val id: String?,
@SerializedName("name") val name: String?,
@SerializedName("image_url") val image_url: String?,
@SerializedName("coordinates") val coordinates: CoordinatesRecord?
) : Serializable

View File

@ -0,0 +1,9 @@
package fishrungames.yelpmapapp.records
/**
* Created by mephi on 10.06.2017.
*/
data class ReviewListRecord(
val reviews: List<ReviewRecord>?,
val total: Int?)

View File

@ -0,0 +1,12 @@
package fishrungames.yelpmapapp.records
/**
* Created by mephi on 10.06.2017.
*/
data class ReviewRecord(
val rating: Double?,
val user: ReviewUserRecord?,
val text: String?,
val time_created: String?,
val url: String?)

View File

@ -0,0 +1,9 @@
package fishrungames.yelpmapapp.records
/**
* Created by mephi on 10.06.2017.
*/
data class ReviewUserRecord(
val image_url: String?,
val name: String?)

View File

@ -48,20 +48,11 @@
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:lineSpacingExtra="8dp"
android:text="La la la la la la"
android:padding="12dp"
/>
</android.support.v4.widget.NestedScrollView>
android:scrollbars="none"
android:id="@+id/detailRecyclerView"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Address:"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"/>
<TextView
android:id="@+id/addressTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="123 Main st."
android:textAppearance="@style/TextAppearance.AppCompat.Large"/>
</LinearLayout>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Phone:"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"/>
<TextView
android:id="@+id/phoneTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="15000929180"
android:textAppearance="@style/TextAppearance.AppCompat.Large"/>
</LinearLayout>