Bimba.git

commit 610865e8df2cf3b90fa1ee401ce15fd043ae7460

Author: Adam Evyčędo <git@apiote.xyz>

filter feeds when more than 12 in feed chooser

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


diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/settings/feeds/FeedChooserActivity.kt b/app/src/main/java/xyz/apiote/bimba/czwek/settings/feeds/FeedChooserActivity.kt
index cb78842e2a9225db4ddfa84fdfeb454ec7d434cf..9a0d146235b441b3dba102139db061d33fa0ef89 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/settings/feeds/FeedChooserActivity.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/settings/feeds/FeedChooserActivity.kt
@@ -6,26 +6,20 @@ package xyz.apiote.bimba.czwek.settings.feeds
 
 import android.content.Intent
 import android.os.Bundle
-import android.util.Log
 import android.view.View
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.content.res.AppCompatResources
 import androidx.core.content.edit
+import androidx.core.widget.doAfterTextChanged
 import androidx.lifecycle.ViewModelProvider
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.transition.TransitionManager
 import com.google.android.material.transition.MaterialFade
-import kotlinx.coroutines.MainScope
-import kotlinx.coroutines.launch
 import xyz.apiote.bimba.czwek.R
 import xyz.apiote.bimba.czwek.api.Server
 import xyz.apiote.bimba.czwek.dashboard.MainActivity
 import xyz.apiote.bimba.czwek.databinding.ActivityFeedChooserBinding
 import xyz.apiote.bimba.czwek.repo.FeedInfo
-import xyz.apiote.bimba.czwek.repo.OfflineRepository
-import xyz.apiote.bimba.czwek.repo.OnlineRepository
-import xyz.apiote.bimba.czwek.repo.TrafficResponseException
-import xyz.apiote.bimba.czwek.repo.join
 
 // TODO on internet connection -> getServer
 // TODO swipe to refresh?
@@ -36,8 +30,6 @@ 	private var _binding: ActivityFeedChooserBinding? = null
 	private val binding get() = _binding!!
 
 	private lateinit var adapter: BimbaFeedInfoAdapter
-
-	private val feeds: MutableMap<String, FeedInfo> = mutableMapOf()
 
 	override fun onCreate(savedInstanceState: Bundle?) {
 		super.onCreate(savedInstanceState)
@@ -53,6 +45,14 @@ 		setUpRecycler()
 
 		getServer()
 
+		binding.searchBar.editText?.doAfterTextChanged { editable ->
+			if (editable != null) {
+				updateItems((viewModel.feeds.value ?: emptyMap()).values.filter {
+					it.name.contains(editable, true)
+				}, null)
+			}
+		}
+
 		binding.button.setOnClickListener {
 			moveOn()
 		}
@@ -61,7 +61,7 @@
 	private fun showBottomSheet(feedID: String) {
 		FeedBottomSheet(
 			feedID,
-			feeds,
+			viewModel.feeds.value!!,
 			viewModel.settings.value ?: FeedsSettings(mutableMapOf())
 		) { settings ->
 			if (settings != null) {
@@ -82,7 +82,7 @@ 		binding.resultsRecycler.layoutManager = LinearLayoutManager(this)
 		adapter =
 			BimbaFeedInfoAdapter(
 				layoutInflater,
-				feeds.map { it.value }.sortedBy { it.name },
+				(viewModel.feeds.value ?: emptyMap()).map { it.value }.sortedBy { it.name },
 				viewModel.settings.value!!,
 				this,
 				{
@@ -96,30 +96,12 @@
 	private fun getServer() {
 		binding.progress.visibility = View.VISIBLE
 		binding.resultsRecycler.visibility = View.GONE
-
-		MainScope().launch {
-			val offlineRepository = OfflineRepository()
-			val offlineFeeds =
-				offlineRepository.getFeeds(this@FeedChooserActivity)
-			if (!offlineFeeds.isNullOrEmpty()) {
-				feeds.putAll(offlineFeeds)
-				updateItems(offlineFeeds.map { it.value }, null)
-			}
-			try {
-				val repository = OnlineRepository()
-				val onlineFeeds =
-					repository.getFeeds(this@FeedChooserActivity)
-				feeds.clear()
-				joinFeeds(offlineFeeds, onlineFeeds).let { joinedFeeds ->
-					feeds.putAll(joinedFeeds)
-					updateItems(joinedFeeds.map { it.value }, null)
-				}
-			} catch (e: TrafficResponseException) {
-				if (offlineFeeds.isNullOrEmpty()) {
-					showError(e.error.imageResource, e.error.stringResource)
-				}
-				Log.e("Feeds", "$e")
-			}
+		viewModel.loadFeeds(this)
+		viewModel.feeds.observe(this) { feeds ->
+			updateItems(feeds.map { it.value }, null)
+		}
+		viewModel.error.observe(this) {
+			showError(it.imageResource, it.stringResource)
 		}
 	}
 
@@ -150,24 +132,6 @@ 		}
 
 	}
 
-	private fun joinFeeds(
-		feeds1: Map<String, FeedInfo>?,
-		feeds2: Map<String, FeedInfo>?
-	): Map<String, FeedInfo> {
-		if (feeds1.isNullOrEmpty() && feeds2.isNullOrEmpty()) {
-			return emptyMap()
-		}
-
-		if (feeds1.isNullOrEmpty()) {
-			return feeds2!!
-		}
-		if (feeds2.isNullOrEmpty()) {
-			return feeds1
-		}
-
-		return feeds1.keys.union(feeds2.keys).associateWith { feeds1[it].join(feeds2[it]) }
-	}
-
 	private fun updateItems(
 		feeds: List<FeedInfo>?,
 		feedsSettings: FeedsSettings?,
@@ -175,6 +139,11 @@ 		notify: Boolean = true
 	) {
 		binding.feedsOverlay.visibility = View.GONE
 		binding.resultsRecycler.visibility = View.VISIBLE
+		binding.searchBar.visibility = if ((viewModel.feeds.value?.size ?: 0) > 12) {
+			View.VISIBLE
+		} else {
+			View.GONE
+		}
 		binding.button.visibility = View.VISIBLE
 		adapter.update(feeds, feedsSettings, notify)
 		if (feeds?.isEmpty() == true) {




diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/settings/feeds/FeedInfos.kt b/app/src/main/java/xyz/apiote/bimba/czwek/settings/feeds/FeedInfos.kt
index e65c86b1e92f3ea79cce05fe58b20c7836bdd8ea..54982bae5dffcc38ad1db6eeb112710ba12adec7 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/settings/feeds/FeedInfos.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/settings/feeds/FeedInfos.kt
@@ -141,7 +141,7 @@ }
 
 class FeedBottomSheet(
 	private val feedID: String,
-	private val feeds: MutableMap<String, FeedInfo>,
+	private val feeds: Map<String, FeedInfo>,
 	private val feedsSettings: FeedsSettings,
 	private val onDismiss: (FeedSettings?) -> Unit
 ) :




diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/settings/feeds/FeedsViewModel.kt b/app/src/main/java/xyz/apiote/bimba/czwek/settings/feeds/FeedsViewModel.kt
index 95c79d3f824816a88d119ecb66bdb0bad3d23d0b..e3a30eb70e68b23cec4669b2fbc0f57f1a1bd77b 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/settings/feeds/FeedsViewModel.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/settings/feeds/FeedsViewModel.kt
@@ -5,13 +5,28 @@
 package xyz.apiote.bimba.czwek.settings.feeds
 
 import android.content.Context
+import android.util.Log
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.launch
+import xyz.apiote.bimba.czwek.api.Error
+import xyz.apiote.bimba.czwek.repo.FeedInfo
+import xyz.apiote.bimba.czwek.repo.OfflineRepository
+import xyz.apiote.bimba.czwek.repo.OnlineRepository
+import xyz.apiote.bimba.czwek.repo.TrafficResponseException
+import xyz.apiote.bimba.czwek.repo.join
 
 class FeedsViewModel : ViewModel() {
 	private val _settings = MutableLiveData<FeedsSettings>()
 	val settings: LiveData<FeedsSettings> = _settings
+
+	private val _feeds = MutableLiveData<Map<String, FeedInfo>>()
+	val feeds: LiveData<Map<String, FeedInfo>> = _feeds
+
+	private val _error = MutableLiveData<Error>()
+	val error: LiveData<Error> = _error
 
 	fun loadSettings(context: Context) {
 		_settings.value = FeedsSettings.load(context)
@@ -26,5 +41,47 @@
 	fun setEnabled(feedID: String, enabled: Boolean) {
 		val feedSettings = (_settings.value ?: FeedsSettings(mutableMapOf())).settings[feedID]
 		setSettings(feedID, feedSettings?.copy(enabled = enabled) ?: FeedSettings(enabled, true))
+	}
+
+	fun loadFeeds(context: Context) {
+		MainScope().launch {
+			val offlineRepository = OfflineRepository()
+			val offlineFeeds =
+				offlineRepository.getFeeds(context)
+			if (!offlineFeeds.isNullOrEmpty()) {
+				_feeds.value = offlineFeeds
+			}
+			try {
+				val repository = OnlineRepository()
+				val onlineFeeds =
+					repository.getFeeds(context)
+				joinFeeds(offlineFeeds, onlineFeeds).let { joinedFeeds ->
+					_feeds.value = joinedFeeds
+				}
+			} catch (e: TrafficResponseException) {
+				if (offlineFeeds.isNullOrEmpty()) {
+					_error.value = e.error
+				}
+				Log.e("Feeds", "$e")
+			}
+		}
+	}
+
+	private fun joinFeeds(
+		feeds1: Map<String, FeedInfo>?,
+		feeds2: Map<String, FeedInfo>?
+	): Map<String, FeedInfo> {
+		if (feeds1.isNullOrEmpty() && feeds2.isNullOrEmpty()) {
+			return emptyMap()
+		}
+
+		if (feeds1.isNullOrEmpty()) {
+			return feeds2!!
+		}
+		if (feeds2.isNullOrEmpty()) {
+			return feeds1
+		}
+
+		return feeds1.keys.union(feeds2.keys).associateWith { feeds1[it].join(feeds2[it]) }
 	}
 }




diff --git a/app/src/main/res/layout/activity_feed_chooser.xml b/app/src/main/res/layout/activity_feed_chooser.xml
index 6d6cf4517dea6227853d571d702266e02ae40563..6c1203c951164d69fce52f6ab6ba8030869cf919 100644
--- a/app/src/main/res/layout/activity_feed_chooser.xml
+++ b/app/src/main/res/layout/activity_feed_chooser.xml
@@ -56,6 +56,24 @@ 			app:layout_constraintTop_toBottomOf="@+id/error_image"
 			tool:text="No connection" />
 	</androidx.constraintlayout.widget.ConstraintLayout>
 
+	<com.google.android.material.textfield.TextInputLayout
+		android:id="@+id/search_bar"
+		android:layout_width="match_parent"
+		android:layout_height="wrap_content"
+		android:layout_marginStart="8dp"
+		android:layout_marginTop="8dp"
+		android:layout_marginEnd="8dp"
+		android:hint="@string/filter_localities"
+		android:visibility="gone"
+		app:layout_constraintEnd_toEndOf="parent"
+		app:layout_constraintStart_toStartOf="parent"
+		app:layout_constraintTop_toTopOf="parent">
+
+		<com.google.android.material.textfield.TextInputEditText
+			android:layout_width="match_parent"
+			android:layout_height="wrap_content" />
+	</com.google.android.material.textfield.TextInputLayout>
+
 	<androidx.recyclerview.widget.RecyclerView
 		android:id="@+id/results_recycler"
 		android:layout_width="match_parent"
@@ -69,7 +87,7 @@ 		app:layout_behavior="@string/appbar_scrolling_view_behavior"
 		app:layout_constraintBottom_toTopOf="@+id/button"
 		app:layout_constraintEnd_toEndOf="parent"
 		app:layout_constraintStart_toStartOf="parent"
-		app:layout_constraintTop_toTopOf="parent" />
+		app:layout_constraintTop_toBottomOf="@id/search_bar" />
 
 	<Button
 		android:id="@+id/button"




diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 2243ddb33dcaf64b8b83cfb29f41dda6e5cb5497..25dd3b453d7516e52b024b3291349b3472d5803b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -111,4 +111,5 @@ 	Use online feed
 	<string name="information_may_be_outdated">Information may be outdated</string>
 	<string name="current_timetable_validity">Current timetable valid: %1$s to %2$s</string>
 	<string name="error_406">App version is not compatible with the server</string>
+	<string name="filter_localities">filter localities</string>
 </resources>
\ No newline at end of file