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