ArticleListActivity: add a search menu action
authorDa Risk <da_risk@geekorum.com>
Fri, 07 Dec 2018 16:39:44 -0800
changeset 28 dc628b17d59c
parent 27 ee72e8321d95
child 29 5416af5f801f
ArticleListActivity: add a search menu action
app/src/main/java/com/geekorum/ttrss/articles_list/ActivityViewModel.kt
app/src/main/java/com/geekorum/ttrss/articles_list/ArticleListActivity.kt
app/src/main/res/drawable/ic_search_24dp.xml
app/src/main/res/menu/activity_articles_list.xml
app/src/main/res/values/strings.xml
--- a/app/src/main/java/com/geekorum/ttrss/articles_list/ActivityViewModel.kt	Fri Dec 07 12:49:30 2018 -0800
+++ b/app/src/main/java/com/geekorum/ttrss/articles_list/ActivityViewModel.kt	Fri Dec 07 16:39:44 2018 -0800
@@ -32,6 +32,9 @@
 import com.geekorum.ttrss.data.Feed
 import com.geekorum.ttrss.providers.ArticlesContract
 import com.geekorum.geekdroid.app.lifecycle.EmptyEvent.Companion.makeEmptyEvent as RefreshEvent
+import com.geekorum.geekdroid.app.lifecycle.EmptyEvent.Companion.makeEmptyEvent as SearchClosedEvent
+import com.geekorum.geekdroid.app.lifecycle.EmptyEvent.Companion.makeEmptyEvent as SearchOpenedEvent
+
 
 /**
  * [ViewModel] for the [ArticleListActivity]
@@ -45,6 +48,15 @@
     private val _articleSelectedEvent = MutableLiveData<Event<ArticleSelectedParameters>>()
     val articleSelectedEvent: LiveData<Event<ArticleSelectedParameters>> = _articleSelectedEvent
 
+    private val _searchOpenedEvent = MutableLiveData<EmptyEvent>()
+    val searchOpenedEvent: LiveData<EmptyEvent> = _searchOpenedEvent
+
+    private val _searchClosedEvent = MutableLiveData<EmptyEvent>()
+    val searchClosedEvent: LiveData<EmptyEvent> = _searchClosedEvent
+
+    private val _searchQuery = MutableLiveData<String>()
+    val searchQuery: LiveData<String> = _searchQuery
+
     val isRefreshing: LiveData<Boolean> = Transformations.switchMap(account) {
         SyncInProgressLiveData(it, ArticlesContract.AUTHORITY)
     }
@@ -65,6 +77,18 @@
         _articleSelectedEvent.value = ArticleSelectedEvent(position, article)
     }
 
+    fun onSearchOpened() {
+        _searchOpenedEvent.value = SearchOpenedEvent()
+    }
+
+    fun onSearchClosed() {
+        _searchClosedEvent.value = SearchClosedEvent()
+    }
+
+    fun setSearchQuery(query: String) {
+        _searchQuery.value = query
+    }
+
     class ArticleSelectedParameters internal constructor(val position: Int, val article: Article)
 
     @Suppress("FunctionName")
--- a/app/src/main/java/com/geekorum/ttrss/articles_list/ArticleListActivity.kt	Fri Dec 07 12:49:30 2018 -0800
+++ b/app/src/main/java/com/geekorum/ttrss/articles_list/ArticleListActivity.kt	Fri Dec 07 16:39:44 2018 -0800
@@ -29,6 +29,7 @@
 import android.view.MenuItem
 import android.view.View
 import androidx.appcompat.app.ActionBarDrawerToggle
+import androidx.appcompat.widget.SearchView
 import androidx.core.view.children
 import androidx.databinding.DataBindingUtil
 import androidx.drawerlayout.widget.DrawerLayout
@@ -59,6 +60,7 @@
 class ArticleListActivity : SessionActivity() {
     companion object {
         private const val FRAGMENT_ARTICLES_LIST = "articles_list"
+        private const val FRAGMENT_BACKSTACK_SEARCH = "search"
         private const val FRAGMENT_FEEDS_LIST = "feeds_list"
     }
 
@@ -97,6 +99,14 @@
             onArticleSelected(parameters.position, parameters.article)
         })
 
+        activityViewModel.searchOpenedEvent.observe(this, EventObserver {
+            navigateToSearch()
+        })
+
+        activityViewModel.searchClosedEvent.observe(this, EventObserver {
+            navigateUpToList()
+        })
+
         accountViewModel = ViewModelProviders.of(this, viewModelFactory).get()
         accountViewModel.selectedAccount.observe(this, Observer { account ->
             if (account != null) {
@@ -141,10 +151,13 @@
     private fun setupToolbar() {
         val toolbar = binding.toolbar.toolbar
         toolbar.title = title
+        setupSearch()
+
         if (!twoPane) {
             actionBarDrawerToggle = ActionBarDrawerToggle(this, binding.headlinesDrawer, toolbar,
-                R.string.drawer_open, R.string.drawer_close)
-            binding.headlinesDrawer?.addDrawerListener(actionBarDrawerToggle!!)
+                R.string.drawer_open, R.string.drawer_close).also {
+                binding.headlinesDrawer?.addDrawerListener(it)
+            }
         } else {
             toolbar.setNavigationIcon(R.drawable.ic_menu_24dp)
             toolbar.setNavigationOnClickListener {
@@ -154,6 +167,50 @@
         }
     }
 
+    private fun setupSearch() {
+        val searchItem = with(binding.toolbar.toolbar) {
+            inflateMenu(R.menu.activity_articles_list)
+            menu.findItem(R.id.articles_search)
+        }
+
+        searchItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
+            override fun onMenuItemActionExpand(item: MenuItem): Boolean {
+                activityViewModel.onSearchOpened()
+                return true
+            }
+
+            override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
+                activityViewModel.onSearchClosed()
+                return true
+            }
+        })
+
+        val searchView = searchItem.actionView as SearchView
+        searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
+            override fun onQueryTextSubmit(query: String): Boolean {
+                activityViewModel.setSearchQuery(query)
+                return true
+            }
+
+            override fun onQueryTextChange(query: String): Boolean {
+                activityViewModel.setSearchQuery(query)
+                return true
+            }
+        })
+
+        supportFragmentManager.addOnBackStackChangedListener {
+            val isOnSearchFragment = supportFragmentManager.run {
+                if (backStackEntryCount > 0) {
+                    val backStackEntry = getBackStackEntryAt(backStackEntryCount - 1)
+                    return@run backStackEntry.name == FRAGMENT_BACKSTACK_SEARCH
+                }
+                false
+            }
+            if (!isOnSearchFragment) {
+                searchItem.collapseActionView()
+            }
+        }
+    }
 
     private fun setupPeriodicJobs() {
         backgroundJobManager.setupPeriodicJobs()
@@ -204,4 +261,10 @@
         drawerLayout?.closeDrawers()
     }
 
+    private fun navigateToSearch() {
+    }
+
+    private fun navigateUpToList() {
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/res/drawable/ic_search_24dp.xml	Fri Dec 07 16:39:44 2018 -0800
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
+</vector>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/res/menu/activity_articles_list.xml	Fri Dec 07 16:39:44 2018 -0800
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+    Geekttrss is a RSS feed reader application on the Android Platform.
+
+    Copyright (C) 2017-2018 by Frederic-Charles Barthelery.
+
+    This file is part of Geekttrss.
+
+    Geekttrss is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Geekttrss is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Geekttrss.  If not, see <http://www.gnu.org/licenses/>.
+
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <item
+            android:id="@+id/articles_search"
+            android:icon="@drawable/ic_search_24dp"
+            app:iconTint="?colorControlNormal"
+            android:title="@string/search"
+            app:actionViewClass="androidx.appcompat.widget.SearchView"
+            app:showAsAction="collapseActionView|always" />
+</menu>
--- a/app/src/main/res/values/strings.xml	Fri Dec 07 12:49:30 2018 -0800
+++ b/app/src/main/res/values/strings.xml	Fri Dec 07 16:39:44 2018 -0800
@@ -83,6 +83,7 @@
     <!-- Menus -->
     <string name="share_article">Share article</string>
     <string name="context_selection_toggle_unread">(Un)Read</string>
+    <string name="search">Search</string>
 
     <!-- Api error messages -->
     <string name="error_unknown">Error: Unknown error (see log)</string>