diff --git a/Habitica/build.gradle b/Habitica/build.gradle index 8b68dfbdb..34a60a120 100644 --- a/Habitica/build.gradle +++ b/Habitica/build.gradle @@ -152,7 +152,7 @@ android { buildConfigField "String", "TESTING_LEVEL", "\"production\"" multiDexEnabled true - versionCode 2224 + versionCode 2226 versionName "2.1" } diff --git a/Habitica/res/drawable/ic_search.xml b/Habitica/res/drawable/ic_search.xml new file mode 100644 index 000000000..6ba0de078 --- /dev/null +++ b/Habitica/res/drawable/ic_search.xml @@ -0,0 +1,4 @@ + + + + diff --git a/Habitica/res/layout/toolbar_search.xml b/Habitica/res/layout/toolbar_search.xml new file mode 100644 index 000000000..ffdd8f28f --- /dev/null +++ b/Habitica/res/layout/toolbar_search.xml @@ -0,0 +1,12 @@ + + \ No newline at end of file diff --git a/Habitica/res/menu/menu_main_activity.xml b/Habitica/res/menu/menu_main_activity.xml index 542721cdf..7225931c4 100644 --- a/Habitica/res/menu/menu_main_activity.xml +++ b/Habitica/res/menu/menu_main_activity.xml @@ -8,10 +8,14 @@ android:icon="@drawable/ic_refresh_white" android:title="@string/action_refresh" app:showAsAction="never" - android:actionViewClass="android.widget.ImageButton"/> - - + app:actionViewClass="android.widget.ImageButton"/> + + diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml index d2e0a2053..689c799cf 100644 --- a/Habitica/res/values/strings.xml +++ b/Habitica/res/values/strings.xml @@ -841,4 +841,6 @@ Reject Complete Daily + Search + Search tasks diff --git a/Habitica/res/values/styles.xml b/Habitica/res/values/styles.xml index f81c07ba1..cf59fc0c4 100644 --- a/Habitica/res/values/styles.xml +++ b/Habitica/res/values/styles.xml @@ -46,6 +46,8 @@ @color/brand_50 @color/brand_50 + + @style/SearchViewStyle @@ -646,6 +648,11 @@ @color/red_50 + + #99edecee \ No newline at end of file diff --git a/Habitica/res/xml/searchable.xml b/Habitica/res/xml/searchable.xml new file mode 100644 index 000000000..443afb501 --- /dev/null +++ b/Habitica/res/xml/searchable.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskFilterHelper.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskFilterHelper.kt index 4ac4dee54..288f4e78f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskFilterHelper.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskFilterHelper.kt @@ -1,11 +1,13 @@ package com.habitrpg.android.habitica.helpers import com.habitrpg.android.habitica.models.tasks.Task +import io.realm.Case import io.realm.OrderedRealmCollection import io.realm.RealmQuery import java.util.* class TaskFilterHelper { + var searchQuery: String? = null private var tagsId: MutableList = ArrayList() private val activeFilters = HashMap() @@ -96,6 +98,9 @@ class TaskFilterHelper { if (tagsId.size > 0) { query = query.`in`("tags.id", tagsId.toTypedArray()) } + if (searchQuery?.isNotEmpty() == true) { + query = query.beginsWith("text", searchQuery ?: "", Case.INSENSITIVE) + } if (activeFilter != null && activeFilter != Task.FILTER_ALL) { when (activeFilter) { Task.FILTER_ACTIVE -> query = if (Task.TYPE_DAILY == taskType) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt index d815e0729..01c21fd66 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt @@ -236,7 +236,10 @@ open class Task : RealmObject, Parcelable { } return if (Task::class.java.isAssignableFrom(other.javaClass)) { val otherTask = other as? Task - this.id == otherTask?.id + if (!this.isValid || otherTask?.isValid != true) { + return false + } + this.id == otherTask.id } else { super.equals(other) } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt index 094bb663c..b4914acdc 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt @@ -5,6 +5,7 @@ import android.content.Intent import android.graphics.PorterDuff import android.os.Bundle import android.view.* +import androidx.appcompat.widget.SearchView import androidx.fragment.app.FragmentPagerAdapter import com.habitrpg.android.habitica.HabiticaBaseApplication import com.habitrpg.android.habitica.R @@ -25,7 +26,8 @@ import java.util.* import javax.inject.Inject import kotlin.collections.ArrayList -class TasksFragment : BaseMainFragment() { + +class TasksFragment : BaseMainFragment(), SearchView.OnQueryTextListener { var viewPager: androidx.viewpager.widget.ViewPager? = null @Inject @@ -108,13 +110,40 @@ class TasksFragment : BaseMainFragment() { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.menu_main_activity, menu) - filterMenuItem = menu.findItem(R.id.action_search) + filterMenuItem = menu.findItem(R.id.action_filter) updateFilterIcon() + + val item = menu.findItem(R.id.action_search) + val sv = item.actionView as? SearchView + sv?.setOnQueryTextListener(this) + sv?.setIconifiedByDefault(false) + item.setOnActionExpandListener(object : MenuItem.OnActionExpandListener { + override fun onMenuItemActionCollapse(item: MenuItem): Boolean { + filterMenuItem?.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS) + return true + } + + override fun onMenuItemActionExpand(item: MenuItem): Boolean { + // Do something when expanded + filterMenuItem?.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER) + return true + } + }) + } + + override fun onQueryTextSubmit(query: String?): Boolean { + return true + } + + override fun onQueryTextChange(newText: String?): Boolean { + taskFilterHelper.searchQuery = newText + viewFragmentsDictionary?.values?.forEach { values -> values.recyclerAdapter?.filter() } + return true } override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { - R.id.action_search -> { + R.id.action_filter -> { showFilterDialog() true } @@ -145,14 +174,11 @@ class TasksFragment : BaseMainFragment() { if (viewFragmentsDictionary == null) { return } - val activePos = viewPager?.currentItem ?: 0 - viewFragmentsDictionary?.get(activePos - 1)?.recyclerAdapter?.filter() - viewFragmentsDictionary?.get(activePos + 1)?.recyclerAdapter?.filter() taskFilterHelper.tags = activeTags if (activeTaskFilter != null) { activeFragment?.setActiveFilter(activeTaskFilter) } - viewFragmentsDictionary?.values?.forEach { it.recyclerAdapter?.filter() } + viewFragmentsDictionary?.values?.forEach { values -> values.recyclerAdapter?.filter() } updateFilterIcon() } }) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/SafeDefaultItemAnimator.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/SafeDefaultItemAnimator.kt index 2477698e1..34715012f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/SafeDefaultItemAnimator.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/SafeDefaultItemAnimator.kt @@ -8,7 +8,7 @@ import androidx.core.view.ViewCompat import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.SimpleItemAnimator import com.habitrpg.shared.habitica.LogLevel -import com.habitrpg.shared.habitica.Logger +import com.habitrpg.shared.habitica.HLogger import java.util.* /** @@ -226,8 +226,8 @@ class SafeDefaultItemAnimator : SimpleItemAnimator() { if (deltaY != 0) { view.translationY = (-deltaY).toFloat() } - Logger.log(LogLevel.INFO, "Moving1", "$toX, $fromX, $deltaX") - Logger.log(LogLevel.INFO, "Moving1", "$toX, $fromX, $deltaX") + HLogger.log(LogLevel.INFO, "Moving1", "$toX, $fromX, $deltaX") + HLogger.log(LogLevel.INFO, "Moving1", "$toX, $fromX, $deltaX") pendingMoves.add(MoveInfo(holder, newFromX, newFromY, toX, toY)) return true } @@ -242,8 +242,8 @@ class SafeDefaultItemAnimator : SimpleItemAnimator() { if (deltaY != 0) { view.animate().translationY(0f) } - Logger.log(LogLevel.INFO, "Moving", "$toX, $fromX, $deltaX") - Logger.log(LogLevel.INFO, "Moving", "$toX, $fromX, $deltaX") + HLogger.log(LogLevel.INFO, "Moving", "$toX, $fromX, $deltaX") + HLogger.log(LogLevel.INFO, "Moving", "$toX, $fromX, $deltaX") // vpas are canceled (and can't end them. why?) // need listener functionality in VPACompat for this. Ick. val animation = view.animate() @@ -295,8 +295,8 @@ class SafeDefaultItemAnimator : SimpleItemAnimator() { newHolder.itemView.translationY = (-deltaY).toFloat() newHolder.itemView.alpha = 0f } - Logger.log(LogLevel.INFO, "Changing", "$toX, $fromX, $deltaX") - Logger.log(LogLevel.INFO, "Changing", "$toX, $fromX, $deltaX") + HLogger.log(LogLevel.INFO, "Changing", "$toX, $fromX, $deltaX") + HLogger.log(LogLevel.INFO, "Changing", "$toX, $fromX, $deltaX") newHolder?.let { pendingChanges.add(ChangeInfo(oldHolder, it, fromX, fromY, toX, toY)) } return true } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/InboxViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/InboxViewModel.kt index 327cccb93..ba16da99d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/InboxViewModel.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/InboxViewModel.kt @@ -63,9 +63,11 @@ private class MessagesDataSource(val socialRepository: SocialRepository, val rec override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback) { lastFetchWasEnd = false GlobalScope.launch(Dispatchers.Main.immediate) { - socialRepository.getInboxMessages(recipientID).firstElement() + socialRepository.getInboxMessages(recipientID) + .map { socialRepository.getUnmanagedCopy(it) } + .firstElement() .flatMapPublisher { - if (it.size == 0) { + if (it.isEmpty()) { socialRepository.retrieveInboxMessages(recipientID, 0) .doOnNext { messages -> if (messages.size != 10) lastFetchWasEnd = true diff --git a/shared/src/commonMain/kotlin/com/habitrpg/shared/habitica/Logger.kt b/shared/src/commonMain/kotlin/com/habitrpg/shared/habitica/HLogger.kt similarity index 98% rename from shared/src/commonMain/kotlin/com/habitrpg/shared/habitica/Logger.kt rename to shared/src/commonMain/kotlin/com/habitrpg/shared/habitica/HLogger.kt index 912824958..1026cc353 100644 --- a/shared/src/commonMain/kotlin/com/habitrpg/shared/habitica/Logger.kt +++ b/shared/src/commonMain/kotlin/com/habitrpg/shared/habitica/HLogger.kt @@ -13,7 +13,7 @@ enum class LogLevel { ERROR, INFO, DEBUG } -class Logger { +class HLogger { companion object { private val platformLogger = PlatformLogger()