From 199456487c3050d7cc57d9032d4e8ec609a9c274 Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 28 Oct 2019 14:36:15 +0100 Subject: [PATCH 1/4] Search reaction by name/keywords --- CHANGES.md | 2 +- .../vector/riotx/core/di/ScreenComponent.kt | 3 + .../reactions/EmojiChooserFragment.kt | 3 +- .../reactions/EmojiChooserViewModel.kt | 2 +- .../reactions/EmojiReactionPickerActivity.kt | 64 +++++++++++++-- .../reactions/EmojiSearchResultController.kt | 77 +++++++++++++++++++ .../reactions/EmojiSearchResultFragment.kt | 69 +++++++++++++++++ .../reactions/EmojiSearchResultItem.kt | 60 +++++++++++++++ .../reactions/EmojiSearchResultViewModel.kt | 54 +++++++++++++ .../layout/activity_emoji_reaction_picker.xml | 8 ++ .../src/main/res/layout/item_emoji_result.xml | 51 ++++++++++++ .../res/menu/menu_emoji_reaction_picker.xml | 1 + vector/src/main/res/values/strings.xml | 1 + 13 files changed, 385 insertions(+), 10 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultController.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultFragment.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultItem.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultViewModel.kt create mode 100644 vector/src/main/res/layout/item_emoji_result.xml diff --git a/CHANGES.md b/CHANGES.md index b05300f94b..da1c26e425 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,7 +5,7 @@ Features ✨: - Improvements 🙌: - - + - Search reaction by name or keyword in emoji picker Other changes: - diff --git a/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt b/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt index 0efbc0e173..79e496c141 100644 --- a/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt +++ b/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt @@ -59,6 +59,7 @@ import im.vector.riotx.features.rageshake.BugReportActivity import im.vector.riotx.features.rageshake.BugReporter import im.vector.riotx.features.rageshake.RageShake import im.vector.riotx.features.reactions.EmojiReactionPickerActivity +import im.vector.riotx.features.reactions.EmojiSearchResultFragment import im.vector.riotx.features.reactions.widget.ReactionButton import im.vector.riotx.features.roomdirectory.PublicRoomsFragment import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity @@ -197,6 +198,8 @@ interface ScreenComponent { fun inject(incomingShareActivity: IncomingShareActivity) + fun inject(emojiSearchResultFragment: EmojiSearchResultFragment) + @Component.Factory interface Factory { fun create(vectorComponent: VectorComponent, diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserFragment.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserFragment.kt index 8aec8231db..36b1a52b27 100644 --- a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserFragment.kt @@ -36,12 +36,11 @@ class EmojiChooserFragment : VectorBaseFragment() { viewModel = activity?.run { ViewModelProviders.of(this, viewModelFactory).get(EmojiChooserViewModel::class.java) } ?: throw Exception("Invalid Activity") - viewModel.initWithContect(context!!) + viewModel.initWithContext(context!!) (view as? RecyclerView)?.let { it.adapter = viewModel.adapter it.adapter?.notifyDataSetChanged() } -// val ds = EmojiDataSource(this.context!!) } } diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserViewModel.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserViewModel.kt index 16aecd0906..bbde2ac54c 100644 --- a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserViewModel.kt @@ -39,7 +39,7 @@ class EmojiChooserViewModel @Inject constructor() : ViewModel() { } } - fun initWithContect(context: Context) { + fun initWithContext(context: Context) { // TODO load async val emojiDataSource = EmojiDataSource(context) emojiSourceLiveData.value = emojiDataSource diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt index 0a4e05a4c8..7de38602cb 100644 --- a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt @@ -25,15 +25,22 @@ import android.view.MenuInflater import android.view.MenuItem import android.widget.SearchView import androidx.appcompat.widget.Toolbar +import androidx.core.view.isInvisible +import androidx.core.view.isVisible import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders +import com.airbnb.mvrx.viewModel import com.google.android.material.tabs.TabLayout import im.vector.riotx.EmojiCompatFontProvider import im.vector.riotx.R import im.vector.riotx.core.di.ScreenComponent import im.vector.riotx.core.extensions.observeEvent import im.vector.riotx.core.platform.VectorBaseActivity +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers import kotlinx.android.synthetic.main.activity_emoji_reaction_picker.* +import timber.log.Timber +import java.util.concurrent.TimeUnit import javax.inject.Inject /** @@ -41,9 +48,9 @@ import javax.inject.Inject * TODO: Loading indicator while getting emoji data source? * TODO: migrate to MvRx * TODO: Finish Refactor to vector base activity - * TODO: Move font request to app */ -class EmojiReactionPickerActivity : VectorBaseActivity(), EmojiCompatFontProvider.FontProviderListener { +class EmojiReactionPickerActivity : VectorBaseActivity(), + EmojiCompatFontProvider.FontProviderListener { private lateinit var tabLayout: TabLayout @@ -57,6 +64,8 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), EmojiCompatFontProvide @Inject lateinit var emojiCompatFontProvider: EmojiCompatFontProvider + val searchResultViewModel: EmojiSearchResultViewModel by viewModel() + private var tabLayoutSelectionListener = object : TabLayout.OnTabSelectedListener { override fun onTabReselected(tab: TabLayout.Tab) { } @@ -121,10 +130,15 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), EmojiCompatFontProvide finish() } } + + supportFragmentManager.findFragmentById(R.id.fragment)?.view?.isVisible = true + supportFragmentManager.findFragmentById(R.id.searchFragment)?.view?.isInvisible = true + tabLayout.isVisible = true } override fun compatibilityFontUpdate(typeface: Typeface?) { EmojiDrawView.configureTextPaint(this, typeface) + searchResultViewModel.dataSource } override fun onDestroy() { @@ -137,11 +151,11 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), EmojiCompatFontProvide inflater.inflate(getMenuRes(), menu) val searchItem = menu.findItem(R.id.search) - (searchItem.actionView as? SearchView)?.let { + (searchItem.actionView as? SearchView)?.let { searchView -> searchItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener { override fun onMenuItemActionExpand(p0: MenuItem?): Boolean { - it.isIconified = false - it.requestFocusFromTouch() + searchView.isIconified = false + searchView.requestFocusFromTouch() // we want to force the tool bar as visible even if hidden with scroll flags findViewById(R.id.toolbar)?.minimumHeight = getActionBarSize() return true @@ -150,10 +164,35 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), EmojiCompatFontProvide override fun onMenuItemActionCollapse(p0: MenuItem?): Boolean { // when back, clear all search findViewById(R.id.toolbar)?.minimumHeight = 0 - it.setQuery("", true) + searchView.setQuery("", true) return true } }) + + val searchObservable = Observable.create { emitter -> + + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String?): Boolean { + query?.let { emitter.onNext(it) } + return true + } + + override fun onQueryTextChange(newText: String?): Boolean { + Timber.d("onQueryTextChange $newText") + newText?.let { emitter.onNext(it) } + return true + } + + }) + } + + searchObservable + .throttleWithTimeout(600, TimeUnit.MILLISECONDS) + .doOnError { err -> Timber.e(err) } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { query -> + onQueryText(query) + } } return true @@ -171,6 +210,19 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), EmojiCompatFontProvide } } + private fun onQueryText(query: String) { + if (query.isEmpty()) { + supportFragmentManager.findFragmentById(R.id.fragment)?.view?.isVisible = true + supportFragmentManager.findFragmentById(R.id.searchFragment)?.view?.isInvisible = true + tabLayout.isVisible = true + } else { + tabLayout.isVisible = false + supportFragmentManager.findFragmentById(R.id.fragment)?.view?.isInvisible = true + supportFragmentManager.findFragmentById(R.id.searchFragment)?.view?.isVisible = true + searchResultViewModel.updateQuery(query) + } + } + companion object { const val EXTRA_EVENT_ID = "EXTRA_EVENT_ID" diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultController.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultController.kt new file mode 100644 index 0000000000..41bcfe7be5 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultController.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.riotx.features.reactions + +import android.graphics.Typeface +import com.airbnb.epoxy.TypedEpoxyController +import im.vector.riotx.EmojiCompatFontProvider +import im.vector.riotx.R +import im.vector.riotx.core.resources.StringProvider +import im.vector.riotx.core.ui.list.genericFooterItem +import javax.inject.Inject + + +class EmojiSearchResultController @Inject constructor(val stringProvider: StringProvider, + fontProvider: EmojiCompatFontProvider) + : TypedEpoxyController() { + + + var emojiTypeface: Typeface? = fontProvider.typeface + + init { + fontProvider.addListener(object : EmojiCompatFontProvider.FontProviderListener { + override fun compatibilityFontUpdate(typeface: Typeface?) { + emojiTypeface = typeface + } + }) + } + + + var listener: ReactionClickListener? = null + + override fun buildModels(data: EmojiSearchResultViewState?) { + val results = data?.results ?: return + + if (results.isEmpty()) { + if (data.query.isEmpty()) { + //display 'Type something to find' + genericFooterItem { + id("type.query.item") + text(stringProvider.getString(R.string.reaction_search_type_hint)) + } + } else { + //Display no search Results + genericFooterItem { + id("no.results.item") + text(stringProvider.getString(R.string.no_result_placeholder)) + } + } + } else { + //Build the search results + results.forEach { + emojiSearchResultItem { + id(it.name) + emojiItem(it) + emojiTypeFace(emojiTypeface) + currentQuery(data.query) + onClickListener(listener) + } + } + + } + } + +} diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultFragment.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultFragment.kt new file mode 100644 index 0000000000..a4f443de1e --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultFragment.kt @@ -0,0 +1,69 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.riotx.features.reactions + +import android.os.Bundle +import androidx.lifecycle.ViewModelProviders +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.airbnb.epoxy.EpoxyRecyclerView +import com.airbnb.mvrx.activityViewModel +import com.airbnb.mvrx.withState +import im.vector.riotx.R +import im.vector.riotx.core.di.ScreenComponent +import im.vector.riotx.core.platform.VectorBaseFragment +import im.vector.riotx.core.utils.LiveEvent +import javax.inject.Inject + +class EmojiSearchResultFragment : VectorBaseFragment() { + + override fun getLayoutResId(): Int = R.layout.fragment_generic_recycler_epoxy + + val viewModel: EmojiSearchResultViewModel by activityViewModel() + + var sharedViewModel: EmojiChooserViewModel? = null + + @Inject lateinit var epoxyController: EmojiSearchResultController + + override fun injectWith(injector: ScreenComponent) { + injector.inject(this) + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + + sharedViewModel = ViewModelProviders.of(requireActivity(), viewModelFactory).get(EmojiChooserViewModel::class.java) + + epoxyController.listener = object : ReactionClickListener { + override fun onReactionSelected(reaction: String) { + sharedViewModel?.selectedReaction = reaction + sharedViewModel?.navigateEvent?.value = LiveEvent(EmojiChooserViewModel.NAVIGATE_FINISH) + } + } + + val lmgr = LinearLayoutManager(context, RecyclerView.VERTICAL, false) + val epoxyRecyclerView = view as? EpoxyRecyclerView ?: return + epoxyRecyclerView.layoutManager = lmgr + val dividerItemDecoration = DividerItemDecoration(epoxyRecyclerView.context, lmgr.orientation) + epoxyRecyclerView.addItemDecoration(dividerItemDecoration) + epoxyRecyclerView.setController(epoxyController) + } + + override fun invalidate() = withState(viewModel) { state -> + epoxyController.setData(state) + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultItem.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultItem.kt new file mode 100644 index 0000000000..4a9380d452 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultItem.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.riotx.features.reactions + +import android.graphics.Typeface +import android.widget.TextView +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import com.airbnb.epoxy.EpoxyModelWithHolder +import im.vector.riotx.R +import im.vector.riotx.core.epoxy.VectorEpoxyHolder + + +@EpoxyModelClass(layout = R.layout.item_emoji_result) +abstract class EmojiSearchResultItem : EpoxyModelWithHolder() { + + @EpoxyAttribute + lateinit var emojiItem: EmojiDataSource.EmojiItem + + @EpoxyAttribute + var currentQuery: String? = null + + @EpoxyAttribute + var onClickListener: ReactionClickListener? = null + + @EpoxyAttribute + var emojiTypeFace: Typeface? = null + + override fun bind(holder: Holder) { + super.bind(holder) + //TODO use query string to highlight the matched query in name and keywords? + holder.emojiText.text = emojiItem.emojiString() + holder.emojiText.typeface = emojiTypeFace ?: Typeface.DEFAULT + holder.emojiNameText.text = emojiItem.name + holder.emojiKeywordText.text = emojiItem.keywords?.joinToString(", ") + holder.view.setOnClickListener { + onClickListener?.onReactionSelected(emojiItem.emojiString()) + } + } + + class Holder : VectorEpoxyHolder() { + val emojiText by bind(R.id.item_emoji_tv) + val emojiNameText by bind(R.id.item_emoji_name) + val emojiKeywordText by bind(R.id.item_emoji_keyword) + } +} + diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultViewModel.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultViewModel.kt new file mode 100644 index 0000000000..e0c9453e4c --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultViewModel.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.riotx.features.reactions + +import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.ViewModelContext +import im.vector.riotx.core.platform.VectorViewModel + +data class EmojiSearchResultViewState( + val query: String = "", + val results: List = emptyList() +) : MvRxState + +class EmojiSearchResultViewModel(val dataSource: EmojiDataSource, initialState: EmojiSearchResultViewState) + : VectorViewModel(initialState) { + + fun updateQuery(queryString: String) { + setState { + copy( + query = queryString, + results = dataSource.rawData?.emojis?.toList() + ?.map { it.second } + ?.filter { + it.name.contains(queryString, true) + || queryString.split("\\s".toRegex()).fold(true, { prev, q -> + prev && (it.keywords?.any { it.contains(q, true) } ?: false) + }) + } ?: emptyList() + ) + } + } + + companion object : MvRxViewModelFactory { + + override fun create(viewModelContext: ViewModelContext, state: EmojiSearchResultViewState): EmojiSearchResultViewModel? { + //TODO get the data source from activity? share it with other fragment + return EmojiSearchResultViewModel(EmojiDataSource(viewModelContext.activity), state) + } + } +} diff --git a/vector/src/main/res/layout/activity_emoji_reaction_picker.xml b/vector/src/main/res/layout/activity_emoji_reaction_picker.xml index ccaf149732..d56198d341 100644 --- a/vector/src/main/res/layout/activity_emoji_reaction_picker.xml +++ b/vector/src/main/res/layout/activity_emoji_reaction_picker.xml @@ -14,6 +14,14 @@ app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:layout="@layout/emoji_chooser_fragment" /> + + + + + + + + + + + + + + + + diff --git a/vector/src/main/res/menu/menu_emoji_reaction_picker.xml b/vector/src/main/res/menu/menu_emoji_reaction_picker.xml index 98242f57bb..87135d64ea 100644 --- a/vector/src/main/res/menu/menu_emoji_reaction_picker.xml +++ b/vector/src/main/res/menu/menu_emoji_reaction_picker.xml @@ -4,6 +4,7 @@ diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 83ce65783f..eb1eaf1368 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1528,6 +1528,7 @@ Why choose Riot.im? Add Reaction View Reactions Reactions + Type keywords to find a reaction. Event deleted by user Event moderated by room admin From de4c389c76dd4cf928bf04dbb67ee00ba235a5a1 Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 28 Oct 2019 15:12:49 +0100 Subject: [PATCH 2/4] klint cleaning --- .../riotx/features/reactions/EmojiChooserFragment.kt | 1 - .../features/reactions/EmojiReactionPickerActivity.kt | 1 - .../features/reactions/EmojiSearchResultController.kt | 11 +++-------- .../riotx/features/reactions/EmojiSearchResultItem.kt | 4 +--- .../features/reactions/EmojiSearchResultViewModel.kt | 2 +- 5 files changed, 5 insertions(+), 14 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserFragment.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserFragment.kt index 36b1a52b27..77cad5643f 100644 --- a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserFragment.kt @@ -41,6 +41,5 @@ class EmojiChooserFragment : VectorBaseFragment() { it.adapter = viewModel.adapter it.adapter?.notifyDataSetChanged() } - } } diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt index 7de38602cb..a0acd7b5e8 100644 --- a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt @@ -182,7 +182,6 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), newText?.let { emitter.onNext(it) } return true } - }) } diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultController.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultController.kt index 41bcfe7be5..82f8cdf3be 100644 --- a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultController.kt +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultController.kt @@ -23,12 +23,10 @@ import im.vector.riotx.core.resources.StringProvider import im.vector.riotx.core.ui.list.genericFooterItem import javax.inject.Inject - class EmojiSearchResultController @Inject constructor(val stringProvider: StringProvider, fontProvider: EmojiCompatFontProvider) : TypedEpoxyController() { - var emojiTypeface: Typeface? = fontProvider.typeface init { @@ -39,7 +37,6 @@ class EmojiSearchResultController @Inject constructor(val stringProvider: String }) } - var listener: ReactionClickListener? = null override fun buildModels(data: EmojiSearchResultViewState?) { @@ -47,20 +44,20 @@ class EmojiSearchResultController @Inject constructor(val stringProvider: String if (results.isEmpty()) { if (data.query.isEmpty()) { - //display 'Type something to find' + // display 'Type something to find' genericFooterItem { id("type.query.item") text(stringProvider.getString(R.string.reaction_search_type_hint)) } } else { - //Display no search Results + // Display no search Results genericFooterItem { id("no.results.item") text(stringProvider.getString(R.string.no_result_placeholder)) } } } else { - //Build the search results + // Build the search results results.forEach { emojiSearchResultItem { id(it.name) @@ -70,8 +67,6 @@ class EmojiSearchResultController @Inject constructor(val stringProvider: String onClickListener(listener) } } - } } - } diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultItem.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultItem.kt index 4a9380d452..1b117035d9 100644 --- a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultItem.kt @@ -23,7 +23,6 @@ import com.airbnb.epoxy.EpoxyModelWithHolder import im.vector.riotx.R import im.vector.riotx.core.epoxy.VectorEpoxyHolder - @EpoxyModelClass(layout = R.layout.item_emoji_result) abstract class EmojiSearchResultItem : EpoxyModelWithHolder() { @@ -41,7 +40,7 @@ abstract class EmojiSearchResultItem : EpoxyModelWithHolder(R.id.item_emoji_keyword) } } - diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultViewModel.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultViewModel.kt index e0c9453e4c..d11c25a1e3 100644 --- a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultViewModel.kt @@ -47,7 +47,7 @@ class EmojiSearchResultViewModel(val dataSource: EmojiDataSource, initialState: companion object : MvRxViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: EmojiSearchResultViewState): EmojiSearchResultViewModel? { - //TODO get the data source from activity? share it with other fragment + // TODO get the data source from activity? share it with other fragment return EmojiSearchResultViewModel(EmojiDataSource(viewModelContext.activity), state) } } From 73267442bbdf2cee53d7d7f07b507782c7ac96f2 Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 1 Nov 2019 11:28:27 +0100 Subject: [PATCH 3/4] Fix / remove listener --- .../reactions/EmojiSearchResultController.kt | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultController.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultController.kt index 82f8cdf3be..3e8f1c9769 100644 --- a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultController.kt +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultController.kt @@ -16,6 +16,7 @@ package im.vector.riotx.features.reactions import android.graphics.Typeface +import androidx.recyclerview.widget.RecyclerView import com.airbnb.epoxy.TypedEpoxyController import im.vector.riotx.EmojiCompatFontProvider import im.vector.riotx.R @@ -24,17 +25,19 @@ import im.vector.riotx.core.ui.list.genericFooterItem import javax.inject.Inject class EmojiSearchResultController @Inject constructor(val stringProvider: StringProvider, - fontProvider: EmojiCompatFontProvider) + private val fontProvider: EmojiCompatFontProvider) : TypedEpoxyController() { var emojiTypeface: Typeface? = fontProvider.typeface + private val fontProviderListener = object : EmojiCompatFontProvider.FontProviderListener { + override fun compatibilityFontUpdate(typeface: Typeface?) { + emojiTypeface = typeface + } + } + init { - fontProvider.addListener(object : EmojiCompatFontProvider.FontProviderListener { - override fun compatibilityFontUpdate(typeface: Typeface?) { - emojiTypeface = typeface - } - }) + fontProvider.addListener(fontProviderListener) } var listener: ReactionClickListener? = null @@ -69,4 +72,9 @@ class EmojiSearchResultController @Inject constructor(val stringProvider: String } } } + + override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { + super.onDetachedFromRecyclerView(recyclerView) + fontProvider.removeListener(fontProviderListener) + } } From 151ad0103851988d546470d167f7ea819c9c0b9a Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 1 Nov 2019 11:57:15 +0100 Subject: [PATCH 4/4] Use RxBinding on searchView --- .../reactions/EmojiReactionPickerActivity.kt | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt index a0acd7b5e8..a442f5f77e 100644 --- a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt @@ -31,12 +31,12 @@ import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import com.airbnb.mvrx.viewModel import com.google.android.material.tabs.TabLayout +import com.jakewharton.rxbinding3.widget.queryTextChanges import im.vector.riotx.EmojiCompatFontProvider import im.vector.riotx.R import im.vector.riotx.core.di.ScreenComponent import im.vector.riotx.core.extensions.observeEvent import im.vector.riotx.core.platform.VectorBaseActivity -import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import kotlinx.android.synthetic.main.activity_emoji_reaction_picker.* import timber.log.Timber @@ -169,31 +169,15 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), } }) - val searchObservable = Observable.create { emitter -> - - searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { - override fun onQueryTextSubmit(query: String?): Boolean { - query?.let { emitter.onNext(it) } - return true - } - - override fun onQueryTextChange(newText: String?): Boolean { - Timber.d("onQueryTextChange $newText") - newText?.let { emitter.onNext(it) } - return true - } - }) - } - - searchObservable + searchView.queryTextChanges() .throttleWithTimeout(600, TimeUnit.MILLISECONDS) .doOnError { err -> Timber.e(err) } .observeOn(AndroidSchedulers.mainThread()) .subscribe { query -> - onQueryText(query) + onQueryText(query.toString()) } + .disposeOnDestroy() } - return true }