<file_sep>package ru.gorshkov.agrotask.features.map.repositories

import com.google.android.gms.maps.model.LatLng
import ru.gorshkov.agrotask.R
import ru.gorshkov.agrotask.data.pojo.AgroField
import ru.gorshkov.agrotask.utils.DateUtils
import java.util.*

class LocalFieldsRepositoryImpl constructor(private val dateUtils: DateUtils) : FieldsRepository {

    override fun getYears(): List<String> {
        return getFields()
            .map { dateUtils.getYear(it.dateEnd) }
            .distinct()
    }

    override fun onSearchChanged(text: String): List<AgroField> {
        return getFields()
            .filter { it.name.toLowerCase(Locale.getDefault()).contains(text) }
    }

    override fun onFilterSelected(year: String?): List<AgroField> {
        return if (year.isNullOrEmpty()) {
            getFields()
        } else {
            getFields()
                .filter { dateUtils.getYear(it.dateEnd).contains(year) }
        }
    }

    override fun getFields(): List<AgroField> {
        val fields = mutableListOf<AgroField>()
        fields.add(
            AgroField(
                310101001,
                130,
                "<NAME>",
                "Скипетр РС1",
                1429736400000,
                1442955600000,
                R.color.green_40,
                getFirstField()
            )
        )
        fields.add(
            AgroField(
                310101002,
                96,
                "Соя",
                "Кофу РС2",
                1431637200000,
                1444856400000,
                R.color.blue_40,
                getSecondField()
            )
        )
        fields.add(
            AgroField(
                310101003,
                212,
                "<NAME>",
                "Крокодил F1",
                1457557200000,
                1476046800000,
                R.color.red_40,
                getThirdField()
            )
        )
        fields.add(
            AgroField(
                310101004,
                96,
                "<NAME>",
                "Скипетр РС1",
                1459803600000,
                1478293200000,
                R.color.orange_40,
                getFourthField()
            )
        )
        fields.add(
            AgroField(
                310101005,
                110,
                "Кукуруза",
                "Скипетр РС3",
                1519851600000,
                1538341200000,
                R.color.yellow_40,
                getFifthField()
            )
        )
        fields.add(
            AgroField(
                310101006,
                300,
                "<NAME>",
                "Скипетр РС4",
                1526590800000,
                1542488400000,
                R.color.violin_40,
                getSixthField()
            )
        )
        fields.add(
            AgroField(
                310101007,
                50,
                "Лен",
                "Скипетр РС5",
                1521666000000,
                1537563600000,
                R.color.pink_40,
                getSeventhField()
            )
        )

        return fields
    }

    private fun getFirstField(): List<LatLng> {
        return listOf(
            LatLng(61.80384840739244, 39.29752572015718),
            LatLng(61.768789522352435, 39.41562874750093),
            LatLng(61.834978305380716, 39.44309456781343),
            LatLng(61.904905227594, 39.36069710687593),
            LatLng(61.891967838990254, 39.17942269281343)
        )
    }

    private fun getSecondField(): List<LatLng> {
        return listOf(
            LatLng(61.79735903774938, 39.51450570062593),
            LatLng(61.742794189868945, 39.53098519281343),
            LatLng(61.742794189868945, 39.76169808343843),
            LatLng(61.81941730253335, 39.74521859125093)
        )
    }

    private fun getThirdField(): List<LatLng> {
        return listOf(
            LatLng(62.03011428809841, 39.61338265375093),
            LatLng(62.00820756072283, 39.77543099359468),
            LatLng(61.96047369035458, 39.73697884515718),
            LatLng(61.98241475021735, 39.53647835687593),
            LatLng(62.0378423106961, 39.50351937250093)
        )
    }

    private fun getFourthField(): List<LatLng> {
        return listOf(
            LatLng(61.86996172037123, 39.77817757562593),
            LatLng(61.84923562726734, 39.90177376703218),
            LatLng(61.91783714634502, 39.91276009515718)
        )
    }

    private fun getFifthField(): List<LatLng> {
        return listOf(
            LatLng(61.75319495756062, 39.92099984125093),
            LatLng(61.828495513144205, 39.98417122796968),
            LatLng(61.81941730253335, 40.12424691156343),
            LatLng(61.755794600533115, 40.23136361078218),
            LatLng(61.72588544747111, 40.14621956781343)
        )
    }

    private fun getSixthField(): List<LatLng> {
        return listOf(
            LatLng(62.05972771569589, 39.95945198968843),
            LatLng(61.97725356777783, 39.96769173578218),
            LatLng(62.00691843868552, 40.28080208734468),
            LatLng(62.08031135584757, 40.14621956781343),
            LatLng(62.07645298575181, 39.99241097406343)
        )
    }

    private fun getSeventhField(): List<LatLng> {
        return listOf(
            LatLng(61.91913003744191, 39.51175911859468),
            LatLng(61.88808555554062, 39.53373177484468),
            LatLng(61.85830501784389, 39.62711556390718),
            LatLng(61.90878537747861, 39.61612923578218),
            LatLng(61.92947119786394, 39.58042366937593)
        )
    }
}<file_sep>package ru.gorshkov.agrotask.features.map.repositories

import ru.gorshkov.agrotask.data.pojo.AgroField


interface FieldsRepository {
    fun getFields(): List<AgroField>

    fun onSearchChanged(text: String): List<AgroField>

    fun onFilterSelected(year: String?): List<AgroField>

    fun getYears() : List<String>
}<file_sep>package ru.gorshkov.agrotask

import android.app.Application
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin
import ru.gorshkov.agrotask.di.appModule
import ru.gorshkov.agrotask.di.mapModule

class AgroApp : Application() {
    override fun onCreate() {
        super.onCreate()

        startKoin {
            androidContext(this@AgroApp)
            modules(listOf(appModule, mapModule))
        }
    }
}<file_sep>package ru.gorshkov.agrotask.features.filter.recycler

import android.view.View
import kotlinx.android.synthetic.main.holder_filter.view.*
import ru.gorshkov.agrotask.base.adapter.BaseViewHolder


class FilterHolder(private val view: View) : BaseViewHolder<String>(view) {
    override fun bind(item: String) {
        view.filter_item.text = item
    }
}<file_sep>package ru.gorshkov.agrotask.base.adapter

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView

abstract class BaseAdapter<Item, Holder : BaseViewHolder<Item>> constructor() : RecyclerView.Adapter<Holder>() {
    constructor(items: List<Item>) : this() {
        this.items = items
    }

    protected var items: List<Item> = listOf()
    var onClickListener: AdapterClickListener<Item>? = null

    override fun onCreateViewHolder(
        viewGroup: ViewGroup, layoutId: Int
    ): Holder {
        val holder = item(
            LayoutInflater.from(viewGroup.context).inflate(layoutId, viewGroup, false)
        )
        holder.itemView.setOnClickListener {
            onClickListener?.onClick(it.tag as Item)
        }
        return holder
    }

    abstract fun item(itemView: View): Holder

    override fun getItemCount(): Int = items.size

    override fun onBindViewHolder(holder: Holder, position: Int) {
        val item = items[position]
        holder.bind(item)
        holder.itemView.tag = item
    }
}<file_sep>package ru.gorshkov.agrotask.features.filter.recycler

import android.view.View
import ru.gorshkov.agrotask.R
import ru.gorshkov.agrotask.base.adapter.BaseAdapter


class FilterAdapter(items : List<String>) : BaseAdapter<String, FilterHolder>(items) {

    override fun item(itemView: View) = FilterHolder(itemView)

    override fun getItemViewType(position: Int) = R.layout.holder_filter

}<file_sep>package ru.gorshkov.agrotask.di

import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
import ru.gorshkov.agrotask.features.map.MapViewModel
import ru.gorshkov.agrotask.features.map.interactors.FieldsInteractor
import ru.gorshkov.agrotask.features.map.repositories.FieldsRepository
import ru.gorshkov.agrotask.features.map.repositories.LocalFieldsRepositoryImpl
import ru.gorshkov.agrotask.utils.DateUtils
import ru.gorshkov.agrotask.utils.MapUtils

val mapModule = module {
    viewModel { MapViewModel(get()) }
    single { FieldsInteractor(get()) }
    single { LocalFieldsRepositoryImpl(get()) as FieldsRepository }
}

val appModule = module {
    single { DateUtils() }
    single { MapUtils(androidContext()) }
}<file_sep>package ru.gorshkov.agrotask.data.pojo

import androidx.annotation.ColorRes
import com.google.android.gms.maps.model.LatLng


data class AgroField(
    val id: Long = 0L,
    val size: Int = 0,
    val name: String = "",
    val description: String = "",
    val dateStart: Long = 0L,
    val dateEnd: Long = 0L,
    @ColorRes
    val color: Int = 0,
    var polygon: List<LatLng>
)<file_sep>apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

apply from: 'dependencies.gradle'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "ru.gorshkov.agrotask"
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        resValue "string", "google_maps_key", (project.findProperty("GOOGLE_MAPS_API_KEY") ?: "")
    }
    repositories {
        maven { url "http://maven.google.com/" }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}
<file_sep>package ru.gorshkov.agrotask.base.adapter


interface AdapterClickListener<T> {
    fun onClick(item : T)
}<file_sep>package ru.gorshkov.agrotask.features.map.interactors

import ru.gorshkov.agrotask.features.map.repositories.FieldsRepository


class FieldsInteractor(private val fieldsRepository: FieldsRepository) {
    fun getFields() = fieldsRepository.getFields()

    fun searchItems(text: String) = fieldsRepository.onSearchChanged(text)

    fun filterItems(year: String?) = fieldsRepository.onFilterSelected(year)

    fun getYears() = fieldsRepository.getYears()
}<file_sep>ext {
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])

        //Kotlin
        implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

        //Android
        implementation "androidx.appcompat:appcompat:$appcompat_version"
        implementation "com.google.android.material:material:$material_version"
        implementation "androidx.core:core-ktx:$appcompat_version"
        implementation "androidx.constraintlayout:constraintlayout:$constraint_version"
        implementation "androidx.fragment:fragment-ktx:$fragment_version"

        //ViewModel and LiveData
        implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"

        //Logging
        implementation "com.github.ajalt:timberkt:$timberkt_version"

        //Glide
        implementation "com.github.bumptech.glide:glide:$glide_version"
        kapt "com.github.bumptech.glide:compiler:$glide_version"

        //Google services
        implementation "com.google.android.gms:play-services-maps:$map_version"

        //Koin
        implementation "org.koin:koin-core:$koin_version"
        implementation "org.koin:koin-android:$koin_version"
        implementation "org.koin:koin-androidx-viewmodel:$koin_version"

        //Permissions
        implementation "pub.devrel:easypermissions:$permission_version"

    }
}<file_sep>package ru.gorshkov.agrotask.features.map.recycler

import android.view.View
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.google.android.gms.maps.model.Polygon
import ru.gorshkov.agrotask.R
import ru.gorshkov.agrotask.base.adapter.BaseAdapter
import ru.gorshkov.agrotask.data.pojo.AgroField
import ru.gorshkov.agrotask.utils.DateUtils


class AgroFieldAdapter(private val dateUtils: DateUtils) :
    BaseAdapter<AgroField, AgroFieldHolder>() {

    private var selectedPosition = RecyclerView.NO_POSITION

    override fun item(itemView: View) = AgroFieldHolder(itemView, dateUtils)

    override fun getItemViewType(position: Int) = R.layout.holder_fields

    fun update(newItems: List<AgroField>) {
        val diffResult = DiffUtil.calculateDiff(AgroFieldCallback(this.items, newItems))
        this.items = newItems
        diffResult.dispatchUpdatesTo(this)
    }

    override fun onBindViewHolder(holder: AgroFieldHolder, position: Int) {
        super.onBindViewHolder(holder, position)
        holder.setSelected(position == selectedPosition)
    }

    fun getFieldItem(polygon: Polygon): AgroField? {
        val code = polygon.points[0]

        for (item in items) {
            if (code == item.polygon[0])
                return item
        }
        return null
    }

    fun getPosition(field: AgroField?) = items.indexOf(field)

    fun selectItem(field: AgroField?) {
        val position = items.indexOf(field)
        if (selectedPosition != RecyclerView.NO_POSITION) {
            notifyItemChanged(selectedPosition)
        }

        selectedPosition = position
        notifyItemChanged(selectedPosition)
    }
}<file_sep>// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    ext {
        kotlin_version = '1.3.61'
        appcompat_version = '1.1.0'
        material_version = '1.2.0-alpha02'
        constraint_version = '2.0.0-beta3'
        fragment_version = '1.1.0'
        lifecycle_version = '2.1.0'
        timberkt_version = '1.5.1'
        map_version = '17.0.0'
        glide_version = '4.9.0'
        koin_version = '2.0.1'
        permission_version = '3.0.0'
    }
    repositories {
        google()
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        maven { url "http://jitpack.io/" }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
<file_sep>package ru.gorshkov.agrotask.features.map

import android.Manifest
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.RelativeLayout
import android.widget.Toast
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator
import com.github.ajalt.timberkt.Timber
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE
import com.google.android.gms.maps.MapsInitializer
import kotlinx.android.synthetic.main.fragment_map.*
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
import pub.devrel.easypermissions.EasyPermissions
import ru.gorshkov.agrotask.R
import ru.gorshkov.agrotask.base.adapter.AdapterClickListener
import ru.gorshkov.agrotask.base.fragment.BaseFragment
import ru.gorshkov.agrotask.data.pojo.AgroField
import ru.gorshkov.agrotask.features.filter.FilterDialog
import ru.gorshkov.agrotask.features.map.recycler.AgroFieldAdapter
import ru.gorshkov.agrotask.utils.DateUtils
import ru.gorshkov.agrotask.utils.MapUtils

class MapFragment : BaseFragment(), EasyPermissions.PermissionCallbacks {
    private var googleMap: GoogleMap? = null
    private var adapter: AgroFieldAdapter? = null

    private val mapViewModel: MapViewModel by viewModel()
    private val dateUtils: DateUtils by inject()
    private val mapUtils: MapUtils by inject()

    override val layoutRes = R.layout.fragment_map

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mapViewModel.fieldsUpdateLiveData.observe(this, Observer {
            googleMap?.clear()
            if (it.isNullOrEmpty()) {
                fields_recycler.visibility = View.INVISIBLE
                return@Observer
            }
            fields_recycler.visibility = View.VISIBLE
            (fields_recycler.adapter as AgroFieldAdapter).update(it)

            for (field in it) {
                googleMap?.addPolygon(mapUtils.getFieldPolygon(field))
            }
            mapUtils.moveCamera(googleMap, it[0].polygon, it[0].name)
        })

        mapViewModel.filterLiveData.observe(this, Observer {
            showFilterDialog(it)
        })
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        map_view.onCreate(savedInstanceState)
        MapsInitializer.initialize(activity)

        requestPermissions()
        initAdapter()
        initRecycler()

        search_edit_text.addTextChangedListener {
            mapViewModel.onSearchChanged(it.toString())
        }

        filter_button.setOnClickListener {
            mapViewModel.onFilterClicked()
        }
    }

    private fun getMap() {
        map_view.getMapAsync { googleMap ->
            initMap(googleMap)
            mapViewModel.start()
        }
    }

    private fun requestPermissions() {
        if (EasyPermissions.hasPermissions(context!!, Manifest.permission.ACCESS_FINE_LOCATION)) {
            getMap()
        } else {
            EasyPermissions.requestPermissions(
                this, getString(R.string.message_denied),
                100, Manifest.permission.ACCESS_FINE_LOCATION
            )
        }
    }

    private fun initRecycler() {
        with(fields_recycler) {
            layoutManager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
            (itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false

            adapter = this@MapFragment.adapter
        }
    }

    private fun initAdapter() {
        adapter = AgroFieldAdapter(dateUtils)
        adapter?.onClickListener = object : AdapterClickListener<AgroField> {
            override fun onClick(item: AgroField) {
                mapUtils.moveCamera(googleMap, item.polygon, item.name)

                adapter?.selectItem(item)
                val position = adapter?.getPosition(item)
                if (position != null) {
                    fields_recycler.scrollToPosition(position)
                }
            }
        }
    }

    private fun initMap(googleMap: GoogleMap) {
        this.googleMap = googleMap
        val isMyLocatioEnabled =
            EasyPermissions.hasPermissions(context!!, Manifest.permission.ACCESS_FINE_LOCATION)
        googleMap.uiSettings.isMyLocationButtonEnabled = isMyLocatioEnabled
        googleMap.isMyLocationEnabled = isMyLocatioEnabled
        googleMap.setOnPolygonClickListener {
            val item = adapter?.getFieldItem(it)
            adapter?.selectItem(item)
            mapUtils.moveCamera(googleMap, it.points, item?.name)

            val position = adapter?.getPosition(item)
            if (position != null) {
                fields_recycler.scrollToPosition(position)
            }
        }

        googleMap.setOnCameraMoveStartedListener {
            if (it == REASON_GESTURE) {
                search_edit_text.clearFocus()
                search_edit_text?.let { v ->
                    val imm =
                        context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
                    imm?.hideSoftInputFromWindow(v.windowToken, 0)
                }
            }
        }

        moveMyLocationButton()
    }

    private fun showFilterDialog(years: List<String>) {
        if (activity == null || activity?.supportFragmentManager == null) {
            Timber.e { "MapFragment::showFilterDialog: activity is null" }
            return
        }
        val filterDialog = FilterDialog()

        val args = Bundle()
        args.putStringArrayList(FilterDialog.YEARS_BUNDLE, ArrayList(years))

        filterDialog.arguments = args
        filterDialog.setTargetFragment(this, FilterDialog.REQUEST_CODE)
        filterDialog.setStyle(DialogFragment.STYLE_NORMAL, R.style.DialogStyle)
        filterDialog.show(activity?.supportFragmentManager!!, filterDialog.javaClass.name)
    }

    //workaround. No other way how to move my location button
    private fun moveMyLocationButton() {
        val locationButton =
            (map_view.findViewById<View>(Integer.parseInt("1")).parent as View).findViewById<View>(
                Integer.parseInt("2")
            )
        val padding = resources.getDimensionPixelSize(R.dimen.search_edit_text_height) +
                resources.getDimensionPixelOffset(R.dimen.padding_16dp)
        val rlp = locationButton.layoutParams as (RelativeLayout.LayoutParams)
        // position on right top
        rlp.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0)
        rlp.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE)
        rlp.setMargins(0, padding, 30, 0)
    }

    override fun onResume() {
        super.onResume()
        map_view.onResume()
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when (requestCode) {
            FilterDialog.REQUEST_CODE ->
                mapViewModel.onFilterSelected(data?.getStringExtra(FilterDialog.YEAR_EXTRA))
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int, permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
    }

    override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
        Toast.makeText(context, R.string.message_denied, Toast.LENGTH_LONG).show()
        getMap()
    }

    override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>) {
        Toast.makeText(context, R.string.message_approved, Toast.LENGTH_LONG).show()
        getMap()
    }
}<file_sep>package ru.gorshkov.agrotask.base.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment

abstract class BaseFragment : Fragment() {
    private var rootView: View? = null
    protected abstract val layoutRes: Int

    override fun onCreateView(
        inflater: LayoutInflater, root: ViewGroup?, savedInstanceState: Bundle?): View? {
        rootView = inflater.inflate(layoutRes, root, false)
        return rootView
    }
}<file_sep>package ru.gorshkov.agrotask.utils

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import androidx.core.content.ContextCompat
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.*
import ru.gorshkov.agrotask.R
import ru.gorshkov.agrotask.data.pojo.AgroField

class MapUtils(private val context : Context) {

    fun getFieldPolygon(field: AgroField): PolygonOptions {
        val color = ContextCompat.getColor(context, field.color)
        return PolygonOptions()
            .clickable(true)
            .addAll(field.polygon)
            .strokeColor(color)
            .fillColor(color)
    }

    fun moveCamera(map: GoogleMap?, coordinates: List<LatLng>, title: String?) {
        val center = getPolygonCenterPoint(coordinates)
        val cameraPosition = CameraPosition.Builder()
            .target(center)
            .zoom(9f)
            .build()
        val marker = map?.addMarker(getMarker(center, title))
        marker?.showInfoWindow()
        map?.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))
    }

    private fun getMarker(latLng: LatLng, title: String?) : MarkerOptions {
        return MarkerOptions()
            .position(LatLng(latLng.latitude, latLng.longitude))
            .title(title)
            .icon(bitmapDescriptorFromVector(R.drawable.ic_empty))
    }

    private fun getPolygonCenterPoint(polygonPointsList: List<LatLng>): LatLng {
        val centerLatLng: LatLng?
        val builder: LatLngBounds.Builder = LatLngBounds.Builder()
        for (element in polygonPointsList) {
            builder.include(element)
        }
        val bounds: LatLngBounds = builder.build()
        centerLatLng = bounds.center
        return centerLatLng
    }

    private fun bitmapDescriptorFromVector(vectorResId: Int): BitmapDescriptor? {
        return ContextCompat.getDrawable(context, vectorResId)?.run {
            setBounds(0, 0, intrinsicWidth, intrinsicHeight)
            val bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888)
            draw(Canvas(bitmap))
            BitmapDescriptorFactory.fromBitmap(bitmap)
        }
    }
}<file_sep>package ru.gorshkov.agrotask.features.map.recycler

import android.view.View
import androidx.core.content.ContextCompat
import kotlinx.android.synthetic.main.holder_fields.view.*
import ru.gorshkov.agrotask.R
import ru.gorshkov.agrotask.base.adapter.BaseViewHolder
import ru.gorshkov.agrotask.data.pojo.AgroField
import ru.gorshkov.agrotask.utils.DateUtils


class AgroFieldHolder(
    private val view: View,
    private val dateUtils: DateUtils
) : BaseViewHolder<AgroField>(view) {

    fun setSelected(isSelected: Boolean) {
        val color: Int = if (isSelected)
            ContextCompat.getColor(itemView.context, R.color.gray)
        else
            ContextCompat.getColor(itemView.context, R.color.white)

        view.holder_root.setCardBackgroundColor(color)

    }

    override fun bind(item: AgroField) {
        view.field_id_text.text = view.resources.getString(R.string.field_name, item.id)
        view.field_description_text.text = item.description
        view.field_name_text.text = item.name
        view.field_size_text.text = view.resources.getString(R.string.field_size, item.size)
        view.date_start_text.text = dateUtils.getFieldDate(item.dateStart)
        view.date_end_text.text = dateUtils.getFieldDate(item.dateEnd)
    }
}<file_sep>package ru.gorshkov.agrotask.features.filter

import android.app.Activity
import android.app.Dialog
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.dialog_filter.*
import ru.gorshkov.agrotask.R
import ru.gorshkov.agrotask.base.adapter.AdapterClickListener
import ru.gorshkov.agrotask.base.fragment.BaseDialogFragment
import ru.gorshkov.agrotask.features.filter.recycler.FilterAdapter

class FilterDialog : BaseDialogFragment() {
    companion object {
        const val REQUEST_CODE = 111
        const val YEARS_BUNDLE = "years_bundle"
        const val YEAR_EXTRA = "year_extra"
    }

    private var adapter: FilterAdapter? = null
    private val allYears: String by lazy { resources.getString(R.string.all_years) }

    override val layoutRes = R.layout.dialog_filter

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val years = arguments?.getStringArrayList(YEARS_BUNDLE)
        years?.add(allYears)

        adapter = FilterAdapter(years as List<String>)
        adapter?.onClickListener = object : AdapterClickListener<String> {
            override fun onClick(item: String) {
                val intent = Intent()
                if (TextUtils.equals(item, allYears)) {
                    intent.putExtra(YEAR_EXTRA, "")
                } else {
                    intent.putExtra(YEAR_EXTRA, item)
                }
                targetFragment?.onActivityResult(REQUEST_CODE, Activity.RESULT_OK, intent)
                dismiss()
            }
        }

        with(filter_recycler) {
            layoutManager = LinearLayoutManager(activity)
            adapter = this@FilterDialog.adapter
        }
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val dialog = super.onCreateDialog(savedInstanceState)
        dialog.setTitle(R.string.choose_year)
        return dialog
    }
}<file_sep>include ':app'
rootProject.name='AgroTask'
<file_sep>package ru.gorshkov.agrotask.features.map

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import ru.gorshkov.agrotask.data.pojo.AgroField
import ru.gorshkov.agrotask.features.map.interactors.FieldsInteractor

class MapViewModel(private val fieldsInteractor: FieldsInteractor) : ViewModel(){
    val fieldsUpdateLiveData = MutableLiveData<List<AgroField>>()
    val filterLiveData = MutableLiveData<List<String>>()

    fun start() {
        fieldsUpdateLiveData.postValue(fieldsInteractor.getFields())
    }

    fun onSearchChanged(text: String) {
        fieldsUpdateLiveData.postValue(fieldsInteractor.searchItems(text))
    }

    fun onFilterClicked() {
        filterLiveData.postValue(fieldsInteractor.getYears())
    }

    fun onFilterSelected(year: String?) {
        fieldsUpdateLiveData.postValue(fieldsInteractor.filterItems(year))
    }
}<file_sep>package ru.gorshkov.agrotask.utils

import java.text.SimpleDateFormat
import java.util.*

class DateUtils {
    fun getFieldDate(timeMills: Long) = getDate("dd.MM.yyyy", timeMills)

    fun getYear(timeMills: Long) = getDate("yyyy", timeMills)

    private fun getDate(format : String, timeMills: Long): String {
        return if(timeMills == 0L)
            ""
        else
            SimpleDateFormat(format, Locale.getDefault()).format(timeMills)
    }
}<file_sep>package ru.gorshkov.agrotask.features.map.recycler

import androidx.recyclerview.widget.DiffUtil
import ru.gorshkov.agrotask.data.pojo.AgroField


class AgroFieldCallback(
    private val oldList: List<AgroField>,
    private val newList: List<AgroField>
) : DiffUtil.Callback() {
    override fun getOldListSize() = oldList.size

    override fun getNewListSize() = newList.size

    override fun areItemsTheSame(oldPosition: Int, newPosition: Int): Boolean {
        return oldList[oldPosition].id == newList[newPosition].id
    }

    override fun areContentsTheSame(oldPosition: Int, newPosition: Int): Boolean {
        return oldList[oldPosition] == newList[newPosition]
    }
}