Bimba.git

commit 871c9b2bf560875527b20388a6f2015ed1f4e963

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

edit favourites

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


diff --git a/app/src/main/java/ml/adamsprogs/bimba/ProviderProxy.kt b/app/src/main/java/ml/adamsprogs/bimba/ProviderProxy.kt
index f45c01a976e60d588a49bce3749a06e20b9ee428..a484c43a07383038d0b9f3b60c967bc4b030e26e 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/ProviderProxy.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/ProviderProxy.kt
@@ -11,7 +11,7 @@ import kotlin.collections.HashMap
 
 //todo make singleton
 class ProviderProxy(context: Context? = null) {
-    private val vmStopsClient = VmClient.getVmStopClient()
+    private val vmClient = VmClient.getVmClient()
     private var timetable: Timetable = Timetable.getTimetable(context)
     private var suggestions = emptyList<GtfsSuggestion>()
     private val requests = HashMap<String, Request>()
@@ -35,7 +35,7 @@     }
 
     private suspend fun getStopSuggestions(query: String): List<StopSuggestion> {
         val vmSuggestions = withContext(DefaultDispatcher) {
-            vmStopsClient.getStops(query)
+            vmClient.getStops(query)
         }
 
         return if (vmSuggestions.isEmpty() and !timetable.isEmpty()) {
@@ -67,7 +67,7 @@
     fun getSheds(name: String, callback: (Map<String, Set<String>>) -> Unit) {
         launch(UI) {
             val sheds = withContext(DefaultDispatcher) {
-                val vmSheds = vmStopsClient.getSheds(name)
+                val vmSheds = vmClient.getSheds(name)
 
                 if (vmSheds.isEmpty() and !timetable.isEmpty()) {
                     timetable.getHeadlinesForStop(name)
@@ -158,6 +158,39 @@             emptyMap()
         else
             timetable.getStopDeparturesBySegments(stopSegments)
 
+    }
+
+    fun fillStopSegment(stopSegment: StopSegment, callback: (StopSegment?) -> Unit) {
+        launch(UI) {
+            withContext(DefaultDispatcher) {
+                callback(fillStopSegment(stopSegment))
+            }
+        }
+    }
+
+    suspend fun fillStopSegment(stopSegment: StopSegment): StopSegment? {
+        if (stopSegment.plates != null)
+            return stopSegment
+
+        return if (timetable.isEmpty())
+            vmClient.getDirections(stopSegment.stop)
+        else
+            timetable.getHeadlinesForStopCode(stopSegment.stop)
+    }
+
+    fun getStopName(stopCode: String, callback: (String?) -> Unit) {
+        launch(UI) {
+            withContext(DefaultDispatcher) {
+                callback(getStopName(stopCode))
+            }
+        }
+    }
+
+    suspend fun getStopName(stopCode: String): String? {
+        return if (timetable.isEmpty())
+            vmClient.getName(stopCode)
+        else
+            timetable.getStopName(stopCode)
     }
 
     interface OnDeparturesReadyListener {




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 047a1243509f73149635309d43770b932d9215b5..7bcd314cf54224f830474503d13805caf820e671 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/StopActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/StopActivity.kt
@@ -72,7 +72,7 @@         showFab()
 
         val layoutManager = LinearLayoutManager(this)
         departuresList.addItemDecoration(DividerItemDecoration(departuresList.context, layoutManager.orientation))
-        departuresList.adapter = DeparturesAdapter(this, emptyList(), true)
+        departuresList.adapter = DeparturesAdapter(this, null, true)
         adapter = departuresList.adapter as DeparturesAdapter
         departuresList.layoutManager = layoutManager
 




diff --git a/app/src/main/java/ml/adamsprogs/bimba/collections/FavouriteStorage.kt b/app/src/main/java/ml/adamsprogs/bimba/collections/FavouriteStorage.kt
index 948b545155f4a33101d0b41d762abe2782467422..d937e039aa9cc926d197f7bebe913883845281a5 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/collections/FavouriteStorage.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/collections/FavouriteStorage.kt
@@ -85,9 +85,11 @@         positionIndex.remove(name)
         serialize()
     }
 
-    fun delete(name: String, plate: Plate.ID) {
-        favourites[name]?.delete(plate)
-        serialize()
+    fun delete(name: String, plate: Plate.ID): Boolean {
+        return favourites[name]?.delete(plate).let {
+            serialize()
+            it
+        } ?: false
     }
 
     private fun serialize() {




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 a13d730482d3b2484e636b4c993d24fe1abc9f29..af652ab3dad6fec82a7bb93d85733aac2cc10f56 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/datasources/VmClient.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/datasources/VmClient.kt
@@ -3,6 +3,8 @@
 import com.google.gson.*
 import kotlinx.coroutines.experimental.*
 import ml.adamsprogs.bimba.NetworkStateReceiver
+import ml.adamsprogs.bimba.models.Plate
+import ml.adamsprogs.bimba.models.StopSegment
 import ml.adamsprogs.bimba.models.suggestions.*
 import okhttp3.*
 import java.io.IOException
@@ -14,7 +16,7 @@ class VmClient {
     companion object {
         private var vmClient: VmClient? = null
 
-        fun getVmStopClient(): VmClient {
+        fun getVmClient(): VmClient {
             if (vmClient == null)
                 vmClient = VmClient()
             return vmClient!!
@@ -100,5 +102,32 @@             Gson().fromJson(responseBody, JsonObject::class.java)
         } catch (e: JsonSyntaxException) {
             JsonObject()
         }
+    }
+
+    suspend fun getName(symbol: String): String? {
+        val timesResponse = withContext(DefaultDispatcher) {
+            makeRequest("getTimes", """{"symbol": "$symbol"}""")
+        }
+        if (!timesResponse.has("success"))
+            return null
+
+        return timesResponse["success"].asJsonObject["bollard"].asJsonObject["name"].asString
+    }
+
+    suspend fun getDirections(symbol: String): StopSegment? {
+        val name = getName(symbol)
+        val directionsResponse = makeRequest("getBollardsByStopPoint", """{"name": "$name"}""")
+
+        if (!directionsResponse.has("success"))
+            return null
+
+        return StopSegment(symbol,
+                directionsResponse["success"].asJsonObject["bollards"].asJsonArray.filter {
+                    it.asJsonObject["bollard"].asJsonObject["tag"].asString == symbol
+                }[0].asJsonObject["directions"].asJsonArray.map {
+                    it.asJsonObject.let { direction ->
+                        Plate.ID(direction["lineName"].asString, symbol, direction["direction"].asString)
+                    }
+                }.toSet())
     }
 }




diff --git a/app/src/main/java/ml/adamsprogs/bimba/datasources/VmService.kt b/app/src/main/java/ml/adamsprogs/bimba/datasources/VmService.kt
index 06aa77db42b01d4c0e94ee094007eb064c51e9dd..710aa49f6b3ad7a7f661864ea4231306aa403f20 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/datasources/VmService.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/datasources/VmService.kt
@@ -50,7 +50,9 @@         handler!!.postDelayed(tick6ZinaTim, TICK_6_ZINA_TIM)
     }
 
     override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
-        val stopCode = intent?.getStringExtra("stop")!!
+        if (intent == null)
+            return START_STICKY
+        val stopCode = intent.getStringExtra("stop")!!
         val action = intent.action
         val once = intent.getBooleanExtra("once", false)
         if (action == "request") {
@@ -119,7 +121,7 @@             sendResult(stopCode, null, null)
             return
         }
 
-        val javaRootMapObject = VmClient.getVmStopClient().makeRequest("getTimes", """{"symbol": "$stopCode"}""")
+        val javaRootMapObject = VmClient.getVmClient().makeRequest("getTimes", """{"symbol": "$stopCode"}""")
 
         if (!javaRootMapObject.has("success")) {
             sendResult(stopCode, null, null)




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 a1e71f73cbed2a420f310de9ce9b85d03d31295c..8e2a99c5f289cabf1caacd451ff3bd91cb26d5d1 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/Favourite.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/Favourite.kt
@@ -94,11 +94,13 @@         }
         mapFile.writeText(map)
     }
 
-    fun delete(plateId: Plate.ID) {
+    fun delete(plateId: Plate.ID): Boolean {
         segments.forEach {
-            it.remove(plateId)
+            if (!it.remove(plateId))
+                return false
         }
         removeFromCache(plateId)
+        return true
     }
 
     fun rename(newName: String) {




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/StopSegment.kt b/app/src/main/java/ml/adamsprogs/bimba/models/StopSegment.kt
index 22b8e0b9ef369a53affb2c3df27cdffc902f9372..50f2fb4860b39f77025541cb341a46a18ab93e2c 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/StopSegment.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/StopSegment.kt
@@ -62,8 +62,10 @@             return plateId.stop == stop
         return plates!!.contains(plateId)
     }
 
-    fun remove(plateId: Plate.ID) {
-        (plates as HashSet).remove(plateId)
+    fun remove(plateId: Plate.ID): Boolean {
+        if (plates == null)
+            return false
+        return (plates as HashSet).remove(plateId)
     }
 
     override fun toString(): String {




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 f6b9dcfe6915fa4e06b2980cf7d5a341d0e0a96a..d2aad3409764302956a3650228b9fc792c495669 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt
@@ -145,6 +145,29 @@         AWF73 -> {10 → Franowo, 29 → Franowo, 6 → Miłostowo, 5 → Stomil, 18 → Franowo, 15 → Franowo, 12 → Starołęka, 74 → Os. Orła Białego}
         */
     }
 
+    fun getHeadlinesForStopCode(stop: String): StopSegment {
+        var cursor = db!!.rawQuery("select stop_id from stops where stop_code = ?",
+                arrayOf(stop))
+        cursor.moveToFirst()
+        val stopId = cursor.getInt(0)
+        cursor.close()
+
+
+        cursor = db!!.rawQuery("select route_id, trip_headsign " +
+                "from stop_times natural join trips where stop_id = ? ",
+                arrayOf(stopId.toString()))
+
+        val plates = HashSet<Plate.ID>()
+
+        while (cursor.moveToNext()) {
+            val route = cursor.getString(0)
+            val headsign = cursor.getString(1)
+            plates.add(Plate.ID(route, stop, headsign))
+        }
+        cursor.close()
+        return StopSegment(stop, plates)
+    }
+
     fun getStopName(stopCode: String): String {
         val cursor = db!!.rawQuery("select stop_name from stops where stop_code = ?",
                 arrayOf(stopCode))




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/adapters/FavouriteEditRowAdapter.kt b/app/src/main/java/ml/adamsprogs/bimba/models/adapters/FavouriteEditRowAdapter.kt
index 4b2a2eac4ee1f245a99982b9dc6cbfbd1940ed85..8532b027357f41a83507319536e2fd74de53f0ef 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/adapters/FavouriteEditRowAdapter.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/adapters/FavouriteEditRowAdapter.kt
@@ -6,31 +6,61 @@ import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageView
 import android.widget.TextView
+import kotlinx.coroutines.experimental.DefaultDispatcher
+import kotlinx.coroutines.experimental.android.UI
+import kotlinx.coroutines.experimental.launch
+import kotlinx.coroutines.experimental.withContext
+import ml.adamsprogs.bimba.ProviderProxy
 import ml.adamsprogs.bimba.R
 import ml.adamsprogs.bimba.collections.FavouriteStorage
 import ml.adamsprogs.bimba.models.Favourite
 import ml.adamsprogs.bimba.models.Plate
-import ml.adamsprogs.bimba.models.Timetable
+import ml.adamsprogs.bimba.models.StopSegment
 
 
 //todo when plates null -> get all plates from proxy
 class FavouriteEditRowAdapter(private var favourite: Favourite) :
         RecyclerView.Adapter<FavouriteEditRowAdapter.ViewHolder>() {
+
+    private val segments = HashMap<String, StopSegment>()
+    private val providerProxy = ProviderProxy()
+
+    init {
+        launch(UI) {
+            withContext(DefaultDispatcher) {
+                favourite.segments.forEach {
+                    segments[it.stop] = providerProxy.fillStopSegment(it) ?: it
+                }
+            }
+            this@FavouriteEditRowAdapter.notifyDataSetChanged()
+        }
+    }
+
+
     override fun getItemCount(): Int {
-        return favourite.size
+        return segments.flatMap { it.value.plates ?: emptyList<Plate.ID>() }.size
     }
 
     override fun onBindViewHolder(holder: ViewHolder, position: Int) {
-        val timetable = Timetable.getTimetable()
-        val favourites = FavouriteStorage.getFavouriteStorage()
-        val id = favourite.segments.flatMap { it.plates!! }.sortedBy { "${it.line}${it.stop}"}[position]
-        val plate = Plate(id, null)
-        val favouriteElement = "${timetable.getStopName(plate.id.stop)} ( ${timetable.getStopCode(plate.id.stop)}):\n${plate.id.line} → ${plate.id.headsign}"
-        holder.rowTextView.text = favouriteElement
-        holder.deleteButton.setOnClickListener {
-            favourites.delete(favourite.name, id)
-            favourite = favourites.favourites[favourite.name]!!
-            notifyDataSetChanged()
+        launch(UI) {
+            val plates = segments.flatMap { it.value.plates ?: emptyList<Plate.ID>() }
+            val favourites = FavouriteStorage.getFavouriteStorage()
+            val id = plates.sortedBy { "${it.line}${it.stop}" }[position]
+            val favouriteElement = withContext(DefaultDispatcher) {
+                providerProxy.getStopName(id.stop).let {
+                    "${it ?: ""} (${id.stop}):\n${id.line} → ${id.headsign}"
+                }
+            }
+            holder.rowTextView.text = favouriteElement
+            holder.deleteButton.setOnClickListener {
+                launch(UI) {
+                    favourite.segments.clear()
+                    favourite.segments.addAll(segments.map { it.value })
+                    favourites.delete(favourite.name, id)
+                    favourite = favourites.favourites[favourite.name]!!
+                    notifyDataSetChanged()
+                }
+            }
         }
     }
 
@@ -43,7 +73,7 @@         return ViewHolder(rowView)
     }
 
     inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-        val rowTextView:TextView = itemView.findViewById(R.id.favourite_edit_row)
-        val deleteButton:ImageView = itemView.findViewById(R.id.favourite_edit_delete)
+        val rowTextView: TextView = itemView.findViewById(R.id.favourite_edit_row)
+        val deleteButton: ImageView = itemView.findViewById(R.id.favourite_edit_delete)
     }
 }
\ No newline at end of file