Author: Adam Pioterek <adam.pioterek@protonmail.ch>
dynamic tabs rollback; static timetable works (slow)
%!v(PANIC=String method: strings: negative Repeat count)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c767be9fdc8a0fda0f07435c066d24374c4aa82f..039e73a8a82d72abbf1d496d8b84d9f149739718 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -18,10 +18,6 @@ android:name=".datasources.TimetableDownloader" android:exported="false" /> <activity - android:name=".activities.StopActivity" - android:label="@string/title_activity_stop" - android:theme="@style/AppTheme" /> - <activity android:name=".activities.SplashActivity" android:theme="@style/SplashTheme"> <intent-filter> @@ -42,7 +38,16 @@ android:name=".datasources.VmClient" android:enabled="true" android:exported="false" /> - <activity android:name=".activities.StopSpecifyActivity"></activity> + <activity android:name=".activities.StopSpecifyActivity" /> + <activity + android:name=".activities.StopActivity" + android:label="@string/title_activity_stop" + android:parentActivityName=".activities.StopSpecifyActivity" + android:theme="@style/AppTheme"> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value="ml.adamsprogs.bimba.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 6f9d1b16cef4ef12376f9ab104dfce3163653df4..95d223cddcf4b3c1ab52227267f8e07c214d86b2 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt @@ -122,9 +122,9 @@ searchView.setOnBindSuggestionCallback { _, _, textView, item, _ -> val suggestion = item as StopSuggestion val text = suggestion.body.split("\n") 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) + "A" -> "#${getColour(R.color.zoneA, context).toString(16)}" + "B" -> "#${getColour(R.color.zoneB, context).toString(16)}" + "C" -> "#${getColour(R.color.zoneC, context).toString(16)}" else -> "#000000" } val t = "<small><font color=\"$colour\">" + text[1] + "</font></small>" 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 9731a065e2b2754d6f0d52cdb01b74f74bbd9e90..04da7ada55bdb13f87789f6fec5dccf0a11e118f 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/activities/SplashActivity.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/activities/SplashActivity.kt @@ -19,7 +19,6 @@ startActivity(Intent(this, NoDbActivity::class.java)) else startActivity(Intent(this, DashActivity::class.java)) } catch(e: Exception) { - e.printStackTrace() startActivity(Intent(this, NoDbActivity::class.java)) } finish() 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 98728eaddb91d85a24cd3cdeb43b383b15a23182..f8c95ab545ed1b4cad1842a348875cb4ef3b55e8 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/activities/StopActivity.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/activities/StopActivity.kt @@ -1,28 +1,42 @@ package ml.adamsprogs.bimba.activities -import java.util.* -import kotlin.collections.* +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.database.DataSetObserver +import android.support.design.widget.TabLayout +import android.support.design.widget.Snackbar +import android.support.v7.app.AppCompatActivity -import android.content.* +import android.support.v4.app.Fragment +import android.support.v4.app.FragmentManager import android.os.Bundle -import android.view.* -import android.support.design.widget.* -import android.support.v7.app.AppCompatActivity -import android.support.v7.widget.* -import android.support.v4.app.* -import android.support.v4.view.* +import android.support.v4.app.FragmentStatePagerAdapter import android.support.v4.content.res.ResourcesCompat +import android.support.v4.view.PagerAdapter +import android.support.v7.widget.DividerItemDecoration +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup -import ml.adamsprogs.bimba.models.* -import ml.adamsprogs.bimba.* -import kotlin.concurrent.thread import kotlinx.android.synthetic.main.activity_stop.* +import ml.adamsprogs.bimba.MessageReceiver +import ml.adamsprogs.bimba.R import ml.adamsprogs.bimba.datasources.TimetableDownloader import ml.adamsprogs.bimba.datasources.VmClient import ml.adamsprogs.bimba.gtfs.AgencyAndId -import android.support.v4.view.ViewPager +import ml.adamsprogs.bimba.models.* +import java.util.* +import kotlin.concurrent.thread class StopActivity : AppCompatActivity(), MessageReceiver.OnTimetableDownloadListener, MessageReceiver.OnVmListener, Favourite.OnVmPreparedListener { + + private var sectionsPagerAdapter: SectionsPagerAdapter? = null + companion object { const val EXTRA_STOP_ID = "stopId" const val EXTRA_FAVOURITE = "favourite" @@ -31,21 +45,16 @@ const val SOURCE_TYPE_STOP = "stop" const val SOURCE_TYPE_FAV = "favourite" } - private var stopSegment: StopSegment? = null private var favourite: Favourite? = null private var timetableType = "departure" - private var sectionsPagerAdapter: SectionsPagerAdapter? = null - private var viewPager: ViewPager? = null private lateinit var timetable: Timetable - private lateinit var tabLayout: TabLayout private val context = this private val receiver = MessageReceiver.getMessageReceiver() private val vmDepartures = HashMap<Plate.ID, Set<Departure>>() private var hasDepartures = false private lateinit var sourceType: String - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_stop) @@ -54,7 +63,6 @@ timetable = Timetable.getTimetable() sourceType = intent.getStringExtra(SOURCE_TYPE) - val toolbar = findViewById<Toolbar>(R.id.toolbar) setSupportActionBar(toolbar) when (sourceType) { @@ -70,30 +78,16 @@ favourite!!.addOnVmPreparedListener(this) } } - prepareOnDownloadListener() - - viewPager = container - tabLayout = tabs sectionsPagerAdapter = SectionsPagerAdapter(supportFragmentManager, HashMap<AgencyAndId, ArrayList<Departure>>()) - /*thread { - if (sourceType == SOURCE_TYPE_STOP) { - sectionsPagerAdapter!!.departures = Departure.createDepartures(stopSegment!!.stop) - } else { - sectionsPagerAdapter!!.departures = favourite!!.allDepartures() - } - runOnUiThread { - sectionsPagerAdapter?.notifyDataSetChanged() - } - }*/ - - viewPager!!.adapter = sectionsPagerAdapter - viewPager!!.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabLayout)) - tabLayout.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(viewPager)) + container.adapter = sectionsPagerAdapter - selectTodayPage() + container.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs)) + tabs.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(container)) showFab() + + prepareOnDownloadListener() } private fun getFavouriteDepartures() { @@ -103,31 +97,12 @@ } } private fun refreshAdapter(departures: Map<AgencyAndId, List<Departure>>) { - tabLayout.removeAllTabs() - sectionsPagerAdapter?.notifyDataSetChanged() - departures.keys.sortedBy { - timetable.calendarToMode(AgencyAndId(it.id)).sorted()[0] - }.forEach { - val tab = tabLayout.newTab() - tab.text = timetable.calendarToMode(it) - .joinToString { resources.getStringArray(R.array.daysOfWeekShort)[it] } - tabLayout.addTab(tab) - sectionsPagerAdapter?.notifyDataSetChanged() - } - println("refreshing:") - departures[AgencyAndId("4")]?.forEach { - println("${it.lineText} -> ${it.direction} @ ${it.time}") - } + sectionsPagerAdapter?.departures = departures - try { + runOnUiThread { sectionsPagerAdapter?.notifyDataSetChanged() - } catch (e: Exception) { - runOnUiThread { - sectionsPagerAdapter?.notifyDataSetChanged() - } + selectTodayPage() } - - selectTodayPage() } override fun onVmPrepared() { @@ -188,7 +163,7 @@ else this.vmDepartures.remove(plateId) val departures = HashMap<AgencyAndId, List<Departure>>() if (this.vmDepartures.isNotEmpty()) { - departures[timetable.getServiceForToday()] = this.vmDepartures.flatMap { it.value }.sortedBy { it.timeTill() } + departures[timetable.getServiceForToday()] = this.vmDepartures.flatMap { it.value }.sortedBy { it.timeTill(true) } refreshAdapter(departures) } else { refreshAdapter(Departure.createDepartures(stopSegment!!.stop)) @@ -212,9 +187,9 @@ } //todo refresh } - private fun selectTodayPage() { //fixme does not work + private fun selectTodayPage() { val today = (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 1) % 7 - tabLayout.getTabAt(sectionsPagerAdapter!!.todayTab(today)) + tabs.getTabAt(sectionsPagerAdapter!!.todayTab(today)) } override fun onCreateOptionsMenu(menu: Menu): Boolean { @@ -263,8 +238,43 @@ favourite!!.deregisterOnVm(receiver, context) unregisterReceiver(receiver) } - class PlaceholderFragment : Fragment() { + inner class SectionsPagerAdapter(fm: FragmentManager, var departures: Map<AgencyAndId, List<Departure>>) : FragmentStatePagerAdapter(fm) { + var relativeTime = true + private var modes = ArrayList<AgencyAndId>() + init { + this.registerDataSetObserver(object : DataSetObserver() { + override fun onChanged() { + departures.keys.sortedBy { timetable.calendarToMode(it)[0] }.mapTo(modes) { it } + } + }) + } + + override fun getItem(position: Int): Fragment { + departures.keys.sortedBy { timetable.calendarToMode(it)[0] }.mapTo(modes) { it } + val list = if (departures.isEmpty()) + ArrayList() + else + departures[modes[position]]!! + return PlaceholderFragment.newInstance(list, relativeTime) + } + + override fun getCount() = 5 + + override fun getItemPosition(obj: Any): Int { + return PagerAdapter.POSITION_NONE + } + + fun todayTab(today: Int): Int { + if (modes.isEmpty()) + return 0 + return modes.indexOf(modes.filter { + timetable.calendarToMode(it).contains(today) + }[0]) + } + } + + class PlaceholderFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val rootView = inflater.inflate(R.layout.fragment_stop, container, false) @@ -273,6 +283,8 @@ val departuresList: RecyclerView = rootView.findViewById(R.id.departuresList) departuresList.addItemDecoration(DividerItemDecoration(departuresList.context, layoutManager.orientation)) val departures = arguments?.getStringArrayList("departures")!!.map { Departure.fromString(it) } + + departuresList.adapter = DeparturesAdapter(activity as Context, departures, arguments?.get("relativeTime") as Boolean) departuresList.layoutManager = layoutManager @@ -280,18 +292,10 @@ return rootView } companion object { - private const val ARG_SECTION_NUMBER = "section_number" - - fun newInstance(sectionNumber: Int, departures: List<Departure>, relativeTime: Boolean): - PlaceholderFragment { + fun newInstance(departures: List<Departure>, relativeTime: Boolean): PlaceholderFragment { val fragment = PlaceholderFragment() val args = Bundle() - args.putInt(ARG_SECTION_NUMBER, sectionNumber) - println("newInstance:") - departures.forEach { - println("${it.lineText} -> ${it.direction} @ ${it.time}") - } - if (departures.isEmpty()) { + if (departures.isNotEmpty()) { val d = ArrayList<String>() departures.mapTo(d) { it.toString() } args.putStringArrayList("departures", d) @@ -302,59 +306,5 @@ fragment.arguments = args return fragment } } - } - - inner class SectionsPagerAdapter(fm: FragmentManager, departures: Map<AgencyAndId, List<Departure>>) : FragmentStatePagerAdapter(fm) { //todo swipe - - var departures: Map<AgencyAndId, List<Departure>> = departures - set(value) { - println("setting:") - value[AgencyAndId("4")]?.forEach { - println("${it.lineText} -> ${it.direction} @ ${it.time}") - } - field = value - println("set:") - this.departures[AgencyAndId("4")]?.forEach { - println("${it.lineText} -> ${it.direction} @ ${it.time}") - } - } - - private var modes = ArrayList<AgencyAndId>() - - init { - val tab = tabLayout.newTab() - tab.text = getString(R.string.today) - tabLayout.addTab(tab) - sectionsPagerAdapter?.notifyDataSetChanged() - } - - var relativeTime = true - - fun todayTab(today: Int): Int { - if (modes.isEmpty()) - return 0 - return modes.indexOf(modes.filter { - timetable.calendarToMode(it).contains(today) - }[0]) - } - - override fun getItemPosition(obj: Any): Int { - return PagerAdapter.POSITION_NONE - } - - override fun getItem(position: Int): Fragment { - //fixme doesn't refresh after getting departures/switching. Thinks `departures` is empty. May be connected with swipe - println("adapter:") - departures[AgencyAndId("4")]?.forEach { - println("${it.lineText} -> ${it.direction} @ ${it.time}") - } - val list = if (departures.isEmpty()) - ArrayList() - else - departures[modes[position]]!! - return PlaceholderFragment.newInstance(position + 1, list, relativeTime) - } - - override fun getCount() = if (departures.isEmpty()) 1 else modes.size } } 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 ae47d0daee70f338262a9699d121ec57fe1411a0..2e72955d6dc31befe602c2bd85c587c98c4281e4 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/activities/StopSpecifyActivity.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/activities/StopSpecifyActivity.kt @@ -11,7 +11,6 @@ import ml.adamsprogs.bimba.gtfs.AgencyAndId import ml.adamsprogs.bimba.models.Timetable import android.content.Context import android.widget.TextView -import android.support.v7.widget.DividerItemDecoration import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView import android.view.LayoutInflater 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 3bdb006976f4f1b60cf5e7c8797ca97445ed6526..0bd7aabfb4cc0d0e29efa6888c121c73b577f397 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/datasources/VmClient.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/datasources/VmClient.kt @@ -219,7 +219,7 @@ val departuresForPlate = HashMap<AgencyAndId, HashSet<Departure>>() departuresForPlate[timetable.getServiceForToday()] = departures val vm = vms[plateId.stop] ?: HashSet() - vm.remove(vm.filter { it.id == plateId }[0]) + vm.remove(vm.filter { it.id == plateId }[0]) //fixme outOfBound when vm is still empty (1st time) vm.add(Plate(plateId, departuresForPlate)) vms[plateId.stop] = vm if (departures.isEmpty()) diff --git a/app/src/main/java/ml/adamsprogs/bimba/extensions.kt b/app/src/main/java/ml/adamsprogs/bimba/extensions.kt index 678772f07cfc39e9a715cc272674929ecf5cff0e..7a3713d35fc96dc9be71a438ca4ad26db214e2d4 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/extensions.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/extensions.kt @@ -1,5 +1,7 @@ package ml.adamsprogs.bimba +import android.content.Context +import android.os.Build import java.text.SimpleDateFormat import java.util.* @@ -43,4 +45,12 @@ val date = dateFormat.parse(iso) //date.hours = date.getHours() - 1 //fixme why? 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(R.color.colorAccent, null) + else + context.resources.getColor(R.color.colorAccent)) } \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/Departure.kt b/app/src/main/java/ml/adamsprogs/bimba/models/Departure.kt index ba7a0ef79c1445d5c974c185c741ecec40f2c620..a7a5816b52eda2272d833886f5685011bcb8e908 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/models/Departure.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/models/Departure.kt @@ -2,6 +2,7 @@ package ml.adamsprogs.bimba.models import ml.adamsprogs.bimba.rollTime import ml.adamsprogs.bimba.gtfs.AgencyAndId +import java.io.Serializable import java.util.* import kotlin.collections.ArrayList import kotlin.collections.HashMap @@ -24,51 +25,51 @@ return Departure.fromString(this.toString()) } companion object { - private fun filterDepartures(departures: List<Departure>): ArrayList<Departure> { + private fun filterDepartures(departures: List<Departure>, relative: Boolean = true): Array<Serializable> { val filtered = ArrayList<Departure>() val lines = HashMap<AgencyAndId, Int>() - val sortedDepartures = departures.sortedBy { it.timeTill() } + val sortedDepartures = departures.sortedBy { it.timeTill(relative) } for (departure in sortedDepartures) { var lineExistedTimes = lines[departure.line] - if (departure.timeTill() >= 0 && lineExistedTimes ?: 0 < 3) { + if (departure.timeTill(relative) >= 0 && lineExistedTimes ?: 0 < 3) { lineExistedTimes = (lineExistedTimes ?: 0) + 1 lines[departure.line] = lineExistedTimes filtered.add(departure) } } - return filtered + return arrayOf(filtered, lines.all { it.value >= 3 }) } fun createDepartures(stopId: AgencyAndId): Map<AgencyAndId, List<Departure>> { val timetable = Timetable.getTimetable() val departures = timetable.getStopDepartures(stopId) - return createDepartures(departures) + + return rollDepartures(departures) } - fun createDepartures(departures: Map<AgencyAndId, List<Departure>>): Map<AgencyAndId, List<Departure>> { //todo if departure.timeTill < 0 -> show ‘just departed’ - val moreDepartures = HashMap<AgencyAndId, ArrayList<Departure>>() - for ((k, v) in departures) { - moreDepartures[k] = ArrayList() - for (departure in v) - moreDepartures[k]!!.add(departure.copy()) - } - val rolledDepartures = HashMap<AgencyAndId, ArrayList<Departure>>() - - for ((_, tomorrowDepartures) in moreDepartures) { - tomorrowDepartures.forEach { it.tomorrow = true } + fun rollDepartures(departures: Map<AgencyAndId, List<Departure>>): Map<AgencyAndId, List<Departure>> { //todo if departure.timeTill < 0 -> show ‘just departed’ + val rolledDepartures = HashMap<AgencyAndId, List<Departure>>() + departures.keys.forEach { + val (filtered, isFull) = filterDepartures(departures[it]!!) + if (isFull as Boolean) { + @Suppress("UNCHECKED_CAST") + rolledDepartures[it] = filtered as List<Departure> + } else { + val (filteredTomorrow, _) = filterDepartures(departures[it]!!, false) + val departuresTomorrow = ArrayList<Departure>() + @Suppress("UNCHECKED_CAST") + (filteredTomorrow as List<Departure>).forEach { + val departure = it.copy() + departure.tomorrow = true + departuresTomorrow.add(departure) + } + val (result, _) = + @Suppress("UNCHECKED_CAST") + filterDepartures((filtered as List<Departure>) + departuresTomorrow) + @Suppress("UNCHECKED_CAST") + rolledDepartures[it] = (result as List<Departure>).sortedBy { it.timeTill(true) } + } } - - for ((mode, _) in departures) { - rolledDepartures[mode] = (departures[mode] as ArrayList<Departure> + - moreDepartures[mode] as ArrayList<Departure>) as ArrayList<Departure> - rolledDepartures[mode] = filterDepartures(rolledDepartures[mode]!!) - } - - println("rolled:") - rolledDepartures[AgencyAndId("4")]?.forEach { - println("${it.lineText} -> ${it.direction} @ ${it.time}") - } - return rolledDepartures } @@ -84,9 +85,11 @@ array[7] == "true", array[8] == "true") } } - fun timeTill(): Long { + fun timeTill(relative: Boolean = true): Long { val time = Calendar.getInstance().rollTime(this.time) - val now = Calendar.getInstance() + var now = Calendar.getInstance() + if(!relative) + now = now.rollTime(0) if (this.tomorrow) time.add(Calendar.DAY_OF_MONTH, 1) return (time.timeInMillis - now.timeInMillis) / (1000 * 60) diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/DeparturesAdapter.kt b/app/src/main/java/ml/adamsprogs/bimba/models/DeparturesAdapter.kt index e76c76a5dc1b270d7cbea8e7cb86cc2da2851f05..9396ef56f99e887052ee82ea9a8634eb5799a0ea 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/models/DeparturesAdapter.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/models/DeparturesAdapter.kt @@ -50,7 +50,8 @@ val departureIn = (departureTime.timeInMillis - now.timeInMillis) / (1000 * 60) val timeString: String timeString = if (departureIn > 60 || departureIn < 0 || !relativeTime) - context.getString(R.string.departure_at, "${departureTime.get(Calendar.HOUR_OF_DAY)}:${departureTime.get(Calendar.MINUTE)}") + //todo shall we pad hour too? + context.getString(R.string.departure_at, "${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 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 8a7323530034fe0725df76b3698531708cec54c2..54880ff5ae53f5698aef244c4a2827c8fd8e3e89 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/models/Favourite.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/models/Favourite.kt @@ -62,7 +62,7 @@ private fun filterVmDepartures() { this.vmDepartures.forEach { val newSet = it.value - .filter { it.timeTill() >= 0 }.toSet() + .filter { it.timeTill(true) >= 0 }.toSet() this.vmDepartures[it.key] = newSet } } @@ -135,7 +135,7 @@ if (vmDepartures.isNotEmpty()) { return vmDepartures.flatMap { it.value } .minBy { - it.timeTill() + it.timeTill(true) } } @@ -145,8 +145,8 @@ if (twoDayDepartures.isEmpty()) return null return twoDayDepartures - .filter { it.timeTill() >= 0 } - .minBy { it.timeTill() } + .filter { it.timeTill(true) >= 0 } + .minBy { it.timeTill(true) } } private fun nowDepartures(): ArrayList<Departure> { @@ -175,7 +175,7 @@ val today = timetable.getServiceForToday() departures[today] = vmDepartures.flatMap { it.value } as ArrayList<Departure> } - return Departure.createDepartures(departures) + return Departure.rollDepartures(departures) } fun fullTimetable(): Map<AgencyAndId, List<Departure>> { diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/FavouritesAdapter.kt b/app/src/main/java/ml/adamsprogs/bimba/models/FavouritesAdapter.kt index 8c62986865d0808f53d12ac353416e220ed4ad92..76ae3f570fae1f4eb659ca1d82345507e86dfa0e 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/models/FavouritesAdapter.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/models/FavouritesAdapter.kt @@ -3,7 +3,6 @@ import android.app.Activity import android.content.Context import android.content.Intent -import android.os.Build import android.support.design.widget.AppBarLayout import android.support.v4.content.res.ResourcesCompat import android.support.v7.widget.* @@ -18,6 +17,7 @@ import android.util.TypedValue import com.arlib.floatingsearchview.FloatingSearchView import ml.adamsprogs.bimba.Declinator import ml.adamsprogs.bimba.activities.StopActivity +import ml.adamsprogs.bimba.getColour import kotlin.collections.ArrayList class FavouritesAdapter(val context: Context, var favourites: List<Favourite>, private val onMenuItemClickListener: FavouritesAdapter.OnMenuItemClickListener) : @@ -61,7 +61,7 @@ } val nextDepartureText: String val nextDepartureLineText: String if (nextDeparture != null) { - val interval = nextDeparture.timeTill() + val interval = nextDeparture.timeTill(true) if (interval < 0) return@thread nextDepartureText = context.getString(Declinator.decline(interval), interval.toString()) @@ -125,11 +125,7 @@ private fun select(view: CardView, position: Int) { growSelected(position) - @Suppress("DEPRECATION") - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) - view.setCardBackgroundColor(context.resources.getColor(R.color.colorAccent, null)) - else - view.setCardBackgroundColor(context.resources.getColor(R.color.colorAccent)) + view.setCardBackgroundColor(getColour(R.color.colorAccent, context)) selected[position] = true setSelecting() } 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 d6106c90f3bd0b2ec63a2fca13b377adbfc1986e..86f05318d4ee75a376e7977751aac467ba9e115f 100644 --- a/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt +++ b/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt @@ -39,6 +39,7 @@ //private lateinit var cacheManager: CacheManager private var _stops: List<StopSuggestion>? = null private lateinit var filesDir: File + private val tripsCache = HashMap<String, Array<String>>() fun refresh() { //cacheManager.recreate(getStopDeparturesByPlates(cacheManager.keys().toSet())) @@ -91,6 +92,7 @@ } val stopsFile = File(filesDir, "gtfs_files/trips.txt") parser.parseAll(stopsFile).forEach { + tripsCache[it[2]] = it routes[it[2]] = Pair(it[0], it[3]) } @@ -177,7 +179,6 @@ toGet.add(it) } getStopDeparturesByPlates(toGet, trips).forEach { plates.add(it) } - return Plate.join(plates) } @@ -195,7 +196,8 @@ return plates.map { getStopDeparturesByPlate(it, trips) }.toSet() } - private fun getStopDeparturesByPlate(plate: Plate, trips: Map<String, Trip>): Plate { + private fun getStopDeparturesByPlate(plate: Plate, trips: Map<String, Trip>): Plate { //fixme takes too long + println("getStopDeparturesByPlate: ${JCalendar.getInstance().timeInMillis}") val resultPlate = Plate(Plate.ID(plate.id), HashMap()) val stopTimes = HashMap<String, Map<String, Any>>() val stopTimesFile = File(filesDir, "gtfs_files/stop_times_${plate.id.stop.id}.txt") @@ -231,6 +233,7 @@ resultPlate.departures[serviceId] = HashSet() resultPlate.departures[serviceId]!!.add(dep) } } + println("</>: ${JCalendar.getInstance().timeInMillis}") return resultPlate } @@ -281,31 +284,14 @@ return explanations } private fun getRouteForTrip(trip: Trip): Route { - val routesFile = File(filesDir, "gtfs_files/trips.txt") - var mapReader = CsvMapReader(FileReader(routesFile), CsvPreference.STANDARD_PREFERENCE) - var header = mapReader.getHeader(true) - - var routeId = "" - var row: Map<String, Any>? = null - var processors = Array<CellProcessor?>(header.size, { null }) - while ({ row = mapReader.read(header, processors); row }() != null) { - if ((row!!["trip_id"] as String) == trip.rawId) { - mapReader.close() - routeId = row!!["route_id"] as String - break - } - } - if (routeId == "") { - mapReader.close() - throw IllegalArgumentException("Trip ${trip.rawId} not in store") - } + val routeId = tripsCache[trip.rawId]!![0] val tripsFile = File(filesDir, "gtfs_files/routes.txt") - mapReader = CsvMapReader(FileReader(tripsFile), CsvPreference.STANDARD_PREFERENCE) - header = mapReader.getHeader(true) + val mapReader = CsvMapReader(FileReader(tripsFile), CsvPreference.STANDARD_PREFERENCE) + val header = mapReader.getHeader(true) var routeRow: Map<String, Any>? = null - processors = Array(header.size, { null }) + val processors = Array<CellProcessor?>(header.size, { null }) while ({ routeRow = mapReader.read(header, processors); routeRow }() != null) { if ((routeRow!!["route_id"] as String) == routeId) { mapReader.close() @@ -343,41 +329,24 @@ fun getTripsForStop(stopId: AgencyAndId): HashMap<String, Trip> { //todo actually, we have trips at the start. Why not cache? val tripIds = HashSet<String>() val stopTimesFile = File(filesDir, "gtfs_files/stop_times_${stopId.id}.txt") - var mapReader = CsvMapReader(FileReader(stopTimesFile), CsvPreference.STANDARD_PREFERENCE) - var header = mapReader.getHeader(true) + val mapReader = CsvMapReader(FileReader(stopTimesFile), CsvPreference.STANDARD_PREFERENCE) + val header = mapReader.getHeader(true) var stopTimesRow: Map<String, Any>? = null - var processors = Array<CellProcessor?>(header.size, { null }) + val processors = Array<CellProcessor?>(header.size, { null }) while ({ stopTimesRow = mapReader.read(header, processors); stopTimesRow }() != null) { val tripId = stopTimesRow!!["trip_id"] as String tripIds.add(tripId) } mapReader.close() - - val trips = HashMap<String, Trip>() - 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) { - val tripId = tripsRow!!["trip_id"] as String - trips[tripId] = Trip(AgencyAndId(tripsRow!!["route_id"] as String), - AgencyAndId(tripsRow!!["service_id"] as String), - createTripId(tripId), - tripsRow!!["trip_headsign"] as String, - Integer.parseInt(tripsRow!!["direction_id"] as String), - AgencyAndId(tripsRow!!["shape_id"] as String), - tripsRow!!["wheelchair_accessible"] as String == "1") - } - mapReader.close() - val filteredTrips = HashMap<String, Trip>() tripIds.forEach { - filteredTrips[it] = trips[it]!! + filteredTrips[it] = Trip(AgencyAndId(tripsCache[it]!![0]), + AgencyAndId(tripsCache[it]!![1]), createTripId(tripsCache[it]!![2]), + tripsCache[it]!![3], Integer.parseInt(tripsCache[it]!![4]), + AgencyAndId(tripsCache[it]!![5]), tripsCache[it]!![6] == "1") } return filteredTrips } @@ -483,37 +452,22 @@ throw IllegalArgumentException("Route $number not in store") } fun getPlatesForStop(stop: AgencyAndId): Set<Plate.ID> { - val plates = HashMap<String, Plate.ID>() val tripIds = HashSet<String>() val stopTimesFile = File(filesDir, "gtfs_files/stop_times_${stop.id}.txt") - var mapReader = CsvMapReader(FileReader(stopTimesFile), CsvPreference.STANDARD_PREFERENCE) - var header = mapReader.getHeader(true) + val mapReader = CsvMapReader(FileReader(stopTimesFile), CsvPreference.STANDARD_PREFERENCE) + val header = mapReader.getHeader(true) var stopTimesRow: Map<String, Any>? = null - var processors = Array<CellProcessor?>(header.size, { null }) + val processors = Array<CellProcessor?>(header.size, { null }) while ({ stopTimesRow = mapReader.read(header, processors); stopTimesRow }() != null) { val tripId = stopTimesRow!!["trip_id"] as String tripIds.add(tripId) } mapReader.close() - - 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) { - val tripId = tripsRow!!["trip_id"] as String - plates[tripId] = Plate.ID(AgencyAndId(tripsRow!!["route_id"] as String), stop, tripsRow!!["trip_headsign"] as String) - - } - mapReader.close() - val filteredPlates = HashSet<Plate.ID>() tripIds.forEach { - filteredPlates.add(plates[it]!!) + filteredPlates.add(Plate.ID(AgencyAndId(tripsCache[it]!![0]), stop, tripsCache[it]!![3])) } return filteredPlates diff --git a/app/src/main/res/layout/activity_stop.xml b/app/src/main/res/layout/activity_stop.xml index 6de28177cef9c063f6323d9a2e1dd99572646e63..670a7d4526703b96c1085c7e07604c3f57960a6a 100644 --- a/app/src/main/res/layout/activity_stop.xml +++ b/app/src/main/res/layout/activity_stop.xml @@ -5,7 +5,6 @@ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main_content" android:layout_width="match_parent" android:layout_height="match_parent" - android:animateLayoutChanges="true" android:fitsSystemWindows="true" tools:context="ml.adamsprogs.bimba.activities.StopActivity"> @@ -16,21 +15,53 @@ android:layout_height="wrap_content" android:paddingTop="@dimen/appbar_padding_top" android:theme="@style/AppTheme.AppBarOverlay"> - <!--suppress AndroidDomInspection --> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:layout_weight="1" - android:background="@color/colorPrimary" + android:background="?attr/colorPrimary" app:layout_scrollFlags="scroll|enterAlways" app:popupTheme="@style/AppTheme.PopupOverlay" - app:title="@string/app_name" /> + app:title="@string/app_name"> + + </android.support.v7.widget.Toolbar> <android.support.design.widget.TabLayout android:id="@+id/tabs" android:layout_width="match_parent" - android:layout_height="wrap_content" /> + android:layout_height="wrap_content"> + + <android.support.design.widget.TabItem + android:id="@+id/tabItem" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/mon" /> + + <android.support.design.widget.TabItem + android:id="@+id/tabItem2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/tue__thu" /> + + <android.support.design.widget.TabItem + android:id="@+id/tabItem3" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/fri" /> + + <android.support.design.widget.TabItem + android:id="@+id/tabItem4" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/sat" /> + + <android.support.design.widget.TabItem + android:id="@+id/tabItem5" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/sun" /> + </android.support.design.widget.TabLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cc3dac1c13fa07f11275b532af588802f03da62b..b8faa65871949ede9b611e8111910a00f227299a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -93,8 +93,10 @@- Sat
<item>Sun</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> <string name="today">Today</string> + <string name="mon">Mon</string> + <string name="tue__thu">Tue, …, Thu</string> + <string name="fri">Fri</string> + <string name="sat">Sat</string> + <string name="sun">Sun</string> </resources>