<repo_name>HarlockOfficial/dva232_labs<file_sep>/lab1/app/src/main/java/se/mdh/student/dva232/lab1/ConversionRates.kt
package se.mdh.student.dva232.lab1

import android.app.Activity
import android.os.Bundle
import android.view.View
import android.widget.*
import kotlin.math.round

class ConversionRates: Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.rates_conversion)

        val arr:Array<String>? = intent.getStringArrayExtra("se.mdh.student.dva232.lab1.Rates")
        if(arr==null || arr.isEmpty()) { //should not happen, almost impossible, but IDK
            Toast.makeText(this, getText(R.string.resource_error), Toast.LENGTH_SHORT).show()
            this.onBackPressed()
            return
        }
        val currencyTable: TableLayout = findViewById(R.id.currency_grid)
        val spinner: Spinner = findViewById(R.id.currency_selector)
        ArrayAdapter.createFromResource(this,
            R.array.currencies,
            android.R.layout.simple_spinner_item
        ).also { adapter ->
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
            spinner.adapter = adapter
        }
        spinner.onItemSelectedListener = object: AdapterView.OnItemSelectedListener{
            override fun onItemSelected(parent: AdapterView<*>, view: View?, pos: Int, id: Long) {
                currencyTable.removeAllViewsInLayout()

                val startCurrency: CurrencyType = CurrencyType.valueOf(parent.getItemAtPosition(pos).toString())
                for(currency:String in arr){
                    if(currency == startCurrency.toString())
                        continue
                    val row:View = layoutInflater.inflate(R.layout.conversion_table_row, currencyTable,false)
                    (row.findViewById(R.id.currency_code) as TextView).text = currency
                    (row.findViewById(R.id.currency_change) as TextView).text = "%,.5f".format(
                            ChangeRate.getExchange(startCurrency, CurrencyType.valueOf(currency)))
                    currencyTable.addView(row)
                }
            }
            override fun onNothingSelected(p0: AdapterView<*>?) {}
        }
    }
}<file_sep>/lab2/app/src/main/java/se/mdh/student/dva232/lab2/Geocoder.kt
package se.mdh.student.dva232.lab2

import android.location.Location
import androidx.lifecycle.ViewModel
import org.json.JSONException
import org.json.JSONObject
import java.net.URL
import java.util.*

//not all manufacturers implements Geocoder
//better to implement the needed feature
class Geocoder: ViewModel(){
    companion object {
        fun getLocale(location: Location): Locale {
            return try {
                val json = JSONObject(URL("https://nominatim.openstreetmap.org/reverse?format=json&lat=" +
                        location.latitude + "&lon=" +
                        location.longitude + "&zoom=18").readText())
                Locale.getAvailableLocales().first {
                    it.country == json.getJSONObject("address").
                        getString("country_code").toUpperCase(Locale.ROOT)
                }
            } catch (unused: NoSuchElementException) {
                Locale.GERMANY
            } catch (unused: JSONException) {
                Locale.GERMANY
            }
        }
    }
}<file_sep>/lab1/app/src/main/java/se/mdh/student/dva232/lab1/CurrencyType.kt
package se.mdh.student.dva232.lab1

enum class CurrencyType {
    EUR, SEK, USD, GBP, CNY, JPY, KRW
}<file_sep>/lab1/app/src/main/java/se/mdh/student/dva232/lab1/CurrencyConverter.kt
package se.mdh.student.dva232.lab1

import kotlin.math.round

class CurrencyConverter(private var amount: Double,private var inputCurrency: CurrencyType, private var outputCurrency: CurrencyType) {
    fun convert(): String {
        return "%,.2f".format(amount * ChangeRate.getExchange(inputCurrency,outputCurrency))
    }
}<file_sep>/lab1/app/src/main/java/se/mdh/student/dva232/lab1/MainActivity.kt
package se.mdh.student.dva232.lab1

import android.content.Intent
import android.os.Bundle
import android.widget.*
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    val inputCurrency = ItemSelectionEvent(input = true, mainActivity = this)
    val outputCurrency = ItemSelectionEvent(input = false, mainActivity = this)

    lateinit var output: TextView
        private set
    lateinit var input: EditText
        private set
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        input = findViewById(R.id.user_input)
        output = findViewById(R.id.output)

        //add currencies to spinners
        var spinner: Spinner = findViewById(R.id.dropdown_input)
        ArrayAdapter.createFromResource(this,
            R.array.currencies,
            android.R.layout.simple_spinner_item
        ).also { adapter ->
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
            spinner.adapter = adapter
        }
        spinner.onItemSelectedListener = inputCurrency

        spinner = findViewById(R.id.dropdown_output)
        ArrayAdapter.createFromResource(this,
            R.array.currencies,
            android.R.layout.simple_spinner_item
        ).also { adapter ->
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
            spinner.adapter = adapter
        }
        spinner.onItemSelectedListener = outputCurrency

        input.addTextChangedListener(TextChangeEvent(mainActivity = this))
        findViewById<Button>(R.id.to_screen_two).setOnClickListener {
            startActivity(Intent(this.baseContext, ConversionRates::class.java).apply {
                putExtra("se.mdh.student.dva232.lab1.Rates", (resources.getStringArray(R.array.currencies) as Array<String>))
            })
        }
    }
}<file_sep>/lab2/app/src/main/java/se/mdh/student/dva232/lab2/Plot.kt
package se.mdh.student.dva232.lab2

import android.app.Activity
import android.graphics.Color
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.CalendarView
import android.widget.Spinner
import android.widget.Toast
import com.androidplot.xy.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.json.JSONObject
import java.text.FieldPosition
import java.text.Format
import java.text.ParsePosition
import java.text.SimpleDateFormat
import java.util.*


//using https://github.com/halfhp/androidplot
//as plot library
class Plot: Activity() {
    private lateinit var plot: XYPlot
    private lateinit var itemStartSelectionEvent: PlotItemSelectionEvent
    private lateinit var itemEndSelectionEvent: PlotItemSelectionEvent
    private lateinit var dateFromChangeListener: PlotDateChangeListener
    private lateinit var dateToChangeListener: PlotDateChangeListener

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.plot)

        val arr: String? = intent.getStringExtra("se.mdh.student.dva232.lab2.Rates")
        if (arr == null || arr.isEmpty()) { //should not happen, almost impossible, but IDK
            Toast.makeText(this, getText(R.string.resource_error), Toast.LENGTH_SHORT).show()
            this.onBackPressed()
            return
        }
        val array: List<String> = arr.substring(1, arr.length - 1).split(",")
        val default: Int = intent.getIntExtra("se.mdh.student.dva232.lab2.Default", 0)

        plot = findViewById(R.id.plot)
        plot.layoutManager.remove(plot.legend)

        //adding listeners to get the selected day
        val dateFrom: CalendarView = findViewById(R.id.from)
        val dateTo: CalendarView = findViewById(R.id.to)
        val calendar = Calendar.getInstance()
        dateFromChangeListener = PlotDateChangeListener(this, "${calendar.get(Calendar.YEAR)-2}-${calendar.get(Calendar.MONTH)+1}-${calendar.get(Calendar.DAY_OF_MONTH)}")
        dateToChangeListener = PlotDateChangeListener(this, "${calendar.get(Calendar.YEAR)}-${calendar.get(Calendar.MONTH)+1}-${calendar.get(Calendar.DAY_OF_MONTH)}")
        dateFrom.setOnDateChangeListener(dateFromChangeListener)
        dateTo.setOnDateChangeListener(dateToChangeListener)

        var spinner: Spinner = findViewById(R.id.start_currency)
        ArrayAdapter(
                this,
                android.R.layout.simple_spinner_item,
                array.toMutableList()
        ).also { adapter ->
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
            spinner.adapter = adapter
        }
        spinner.setSelection(default, false)
        itemStartSelectionEvent = PlotItemSelectionEvent(this, spinner.selectedItem.toString())
        spinner.onItemSelectedListener = itemStartSelectionEvent

        spinner = findViewById(R.id.end_currency)
        ArrayAdapter(
                this,
                android.R.layout.simple_spinner_item,
                array.toMutableList()
        ).also { adapter ->
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
            spinner.adapter = adapter
        }
        spinner.setSelection(0, false)
        itemEndSelectionEvent = PlotItemSelectionEvent(this, spinner.selectedItem.toString())
        spinner.onItemSelectedListener = itemEndSelectionEvent

        plot()
    }
    
    fun plot() {
        GlobalScope.launch(Dispatchers.IO) {
            if(dateToChangeListener.date == dateFromChangeListener.date){
                runOnUiThread{
                    Toast.makeText(this@Plot, this@Plot.getString(R.string.invalid_date_selected), Toast.LENGTH_SHORT).show()
                }
                return@launch
            }
            val data: JSONObject? = ChangeRate.getPlotData(
                    dateFromChangeListener.date,
                    dateToChangeListener.date
            )
            if (data!!.length() == 0) {
                runOnUiThread {
                    Toast.makeText(
                            this@Plot,
                            getString(R.string.get_plot_data_error),
                            Toast.LENGTH_SHORT
                    ).show()
                }
                return@launch
            }
            val startValue = itemStartSelectionEvent.selectedItem.trim()
            val endValue = itemEndSelectionEvent.selectedItem.trim()
            if(startValue == endValue){
                runOnUiThread {
                    Toast.makeText(this@Plot, this@Plot.getString(R.string.invalid_currencies_selected), Toast.LENGTH_SHORT).show()
                }
                return@launch
            }
            val currency: SortedMap<String, Double> = TreeMap()
            for(key in data.keys()){
                val obj = data.getJSONObject(key)
                val currency1: Double = if(startValue!="EUR") {
                    obj.getDouble(startValue)
                }else{
                    1.0
                }
                val currency2: Double = if(endValue!="EUR") {
                    obj.getDouble(endValue)
                }else{
                    1.0
                }
                currency[key] = (currency2/currency1)
            }

            //Starting plot stuff
            plot.clear()
            val series: XYSeries = PlotXYSeries(currency, "")
            val seriesFormat = LineAndPointFormatter(Color.RED, Color.GREEN, Color.BLUE, null)
            plot.addSeries(series, seriesFormat)

            plot.graph.getLineLabelStyle(XYGraphWidget.Edge.BOTTOM).format = object : Format() {
                override fun format(obj: Any, toAppendTo: StringBuffer, pos: FieldPosition): StringBuffer {
                    val date = Date((obj as Double).toLong())
                    val formatter = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
                    return StringBuffer(formatter.format(date))
                }
                override fun parseObject(source: String?, pos: ParsePosition?): Any? {
                    return null
                }
            }
            plot.graph.getLineLabelStyle(XYGraphWidget.Edge.LEFT).format = object: Format(){
                override fun format(obj: Any, toAppendTo: StringBuffer, pos: FieldPosition): StringBuffer {
                    return StringBuffer(String.format("%.3f", (obj as Double)))
                }
                override fun parseObject(source: String, pos: ParsePosition): Any? {
                    return null
                }
            }
            plot.redraw()
        }
    }
}<file_sep>/lab2/app/src/main/java/se/mdh/student/dva232/lab2/ChangeRate.kt
package se.mdh.student.dva232.lab2

import androidx.lifecycle.ViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.json.JSONException
import org.json.JSONObject
import java.net.MalformedURLException
import java.net.URL


class ChangeRate: ViewModel(){
    //https://www.countryflags.io/
    companion object {
        private var currencyExchangeRates: HashMap<String, Double> = HashMap()
        fun updateExchangeRates() {
            GlobalScope.launch(Dispatchers.IO){
                try {
                    val tmp = JSONObject(
                            URL("https://api.exchangeratesapi.io/latest").readText()
                    )
                    for (key: String in tmp.getJSONObject("rates").keys()) {
                        currencyExchangeRates[key.trim()] = tmp.getJSONObject("rates").getDouble(key)
                    }
                    currencyExchangeRates["EUR"] = 1.0
                } catch (unused: JSONException) {
                } catch (unused: MalformedURLException){}
            }
        }
        fun getCurrencyList(): MutableSet<String>? {
            return if(currencyExchangeRates.keys.size>0) currencyExchangeRates.keys.toSortedSet() else null
        }
        fun getExchange(start: String, end: String): Double {
            if(currencyExchangeRates.isEmpty()){
                GlobalScope.launch (Dispatchers.IO){
                    updateExchangeRates()
                }
                return 0.0
            }
            val change1:Double = currencyExchangeRates[start.trim()] ?: return 0.0
            val change2:Double = currencyExchangeRates[end.trim()] ?: return 0.0
            return change2/change1
        }
        fun getPlotData(dateFrom: String, dateTo: String): JSONObject?{
            return try {
                JSONObject(
                    URL(
                        "https://api.exchangeratesapi.io/history?start_at=" +
                                "$dateFrom&end_at=$dateTo"
                    ).readText()
                ).getJSONObject("rates")
            }catch (unused: JSONException){
                null
            }catch (unused: MalformedURLException){
                null
            }
        }
    }
}<file_sep>/lab2/app/src/main/java/se/mdh/student/dva232/lab2/CurrencyConverter.kt
package se.mdh.student.dva232.lab2

class CurrencyConverter(private var amount: Double,private var inputCurrency: String, private var outputCurrency: String) {
    fun convert(): String {
        return "%,.2f".format(amount * ChangeRate.getExchange(inputCurrency,outputCurrency))
    }
}<file_sep>/lab2/app/src/main/java/se/mdh/student/dva232/lab2/ItemSelectionEvent.kt
package se.mdh.student.dva232.lab2

import android.view.View
import android.widget.AdapterView
import java.lang.NumberFormatException

class ItemSelectionEvent(private val input: Boolean, private val mainActivity: MainActivity): AdapterView.OnItemSelectedListener {
    lateinit var actCurrency: String
        private set

    override fun onItemSelected(parent: AdapterView<*>, view: View?, pos: Int, id: Long) {
        try{
            val inputCurrency: String
            val outputCurrency: String
            val item : String = parent.getItemAtPosition(pos) as String
            if(input) {
                actCurrency = item
                inputCurrency = actCurrency
                outputCurrency = mainActivity.outputCurrency.actCurrency
            }else {
                actCurrency = item
                inputCurrency = mainActivity.inputCurrency.actCurrency
                outputCurrency = actCurrency
            }
            val value: Double = mainActivity.input.text.toString().toDouble()
            mainActivity.output.text = CurrencyConverter(value, inputCurrency , outputCurrency).convert()
        }catch (unused: NumberFormatException) {
            return
        }catch (unused: UninitializedPropertyAccessException){
            return
        }
    }

    override fun onNothingSelected(parent: AdapterView<*>?) {}
}<file_sep>/lab2/app/src/main/java/se/mdh/student/dva232/lab2/TextChangeEvent.kt
package se.mdh.student.dva232.lab2

import android.text.Editable
import android.text.TextWatcher

class TextChangeEvent(private val mainActivity: MainActivity): TextWatcher {
    override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}

    override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}

    override fun afterTextChanged(editable: Editable?) {
        if(editable.isNullOrBlank()){
            mainActivity.output.text = ""
            return
        }
        try{
            val value = editable.toString().toDouble()
            val inputCurrency: String = mainActivity.inputCurrency.actCurrency
            val outputCurrency: String = mainActivity.outputCurrency.actCurrency
            mainActivity.output.text = CurrencyConverter(value, inputCurrency, outputCurrency).convert()
        }catch (unused: NumberFormatException){
            return
        }
    }
}<file_sep>/lab2/app/src/main/java/se/mdh/student/dva232/lab2/MainActivity.kt
package se.mdh.student.dva232.lab2

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
import android.os.Looper
import android.widget.*
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.util.*

class MainActivity : AppCompatActivity() {
    val inputCurrency = ItemSelectionEvent(input = true, mainActivity = this)
    val outputCurrency = ItemSelectionEvent(input = false, mainActivity = this)
    lateinit var output: TextView
        private set
    lateinit var input: EditText
        private set
    private var answered = false
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        input = findViewById(R.id.user_input)
        output = findViewById(R.id.output)

        //ask for localization permissions
        checkPermissions()

        val spinner1: Spinner = findViewById(R.id.dropdown_input)

        GlobalScope.launch(Dispatchers.IO) {
            //get updated exchange rates
            ChangeRate.updateExchangeRates()
            var tmp: MutableList<String>? = ChangeRate.getCurrencyList()?.toMutableList()
            while (tmp == null) {
                delay(10)
                tmp = ChangeRate.getCurrencyList()?.toMutableList()
            }

            //add currencies to spinners
            GlobalScope.launch(Dispatchers.Main) {
                ArrayAdapter(
                        this@MainActivity,
                        android.R.layout.simple_spinner_item,
                        tmp
                ).also { adapter ->
                    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
                    spinner1.adapter = adapter
                }
                spinner1.onItemSelectedListener = inputCurrency

                val spinner2: Spinner = findViewById(R.id.dropdown_output)
                ArrayAdapter(
                        this@MainActivity,
                        android.R.layout.simple_spinner_item,
                        tmp
                ).also { adapter ->
                    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
                    spinner2.adapter = adapter
                }
                spinner2.onItemSelectedListener = outputCurrency

                //set listener for input
                input.addTextChangedListener(TextChangeEvent(mainActivity = this@MainActivity))
            }

            //wait for permissions check
            while(!answered){
                delay(10)
            }

            //get location
            var provider: String? = null

            if(ActivityCompat.checkSelfPermission(this@MainActivity,
                            Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED){
                provider = LocationManager.NETWORK_PROVIDER
            }
            if (ActivityCompat.checkSelfPermission(this@MainActivity,
                            Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                provider = LocationManager.GPS_PROVIDER
            }
            var actCurrency = "EUR"

            if(provider != null) {  //allowed to use geolocationw
                val locationManager: LocationManager =
                        getSystemService(LOCATION_SERVICE) as LocationManager
                var actualLocation: Location? = null
                //request single update deprecated in API 30
                locationManager.requestLocationUpdates(provider, 100L, 0F, object : LocationListener {
                    override fun onLocationChanged(location: Location?) {
                        if (location == null) {
                            return
                        }
                        actualLocation = location
                        locationManager.removeUpdates(this)
                    }

                    override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) {}
                    override fun onProviderEnabled(p0: String?) {}
                    override fun onProviderDisabled(p0: String?) {}
                }, Looper.getMainLooper())

                while (actualLocation == null) {
                    delay(10)
                }

                //get currency code
                actCurrency = Currency.getInstance(
                        Geocoder.getLocale(actualLocation!!)
                ).currencyCode
            }

            //change the input currency to country currency or EUR
            var selected = -1
            for (i in 0 until spinner1.count) {
                if (spinner1.getItemAtPosition(i).toString() == "EUR") {
                    selected = i
                }
                if (spinner1.getItemAtPosition(i).toString() == actCurrency) {
                    selected = i
                    break
                }
            }
            runOnUiThread {
                spinner1.setSelection(selected)
                //set listener for button
                findViewById<Button>(R.id.to_screen_two).setOnClickListener {
                    startActivity(Intent(this@MainActivity, ConversionRates::class.java).apply {
                        putExtra("se.mdh.student.dva232.lab2.Rates", tmp.toString())
                        putExtra("se.mdh.student.dva232.lab2.Default", selected)
                    })
                }
                findViewById<Button>(R.id.to_screen_three).setOnClickListener {
                    startActivity(Intent(this@MainActivity, Plot::class.java).apply {
                        putExtra("se.mdh.student.dva232.lab2.Rates", tmp.toString())
                        putExtra("se.mdh.student.dva232.lab2.Default", selected)
                    })
                }
            }
        }
    }

    private fun checkPermissions(){
        var counter = 1 //number of permissions to ask
        val requestPermissionLauncher = registerForActivityResult(
                ActivityResultContracts.RequestPermission()
            ) { isGranted: Boolean ->
                if(counter--<=0){
                    answered = true
                    if (!isGranted) {
                        Toast.makeText(this@MainActivity, getString(R.string.location_disabled), Toast.LENGTH_SHORT).show()
                    }
                }
            }
        //even if they're 2, they are counted as a single permission
        //both belong to geolocation
        requestPermissionLauncher.launch(Manifest.permission.ACCESS_COARSE_LOCATION)
        requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
    }

}<file_sep>/lab2/app/src/main/java/se/mdh/student/dva232/lab2/PlotDateChangeListener.kt
package se.mdh.student.dva232.lab2

import android.widget.CalendarView

class PlotDateChangeListener(private val plotContext: Plot, today: String): CalendarView.OnDateChangeListener {
    var date: String = today
        private set
    override fun onSelectedDayChange(view: CalendarView, year: Int, month: Int, day: Int) {
        date = "$year-${month+1}-$day"
        plotContext.plot()
    }
}<file_sep>/lab1/app/src/main/java/se/mdh/student/dva232/lab1/ChangeRate.kt
package se.mdh.student.dva232.lab1

class ChangeRate {
    //https://exchangeratesapi.io/
    //https://www.countryflags.io/
    companion object {
        private val toNonCurrency: Map<CurrencyType, Double> = mapOf(
                CurrencyType.EUR to 1000.0,
                CurrencyType.USD to 1800.0,
                CurrencyType.CNY to 7820.0,
                CurrencyType.GBP to 900.0,
                CurrencyType.JPY to 123880.0,
                CurrencyType.KRW to 1311850.0,
                CurrencyType.SEK to 10280.0
        )

        fun getExchange(start: CurrencyType, end: CurrencyType): Double {
            val change1 = toNonCurrency[start] ?: return 0.0
            val change2 = toNonCurrency[end] ?: return 0.0
            return change2/change1
        }
    }
}<file_sep>/lab2/app/src/main/java/se/mdh/student/dva232/lab2/ConversionRates.kt
package se.mdh.student.dva232.lab2

import android.app.Activity
import android.os.Bundle
import android.view.View
import android.widget.*

class ConversionRates: Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.rates_conversion)

        val arr:String? = intent.getStringExtra("se.mdh.student.dva232.lab2.Rates")
        if(arr==null || arr.isEmpty()) { //should not happen, almost impossible, but IDK
            Toast.makeText(this, getText(R.string.resource_error), Toast.LENGTH_SHORT).show()
            this.onBackPressed()
            return
        }
        val array: List<String> = arr.substring(1,arr.length-1).split(",")
        val currencyTable: TableLayout = findViewById(R.id.currency_grid)
        val spinner: Spinner = findViewById(R.id.currency_selector)

        ArrayAdapter(this,
            android.R.layout.simple_spinner_item,
            array.toMutableList()
        ).also { adapter ->
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
            spinner.adapter = adapter
        }
        spinner.onItemSelectedListener = object: AdapterView.OnItemSelectedListener{
            override fun onItemSelected(parent: AdapterView<*>, view: View?, pos: Int, id: Long) {
                currencyTable.removeAllViewsInLayout()
                val startCurrency: String = parent.getItemAtPosition(pos).toString()
                for(currency:String in array){
                    if(currency == startCurrency)
                        continue
                    val row:View = layoutInflater.inflate(R.layout.conversion_table_row,
                                    currencyTable,false)
                    (row.findViewById(R.id.currency_code) as TextView).text = currency
                    (row.findViewById(R.id.currency_change) as TextView).text = "%,.5f".format(
                            ChangeRate.getExchange(startCurrency, currency))
                    currencyTable.addView(row)
                }
            }
            override fun onNothingSelected(p0: AdapterView<*>?) {}
        }


    }
}<file_sep>/lab2/app/src/main/java/se/mdh/student/dva232/lab2/PlotXYSeries.kt
package se.mdh.student.dva232.lab2

import com.androidplot.xy.XYSeries
import java.text.SimpleDateFormat
import java.util.*

class PlotXYSeries(private val series: Map<String, Double>, private val title: String): XYSeries {
    override fun getTitle(): String {
        return title
    }

    override fun size(): Int {
        return series.size
    }

    override fun getX(index: Int): Number {
        val date: Date? = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).parse(series.keys.elementAt(index))
        return date!!.time
    }

    override fun getY(index: Int): Number {
        //impossible to go out of bounds
        return series.getValue(series.keys.elementAt(index))
    }
}<file_sep>/lab2/app/src/main/java/se/mdh/student/dva232/lab2/PlotItemSelectionEvent.kt
package se.mdh.student.dva232.lab2

import android.view.View
import android.widget.AdapterView

class PlotItemSelectionEvent(private val plotContext: Plot, selected: String): AdapterView.OnItemSelectedListener {
    var selectedItem: String = selected
        private set
    override fun onItemSelected(parent: AdapterView<*>, view: View?, pos: Int, id: Long) {
        selectedItem = parent.getItemAtPosition(pos) as String
        plotContext.plot()
    }
    override fun onNothingSelected(p0: AdapterView<*>?) {}
}