Bimba.git

commit a52096478ab19aae3f657e40d0b973ae1276e090

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

stop has to be chosen in 2 steps

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


diff --git a/app/build.gradle b/app/build.gradle
index d7b28bff18fb3049628861a5b2e676f896faa9a4..82d256882bd58e17de656e717112626b8d79791d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -37,6 +37,7 @@     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 'com.github.ghost1372:Mzip-Android:0.4.0'
+    implementation 'com.univocity:univocity-parsers:2.5.9'
     implementation 'net.sf.supercsv:super-csv:2.4.0'
     implementation 'io.requery:sqlite-android:3.22.0'
 }




diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 83ec6c0175dbddbcd360a33e7ac7486bbc88fb1c..c767be9fdc8a0fda0f07435c066d24374c4aa82f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -31,7 +31,6 @@                 
             </intent-filter>
         </activity>
         <activity android:name=".activities.NoDbActivity" />
-
         <activity android:name=".activities.EditFavouriteActivity" />
         <activity
             android:name=".activities.HelpActivity"
@@ -42,6 +41,8 @@                      android:name=".datasources.VmClient"
             android:enabled="true"
             android:exported="false" />
+
+        <activity android:name=".activities.StopSpecifyActivity"></activity>
     </application>
 
 </manifest>
\ No newline at end of file




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 ad34903559b2740b8cda9f7e594660d7f5aa52ad..ef52f870857a4c47430fcaefaddf004188946012 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt
@@ -17,7 +17,6 @@ import android.support.v7.widget.*
 import android.view.*
 import android.view.inputmethod.InputMethodManager
 import ml.adamsprogs.bimba.*
-import java.util.*
 import android.os.Bundle
 import android.util.Log
 import kotlinx.android.synthetic.main.activity_dash.*
@@ -30,7 +29,7 @@         FavouritesAdapter.OnMenuItemClickListener, Favourite.OnVmPreparedListener {
     val context: Context = this
     private val receiver = MessageReceiver.getMessageReceiver()
     lateinit var timetable: Timetable
-    var stops: ArrayList<StopSuggestion>? = null
+    var stops: List<StopSuggestion>? = null
     private lateinit var drawerLayout: DrawerLayout
     private lateinit var drawerView: NavigationView
     lateinit var favouritesList: RecyclerView
@@ -111,10 +110,9 @@                 if (view == null) {
                     view = View(context)
                 }
                 imm.hideSoftInputFromWindow(view.windowToken, 0)
-                intent = Intent(context, StopActivity::class.java)
+                intent = Intent(context, StopSpecifyActivity::class.java) //todo mid activity choose shed
                 searchSuggestion as StopSuggestion
-                intent.putExtra(StopActivity.SOURCE_TYPE, StopActivity.SOURCE_TYPE_STOP)
-                intent.putExtra(StopActivity.EXTRA_STOP_ID, searchSuggestion.id)
+                intent.putExtra(StopSpecifyActivity.EXTRA_STOP_IDS, searchSuggestion.ids.joinToString(",") { it.id })
                 startActivity(intent)
             }
 
@@ -125,9 +123,16 @@
         searchView.setOnBindSuggestionCallback { _, _, textView, item, _ ->
             val suggestion = item as StopSuggestion
             val text = suggestion.body.split("\n")
-            val t = "<small><font color=\"#a0a0a0\">" + text[1] + "</font></small>"
+            val colour = when (text[1]) {
+                "A" -> context.getString(R.string.zone_a_colour)
+                "B" -> context.getString(R.string.zone_b_colour)
+                "C" -> context.getString(R.string.zone_c_colour)
+                else -> "#000000"
+            }
+            println("${text[0]} $colour")
+            val t = "<small><font color=\"$colour\">" + text[1] + "</font></small>"
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-                textView.text = Html.fromHtml(text[0] + "<br/>" + t, Html.FROM_HTML_MODE_LEGACY)
+                textView.text = Html.fromHtml("${text[0]} $t", Html.FROM_HTML_MODE_LEGACY)
             } else {
                 @Suppress("DEPRECATION")
                 textView.text = Html.fromHtml(text[0] + "<br/>" + t)
@@ -152,7 +157,7 @@     }
 
     private fun getStops() {
         timetable = Timetable.getTimetable(this)
-        stops = timetable.getStops() as ArrayList<StopSuggestion>
+        stops = timetable.getStops()
     }
 
     private fun prepareListeners() {
@@ -237,7 +242,7 @@             else -> getString(R.string.error_try_later)
         }
         Snackbar.make(findViewById(R.id.drawer_layout), message, Snackbar.LENGTH_LONG).show()
         if (result == TimetableDownloader.RESULT_FINISHED) {
-            stops = timetable.getStops() as ArrayList<StopSuggestion>
+            stops = timetable.getStops()
 
             drawerView.menu.findItem(R.id.drawer_validity_since).title = getString(R.string.valid_since, timetable.getValidSince())
             drawerView.menu.findItem(R.id.drawer_validity_till).title = getString(R.string.valid_since, timetable.getValidTill())




diff --git a/app/src/main/java/ml/adamsprogs/bimba/activities/StopSpecifyActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/activities/StopSpecifyActivity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..01bae71d5ba1be49469bb1f76fc5f96afbc30d7f
--- /dev/null
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/StopSpecifyActivity.kt
@@ -0,0 +1,32 @@
+package ml.adamsprogs.bimba.activities
+
+import android.content.Intent
+import android.support.v7.app.AppCompatActivity
+import android.os.Bundle
+import ml.adamsprogs.bimba.R
+import ml.adamsprogs.bimba.gtfs.AgencyAndId
+import ml.adamsprogs.bimba.models.Timetable
+
+class StopSpecifyActivity : AppCompatActivity() {
+
+    companion object {
+        const val EXTRA_STOP_IDS = "stopIds"
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_stop_specify)
+
+        val ids = intent.getStringExtra(EXTRA_STOP_IDS).split(",").map {AgencyAndId(it)}.toSet()
+        val headlines = Timetable.getTimetable().getHeadlinesForStop(ids)
+
+        //todo select shed
+
+        val shed = AgencyAndId("1")
+
+        intent = Intent(this, StopActivity::class.java)
+        intent.putExtra(StopActivity.SOURCE_TYPE, StopActivity.SOURCE_TYPE_STOP)
+        intent.putExtra(StopActivity.EXTRA_STOP_ID, shed)
+        startActivity(intent)
+    }
+}




diff --git a/app/src/main/java/ml/adamsprogs/bimba/datasources/TimetableConverter.kt b/app/src/main/java/ml/adamsprogs/bimba/datasources/TimetableConverter.kt
deleted file mode 100644
index eba5e37a707473e4c39b73e943c15e5ea10e44b0..0000000000000000000000000000000000000000
--- a/app/src/main/java/ml/adamsprogs/bimba/datasources/TimetableConverter.kt
+++ /dev/null
@@ -1,419 +0,0 @@
-package ml.adamsprogs.bimba.datasources
-
-import android.content.ContentValues
-import android.content.Context
-import io.requery.android.database.sqlite.SQLiteDatabase
-import java.io.File
-import ir.mahdi.mzip.zip.ZipArchive
-import org.supercsv.cellprocessor.ift.CellProcessor
-import org.supercsv.prefs.CsvPreference
-import org.supercsv.io.CsvMapReader
-import org.supercsv.io.ICsvMapReader
-import java.io.FileReader
-import java.util.*
-
-//todo faster csv: http://simpleflatmapper.org/0101-getting-started-csv.html
-//todo faster csv: https://github.com/uniVocity/univocity-parsers
-class TimetableConverter(from: File, context: Context) {
-    init {
-       // println(Calendar.getInstance())
-        val target = File(context.filesDir, "gtfs_files")
-        target.mkdir()
-        ZipArchive.unzip(from.path, target.path, "")
-        /*println("tables…")
-        createTables()
-        println(" done")
-        println("agency…")
-        insertAgency(context)
-        println(" done")
-        println("calendar…")
-        insertCalendar(context)
-        println(" done")
-        println("dates…")
-        insertCalendarDates(context)
-        println(" done")
-        println("feed…")
-        insertFeedInfo(context)
-        println(" done")
-        println("routes…")
-        insertRoutes(context)
-        println(" done")
-        println("shapes…")
-        insertShapes(context)
-        println(" done")
-        println("stops…")
-        insertStops(context)
-        println(" done")
-        println("times…")
-        insertStopTimes(context)
-        println(" done")
-        println("trips…")
-        insertTrips(context)
-        println(" done")
-        target.deleteRecursively()
-        println(Calendar.getInstance())*/
-    } /*
-
-    private fun createTables() {
-        db.execSQL("create table agency(" +
-                "agency_id TEXT PRIMARY KEY," +
-                "agency_name TEXT," +
-                "agency_url TEXT," +
-                "agency_timezone TEXT," +
-                "agency_phone TEXT," +
-                "agency_lang TEXT" +
-                ")")
-        db.execSQL("create table calendar(" +
-                "service_id TEXT PRIMARY KEY," +
-                "monday INT," +
-                "tuesday INT," +
-                "wednesday INT," +
-                "thursday INT," +
-                "friday INT," +
-                "saturday INT," +
-                "sunday INT," +
-                "start_date TEXT," +
-                "end_date TEXT" +
-                ")")
-        db.execSQL("create table calendar_dates(" +
-                "service_id TEXT," +
-                "date TEXT," +
-                "exception_type INT," +
-                "FOREIGN KEY(service_id) REFERENCES calendar(service_id)" +
-                ")")
-        db.execSQL("create table feed_info(" +
-                "feed_publisher_name TEXT PRIMARY KEY," +
-                "feed_publisher_url TEXT," +
-                "feed_lang TEXT," +
-                "feed_start_date TEXT," +
-                "feed_end_date TEXT" +
-                ")")
-        db.execSQL("create table routes(" +
-                "route_id TEXT PRIMARY KEY," +
-                "agency_id TEXT," +
-                "route_short_name TEXT," +
-                "route_long_name TEXT," +
-                "route_desc TEXT," +
-                "route_type INT," +
-                "route_color TEXT," +
-                "route_text_color TEXT," +
-                "FOREIGN KEY(agency_id) REFERENCES agency(agency_id)" +
-                ")")
-        db.execSQL("create table shapes(" +
-                "shape_id TEXT," +
-                "shape_pt_lat DOUBLE," +
-                "shape_pt_lon DOUBLE," +
-                "shape_pt_sequence INT" +
-                ")")
-        db.execSQL("create table stops(" +
-                "stop_id TEXT PRIMARY KEY," +
-                "stop_code TEXT," +
-                "stop_name TEXT," +
-                "stop_lat DOUBLE," +
-                "stop_lon DOUBLE," +
-                "zone_id TEXT" +
-                ")")
-        db.execSQL("create table stop_times(" +
-                "trip_id TEXT," +
-                "arrival_time TEXT," +
-                "departure_time TEXT," +
-                "stop_id TEXT," +
-                "stop_sequence INT," +
-                "stop_headsign TEXT," +
-                "pickup_type INT," +
-                "drop_off_type INT," +
-                "FOREIGN KEY(stop_id) REFERENCES stops(stop_id)" +
-                ")")
-        db.execSQL("create table trips(" +
-                "route_id TEXT," +
-                "service_id TEXT," +
-                "trip_id TEXT PRIMARY KEY," +
-                "trip_headsign TEXT," +
-                "direction_id INT," +
-                "shape_id TEXT," +
-                "wheelchair_accessible INT," +
-                "FOREIGN KEY(route_id) REFERENCES routes(route_id)," +
-                "FOREIGN KEY(service_id) REFERENCES calendar(service_id)," +
-                "FOREIGN KEY(shape_id) REFERENCES shapes(shape_id)" +
-                ")")
-    }
-
-    private fun insertAgency(context: Context) {
-        val file = File(context.filesDir, "gtfs_files/agency.txt")
-        var mapReader: ICsvMapReader? = null
-        try {
-            db.beginTransaction()
-            mapReader = CsvMapReader(FileReader(file), CsvPreference.STANDARD_PREFERENCE)
-            val header = mapReader.getHeader(true)
-
-            var customerMap: Map<String, Any>? = null
-            val processors = Array<CellProcessor?>(header.size, { null })
-            while ({ customerMap = mapReader.read(header, processors); customerMap }() != null) {
-                val values = ContentValues().apply {
-                    put("agency_id", customerMap!!["agency_id"] as String)
-                    put("agency_name", customerMap!!["agency_name"] as String)
-                    put("agency_url", customerMap!!["agency_url"] as String)
-                    put("agency_timezone", customerMap!!["agency_timezone"] as String)
-                    put("agency_phone", customerMap!!["agency_phone"] as String)
-                    put("agency_lang", customerMap!!["agency_lang"] as String)
-                }
-                db.insert("agency", null, values)
-            }
-            db.setTransactionSuccessful()
-            db.endTransaction()
-        } finally {
-            if (mapReader != null) {
-                mapReader.close()
-            }
-        }
-    }
-
-    private fun insertCalendar(context: Context) {
-        val file = File(context.filesDir, "gtfs_files/calendar.txt")
-        var mapReader: ICsvMapReader? = null
-        try {
-            db.beginTransaction()
-            mapReader = CsvMapReader(FileReader(file), CsvPreference.STANDARD_PREFERENCE)
-            val header = mapReader.getHeader(true)
-
-            var customerMap: Map<String, Any>? = null
-            val processors = Array<CellProcessor?>(header.size, { null })
-            while ({ customerMap = mapReader.read(header, processors); customerMap }() != null) {
-                val values = ContentValues().apply {
-                    put("service_id", customerMap!!["service_id"] as String)
-                    put("monday", customerMap!!["monday"] as String)
-                    put("tuesday", customerMap!!["tuesday"] as String)
-                    put("wednesday", customerMap!!["wednesday"] as String)
-                    put("thursday", customerMap!!["thursday"] as String)
-                    put("friday", customerMap!!["friday"] as String)
-                    put("saturday", customerMap!!["saturday"] as String)
-                    put("sunday", customerMap!!["sunday"] as String)
-                    put("start_date", customerMap!!["start_date"] as String)
-                    put("end_date", customerMap!!["end_date"] as String)
-                }
-
-                db.insert("calendar", null, values)
-            }
-            db.setTransactionSuccessful()
-            db.endTransaction()
-        } finally {
-            if (mapReader != null) {
-                mapReader.close()
-            }
-        }
-    }
-
-    private fun insertCalendarDates(context: Context) {
-        val file = File(context.filesDir, "gtfs_files/calendar_dates.txt")
-
-        var mapReader: ICsvMapReader? = null
-        try {
-            db.beginTransaction()
-            mapReader = CsvMapReader(FileReader(file), CsvPreference.STANDARD_PREFERENCE)
-            val header = mapReader.getHeader(true)
-
-            var customerMap: Map<String, Any>? = null
-            val processors = Array<CellProcessor?>(header.size, { null })
-            while ({ customerMap = mapReader.read(header, processors); customerMap }() != null) {
-                val values = ContentValues().apply {
-                    put("service_id", customerMap!!["service_id"] as String)
-                    put("date", customerMap!!["date"] as String)
-                    put("exceptionType", customerMap!!["exceptionType"] as String)
-                }
-                db.insert("calendar_dates", null, values)
-            }
-            db.setTransactionSuccessful()
-            db.endTransaction()
-        } finally {
-            if (mapReader != null) {
-                mapReader.close()
-            }
-        }
-    }
-
-    private fun insertFeedInfo(context: Context) {
-        val file = File(context.filesDir, "gtfs_files/feed_info.txt")
-        var mapReader: ICsvMapReader? = null
-        try {
-            db.beginTransaction()
-            mapReader = CsvMapReader(FileReader(file), CsvPreference.STANDARD_PREFERENCE)
-            val header = mapReader.getHeader(true)
-
-            var customerMap: Map<String, Any>? = null
-            val processors = Array<CellProcessor?>(header.size, { null })
-            while ({ customerMap = mapReader.read(header, processors); customerMap }() != null) {
-                val values = ContentValues().apply {
-                    put("feed_publisher_name", customerMap!!["feed_publisher_name"] as String)
-                    put("feed_publisher_url", customerMap!!["feed_publisher_url"] as String)
-                    put("feed_lang", customerMap!!["feed_lang"] as String)
-                    put("feed_start_date", customerMap!!["feed_start_date"] as String)
-                    put("feed_end_date", customerMap!!["feed_end_date"] as String)
-                }
-                db.insert("feed_info", null, values)
-            }
-            db.setTransactionSuccessful()
-            db.endTransaction()
-        } finally {
-            if (mapReader != null) {
-                mapReader.close()
-            }
-        }
-    }
-
-    private fun insertRoutes(context: Context) {
-        val file = File(context.filesDir, "gtfs_files/routes.txt")
-        var mapReader: ICsvMapReader? = null
-        try {
-            db.beginTransaction()
-            mapReader = CsvMapReader(FileReader(file), CsvPreference.STANDARD_PREFERENCE)
-            val header = mapReader.getHeader(true)
-
-            var customerMap: Map<String, Any>? = null
-            val processors = Array<CellProcessor?>(header.size, { null })
-            while ({ customerMap = mapReader.read(header, processors); customerMap }() != null) {
-                val values = ContentValues().apply {
-                    put("route_id", customerMap!!["route_id"] as String)
-                    put("agency_id", customerMap!!["agency_id"] as String)
-                    put("route_short_name", customerMap!!["route_short_name"] as String)
-                    put("route_long_name", customerMap!!["route_long_name"] as String)
-                    put("route_desc", customerMap!!["route_desc"] as String)
-                    put("route_type", customerMap!!["route_type"] as String)
-                    put("route_color", customerMap!!["route_color"] as String)
-                    put("route_text_color", customerMap!!["route_text_color"] as String)
-                }
-                db.insert("routes", null, values)
-            }
-            db.setTransactionSuccessful()
-            db.endTransaction()
-        } finally {
-            if (mapReader != null) {
-                mapReader.close()
-            }
-        }
-    }
-
-    private fun insertShapes(context: Context) {
-        val file = File(context.filesDir, "gtfs_files/shapes.txt")
-        var mapReader: ICsvMapReader? = null
-        try {
-            db.beginTransaction()
-            mapReader = CsvMapReader(FileReader(file), CsvPreference.STANDARD_PREFERENCE)
-            val header = mapReader.getHeader(true)
-
-            var customerMap: Map<String, Any>? = null
-            val processors = Array<CellProcessor?>(header.size, { null })
-            while ({ customerMap = mapReader.read(header, processors); customerMap }() != null) {
-                val values = ContentValues().apply {
-                    put("shape_id", customerMap!!["shape_id"] as String)
-                    put("shape_pt_lat", customerMap!!["shape_pt_lat"] as String)
-                    put("shape_pt_lon", customerMap!!["shape_pt_lon"] as String)
-                    put("shape_pt_sequence", customerMap!!["shape_pt_sequence"] as String)
-                }
-                db.insert("shapes", null, values)
-                if (mapReader.rowNumber % 1000 == 0)
-                    println(mapReader.rowNumber)
-            }
-            db.setTransactionSuccessful()
-            db.endTransaction()
-        } finally {
-            if (mapReader != null) {
-                mapReader.close()
-            }
-        }
-    }
-
-    private fun insertStops(context: Context) {
-        val file = File(context.filesDir, "gtfs_files/stops.txt")
-        var mapReader: ICsvMapReader? = null
-        try {
-            db.beginTransaction()
-            mapReader = CsvMapReader(FileReader(file), CsvPreference.STANDARD_PREFERENCE)
-            val header = mapReader.getHeader(true)
-
-            var customerMap: Map<String, Any>? = null
-            val processors = Array<CellProcessor?>(header.size, { null })
-            while ({ customerMap = mapReader.read(header, processors); customerMap }() != null) {
-                val values = ContentValues().apply {
-                    put("stop_id", customerMap!!["stop_id"] as String)
-                    put("stop_code", customerMap!!["stop_code"] as String)
-                    put("stop_name", customerMap!!["stop_name"] as String)
-                    put("stop_lat", customerMap!!["stop_lat"] as String)
-                    put("stop_lon", customerMap!!["stop_lon"] as String)
-                    put("zone_id", customerMap!!["zone_id"] as String)
-                }
-                db.insert("stops", null, values)
-            }
-            db.setTransactionSuccessful()
-            db.endTransaction()
-        } finally {
-            if (mapReader != null) {
-                mapReader.close()
-            }
-        }
-    }
-
-    private fun insertStopTimes(context: Context) {
-        val file = File(context.filesDir, "gtfs_files/stop_times.txt")
-        var mapReader: ICsvMapReader? = null
-        try {
-            db.beginTransaction()
-            mapReader = CsvMapReader(FileReader(file), CsvPreference.STANDARD_PREFERENCE)
-            val header = mapReader.getHeader(true)
-
-            var customerMap: Map<String, Any>? = null
-            val processors = Array<CellProcessor?>(header.size, { null })
-            while ({ customerMap = mapReader.read(header, processors); customerMap }() != null) {
-                val values = ContentValues().apply {
-                    put("trip_id", customerMap!!["trip_id"] as String)
-                    put("arrival_time", customerMap!!["arrival_time"] as String)
-                    put("departure_time", customerMap!!["departure_time"] as String)
-                    put("stop_id", customerMap!!["stop_id"] as String)
-                    put("stop_sequence", customerMap!!["stop_sequence"] as String)
-                    put("stop_headsign", customerMap!!["stop_headsign"] as String)
-                    put("pickup_type", customerMap!!["pickup_type"] as String)
-                    put("drop_off_type", customerMap!!["drop_off_type"] as String)
-                }
-                db.insert("stop_times", null, values)
-                if (mapReader.rowNumber % 10000 == 0)
-                    println(mapReader.rowNumber)
-            }
-            db.setTransactionSuccessful()
-            db.endTransaction()
-        } finally {
-            if (mapReader != null) {
-                mapReader.close()
-            }
-        }
-    }
-
-    private fun insertTrips(context: Context) {
-        val file = File(context.filesDir, "gtfs_files/trips.txt")
-        var mapReader: ICsvMapReader? = null
-        try {
-            db.beginTransaction()
-            mapReader = CsvMapReader(FileReader(file), CsvPreference.STANDARD_PREFERENCE)
-            val header = mapReader.getHeader(true)
-
-            var customerMap: Map<String, Any>? = null
-            val processors = Array<CellProcessor?>(header.size, { null })
-            while ({ customerMap = mapReader.read(header, processors); customerMap }() != null) {
-                val values = ContentValues().apply {
-                    put("route_id", customerMap!!["route_id"] as String)
-                    put("service_id", customerMap!!["service_id"] as String)
-                    put("trip_id", customerMap!!["trip_id"] as String)
-                    put("trip_headsign", customerMap!!["trip_headsign"] as String)
-                    put("direction_id", customerMap!!["direction_id"] as String)
-                    put("shape_id", customerMap!!["shape_id"] as String)
-                    put("wheelchair_accessible", customerMap!!["wheelchair_accessible"] as String)
-                }
-                db.insert("trips", null, values)
-            }
-            db.setTransactionSuccessful()
-            db.endTransaction()
-        } finally {
-            if (mapReader != null) {
-                mapReader.close()
-            }
-        }
-    }*/
-}
\ No newline at end of file




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 fc3101e6e7c0b3cc699dbc5f9715b08e3025afb9..06fc8fed24f7c6f5e687e5611c8619882a3b683e 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/datasources/TimetableDownloader.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/datasources/TimetableDownloader.kt
@@ -61,7 +61,6 @@
             notifyDownloading(0)
 
             val gtfs = File(this.filesDir, "timetable.zip")
-            //val db = File(this.filesDir, "timetable.db")
             copyInputStreamToFile(httpCon.inputStream, gtfs)
             val prefsEditor = prefs.edit()
             prefsEditor.putString("timetableLastModified", lastModified)
@@ -70,16 +69,13 @@             sendResult(RESULT_DOWNLOADED)
 
             //notifyConverting() //fixme
 
-            //db.delete()
             val target = File(this.filesDir, "gtfs_files")
             target.deleteRecursively()
-            println("deleted")
             target.mkdir()
             ZipArchive.unzip(gtfs.path, target.path, "")
-            println("unzipped")
+            //todo divide stop_times by stop_id
             gtfs.delete()
             Timetable.getTimetable().refresh()
-            println("refreshed")
 
             cancelNotification()
 




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/StopSuggestion.kt b/app/src/main/java/ml/adamsprogs/bimba/models/StopSuggestion.kt
index 3746e8ea1a2f6acc7c16f517a21f0eace3eb419a..0df965d63f7486ce40a9f02ffe12bb55e57d0884 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/StopSuggestion.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/StopSuggestion.kt
@@ -5,22 +5,27 @@ import android.os.Parcelable
 import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
 import ml.adamsprogs.bimba.gtfs.AgencyAndId
 
-class StopSuggestion(private val directions: Set<String>, val id: AgencyAndId) : SearchSuggestion {
+class StopSuggestion(val name: String, val ids: Set<AgencyAndId>, private val zone: String) : SearchSuggestion, Comparable<StopSuggestion> {
 
     @Suppress("UNCHECKED_CAST")
-    constructor(parcel: Parcel) : this(parcel.readSerializable() as HashSet<String>, parcel.readSerializable() as AgencyAndId)
+    constructor(parcel: Parcel) : this(parcel.readString(), parcel.readString().split(",").map { AgencyAndId(it) }.toSet(), parcel.readString())
 
     override fun describeContents(): Int {
         return Parcelable.CONTENTS_FILE_DESCRIPTOR
     }
 
     override fun writeToParcel(dest: Parcel?, flags: Int) {
-        dest?.writeSerializable(directions as HashSet)
-        dest?.writeSerializable(id)
+        dest?.writeString(name)
+        dest?.writeString(ids.joinToString(",") { it.toString() })
+        dest?.writeString(zone)
     }
 
     override fun getBody(): String {
-        return "${Timetable.getTimetable().getStopName(id)}\n${directions.sortedBy{it}.joinToString()}"
+        return "$name\n$zone"
+    }
+
+    override fun compareTo(other: StopSuggestion): Int {
+        return name.compareTo(other.name)
     }
 
     companion object CREATOR : Parcelable.Creator<StopSuggestion> {




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 8627e2102c2f0ee359421cf9229e9d366deab2c7..fe52772baa69c84eb089af806c8ceff6019823ae 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt
@@ -1,6 +1,8 @@
 package ml.adamsprogs.bimba.models
 
 import android.content.Context
+import com.univocity.parsers.csv.CsvParser
+import com.univocity.parsers.csv.CsvParserSettings
 import ml.adamsprogs.bimba.datasources.CacheManager
 import ml.adamsprogs.bimba.gtfs.AgencyAndId
 import ml.adamsprogs.bimba.gtfs.Route
@@ -17,9 +19,6 @@ import kotlin.collections.HashMap
 import kotlin.collections.HashSet
 import java.util.Calendar as JCalendar
 
-//todo faster csv: http://simpleflatmapper.org/0101-getting-started-csv.html
-//todo faster csv: https://github.com/uniVocity/univocity-parsers
-//todo prolly need to write own simple and fast parser
 class Timetable private constructor() {
     companion object {
         private var timetable: Timetable? = null
@@ -28,7 +27,6 @@         fun getTimetable(context: Context? = null, force: Boolean = false): Timetable {
             return if (timetable == null || force)
                 if (context != null) {
                     timetable = Timetable()
-                    //timetable!!.store = read(context)
                     timetable!!.filesDir = context.filesDir
                     timetable!!.cacheManager = CacheManager.getCacheManager(context)
                     timetable as Timetable
@@ -37,21 +35,13 @@                     throw IllegalArgumentException("new timetable requested and no context given")
             else
                 timetable as Timetable
         }
-
-        /*private fun read(context: Context): SQLiteDatabase {
-            return SQLiteDatabase.openDatabase(File(context.filesDir, "timetable.db").path,
-                    null, SQLiteDatabase.OPEN_READONLY)
-        }*/
     }
 
-    //lateinit var store: SQLiteDatabase
     private lateinit var cacheManager: CacheManager
-    private var _stops: ArrayList<StopSuggestion>? = null
+    private var _stops: List<StopSuggestion>? = null
     private lateinit var filesDir: File
 
     fun refresh() {
-        //this.store = read(context)
-
         cacheManager.recreate(getStopDeparturesByPlates(cacheManager.keys().toSet()))
 
         getStops(true)
@@ -62,95 +52,37 @@         println("STOPS!")
         if (_stops != null && !force)
             return _stops!!
 
-        /*
-        AWF
-        232 → Os. Rusa|8:1435|AWF03
-        AWF
-        232 → Rondo Kaponiera|8:1436|AWF04
-        AWF
-        76 → Pl. Bernardyński, 74 → Os. Sobieskiego, 603 → Pl. Bernardyński|8:1437|AWF02
-        AWF
-        76 → Os. Dębina, 603 → Łęczyca/Dworcowa|8:1634|AWF01
-        AWF
-        29 → Pl. Wiosny Ludów|8:171|AWF42
-        AWF
-        10 → Połabska, 29 → Dębiec, 15 → Budziszyńska, 10 → Dębiec, 15 → Os. Sobieskiego, 12 → Os. Sobieskiego, 6 → Junikowo, 18 → Ogrody, 2 → Ogrody|8:172|AWF41
-        AWF
-        10 → Franowo, 29 → Franowo, 6 → Miłostowo, 5 → Stomil, 18 → Franowo, 15 → Franowo, 12 → Starołęka, 74 → Os. Orła Białego|8:4586|AWF73
-        */
 
-        //trip_id, stop_id from stop_times if pickup_type in {0,3}
-        //route_id as line, trip_id, headsign from trips
-
-        println(JCalendar.getInstance())
-        val stopTripMap = HashMap<String, Set<String>>()
-        val stopTimesFile = File(filesDir, "gtfs_files/stop_times.txt")
-        var mapReader = CsvMapReader(FileReader(stopTimesFile), CsvPreference.STANDARD_PREFERENCE)
-        var header = mapReader.getHeader(true)
-
-        var stopTimesRow: Map<String, Any>? = null
-        var processors = Array<CellProcessor?>(header.size, { null })
-        while ({ stopTimesRow = mapReader.read(header, processors); stopTimesRow }() != null) {
-            if ((stopTimesRow!!["pickup_type"] as String) in arrayOf("0", "3")) {
-                val stopId = stopTimesRow!!["stop_id"] as String
-                val tripId = stopTimesRow!!["trip_id"] as String
-                if (stopId !in stopTripMap)
-                    stopTripMap[stopId] = HashSet()
-                (stopTripMap[stopId]!! as HashSet).add(tripId)
-            }
-        }
-        mapReader.close()
-        println(JCalendar.getInstance())
-
-        val tripIds = stopTripMap.flatMap { it.value }
-
-        val trips = HashMap<String, String>()
-        val tripsFile = File(filesDir, "gtfs_files/trips.txt")
-        mapReader = CsvMapReader(FileReader(tripsFile), CsvPreference.STANDARD_PREFERENCE)
-        header = mapReader.getHeader(true)
-
-        var tripsRow: Map<String, Any>? = null
-        processors = Array(header.size, { null })
-        while ({ tripsRow = mapReader.read(header, processors); tripsRow }() != null) { //fixme takes 16 min, 21 times more than a file 28 times bigger
-            val tripId = tripsRow!!["trip_id"] as String
-            if (tripId in tripIds) {
-                trips[tripId] = tripsRow!!["trip_headsign"] as String //todo save route_id
-            }
-        }
-        mapReader.close()
-        println(JCalendar.getInstance())
+        val settings = CsvParserSettings()
+        settings.format.setLineSeparator("\r\n")
+        val parser = CsvParser(settings)
 
-        val routes = HashMap<String, String>()
-        val routesFile = File(filesDir, "gtfs_files/routes.txt")
-        mapReader = CsvMapReader(FileReader(routesFile), CsvPreference.STANDARD_PREFERENCE)
-        header = mapReader.getHeader(true)
+        val ids = HashMap<String, HashSet<AgencyAndId>>()
+        val zones = HashMap<String, String>()
 
-        var routesRow: Map<String, Any>? = null
-        processors = Array(header.size, { null })
-        while ({ routesRow = mapReader.read(header, processors); routesRow }() != null) {
-            val tripId = routesRow!!["route_id"] as String
-            if (tripId in tripIds) {//fixme
-                routes[tripId] = routesRow!!["route_short_name"] as String
-            }
+        val stopsFile = File(filesDir, "gtfs_files/stops.txt")
+        parser.parseAll(stopsFile).forEach {
+            if (it[2] !in ids)
+                ids[it[2]] = HashSet()
+            ids[it[2]]!!.add(AgencyAndId(it[0]))
+            zones[it[2]] = it[5]
         }
-        mapReader.close()
-        println(JCalendar.getInstance())
 
-        val map = HashMap<AgencyAndId, Set<String>>()
-
-        stopTripMap.forEach {
-            val directions = HashSet<String>()
-            it.value.forEach {
-                val route = routes[it]
-                val headsign = trips[it]
-                directions.add("$route → $headsign")
-            }
-            map[AgencyAndId(it.key)] = directions
-        }
-
-        _stops = map.map { StopSuggestion(it.value, it.key) }.sortedBy { getStopName(it.id) } as ArrayList<StopSuggestion>
+        _stops = ids.map { StopSuggestion(it.key, it.value, zones[it.key]!!) }.sorted()
+        return _stops!!
+    }
 
-        return _stops!!
+    fun getHeadlinesForStop(stops: Set<AgencyAndId>): Map<AgencyAndId, Pair<String, Set<String>>> {
+        TODO("Not Implemented")
+        /*
+        1435 -> (AWF03, {232 → Os. Rusa})
+        1436 -> (AWF04, {232 → Rondo Kaponiera})
+        1437 -> (AWF02, {76 → Pl. Bernardyński, 74 → Os. Sobieskiego, 603 → Pl. Bernardyński})
+        1634 -> (AWF01, {76 → Os. Dębina, 603 → Łęczyca/Dworcowa})
+        171 -> (AWF42, {29 → Pl. Wiosny Ludów})
+        172 -> (AWF41, {10 → Połabska, 29 → Dębiec, 15 → Budziszyńska, 10 → Dębiec, 15 → Os. Sobieskiego, 12 → Os. Sobieskiego, 6 → Junikowo, 18 → Ogrody, 2 → Ogrody})
+        4586 -> (AWF73, {10 → Franowo, 29 → Franowo, 6 → Miłostowo, 5 → Stomil, 18 → Franowo, 15 → Franowo, 12 → Starołęka, 74 → Os. Orła Białego})
+        */
     }
 
     fun getStopName(stopId: AgencyAndId): String {
@@ -251,7 +183,7 @@
     private fun getStopDeparturesByPlate(plate: Plate): Plate {
         val resultPlate = Plate(Plate.ID(plate.id), HashMap())
         val trips = HashMap<String, Map<String, Any>>()
-        val stopTimesFile = File(filesDir, "gtfs_files/stop_times.txt")
+        val stopTimesFile = File(filesDir, "gtfs_files/stop_times.txt") //todo stop_times_$stopId
         var mapReader = CsvMapReader(FileReader(stopTimesFile), CsvPreference.STANDARD_PREFERENCE)
         var header = mapReader.getHeader(true)
 




diff --git a/app/src/main/res/layout/activity_stop_specify.xml b/app/src/main/res/layout/activity_stop_specify.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2993f069ddbe51de49f13ce80801ace483a86074
--- /dev/null
+++ b/app/src/main/res/layout/activity_stop_specify.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.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.constraint.ConstraintLayout>




diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index e6eff41ef25116d87efc95d937ec8414eba592bc..aa1cb3affb568fb5d32ae10dbfa9f9f08ccaa026 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -8,7 +8,7 @@     #be7e3e
 
     <color name="zoneA">#00a650</color>
     <color name="zoneB">#ed1c24</color>
-    <color name="zoneC">#fff200</color>
+    <color name="zoneC">#ffc107</color>
 
     <color name="tram">#00adef</color>
     <color name="bus">#c4212a</color>




diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 08f791cd5383ccb69a47c806a3324f2e1598f9c6..f32ba834964104a849d4039d163c2bffae2c0ea1 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -82,4 +82,8 @@         Friday
         <item>Saturday</item>
         <item>Sunday</item>
     </string-array>
+
+    <string name="zone_a_colour" translatable="false">#00a650</string>
+    <string name="zone_b_colour" translatable="false">#ed1c24</string>
+    <string name="zone_c_colour" translatable="false">#ffc107</string>
 </resources>