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