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>