Bimba.git

commit a185e9112eb7c64c9e2afdbca2787dc69e34ef31

Author: Adam Pioterek <adam.pioterek@protonmail.ch>

refactoring (string constants and static functions) & fixed vm when timetable is full mode

%!v(PANIC=String method: strings: negative Repeat count)


diff --git a/app/src/main/java/ml/adamsprogs/bimba/MessageReceiver.kt b/app/src/main/java/ml/adamsprogs/bimba/MessageReceiver.kt
index bc53ddb2579afcedda4f27b10e3ba572a7c31ec5..74c0a57f9d4a927528767567f96afe77bb248194 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/MessageReceiver.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/MessageReceiver.kt
@@ -4,29 +4,27 @@ import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
 import ml.adamsprogs.bimba.models.Departure
-import ml.adamsprogs.bimba.models.fromString
 
-class MessageReceiver: BroadcastReceiver() {
+class MessageReceiver : BroadcastReceiver() {
     val onTimetableDownloadListeners: HashSet<OnTimetableDownloadListener> = HashSet()
     val onVmListeners: HashSet<OnVmListener> = HashSet()
 
     override fun onReceive(context: Context?, intent: Intent?) {
-        if (intent?.action == "ml.adamsprogs.bimba.timetableDownloaded") {
-            val result = intent.getStringExtra("result")
+        if (intent?.action == TimetableDownloader.ACTION_DOWNLOADED) {
+            val result = intent.getStringExtra(TimetableDownloader.EXTRA_RESULT)
             for (listener in onTimetableDownloadListeners) {
                 listener.onTimetableDownload(result)
             }
         }
-        if (intent?.action == "ml.adamsprogs.bimba.departuresCreated") {
-            val workdays = intent.getStringArrayListExtra("workdays").map { fromString(it)} as ArrayList<Departure>
-            val saturdays = intent.getStringArrayListExtra("saturdays").map { fromString(it)} as ArrayList<Departure>
-            val sundays = intent.getStringArrayListExtra("sundays").map { fromString(it)} as ArrayList<Departure>
-            val departures = HashMap<String, ArrayList<Departure>>()
-            departures["workdays"] = workdays
-            departures["saturdays"] = saturdays
-            departures["sundays"] = sundays
+        if (intent?.action == VmClient.ACTION_DEPARTURES_CREATED) {
+            val departures = intent.getStringArrayListExtra(VmClient.EXTRA_DEPARTURES).map { Departure.fromString(it) } as ArrayList<Departure>
             for (listener in onVmListeners) {
                 listener.onVm(departures)
+            }
+        }
+        if (intent?.action == VmClient.ACTION_NO_DEPARTURES) {
+            for (listener in onVmListeners) {
+                listener.onVm(null)
             }
         }
     }
@@ -52,6 +50,6 @@         fun onTimetableDownload(result: String?)
     }
 
     interface OnVmListener {
-        fun onVm(departures: HashMap<String, ArrayList<Departure>>)
+        fun onVm(vmDepartures: ArrayList<Departure>?)
     }
 }
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/NetworkStateReceiver.kt b/app/src/main/java/ml/adamsprogs/bimba/NetworkStateReceiver.kt
index cd17f1cdc5ed38f6452844e51000d72fdc21e380..71ef786ec8e6cfec1495edf62cdbca6f904f51dd 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/NetworkStateReceiver.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/NetworkStateReceiver.kt
@@ -5,12 +5,6 @@ import android.content.Intent
 import android.content.BroadcastReceiver
 import android.content.Context
 
-fun isNetworkAvailable(context: Context): Boolean {
-    val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
-    val activeNetworkInfo = connectivityManager.activeNetworkInfo
-    return activeNetworkInfo != null && activeNetworkInfo.isConnected
-}
-
 class NetworkStateReceiver : BroadcastReceiver() {
 
     val onConnectivityChangeListeners = HashSet<OnConnectivityChangeListener>()
@@ -40,5 +34,13 @@     }
 
     interface OnConnectivityChangeListener {
         fun onConnectivityChange(connected: Boolean)
+    }
+
+    companion object {
+        fun isNetworkAvailable(context: Context): Boolean {
+            val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+            val activeNetworkInfo = connectivityManager.activeNetworkInfo
+            return activeNetworkInfo != null && activeNetworkInfo.isConnected
+        }
     }
 }
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/TimetableDownloader.kt b/app/src/main/java/ml/adamsprogs/bimba/TimetableDownloader.kt
index 39d9ee191aac7f3939939acebd03bcc59e93413e..ac1a62fa93168ced7d984c0ba40a2c68bea52fc4 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/TimetableDownloader.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/TimetableDownloader.kt
@@ -12,9 +12,20 @@ import java.security.MessageDigest
 import kotlin.experimental.and
 import android.util.Log
 import android.app.NotificationManager
+import ml.adamsprogs.bimba.models.Timetable
 
 
 class TimetableDownloader : IntentService("TimetableDownloader") {
+    companion object {
+        val ACTION_DOWNLOADED = "ml.adamsprogs.bimba.timetableDownloaded"
+        val EXTRA_FORCE = "force"
+        val EXTRA_RESULT = "result"
+        val RESULT_NO_CONNECTIVITY = "no connectivity"
+        val RESULT_VERSION_MISMATCH = "version mismatch"
+        val RESULT_UP_TO_DATE = "up-to-date"
+        val RESULT_DOWNLOADED = "downloaded"
+        val RESULT_VALIDITY_FAILED = "validity failed"
+    }
     lateinit var notificationManager: NotificationManager
     var size: Int = 0
 
@@ -23,28 +34,30 @@
         if (intent != null) {
             notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
             val prefs = this.getSharedPreferences("ml.adamsprogs.bimba.prefs", Context.MODE_PRIVATE)!!
-            if (!isNetworkAvailable(this)) {
-                sendResult("no connectivity")
+            if (!NetworkStateReceiver.isNetworkAvailable(this)) {
+                sendResult(RESULT_NO_CONNECTIVITY)
                 return
             }
             val metadataUrl = URL("https://adamsprogs.ml/w/_media/programmes/bimba/timetable.db.meta")
             var httpCon = metadataUrl.openConnection() as HttpURLConnection
-            if (httpCon.responseCode != HttpURLConnection.HTTP_OK)
-                throw Exception("Failed to connect")
+            if (httpCon.responseCode != HttpURLConnection.HTTP_OK){
+                sendResult(RESULT_NO_CONNECTIVITY)
+                return
+            }
             Log.i("Downloader", "Got metadata")
             val reader = BufferedReader(InputStreamReader(httpCon.inputStream))
             val lastModified = reader.readLine()
             val checksum = reader.readLine()
             size = Integer.parseInt(reader.readLine()) / 1024
             val dbVersion = reader.readLine()
-            if (Integer.parseInt(dbVersion.split(".")[0]) > 1) { //todo version to const
-                sendResult("version mismatch")
+            if (Integer.parseInt(dbVersion.split(".")[0]) > Timetable.version) {
+                sendResult(RESULT_VERSION_MISMATCH)
                 return
             }
             val dbFilename = reader.readLine()
             val currentLastModified = prefs.getString("timetableLastModified", "19791012")
-            if (lastModified <= currentLastModified && !intent.getBooleanExtra("force", false)) {
-                sendResult("up-to-date")
+            if (lastModified <= currentLastModified && !intent.getBooleanExtra(EXTRA_FORCE, false)) {
+                sendResult(RESULT_UP_TO_DATE)
                 return
             }
             Log.i("Downloader", "timetable is newer ($lastModified > $currentLastModified)")
@@ -53,8 +66,10 @@             notify(0)
 
             val xzDbUrl = URL("https://adamsprogs.ml/w/_media/programmes/bimba/$dbFilename")
             httpCon = xzDbUrl.openConnection() as HttpURLConnection
-            if (httpCon.responseCode != HttpURLConnection.HTTP_OK)
-                throw Exception("Failed to connect")
+            if (httpCon.responseCode != HttpURLConnection.HTTP_OK){
+                sendResult(RESULT_NO_CONNECTIVITY)
+                return
+            }
             Log.i("Downloader", "connected to db")
             val xzIn = XZInputStream(httpCon.inputStream)
             val file = File(this.filesDir, "new_timetable.db")
@@ -66,10 +81,10 @@                 file.renameTo(oldFile)
                 val prefsEditor = prefs.edit()
                 prefsEditor.putString("timetableLastModified", lastModified)
                 prefsEditor.apply()
-                sendResult("downloaded")
+                sendResult(RESULT_DOWNLOADED)
             } else {
                 Log.i("Downloader", "downloaded but is wrong")
-                sendResult("validity failed")
+                sendResult(RESULT_VALIDITY_FAILED)
             }
 
             cancelNotification()
@@ -78,9 +93,9 @@     }
 
     private fun sendResult(result: String) {
         val broadcastIntent = Intent()
-        broadcastIntent.action = "ml.adamsprogs.bimba.timetableDownloaded"
+        broadcastIntent.action = ACTION_DOWNLOADED
         broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT)
-        broadcastIntent.putExtra("result", result)
+        broadcastIntent.putExtra(EXTRA_RESULT, result)
         sendBroadcast(broadcastIntent)
     }
 




diff --git a/app/src/main/java/ml/adamsprogs/bimba/VmClient.kt b/app/src/main/java/ml/adamsprogs/bimba/VmClient.kt
index 77a60772f12835221c39d198b292738d3f4ffe00..86ab7c5b3c2becd0e5031c1af21e2930be46a83d 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/VmClient.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/VmClient.kt
@@ -10,47 +10,50 @@ import java.util.*
 
 
 class VmClient : IntentService("VmClient") {
+    companion object {
+        val ACTION_DEPARTURES_CREATED = "ml.adamsprogs.bimba.departuresCreated"
+        val ACTION_NO_DEPARTURES = "ml.adamsprogs.bimba.noVM"
+        val EXTRA_STOP_SYMBOL = "stopSymbol"
+        val EXTRA_LINE_NUMBER = "lineNumber"
+        val EXTRA_DEPARTURES = "departures"
+    }
 
     override fun onHandleIntent(intent: Intent?) {
         if (intent != null) {
-            val stopId = intent.getStringExtra("stopId")
-            if (!isNetworkAvailable(this)) {
-                sendResult(createDepartures(stopId))
-            } else {
-                val stopSymbol = intent.getStringExtra("stopSymbol")
-                val departures = createDepartures(stopId)
+            if (!NetworkStateReceiver.isNetworkAvailable(this)) {
+                sendNullResult()
+                return
+            }
+
+            val stopSymbol = intent.getStringExtra(EXTRA_STOP_SYMBOL)
+            val lineNumber = intent.getStringExtra(EXTRA_LINE_NUMBER)
 
-                val client = OkHttpClient()
-                val url = "http://www.peka.poznan.pl/vm/method.vm?ts=${Calendar.getInstance().timeInMillis}"
-                val formBody = FormBody.Builder()
-                        .add("method", "getTimes")
-                        .add("p0", "{\"symbol\": \"$stopSymbol\"}")
-                        .build()
-                val request = Request.Builder()
-                        .url(url)
-                        .post(formBody)
-                        .build()
-                val responseBody : String?
-                try {
-                    responseBody = client.newCall(request).execute().body()?.string()
-                } catch(e: IOException) {
-                    sendResult(departures)
-                    return
-                }
-                val javaRootMapObject = Gson().fromJson(responseBody, HashMap::class.java)
-                val times = (javaRootMapObject["success"] as Map<*, *>)["times"] as List<*>
-                val date = Calendar.getInstance()
-                val today = date.get(Calendar.DAY_OF_WEEK)
-                val todayDay = "${date.get(Calendar.DATE)}"
-                val todayMode: String
-                when (today) {
-                    Calendar.SATURDAY -> todayMode = "saturdays"
-                    Calendar.SUNDAY -> todayMode = "sundays"
-                    else -> todayMode = "workdays"
-                }
-                val departuresToday = ArrayList<Departure>()
-                for (time in times) {
-                    val t = time as Map<*, *>
+            val client = OkHttpClient()
+            val url = "http://www.peka.poznan.pl/vm/method.vm?ts=${Calendar.getInstance().timeInMillis}"
+            val formBody = FormBody.Builder()
+                    .add("method", "getTimes")
+                    .add("p0", "{\"symbol\": \"$stopSymbol\"}")
+                    .build()
+            val request = Request.Builder()
+                    .url(url)
+                    .post(formBody)
+                    .build()
+            val responseBody: String?
+            try {
+                responseBody = client.newCall(request).execute().body()?.string()
+            } catch(e: IOException) {
+                sendNullResult()
+                return
+            }
+            val javaRootMapObject = Gson().fromJson(responseBody, HashMap::class.java)
+            val times = (javaRootMapObject["success"] as Map<*, *>)["times"] as List<*>
+            val date = Calendar.getInstance()
+            val todayDay = "${date.get(Calendar.DATE)}"
+            val todayMode = date.getMode()
+            val departuresToday = ArrayList<Departure>()
+            for (time in times) {
+                val t = time as Map<*, *>
+                if (lineNumber == null || t["line"] == lineNumber) {
                     val departureDay = (t["departure"] as String).split("T")[0].split("-")[2]
 
                     val departureTimeRaw = (t["departure"] as String).split("T")[1].split(":")
@@ -60,19 +63,27 @@                             null, t["direction"] as String, t["realTime"] as Boolean,
                             departureDay != todayDay, t["onStopPoint"] as Boolean)
                     departuresToday.add(departure)
                 }
-                departures[todayMode] = departuresToday
-                sendResult(departures)
             }
+            if (departuresToday.isEmpty())
+                sendNullResult()
+            else
+                sendResult(departuresToday)
+
         }
     }
 
-    private fun sendResult(departures: HashMap<String, ArrayList<Departure>>) {
+    private fun sendNullResult() {
         val broadcastIntent = Intent()
-        broadcastIntent.action = "ml.adamsprogs.bimba.departuresCreated"
+        broadcastIntent.action = ACTION_NO_DEPARTURES
         broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT)
-        broadcastIntent.putStringArrayListExtra("workdays", departures["workdays"]?.map { it.toString() } as java.util.ArrayList<String>)
-        broadcastIntent.putStringArrayListExtra("saturdays", departures["saturdays"]?.map { it.toString() } as java.util.ArrayList<String>)
-        broadcastIntent.putStringArrayListExtra("sundays", departures["sundays"]?.map { it.toString() } as java.util.ArrayList<String>)
+        sendBroadcast(broadcastIntent)
+    }
+
+    private fun sendResult(departures: ArrayList<Departure>) {
+        val broadcastIntent = Intent()
+        broadcastIntent.action = ACTION_DEPARTURES_CREATED
+        broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT)
+        broadcastIntent.putStringArrayListExtra(EXTRA_DEPARTURES, departures.map { it.toString() } as java.util.ArrayList<String>)
         sendBroadcast(broadcastIntent)
     }
 }




diff --git a/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt
index 04934cf7346636bed7760e4df87a249705ee3187..b58059fb156c426130e6b4e0b23fb5d85119effe 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt
@@ -85,8 +85,8 @@                 }
                 imm.hideSoftInputFromWindow(view.windowToken, 0)
                 intent = Intent(context, StopActivity::class.java)
                 searchSuggestion as StopSuggestion
-                intent.putExtra("stopId", searchSuggestion.id)
-                intent.putExtra("stopSymbol", searchSuggestion.symbol)
+                intent.putExtra(StopActivity.EXTRA_STOP_ID, searchSuggestion.id)
+                intent.putExtra(StopActivity.EXTRA_STOP_SYMBOL, searchSuggestion.symbol)
                 startActivity(intent)
             }
 
@@ -141,7 +141,7 @@         stops = timetable.getStops()
     }
 
     private fun prepareOnDownloadListener() {
-        val filter = IntentFilter("ml.adamsprogs.bimba.timetableDownloaded")
+        val filter = IntentFilter(TimetableDownloader.ACTION_DOWNLOADED)
         filter.addCategory(Intent.CATEGORY_DEFAULT)
         registerReceiver(receiver, filter)
         receiver.addOnTimetableDownloadListener(context as MessageReceiver.OnTimetableDownloadListener)
@@ -205,10 +205,10 @@     override fun onTimetableDownload(result: String?) {
         Log.i("Refresh", "downloaded: $result")
         val message: String
         when (result) {
-            "downloaded" -> message = getString(R.string.timetable_downloaded)
-            "no connectivity" -> message = getString(R.string.no_connectivity)
-            "up-to-date" -> message = getString(R.string.timetable_up_to_date)
-            "validity failed" -> message = getString(R.string.validity_failed)
+            TimetableDownloader.RESULT_DOWNLOADED -> message = getString(R.string.timetable_downloaded)
+            TimetableDownloader.RESULT_NO_CONNECTIVITY -> message = getString(R.string.no_connectivity)
+            TimetableDownloader.RESULT_UP_TO_DATE -> message = getString(R.string.timetable_up_to_date)
+            TimetableDownloader.RESULT_VALIDITY_FAILED -> message = getString(R.string.validity_failed)
             else -> message = getString(R.string.error_try_later)
         }
         timetable.refresh()
@@ -218,7 +218,7 @@     }
 
     override fun edit(name: String): Boolean {
         val intent = Intent(this, EditFavouriteActivity::class.java)
-        intent.putExtra("favourite", favourites.favourites[name])
+        intent.putExtra(EditFavouriteActivity.EXTRA_FAVOURITE, favourites.favourites[name])
         startActivity(intent)
         (favouritesList.adapter as FavouritesAdapter).favourites = favourites.favouritesList
         favouritesList.adapter.notifyDataSetChanged()




diff --git a/app/src/main/java/ml/adamsprogs/bimba/activities/EditFavouriteActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/activities/EditFavouriteActivity.kt
index 9a044a18bb4329a09eca5bbf1002070d68f604b5..e8d0b94f23b4029ad6379ebd7e0b6f016aec1293 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/EditFavouriteActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/EditFavouriteActivity.kt
@@ -13,6 +13,9 @@ import ml.adamsprogs.bimba.models.FavouriteEditRowAdapter
 import ml.adamsprogs.bimba.models.FavouriteStorage
 
 class EditFavouriteActivity : AppCompatActivity() {
+    companion object {
+        val EXTRA_FAVOURITE = "favourite"
+    }
 
     lateinit var favourites: FavouriteStorage
     lateinit var nameEdit: EditText
@@ -22,7 +25,7 @@     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_edit_favourite)
 
-        favourite = intent.getParcelableExtra<Favourite>("favourite")
+        favourite = intent.getParcelableExtra<Favourite>(EXTRA_FAVOURITE)
         if (favourite == null)
             finish()
         favourites = FavouriteStorage.getFavouriteStorage(this)




diff --git a/app/src/main/java/ml/adamsprogs/bimba/activities/NoDbActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/activities/NoDbActivity.kt
index 84182ce84b7908f81cd6836fdadcd6745b47f68b..b35bf71c9670673bb7ec6a368874560476b3fac0 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/NoDbActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/NoDbActivity.kt
@@ -17,12 +17,12 @@
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_nodb)
-        var filter: IntentFilter = IntentFilter("ml.adamsprogs.bimba.timetableDownloaded")
+        var filter: IntentFilter = IntentFilter(TimetableDownloader.ACTION_DOWNLOADED)
         filter.addCategory(Intent.CATEGORY_DEFAULT)
         registerReceiver(timetableDownloadReceiver, filter)
         timetableDownloadReceiver.addOnTimetableDownloadListener(this)
 
-        if (!isNetworkAvailable(this)) {
+        if (!NetworkStateReceiver.isNetworkAvailable(this)) {
             askedForNetwork = true
             (findViewById(R.id.noDbCaption) as TextView).text = getString(R.string.no_db_connect)
             filter = IntentFilter("android.net.conn.CONNECTIVITY_CHANGE")
@@ -34,10 +34,10 @@     }
 
     override fun onResume() {
         super.onResume()
-        var filter: IntentFilter = IntentFilter("ml.adamsprogs.bimba.timetableDownloaded")
+        var filter: IntentFilter = IntentFilter(TimetableDownloader.ACTION_DOWNLOADED)
         filter.addCategory(Intent.CATEGORY_DEFAULT)
         registerReceiver(timetableDownloadReceiver, filter)
-        if (!isNetworkAvailable(this)) {
+        if (!NetworkStateReceiver.isNetworkAvailable(this)) {
             askedForNetwork = true
             (findViewById(R.id.noDbCaption) as TextView).text = getString(R.string.no_db_connect)
             filter = IntentFilter("android.net.conn.CONNECTIVITY_CHANGE")
@@ -51,7 +51,7 @@     fun downloadTimetable() {
         (findViewById(R.id.noDbCaption) as TextView).text = getString(R.string.no_db_downloading)
         serviceRunning = true
         intent = Intent(this, TimetableDownloader::class.java)
-        intent.putExtra("force", true)
+        intent.putExtra(TimetableDownloader.EXTRA_FORCE, true)
         startService(intent)
     }
 
@@ -64,7 +64,7 @@     }
 
     override fun onTimetableDownload(result: String?) {
         when (result) {
-            "downloaded" -> {
+            TimetableDownloader.RESULT_DOWNLOADED -> {
                 timetableDownloadReceiver.removeOnTimetableDownloadListener(this)
                 networkStateReceiver.removeOnConnectivityChangeListener(this)
                 startActivity(Intent(this, DashActivity::class.java))




diff --git a/app/src/main/java/ml/adamsprogs/bimba/activities/StopActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/activities/StopActivity.kt
index c9ff27e2028878e4a1d07fdc8da4fbf07b8cb0c8..3f1c27bd741334890ffc27d29a3015314e7d8b7c 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/StopActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/StopActivity.kt
@@ -12,13 +12,17 @@ import android.support.v7.widget.*
 import android.support.v4.app.*
 import android.support.v4.view.*
 import android.support.v4.content.res.ResourcesCompat
-import android.util.Log
 
 import ml.adamsprogs.bimba.models.*
 import ml.adamsprogs.bimba.*
 
 
 class StopActivity : AppCompatActivity(), MessageReceiver.OnVmListener {
+
+    companion object {
+        val EXTRA_STOP_ID = "stopId"
+        val EXTRA_STOP_SYMBOL = "stopSymbol"
+    }
 
     private lateinit var stopId: String
     private lateinit var stopSymbol: String
@@ -32,18 +36,15 @@     private var timer = Timer()
     private lateinit var timerTask: TimerTask
     private val context = this
     private val receiver = MessageReceiver()
-    private lateinit var sharedPreferences: SharedPreferences
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_stop)
-        stopId = intent.getStringExtra("stopId")
-        stopSymbol = intent.getStringExtra("stopSymbol")
+        stopId = intent.getStringExtra(EXTRA_STOP_ID)
+        stopSymbol = intent.getStringExtra(EXTRA_STOP_SYMBOL)
 
         val toolbar = findViewById(R.id.toolbar) as Toolbar
         setSupportActionBar(toolbar)
-
-        sharedPreferences = this.getSharedPreferences("ml.adamsprogs.bimba.prefs", Context.MODE_PRIVATE)
 
         createTimerTask()
 
@@ -55,7 +56,7 @@
         viewPager = findViewById(R.id.container) as ViewPager
         tabLayout = findViewById(R.id.tabs) as TabLayout
 
-        sectionsPagerAdapter = SectionsPagerAdapter(supportFragmentManager, createDepartures(stopId))
+        sectionsPagerAdapter = SectionsPagerAdapter(supportFragmentManager, Departure.createDepartures(stopId))
 
         viewPager!!.adapter = sectionsPagerAdapter
         viewPager!!.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabLayout))
@@ -73,19 +74,15 @@             fab.setImageDrawable(ResourcesCompat.getDrawable(context.resources, R.drawable.ic_favourite_empty, this.theme))
         }
 
         fab.setOnClickListener {
-            Log.i("FAB", "Click")
             if (!favourites.has(stopSymbol)) {
-                Log.i("FAB", "Add")
                 val items = ArrayList<HashMap<String, String>>()
                 timetable.getLines(stopId).forEach {
                     val o = HashMap<String, String>()
-                    o["stop"] = stopId
-                    o["line"] = it
+                    o[Favourite.TAG_STOP] = stopId
+                    o[Favourite.TAG_LINE] = it
                     items.add(o)
                 }
-                Log.i("FAB", "Say")
                 favourites.add(stopSymbol, items)
-                Log.i("FAB", "Change")
                 fab.setImageDrawable(ResourcesCompat.getDrawable(context.resources, R.drawable.ic_favourite, this.theme))
             } else {
                 Snackbar.make(it, getString(R.string.stop_already_fav), Snackbar.LENGTH_LONG)
@@ -98,23 +95,29 @@     private fun createTimerTask() {
         timerTask = object : TimerTask() {
             override fun run() {
                 val vmIntent = Intent(context, VmClient::class.java)
-                vmIntent.putExtra("stopId", stopId)
-                vmIntent.putExtra("stopSymbol", stopSymbol)
+                vmIntent.putExtra(VmClient.EXTRA_STOP_SYMBOL, stopSymbol)
                 startService(vmIntent)
             }
         }
     }
 
     private fun prepareOnDownloadListener() {
-        val filter = IntentFilter("ml.adamsprogs.bimba.departuresCreated")
+        val filter = IntentFilter(VmClient.ACTION_DEPARTURES_CREATED)
+        filter.addAction(VmClient.ACTION_NO_DEPARTURES)
         filter.addCategory(Intent.CATEGORY_DEFAULT)
         registerReceiver(receiver, filter)
         receiver.addOnVmListener(context as MessageReceiver.OnVmListener)
     }
 
-    override fun onVm(departures: HashMap<String, ArrayList<Departure>>) {
-        sectionsPagerAdapter?.departures = departures
-        sectionsPagerAdapter?.notifyDataSetChanged()
+    override fun onVm(vmDepartures: ArrayList<Departure>?) {
+        if (timetableType == "departure") {
+            val fullDepartures = Departure.createDepartures(stopId)
+            if (vmDepartures != null) {
+                fullDepartures[today.getMode()] = vmDepartures
+            }
+            sectionsPagerAdapter?.departures = fullDepartures
+            sectionsPagerAdapter?.notifyDataSetChanged()
+        }
     }
 
     private fun selectTodayPage() {
@@ -151,7 +154,7 @@                 timer.cancel()
             } else {
                 timetableType = "departure"
                 item.icon = (ResourcesCompat.getDrawable(resources, R.drawable.ic_timetable_full, this.theme))
-                sectionsPagerAdapter?.departures = createDepartures(stopId)
+                sectionsPagerAdapter?.departures = Departure.createDepartures(stopId)
                 sectionsPagerAdapter?.relativeTime = true
                 sectionsPagerAdapter?.notifyDataSetChanged()
                 scheduleRefresh()
@@ -179,7 +182,7 @@             val layoutManager = LinearLayoutManager(activity)
             val departuresList: RecyclerView = rootView.findViewById(R.id.departuresList) as RecyclerView
             val dividerItemDecoration = DividerItemDecoration(departuresList.context, layoutManager.orientation)
             departuresList.addItemDecoration(dividerItemDecoration)
-            val adapter = DeparturesAdapter(activity, arguments.getStringArrayList("departures").map { fromString(it) },
+            val adapter = DeparturesAdapter(activity, arguments.getStringArrayList("departures").map { Departure.fromString(it) },
                     arguments["relativeTime"] as Boolean)
             departuresList.adapter = adapter
             departuresList.layoutManager = layoutManager
@@ -216,9 +219,9 @@
         override fun getItem(position: Int): Fragment {
             var mode: String? = null
             when (position) {
-                0 -> mode = "workdays"
-                1 -> mode = "saturdays"
-                2 -> mode = "sundays"
+                0 -> mode = Timetable.MODE_WORKDAYS
+                1 -> mode = Timetable.MODE_SATURDAYS
+                2 -> mode = Timetable.MODE_SUNDAYS
             }
             return PlaceholderFragment.newInstance(position + 1, stopId, departures[mode], relativeTime)
         }




diff --git a/app/src/main/java/ml/adamsprogs/bimba/extensions.kt b/app/src/main/java/ml/adamsprogs/bimba/extensions.kt
new file mode 100644
index 0000000000000000000000000000000000000000..59572d65b5f42dcd6f63cfaa7bda08380ff22c3a
--- /dev/null
+++ b/app/src/main/java/ml/adamsprogs/bimba/extensions.kt
@@ -0,0 +1,12 @@
+package ml.adamsprogs.bimba
+
+import ml.adamsprogs.bimba.models.Timetable
+import java.util.*
+
+internal fun Calendar.getMode(): String {
+    when (this.get(Calendar.DAY_OF_WEEK)) {
+        Calendar.SUNDAY -> return Timetable.MODE_SUNDAYS
+        Calendar.SATURDAY -> return Timetable.MODE_SATURDAYS
+        else -> return Timetable.MODE_WORKDAYS
+    }
+}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/Departure.kt b/app/src/main/java/ml/adamsprogs/bimba/models/Departure.kt
index aac1cd0c15f12c8e01e03ab340e87b4c23ca52d1..97a303f74d08250922cae1bc1c2d08b16a0ad609 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/Departure.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/Departure.kt
@@ -1,10 +1,6 @@
 package ml.adamsprogs.bimba.models
 
-fun fromString(string: String): Departure {
-    val array = string.split("|")
-    return Departure(array[0], array[1], array[2], array[3] == "1", array[4], array[5],
-            array[6] == "true", array[7] == "true", array[8] == "true")
-}
+import java.util.*
 
 data class Departure(val line: String, val mode: String, val time: String, val lowFloor: Boolean,
                      val modification: String?, val direction: String, val vm: Boolean = false,
@@ -12,5 +8,58 @@                      var tomorrow: Boolean = false, val onStop: Boolean = false) {
 
     override fun toString(): String {
         return "$line|$mode|$time|$lowFloor|$modification|$direction|$vm|$tomorrow|$onStop"
+    }
+
+    fun copy(): Departure {
+        return Departure.fromString(this.toString())
+    }
+
+    companion object {
+        private fun filterDepartures(departures: List<Departure>?): ArrayList<Departure> {
+            val filtered = ArrayList<Departure>()
+            val lines = HashMap<String, Int>()
+            val now = Calendar.getInstance()
+            for (departure in departures!!) {
+                val time = Calendar.getInstance()
+                time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(departure.time.split(":")[0]))
+                time.set(Calendar.MINUTE, Integer.parseInt(departure.time.split(":")[1]))
+                time.set(Calendar.SECOND, 0)
+                time.set(Calendar.MILLISECOND, 0)
+                if (departure.tomorrow)
+                    time.add(Calendar.DAY_OF_MONTH, 1)
+                var lineExistedTimes = lines[departure.line]
+                if ((now.before(time) || now == time) && lineExistedTimes ?: 0 < 3) {
+                    lineExistedTimes = (lineExistedTimes ?: 0) + 1
+                    lines[departure.line] = lineExistedTimes
+                    filtered.add(departure)
+                }
+            }
+            return filtered
+        }
+
+        fun createDepartures(stopId: String): HashMap<String, ArrayList<Departure>> {
+            val timetable = Timetable.getTimetable()
+            val departures = timetable.getStopDepartures(stopId)
+            val moreDepartures = timetable.getStopDepartures(stopId)
+            val rolledDepartures = HashMap<String, ArrayList<Departure>>()
+
+            for ((_, tomorrowDepartures) in moreDepartures!!) {
+                tomorrowDepartures.forEach { it.tomorrow = true }
+            }
+
+            for ((mode, _) in departures!!) {
+                rolledDepartures[mode] = (departures[mode] as ArrayList<Departure> +
+                        moreDepartures[mode] as ArrayList<Departure>) as ArrayList<Departure>
+                rolledDepartures[mode] = filterDepartures(rolledDepartures[mode])
+            }
+
+            return rolledDepartures
+        }
+
+        fun fromString(string: String): Departure {
+            val array = string.split("|")
+            return Departure(array[0], array[1], array[2], array[3] == "1", array[4], array[5],
+                    array[6] == "true", array[7] == "true", array[8] == "true")
+        }
     }
 }
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/DeparturesAdapter.kt b/app/src/main/java/ml/adamsprogs/bimba/models/DeparturesAdapter.kt
index 0b9376f1f9ef371b34511a3682bec683a909c3b6..c175a6e11d1209aa827274f6484acc3e8ce1c561 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/DeparturesAdapter.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/DeparturesAdapter.kt
@@ -12,47 +12,6 @@ import android.view.LayoutInflater
 import ml.adamsprogs.bimba.Declinator
 import java.util.*
 
-fun filterDepartures(departures: List<Departure>?): ArrayList<Departure> {
-    val filtered = ArrayList<Departure>()
-    val lines = HashMap<String, Int>()
-    val now = Calendar.getInstance()
-    for (departure in departures!!) {
-        val time = Calendar.getInstance()
-        time.set(Calendar.HOUR_OF_DAY, Integer.parseInt(departure.time.split(":")[0]))
-        time.set(Calendar.MINUTE, Integer.parseInt(departure.time.split(":")[1]))
-        time.set(Calendar.SECOND, 0)
-        time.set(Calendar.MILLISECOND, 0)
-        if (departure.tomorrow)
-            time.add(Calendar.DAY_OF_MONTH, 1)
-        var lineExistedTimes = lines[departure.line]
-        if ((now.before(time) || now == time) && lineExistedTimes ?: 0 < 3) {
-            lineExistedTimes = (lineExistedTimes ?: 0) + 1
-            lines[departure.line] = lineExistedTimes
-            filtered.add(departure)
-        }
-    }
-    return filtered
-}
-
-fun createDepartures(stopId: String): HashMap<String, ArrayList<Departure>> {
-    val timetable = Timetable.getTimetable()
-    val departures = timetable.getStopDepartures(stopId)
-    val moreDepartures = timetable.getStopDepartures(stopId)
-    val rolledDepartures = HashMap<String, ArrayList<Departure>>()
-
-    for ((_, tomorrowDepartures) in moreDepartures!!) {
-        tomorrowDepartures.forEach { it.tomorrow = true }
-    }
-
-    for ((mode, _) in departures!!) {
-        rolledDepartures[mode] = (departures[mode] as ArrayList<Departure> +
-                moreDepartures[mode] as ArrayList<Departure>) as ArrayList<Departure>
-        rolledDepartures[mode] = filterDepartures(rolledDepartures[mode])
-    }
-
-    return rolledDepartures
-}
-
 class DeparturesAdapter(val context: Context, val departures: List<Departure>, val relativeTime: Boolean) :
         RecyclerView.Adapter<DeparturesAdapter.ViewHolder>() {
     override fun getItemCount(): Int {




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/Favourite.kt b/app/src/main/java/ml/adamsprogs/bimba/models/Favourite.kt
index cf116c5fd6d84d9c9505a2d76a1edced6d53f8a0..976c01548a1079143e8f4ccbe5e8270fa4e1d462 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/Favourite.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/Favourite.kt
@@ -3,6 +3,7 @@
 import android.os.Parcel
 import android.os.Parcelable
 import android.util.Log
+import ml.adamsprogs.bimba.getMode
 import java.util.*
 import kotlin.collections.ArrayList
 import kotlin.collections.HashMap
@@ -10,7 +11,7 @@
 class Favourite : Parcelable {
     var name: String
     var timetables: ArrayList<HashMap<String, String>>
-    private var oneDayDepartures:ArrayList<HashMap<String, ArrayList<Departure>>>? = null
+    private var oneDayDepartures: ArrayList<HashMap<String, ArrayList<Departure>>>? = null
 
     constructor(parcel: Parcel) {
         val array = ArrayList<String>()
@@ -18,8 +19,8 @@         parcel.readStringList(array)
         val timetables = ArrayList<HashMap<String, String>>()
         for (row in array) {
             val element = HashMap<String, String>()
-            element["stop"] = row.split("|")[0]
-            element["line"] = row.split("|")[1]
+            element[TAG_STOP] = row.split("|")[0]
+            element[TAG_LINE] = row.split("|")[1]
             timetables.add(element)
         }
         this.name = parcel.readString()
@@ -36,7 +37,7 @@         return 105
     }
 
     override fun writeToParcel(dest: Parcel?, flags: Int) {
-        val parcel = timetables.map { "${it["stop"]}|${it["line"]}" }
+        val parcel = timetables.map { "${it[TAG_STOP]}|${it[TAG_LINE]}" }
         dest?.writeStringList(parcel)
         dest?.writeString(name)
     }
@@ -49,41 +50,34 @@     var nextDeparture: Departure? = null
         get() {
             if (timetables.isEmpty())
                 return null
-            val today: String
-            val tomorrow: String
             val twoDayDepartures = ArrayList<Departure>()
             val now = Calendar.getInstance()
             val departureTime = Calendar.getInstance()
-            when (Calendar.getInstance().get(Calendar.DAY_OF_WEEK)) {
-                Calendar.SUNDAY -> today = "sundays"
-                Calendar.SATURDAY -> today = "saturdays"
-                else -> today = "workdays"
-            }
+            val today = now.getMode()
             val tomorrowCal = Calendar.getInstance()
             tomorrowCal.add(Calendar.DAY_OF_MONTH, 1)
-            when (tomorrowCal.get(Calendar.DAY_OF_WEEK)) {
-                Calendar.SUNDAY -> tomorrow = "sundays"
-                Calendar.SATURDAY -> tomorrow = "saturdays"
-                else -> tomorrow = "workdays"
-            }
+            val tomorrow = tomorrowCal.getMode()
 
             if (oneDayDepartures == null) {
                 oneDayDepartures = ArrayList<HashMap<String, ArrayList<Departure>>>()
-                timetables.mapTo(oneDayDepartures!!) { timetable.getStopDepartures(it["stop"] as String, it["line"])!! }
+                timetables.mapTo(oneDayDepartures!!) { timetable.getStopDepartures(it[TAG_STOP] as String, it[TAG_LINE])!! }
             }
 
             oneDayDepartures!!.forEach {
                 it[today]!!.forEach {
-                    twoDayDepartures.add(fromString(it.toString()))
+                    twoDayDepartures.add(it.copy())
                 }
             }
             oneDayDepartures!!.forEach {
                 it[tomorrow]!!.forEach {
-                    val d = fromString(it.toString())
+                    val d = it.copy()
                     d.tomorrow = true
                     twoDayDepartures.add(d)
                 }
             }
+
+            if (twoDayDepartures.isEmpty())
+                return null
 
             var minDeparture: Departure = twoDayDepartures[0]
             var minInterval = 24 * 60L
@@ -106,7 +100,7 @@         private set
 
     fun delete(stop: String, line: String) {
         Log.i("ROW", "Favourite deleting $stop, $line")
-        timetables.remove(timetables.find { it["stop"] == stop && it["line"] == line })
+        timetables.remove(timetables.find { it[TAG_STOP] == stop && it[TAG_LINE] == line })
         Log.i("ROW", timetables.toString())
     }
 
@@ -118,5 +112,8 @@
         override fun newArray(size: Int): Array<Favourite?> {
             return arrayOfNulls(size)
         }
+
+        val TAG_STOP = "stop"
+        val TAG_LINE = "line"
     }
 }




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteEditRowAdapter.kt b/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteEditRowAdapter.kt
index b46c27f10bf33ea327cd12ab933e81f578a5c289..336c547c2784a8796b9a6a02c2840ecca6016eb0 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteEditRowAdapter.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteEditRowAdapter.kt
@@ -17,18 +17,18 @@
     override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
         val timetable = Timetable.getTimetable()
         val favourites = FavouriteStorage.getFavouriteStorage()
-        val favouriteElement = timetable.getFavouriteElement(favourite.timetables[position]["stop"]!!,
-                favourite.timetables[position]["line"]!!)
+        val favouriteElement = timetable.getFavouriteElement(favourite.timetables[position][Favourite.TAG_STOP]!!,
+                favourite.timetables[position][Favourite.TAG_LINE]!!)
         holder?.rowTextView?.text = favouriteElement
         holder?.splitButton?.setOnClickListener {
-            favourites.detach(favourite.name, favourite.timetables[position]["stop"]!!,
-                    favourite.timetables[position]["line"]!!, favouriteElement!!)
+            favourites.detach(favourite.name, favourite.timetables[position][Favourite.TAG_STOP]!!,
+                    favourite.timetables[position][Favourite.TAG_LINE]!!, favouriteElement!!)
             favourite = favourites.favourites[favourite.name]!!
             notifyDataSetChanged()
         }
         holder?.deleteButton?.setOnClickListener {
-            favourites.delete(favourite.name, favourite.timetables[position]["stop"]!!,
-                    favourite.timetables[position]["line"]!!)
+            favourites.delete(favourite.name, favourite.timetables[position][Favourite.TAG_STOP]!!,
+                    favourite.timetables[position][Favourite.TAG_LINE]!!)
             favourite = favourites.favourites[favourite.name]!!
             notifyDataSetChanged()
         }




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteStorage.kt b/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteStorage.kt
index 7be084c70a618c7078fa944e579a7e9a8dfcd8f0..533ed3c316d3fbec75ca55c2163f07da656a54f9 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteStorage.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteStorage.kt
@@ -37,8 +37,8 @@         for ((name, jsonTimetables) in favouritesMap.entrySet()) {
             val timetables = ArrayList<HashMap<String, String>>()
             for (jsonTimetable in jsonTimetables.asJsonArray) {
                 val timetable = HashMap<String, String>()
-                timetable["stop"] = jsonTimetable.asJsonObject["stop"].asString
-                timetable["line"] = jsonTimetable.asJsonObject["line"].asString
+                timetable[Favourite.TAG_STOP] = jsonTimetable.asJsonObject[Favourite.TAG_STOP].asString
+                timetable[Favourite.TAG_LINE] = jsonTimetable.asJsonObject[Favourite.TAG_LINE].asString
                 timetables.add(timetable)
             }
             favourites[name] = Favourite(name, timetables)
@@ -77,8 +77,8 @@         for ((name, favourite) in favourites) {
             val timetables = JsonArray()
             for (timetable in favourite.timetables) {
                 val element = JsonObject()
-                element.addProperty("stop", timetable["stop"])
-                element.addProperty("line", timetable["line"])
+                element.addProperty(Favourite.TAG_STOP, timetable[Favourite.TAG_STOP])
+                element.addProperty(Favourite.TAG_LINE, timetable[Favourite.TAG_LINE])
                 timetables.add(element)
             }
             rootObject.add(name, timetables)
@@ -92,8 +92,8 @@     }
 
     fun detach(name: String, stop: String, line: String, newName: String) {
         val element = HashMap<String, String>()
-        element["stop"] = stop
-        element["line"] = line
+        element[Favourite.TAG_STOP] = stop
+        element[Favourite.TAG_LINE] = line
         val array = ArrayList<HashMap<String, String>>()
         array.add(element)
         favourites[newName] = Favourite(newName, array)




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/FavouritesAdapter.kt b/app/src/main/java/ml/adamsprogs/bimba/models/FavouritesAdapter.kt
index fd1c29d7ed811d15bd86d656a267d47037cb5e71..2a3f07ea66f19f36ce4f26f53fc6ffe600ac762c 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/FavouritesAdapter.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/FavouritesAdapter.kt
@@ -69,7 +69,7 @@                 if (nextDeparture.tomorrow)
                     departureTime.add(Calendar.DAY_OF_MONTH, 1)
                 val interval = ((departureTime.timeInMillis - now.timeInMillis) / (1000 * 60))
                 Log.i("Interval", "$interval")
-                nextDepartureText = context.getString(Declinator.decline(interval), interval.toString()) // fixme -1
+                nextDepartureText = context.getString(Declinator.decline(interval), interval.toString())
                 nextDepartureLineText = context.getString(R.string.departure_to_line, nextDeparture.line, nextDeparture.direction)
             } else {
                 nextDepartureText = context.getString(R.string.no_next_departure)




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt b/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt
index a72e4d39081641a2cd05c084aea9b01cbd285c34..fb449ce4a9022308d23a7305aa12aeae0546c4cf 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt
@@ -8,9 +8,13 @@ import java.io.File
 
 class Timetable private constructor() {
     companion object {
+        val version = 1
+        val MODE_WORKDAYS = "workdays"
+        val MODE_SATURDAYS = "saturdays"
+        val MODE_SUNDAYS = "sundays"
         private var timetable: Timetable? = null
 
-        fun getTimetable(context: Context? = null, force: Boolean = false): Timetable {
+        fun getTimetable(context: Context? = null, force: Boolean = false): Timetable{
             if (timetable == null || force)
                 if (context != null) {
                     val db: SQLiteDatabase?
@@ -83,9 +87,9 @@                 "substr('0'||minute, -2) as time, lowFloor, modification, headsign from departures join " +
                 "timetables on(timetable_id = timetables.id) join lines on(line_id = lines.id) where " +
                 "stop_id = ? $andLine order by mode, time;", listOf(stopId).toTypedArray())
         val departures = HashMap<String, ArrayList<Departure>>()
-        departures.put("workdays", ArrayList())
-        departures.put("saturdays", ArrayList())
-        departures.put("sundays", ArrayList())
+        departures.put(MODE_WORKDAYS, ArrayList())
+        departures.put(MODE_SATURDAYS, ArrayList())
+        departures.put(MODE_SUNDAYS, ArrayList())
         while (cursor.moveToNext()) {
             departures[cursor.getString(1)]?.add(Departure(cursor.getString(0),
                     cursor.getString(1), cursor.getString(2), cursor.getInt(3) == 1,




diff --git a/app/src/main/res/layout/activity_dash.xml b/app/src/main/res/layout/activity_dash.xml
index 37ba2c615b1ac3bc0bbb913935e0aa79e5f562b0..cc390f75452ce75bfe33423cf398c1477d683924 100644
--- a/app/src/main/res/layout/activity_dash.xml
+++ b/app/src/main/res/layout/activity_dash.xml
@@ -29,20 +29,6 @@                 app:layout_scrollFlags="scroll|enterAlways"
                 app:popupTheme="@style/AppTheme.PopupOverlay" />
         </android.support.design.widget.AppBarLayout>
 
-        <com.arlib.floatingsearchview.FloatingSearchView
-            android:id="@+id/search_view"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            app:floatingSearch_close_search_on_keyboard_dismiss="true"
-            app:floatingSearch_leftActionMode="showHamburger"
-            app:floatingSearch_searchBarMarginLeft="16dp"
-            app:floatingSearch_searchBarMarginRight="16dp"
-            app:floatingSearch_searchBarMarginTop="16dp"
-            app:floatingSearch_searchHint="@string/search_placeholder"
-            app:floatingSearch_showSearchKey="false"
-            app:floatingSearch_suggestionsListAnimDuration="250" />
-
-
         <android.support.v7.widget.RecyclerView
             android:id="@+id/favouritesList"
             android:layout_width="match_parent"
@@ -56,6 +42,19 @@             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toTopOf="parent" />
+
+        <com.arlib.floatingsearchview.FloatingSearchView
+            android:id="@+id/search_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            app:floatingSearch_close_search_on_keyboard_dismiss="true"
+            app:floatingSearch_leftActionMode="showHamburger"
+            app:floatingSearch_searchBarMarginLeft="16dp"
+            app:floatingSearch_searchBarMarginRight="16dp"
+            app:floatingSearch_searchBarMarginTop="16dp"
+            app:floatingSearch_searchHint="@string/search_placeholder"
+            app:floatingSearch_showSearchKey="false"
+            app:floatingSearch_suggestionsListAnimDuration="250" />
 
     </android.support.constraint.ConstraintLayout>