diff --git a/app/build.gradle b/app/build.gradle index c47e5baa..a4990263 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -58,6 +58,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" implementation "org.jetbrains.anko:anko-commons:$anko_version" + implementation 'androidx.core:core-ktx:0.1' // Android support libraries implementation "com.android.support:support-v13:$support_version" diff --git a/app/src/main/java/com/bubelov/coins/repository/placeicon/PlaceIconsRepository.kt b/app/src/main/java/com/bubelov/coins/repository/placeicon/PlaceIconsRepository.kt index 172a566a..ac0349ac 100644 --- a/app/src/main/java/com/bubelov/coins/repository/placeicon/PlaceIconsRepository.kt +++ b/app/src/main/java/com/bubelov/coins/repository/placeicon/PlaceIconsRepository.kt @@ -1,3 +1,30 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + package com.bubelov.coins.repository.placeicon import android.content.Context @@ -13,10 +40,7 @@ import android.support.annotation.DrawableRes import android.support.graphics.drawable.VectorDrawableCompat import android.graphics.drawable.VectorDrawable import android.support.v4.content.ContextCompat - -/** - * @author Igor Bubelov - */ +import androidx.graphics.drawable.toBitmap @Singleton class PlaceIconsRepository @Inject constructor( @@ -35,7 +59,12 @@ class PlaceIconsRepository @Inject constructor( return marker } - fun getPlaceCategoryIconResId(category: String): Int? { + fun getPlaceIcon(category: String): Bitmap { + val iconId = getPlaceCategoryIconResId(category) ?: R.drawable.ic_place + return ContextCompat.getDrawable(context, iconId)!!.toBitmap() + } + + private fun getPlaceCategoryIconResId(category: String): Int? { return when (category.toLowerCase()) { "atm" -> R.drawable.ic_atm "restaurant" -> R.drawable.ic_restaurant diff --git a/app/src/main/java/com/bubelov/coins/ui/adapter/PlacesSearchResultsAdapter.kt b/app/src/main/java/com/bubelov/coins/ui/adapter/PlacesSearchResultsAdapter.kt index c349f3ba..40dec041 100644 --- a/app/src/main/java/com/bubelov/coins/ui/adapter/PlacesSearchResultsAdapter.kt +++ b/app/src/main/java/com/bubelov/coins/ui/adapter/PlacesSearchResultsAdapter.kt @@ -33,14 +33,13 @@ import android.view.View import android.view.ViewGroup import com.bubelov.coins.R -import com.bubelov.coins.ui.model.PlacesSearchResult +import com.bubelov.coins.ui.model.PlacesSearchRow import kotlinx.android.synthetic.main.row_places_search_result.view.* -import java.text.NumberFormat class PlacesSearchResultsAdapter( - private val items: List, - private val itemClick: (PlacesSearchResult) -> Unit + private val items: List, + private val itemClick: (PlacesSearchRow) -> Unit ) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { @@ -54,34 +53,20 @@ class PlacesSearchResultsAdapter( } override fun onBindViewHolder(holder: ViewHolder, position: Int) { - val item = items[position] - - holder.itemView.apply { - icon.setImageResource(item.iconResId) - name.text = item.placeName - - if (item.distance != null) { - distance.visibility = android.view.View.VISIBLE - - distance.text = resources.getString( - R.string.distance_format, - DISTANCE_FORMAT.format(item.distance), - item.distanceUnits - ) - } else { - distance.visibility = android.view.View.GONE - } - - setOnClickListener { itemClick(item) } - } + holder.bind(items[position], itemClick) } override fun getItemCount() = items.size - class ViewHolder(view: View) : RecyclerView.ViewHolder(view) - - companion object { - private val DISTANCE_FORMAT = - NumberFormat.getNumberInstance().apply { maximumFractionDigits = 1 } + class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { + fun bind(item: PlacesSearchRow, itemClick: (PlacesSearchRow) -> Unit) { + itemView.apply { + icon.setImageBitmap(item.icon) + name.text = item.name + distance.visibility = if (item.distance.isNotEmpty()) View.VISIBLE else View.GONE + distance.text = item.distance + setOnClickListener { itemClick(item) } + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/bubelov/coins/ui/model/PlaceMarker.kt b/app/src/main/java/com/bubelov/coins/ui/model/PlaceMarker.kt index 1170476e..3eed8c16 100644 --- a/app/src/main/java/com/bubelov/coins/ui/model/PlaceMarker.kt +++ b/app/src/main/java/com/bubelov/coins/ui/model/PlaceMarker.kt @@ -1,13 +1,36 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + package com.bubelov.coins.ui.model import com.google.android.gms.maps.model.BitmapDescriptor import com.google.android.gms.maps.model.LatLng import com.google.maps.android.clustering.ClusterItem -/** - * @author Igor Bubelov - */ - data class PlaceMarker internal constructor(val placeId: Long, val icon: BitmapDescriptor, val latitude: Double, val longitude: Double) : ClusterItem { override fun getPosition(): LatLng { return LatLng(latitude, longitude) diff --git a/app/src/main/java/com/bubelov/coins/ui/model/PlacesSearchResult.kt b/app/src/main/java/com/bubelov/coins/ui/model/PlacesSearchResult.kt deleted file mode 100644 index 8ad90249..00000000 --- a/app/src/main/java/com/bubelov/coins/ui/model/PlacesSearchResult.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.bubelov.coins.ui.model - -/** - * @author Igor Bubelov - */ - -data class PlacesSearchResult( - val placeId: Long, - val placeName: String, - val distance: Double?, - val distanceUnits: String?, - val iconResId: Int -) \ No newline at end of file diff --git a/app/src/main/java/com/bubelov/coins/ui/model/PlacesSearchRow.kt b/app/src/main/java/com/bubelov/coins/ui/model/PlacesSearchRow.kt new file mode 100644 index 00000000..350cf8ac --- /dev/null +++ b/app/src/main/java/com/bubelov/coins/ui/model/PlacesSearchRow.kt @@ -0,0 +1,37 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + +package com.bubelov.coins.ui.model + +import android.graphics.Bitmap + +data class PlacesSearchRow( + val placeId: Long, + val icon: Bitmap, + val name: String, + val distance: String +) \ No newline at end of file diff --git a/app/src/main/java/com/bubelov/coins/ui/viewmodel/PlacesSearchViewModel.kt b/app/src/main/java/com/bubelov/coins/ui/viewmodel/PlacesSearchViewModel.kt index d5ed67b7..5f84689e 100644 --- a/app/src/main/java/com/bubelov/coins/ui/viewmodel/PlacesSearchViewModel.kt +++ b/app/src/main/java/com/bubelov/coins/ui/viewmodel/PlacesSearchViewModel.kt @@ -34,15 +34,16 @@ import android.preference.PreferenceManager import com.bubelov.coins.App import com.bubelov.coins.R +import com.bubelov.coins.model.Place import com.bubelov.coins.repository.place.PlacesRepository import com.bubelov.coins.repository.placeicon.PlaceIconsRepository -import com.bubelov.coins.ui.model.PlacesSearchResult +import com.bubelov.coins.ui.model.PlacesSearchRow import com.bubelov.coins.util.* +import java.text.NumberFormat import javax.inject.Inject class PlacesSearchViewModel(app: Application) : AndroidViewModel(app) { @Inject lateinit var placesRepository: PlacesRepository - @Inject lateinit var placeIconsRepository: PlaceIconsRepository private var userLocation: Location? = null @@ -51,23 +52,19 @@ class PlacesSearchViewModel(app: Application) : AndroidViewModel(app) { val searchQuery = MutableLiveData() - val searchResults: LiveData> = Transformations.switchMap(searchQuery) { query -> - if (query.length < MIN_QUERY_LENGTH) { - MutableLiveData>().apply { value = emptyList() } - } else { - Transformations.map(placesRepository.getPlaces(query)) { - it.filter { it.currencies.contains(currency) }.map { place -> - PlacesSearchResult( - placeId = place.id, - placeName = place.name, - distance = userLocation?.distanceTo(place.latitude, place.longitude, getDistanceUnits()), - distanceUnits = getDistanceUnits().getShortName(), - iconResId = placeIconsRepository.getPlaceCategoryIconResId(place.category) ?: R.drawable.ic_place - ) - }.sortedBy { it.distance } + val searchResults: LiveData> = + Transformations.switchMap(searchQuery) { query -> + if (query.length < MIN_QUERY_LENGTH) { + MutableLiveData>().apply { value = emptyList() } + } else { + Transformations.map(placesRepository.getPlaces(query)) { places -> + places + .filter { it.currencies.contains(currency) } + .map { it.toRow() } + .sortedBy { it.distance } + } } } - } init { appComponent().inject(this) @@ -78,9 +75,32 @@ class PlacesSearchViewModel(app: Application) : AndroidViewModel(app) { this.currency = currency } + private fun Place.toRow(): PlacesSearchRow { + val userLocation = userLocation + + val distanceString = if (userLocation != null) DISTANCE_FORMAT.format( + userLocation.distanceTo( + latitude, + longitude, + getDistanceUnits() + ) + ) + " ${getDistanceUnits().getShortName()}" else "" + + return PlacesSearchRow( + placeId = id, + name = name, + distance = distanceString, + icon = placeIconsRepository.getPlaceIcon(category) + ) + } + private fun getDistanceUnits(): DistanceUnits { val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplication()) - val distanceUnitsString = sharedPreferences.getString(getApplication().getString(R.string.pref_distance_units_key), getApplication().getString(R.string.pref_distance_units_automatic)) + + val distanceUnitsString = sharedPreferences.getString( + getApplication().getString(R.string.pref_distance_units_key), + getApplication().getString(R.string.pref_distance_units_automatic) + ) return if (distanceUnitsString == getApplication().getString(R.string.pref_distance_units_automatic)) { DistanceUnits.default @@ -98,5 +118,8 @@ class PlacesSearchViewModel(app: Application) : AndroidViewModel(app) { companion object { private const val MIN_QUERY_LENGTH = 2 + + private val DISTANCE_FORMAT = + NumberFormat.getNumberInstance().apply { maximumFractionDigits = 1 } } } \ No newline at end of file