diff --git a/.idea/misc.xml b/.idea/misc.xml
index 9f0815d..4c54e75 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -6,10 +6,12 @@
-
+
+
+
diff --git a/app/build.gradle b/app/build.gradle
index 16d2f0b..eb330fc 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,6 +1,7 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
+ id 'kotlin-kapt'
}
android {
@@ -16,16 +17,13 @@ android {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
- buildFeatures {
- viewBinding = true
- }
-
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
@@ -41,21 +39,32 @@ android {
}
}
buildFeatures {
- viewBinding true
+ dataBinding true
}
+
}
dependencies {
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
+
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.2'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.2'
+
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
+
implementation 'com.google.android.gms:play-services-basement:17.3.0'
implementation 'com.google.android.gms:play-services-maps:17.0.0'
+ // Retrofit with Moshi Converter
+ implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
+ // Moshi
+ implementation 'com.squareup.moshi:moshi-kotlin:1.13.0'
+ // Coil
+ implementation "io.coil-kt:coil:2.2.2"
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/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a9f6be1..01d4757 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,6 +3,8 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.example.assignment">
+
+
-
@@ -26,7 +28,7 @@
diff --git a/app/src/main/java/com/example/assignment/BindingAdapters.kt b/app/src/main/java/com/example/assignment/BindingAdapters.kt
new file mode 100644
index 0000000..2895231
--- /dev/null
+++ b/app/src/main/java/com/example/assignment/BindingAdapters.kt
@@ -0,0 +1,52 @@
+package com.example.assignment
+
+import android.provider.Settings.Global.getString
+import android.util.Log
+import android.widget.TextView
+import androidx.databinding.BindingAdapter
+import androidx.recyclerview.widget.RecyclerView
+import com.example.assignment.adapter.MeteorsListAdapter
+import com.example.assignment.model.MeteorData
+import java.text.SimpleDateFormat
+import java.util.*
+
+
+/**
+ * Updates the data shown in the [RecyclerView].
+ */
+@BindingAdapter("listData")
+fun bindRecyclerView(recyclerView: RecyclerView, data: MutableList?) {
+ val adapter = recyclerView.adapter as MeteorsListAdapter
+ if (data != null) {
+ adapter.submitList(data)
+ Log.d("Binding", data.toString())
+ adapter.notifyDataSetChanged();
+ }
+}
+
+/**
+ * Transform mass attribute from Double to String with kg.
+ */
+@BindingAdapter("app:massText")
+fun massText(view: TextView, mass: Double) {
+ view.text = String.format("%.1f", mass) + R.string.main_mass_unit
+}
+
+/**
+ * Transform date format.
+ */
+@BindingAdapter("app:dateText")
+fun dateText(view: TextView, text: String) {
+ val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
+ val date: Date = format.parse(text)
+ view.text = date.toString()
+}
+
+/**
+ * Combine reclat and reclong together
+ */
+@BindingAdapter("app:locationText")
+fun locationText(view: TextView, meteor: MeteorData) {
+ view.text ='[' + meteor.reclat.toString() + ',' + meteor.reclong.toString() + ']'
+}
+
diff --git a/app/src/main/java/com/example/assignment/adapter/MeteorsListAdapter.kt b/app/src/main/java/com/example/assignment/adapter/MeteorsListAdapter.kt
index b100220..d830fe5 100644
--- a/app/src/main/java/com/example/assignment/adapter/MeteorsListAdapter.kt
+++ b/app/src/main/java/com/example/assignment/adapter/MeteorsListAdapter.kt
@@ -1,124 +1,56 @@
package com.example.assignment.adapter
import android.content.Context
-import android.util.Log
import android.view.LayoutInflater
-import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
-import com.example.assignment.R
import com.example.assignment.databinding.ItemMeteoriteBinding
import com.example.assignment.model.MeteorData
-import com.google.gson.Gson
-import java.io.IOException
-import java.io.InputStream
class MeteorsListAdapter(
+ meteorList: List,
context: Context,
recyclerItemClickListener: RecyclerItemClickListener
) : RecyclerView.Adapter() {
private val TAG: String = this.javaClass.name
- var meteorDataList: MutableList
- var context: Context
- var recyclerItemClickListener: RecyclerItemClickListener
- init {
- this.context = context
- meteorDataList = parseJsonToObject(context) as MutableList
- Log.d(TAG, meteorDataList.toString())
- this.recyclerItemClickListener = recyclerItemClickListener
- }
-
- override fun onCreateViewHolder(
- parent: ViewGroup,
- viewType: Int
- ): MeteorsViewHolder {
- Log.d(TAG, "onCreateViewHolder called!!")
- val li = LayoutInflater.from(context)
- return MeteorsViewHolder(ItemMeteoriteBinding.inflate(li))
- }
+ var meteorDataList: List = listOf()
- override fun onBindViewHolder(
- holder: MeteorsViewHolder,
- position: Int
- ) {
- Log.d(TAG, "onBindViewHolder bind position:$position")
- val meteorDataData: MeteorData = meteorDataList[position]
- holder.bind(meteorDataData)
- }
-
- override fun getItemCount(): Int {
- Log.d(TAG, "MeteorsListAdapter getItemCount=" + meteorDataList.size)
- return meteorDataList.size
+ interface RecyclerItemClickListener {
+ fun onRecyclerItemClick(meteorItem: MeteorData)
}
- private fun remove(item: MeteorData) {
- Log.d(TAG, "remove list item:$item")
- val pos = meteorDataList.indexOf(item)
- if (pos > -1) {
- meteorDataList.removeAt(pos)
- notifyItemRemoved(pos)
+ class MeteorsViewHolder private constructor(private var binding: ItemMeteoriteBinding): RecyclerView.ViewHolder(binding.root) {
+ fun bind(meteorData: MeteorData) {
+ binding.meteor = meteorData
+ binding.executePendingBindings()
}
- }
-
- private fun getItem(position: Int): MeteorData {
- return meteorDataList[position]
- }
- fun clear() {
- Log.d(TAG, "clear Recycler view.")
- while (itemCount > 0) {
- remove(getItem(0))
+ companion object {
+ fun from(parent: ViewGroup): MeteorsViewHolder {
+ val layoutInflater = LayoutInflater.from(parent.context)
+ val binding = ItemMeteoriteBinding.inflate(layoutInflater, parent, false)
+ return MeteorsViewHolder(binding)
+ }
}
}
- interface RecyclerItemClickListener {
- fun onRecyclerItemClick(meteorItem: MeteorData?)
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MeteorsViewHolder {
+ return MeteorsViewHolder.from(parent)
}
- inner class MeteorsViewHolder(itemBinding: ItemMeteoriteBinding) :
- RecyclerView.ViewHolder(itemBinding.getRoot()) {
- var itemMeteoriteBinding: ItemMeteoriteBinding
- fun bind(meteorDataData: MeteorData) {
- Log.d(TAG, "MeteorsViewHolder bind started")
- itemMeteoriteBinding.name.setText(meteorDataData.name)
- itemMeteoriteBinding.mass.setText(context.getString(R.string.main_mass, meteorDataData.mass))
- itemMeteoriteBinding.location.setText(meteorDataData.reclat.toString() + ", " + meteorDataData.reclong.toString())
- itemMeteoriteBinding.date.setText(meteorDataData.year?.substring(0, meteorDataData.year!!.indexOf("-")))
- }
-
- init {
- itemMeteoriteBinding = itemBinding
- itemBinding.getRoot().setOnClickListener(View.OnClickListener {
- Log.d(TAG,"MeteorsViewHolder clicked pos=" + meteorDataList[adapterPosition])
- recyclerItemClickListener.onRecyclerItemClick(meteorDataList[adapterPosition])
- })
- }
+ override fun onBindViewHolder(holder: MeteorsViewHolder, position: Int) {
+ val meteor: MeteorData = meteorDataList[position]
+ holder.bind(meteor)
}
- private fun loadJSONFromAsset(context: Context): String? {
- var json: String? = null
- json = try {
- val `is`: InputStream = context.assets.open("y77d-th95.json")
- val size: Int = `is`.available()
- val buffer = ByteArray(size)
- `is`.read(buffer)
- `is`.close()
- String(buffer)
- } catch (ex: IOException) {
- ex.printStackTrace()
- return null
- }
- return json
+ override fun getItemCount(): Int {
+ return meteorDataList.size
}
- private fun parseJsonToObject(context: Context): List {
- val jsonString: String? = loadJSONFromAsset(context)
- return Gson().fromJson(jsonString, Array::class.java).toList()
+ fun submitList(data: MutableList) {
+ meteorDataList = data
}
-
-
-
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/assignment/model/MeteorData.kt b/app/src/main/java/com/example/assignment/model/MeteorData.kt
index a4ff49c..fe1e88c 100644
--- a/app/src/main/java/com/example/assignment/model/MeteorData.kt
+++ b/app/src/main/java/com/example/assignment/model/MeteorData.kt
@@ -1,12 +1,13 @@
package com.example.assignment.model
+import com.squareup.moshi.Json
-open class MeteorData(){
- var id: String? = null
- var mass = 0.0
- var name: String? = null
- var reclat: String? = null
- var reclong: String? = null
- var year: String? = null
-}
\ No newline at end of file
+data class MeteorData(
+ @Json(name = "id") val id: String? = null,
+ @Json(name = "mass") val mass: Double = 0.0,
+ @Json(name = "name") val name: String? = null,
+ @Json(name = "reclat") val reclat: String? = null,
+ @Json(name = "reclong") val reclong: String? = null,
+ @Json(name = "year") val year: String? = null,
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/example/assignment/network/MeteorApiService.kt b/app/src/main/java/com/example/assignment/network/MeteorApiService.kt
new file mode 100644
index 0000000..5c0774a
--- /dev/null
+++ b/app/src/main/java/com/example/assignment/network/MeteorApiService.kt
@@ -0,0 +1,49 @@
+package com.example.assignment.network
+
+import com.example.assignment.model.MeteorData
+import com.squareup.moshi.Moshi
+import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
+import retrofit2.Retrofit
+import retrofit2.converter.moshi.MoshiConverterFactory
+import retrofit2.http.GET
+
+private const val BASE_URL = "https://data.nasa.gov/"
+
+/**
+ * Build the Moshi object that Retrofit will be using, making sure to add the Kotlin adapter for
+ * full Kotlin compatibility.
+ */
+private val moshi = Moshi.Builder()
+ .add(KotlinJsonAdapterFactory())
+ .build()
+
+/**
+ * Use the Retrofit builder to build a com.example.assignment.network.retrofit object using a Moshi converter with our Moshi
+ * object.
+ */
+private val retrofit = Retrofit.Builder()
+ .addConverterFactory(MoshiConverterFactory.create(moshi))
+ .baseUrl(BASE_URL)
+ .build()
+
+/**
+ * A public interface that exposes the [getMeteorsInfo] method
+ */
+interface MeteorsApiService {
+ /**
+ * Returns a [MutableList] of [MeteorData] and this method can be called from a Coroutine.
+ * The @GET annotation indicates that the "photos" endpoint will be requested with the GET
+ * HTTP method
+ */
+ @GET("resource/y77d-th95.json?\$where=year>='1900-01-01T00:00:00.000'")//&\$limit=15")
+ suspend fun getMeteorsInfo(): List
+}
+
+/**
+ * A public Api object that exposes the lazy-initialized Retrofit service
+ */
+object MeteorsApi {
+ val retrofitService: MeteorsApiService by lazy {
+ retrofit.create(MeteorsApiService::class.java)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/assignment/ui/MapActivity.kt b/app/src/main/java/com/example/assignment/ui/MapActivity.kt
deleted file mode 100644
index de540f4..0000000
--- a/app/src/main/java/com/example/assignment/ui/MapActivity.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.example.assignment.ui
-
-import android.os.Bundle
-import android.util.Log
-import android.view.MenuItem
-import androidx.appcompat.app.ActionBar
-import androidx.appcompat.app.AppCompatActivity
-import com.example.assignment.R
-import com.example.assignment.databinding.ActivityMapBinding
-import com.example.assignment.util.Constant
-import com.google.android.gms.maps.CameraUpdateFactory
-import com.google.android.gms.maps.GoogleMap
-import com.google.android.gms.maps.OnMapReadyCallback
-import com.google.android.gms.maps.SupportMapFragment
-import com.google.android.gms.maps.model.LatLng
-import com.google.android.gms.maps.model.MarkerOptions
-
-
-class MapActivity : AppCompatActivity(), OnMapReadyCallback {
- private var TAG: String? = null
- private var meteorName: String? = null
- private var lat = 0.0
- private var lng = 0.0
- var actionBar: ActionBar? = null
- var activityMapBinding: ActivityMapBinding? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- TAG = this.javaClass.name
- Log.d(TAG, "onCreate called")
- super.onCreate(savedInstanceState)
- activityMapBinding = ActivityMapBinding.inflate(getLayoutInflater())
- setContentView(activityMapBinding!!.getRoot())
- meteorName = intent.getStringExtra(Constant.Intent.METEORITE_NAME)
- lat = intent.getStringExtra(Constant.Intent.METEORITE_LAT)!!.toDouble()
- lng = intent.getStringExtra(Constant.Intent.METEORITE_LNG)!!.toDouble()
- val supportMapFragment =
- supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
- supportMapFragment!!.getMapAsync(this)
- actionBar = supportActionBar
- actionBar!!.setDisplayHomeAsUpEnabled(true)
- actionBar!!.setTitle(meteorName)
- }
-
- override fun onMapReady(googleMap: GoogleMap) {
- googleMap.mapType = GoogleMap.MAP_TYPE_HYBRID
- val latLng = LatLng(lat, lng)
- googleMap.addMarker(
- MarkerOptions()
- .position(latLng)
- .title(meteorName)
- )
- googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, Constant.Map.CAMERA_ZOOM))
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- onBackPressed()
- return true
- }
-}
diff --git a/app/src/main/java/com/example/assignment/ui/MainActivity.kt b/app/src/main/java/com/example/assignment/view/MainActivity.kt
similarity index 53%
rename from app/src/main/java/com/example/assignment/ui/MainActivity.kt
rename to app/src/main/java/com/example/assignment/view/MainActivity.kt
index 4b8cd61..19a56f5 100644
--- a/app/src/main/java/com/example/assignment/ui/MainActivity.kt
+++ b/app/src/main/java/com/example/assignment/view/MainActivity.kt
@@ -1,4 +1,4 @@
-package com.example.assignment.ui
+package com.example.assignment.view
import android.content.Context
import android.content.Intent
@@ -7,35 +7,45 @@ import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
+import android.widget.Toast
+import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
-import com.example.assignment.databinding.ActivityMainBinding
import com.example.assignment.R
import com.example.assignment.adapter.MeteorsListAdapter
+import com.example.assignment.databinding.ActivityMainBinding
import com.example.assignment.model.MeteorData
import com.example.assignment.util.Constant
+import com.example.assignment.viewModel.MainViewModel
-class MainActivity : AppCompatActivity(), MeteorsListAdapter.RecyclerItemClickListener {
+class MainActivity : AppCompatActivity(), MeteorsListAdapter.RecyclerItemClickListener{
private val TAG: String = this.javaClass.name
+ private val viewModel: MainViewModel by viewModels()
lateinit var meteorsListAdapter: MeteorsListAdapter
- lateinit var activityMainBinding: ActivityMainBinding
lateinit var context: Context
+ lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
this.context = getApplicationContext()
//get layout view
- activityMainBinding = ActivityMainBinding.inflate(getLayoutInflater())
- val view: View = activityMainBinding.getRoot()
+ binding = ActivityMainBinding.inflate(getLayoutInflater())
+
+ val view: View = binding.getRoot()
setContentView(view)
- val layoutManager: RecyclerView.LayoutManager = LinearLayoutManager(this)
- activityMainBinding.recycler.setLayoutManager(layoutManager)
+ binding.lifecycleOwner = this
+
+ binding.viewModel = viewModel
+ lifecycle.addObserver(viewModel)
- fillRecyclerViewData()
+ val layoutManager: RecyclerView.LayoutManager = LinearLayoutManager(this)
+ binding.recycler.layoutManager = layoutManager
+ meteorsListAdapter = MeteorsListAdapter(viewModel.meteors.value ?: emptyList(),this,this)
+ binding.recycler.adapter = meteorsListAdapter
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
@@ -43,19 +53,30 @@ class MainActivity : AppCompatActivity(), MeteorsListAdapter.RecyclerItemClickLi
return true
}
+ override fun onRecyclerItemClick(meteorItem: MeteorData) {
+ val mapActivityIntent = Intent(this, MapActivity::class.java)
+ mapActivityIntent.putExtra(Constant.Intent.METEORITE_NAME, meteorItem.name)
+ mapActivityIntent.putExtra(Constant.Intent.METEORITE_LAT, meteorItem.reclat)
+ mapActivityIntent.putExtra(Constant.Intent.METEORITE_LNG, meteorItem.reclong)
+ startActivity(mapActivityIntent)
+ }
- fun fillRecyclerViewData() {
- Log.d(TAG, "fillRecyclerViewData called!!")
- meteorsListAdapter = MeteorsListAdapter(this,this)
- activityMainBinding.recycler.setAdapter(meteorsListAdapter)
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
+ R.id.action_sort -> {
+ Log.d(TAG,"TODO")
+ }
+ R.id.action_refresh -> {
+ viewModel.refresh()
+ Toast.makeText(this, "List refreshed", Toast.LENGTH_SHORT).show()
+ }
+ }
+ return true
}
- override fun onRecyclerItemClick(meteorItem: MeteorData?) {
- Log.d(TAG, "onRecyclerItemClick called!!")
- val mapActivityIntent = Intent(this, MapActivity::class.java)
- mapActivityIntent.putExtra(Constant.Intent.METEORITE_NAME, meteorItem?.name)
- mapActivityIntent.putExtra(Constant.Intent.METEORITE_LAT, meteorItem?.reclat)
- mapActivityIntent.putExtra(Constant.Intent.METEORITE_LNG, meteorItem?.reclong)
- startActivity(mapActivityIntent)
+ override fun onDestroy(){
+ super.onDestroy()
+ binding.recycler.adapter = null
+ lifecycle.removeObserver(viewModel)
}
}
diff --git a/app/src/main/java/com/example/assignment/view/MapActivity.kt b/app/src/main/java/com/example/assignment/view/MapActivity.kt
new file mode 100644
index 0000000..f13520b
--- /dev/null
+++ b/app/src/main/java/com/example/assignment/view/MapActivity.kt
@@ -0,0 +1,58 @@
+package com.example.assignment.view
+
+import android.os.Bundle
+import android.util.Log
+import android.view.MenuItem
+import androidx.appcompat.app.ActionBar
+import androidx.appcompat.app.AppCompatActivity
+import com.example.assignment.R
+import com.example.assignment.util.Constant
+import com.google.android.gms.maps.CameraUpdateFactory
+import com.google.android.gms.maps.GoogleMap
+import com.google.android.gms.maps.OnMapReadyCallback
+import com.google.android.gms.maps.SupportMapFragment
+import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.MarkerOptions
+
+
+class MapActivity{
+// private var TAG: String? = null
+// private var meteorName: String? = null
+// private var lat = 0.0
+// private var lng = 0.0
+// var actionBar: ActionBar? = null
+// var activityMapBinding: ac? = null
+//
+// override fun onCreate(savedInstanceState: Bundle?) {
+// TAG = this.javaClass.name
+// Log.d(TAG, "onCreate called")
+// super.onCreate(savedInstanceState)
+// activityMapBinding = ActivityMapBinding.inflate(getLayoutInflater())
+// setContentView(activityMapBinding!!.getRoot())
+// meteorName = intent.getStringExtra(Constant.Intent.METEORITE_NAME)
+// lat = intent.getStringExtra(Constant.Intent.METEORITE_LAT)!!.toDouble()
+// lng = intent.getStringExtra(Constant.Intent.METEORITE_LNG)!!.toDouble()
+// val supportMapFragment =
+// supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
+// supportMapFragment!!.getMapAsync(this)
+// actionBar = supportActionBar
+// actionBar!!.setDisplayHomeAsUpEnabled(true)
+// actionBar!!.setTitle(meteorName)
+// }
+//
+// override fun onMapReady(googleMap: GoogleMap) {
+// googleMap.mapType = GoogleMap.MAP_TYPE_HYBRID
+// val latLng = LatLng(lat, lng)
+// googleMap.addMarker(
+// MarkerOptions()
+// .position(latLng)
+// .title(meteorName)
+// )
+// googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, Constant.Map.CAMERA_ZOOM))
+// }
+//
+// override fun onOptionsItemSelected(item: MenuItem): Boolean {
+// onBackPressed()
+// return true
+// }
+}
diff --git a/app/src/main/java/com/example/assignment/viewModel/MainViewModel.kt b/app/src/main/java/com/example/assignment/viewModel/MainViewModel.kt
new file mode 100644
index 0000000..a066d84
--- /dev/null
+++ b/app/src/main/java/com/example/assignment/viewModel/MainViewModel.kt
@@ -0,0 +1,52 @@
+package com.example.assignment.viewModel
+
+import android.content.Intent
+import android.util.Log
+import androidx.core.content.ContextCompat.startActivity
+import androidx.lifecycle.*
+import com.example.assignment.model.MeteorData
+import com.example.assignment.network.MeteorsApi
+import com.example.assignment.util.Constant
+import com.example.assignment.view.MainActivity
+import com.example.assignment.view.MapActivity
+import kotlinx.coroutines.launch
+import java.security.AccessController.getContext
+
+enum class MarsApiStatus { LOADING, ERROR, DONE }
+
+/**
+ * The [ViewModel] that is attached to the [MainActivity].
+ */
+class MainViewModel : ViewModel(), DefaultLifecycleObserver {
+
+ // Internally, we use a MutableLiveData, because we will be updating the List of MarsPhoto
+ // with new values
+ private val _meteors = MutableLiveData>()
+
+ // The external LiveData interface to the property is immutable, so only this class can modify
+ val meteors: LiveData> = _meteors
+
+ override fun onResume(owner: LifecycleOwner) {
+ getMeteorsInfo()
+ }
+
+ /**
+ * Gets Meteors photos information from the NASA's API Retrofit service and updates the
+ * [MeteorData] [List] [LiveData].
+ */
+ private fun getMeteorsInfo() {
+ viewModelScope.launch {
+ try {
+ _meteors.value = MeteorsApi.retrofitService.getMeteorsInfo()
+ } catch (e: Exception) {
+ _meteors.value = mutableListOf()
+ }
+ }
+ }
+
+ fun refresh(){
+ getMeteorsInfo()
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 3f7768f..593c898 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,23 +1,34 @@
-
+
-
+
+
+
+
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context=".view.MainActivity">
-
+ android:layout_height="wrap_content">
+
+
-
+
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_map.xml b/app/src/main/res/layout/activity_map.xml
index b544423..8ff8bbe 100644
--- a/app/src/main/res/layout/activity_map.xml
+++ b/app/src/main/res/layout/activity_map.xml
@@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".ui.MapActivity">
+ tools:context=".view.MapActivity">
-
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
-
+
+
+
+
+
+
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="4dp"
+ android:layout_marginTop="4dp"
+ android:layout_marginRight="4dp"
+ android:foreground="?attr/selectableItemBackground"
+ android:onClick="@{() -> itemClickListener.onRecyclerItemClick(meteor)}"
+ card_view:cardCornerRadius="2dp">
-
+ android:layout_height="103dp">
+ android:layout_width="106dp"
+ android:layout_height="21dp"
+ android:layout_marginStart="10dp"
+ android:layout_marginTop="5dp"
+ android:text="@{meteor.name}"
+ card_view:layout_constraintStart_toStartOf="parent"
+ card_view:layout_constraintTop_toTopOf="parent"
+ tools:text="Test name" />
+ app:massText="@{meteor.mass}"
+ card_view:layout_constraintEnd_toEndOf="parent"
+ card_view:layout_constraintTop_toTopOf="parent"
+ tools:text="32320kg" />
+ app:locationText="@{meteor}"
+ card_view:layout_constraintStart_toStartOf="parent"
+ card_view:layout_constraintTop_toBottomOf="@+id/name"
+ tools:text="[54.0000420, 22:005000]" />
-
-
-
-
-
-
-
+ app:dateText="@{meteor.year}"
+ card_view:layout_constraintEnd_toEndOf="parent"
+ card_view:layout_constraintHorizontal_bias="0.0"
+ card_view:layout_constraintStart_toStartOf="parent"
+ card_view:layout_constraintTop_toBottomOf="@+id/location"
+ tools:text="Tue Jan 01 00:00:00 GMT 1952" />
+
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c42b56c..c01d0b0 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -7,6 +7,7 @@
Cancel
Ascending
Descending
+ kg
No data available, sorting is disabled
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index ca2774f..cd21b0b 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -15,5 +15,6 @@
\ No newline at end of file