Bimba.git

commit 61a9ed8217e9a1eb727af588895a7422824b1f9d

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

Merge branch 'v2.1'

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


diff --git a/CHANGELOG.rst b/CHANGELOG.rst
new file mode 100644
index 0000000000000000000000000000000000000000..e8b4d3b6abaf9763cb998eb01d51790d5e3803ce
--- /dev/null
+++ b/CHANGELOG.rst
@@ -0,0 +1,73 @@
+Changelog
+#########
+
+All notable changes to this project will be documented in this file.
+
+The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_`, using ReStructuredText instead of Markdown, and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_.
+
+[Unreleased]
+============
+
+Added
+-----
+
++ logging and reporting crashes
++ history of frequently searched stops
++ retry buttons
++ caching favourite
++ update info in APK releases
++ day/night setting – auto, always day, always night
++ trip planning
++ full timetable online
++ free train departures
++ searching by lines
++ city bike stations
+
+Changed
+-------
+
+* reduce flickering of search results
+* VM messages appear also in favourites (if it contains 1 stop only)
+* ‘no connectivity’ warning only when offline timetable is not present
+
+[2.1] – 2019-02-04
+==================
+
+Added
+-----
+
++ showing empty search result
++ loading in shed selection and stop screen
++ VM messages
+
+Changed
+-------
+
+* search bar
+* empty departures state
+* ‘now’ departure is ‘in a moment’ if the vehicle is not on-stop
+* sorting departures: on-stop at the top
+* sorting search results by similarity
+
+[2.0] – 2018-09-21
+==================
+
+Added
+-----
+
++ official timetable from ZTM
+
+Changed
+-------
+
+* VM can be used without offline timetable
+* offline timetable uses exact dates (instead of workdays/saturdays/holidays)
+* VM is quicker and is more reliable (as it’s computed in the same way as offline departures)
+* favourites rewritten from scratch
+* app is movable to external storage
+* new colours—grey and green—fitting new Poznań style
+
+Fixed
+-----
+
+* multiple bug fixes




diff --git a/app/build.gradle b/app/build.gradle
index 60d7ff4dd1cc7f634f2ea63bade2a44142788dd3..9e3ad74ce333488e06b01b657ce46f93ccae8062 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -3,15 +3,15 @@ apply plugin: 'kotlin-android'
 apply plugin: 'kotlin-android-extensions'
 
 android {
-    compileSdkVersion 27
-    buildToolsVersion "28.0.2"
+    compileSdkVersion 28
+    buildToolsVersion '28.0.3'
     defaultConfig {
         applicationId "ml.adamsprogs.bimba"
         minSdkVersion 19
-        targetSdkVersion 27
-        versionCode 15
-        versionName "2.0"
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        targetSdkVersion 28
+        versionCode 16
+        versionName "2.1"
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
         vectorDrawables.useSupportLibrary = true
     }
     buildTypes {
@@ -24,22 +24,26 @@ }
 
 dependencies {
     implementation fileTree(include: ['*.jar'], dir: 'libs')
-    androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
+    androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
         exclude group: 'com.android.support', module: 'support-annotations'
     })
-    implementation 'com.android.support:appcompat-v7:27.1.1'
-    implementation 'com.android.support:cardview-v7:27.1.1'
-    implementation 'com.android.support:design:27.1.1'
-    implementation 'com.android.support:support-vector-drawable:27.1.1'
-    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
+    implementation 'androidx.appcompat:appcompat:1.0.2'
+    implementation 'androidx.cardview:cardview:1.0.0'
+    implementation 'androidx.vectordrawable:vectordrawable:1.0.1'
+    implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3'
+
+    implementation 'com.google.android.material:material:1.1.0-alpha03'
+
     implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
-    implementation 'com.github.arimorty:floatingsearchview:2.1.1'
-    implementation 'com.google.code.gson:gson:2.8.1'
-    implementation 'com.squareup.okhttp3:okhttp:3.8.1'
-    implementation 'io.requery:sqlite-android:3.22.0'
-    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.22.5'
-    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.22.5'
+    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.27.0-eap13'
+    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.27.0-eap13'
+
     testImplementation 'junit:junit:4.12'
+
+    implementation 'io.requery:sqlite-android:3.22.0'
+    implementation 'com.google.code.gson:gson:2.8.2'
+    implementation 'com.squareup.okhttp3:okhttp:3.10.0'
+    implementation 'com.github.mancj:MaterialSearchBar:0.8.1'
 }
 repositories {
     maven { url "https://maven.google.com" }




diff --git a/app/src/androidTest/java/ml/adamsprogs/bimba/ExampleInstrumentedTest.java b/app/src/androidTest/java/ml/adamsprogs/bimba/ExampleInstrumentedTest.java
deleted file mode 100644
index f66a5f890feef1d0355c36fae39cced6e1446d12..0000000000000000000000000000000000000000
--- a/app/src/androidTest/java/ml/adamsprogs/bimba/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package ml.adamsprogs.bimba;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.*;
-
-/**
- * Instrumentation test, which will execute on an Android device.
- *
- * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
-    @Test
-    public void useAppContext() throws Exception {
-        // Context of the app under test.
-        Context appContext = InstrumentationRegistry.getTargetContext();
-
-        assertEquals("ml.adamsprogs.bimba", appContext.getPackageName());
-    }
-}




diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e0b120550519b6a66af16dd4c18b7fe0c5606fcc..25e36bf5433aefd3a374503d0e5d22067650e1ad 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
     package="ml.adamsprogs.bimba"
     android:installLocation="auto">
 
@@ -7,12 +8,12 @@     
     <uses-permission android:name="android.permission.INTERNET" />
 
     <application
-        android:allowBackup="true"
         android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
         android:roundIcon="@mipmap/ic_launcher_round"
-        android:label="@string/app_name"
         android:supportsRtl="true"
-        android:theme="@style/AppTheme">
+        android:theme="@style/AppTheme"
+        tools:ignore="GoogleAppIndexingWarning">
         <activity android:name=".activities.DashActivity" />
 
         <service
@@ -33,15 +34,11 @@                      android:name=".activities.SettingsActivity"
             android:label="@string/title_activity_settings"
             android:parentActivityName=".activities.DashActivity"
-            android:theme="@style/AppTheme" >
+            android:theme="@style/AppTheme">
             <meta-data
                 android:name="android.support.PARENT_ACTIVITY"
                 android:value="ml.adamsprogs.bimba.activities.DashActivity" />
         </activity>
-        <activity
-            android:name=".activities.HelpActivity"
-            android:label="@string/title_activity_help"
-            android:theme="@style/AppTheme" />
 
         <service
             android:name=".datasources.VmService"




diff --git a/app/src/main/java/ml/adamsprogs/bimba/NetworkStateReceiver.kt b/app/src/main/java/ml/adamsprogs/bimba/NetworkStateReceiver.kt
index 2acd1e1eb9dbb95db986e6907c6e07db549c9792..770ba13101e61f4ccd213248bb2af9aadc0f4874 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/NetworkStateReceiver.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/NetworkStateReceiver.kt
@@ -24,14 +24,6 @@             }
         }
     }
 
-    fun addOnConnectivityChangeListener(listener: OnConnectivityChangeListener) {
-        onConnectivityChangeListeners.add(listener)
-    }
-
-    fun removeOnConnectivityChangeListener(listener: OnConnectivityChangeListener) {
-        onConnectivityChangeListeners.remove(listener)
-    }
-
     interface OnConnectivityChangeListener {
         fun onConnectivityChange(connected: Boolean)
     }




diff --git a/app/src/main/java/ml/adamsprogs/bimba/NotificationChannels.kt b/app/src/main/java/ml/adamsprogs/bimba/NotificationChannels.kt
index 8ed8000409fe4705c3161668f926bb0d8d87272d..738003153a01f7d7753f888009f26268299a5f78 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/NotificationChannels.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/NotificationChannels.kt
@@ -3,12 +3,12 @@
 import android.app.NotificationChannel
 import android.app.NotificationManager
 import android.os.Build
-import android.support.annotation.RequiresApi
+import androidx.annotation.RequiresApi
 
 
 class NotificationChannels {
     companion object {
-        val CHANNEL_UPDATES = "updates"
+        const val CHANNEL_UPDATES = "updates"
 
         @RequiresApi(Build.VERSION_CODES.O)
         fun makeChannel(id: String, name: String, manager: NotificationManager) {




diff --git a/app/src/main/java/ml/adamsprogs/bimba/ProviderProxy.kt b/app/src/main/java/ml/adamsprogs/bimba/ProviderProxy.kt
index 45a60fc90e45adb61e3dd09c5a5ed12bbe9b7059..99225e0e49c57da0143579fe0ecda2b31459456e 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/ProviderProxy.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/ProviderProxy.kt
@@ -1,15 +1,20 @@
 package ml.adamsprogs.bimba
 
-import android.content.*
-import kotlinx.coroutines.experimental.android.UI
-import kotlinx.coroutines.experimental.*
-import ml.adamsprogs.bimba.datasources.*
-import ml.adamsprogs.bimba.models.*
-import ml.adamsprogs.bimba.models.suggestions.*
+import android.content.Context
+import android.content.Intent
+import kotlinx.coroutines.*
+import kotlinx.coroutines.android.Main
+import ml.adamsprogs.bimba.datasources.VmClient
+import ml.adamsprogs.bimba.datasources.VmService
+import ml.adamsprogs.bimba.models.Departure
+import ml.adamsprogs.bimba.models.Plate
+import ml.adamsprogs.bimba.models.StopSegment
+import ml.adamsprogs.bimba.models.Timetable
+import ml.adamsprogs.bimba.models.suggestions.GtfsSuggestion
+import ml.adamsprogs.bimba.models.suggestions.StopSuggestion
 import java.util.*
 import kotlin.collections.HashMap
 
-//todo make singleton
 class ProviderProxy(context: Context? = null) {
     private val vmClient = VmClient.getVmClient()
     private var timetable: Timetable = Timetable.getTimetable(context)
@@ -24,17 +29,17 @@         const val MODE_VM = "mode_vm"
     }
 
     fun getSuggestions(query: String = "", callback: (List<GtfsSuggestion>) -> Unit) {
-        launch(UI) {
-            val filtered = withContext(DefaultDispatcher) {
-                suggestions = getStopSuggestions(query) //+ getLineSuggestions(query) //todo<p:v+1> + bike stations, train stations, &c
-                filterSuggestions(query)
+        GlobalScope.launch {
+            suggestions = getStopSuggestions(query) //+ getLineSuggestions(query) //todo<p:v+1> + bike stations, train stations, &c
+            val filtered = filterSuggestions(query)
+            launch(Dispatchers.Main) {
+                callback(filtered)
             }
-            callback(filtered)
         }
     }
 
     private suspend fun getStopSuggestions(query: String): List<StopSuggestion> {
-        val vmSuggestions = withContext(DefaultDispatcher) {
+        val vmSuggestions = withContext(Dispatchers.Default) {
             vmClient.getStops(query)
         }
 
@@ -65,18 +70,27 @@         return result
     }
 
     fun getSheds(name: String, callback: (Map<String, Set<String>>) -> Unit) {
-        launch(UI) {
-            val sheds = withContext(DefaultDispatcher) {
-                val vmSheds = vmClient.getSheds(name)
+        GlobalScope.launch {
+            val vmSheds = vmClient.getSheds(name)
 
-                if (vmSheds.isEmpty() and !timetable.isEmpty()) {
-                    timetable.getHeadlinesForStop(name)
-                } else {
-                    vmSheds
-                }
+            val sheds = if (vmSheds.isEmpty() and !timetable.isEmpty()) {
+                timetable.getHeadlinesForStop(name)
+            } else {
+                vmSheds
             }
 
-            callback(sheds)
+            launch(Dispatchers.Main) {
+                callback(sheds)
+            }
+        }
+    }
+
+    fun getVmMessage(shed: String, callback: (String?) -> Unit) {
+        GlobalScope.launch {
+            val message = vmClient.getMessage(shed)
+            launch(Dispatchers.Main) {
+                callback(message)
+            }
         }
     }
 
@@ -104,7 +118,7 @@         return uuid
     }
 
     private fun constructSegmentDepartures(stopSegments: Set<StopSegment>): Deferred<Map<String, List<Departure>>> {
-        return async {
+        return GlobalScope.async {
             if (timetable.isEmpty())
                 emptyMap()
             else {
@@ -161,10 +175,8 @@
     }
 
     fun fillStopSegment(stopSegment: StopSegment, callback: (StopSegment?) -> Unit) {
-        launch(UI) {
-            withContext(DefaultDispatcher) {
-                callback(fillStopSegment(stopSegment))
-            }
+        GlobalScope.launch {
+            callback(fillStopSegment(stopSegment))
         }
     }
 
@@ -179,10 +191,8 @@             timetable.getHeadlinesForStopCode(stopSegment.stop)
     }
 
     fun getStopName(stopCode: String, callback: (String?) -> Unit) {
-        launch(UI) {
-            withContext(DefaultDispatcher) {
-                callback(getStopName(stopCode))
-            }
+        GlobalScope.launch {
+            callback(getStopName(stopCode))
         }
     }
 
@@ -216,13 +226,13 @@         private var cache: Deferred>>? = null
 
         init {
             receiver.addOnVmListener(this@Request)
-            launch(UI) {
+            GlobalScope.launch {
                 cache = constructSegmentDepartures(segments)
             }
         }
 
         override fun onVm(vmDepartures: Set<Departure>?, plateId: Plate.ID?, stopCode: String, code: Int) {
-            launch(UI) {
+            GlobalScope.launch(Dispatchers.Main) {
                 if ((plateId == null || vmDepartures == null) and (timetable.isEmpty())) {
                     listener.onDeparturesReady(emptyList(), null, code)
                     return@launch




diff --git a/app/src/main/java/ml/adamsprogs/bimba/activities/AppCompatPreferenceActivity.java b/app/src/main/java/ml/adamsprogs/bimba/activities/AppCompatPreferenceActivity.java
index 6e707b84bb48d8df1fabb89d95b2eeea5138d456..d276164afc8be57b1d2a6d4c629670704dd536cf 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/AppCompatPreferenceActivity.java
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/AppCompatPreferenceActivity.java
@@ -1,16 +1,17 @@
 package ml.adamsprogs.bimba.activities;
 
 import android.content.res.Configuration;
-        import android.os.Bundle;
-        import android.preference.PreferenceActivity;
-        import android.support.annotation.LayoutRes;
-        import android.support.annotation.Nullable;
-        import android.support.v7.app.ActionBar;
-        import android.support.v7.app.AppCompatDelegate;
-        import android.support.v7.widget.Toolbar;
-        import android.view.MenuInflater;
-        import android.view.View;
-        import android.view.ViewGroup;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.LayoutRes;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatDelegate;
+import androidx.appcompat.widget.Toolbar;
 
 /**
  * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls




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 e29da9681bc17c52d83898bf9589e5371d4c6a6a..cd714bbfd3e7e604ffb1d83c2e9ee486a2eb482a 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt
@@ -2,49 +2,62 @@ package ml.adamsprogs.bimba.activities
 
 import android.annotation.SuppressLint
 import android.app.Activity
-import android.content.*
-import android.os.*
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.Bundle
 import android.preference.PreferenceManager.getDefaultSharedPreferences
-import android.support.design.widget.*
-import android.support.v4.widget.*
-import android.support.v7.widget.*
-import android.support.v7.app.*
-import android.text.Html
-import android.view.*
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.ActionMode
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
 import android.view.inputmethod.InputMethodManager
-import kotlin.collections.ArrayList
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.navigation.NavigationView
+import com.google.android.material.snackbar.Snackbar
+import com.mancj.materialsearchbar.MaterialSearchBar
+import com.mancj.materialsearchbar.MaterialSearchBar.BUTTON_BACK
+import com.mancj.materialsearchbar.MaterialSearchBar.BUTTON_NAVIGATION
 import kotlinx.android.synthetic.main.activity_dash.*
+import ml.adamsprogs.bimba.*
+import ml.adamsprogs.bimba.collections.FavouriteStorage
+import ml.adamsprogs.bimba.datasources.TimetableDownloader
+import ml.adamsprogs.bimba.datasources.VmService
+import ml.adamsprogs.bimba.models.Departure
+import ml.adamsprogs.bimba.models.Plate
+import ml.adamsprogs.bimba.models.Timetable
+import ml.adamsprogs.bimba.models.adapters.FavouritesAdapter
+import ml.adamsprogs.bimba.models.adapters.SuggestionsAdapter
+import ml.adamsprogs.bimba.models.suggestions.EmptySuggestion
+import ml.adamsprogs.bimba.models.suggestions.GtfsSuggestion
+import ml.adamsprogs.bimba.models.suggestions.LineSuggestion
+import ml.adamsprogs.bimba.models.suggestions.StopSuggestion
+import java.text.DateFormat
 import java.util.*
-import java.text.*
+import kotlin.collections.ArrayList
 
-import ml.adamsprogs.bimba.models.*
-import ml.adamsprogs.bimba.*
-import ml.adamsprogs.bimba.datasources.*
-import ml.adamsprogs.bimba.models.suggestions.*
-import ml.adamsprogs.bimba.models.adapters.*
-import ml.adamsprogs.bimba.collections.*
-
-import com.arlib.floatingsearchview.FloatingSearchView
-import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
-
-//todo<p:1> searchView integration
 class DashActivity : AppCompatActivity(), MessageReceiver.OnTimetableDownloadListener,
-        FavouritesAdapter.OnMenuItemClickListener, FavouritesAdapter.ViewHolder.OnClickListener, ProviderProxy.OnDeparturesReadyListener {
+        FavouritesAdapter.OnMenuItemClickListener, FavouritesAdapter.ViewHolder.OnClickListener, ProviderProxy.OnDeparturesReadyListener, SuggestionsAdapter.OnSuggestionClickListener {
 
     val context: Context = this
     private val receiver = MessageReceiver.getMessageReceiver()
     private lateinit var timetable: Timetable
     private var suggestions: List<GtfsSuggestion>? = null
-    private lateinit var drawerLayout: DrawerLayout
+    private lateinit var drawerLayout: androidx.drawerlayout.widget.DrawerLayout
     private lateinit var drawerView: NavigationView
-    lateinit var favouritesList: RecyclerView
-    lateinit var searchView: FloatingSearchView
+    lateinit var favouritesList: androidx.recyclerview.widget.RecyclerView
+    lateinit var searchView: MaterialSearchBar
     private lateinit var favourites: FavouriteStorage
     private lateinit var adapter: FavouritesAdapter
     private val actionModeCallback = ActionModeCallback()
     private var actionMode: ActionMode? = null
     private var isWarned = false
     private lateinit var providerProxy: ProviderProxy
+    private lateinit var suggestionsAdapter: SuggestionsAdapter
 
     companion object {
         const val REQUEST_EDIT_FAVOURITE = 1
@@ -59,8 +72,6 @@
         providerProxy = ProviderProxy(this)
         timetable = Timetable.getTimetable()
         NetworkStateReceiver.init(this)
-
-        getSuggestions()
 
         prepareFavourites()
 
@@ -90,63 +101,78 @@
         showValidityInDrawer()
 
         searchView = search_view
+        suggestionsAdapter = SuggestionsAdapter(layoutInflater, this, this)
+        searchView.setCustomSuggestionAdapter(suggestionsAdapter)
 
-        searchView.setOnFocusChangeListener(object : FloatingSearchView.OnFocusChangeListener {
-            override fun onFocus() {
-                favouritesList.visibility = View.GONE
-                providerProxy.getSuggestions(searchView.query) {
-                    searchView.swapSuggestions(it)
+        searchView.addTextChangeListener(object : TextWatcher {
+            override fun afterTextChanged(s: Editable?) {
+                if (searchView.isSearchEnabled) {
+                    getSuggestions(s.toString())
                 }
             }
 
-            override fun onFocusCleared() {
-                favouritesList.visibility = View.VISIBLE
+            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
             }
-        })
 
-        searchView.setOnQueryChangeListener { oldQuery, newQuery ->
-            if (oldQuery != "" && newQuery == "")
-                searchView.clearSuggestions()
-            providerProxy.getSuggestions(newQuery) {
-                searchView.swapSuggestions(it)
+            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
             }
-        }
 
-        searchView.setOnSearchListener(object : FloatingSearchView.OnSearchListener {
-            override fun onSuggestionClicked(searchSuggestion: SearchSuggestion) {
-                val imm = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
-                var view = (context as DashActivity).currentFocus
-                if (view == null) {
-                    view = View(context)
-                }
-                imm.hideSoftInputFromWindow(view.windowToken, 0)
-                if (searchSuggestion is StopSuggestion) {
-                    val intent = Intent(context, StopSpecifyActivity::class.java)
-                    intent.putExtra(StopSpecifyActivity.EXTRA_STOP_NAME, searchSuggestion.name)
-                    startActivity(intent)
-                } else if (searchSuggestion is LineSuggestion) {
-                    val intent = Intent(context, LineSpecifyActivity::class.java)
-                    intent.putExtra(LineSpecifyActivity.EXTRA_LINE_ID, searchSuggestion.name)
-                    startActivity(intent)
+        })
+
+        searchView.setOnSearchActionListener(object : MaterialSearchBar.OnSearchActionListener {
+            override fun onButtonClicked(buttonCode: Int) {
+                when (buttonCode) {
+                    BUTTON_NAVIGATION -> {
+                        if (drawerLayout.isDrawerOpen(drawerView))
+                            drawerLayout.closeDrawer(drawerView)
+                        else
+                            drawerLayout.openDrawer(drawerView)
+                    }
+                    BUTTON_BACK -> {
+                        searchView.disableSearch()
+                    }
                 }
             }
 
-            override fun onSearchAction(query: String) {
+            override fun onSearchStateChanged(enabled: Boolean) {
+            }
+
+            override fun onSearchConfirmed(text: CharSequence?) {
+                getSuggestions(text.toString())
             }
         })
+    }
 
-        searchView.setOnBindSuggestionCallback { _, iconView, textView, item, _ ->
-            val suggestion = item as GtfsSuggestion
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-                textView.text = Html.fromHtml(item.body, Html.FROM_HTML_MODE_LEGACY)
-            } else {
-                @Suppress("DEPRECATION")
-                textView.text = Html.fromHtml(item.body)
+    private fun getSuggestions(query: String = "") {
+        providerProxy.getSuggestions(query) { suggestions ->
+            if (!suggestionsAdapter.equals(suggestions)) {
+                if (suggestions.isEmpty()) {
+                    suggestionsAdapter.clearSuggestions()
+                    suggestionsAdapter.addSuggestion(EmptySuggestion())
+                } else {
+                    suggestionsAdapter.updateSuggestions(suggestions, query)
+                }
+                searchView.showSuggestionsList()
             }
-            iconView.setImageDrawable(getDrawable(suggestion.getIcon(), context))
         }
+    }
 
-        searchView.attachNavigationDrawerToMenuButton(drawer_layout as DrawerLayout)
+    override fun onSuggestionClickListener(suggestion: GtfsSuggestion) {
+        val imm = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
+        var view = (context as DashActivity).currentFocus
+        if (view == null) {
+            view = View(context)
+        }
+        imm.hideSoftInputFromWindow(view.windowToken, 0)
+        if (suggestion is StopSuggestion) {
+            val intent = Intent(context, StopSpecifyActivity::class.java)
+            intent.putExtra(StopSpecifyActivity.EXTRA_STOP_NAME, suggestion.name)
+            startActivity(intent)
+        } else if (suggestion is LineSuggestion) {
+            val intent = Intent(context, LineSpecifyActivity::class.java)
+            intent.putExtra(LineSpecifyActivity.EXTRA_LINE_ID, suggestion.name)
+            startActivity(intent)
+        }
     }
 
     override fun onRestart() {
@@ -243,25 +269,19 @@         favourites = FavouriteStorage.getFavouriteStorage(context)
         favourites.forEach {
             it.subscribeForDepartures(this, this)
         }
-        val layoutManager = LinearLayoutManager(context)
+        val layoutManager = androidx.recyclerview.widget.LinearLayoutManager(context)
         favouritesList = favourites_list
         adapter = FavouritesAdapter(context, favourites, this, this)
         favouritesList.adapter = adapter
-        favouritesList.itemAnimator = DefaultItemAnimator()
+        favouritesList.itemAnimator = androidx.recyclerview.widget.DefaultItemAnimator()
         favouritesList.layoutManager = layoutManager
     }
 
     override fun onDeparturesReady(departures: List<Departure>, plateId: Plate.ID?, code: Int) {
-        favouritesList.adapter.notifyDataSetChanged()
+        favouritesList.adapter!!.notifyDataSetChanged()
         showError(drawer_layout, code, this)
     }
 
-    private fun getSuggestions() {
-        providerProxy.getSuggestions {
-            searchView.swapSuggestions(it)
-        }
-    }
-
     private fun prepareListeners() {
         val filter = IntentFilter(TimetableDownloader.ACTION_DOWNLOADED)
         filter.addAction(VmService.ACTION_READY)
@@ -275,12 +295,14 @@         if (getDefaultSharedPreferences(this).getBoolean(getString(R.string.key_timetable_automatic_update), false) or force)
             startService(Intent(context, TimetableDownloader::class.java))
     }
 
-    override fun onBackPressed() { //fixme
+    override fun onBackPressed() {
         if (drawerLayout.isDrawerOpen(drawerView)) {
             drawerLayout.closeDrawer(drawerView)
             return
         }
-        if (!searchView.setSearchFocused(false)) {
+        if (searchView.isSearchEnabled) {
+            searchView.disableSearch()
+        } else {
             super.onBackPressed()
         }
     }
@@ -288,7 +310,7 @@
     override fun onResume() {
         super.onResume()
         adapter.favourites = favourites
-        favouritesList.adapter.notifyDataSetChanged()
+        favouritesList.adapter!!.notifyDataSetChanged()
     }
 
     override fun onDestroy() {
@@ -307,7 +329,7 @@         }
         Snackbar.make(findViewById(R.id.drawer_layout), message, Snackbar.LENGTH_LONG).show()
         if (result == TimetableDownloader.RESULT_FINISHED) {
             timetable = Timetable.getTimetable(this, true)
-            getSuggestions()
+            getSuggestions(searchView.text)
             showValidityInDrawer()
         }
     }
@@ -321,18 +343,18 @@         startActivityForResult(intent, REQUEST_EDIT_FAVOURITE)
         return true
     }
 
-    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
         if (requestCode == REQUEST_EDIT_FAVOURITE) {
             if (resultCode == Activity.RESULT_OK) {
-                val name = data.getStringExtra(EditFavouriteActivity.EXTRA_NEW_NAME)
+                val name = data!!.getStringExtra(EditFavouriteActivity.EXTRA_NEW_NAME)
                 val positionBefore = data.getIntExtra(EditFavouriteActivity.EXTRA_POSITION_BEFORE, -1)
                 //adapter.favourites = favourites.favouritesList
                 if (positionBefore == -1)
-                    favouritesList.adapter.notifyDataSetChanged()
+                    favouritesList.adapter!!.notifyDataSetChanged()
                 else {
                     val positionAfter = favourites.indexOf(name)
-                    favouritesList.adapter.notifyItemChanged(positionBefore)
-                    favouritesList.adapter.notifyItemMoved(positionBefore, positionAfter)
+                    favouritesList.adapter!!.notifyItemChanged(positionBefore)
+                    favouritesList.adapter!!.notifyItemMoved(positionBefore, positionAfter)
                 }
                 adapter[name]?.let {
                     it.unsubscribeFromDepartures(context)
@@ -345,7 +367,7 @@
     override fun delete(name: String): Boolean {
         favourites.delete(name)
         //adapter.favourites = favourites.favouritesList
-        favouritesList.adapter.notifyItemRemoved(favourites.indexOf(name))
+        favouritesList.adapter!!.notifyItemRemoved(favourites.indexOf(name))
         return true
     }
 




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 d5c812f0e1dccc101297f852d23cd0756d39f300..c372b185980e24b33d0c621529557d547276aa91 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/EditFavouriteActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/EditFavouriteActivity.kt
@@ -1,18 +1,15 @@
 package ml.adamsprogs.bimba.activities
 
-import android.support.v7.app.AppCompatActivity
+import android.app.Activity
+import android.content.Intent
 import android.os.Bundle
-import android.support.v7.widget.DividerItemDecoration
-import android.support.v7.widget.LinearLayoutManager
 import android.widget.EditText
+import androidx.appcompat.app.AppCompatActivity
+import kotlinx.android.synthetic.main.activity_edit_favourite.*
 import ml.adamsprogs.bimba.R
+import ml.adamsprogs.bimba.collections.FavouriteStorage
 import ml.adamsprogs.bimba.models.Favourite
 import ml.adamsprogs.bimba.models.adapters.FavouriteEditRowAdapter
-import ml.adamsprogs.bimba.collections.FavouriteStorage
-import kotlinx.android.synthetic.main.activity_edit_favourite.*
-import android.app.Activity
-import android.content.Intent
-
 
 
 class EditFavouriteActivity : AppCompatActivity() {
@@ -38,9 +35,9 @@             finish()
         favourites = FavouriteStorage.getFavouriteStorage(this)
 
         val recyclerView = favourite_edit_list
-        val layoutManager = LinearLayoutManager(this)
+        val layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this)
         recyclerView!!.layoutManager = layoutManager
-        val dividerItemDecoration = DividerItemDecoration(this, layoutManager.orientation)
+        val dividerItemDecoration = androidx.recyclerview.widget.DividerItemDecoration(this, layoutManager.orientation)
         recyclerView.addItemDecoration(dividerItemDecoration)
         recyclerView.adapter = FavouriteEditRowAdapter(favourite!!, favourite_edit_loading, favourite_edit_list)
         setSupportActionBar(toolbar)




diff --git a/app/src/main/java/ml/adamsprogs/bimba/activities/HelpActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/activities/HelpActivity.kt
deleted file mode 100644
index 75dafa19a28bb5eef595683e4f5de44c3eeb878e..0000000000000000000000000000000000000000
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/HelpActivity.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package ml.adamsprogs.bimba.activities
-
-import android.os.Bundle
-import android.support.v7.app.AppCompatActivity
-import kotlinx.android.synthetic.main.activity_help.*
-import ml.adamsprogs.bimba.R
-
-class HelpActivity : AppCompatActivity() {
-
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
-        setContentView(R.layout.activity_help)
-        setSupportActionBar(toolbar)
-    }
-}




diff --git a/app/src/main/java/ml/adamsprogs/bimba/activities/LineSpecifyActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/activities/LineSpecifyActivity.kt
index e33d1edd5cf5253071bf0936ca77d35211ce2426..79f7b0e63feb2b36c529c64ba63418a83a215ff6 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/LineSpecifyActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/LineSpecifyActivity.kt
@@ -1,17 +1,15 @@
 package ml.adamsprogs.bimba.activities
 
-import android.support.design.widget.TabLayout
-import android.support.v7.app.AppCompatActivity
-
-import android.support.v4.app.*
 import android.os.Bundle
-import android.view.*
-
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.tabs.TabLayout
 import kotlinx.android.synthetic.main.activity_line_specify.*
 import kotlinx.android.synthetic.main.fragment_line_specify.view.*
 import ml.adamsprogs.bimba.R
 import ml.adamsprogs.bimba.models.Timetable
-import ml.adamsprogs.bimba.models.gtfs.*
 
 class LineSpecifyActivity : AppCompatActivity() {
     companion object {
@@ -44,16 +42,16 @@         container.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs))
         tabs.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(container))
     }
 
-    inner class SectionsPagerAdapter(fm: FragmentManager, private val graphs: Array<Timetable.TripGraph>) : FragmentPagerAdapter(fm) {
+    inner class SectionsPagerAdapter(fm: androidx.fragment.app.FragmentManager, private val graphs: Array<Timetable.TripGraph>) : androidx.fragment.app.FragmentPagerAdapter(fm) {
 
-        override fun getItem(position: Int): Fragment {
+        override fun getItem(position: Int): androidx.fragment.app.Fragment {
             return PlaceholderFragment.newInstance(position + 1, graphs[position])
         }
 
         override fun getCount() = 2
     }
 
-    class PlaceholderFragment : Fragment() {
+    class PlaceholderFragment : androidx.fragment.app.Fragment() {
 
         override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                                   savedInstanceState: Bundle?): View? {




diff --git a/app/src/main/java/ml/adamsprogs/bimba/activities/SettingsActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/activities/SettingsActivity.kt
index cc70df014cd592d07c7c9dcf553dc13886a552f1..a05be9afc33eba5fe1030e4538f9330b44ff01c7 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/SettingsActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/SettingsActivity.kt
@@ -2,7 +2,7 @@ package ml.adamsprogs.bimba.activities
 
 import android.preference.*
 import android.os.Bundle
-import android.support.v4.app.NavUtils
+import androidx.core.app.NavUtils
 import android.view.MenuItem
 import kotlinx.android.synthetic.main.activity_settings.*
 




diff --git a/app/src/main/java/ml/adamsprogs/bimba/activities/SplashActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/activities/SplashActivity.kt
index e7c3e0085a8ad06f180703cd533e0848579b9752..ff18b865168fce18b51c8abb639f0b194051a12d 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/SplashActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/SplashActivity.kt
@@ -1,12 +1,9 @@
 package ml.adamsprogs.bimba.activities
 
-import android.support.v7.app.AppCompatActivity
+import android.content.Intent
 import android.os.Bundle
-import android.content.Intent
-import android.database.sqlite.SQLiteCantOpenDatabaseException
-import android.support.v7.app.AppCompatDelegate
-import ml.adamsprogs.bimba.models.Timetable
-import java.io.FileNotFoundException
+import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.app.AppCompatDelegate
 
 
 class SplashActivity : AppCompatActivity() {




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 8aeed16739529be5f2f5f927660fa12f76fd659f..2e0129cd1f3e89e7c1bfcc7cc0eee5458afab98c 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/StopActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/StopActivity.kt
@@ -1,22 +1,35 @@
 package ml.adamsprogs.bimba.activities
 
-import android.content.*
-import android.support.design.widget.*
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.Build
 import android.os.Bundle
-import android.view.*
-import android.support.v4.content.res.ResourcesCompat
-import android.support.v7.app.AppCompatActivity
-import android.support.v7.widget.*
+import android.text.Html
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
 import android.widget.AdapterView
-
-import java.util.Calendar
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.res.ResourcesCompat
+import com.google.android.material.snackbar.Snackbar
 import kotlinx.android.synthetic.main.activity_stop.*
+import kotlinx.android.synthetic.main.banner.*
 import ml.adamsprogs.bimba.*
 import ml.adamsprogs.bimba.collections.FavouriteStorage
-import ml.adamsprogs.bimba.datasources.*
-import ml.adamsprogs.bimba.models.*
+import ml.adamsprogs.bimba.datasources.TimetableDownloader
+import ml.adamsprogs.bimba.datasources.VmService
+import ml.adamsprogs.bimba.models.Departure
+import ml.adamsprogs.bimba.models.Favourite
+import ml.adamsprogs.bimba.models.Plate
+import ml.adamsprogs.bimba.models.StopSegment
 import ml.adamsprogs.bimba.models.adapters.DeparturesAdapter
 import ml.adamsprogs.bimba.models.adapters.ServiceAdapter
+import java.util.Calendar
+import kotlin.collections.HashMap
+import kotlin.collections.HashSet
+import kotlin.collections.set
 
 class StopActivity : AppCompatActivity(), MessageReceiver.OnTimetableDownloadListener, ProviderProxy.OnDeparturesReadyListener {
     companion object {
@@ -26,10 +39,6 @@         const val EXTRA_FAVOURITE = "favourite"
         const val SOURCE_TYPE = "sourceType"
         const val SOURCE_TYPE_STOP = "stop"
         const val SOURCE_TYPE_FAV = "favourite"
-
-        const val MODE_WORKDAYS = 0
-        const val MODE_SATURDAYS = 1
-        const val MODE_SUNDAYS = 2
 
         const val TIMETABLE_TYPE_DEPARTURE = "timetable_type_departure"
         const val TIMETABLE_TYPE_FULL = "timetable_type_full"
@@ -71,20 +80,44 @@         }
 
         showFab()
 
-        val layoutManager = LinearLayoutManager(this)
-        departuresList.addItemDecoration(DividerItemDecoration(departuresList.context, layoutManager.orientation))
+        val layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this)
+        departuresList.addItemDecoration(androidx.recyclerview.widget.DividerItemDecoration(departuresList.context, layoutManager.orientation))
         departuresList.adapter = DeparturesAdapter(this, null, true)
         adapter = departuresList.adapter as DeparturesAdapter
         departuresList.layoutManager = layoutManager
 
-        departuresList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
-            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {}
-            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+        departuresList.addOnScrollListener(object : androidx.recyclerview.widget.RecyclerView.OnScrollListener() {
+            override fun onScrollStateChanged(recyclerView: androidx.recyclerview.widget.RecyclerView, newState: Int) {}
+            override fun onScrolled(recyclerView: androidx.recyclerview.widget.RecyclerView, dx: Int, dy: Int) {
                 updateFabVisibility(dy)
                 super.onScrolled(recyclerView, dx, dy)
             }
         })
 
+        if (stopCode != "")
+            providerProxy.getVmMessage(stopCode) { message ->
+                if (message != null) {
+                    val rendered =
+                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+                                Html.fromHtml(message, Html.FROM_HTML_MODE_LEGACY)
+                            } else {
+                                @Suppress("DEPRECATION")
+                                Html.fromHtml(message)
+                            }
+
+                    banner.visibility = View.VISIBLE
+                    banner_text.text = rendered
+                    banner_more.setOnClickListener {
+                        AlertDialog.Builder(context)
+                                .setPositiveButton(context.getText(android.R.string.ok))
+                                { dialog: DialogInterface, _: Int -> dialog.cancel() }
+                                .setCancelable(true)
+                                .setMessage(rendered)
+                                .create().show()
+                    }
+                }
+            }
+
         prepareOnDownloadListener()
         subscribeForDepartures()
     }
@@ -138,6 +171,7 @@             favourite!!.subscribeForDepartures(this, context)
     }
 
     override fun onDeparturesReady(departures: List<Departure>, plateId: Plate.ID?, code: Int) {
+        progressBar.visibility = View.GONE
         showError(stop_layout, code, this)
         if (plateId == null) {
             this.departures.clear()
@@ -149,6 +183,15 @@         }
         if (timetableType == TIMETABLE_TYPE_FULL)
             return
         refreshAdapter()
+        if (adapter.departures?.isEmpty() != false) {
+            emptyStateIcon.visibility = View.VISIBLE
+            emptyStateText.visibility = View.VISIBLE
+            departuresList.visibility = View.GONE
+        } else {
+            emptyStateIcon.visibility = View.GONE
+            emptyStateText.visibility = View.GONE
+            departuresList.visibility = View.VISIBLE
+        }
     }
 
     private fun refreshAdapter() {
@@ -158,7 +201,7 @@             adapter.departures = fullDepartures[(dateSpinner.selectedItem as ServiceAdapter.RowItem).service]
         } else {
             val now = Calendar.getInstance()
             val seconds = now.secondsAfterMidnight()
-            adapter.departures = this.departures.flatMap { it.value }.sortedBy { it.timeTill(seconds) }
+            adapter.departures = this.departures.flatMap { it.value }.sortedBy { (if (it.onStop) 0 else 1) * 172800 + it.timeTill(seconds) }  // todo sorted by also onStop
         }
         adapter.notifyDataSetChanged()
     }




diff --git a/app/src/main/java/ml/adamsprogs/bimba/activities/StopSpecifyActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/activities/StopSpecifyActivity.kt
index a81d3536efc67b4b34a1b4b77337be6ba2379288..e2db35f26607e62e800fa323755b65b7bab5d34e 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/StopSpecifyActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/StopSpecifyActivity.kt
@@ -1,18 +1,16 @@
 package ml.adamsprogs.bimba.activities
 
+import android.content.Context
 import android.content.Intent
-import android.support.v7.app.AppCompatActivity
 import android.os.Bundle
+import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import kotlinx.android.synthetic.main.activity_stop_specify.*
-import ml.adamsprogs.bimba.R
-import android.content.Context
 import android.widget.TextView
-import android.support.v7.widget.LinearLayoutManager
-import android.support.v7.widget.RecyclerView
-import android.view.LayoutInflater
+import androidx.appcompat.app.AppCompatActivity
+import kotlinx.android.synthetic.main.activity_stop_specify.*
 import ml.adamsprogs.bimba.ProviderProxy
+import ml.adamsprogs.bimba.R
 
 class StopSpecifyActivity : AppCompatActivity() {
 
@@ -27,8 +25,9 @@
         val name = intent.getStringExtra(EXTRA_STOP_NAME)
         val providerProxy = ProviderProxy(this)
         providerProxy.getSheds(name) {
-            val layoutManager = LinearLayoutManager(this)
-            val departuresList: RecyclerView = list_view
+            progressBar.visibility = View.GONE
+            val layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this)
+            val departuresList: androidx.recyclerview.widget.RecyclerView = list_view
 
             departuresList.adapter = ShedAdapter(this, it, name)
             departuresList.layoutManager = layoutManager
@@ -42,7 +41,7 @@         supportActionBar?.title = name
     }
 
     class ShedAdapter(val context: Context, private val values: Map<String, Set<String>>, private val stopName: String) :
-            RecyclerView.Adapter<ShedAdapter.ViewHolder>() {
+            androidx.recyclerview.widget.RecyclerView.Adapter<ShedAdapter.ViewHolder>() {
         override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
             val context = parent.context
             val inflater = LayoutInflater.from(context)
@@ -64,11 +63,11 @@                 context.startActivity(intent)
             }
             holder.stopCode.text = values.keys.sorted()[position]
             holder.stopHeadlines.text = values.entries.sortedBy { it.key }[position].value
-                    .sortedBy { it.split(" → ")[0].toInt() }
+                    .sortedBy { it.split(" → ")[0].padStart(4, '0') }
                     .joinToString()
         }
 
-        inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+        inner class ViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) {
             val root = itemView.findViewById<View>(R.id.shed_row)!!
             val stopCode: TextView = itemView.findViewById(R.id.stop_code)
             val stopHeadlines: TextView = itemView.findViewById(R.id.stop_headlines)




diff --git a/app/src/main/java/ml/adamsprogs/bimba/collections/FavouriteStorage.kt b/app/src/main/java/ml/adamsprogs/bimba/collections/FavouriteStorage.kt
index b7d96b89b3fd738796ade8db57b8539e794ba59e..38292650494637faefb6a23f1b8b6b6050752dbb 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/collections/FavouriteStorage.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/collections/FavouriteStorage.kt
@@ -1,10 +1,20 @@
 package ml.adamsprogs.bimba.collections
 
-import android.content.*
+import android.content.Context
+import android.content.SharedPreferences
 import com.google.gson.*
-import ml.adamsprogs.bimba.*
-import ml.adamsprogs.bimba.models.*
+import ml.adamsprogs.bimba.models.Departure
+import ml.adamsprogs.bimba.models.Favourite
+import ml.adamsprogs.bimba.models.Plate
+import ml.adamsprogs.bimba.models.StopSegment
+import ml.adamsprogs.bimba.secondsAfterMidnight
 import java.util.Calendar
+import kotlin.collections.ArrayList
+import kotlin.collections.HashMap
+import kotlin.collections.HashSet
+import kotlin.collections.component1
+import kotlin.collections.component2
+import kotlin.collections.set
 
 
 class FavouriteStorage private constructor(context: Context) : Iterable<Favourite> {
@@ -31,13 +41,13 @@     init {
         val favouritesString = preferences.getString("favourites", "{}")
         JsonParser().parse(favouritesString).asJsonObject.entrySet().forEach { (name, timetables) ->
             timetables.asJsonArray.map {
-                val plates = it.asJsonObject["plates"].let {
-                    if (it == null || it.isJsonNull)
+                val plates = it.asJsonObject["plates"].let { element ->
+                    if (element == null || element.isJsonNull)
                         null
                     else {
-                        it.asJsonArray.map {
-                            it.asJsonObject.let {
-                                Plate.ID(it["line"].asString, it["stop"].asString, it["headsign"].asString)
+                        element.asJsonArray.map { it ->
+                            it.asJsonObject.let { id ->
+                                Plate.ID(id["line"].asString, id["stop"].asString, id["headsign"].asString)
                             }
                         }.toHashSet()
                     }
@@ -123,16 +133,16 @@         if (names.size < 2)
             return
 
         val newCache = HashMap<String, ArrayList<Departure>>()
-        names.forEach {
-            favourites[it]!!.fullTimetable().forEach {
+        names.forEach { name ->
+            favourites[name]!!.fullTimetable().forEach {
                 if (newCache[it.key] == null)
                     newCache[it.key] = ArrayList()
                 newCache[it.key]!!.addAll(it.value)
             }
         }
         val now = Calendar.getInstance().secondsAfterMidnight()
-        newCache.forEach {
-            it.value.sortBy { it.timeTill(now) }
+        newCache.forEach { entry ->
+            entry.value.sortBy { it.timeTill(now) }
         }
         val newFavourite = Favourite(names[0], HashSet(), newCache, context)
         for (name in names) {




diff --git a/app/src/main/java/ml/adamsprogs/bimba/datasources/TimetableDownloader.kt b/app/src/main/java/ml/adamsprogs/bimba/datasources/TimetableDownloader.kt
index 8c39cb5c95f88327c5aa654d3d4b84e701fdcad6..8eb2b34377ea9f1abf1093d2c3928a5cff204f9d 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/datasources/TimetableDownloader.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/datasources/TimetableDownloader.kt
@@ -1,21 +1,29 @@
 package ml.adamsprogs.bimba.datasources
 
 import android.annotation.TargetApi
-import android.app.*
-import android.content.*
-import android.support.v4.app.NotificationCompat
-import java.io.*
+import android.app.IntentService
+import android.app.Notification
+import android.app.NotificationManager
+import android.content.Context
+import android.content.Intent
 import android.os.Build
 import android.preference.PreferenceManager.getDefaultSharedPreferences
+import androidx.core.app.NotificationCompat
 import ml.adamsprogs.bimba.*
-import java.net.*
+import java.io.EOFException
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+import java.net.ConnectException
+import java.net.HttpURLConnection
+import java.net.URL
 import java.util.zip.GZIPInputStream
-import javax.net.ssl.*
+import javax.net.ssl.HttpsURLConnection
+import javax.net.ssl.SSLException
 
 class TimetableDownloader : IntentService("TimetableDownloader") {
     companion object {
         const val ACTION_DOWNLOADED = "ml.adamsprogs.bimba.timetableDownloaded"
-        const val EXTRA_FORCE = "force"
         const val EXTRA_RESULT = "result"
         const val RESULT_NO_CONNECTIVITY = "no connectivity"
         const val RESULT_UP_TO_DATE = "up-to-date"
@@ -40,7 +48,7 @@             val localETag = prefs.getString("etag", "")
 
             val httpCon: HttpURLConnection
             try {
-                var sourceUrl = getDefaultSharedPreferences(this).getString(getString(R.string.key_timetable_source_url), getString(R.string.timetable_source_url))
+                var sourceUrl = getDefaultSharedPreferences(this).getString(getString(R.string.key_timetable_source_url), getString(R.string.timetable_source_url))!!
                 sourceUrl = sourceUrl.replace(Regex("^.*://", RegexOption.IGNORE_CASE), "")
                 sourceUrl = "https://$sourceUrl"
                 val url = URL(sourceUrl)




diff --git a/app/src/main/java/ml/adamsprogs/bimba/datasources/VmClient.kt b/app/src/main/java/ml/adamsprogs/bimba/datasources/VmClient.kt
index 51f7ceb59d2c1d06b955e977950e04c463317fe8..e13f32e35c89ab8748581eff7e4eb1beb25e2e7c 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/datasources/VmClient.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/datasources/VmClient.kt
@@ -1,12 +1,17 @@
 package ml.adamsprogs.bimba.datasources
 
-import com.google.gson.*
-import kotlinx.coroutines.experimental.*
+import com.google.gson.Gson
+import com.google.gson.JsonObject
+import com.google.gson.JsonSyntaxException
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
 import ml.adamsprogs.bimba.NetworkStateReceiver
 import ml.adamsprogs.bimba.models.Plate
 import ml.adamsprogs.bimba.models.StopSegment
-import ml.adamsprogs.bimba.models.suggestions.*
-import okhttp3.*
+import ml.adamsprogs.bimba.models.suggestions.StopSuggestion
+import okhttp3.MediaType
+import okhttp3.OkHttpClient
+import okhttp3.RequestBody
 import java.io.IOException
 import java.util.*
 import kotlin.collections.HashMap
@@ -29,9 +34,9 @@         if (!response.has("success"))
             return emptyMap()
         val rootObject = response["success"].asJsonObject["bollards"].asJsonArray
         val result = HashMap<String, Set<String>>()
-        rootObject.forEach {
-            val code = it.asJsonObject["bollard"].asJsonObject["tag"].asString
-            result[code] = it.asJsonObject["directions"].asJsonArray.map {
+        rootObject.forEach { element ->
+            val code = element.asJsonObject["bollard"].asJsonObject["tag"].asString
+            result[code] = element.asJsonObject["directions"].asJsonArray.map {
                 """${it.asJsonObject["lineName"].asString} → ${it.asJsonObject["direction"].asString}"""
             }.toSet()
         }
@@ -55,7 +60,7 @@         }.toSet()
     }*/
 
     suspend fun getStops(pattern: String): List<StopSuggestion> {
-        val (_, response) = withContext(DefaultDispatcher) {
+        val (_, response) = withContext(Dispatchers.Default) {
             makeRequest("getStopPoints", """{"pattern": "$pattern"}""")
         }
 
@@ -71,7 +76,7 @@             val name = it["name"].asString
             names.add(name)
         }
 
-        return names.map { StopSuggestion(it, "", "") }
+        return names.map { StopSuggestion(it, "") }
     }
 
     suspend fun makeRequest(method: String, data: String): Pair<Int, JsonObject> {
@@ -91,7 +96,7 @@
         var responseBody: String? = null
         var responseCode = 0
         try {
-            withContext(CommonPool) {
+            withContext(Dispatchers.Default) {
                 client.newCall(request).execute().let {
                     responseCode = it.code()
                     responseBody = it.body()?.string()
@@ -109,7 +114,7 @@         }
     }
 
     suspend fun getName(symbol: String): String? {
-        val (_, timesResponse) = withContext(DefaultDispatcher) {
+        val (_, timesResponse) = withContext(Dispatchers.Default) {
             makeRequest("getTimes", """{"symbol": "$symbol"}""")
         }
         if (!timesResponse.has("success"))
@@ -133,5 +138,17 @@                     it.asJsonObject.let { direction ->
                         Plate.ID(direction["lineName"].asString, symbol, direction["direction"].asString)
                     }
                 }.toSet())
+    }
+
+    suspend fun getMessage(shed: String): String? {
+        val (_, response) = makeRequest("findMessagesForBollard", """{"symbol": "$shed"}""")
+
+        if (!response.has("success"))
+            return null
+
+        if (response["success"].asJsonArray.size() == 0)
+            return null
+
+        return response["success"].asJsonArray[0].asJsonObject["content"].asString
     }
 }




diff --git a/app/src/main/java/ml/adamsprogs/bimba/datasources/VmService.kt b/app/src/main/java/ml/adamsprogs/bimba/datasources/VmService.kt
index 82e4f38941d51829f3e42771115968d48869b25a..3d117be561411588acc1dd3864a7087648ac30f2 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/datasources/VmService.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/datasources/VmService.kt
@@ -2,14 +2,18 @@ package ml.adamsprogs.bimba.datasources
 
 import android.app.Service
 import android.content.Intent
-import android.os.*
+import android.os.Handler
+import android.os.HandlerThread
+import android.os.IBinder
 import android.os.Process.THREAD_PRIORITY_BACKGROUND
 import com.google.gson.JsonObject
-import kotlinx.coroutines.experimental.android.UI
-import kotlinx.coroutines.experimental.*
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.Runnable
+import kotlinx.coroutines.launch
 import ml.adamsprogs.bimba.NetworkStateReceiver
 import ml.adamsprogs.bimba.calendarFromIso
-import ml.adamsprogs.bimba.models.*
+import ml.adamsprogs.bimba.models.Departure
+import ml.adamsprogs.bimba.models.Plate
 import ml.adamsprogs.bimba.secondsAfterMidnight
 import java.util.*
 import kotlin.collections.*
@@ -22,7 +26,6 @@         const val EXTRA_PLATE_ID = "ml.adamsprogs.bimba.extra.vm.plate"
         const val EXTRA_STOP_CODE = "ml.adamsprogs.bimba.extra.vm.stop"
         const val EXTRA_CODE = "ml.adamsprogs.bimba.extra.vm.code"
         const val TICK_6_ZINA_TIM = 12500L
-        const val TICK_6_ZINA_TIM_WITH_MARGIN = TICK_6_ZINA_TIM * 3 / 4
     }
 
     private var handler: Handler? = null
@@ -31,10 +34,8 @@         override fun run() {
             handler!!.postDelayed(this, TICK_6_ZINA_TIM)
             try {
                 for (plateId in requests.keys)
-                    launch(UI) {
-                        withContext(DefaultDispatcher) {
-                            downloadVM()
-                        }
+                    GlobalScope.launch {
+                        downloadVM()
                     }
             } catch (e: IllegalArgumentException) {
             }
@@ -63,10 +64,8 @@                 sendResult(stopCode)
             } else {
                 if (!once)
                     addRequest(stopCode)
-                launch(UI) {
-                    withContext(DefaultDispatcher) {
-                        downloadVM(stopCode)
-                    }
+                GlobalScope.launch {
+                    downloadVM(stopCode)
                 }
             }
         } else if (action == "remove") {




diff --git a/app/src/main/java/ml/adamsprogs/bimba/extensions.kt b/app/src/main/java/ml/adamsprogs/bimba/extensions.kt
index 9b51907278628c82c89e90b50b4f7b8c2bc241a9..ec86bc5c93eca92d2228020a27517054304315a0 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/extensions.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/extensions.kt
@@ -4,11 +4,12 @@ import android.annotation.SuppressLint
 import android.content.Context
 import android.graphics.drawable.Drawable
 import android.os.Build
-import android.support.design.widget.Snackbar
 import android.text.format.DateFormat
 import android.view.View
-import ml.adamsprogs.bimba.activities.StopActivity
-import java.io.*
+import com.google.android.material.snackbar.Snackbar
+import java.io.File
+import java.io.InputStream
+import java.io.OutputStream
 import java.text.SimpleDateFormat
 import java.util.*
 import kotlin.collections.ArrayList
@@ -59,28 +60,12 @@     calendar.time = date
     return calendar
 }
 
-fun getColour(id: Int, context: Context): Int {
-    @Suppress("DEPRECATION")
-    (return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
-        context.resources.getColor(id, null)
-    else
-        context.resources.getColor(id))
-}
-
 fun getDrawable(id: Int, context: Context): Drawable {
     @Suppress("DEPRECATION")
     (return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
         context.resources.getDrawable(id, null)
     else
         context.resources.getDrawable(id))
-}
-
-internal fun Calendar.getMode(): Int {
-    return when (this.get(Calendar.DAY_OF_WEEK)) {
-        Calendar.SUNDAY -> StopActivity.MODE_SUNDAYS
-        Calendar.SATURDAY -> StopActivity.MODE_SATURDAYS
-        else -> StopActivity.MODE_WORKDAYS
-    }
 }
 
 internal fun CharSequence.safeSplit(vararg delimiters: String, ignoreCase: Boolean = false, limit: Int = 0): List<String>? {




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 9661f529ba9bd5d83a822b47ec43e022c1daa537..a54cdf20ac0431df54961046c7f02b82490d3f36 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/Departure.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/Departure.kt
@@ -1,11 +1,11 @@
 package ml.adamsprogs.bimba.models
 
+import android.content.Context
+import ml.adamsprogs.bimba.Declinator
+import ml.adamsprogs.bimba.R
+import ml.adamsprogs.bimba.rollTime
 import ml.adamsprogs.bimba.safeSplit
-import ml.adamsprogs.bimba.secondsAfterMidnight
-import java.io.Serializable
 import java.util.*
-import kotlin.collections.ArrayList
-import kotlin.collections.HashMap
 
 data class Departure(val line: String, val mode: List<Int>, val time: Int, val lowFloor: Boolean, //time in seconds since midnight
                      val modification: List<String>, val headsign: String, val vm: Boolean = false,
@@ -25,29 +25,6 @@         return Departure.fromString(this.toString())
     }
 
     companion object {
-        private fun filterDepartures(departures: List<Departure>, relativeTo: Int = Calendar.getInstance().secondsAfterMidnight()): Array<Serializable> {
-            val filtered = ArrayList<Departure>()
-            val lines = HashMap<String, Int>()
-            val sortedDepartures = departures.sortedBy { it.timeTill(relativeTo) }
-            for (departure in sortedDepartures) {
-                val timeTill = departure.timeTill(relativeTo)
-                var lineExistedTimes = lines[departure.line]
-                if (timeTill >= 0 && lineExistedTimes ?: 0 < 3) {
-                    lineExistedTimes = (lineExistedTimes ?: 0) + 1
-                    lines[departure.line] = lineExistedTimes
-                    filtered.add(departure)
-                }
-            }
-            return arrayOf(filtered, lines.all { it.value >= 3 })
-        }
-
-        /*fun createDepartures(stopCode: String): Map<String, List<Departure>> {
-            val timetable = Timetable.getTimetable()
-            val departures = timetable.getStopDepartures(stopCode)
-
-            return rollDepartures(departures)
-        }*/
-
         fun fromString(string: String): Departure {
             val array = string.split("|")
             if (array.size != 9)
@@ -69,4 +46,38 @@         return (time - relativeTo) / 60
     }
 
     val lineText: String = line
+
+    fun timeTillText(context: Context, relativeTime: Boolean = true): String {
+        val now = Calendar.getInstance()
+        val departureTime = Calendar.getInstance().rollTime(time)
+        if (tomorrow)
+            departureTime.add(Calendar.DAY_OF_MONTH, 1)
+
+        val departureIn = ((departureTime.timeInMillis - now.timeInMillis) / (1000 * 60)).toInt()
+
+        return if (departureIn > 60 || departureIn < 0 || !relativeTime)
+            context.getString(R.string.departure_at, "${String.format("%02d", departureTime.get(Calendar.HOUR_OF_DAY))}:${String.format("%02d", departureTime.get(Calendar.MINUTE))}")
+        else if (departureIn > 0 && !onStop)
+            context.getString(Declinator.decline(departureIn), departureIn.toString())
+        else if (departureIn == 0 && !onStop)
+            context.getString(R.string.in_a_moment)
+        else if (departureIn == 0)
+            context.getString(R.string.now)
+        else
+            context.getString(R.string.just_departed)
+    }
+
+    fun timeAtMessage(context: Context): String {
+        val departureTime = Calendar.getInstance().rollTime(time)
+        if (tomorrow)
+            departureTime.add(Calendar.DAY_OF_MONTH, 1)
+
+        return context.getString(R.string.departure_at,
+                "${String.format("%02d",
+                        departureTime.get(Calendar.HOUR_OF_DAY))}:${String.format("%02d",
+                        departureTime.get(Calendar.MINUTE))}") +
+                if (isModified)
+                    " " + modification.joinToString("; ", "(", ")")
+                else ""
+    }
 }
\ No newline at end of file




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 ee3c5ab21c3d525f85f3e52b59ab83c33f560a88..5c7db919c7242c6f09154caa31b6706562f1bddc 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/Favourite.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/Favourite.kt
@@ -1,8 +1,10 @@
 package ml.adamsprogs.bimba.models
 
-import android.content.*
-import android.os.*
-import ml.adamsprogs.bimba.*
+import android.content.Context
+import android.os.Parcel
+import android.os.Parcelable
+import ml.adamsprogs.bimba.ProviderProxy
+import ml.adamsprogs.bimba.safeSplit
 import java.io.File
 import java.math.BigInteger
 import java.security.SecureRandom
@@ -27,10 +29,10 @@
     private val providerProxy: ProviderProxy
 
     constructor(parcel: Parcel) {
-        this.name = parcel.readString()
+        this.name = parcel.readString()!!
         @Suppress("UNCHECKED_CAST")
         val set = HashSet<StopSegment>()
-        val array = parcel.readParcelableArray(StopSegment::class.java.classLoader)
+        val array = parcel.readParcelableArray(StopSegment::class.java.classLoader)!!
         array.forEach {
             set.add(it as StopSegment)
         }
@@ -121,7 +123,7 @@     fun nextDeparture() =
             if (cache.isEmpty())
                 null
             else
-                cache.flatMap { it.value }.let {
+                cache.flatMap { it.value }.let { it ->
                     if (it.isEmpty())
                         null
                     else




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 b3c50228730ad0aad928460bce6685a8500a04e3..363e7bb0640347a8ba1a3882954ead8ec6a670e4 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt
@@ -2,15 +2,19 @@ package ml.adamsprogs.bimba.models
 
 import android.annotation.SuppressLint
 import android.content.Context
-import android.database.*
+import android.database.Cursor
+import android.database.CursorIndexOutOfBoundsException
 import android.database.sqlite.SQLiteDatabase
 import android.database.sqlite.SQLiteException
 import android.util.SparseArray
 import android.util.SparseBooleanArray
 import ml.adamsprogs.bimba.*
-import ml.adamsprogs.bimba.models.gtfs.*
-import ml.adamsprogs.bimba.models.suggestions.*
-import java.io.*
+import ml.adamsprogs.bimba.models.gtfs.Route
+import ml.adamsprogs.bimba.models.gtfs.Stop
+import ml.adamsprogs.bimba.models.gtfs.Trip
+import ml.adamsprogs.bimba.models.suggestions.LineSuggestion
+import ml.adamsprogs.bimba.models.suggestions.StopSuggestion
+import java.io.File
 import kotlin.collections.*
 import java.util.Calendar as JCalendar
 
@@ -89,7 +93,7 @@                 "C" -> "#${getColour(R.color.zoneC, context).toString(16)}"
                 else -> "#000000"
             }
             */
-            StopSuggestion(it.key, it.value, "#000000")
+            StopSuggestion(it.key, it.value)
         }.sorted()
         return _stops!!
     }
@@ -428,24 +432,9 @@             null
         }
     }
 
-    private fun getPlatesForStop(stop: String): Set<Plate.ID> {
-
-        val plates = HashSet<Plate.ID>()
-        val cursor = db!!.rawQuery("select route_id, trip_headsign " +
-                "from stop_times natural join trips natural join stops where stop_code = ? " +
-                "group by route_id, trip_headsign", arrayOf(stop))
-
-        while (cursor.moveToNext()) {
-            val routeId = cursor.getString(0)
-            val headsign = cursor.getString(1)
-            plates.add(Plate.ID(routeId, stop, headsign))
-        }
-
-        cursor.close()
-        return plates
-    }
-
     fun getTripGraphs(id: String): Array<TripGraph> {
+        TODO("Not implemented")
+        /*
         val graphs = arrayOf(TripGraph(), TripGraph())
 
         val cursor = db!!.rawQuery("select trip_id, trip_headsign, direction_id, stop_id, " +
@@ -495,7 +484,7 @@                 }
             }
         }
 
-        return graphs
+        return graphs*/
     }
 
     fun getServiceFirstDay(service: String): Int {




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/adapters/DeparturesAdapter.kt b/app/src/main/java/ml/adamsprogs/bimba/models/adapters/DeparturesAdapter.kt
index 920b6741fea569dcdc950c55aa77a78cf110732e..f0f16dfbc2366b77d7d65f2361b06ac63724f5cd 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/adapters/DeparturesAdapter.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/adapters/DeparturesAdapter.kt
@@ -3,39 +3,22 @@
 import android.app.AlertDialog
 import android.content.Context
 import android.content.DialogInterface
-import android.support.v4.content.res.ResourcesCompat
-import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageView
 import android.widget.TextView
+import androidx.core.content.res.ResourcesCompat
 import ml.adamsprogs.bimba.R
-import android.view.LayoutInflater
-import ml.adamsprogs.bimba.Declinator
 import ml.adamsprogs.bimba.models.Departure
-import ml.adamsprogs.bimba.rollTime
-import java.util.*
 
 class DeparturesAdapter(val context: Context, var departures: List<Departure>?, var relativeTime: Boolean) :
-        RecyclerView.Adapter<DeparturesAdapter.ViewHolder>() {
-
-    companion object {
-        const val VIEW_TYPE_LOADING: Int = 0
-        const val VIEW_TYPE_CONTENT: Int = 1
-    }
+        androidx.recyclerview.widget.RecyclerView.Adapter<DeparturesAdapter.ViewHolder>() {
 
     override fun getItemCount(): Int {
         if (departures == null || departures!!.isEmpty())
             return 1
         return departures!!.size
-    }
-
-    override fun getItemViewType(position: Int): Int {
-        return when {
-            departures == null -> VIEW_TYPE_LOADING //empty
-            departures!!.isEmpty() -> VIEW_TYPE_LOADING
-            else -> VIEW_TYPE_CONTENT
-        }
     }
 
     override fun onBindViewHolder(holder: ViewHolder, position: Int) {
@@ -54,20 +37,8 @@             time.text = context.getString(R.string.no_departures)
             return
         }
         val departure = departures!![position]
-        val now = Calendar.getInstance()
-        val departureTime = Calendar.getInstance().rollTime(departure.time)
-        if (departure.tomorrow)
-            departureTime.add(Calendar.DAY_OF_MONTH, 1)
 
-        val departureIn = ((departureTime.timeInMillis - now.timeInMillis) / (1000 * 60)).toInt()
-        val timeString: String
-
-        timeString = if (departureIn > 60 || departureIn < 0 || !relativeTime)
-            context.getString(R.string.departure_at, "${String.format("%02d", departureTime.get(Calendar.HOUR_OF_DAY))}:${String.format("%02d", departureTime.get(Calendar.MINUTE))}")
-        else if (departureIn > 0 && !departure.onStop)
-            context.getString(Declinator.decline(departureIn), departureIn.toString())
-        else
-            context.getString(R.string.now)
+        val timeString = departure.timeTillText(context, relativeTime)
 
         line.text = departure.lineText
         time.text = timeString
@@ -87,14 +58,7 @@             AlertDialog.Builder(context)
                     .setPositiveButton(context.getText(android.R.string.ok)
                     ) { dialog: DialogInterface, _: Int -> dialog.cancel() }
                     .setCancelable(true)
-                    .setMessage(
-                            context.getString(R.string.departure_at,
-                                    "${String.format("%02d",
-                                            departureTime.get(Calendar.HOUR_OF_DAY))}:${String.format("%02d",
-                                            departureTime.get(Calendar.MINUTE))}")
-                                    + if (departure.isModified)
-                                " " + departure.modification.joinToString("; ", "(", ")")
-                            else "")
+                    .setMessage(departure.timeAtMessage(context))
                     .create().show()
         }
     }
@@ -107,7 +71,7 @@         val rowView = inflater.inflate(R.layout.row_departure, parent, false)
         return ViewHolder(rowView)
     }
 
-    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+    inner class ViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) {
         val root = itemView.findViewById<View>(R.id.departureRow)!!
         val lineTextView: TextView = itemView.findViewById(R.id.lineNumber)
         val timeTextView: TextView = itemView.findViewById(R.id.departureTime)




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/adapters/FavouriteEditRowAdapter.kt b/app/src/main/java/ml/adamsprogs/bimba/models/adapters/FavouriteEditRowAdapter.kt
index cb78df9d44a97addec4f60b2c1539551311584aa..c4e638efb519ce0f8f0d74a1f83adf615a1fb30f 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/adapters/FavouriteEditRowAdapter.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/adapters/FavouriteEditRowAdapter.kt
@@ -1,25 +1,16 @@
 package ml.adamsprogs.bimba.models.adapters
 
-import android.support.v7.widget.RecyclerView
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.TextView
-import kotlinx.coroutines.experimental.DefaultDispatcher
-import kotlinx.coroutines.experimental.android.UI
-import kotlinx.coroutines.experimental.launch
-import kotlinx.coroutines.experimental.withContext
-import ml.adamsprogs.bimba.ProviderProxy
-import ml.adamsprogs.bimba.R
+import android.view.*
+import android.widget.*
+import kotlinx.coroutines.*
+import kotlinx.coroutines.android.Main
+import ml.adamsprogs.bimba.*
 import ml.adamsprogs.bimba.collections.FavouriteStorage
-import ml.adamsprogs.bimba.models.Favourite
-import ml.adamsprogs.bimba.models.Plate
-import ml.adamsprogs.bimba.models.StopSegment
+import ml.adamsprogs.bimba.models.*
 
 
 class FavouriteEditRowAdapter(private var favourite: Favourite, private val loadingView: View, private val listView: View) :
-        RecyclerView.Adapter<FavouriteEditRowAdapter.ViewHolder>() {
+        androidx.recyclerview.widget.RecyclerView.Adapter<FavouriteEditRowAdapter.ViewHolder>() {
 
     private val segments = HashMap<String, StopSegment>()
     private val providerProxy = ProviderProxy()
@@ -28,33 +19,31 @@     private val platesList = ArrayList()
     private val namesList = HashMap<Plate.ID, String>()
 
     init {
-        launch(UI) {
-            withContext(DefaultDispatcher) {
-                favourite.segments.forEach {
-                    if (it.plates == null) {
-                        (providerProxy.fillStopSegment(it) ?: it).let { segment ->
-                            segments[segment.stop] = segment
-                            it.plates = segment.plates
-                        }
-                    } else {
-                        segments[it.stop] = it
+        GlobalScope.launch {
+            favourite.segments.forEach {
+                if (it.plates == null) {
+                    (providerProxy.fillStopSegment(it) ?: it).let { segment ->
+                        segments[segment.stop] = segment
+                        it.plates = segment.plates
                     }
+                } else {
+                    segments[it.stop] = it
                 }
-                favourites[favourite.name] = favourite
+            }
+            favourites[favourite.name] = favourite
 
-                segments.flatMap {
-                    it.value.plates ?: emptyList<Plate.ID>()
-                }.sortedBy { "${it.line}${it.stop}" }.forEach {
-                    platesList.add(it)
-                    namesList[it] = providerProxy.getStopName(it.stop).let { name ->
-                        "${name ?: ""} (${it.stop}):\n${it.line} → ${it.headsign}"
-                    }
+            segments.flatMap {
+                it.value.plates ?: emptyList<Plate.ID>()
+            }.sortedBy { "${it.line}${it.stop}" }.forEach {
+                platesList.add(it)
+                namesList[it] = providerProxy.getStopName(it.stop).let { name ->
+                    "${name ?: ""} (${it.stop}):\n${it.line} → ${it.headsign}"
                 }
-                launch(UI) {
-                    loadingView.visibility = View.GONE
-                    listView.visibility = View.VISIBLE
-                    this@FavouriteEditRowAdapter.notifyDataSetChanged()
-                }
+            }
+            launch(Dispatchers.Main) {
+                loadingView.visibility = View.GONE
+                listView.visibility = View.VISIBLE
+                this@FavouriteEditRowAdapter.notifyDataSetChanged()
             }
         }
     }
@@ -63,19 +52,17 @@
     override fun getItemCount(): Int = platesList.size
 
     override fun onBindViewHolder(holder: ViewHolder, position: Int) {
-        launch(UI) {
+        GlobalScope.launch {
             val id = platesList[position]
             val favouriteElement = namesList[id]
 
             holder.rowTextView.text = favouriteElement
             holder.deleteButton.setOnClickListener {
-                launch(UI) {
-                    favourites.delete(favourite.name, id)
-                    favourite = favourites.favourites[favourite.name]!!
-                    notifyItemRemoved(platesList.indexOf(id))
-                    platesList.remove(id)
-                    namesList.remove(id)
-                }
+                favourites.delete(favourite.name, id)
+                favourite = favourites.favourites[favourite.name]!!
+                notifyItemRemoved(platesList.indexOf(id))
+                platesList.remove(id)
+                namesList.remove(id)
             }
         }
     }
@@ -88,7 +75,7 @@         val rowView = inflater.inflate(R.layout.row_favourite_edit, parent, false)
         return ViewHolder(rowView)
     }
 
-    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+    inner class ViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) {
         val rowTextView: TextView = itemView.findViewById(R.id.favourite_edit_row)
         val deleteButton: ImageView = itemView.findViewById(R.id.favourite_edit_delete)
     }




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/adapters/FavouritesAdapter.kt b/app/src/main/java/ml/adamsprogs/bimba/models/adapters/FavouritesAdapter.kt
index a30130f8c29ad35d2a33a8cefa0ef22786ca5282..3762d36f92937345fefd52ea89c97aa608d52b2e 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/adapters/FavouritesAdapter.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/adapters/FavouritesAdapter.kt
@@ -1,27 +1,29 @@
 package ml.adamsprogs.bimba.models.adapters
 
 import android.content.Context
-import android.support.v4.content.res.ResourcesCompat
-import android.support.v7.widget.*
-import android.support.v7.widget.PopupMenu
 import android.util.SparseBooleanArray
-import android.view.*
-import android.widget.*
-import ml.adamsprogs.bimba.R
 import android.view.LayoutInflater
-import kotlinx.coroutines.experimental.android.UI
-import kotlinx.coroutines.experimental.*
-import java.util.*
-import ml.adamsprogs.bimba.Declinator
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.appcompat.widget.PopupMenu
+import androidx.core.content.res.ResourcesCompat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.android.Main
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import ml.adamsprogs.bimba.R
 import ml.adamsprogs.bimba.collections.FavouriteStorage
 import ml.adamsprogs.bimba.models.Favourite
-import ml.adamsprogs.bimba.secondsAfterMidnight
+import java.util.*
 
 
 class FavouritesAdapter(private val appContext: Context, var favourites: FavouriteStorage,
                         private val onMenuItemClickListener: OnMenuItemClickListener,
                         private val onClickListener: ViewHolder.OnClickListener) :
-        RecyclerView.Adapter<FavouritesAdapter.ViewHolder>() {
+        androidx.recyclerview.widget.RecyclerView.Adapter<FavouritesAdapter.ViewHolder>() {
 
     private val selectedItems = SparseBooleanArray()
 
@@ -52,7 +54,7 @@
     override fun getItemCount() = favourites.size
 
     override fun onBindViewHolder(holder: ViewHolder, position: Int) {
-        launch(UI) {
+        GlobalScope.launch(Dispatchers.Main) /*Main on all?*/ {
             val favourite = favourites[position]!!
             holder.nameTextView.text = favourite.name
 
@@ -71,19 +73,15 @@                 inflater.inflate(R.menu.favourite_actions, popup.menu)
                 popup.show()
             }
 
-            val nextDeparture = withContext(CommonPool) {
+            val nextDeparture = withContext(Dispatchers.Default) {
                 favourite.nextDeparture()
             }
 
             val nextDepartureText: String
             val nextDepartureLineText: String
             if (nextDeparture != null) {
-                val interval = nextDeparture.timeTill(Calendar.getInstance().secondsAfterMidnight())
                 nextDepartureLineText = appContext.getString(R.string.departure_to_line, nextDeparture.line, nextDeparture.headsign)
-                nextDepartureText = if (interval < 0)
-                    appContext.getString(R.string.just_departed)
-                else
-                    appContext.getString(Declinator.decline(interval), interval.toString())
+                nextDepartureText = nextDeparture.timeTillText(appContext)
             } else {
                 nextDepartureText = appContext.getString(R.string.no_next_departure)
                 nextDepartureLineText = ""
@@ -115,7 +113,7 @@     operator fun get(index: String): Favourite? {
         return favourites[index]
     }
 
-    class ViewHolder(itemView: View, private val listener: OnClickListener) : RecyclerView.ViewHolder(itemView), View.OnClickListener, View.OnLongClickListener {
+    class ViewHolder(itemView: View, private val listener: OnClickListener) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView), View.OnClickListener, View.OnLongClickListener {
         override fun onLongClick(v: View?): Boolean {
             return listener.onItemLongClicked(adapterPosition)
         }




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/adapters/SuggestionsAdapter.kt b/app/src/main/java/ml/adamsprogs/bimba/models/adapters/SuggestionsAdapter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6408a4506cde6c5d2fdf7a84a6024a78c5699881
--- /dev/null
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/adapters/SuggestionsAdapter.kt
@@ -0,0 +1,96 @@
+package ml.adamsprogs.bimba.models.adapters
+
+import android.content.Context
+import android.graphics.PorterDuff
+import android.os.Build
+import android.text.Html
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.core.content.ContextCompat.getColor
+import ml.adamsprogs.bimba.R
+import ml.adamsprogs.bimba.getDrawable
+import ml.adamsprogs.bimba.models.suggestions.EmptySuggestion
+import ml.adamsprogs.bimba.models.suggestions.GtfsSuggestion
+import ml.adamsprogs.bimba.models.suggestions.LineSuggestion
+import ml.adamsprogs.bimba.models.suggestions.StopSuggestion
+import com.mancj.materialsearchbar.adapter.SuggestionsAdapter as SearchBarSuggestionsAdapter
+
+class SuggestionsAdapter(inflater: LayoutInflater, private val onSuggestionClickListener: OnSuggestionClickListener, private val context: Context) :
+        SearchBarSuggestionsAdapter<GtfsSuggestion, SuggestionsAdapter.ViewHolder>(inflater) {
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+        val rowView = layoutInflater.inflate(R.layout.row_suggestion, parent, false)
+        return ViewHolder(rowView)
+    }
+
+    override fun getSingleViewHeight(): Int = 48
+
+    override fun onBindSuggestionHolder(suggestion: GtfsSuggestion, holder: ViewHolder?, pos: Int) {
+        holder!!.root.setOnClickListener {
+            onSuggestionClickListener.onSuggestionClickListener(suggestion)
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            holder.text.text = Html.fromHtml(suggestion.getBody(context), Html.FROM_HTML_MODE_LEGACY)
+        } else {
+            @Suppress("DEPRECATION")
+            holder.text.text = Html.fromHtml(suggestion.getBody(context))
+        }
+
+        holder.text.setTextColor(getColor(context, R.color.textDark))
+
+        val icon = getDrawable(suggestion.getIcon(), context)
+        icon.mutate()
+        icon.colorFilter = null
+        if (suggestion is StopSuggestion)
+            when (suggestion.zone) {
+                "A" -> icon.setColorFilter(getColor(context, R.color.zoneA), PorterDuff.Mode.SRC_IN)
+                "B" -> icon.setColorFilter(getColor(context, R.color.zoneB), PorterDuff.Mode.SRC_IN)
+                "C" -> icon.setColorFilter(getColor(context, R.color.zoneC), PorterDuff.Mode.SRC_IN)
+                else -> icon.setColorFilter(getColor(context, R.color.textDark), PorterDuff.Mode.SRC_IN)
+            }
+        else if (suggestion is LineSuggestion) {
+            icon.setColorFilter(suggestion.getColour(), PorterDuff.Mode.SRC_IN)
+            holder.icon.setBackgroundColor(suggestion.getBgColour())
+        }
+        holder.icon.setImageDrawable(icon)
+
+    }
+
+    fun updateSuggestions(newSuggestions: List<GtfsSuggestion>, query: String) {
+        suggestions = sort(newSuggestions, query).take(6)
+        suggestions_clone = suggestions
+        notifyDataSetChanged()
+    }
+
+    private fun sort(suggestions: List<GtfsSuggestion>, query: String): List<GtfsSuggestion> {
+        val r = Regex(query, RegexOption.IGNORE_CASE)
+        return suggestions.sortedBy {
+            (r.find(it.name)?.range?.start?.toString()?.padStart(128, '0') ?: "")+it.name
+        }
+    }
+
+    operator fun contains(suggestion: GtfsSuggestion): Boolean {
+        return suggestion in suggestions //|| suggestion in suggestions_clone
+    }
+
+    inner class ViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) {
+        val root: View = itemView.findViewById(R.id.row_suggestion)
+        val icon: ImageView = itemView.findViewById(R.id.suggestion_row_image)
+        val text: TextView = itemView.findViewById(R.id.suggestion_row_text)
+    }
+
+    interface OnSuggestionClickListener {
+        fun onSuggestionClickListener(suggestion: GtfsSuggestion)
+    }
+
+    fun equals(other: List<GtfsSuggestion>): Boolean {
+        if ((suggestions.containsAll(other) and other.containsAll(suggestions)))
+            return true
+        if (other.isEmpty())
+            if ((suggestions.isEmpty()) or (suggestions[0] is EmptySuggestion))
+                return true
+        return false
+    }
+}




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/suggestions/EmptySuggestion.kt b/app/src/main/java/ml/adamsprogs/bimba/models/suggestions/EmptySuggestion.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6d1ae4255e29b82a47db5d82c5261e273dad8f82
--- /dev/null
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/suggestions/EmptySuggestion.kt
@@ -0,0 +1,37 @@
+package ml.adamsprogs.bimba.models.suggestions
+
+import android.content.Context
+import ml.adamsprogs.bimba.R
+
+class EmptySuggestion : GtfsSuggestion("Empty") {
+    override fun equals(other: Any?): Boolean {
+        return other != null && other is EmptySuggestion
+    }
+
+    override fun getIcon(): Int {
+        return R.drawable.ic_error_outline
+    }
+
+    override fun getColour(): Int {
+        return 0xffffff
+    }
+
+    override fun getBgColour(): Int {
+        return 0x000000
+    }
+
+    override fun getBody(context: Context): String {
+        return context.getString(R.string.nothing_found)
+    }
+
+    override fun compareTo(other: GtfsSuggestion): Int {
+        return if (other is EmptySuggestion)
+            0
+        else
+            -1
+    }
+
+    override fun hashCode(): Int {
+        return name.hashCode()
+    }
+}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/suggestions/GtfsSuggestion.kt b/app/src/main/java/ml/adamsprogs/bimba/models/suggestions/GtfsSuggestion.kt
index 1fab1c029c41a7e5dc26178ae5f5e86b33ab375a..06338fb9e936e9f0580b142ef5995ed419508c5a 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/suggestions/GtfsSuggestion.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/suggestions/GtfsSuggestion.kt
@@ -1,11 +1,17 @@
 package ml.adamsprogs.bimba.models.suggestions
 
-import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
+import android.content.Context
 
-abstract class GtfsSuggestion(val name: String) : SearchSuggestion, Comparable<GtfsSuggestion> {
+abstract class GtfsSuggestion(val name: String) : Comparable<GtfsSuggestion> {
     abstract fun getIcon(): Int
 
     abstract fun getColour(): Int
 
     abstract fun getBgColour(): Int
+
+    abstract fun getBody(context: Context): String
+
+    abstract override fun equals(other: Any?): Boolean
+
+    abstract override fun hashCode(): Int
 }
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/suggestions/LineSuggestion.kt b/app/src/main/java/ml/adamsprogs/bimba/models/suggestions/LineSuggestion.kt
index 0b71ad0cce6bf32496a79b791082caa7a5ebf5c6..b6b11e162b21b5beb4d5b85e276fdcc156e4f408 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/suggestions/LineSuggestion.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/suggestions/LineSuggestion.kt
@@ -1,24 +1,10 @@
 package ml.adamsprogs.bimba.models.suggestions
 
-import android.os.Parcel
-import android.os.Parcelable
+import android.content.Context
 import ml.adamsprogs.bimba.R
 import ml.adamsprogs.bimba.models.gtfs.Route
 
 class LineSuggestion(name: String, private val route: Route) : GtfsSuggestion(name) {
-    constructor(parcel: Parcel) : this(
-            parcel.readString(),
-            parcel.readParcelable(Route::class.java.classLoader))
-
-    override fun writeToParcel(parcel: Parcel, flags: Int) {
-        parcel.writeString(name)
-        parcel.writeParcelable(route, flags)
-    }
-
-    override fun describeContents(): Int {
-        return 0
-    }
-
     override fun getIcon(): Int {
         return when (route.type) {
             Route.TYPE_BUS -> R.drawable.ic_bus
@@ -27,7 +13,7 @@             else -> R.drawable.ic_vehicle
         }
     }
 
-    override fun getBody(): String {
+    override fun getBody(context: Context): String {
         return name
     }
 
@@ -46,13 +32,18 @@         else
             name.compareTo(other.name)
     }
 
-    companion object CREATOR : Parcelable.Creator<LineSuggestion> {
-        override fun createFromParcel(parcel: Parcel): LineSuggestion {
-            return LineSuggestion(parcel)
-        }
+    override fun equals(other: Any?): Boolean {
+        if (other == null || other !is GtfsSuggestion)
+            return false
+        return if (other is LineSuggestion)
+            name.padStart(3, '0') == other.name.padStart(3, '0')
+        else
+            name == other.name
+    }
 
-        override fun newArray(size: Int): Array<LineSuggestion?> {
-            return arrayOfNulls(size)
-        }
+    override fun hashCode(): Int {
+        var result = route.hashCode()
+        result = 31 * result + name.hashCode()
+        return result
     }
 }
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/suggestions/StopSuggestion.kt b/app/src/main/java/ml/adamsprogs/bimba/models/suggestions/StopSuggestion.kt
index cd3ef7762cb9f0e16a905cba2df8193e9d8b4568..88c4f19b68dc32e2d87aee7437e21870d9fc7093 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/suggestions/StopSuggestion.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/suggestions/StopSuggestion.kt
@@ -1,24 +1,11 @@
 package ml.adamsprogs.bimba.models.suggestions
 
-import android.os.Parcel
-import android.os.Parcelable
+import android.content.Context
 import ml.adamsprogs.bimba.R
 
-class StopSuggestion(name: String, private val zone: String, private val zoneColour: String) : GtfsSuggestion(name){
-    @Suppress("UNCHECKED_CAST")
-    constructor(parcel: Parcel) : this(parcel.readString(), parcel.readString(), parcel.readString())
-
-    override fun describeContents(): Int {
-        return Parcelable.CONTENTS_FILE_DESCRIPTOR
-    }
+class StopSuggestion(name: String, val zone: String) : GtfsSuggestion(name) {
 
-    override fun writeToParcel(dest: Parcel?, flags: Int) {
-        dest?.writeString(name)
-        dest?.writeString(zone)
-        dest?.writeString(zoneColour)
-    }
-
-    override fun getBody(): String {
+    override fun getBody(context: Context): String {
         return name
     }
 
@@ -27,24 +14,26 @@         return R.drawable.ic_stop
     }
 
     override fun getColour(): Int {
-        return zoneColour.filter { it in "0123456789abcdef" }.toInt(16)
+        return 0xffffff
     }
 
     override fun getBgColour(): Int {
-        return "ffffff".toInt(16)
+        return 0x000000
     }
 
     override fun compareTo(other: GtfsSuggestion): Int {
         return name.compareTo(other.name)
     }
 
-    companion object CREATOR : Parcelable.Creator<StopSuggestion> {
-        override fun createFromParcel(parcel: Parcel): StopSuggestion {
-            return StopSuggestion(parcel)
-        }
+    override fun equals(other: Any?): Boolean {
+        if (other == null || other !is GtfsSuggestion)
+            return false
+        return name == other.name
+    }
 
-        override fun newArray(size: Int): Array<StopSuggestion?> {
-            return arrayOfNulls(size)
-        }
+    override fun hashCode(): Int {
+        var result = zone.hashCode()
+        result = 31 * result + name.hashCode()
+        return result
     }
 }
\ No newline at end of file




diff --git a/app/src/main/play/de-DE/listing/featureGraphic/feature-graphic.png b/app/src/main/play/de-DE/listing/featureGraphic/feature-graphic.png
deleted file mode 100644
index 51367606dc88dad0e00cf8734ed134899dc6e5a1..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/de-DE/listing/featureGraphic/feature-graphic.png and /dev/null differ




diff --git a/app/src/main/play/de-DE/listing/fulldescription b/app/src/main/play/de-DE/listing/fulldescription
deleted file mode 100644
index 1fcea45855dcc8298ecfd2797b63eb979bca5b85..0000000000000000000000000000000000000000
--- a/app/src/main/play/de-DE/listing/fulldescription
+++ /dev/null
@@ -1,6 +0,0 @@
-Mit dieser App kannst du den Fahrplan des öffentlichen Verkehrs in der Posener Agglomeration (von ZTM Poznań betrieben) überprüfen und dank des Virtuellen Monitors kannst du sehen, wann genau ein Bus oder eine Straßenbahn ankommen wird.
-
-Aktuelle Funktionen:
-* Abfahrtszeiten an der Haltestellen ermitteln (basierend auf offline Fahrplan und Virtuelle Monitor),
-* Erstellen von Lieblingshaltestellen mit der nächsten Abfahrt auf der Startseite,
-* Abfahrten an der Favoriten ermitteln




diff --git a/app/src/main/play/de-DE/listing/icon/logo.png b/app/src/main/play/de-DE/listing/icon/logo.png
deleted file mode 100644
index 7a9bd078b1aed42188fe767423683c64a468312e..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/de-DE/listing/icon/logo.png and /dev/null differ




diff --git a/app/src/main/play/de-DE/listing/phoneScreenshots/Dash.png b/app/src/main/play/de-DE/listing/phoneScreenshots/Dash.png
deleted file mode 100644
index 28c363354aaa8ed0173efed699bc54b9e5106397..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/de-DE/listing/phoneScreenshots/Dash.png and /dev/null differ




diff --git a/app/src/main/play/de-DE/listing/phoneScreenshots/StopActivity.png b/app/src/main/play/de-DE/listing/phoneScreenshots/StopActivity.png
deleted file mode 100644
index 6cde859fa2cdc925aa05d2d04158bfae0eb34301..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/de-DE/listing/phoneScreenshots/StopActivity.png and /dev/null differ




diff --git a/app/src/main/play/de-DE/listing/phoneScreenshots/StopSpecify.png b/app/src/main/play/de-DE/listing/phoneScreenshots/StopSpecify.png
deleted file mode 100644
index 86c00aa109026e9cb98759dc1825df3705a12589..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/de-DE/listing/phoneScreenshots/StopSpecify.png and /dev/null differ




diff --git a/app/src/main/play/de-DE/listing/phoneScreenshots/modification.png b/app/src/main/play/de-DE/listing/phoneScreenshots/modification.png
deleted file mode 100644
index c3648d2dca7047ec3d3f8d5e83047d8a97bf593f..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/de-DE/listing/phoneScreenshots/modification.png and /dev/null differ




diff --git a/app/src/main/play/de-DE/listing/phoneScreenshots/searchStop.png b/app/src/main/play/de-DE/listing/phoneScreenshots/searchStop.png
deleted file mode 100644
index 662c6201e0c55c7f6eed5fad22f9a56052c002a4..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/de-DE/listing/phoneScreenshots/searchStop.png and /dev/null differ




diff --git a/app/src/main/play/de-DE/listing/promoGraphic/promo-graphic.png b/app/src/main/play/de-DE/listing/promoGraphic/promo-graphic.png
deleted file mode 100644
index 6e15268c85de20ae2ea38d0d3cfa85aa913e4f93..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/de-DE/listing/promoGraphic/promo-graphic.png and /dev/null differ




diff --git a/app/src/main/play/de-DE/listing/shortdescription b/app/src/main/play/de-DE/listing/shortdescription
deleted file mode 100644
index ebbe6569b6168bc2a1fef901d32e1aecc1b14b08..0000000000000000000000000000000000000000
--- a/app/src/main/play/de-DE/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Erster Freie-Software Posen Bummelführer




diff --git a/app/src/main/play/de-DE/whatsnew b/app/src/main/play/de-DE/whatsnew
deleted file mode 100644
index cbd4b8733278f81740a965e5c432ce3ec40c15fe..0000000000000000000000000000000000000000
--- a/app/src/main/play/de-DE/whatsnew
+++ /dev/null
@@ -1,8 +0,0 @@
-- offizieller Fahrplan von ZTM
-- VM kann ohne Offline-Fahrplan verwendet werden
-- Offline-Fahrplan verwendet genaue Daten (statt Arbeitstagen/Samstagen/Feiertagen)
-- VM ist schneller und mehr zuverlässig (da es genauso berechnet wird wie Offline-Abfahrten)
-- Lieblingshaltestellen von Grund auf umgeschrieben
-- App ist auf externen Speicher bewegbar
-- neue Farben — grau und grün — die zum neuen Posener Stil passen
-- mehrere Fehler behoben




diff --git a/app/src/main/play/en-GB/whatsnew b/app/src/main/play/en-GB/whatsnew
index 177b822ae2ab045622785f35ecda675d18fd48c9..b1a3873c409b3d24b23061f36dd6b9f68865cfa4 100644
--- a/app/src/main/play/en-GB/whatsnew
+++ b/app/src/main/play/en-GB/whatsnew
@@ -1,8 +1,18 @@
-- official timetable from ZTM
-- VM can be used without offline timetable
-- offline timetable uses exact dates (instead of workdays/saturdays/holidays)
-- VM is quicker and is more reliable (as it’s computed in the same way as offline departures)
-- favourites rewritten from scratch
-- app is movable to external storage
-- new colours—grey and green—fitting new Poznań style
-- multiple bug fixes
+[2.1] – 2019-02-04
+==================
+
+Added
+-----
+
++ showing empty search result
++ loading in shed selection and stop screen
++ VM messages
+
+Changed
+-------
+
+* search bar
+* empty departures state
+* ‘now’ departure is ‘in a moment’ if the vehicle is not on-stop
+* sorting departures: on-stop at the top
+* sorting search results by similarity




diff --git a/app/src/main/play/en-US/listing/featureGraphic/feature-graphic.png b/app/src/main/play/en-US/listing/featureGraphic/feature-graphic.png
deleted file mode 100644
index 1333d62dd12eb83080efd9850179902cbe689da6..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/en-US/listing/featureGraphic/feature-graphic.png and /dev/null differ




diff --git a/app/src/main/play/en-US/listing/fulldescription b/app/src/main/play/en-US/listing/fulldescription
deleted file mode 100644
index 1286c61843fc2318c517f450fc3faa935dd2104d..0000000000000000000000000000000000000000
--- a/app/src/main/play/en-US/listing/fulldescription
+++ /dev/null
@@ -1,6 +0,0 @@
-With this app You can check the public transport timetable in Poznań agglomeration (run by ZTM Poznań), and thanks to the Virtual Monitor You can see when exactly a bus or tram will arrive.
-
-Current features:
-* checking departures by stop (based on offline timetable and Virtual Monitor),
-* creating favourite stops with next departure visible on main screen,
-* checking departures by favourite




diff --git a/app/src/main/play/en-US/listing/icon/logo.png b/app/src/main/play/en-US/listing/icon/logo.png
deleted file mode 100644
index 7a9bd078b1aed42188fe767423683c64a468312e..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/en-US/listing/icon/logo.png and /dev/null differ




diff --git a/app/src/main/play/en-US/listing/phoneScreenshots/Dash.png b/app/src/main/play/en-US/listing/phoneScreenshots/Dash.png
deleted file mode 100644
index b3d55c2a98f3e70f19d7b97b39e7947bc9946b44..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/en-US/listing/phoneScreenshots/Dash.png and /dev/null differ




diff --git a/app/src/main/play/en-US/listing/phoneScreenshots/StopActivity.png b/app/src/main/play/en-US/listing/phoneScreenshots/StopActivity.png
deleted file mode 100644
index a85d7e9dfdcb7b81b3a8a7d5097923c885356065..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/en-US/listing/phoneScreenshots/StopActivity.png and /dev/null differ




diff --git a/app/src/main/play/en-US/listing/phoneScreenshots/modification.png b/app/src/main/play/en-US/listing/phoneScreenshots/modification.png
deleted file mode 100644
index 2f536117feeb2ef180b3be65e36fee4154c94e4f..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/en-US/listing/phoneScreenshots/modification.png and /dev/null differ




diff --git a/app/src/main/play/en-US/listing/phoneScreenshots/searchStop.png b/app/src/main/play/en-US/listing/phoneScreenshots/searchStop.png
deleted file mode 100644
index 93683ba47b92fa3429623a0222488e0df516df93..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/en-US/listing/phoneScreenshots/searchStop.png and /dev/null differ




diff --git a/app/src/main/play/en-US/listing/phoneScreenshots/stopSpecify.png b/app/src/main/play/en-US/listing/phoneScreenshots/stopSpecify.png
deleted file mode 100644
index a67350f5939563ab794be2ec1ef89be4f6f5e5f5..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/en-US/listing/phoneScreenshots/stopSpecify.png and /dev/null differ




diff --git a/app/src/main/play/en-US/listing/promoGraphic/promo-graphic.png b/app/src/main/play/en-US/listing/promoGraphic/promo-graphic.png
deleted file mode 100644
index 6e15268c85de20ae2ea38d0d3cfa85aa913e4f93..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/en-US/listing/promoGraphic/promo-graphic.png and /dev/null differ




diff --git a/app/src/main/play/en-US/listing/shortdescription b/app/src/main/play/en-US/listing/shortdescription
deleted file mode 100644
index 59cba7356e35c4b1d6c521a6ef2ccf0aad7663f8..0000000000000000000000000000000000000000
--- a/app/src/main/play/en-US/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-First Free Software Poznań Wandering Guide




diff --git a/app/src/main/play/en-US/whatsnew b/app/src/main/play/en-US/whatsnew
deleted file mode 100644
index 177b822ae2ab045622785f35ecda675d18fd48c9..0000000000000000000000000000000000000000
--- a/app/src/main/play/en-US/whatsnew
+++ /dev/null
@@ -1,8 +0,0 @@
-- official timetable from ZTM
-- VM can be used without offline timetable
-- offline timetable uses exact dates (instead of workdays/saturdays/holidays)
-- VM is quicker and is more reliable (as it’s computed in the same way as offline departures)
-- favourites rewritten from scratch
-- app is movable to external storage
-- new colours—grey and green—fitting new Poznań style
-- multiple bug fixes




diff --git a/app/src/main/play/it-IT/listing/featureGraphic/feature-graphic.png b/app/src/main/play/it-IT/listing/featureGraphic/feature-graphic.png
deleted file mode 100644
index da3dfc5c953e31be5e8ed9552d073a40f6180a77..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/it-IT/listing/featureGraphic/feature-graphic.png and /dev/null differ




diff --git a/app/src/main/play/it-IT/listing/fulldescription b/app/src/main/play/it-IT/listing/fulldescription
deleted file mode 100644
index 0dc7c3d56a8b560fa6d127d803e8762fa3a09482..0000000000000000000000000000000000000000
--- a/app/src/main/play/it-IT/listing/fulldescription
+++ /dev/null
@@ -1,6 +0,0 @@
-Con questa applicazione puoi guardare l'orario dei trasporti pubblici in agglomerato di Poznań (gestito da ZTM Poznań) e grazie al Monitor Virtuale è possibile vedere quando esattamente arriverà un autobus o un tram.
-
-Caratteristiche attuali:
-* guardare delle partenze alla fermata (in base all’orario offline e Monitor Virtuale)
-* la creazione di favoriti con la partenza successiva visibile sullo schermo principale,
-* guardare dalla favorita




diff --git a/app/src/main/play/it-IT/listing/icon/logo.png b/app/src/main/play/it-IT/listing/icon/logo.png
deleted file mode 100644
index 7a9bd078b1aed42188fe767423683c64a468312e..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/it-IT/listing/icon/logo.png and /dev/null differ




diff --git a/app/src/main/play/it-IT/listing/phoneScreenshots/Dash.png b/app/src/main/play/it-IT/listing/phoneScreenshots/Dash.png
deleted file mode 100644
index f8c2b61d439e4160b8d0193dcb8d1ab3bd2e429e..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/it-IT/listing/phoneScreenshots/Dash.png and /dev/null differ




diff --git a/app/src/main/play/it-IT/listing/phoneScreenshots/StopActivity.png b/app/src/main/play/it-IT/listing/phoneScreenshots/StopActivity.png
deleted file mode 100644
index de1163003b4205b0c6063228029912d5830efd72..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/it-IT/listing/phoneScreenshots/StopActivity.png and /dev/null differ




diff --git a/app/src/main/play/it-IT/listing/phoneScreenshots/StopSpecify.png b/app/src/main/play/it-IT/listing/phoneScreenshots/StopSpecify.png
deleted file mode 100644
index 77d36a1d0fe4a002881d3206a6b1e1218562183d..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/it-IT/listing/phoneScreenshots/StopSpecify.png and /dev/null differ




diff --git a/app/src/main/play/it-IT/listing/phoneScreenshots/modification.png b/app/src/main/play/it-IT/listing/phoneScreenshots/modification.png
deleted file mode 100644
index defccce5b66623b7dc6d0e27aa415238fc11d70b..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/it-IT/listing/phoneScreenshots/modification.png and /dev/null differ




diff --git a/app/src/main/play/it-IT/listing/phoneScreenshots/searchStop.png b/app/src/main/play/it-IT/listing/phoneScreenshots/searchStop.png
deleted file mode 100644
index bfe4811c230e1e5fab38c049d5b3ef95fc458559..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/it-IT/listing/phoneScreenshots/searchStop.png and /dev/null differ




diff --git a/app/src/main/play/it-IT/listing/promoGraphic/promo-graphic.png b/app/src/main/play/it-IT/listing/promoGraphic/promo-graphic.png
deleted file mode 100644
index 6e15268c85de20ae2ea38d0d3cfa85aa913e4f93..0000000000000000000000000000000000000000
Binary files a/app/src/main/play/it-IT/listing/promoGraphic/promo-graphic.png and /dev/null differ




diff --git a/app/src/main/play/it-IT/listing/shortdescription b/app/src/main/play/it-IT/listing/shortdescription
deleted file mode 100644
index 379808b820351d618d30ad2fc3b910c01bed5457..0000000000000000000000000000000000000000
--- a/app/src/main/play/it-IT/listing/shortdescription
+++ /dev/null
@@ -1 +0,0 @@
-Prima libera guida di vagare di Poznań




diff --git a/app/src/main/play/it-IT/whatsnew b/app/src/main/play/it-IT/whatsnew
deleted file mode 100644
index c5e305a6e9aa21fb45523afd12e177be5c6c279e..0000000000000000000000000000000000000000
--- a/app/src/main/play/it-IT/whatsnew
+++ /dev/null
@@ -1,8 +0,0 @@
-- ufficiale orario da ZTM
-- VM può essere utilizzato senza orario offline
-- l’orario offline utilizza le date esatte (invece di giorni lavorativi/sabato/festività)
-- VM è più veloce e più affidabile (in quanto è calcolato allo stesso modo delle partenze offline)
-- favoriti rescritti da capo
-- app è trasferibile su una memoria esterna
-- nuovi colori — grigio e verde — che si adattano al nuovo stile di Poznań
-- più correzioni di bug




diff --git a/app/src/main/play/pl-PL/whatsnew b/app/src/main/play/pl-PL/whatsnew
index 4133aac968c67993723579f25b0b86495d58850c..c05c1080da3ee49f68c365e7a9b2a62ef913c946 100644
--- a/app/src/main/play/pl-PL/whatsnew
+++ b/app/src/main/play/pl-PL/whatsnew
@@ -1,8 +1,18 @@
-- oficjalny rozkład od ZTM
-- VM może być używany bez rozkładu offline
-- rozkład offline operuje na dokładnych datach (zamiast dni powszednie/soboty/święta)
-- VM jest szybszy i pewniejszy (ponieważ jest generowany w ten sam sposób, co odjazdy offline)
-- ulubione przepisane od zera
-- aplikacja może być przenoszona do pamięci zewnętrznej
-- nowe kolory — szary i zielony — pasujące do nowego stylu Poznania
-- naprawiono wiele błędów
+[2.1] – 2019-02-04
+==================
+
+Dodane
+-----
+
++ pokazywanie braku wynków wyszukiwania
++ ładowanie w ekranie wyboru wiaty i ekranie przystanku
++ wiadomości WM
+
+Zmienione
+-------
+
+* pasek wyszukiwania
+* stan braku odjazdów
+* ‘teraz’ odjazd jest ‘za moment’ jeżeli pojazd nie jest na przystanku
+* sortowanie odjazdów: na przystanku są na górze
+* sortowanie wyników wyszukiwania wg podobieństwa




diff --git a/app/src/main/res/drawable/ic_error_outline.xml b/app/src/main/res/drawable/ic_error_outline.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a07a0f90acf868ee9698d8f7b559545f4984939d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_error_outline.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M11,15h2v2h-2zM11,7h2v6h-2zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
+</vector>




diff --git a/app/src/main/res/drawable/ic_help.xml b/app/src/main/res/drawable/ic_help.xml
deleted file mode 100644
index cd2b22d47887f6e146f303f750296cd7bee4c7f6..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_help.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="@color/textDark"
-        android:pathData="M11,18h2v-2h-2v2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5 0,-2.21 -1.79,-4 -4,-4z"/>
-</vector>




diff --git a/app/src/main/res/drawable/ic_home.xml b/app/src/main/res/drawable/ic_home.xml
deleted file mode 100644
index 9f17a8e8f3cef70da0b6573df691ffd762a6e78a..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_home.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="@color/textDark"
-        android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
-</vector>




diff --git a/app/src/main/res/drawable/ic_message.xml b/app/src/main/res/drawable/ic_message.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d2876bfad9b41c533cbcab6156b7585e326a5644
--- /dev/null
+++ b/app/src/main/res/drawable/ic_message.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,14L6,14v-2h12v2zM18,11L6,11L6,9h12v2zM18,8L6,8L6,6h12v2z"/>
+</vector>




diff --git a/app/src/main/res/drawable/ic_skip.xml b/app/src/main/res/drawable/ic_skip.xml
deleted file mode 100644
index 5248d32c9cdb23b266a221cb87153c4569215b06..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_skip.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector android:autoMirrored="true" android:height="24dp"
-    android:viewportHeight="24.0" android:viewportWidth="24.0"
-    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
-    <path android:fillColor="#FF000000" android:pathData="M10.09,15.59L11.5,17l5,-5 -5,-5 -1.41,1.41L12.67,11H3v2h9.67l-2.58,2.59zM19,3H5c-1.11,0 -2,0.9 -2,2v4h2V5h14v14H5v-4H3v4c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
-</vector>




diff --git a/app/src/main/res/drawable/ic_split.xml b/app/src/main/res/drawable/ic_split.xml
deleted file mode 100644
index da15e8544ea4430fa1acbd866fb7470f5337d936..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/ic_split.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="@color/textDark"
-        android:pathData="M14,4l2.29,2.29 -2.88,2.88 1.42,1.42 2.88,-2.88L20,10L20,4zM10,4L4,4v6l2.29,-2.29 4.71,4.7L11,20h2v-8.41l-5.29,-5.3z"/>
-</vector>




diff --git a/app/src/main/res/drawable/ic_texthandle_end.xml b/app/src/main/res/drawable/ic_texthandle_end.xml
new file mode 100644
index 0000000000000000000000000000000000000000..923f2b49a542f61b7fa1b19c720cba506b6767fb
--- /dev/null
+++ b/app/src/main/res/drawable/ic_texthandle_end.xml
@@ -0,0 +1,8 @@
+<vector android:autoMirrored="true" android:height="24dp"
+    android:viewportHeight="88" android:viewportWidth="176"
+    android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillAlpha="1" android:fillColor="#54af39"
+        android:pathData="M88,0A44,44 0,0 1,132 44,44 44,0 0,1 88,88 44,44 0,0 1,44 44V0Z"
+        android:strokeAlpha="1" android:strokeColor="#00000000"
+        android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="0.01982322"/>
+</vector>




diff --git a/app/src/main/res/drawable/ic_texthandle_middle.xml b/app/src/main/res/drawable/ic_texthandle_middle.xml
new file mode 100644
index 0000000000000000000000000000000000000000..da3c7962d98b2e2ef0113080f7491bad6e6c6dc6
--- /dev/null
+++ b/app/src/main/res/drawable/ic_texthandle_middle.xml
@@ -0,0 +1,7 @@
+<vector android:height="24dp" android:viewportHeight="88"
+    android:viewportWidth="88" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillAlpha="1" android:fillColor="#54af39"
+        android:pathData="m69.7747,25.7746a36.4509,36.4508 0,0 1,0 51.5492,36.4509 36.4508,0 0,1 -51.5494,0 36.4509,36.4508 0,0 1,0 -51.5492L44,0Z"
+        android:strokeAlpha="1" android:strokeColor="#00000000"
+        android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="0.01642212"/>
+</vector>




diff --git a/app/src/main/res/drawable/ic_texthandle_start.xml b/app/src/main/res/drawable/ic_texthandle_start.xml
new file mode 100644
index 0000000000000000000000000000000000000000..577a11d14e6d46dade232eca4176dbcf8f469879
--- /dev/null
+++ b/app/src/main/res/drawable/ic_texthandle_start.xml
@@ -0,0 +1,8 @@
+<vector android:autoMirrored="true" android:height="24dp"
+    android:viewportHeight="88" android:viewportWidth="176"
+    android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillAlpha="1" android:fillColor="#54af39"
+        android:pathData="M88,0A44,44 0,0 0,44 44,44 44,0 0,0 88,88 44,44 0,0 0,132 44V0Z"
+        android:strokeAlpha="1" android:strokeColor="#00000000"
+        android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="0.01982322"/>
+</vector>




diff --git a/app/src/main/res/drawable/ic_traffic.xml b/app/src/main/res/drawable/ic_traffic.xml
new file mode 100644
index 0000000000000000000000000000000000000000..081757364d3c63690943ab9b31d5c4109f420e2b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_traffic.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="@color/textDark"
+        android:pathData="M20,10h-3L17,8.86c1.72,-0.45 3,-2 3,-3.86h-3L17,4c0,-0.55 -0.45,-1 -1,-1L8,3c-0.55,0 -1,0.45 -1,1v1L4,5c0,1.86 1.28,3.41 3,3.86L7,10L4,10c0,1.86 1.28,3.41 3,3.86L7,15L4,15c0,1.86 1.28,3.41 3,3.86L7,20c0,0.55 0.45,1 1,1h8c0.55,0 1,-0.45 1,-1v-1.14c1.72,-0.45 3,-2 3,-3.86h-3v-1.14c1.72,-0.45 3,-2 3,-3.86zM12,19c-1.11,0 -2,-0.9 -2,-2s0.89,-2 2,-2c1.1,0 2,0.9 2,2s-0.89,2 -2,2zM12,14c-1.11,0 -2,-0.9 -2,-2s0.89,-2 2,-2c1.1,0 2,0.9 2,2s-0.89,2 -2,2zM12,9c-1.11,0 -2,-0.9 -2,-2 0,-1.11 0.89,-2 2,-2 1.1,0 2,0.89 2,2 0,1.1 -0.89,2 -2,2z"/>
+</vector>




diff --git a/app/src/main/res/drawable/icon_dev.xml b/app/src/main/res/drawable/icon_dev.xml
deleted file mode 100644
index a4b238053d6fdefaa6c74cfe50a206f56b769aff..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/icon_dev.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<vector android:height="24dp" android:viewportHeight="293"
-    android:viewportWidth="298" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
-    <path android:fillAlpha="1" android:fillColor="#5E5E5E"
-        android:pathData="m62.925,292.677v0c-3.69,-0.897 -5.684,-3.789 -4.288,-6.482L90.846,223.472c1.296,-2.593 5.485,-3.989 9.174,-2.992v0c3.69,0.897 5.684,3.789 4.288,6.482l-32.209,62.723c-1.296,2.593 -5.385,3.989 -9.174,2.992z" android:strokeWidth="0.99718279"/>
-    <path android:fillAlpha="1" android:fillColor="#5E5E5E"
-        android:pathData="m229.156,292.677v0c3.69,-0.897 5.684,-3.789 4.288,-6.482l-32.209,-62.723c-1.296,-2.593 -5.485,-3.989 -9.174,-2.992v0c-3.69,0.897 -5.684,3.789 -4.288,6.482l32.209,62.723c1.296,2.593 5.485,3.989 9.174,2.992z" android:strokeWidth="0.99718279"/>
-    <path android:fillAlpha="1" android:fillColor="#5E5E5E"
-        android:pathData="m151.076,37.797 l-0.598,0.199c-1.795,0.698 -3.789,-0.299 -4.487,-2.094L136.418,9.277c-0.698,-1.795 0.299,-3.789 2.094,-4.487l0.598,-0.199c1.795,-0.698 3.789,0.299 4.487,2.094l9.573,26.625c0.698,1.895 -0.299,3.889 -2.094,4.487z" android:strokeWidth="0.99718279"/>
-    <path android:fillAlpha="1" android:fillColor="#5E5E5E"
-        android:pathData="m180.294,4.79v0c0,2.094 -1.695,3.789 -3.789,3.789h-60.828c-2.094,0 -3.789,-1.695 -3.789,-3.789v0c0,-2.094 1.695,-3.789 3.789,-3.789h60.828c2.094,0 3.789,1.695 3.789,3.789z" android:strokeWidth="0.99718279"/>
-    <path android:fillAlpha="1" android:fillColor="#5E5E5E"
-        android:pathData="M218.286,237.034H73.795c-13.263,0 -23.932,-10.77 -23.932,-23.932V105.406c0,-41.184 33.406,-74.689 74.689,-74.689h43.178c41.184,0 74.689,33.406 74.689,74.689v107.696c-0.1,13.163 -10.869,23.932 -24.132,23.932z" android:strokeWidth="0.99718279"/>
-    <path android:fillColor="#FFFFFF" android:pathData="M212.104,146.789L79.977,146.789c-5.584,0 -10.171,-4.487 -10.171,-10.171l0,-34.802c0,-16.852 13.661,-30.514 30.514,-30.514L191.761,71.302c16.852,0 30.514,13.661 30.514,30.514l0,34.802c-0.1,5.684 -4.587,10.171 -10.171,10.171z"/>
-    <path android:fillColor="#FFFFFF" android:pathData="M161.148,56.344L130.933,56.344c-3.191,0 -5.684,-2.593 -5.684,-5.684l0,0c0,-3.191 2.593,-5.684 5.684,-5.684l30.215,0c3.191,0 5.684,2.593 5.684,5.684l0,0c0,3.091 -2.593,5.684 -5.684,5.684z"/>
-    <path android:fillColor="#FFFFFF" android:pathData="M86.957,192.36m-14.758,0a14.758,14.758 0,1 1,29.517 0a14.758,14.758 0,1 1,-29.517 0"/>
-    <path android:fillColor="#FFFFFF" android:pathData="M205.223,192.36m-14.758,0a14.758,14.758 0,1 1,29.517 0a14.758,14.758 0,1 1,-29.517 0"/>
-</vector>




diff --git a/app/src/main/res/drawable/nodb.xml b/app/src/main/res/drawable/nodb.xml
deleted file mode 100644
index 1fee6a8f9864a21b9ed0400fa435fe5adb58e7d4..0000000000000000000000000000000000000000
--- a/app/src/main/res/drawable/nodb.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="1080dp"
-        android:height="1920dp"
-        android:viewportWidth="285.75"
-        android:viewportHeight="508.0">
-    <path
-        android:pathData="M0,0h285.75v508h-285.75z"
-        android:fillAlpha="1"
-        android:strokeColor="#00000000"
-        android:fillColor="#e0e0e0"
-        android:strokeWidth="2.96499991"
-        android:strokeAlpha="1"/>
-    <path
-        android:pathData="M136.13,341.19h13.49v166.81h-13.49z"
-        android:fillAlpha="1"
-        android:strokeColor="#00000000"
-        android:fillColor="#aaaaaa"
-        android:strokeWidth="5.5416379"
-        android:strokeAlpha="1"/>
-    <path
-        android:pathData="M142.88,301.08m-42.33,0a42.33,42.33 69.77,1 1,84.67 0a42.33,42.33 69.77,1 1,-84.67 0"
-        android:strokeColor="#00000000"
-        android:fillColor="#0e518d"/>
-    <path
-        android:pathData="m131.65,282.69 l-10.98,7.52 9.06,6.2L113.25,296.41l0.3,1.93L111.83,304.94l0,8.44l5.23,0l0.45,-2.03l17.69,0l0.45,2.03l14.43,0l0.45,-2.03l17.69,0l0.45,2.03L173.92,313.38L173.92,304.94l-1.73,-6.61 0.31,-1.93L133.57,296.41l9.05,-6.2zM131.65,284.42 L140.09,290.2l0,0.02l-8.44,5.79 -8.44,-5.79l0,-0.02zM114.62,298.33L119.3,298.33L119.3,304.94L112.9,304.94ZM120.52,298.33L128.45,298.33L128.45,304.94L120.52,304.94ZM129.67,298.33l7.93,0l0,6.61l-7.93,0zM138.81,298.33l8.13,0L146.94,304.94L138.81,304.94ZM148.16,298.33l7.93,0l0,6.61l-7.93,0zM157.31,298.33l7.93,0l0,6.61l-7.93,0zM166.45,298.33l4.67,0l1.72,6.61L166.45,304.94ZM119.14,312.66l0,0.69c0,1.51 1.22,2.74 2.74,2.74 1.21,0 2.25,-0.79 2.6,-1.89l3.82,0c0.36,1.1 1.39,1.89 2.6,1.89 1.51,0 2.74,-1.22 2.74,-2.74l-0.01,-0.69L119.14,312.66ZM152.12,312.66 L152.11,313.36c0,1.51 1.22,2.74 2.74,2.74 1.21,0 2.25,-0.79 2.6,-1.89l3.82,0c0.36,1.1 1.39,1.89 2.6,1.89 1.51,0 2.74,-1.22 2.74,-2.74l0,-0.69l-14.49,0z"
-        android:strokeColor="#00000000"
-        android:fillColor="#ffffff"/>
-    <path
-        android:pathData="M142.88,301.08m-40.06,0a40.06,40.06 59.4,1 1,80.12 0a40.06,40.06 82.72,1 1,-80.12 0"
-        android:strokeColor="#f7fbf5"
-        android:fillColor="#00000000"
-        android:strokeWidth="6.73600006"/>
-</vector>




diff --git a/app/src/main/res/layout/activity_dash.xml b/app/src/main/res/layout/activity_dash.xml
index 120aa55d494af4dc38b0eda1ada09d28eb19086d..ee61d3aafc6658f882403f31ff3fa60cb9e2631a 100644
--- a/app/src/main/res/layout/activity_dash.xml
+++ b/app/src/main/res/layout/activity_dash.xml
@@ -1,16 +1,17 @@
 <?xml version="1.0" encoding="utf-8"?>
-<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/drawer_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <android.support.constraint.ConstraintLayout
+    <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/main_layout"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
+        android:layout_height="match_parent"
+        android:clipChildren="false">
 
-        <android.support.design.widget.AppBarLayout
+        <com.google.android.material.appbar.AppBarLayout
             android:id="@+id/appbar"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -19,7 +20,7 @@             android:paddingTop="@dimen/appbar_padding_top"
             android:theme="@style/AppTheme.AppBarOverlay"
             android:visibility="invisible">
 
-            <android.support.v7.widget.Toolbar
+            <androidx.appcompat.widget.Toolbar
                 android:id="@+id/toolbar"
                 android:layout_width="match_parent"
                 android:layout_height="?attr/actionBarSize"
@@ -27,41 +28,43 @@                 android:layout_weight="1"
                 android:background="@color/colorAccentDark"
                 app:layout_scrollFlags="scroll|enterAlways"
                 app:popupTheme="@style/AppTheme.PopupOverlay" />
-        </android.support.design.widget.AppBarLayout>
+        </com.google.android.material.appbar.AppBarLayout>
 
-        <android.support.v7.widget.RecyclerView
+        <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/favourites_list"
             android:layout_width="0dp"
             android:layout_height="0dp"
-            android:layout_marginBottom="0dp"
-            android:layout_marginTop="80dp"
+            android:layout_marginTop="8dp"
             android:scrollbars="none"
+            app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toBottomOf="@id/search_view" />
+            app:layout_constraintTop_toBottomOf="@+id/search_view" />
 
-        <com.arlib.floatingsearchview.FloatingSearchView
+        <com.mancj.materialsearchbar.MaterialSearchBar
             android:id="@+id/search_view"
+            style="@style/SearchBarTheme"
+            app:mt_searchBarColor="@color/cardColor"
             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:layout_height="wrap_content"
+            android:layout_marginStart="8dp"
+            android:layout_marginTop="8dp"
+            android:layout_marginEnd="8dp"
+            android:fadeScrollbars="false"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:mt_hint="@string/search_placeholder"
+            app:mt_navIconEnabled="true"
+            app:mt_placeholder="@string/search_placeholder"
+            app:mt_roundedSearchBarEnabled="true"
+            app:mt_speechMode="false" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
 
-    </android.support.constraint.ConstraintLayout>
-
-    <!-- The navigation drawer -->
-    <android.support.design.widget.NavigationView
+    <com.google.android.material.navigation.NavigationView
         android:id="@+id/drawer"
         android:layout_width="240dp"
         android:layout_height="match_parent"
         android:layout_gravity="start"
-        app:menu="@menu/menu_drawer">
-    </android.support.design.widget.NavigationView>
-</android.support.v4.widget.DrawerLayout>
\ No newline at end of file
+        app:menu="@menu/menu_drawer" />
+</androidx.drawerlayout.widget.DrawerLayout>
\ No newline at end of file




diff --git a/app/src/main/res/layout/activity_edit_favourite.xml b/app/src/main/res/layout/activity_edit_favourite.xml
index 8788c2dcff597cb72bf74e8478c1040bde28a941..0fecff28a7bc950d101cefc5544d96a09a7652db 100644
--- a/app/src/main/res/layout/activity_edit_favourite.xml
+++ b/app/src/main/res/layout/activity_edit_favourite.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/dialog_favourite"
@@ -7,14 +7,14 @@     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical">
 
-    <android.support.design.widget.AppBarLayout
+    <com.google.android.material.appbar.AppBarLayout
         android:id="@+id/appbar"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:paddingTop="@dimen/appbar_padding_top"
         android:theme="@style/AppTheme.AppBarOverlay">
 
-        <android.support.v7.widget.Toolbar
+        <androidx.appcompat.widget.Toolbar
             android:id="@+id/toolbar"
             android:layout_width="match_parent"
             android:layout_height="?attr/actionBarSize"
@@ -22,7 +22,7 @@             android:layout_weight="1"
             android:background="@color/colorPrimary"
             app:layout_scrollFlags="scroll|enterAlways"
             app:popupTheme="@style/AppTheme.PopupOverlay" />
-    </android.support.design.widget.AppBarLayout>
+    </com.google.android.material.appbar.AppBarLayout>
 
     <TextView
         android:id="@+id/name_label"
@@ -39,16 +39,18 @@              android:id="@+id/favourite_name_edit"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_marginEnd="8dp"
         android:layout_marginStart="8dp"
+        android:layout_marginEnd="8dp"
         android:ems="10"
+        android:importantForAutofill="no"
         android:inputType="text"
         android:text=""
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/name_label" />
+        app:layout_constraintTop_toBottomOf="@+id/name_label"
+        tools:ignore="UnusedAttribute" />
 
-    <android.support.v7.widget.RecyclerView
+    <androidx.recyclerview.widget.RecyclerView
         android:id="@+id/favourite_edit_list"
         android:layout_width="0dp"
         android:layout_height="0dp"
@@ -59,7 +61,7 @@         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@+id/favourite_name_edit">
 
-    </android.support.v7.widget.RecyclerView>
+    </androidx.recyclerview.widget.RecyclerView>
 
     <ProgressBar
         android:id="@+id/favourite_edit_loading"
@@ -71,4 +73,4 @@         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@+id/favourite_name_edit" />
 
-</android.support.constraint.ConstraintLayout>
\ No newline at end of file
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file




diff --git a/app/src/main/res/layout/activity_help.xml b/app/src/main/res/layout/activity_help.xml
deleted file mode 100644
index c59e2511f540c91420ab1e3d8bd5b13e47687b04..0000000000000000000000000000000000000000
--- a/app/src/main/res/layout/activity_help.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true"
-    tools:context="ml.adamsprogs.bimba.activities.HelpActivity">
-
-    <android.support.design.widget.AppBarLayout
-        android:id="@+id/app_bar"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/app_bar_height"
-        android:fitsSystemWindows="true"
-        android:theme="@style/AppTheme.AppBarOverlay">
-
-        <android.support.design.widget.CollapsingToolbarLayout
-            android:id="@+id/toolbar_layout"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:fitsSystemWindows="true"
-            app:contentScrim="?attr/colorPrimary"
-            app:layout_scrollFlags="scroll|exitUntilCollapsed"
-            app:toolbarId="@+id/toolbar">
-
-            <android.support.v7.widget.Toolbar
-                android:id="@+id/toolbar"
-                android:layout_width="match_parent"
-                android:layout_height="?attr/actionBarSize"
-                app:layout_collapseMode="pin"
-                app:popupTheme="@style/AppTheme.PopupOverlay" />
-
-        </android.support.design.widget.CollapsingToolbarLayout>
-    </android.support.design.widget.AppBarLayout>
-
-    <include layout="@layout/content_help" />
-
-</android.support.design.widget.CoordinatorLayout>




diff --git a/app/src/main/res/layout/activity_line_specify.xml b/app/src/main/res/layout/activity_line_specify.xml
index 12dfce96805bec6de2222a24fdb2c9c65d76c5e3..ce51c5661d1f2e400fc2ea279aceb915ae4310ef 100644
--- a/app/src/main/res/layout/activity_line_specify.xml
+++ b/app/src/main/res/layout/activity_line_specify.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/main_content"
@@ -8,14 +8,14 @@     android:layout_height="match_parent"
     android:fitsSystemWindows="true"
     tools:context="ml.adamsprogs.bimba.activities.LineSpecifyActivity">
 
-    <android.support.design.widget.AppBarLayout
+    <com.google.android.material.appbar.AppBarLayout
         android:id="@+id/appbar"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:paddingTop="@dimen/appbar_padding_top"
         android:theme="@style/AppTheme.AppBarOverlay">
 
-        <android.support.v7.widget.Toolbar
+        <androidx.appcompat.widget.Toolbar
             android:id="@+id/toolbar"
             android:layout_width="match_parent"
             android:layout_height="?attr/actionBarSize"
@@ -25,32 +25,32 @@             app:layout_scrollFlags="scroll|enterAlways"
             app:popupTheme="@style/AppTheme.PopupOverlay"
             app:title="@string/app_name">
 
-        </android.support.v7.widget.Toolbar>
+        </androidx.appcompat.widget.Toolbar>
 
-        <android.support.design.widget.TabLayout
+        <com.google.android.material.tabs.TabLayout
             android:id="@+id/tabs"
             android:layout_width="match_parent"
             android:layout_height="wrap_content">
 
-            <android.support.design.widget.TabItem
+            <com.google.android.material.tabs.TabItem
                 android:id="@+id/tabItem"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:text="@string/tab_text_line_to" />
 
-            <android.support.design.widget.TabItem
+            <com.google.android.material.tabs.TabItem
                 android:id="@+id/tabItem2"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:text="@string/tab_text_line_fro" />
 
-        </android.support.design.widget.TabLayout>
-    </android.support.design.widget.AppBarLayout>
+        </com.google.android.material.tabs.TabLayout>
+    </com.google.android.material.appbar.AppBarLayout>
 
-    <android.support.v4.view.ViewPager
+    <androidx.viewpager.widget.ViewPager
         android:id="@+id/container"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         app:layout_behavior="@string/appbar_scrolling_view_behavior" />
 
-</android.support.design.widget.CoordinatorLayout>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>




diff --git a/app/src/main/res/layout/activity_nodb.xml b/app/src/main/res/layout/activity_nodb.xml
deleted file mode 100644
index 01276425a1dac205ce4596cae2aa724229a79701..0000000000000000000000000000000000000000
--- a/app/src/main/res/layout/activity_nodb.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <ImageView
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:contentDescription="@string/no_database_background"
-        android:scaleType="centerCrop"
-        app:srcCompat="@drawable/nodb" />
-
-    <android.support.constraint.ConstraintLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical">
-
-        <TextView
-            android:id="@+id/no_db_caption"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginBottom="8dp"
-            android:layout_marginEnd="8dp"
-            android:layout_marginStart="8dp"
-            android:layout_marginTop="8dp"
-            android:text=""
-            android:textAlignment="center"
-            android:textAppearance="@style/TextAppearance.AppCompat.Headline"
-            android:textColor="@color/colorPrimary"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintVertical_bias="0.4" />
-
-        <android.support.design.widget.FloatingActionButton
-            android:id="@+id/skip_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginBottom="16dp"
-            android:layout_marginEnd="16dp"
-            android:clickable="true"
-            android:focusable="true"
-            app:fabSize="normal"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"
-            app:srcCompat="@drawable/ic_skip" />
-
-    </android.support.constraint.ConstraintLayout>
-</FrameLayout>




diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml
index a989df9974dc26f0fcd10e9d7f0190a99cad86bf..b5342c25185db6b54c6e668d71cd9667334a5b6d 100644
--- a/app/src/main/res/layout/activity_settings.xml
+++ b/app/src/main/res/layout/activity_settings.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
-<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     xmlns:app="http://schemas.android.com/apk/res-auto">
 
-    <android.support.design.widget.AppBarLayout
+    <com.google.android.material.appbar.AppBarLayout
         android:id="@+id/appbar"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -14,7 +14,7 @@         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent">
 
-        <android.support.v7.widget.Toolbar
+        <androidx.appcompat.widget.Toolbar
             android:id="@+id/toolbar"
             android:layout_width="match_parent"
             android:layout_height="?attr/actionBarSize"
@@ -24,8 +24,8 @@             app:layout_scrollFlags="scroll|enterAlways"
             app:popupTheme="@style/AppTheme.PopupOverlay"
             app:title="@string/title_activity_settings">
 
-        </android.support.v7.widget.Toolbar>
-    </android.support.design.widget.AppBarLayout>
+        </androidx.appcompat.widget.Toolbar>
+    </com.google.android.material.appbar.AppBarLayout>
 
     <fragment
         android:id="@+id/settings_fragment"
@@ -38,4 +38,4 @@         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@+id/appbar" />
-</android.support.constraint.ConstraintLayout>
\ No newline at end of file
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file




diff --git a/app/src/main/res/layout/activity_stop.xml b/app/src/main/res/layout/activity_stop.xml
index d6a0b92bfbdd7ad1d7be8b4b6481ca929b573770..b3f8038ef17369a5e258300fb6a1f6ce48168dad 100644
--- a/app/src/main/res/layout/activity_stop.xml
+++ b/app/src/main/res/layout/activity_stop.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/stop_layout"
@@ -8,15 +8,14 @@     android:layout_height="match_parent"
     android:fitsSystemWindows="true"
     tools:context="ml.adamsprogs.bimba.activities.StopActivity">
 
-
-    <android.support.design.widget.AppBarLayout
+    <com.google.android.material.appbar.AppBarLayout
         android:id="@+id/appbar"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:paddingTop="@dimen/appbar_padding_top"
         android:theme="@style/AppTheme.AppBarOverlay">
 
-        <android.support.v7.widget.Toolbar
+        <androidx.appcompat.widget.Toolbar
             android:id="@+id/toolbar"
             android:layout_width="match_parent"
             android:layout_height="?attr/actionBarSize"
@@ -26,41 +25,94 @@             app:layout_scrollFlags="scroll|enterAlways"
             app:popupTheme="@style/AppTheme.PopupOverlay"
             app:title="@string/app_name">
 
-        </android.support.v7.widget.Toolbar>
+        </androidx.appcompat.widget.Toolbar>
 
         <Spinner
             android:id="@+id/dateSpinner"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginBottom="8dp"
+            android:layout_marginStart="8dp"
+            android:layout_marginLeft="8dp"
             android:layout_marginEnd="8dp"
-            android:layout_marginLeft="8dp"
             android:layout_marginRight="8dp"
-            android:layout_marginStart="8dp"
+            android:layout_marginBottom="8dp"
             android:layout_weight="1"
             android:visibility="gone" />
+    </com.google.android.material.appbar.AppBarLayout>
 
+    <include
+        android:id="@+id/banner"
+        layout="@layout/banner"
+        android:layout_width="match_parent"
+        android:layout_height="120dp"
+        android:visibility="gone"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/appbar" />
 
-    </android.support.design.widget.AppBarLayout>
+    <ImageView
+        android:id="@+id/emptyStateIcon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:layout_marginTop="8dp"
+        android:layout_marginEnd="8dp"
+        android:layout_marginBottom="8dp"
+        android:contentDescription="@string/departures_empty_state_icon"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/banner"
+        app:srcCompat="@drawable/ic_traffic" />
 
-    <android.support.v7.widget.RecyclerView
+    <TextView
+        android:id="@+id/emptyStateText"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:layout_marginTop="8dp"
+        android:layout_marginEnd="8dp"
+        android:text="@string/no_departures"
+        android:visibility="gone"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/emptyStateIcon" />
+
+    <ProgressBar
+        android:id="@+id/progressBar"
+        style="?android:attr/progressBarStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:layout_marginTop="8dp"
+        android:layout_marginEnd="8dp"
+        android:layout_marginBottom="8dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/banner" />
+
+    <androidx.recyclerview.widget.RecyclerView
         android:id="@+id/departuresList"
         android:layout_width="0dp"
         android:layout_height="0dp"
+        android:visibility="gone"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/appbar" />
+        app:layout_constraintTop_toBottomOf="@+id/banner" />
 
-    <android.support.design.widget.FloatingActionButton
+    <com.google.android.material.floatingactionbutton.FloatingActionButton
         android:id="@+id/fab"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="end|bottom"
         android:layout_margin="@dimen/fab_margin"
-        android:layout_marginBottom="16dp"
         android:layout_marginEnd="16dp"
+        android:layout_marginBottom="16dp"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         app:srcCompat="@drawable/ic_favourite" />
-</android.support.constraint.ConstraintLayout>
+
+</androidx.constraintlayout.widget.ConstraintLayout>




diff --git a/app/src/main/res/layout/activity_stop_specify.xml b/app/src/main/res/layout/activity_stop_specify.xml
index 137b0aaee6804a4787c5368014545db621f99669..681d5a0a455e1c500a1ccbe98080f8a3f6585d71 100644
--- a/app/src/main/res/layout/activity_stop_specify.xml
+++ b/app/src/main/res/layout/activity_stop_specify.xml
@@ -1,12 +1,22 @@
 <?xml version="1.0" encoding="utf-8"?>
-<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     tools:context="ml.adamsprogs.bimba.activities.StopSpecifyActivity">
 
-    <android.support.design.widget.AppBarLayout
+    <ProgressBar
+        android:id="@+id/progressBar"
+        style="?android:attr/progressBarStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/appbar" />
+
+    <com.google.android.material.appbar.AppBarLayout
         android:id="@+id/appbar"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -14,7 +24,7 @@         android:paddingTop="@dimen/appbar_padding_top"
         android:theme="@style/AppTheme.AppBarOverlay">
 
         <!--suppress AndroidDomInspection -->
-        <android.support.v7.widget.Toolbar
+        <androidx.appcompat.widget.Toolbar
             android:id="@+id/toolbar"
             android:layout_width="match_parent"
             android:layout_height="?attr/actionBarSize"
@@ -22,9 +32,9 @@             android:layout_weight="1"
             android:background="@color/colorPrimary"
             app:popupTheme="@style/AppTheme.PopupOverlay"
             app:title="@string/app_name" />
-    </android.support.design.widget.AppBarLayout>
+    </com.google.android.material.appbar.AppBarLayout>
 
-    <android.support.v7.widget.RecyclerView
+    <androidx.recyclerview.widget.RecyclerView
         android:id="@+id/list_view"
         android:layout_width="0dp"
         android:layout_height="0dp"
@@ -33,4 +43,4 @@         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@+id/appbar" />
 
-</android.support.constraint.ConstraintLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>




diff --git a/app/src/main/res/layout/banner.xml b/app/src/main/res/layout/banner.xml
new file mode 100644
index 0000000000000000000000000000000000000000..edb12b05be6566596ba970dff8c2db13821df70b
--- /dev/null
+++ b/app/src/main/res/layout/banner.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="120dp"
+    android:orientation="vertical">
+
+    <View
+        android:id="@+id/banner_separator"
+        android:layout_width="fill_parent"
+        android:layout_height="1dp"
+        android:background="#90909090"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintEnd_toStartOf="parent"
+        app:layout_constraintStart_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <Button
+        android:id="@+id/banner_more"
+        style="@style/Widget.AppCompat.Button.Borderless.Colored"
+        android:layout_width="wrap_content"
+        android:layout_height="36dp"
+        android:layout_marginEnd="8dp"
+        android:layout_marginBottom="8dp"
+        android:text="@string/more"
+        android:textAppearance="@style/TextAppearance.AppCompat.Button"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent" />
+
+    <TextView
+        android:id="@+id/banner_text"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dp"
+        android:layout_marginTop="24dp"
+        android:layout_marginEnd="16dp"
+        android:layout_marginBottom="20dp"
+        android:ellipsize="end"
+        android:maxLines="2"
+        android:minLines="1"
+        android:singleLine="false"
+        android:text=""
+        android:textAppearance="@style/TextAppearance.AppCompat.Body2"
+        app:layout_constraintBottom_toTopOf="@+id/banner_more"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/banner_icon"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <ImageView
+        android:id="@+id/banner_icon"
+        android:layout_width="40dp"
+        android:layout_height="40dp"
+        android:layout_marginStart="16dp"
+        android:contentDescription="@string/vm_message_icon"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="@+id/banner_text"
+        app:srcCompat="@drawable/ic_message" />
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file




diff --git a/app/src/main/res/layout/content_help.xml b/app/src/main/res/layout/content_help.xml
deleted file mode 100644
index 9a733196da59d83c7adecb48a865eba0f12a5013..0000000000000000000000000000000000000000
--- a/app/src/main/res/layout/content_help.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    app:layout_behavior="@string/appbar_scrolling_view_behavior"
-    tools:context="ml.adamsprogs.bimba.activities.HelpActivity"
-    tools:showIn="@layout/activity_help">
-
-    <TextView
-        android:id="@+id/help_text"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:background="@android:color/transparent"
-        android:text="@string/help_text"
-        android:layout_margin="@dimen/text_margin"/>
-</android.support.v4.widget.NestedScrollView>




diff --git a/app/src/main/res/layout/fragment_line_specify.xml b/app/src/main/res/layout/fragment_line_specify.xml
index c3ef48c574cb3df2b0a912cd50fb090b97b984d0..1a630b9bd7f0c510d4405a24e72d7d6f3b40249b 100644
--- a/app/src/main/res/layout/fragment_line_specify.xml
+++ b/app/src/main/res/layout/fragment_line_specify.xml
@@ -1,4 +1,4 @@
-<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/constraintLayout"
@@ -19,4 +19,4 @@         app:layout_constraintTop_toTopOf="@+id/constraintLayout"
         tools:layout_constraintLeft_creator="1"
         tools:layout_constraintTop_creator="1" />
 
-</android.support.constraint.ConstraintLayout>
\ No newline at end of file
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file




diff --git a/app/src/main/res/layout/row_departure.xml b/app/src/main/res/layout/row_departure.xml
index 30ff8bb41d1335b417de5513b6cb6e5e5cbf42e5..d313ecd40420af6c649362838954ef4e1a6d495e 100644
--- a/app/src/main/res/layout/row_departure.xml
+++ b/app/src/main/res/layout/row_departure.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/departureRow"
@@ -76,4 +76,4 @@         android:visibility="gone"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         app:srcCompat="@drawable/ic_low_floor" />
-</android.support.constraint.ConstraintLayout>
\ No newline at end of file
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file




diff --git a/app/src/main/res/layout/row_favourite.xml b/app/src/main/res/layout/row_favourite.xml
index 509a5cbe3111eb1ad5746fc948150efcb30b0bb9..9d517fa29196b630844733f97b029388999f784f 100644
--- a/app/src/main/res/layout/row_favourite.xml
+++ b/app/src/main/res/layout/row_favourite.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/favourite_card"
@@ -17,7 +17,7 @@         android:layout_height="match_parent"
         android:background="@color/colorAccent"
         android:visibility="invisible" />
 
-    <android.support.constraint.ConstraintLayout
+    <androidx.constraintlayout.widget.ConstraintLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
@@ -80,6 +80,6 @@             app:layout_constraintTop_toTopOf="parent"
             app:srcCompat="@drawable/ic_more"
             tools:layout_editor_absoluteX="328dp"
             tools:layout_editor_absoluteY="16dp" />
-    </android.support.constraint.ConstraintLayout>
+    </androidx.constraintlayout.widget.ConstraintLayout>
 
-</android.support.v7.widget.CardView>
\ No newline at end of file
+</androidx.cardview.widget.CardView>
\ No newline at end of file




diff --git a/app/src/main/res/layout/row_favourite_edit.xml b/app/src/main/res/layout/row_favourite_edit.xml
index 1d48cfacec0056c94b5756ed01064e09d3de2e6e..18e99b529d051bc5490f8f6826e8e9acbbdd8568 100644
--- a/app/src/main/res/layout/row_favourite_edit.xml
+++ b/app/src/main/res/layout/row_favourite_edit.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="vertical">
@@ -11,10 +10,10 @@              android:id="@+id/favourite_edit_row"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_marginBottom="16dp"
-        android:layout_marginEnd="16dp"
         android:layout_marginStart="16dp"
         android:layout_marginTop="16dp"
+        android:layout_marginEnd="16dp"
+        android:layout_marginBottom="16dp"
         android:text=""
         android:textAlignment="viewStart"
         android:textAppearance="@style/TextAppearance.AppCompat"
@@ -27,27 +26,13 @@              android:id="@+id/favourite_edit_delete"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginBottom="16dp"
-        android:layout_marginEnd="8dp"
         android:layout_marginTop="16dp"
+        android:layout_marginEnd="8dp"
+        android:layout_marginBottom="16dp"
         android:contentDescription="@string/favourite_element_delete_button"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintTop_toTopOf="parent"
         app:srcCompat="@drawable/ic_delete" />
 
-    <!--<ImageView-->
-        <!--android:id="@+id/favourite_edit_split"-->
-        <!--android:layout_width="wrap_content"-->
-        <!--android:layout_height="wrap_content"-->
-        <!--android:layout_marginBottom="16dp"-->
-        <!--android:layout_marginEnd="58dp"-->
-        <!--android:layout_marginTop="16dp"-->
-        <!--app:layout_constraintBottom_toBottomOf="parent"-->
-        <!--app:layout_constraintEnd_toEndOf="parent"-->
-        <!--app:layout_constraintTop_toTopOf="parent"-->
-        <!--app:srcCompat="@drawable/ic_split"-->
-        <!--tools:layout_editor_absoluteX="302dp"-->
-        <!--tools:layout_editor_absoluteY="16dp"-->
-        <!--android:contentDescription="@string/favourite_element_split_button" />-->
-</android.support.constraint.ConstraintLayout>
\ No newline at end of file
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file




diff --git a/app/src/main/res/layout/row_shed.xml b/app/src/main/res/layout/row_shed.xml
index a99d5bad8c799e2dde6d960e2d64f741fcb7b67d..4be60699faeef456d8a654e9e1133d9debe00f1a 100644
--- a/app/src/main/res/layout/row_shed.xml
+++ b/app/src/main/res/layout/row_shed.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/shed_row"
     android:layout_width="match_parent"
@@ -8,7 +8,7 @@     android:layout_margin="4dp"
     android:foreground="?android:attr/selectableItemBackground"
     app:cardElevation="2dp">
 
-    <android.support.constraint.ConstraintLayout
+    <androidx.constraintlayout.widget.ConstraintLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
@@ -36,5 +36,5 @@             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toBottomOf="@+id/stop_code" />
-    </android.support.constraint.ConstraintLayout>
-</android.support.v7.widget.CardView>
\ No newline at end of file
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</androidx.cardview.widget.CardView>
\ No newline at end of file




diff --git a/app/src/main/res/layout/row_suggestion.xml b/app/src/main/res/layout/row_suggestion.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6c2b77d5f75e48124c32f4a5c74d57c598a50067
--- /dev/null
+++ b/app/src/main/res/layout/row_suggestion.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/row_suggestion"
+    android:layout_width="match_parent"
+    android:layout_height="48dp"
+    android:foreground="?android:attr/selectableItemBackground"
+    android:orientation="vertical">
+
+
+    <ImageView
+        android:id="@+id/suggestion_row_image"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:layout_marginTop="8dp"
+        android:layout_marginBottom="8dp"
+        android:contentDescription="@string/suggestion_row_image"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <TextView
+        android:id="@+id/suggestion_row_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:layout_marginTop="8dp"
+        android:text=""
+        android:textAppearance="@style/TextAppearance.AppCompat.SearchResult.Title"
+        app:layout_constraintStart_toEndOf="@+id/suggestion_row_image"
+        app:layout_constraintTop_toTopOf="parent" />
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file




diff --git a/app/src/main/res/menu/menu_drawer.xml b/app/src/main/res/menu/menu_drawer.xml
index 3dbf30fa996dbd94345b8d176a0f110b1729033c..97188f56a4a54264e7c38e98989bbe959d299c4e 100644
--- a/app/src/main/res/menu/menu_drawer.xml
+++ b/app/src/main/res/menu/menu_drawer.xml
@@ -6,7 +6,7 @@             android:id="@+id/drawer_home"
             android:icon="@drawable/ic_home"
             android:title="@string/home" />
     </group>-->
-    <group android:id="@+id/drawer_group_actions">
+    <group>
         <item
             android:id="@+id/drawer_refresh"
             android:icon="@drawable/ic_refresh"
@@ -21,9 +21,7 @@             android:icon="@drawable/ic_settings"
             android:title="@string/settings"
             />
     </group>
-    <group
-        android:id="@+id/drawer_group_validity"
-        android:enabled="false">
+    <group android:enabled="false">
         <item
             android:id="@+id/drawer_validity_since"
             android:title="" />




diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 5982e32ecdb6a838a1c7f45e3f82e9a77241302e..06523ae87b1d3d5e0ca0bf98a16847c862b5a204 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -13,4 +13,7 @@
     <color name="tram">#00adef</color>
     <color name="bus">#c4212a</color>
     <color name="text_on_toolbar">#ffffff</color>
+
+    <color name="textDark">#141415</color>
+    <color name="cardColor">#ffffff</color>
 </resources>




diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 79d1b762f2b41389057499b42141852197f2ef0f..d1cd0246f80ac882c028743baba512892ebf7262 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -1,9 +1,6 @@
 <resources>
-    <!-- Default screen margins, per the Android Design guidelines. -->
     <dimen name="activity_horizontal_margin">16dp</dimen>
     <dimen name="activity_vertical_margin">16dp</dimen>
     <dimen name="fab_margin">16dp</dimen>
     <dimen name="appbar_padding_top">8dp</dimen>
-    <dimen name="app_bar_height">180dp</dimen>
-    <dimen name="text_margin">16dp</dimen>
 </resources>




diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 513e4652283dcb5cd773feefafbc6ce810b49bcd..48e08d445b8cf87419a49aa7b3d2b839a2538ba5 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,19 +1,12 @@
 <resources>
     <string name="app_name" translatable="false">Bimba</string>
-    <string name="no_timetable">No timetable found. Connect to the Internet and wait for a timetable to be downloaded</string>
     <string name="timetable_downloaded">New timetable downloaded</string>
     <string name="title_activity_stop" translatable="false">StopActivity</string>
-    <string name="tab_workday_text">Workdays</string>
-    <string name="tab_saturday_text">Saturdays</string>
-    <string name="tab_sunday_text">Sundays</string>
     <string name="action_change_type">Type</string>
     <string name="departure_type_icon_description" translatable="false">departure type (timetable, VM)</string>
     <string name="departure_to">→ %1$s</string>
     <string name="departure_to_line">%1$s → %2$s</string>
     <string name="departure_at">At %1$s</string>
-    <string name="no_database_background" translatable="false">no database background</string>
-    <string name="no_db_connect">Connect to the Internet to download the timetable</string>
-    <string name="no_db_downloading">Timetable is being downloaded…</string>
     <string name="timetable_downloading">Downloading timetable</string>
     <string name="timetable_downloading_progress" translatable="false">%1$1.2f MiB/%2$1.2f MiB</string>
     <string name="timetable_decompressing">Decompressing timetable</string>
@@ -21,19 +14,15 @@     Stop…
     <string name="no_connectivity_cant_update">No connectivity – can’t update timetable</string>
     <string name="no_connectivity">No connectivity</string>
     <string name="timetable_up_to_date">Timetable is up-to-date</string>
-    <string name="validity_failed">Downloaded timetable is corrupted – can’t update</string>
     <string name="error_try_later">Error. Try again later</string>
     <string name="now">Now</string>
     <string name="stop_already_fav">This stop is already in favourites</string>
     <string name="favourite_row_more_button" translatable="false">favourite row more button</string>
     <string name="action_edit">Edit</string>
     <string name="action_delete">Delete</string>
-    <string name="done">Done</string>
-    <string name="favourite_edit">Edit favourite</string>
     <string name="favourite_name">Favourite name</string>
     <string name="edit_favourite_title">Edit ‘%1$s’</string>
     <string name="favourite_element_delete_button" translatable="false">favourite element delete button</string>
-    <string name="favourite_element_split_button" translatable="false">favourite element split button</string>
     <string name="no_next_departure">No next departure</string>
     <string name="action_merge">Merge</string>
     <string name="merge_favourites">Merge favourites</string>
@@ -42,28 +31,14 @@     In %1$s minute
     <string name="departure_in__plural_genitive">In %1$s minutes</string>
     <string name="departure_in__plural_nominative">In %1$s minutes</string>
 
-    <string name="home">Home</string>
     <string name="refresh">Update timetable</string>
-    <string name="help">Help</string>
-    <string name="navigation_drawer_home_button" translatable="false">navigation drawer home button</string>
-    <string name="navigation_drawer_refresh_button" translatable="false">navigation drawer refresh button</string>
-    <string name="navigation_drawer_help_button" translatable="false">navigation drawer help button</string>
     <string name="title_activity_help">Help</string>
-    <string name="help_text">
-        "Why a favourite card shows ‘No next departure’?\n\n"
-
-        "Favourite cards contain times for today and tomorrow."
-        "‘No next departure’ may happen when, e.g. there is no timetable for tomorrow and there"
-        "are no more departures today.\n\n"
-    </string>
     <string name="departure_row_getting_departures">Getting departures…</string>
     <string name="valid_since">Valid since %1$s</string>
     <string name="valid_till">Valid till %1$s</string>
     <string name="departure_floor" translatable="false">departure floor type (lowFloor)</string>
     <string name="departure_info" translatable="false">departure info icon</string>
-    <string name="refreshing_cache">Refreshing cache. May take some time…</string>
 
-    <string name="today">Today</string>
     <string name="no_departures">No departures</string>
     <string name="title_activity_main" translatable="false">LineSpecifyActivity</string>
     <string name="tab_text_line_to">To</string>
@@ -91,4 +66,10 @@     Sat
     <string name="Sun">Sun</string>
     <string name="summary_timetable_automatic_update">Automatically check for and download timetable updates</string>
     <string name="server_error">Server error</string>
+    <string name="suggestion_row_image" translatable="false">suggestion row image</string>
+    <string name="nothing_found">Not found</string>
+    <string name="departures_empty_state_icon" translatable="false">departures empty state icon</string>
+    <string name="in_a_moment">In a moment</string>
+    <string name="more">More</string>
+    <string name="vm_message_icon" translatable="false">vm message icon</string>
 </resources>




diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 6e8b3469a57e5c647a8154d464cee71d51fd504d..b957c902a4f271f8a32a4ccb889929ea847c6e6b 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -7,12 +7,6 @@         @color/colorPrimaryDark
         <item name="colorAccent">@color/colorAccent</item>
     </style>
 
-    <style name="AppTheme.ActionBar" parent="Theme.AppCompat.DayNight">
-        <item name="colorPrimary">@color/colorPrimary</item>
-        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
-        <item name="colorAccent">@color/colorAccent</item>
-    </style>
-
     <style name="SplashTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
         <item name="colorPrimary">@color/colorPrimary</item>
         <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
@@ -23,8 +17,26 @@