fix: ordering of search history
This commit is contained in:
parent
7b8af6ea8a
commit
0d365d55c5
4 changed files with 95 additions and 31 deletions
|
@ -10,52 +10,70 @@ import ani.dantotsu.R
|
||||||
import ani.dantotsu.connections.anilist.AnilistSearch.SearchType
|
import ani.dantotsu.connections.anilist.AnilistSearch.SearchType
|
||||||
import ani.dantotsu.databinding.ItemSearchHistoryBinding
|
import ani.dantotsu.databinding.ItemSearchHistoryBinding
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefManager.asLiveStringSet
|
import ani.dantotsu.settings.saving.PrefManager.asLiveClass
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.settings.saving.SharedPreferenceStringSetLiveData
|
import ani.dantotsu.settings.saving.SharedPreferenceClassLiveData
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
data class SearchHistory(val search: String, val time: Long) : Serializable {
|
||||||
|
companion object {
|
||||||
|
private const val serialVersionUID = 1L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class SearchHistoryAdapter(type: SearchType, private val searchClicked: (String) -> Unit) :
|
class SearchHistoryAdapter(type: SearchType, private val searchClicked: (String) -> Unit) :
|
||||||
ListAdapter<String, SearchHistoryAdapter.SearchHistoryViewHolder>(
|
ListAdapter<String, SearchHistoryAdapter.SearchHistoryViewHolder>(
|
||||||
DIFF_CALLBACK_INSTALLED
|
DIFF_CALLBACK_INSTALLED
|
||||||
) {
|
) {
|
||||||
private var searchHistoryLiveData: SharedPreferenceStringSetLiveData? = null
|
private var searchHistoryLiveData: SharedPreferenceClassLiveData<List<SearchHistory>>? = null
|
||||||
private var searchHistory: MutableSet<String>? = null
|
private var searchHistory: MutableList<SearchHistory>? = null
|
||||||
private var historyType: PrefName = when (type) {
|
private var historyType: PrefName = when (type) {
|
||||||
SearchType.ANIME -> PrefName.AnimeSearchHistory
|
SearchType.ANIME -> PrefName.SortedAnimeSH
|
||||||
SearchType.MANGA -> PrefName.MangaSearchHistory
|
SearchType.MANGA -> PrefName.SortedMangaSH
|
||||||
SearchType.CHARACTER -> PrefName.CharacterSearchHistory
|
SearchType.CHARACTER -> PrefName.SortedCharacterSH
|
||||||
SearchType.STAFF -> PrefName.StaffSearchHistory
|
SearchType.STAFF -> PrefName.SortedStaffSH
|
||||||
SearchType.STUDIO -> PrefName.StudioSearchHistory
|
SearchType.STUDIO -> PrefName.SortedStudioSH
|
||||||
SearchType.USER -> PrefName.UserSearchHistory
|
SearchType.USER -> PrefName.SortedUserSH
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun MutableList<SearchHistory>?.sorted(): List<String>? =
|
||||||
|
this?.sortedByDescending { it.time }?.map { it.search }
|
||||||
|
|
||||||
init {
|
init {
|
||||||
searchHistoryLiveData =
|
searchHistoryLiveData =
|
||||||
PrefManager.getLiveVal(historyType, mutableSetOf<String>()).asLiveStringSet()
|
PrefManager.getLiveVal(historyType, mutableListOf<SearchHistory>()).asLiveClass()
|
||||||
searchHistoryLiveData?.observeForever {
|
searchHistoryLiveData?.observeForever { data ->
|
||||||
searchHistory = it.toMutableSet()
|
searchHistory = data.toMutableList()
|
||||||
submitList(searchHistory?.toList())
|
submitList(searchHistory?.sorted())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun remove(item: String) {
|
fun remove(item: String) {
|
||||||
searchHistory?.remove(item)
|
searchHistory?.let { list ->
|
||||||
|
list.removeAll { it.search == item }
|
||||||
|
}
|
||||||
PrefManager.setVal(historyType, searchHistory)
|
PrefManager.setVal(historyType, searchHistory)
|
||||||
submitList(searchHistory?.toList())
|
submitList(searchHistory?.sorted())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(item: String) {
|
fun add(item: String) {
|
||||||
if (searchHistory?.contains(item) == true || item.isBlank()) return
|
val maxSize = 25
|
||||||
|
if (searchHistory?.any { it.search == item } == true || item.isBlank()) return
|
||||||
if (PrefManager.getVal(PrefName.Incognito)) return
|
if (PrefManager.getVal(PrefName.Incognito)) return
|
||||||
searchHistory?.add(item)
|
searchHistory?.add(SearchHistory(item, System.currentTimeMillis()))
|
||||||
submitList(searchHistory?.toList())
|
if ((searchHistory?.size ?: 0) > maxSize) {
|
||||||
|
searchHistory?.removeAt(
|
||||||
|
searchHistory?.sorted()?.lastIndex ?: 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
submitList(searchHistory?.sorted())
|
||||||
PrefManager.setVal(historyType, searchHistory)
|
PrefManager.setVal(historyType, searchHistory)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearHistory() {
|
fun clearHistory() {
|
||||||
searchHistory?.clear()
|
searchHistory?.clear()
|
||||||
PrefManager.setVal(historyType, searchHistory)
|
PrefManager.setVal(historyType, searchHistory)
|
||||||
submitList(searchHistory?.toList())
|
submitList(searchHistory?.sorted())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(
|
override fun onCreateViewHolder(
|
||||||
|
|
|
@ -255,9 +255,6 @@ object PrefManager {
|
||||||
return allEntries
|
return allEntries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun <T> getLiveVal(prefName: PrefName, default: T): SharedPreferenceLiveData<T> {
|
fun <T> getLiveVal(prefName: PrefName, default: T): SharedPreferenceLiveData<T> {
|
||||||
val pref = getPrefLocation(prefName.data.prefLocation)
|
val pref = getPrefLocation(prefName.data.prefLocation)
|
||||||
|
@ -298,7 +295,11 @@ object PrefManager {
|
||||||
default as Set<String>
|
default as Set<String>
|
||||||
) as SharedPreferenceLiveData<T>
|
) as SharedPreferenceLiveData<T>
|
||||||
|
|
||||||
else -> throw IllegalArgumentException("Type not supported")
|
else -> SharedPreferenceClassLiveData(
|
||||||
|
pref,
|
||||||
|
prefName.name,
|
||||||
|
default
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,6 +327,11 @@ object PrefManager {
|
||||||
this as? SharedPreferenceStringSetLiveData
|
this as? SharedPreferenceStringSetLiveData
|
||||||
?: throw ClassCastException("Cannot cast to SharedPreferenceLiveData<Set<String>>")
|
?: throw ClassCastException("Cannot cast to SharedPreferenceLiveData<Set<String>>")
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
inline fun <reified T> SharedPreferenceLiveData<*>.asLiveClass(): SharedPreferenceClassLiveData<T> =
|
||||||
|
this as? SharedPreferenceClassLiveData<T>
|
||||||
|
?: throw ClassCastException("Cannot cast to SharedPreferenceLiveData<T>")
|
||||||
|
|
||||||
fun getAnimeDownloadPreferences(): SharedPreferences =
|
fun getAnimeDownloadPreferences(): SharedPreferences =
|
||||||
animeDownloadsPreferences!! //needs to be used externally
|
animeDownloadsPreferences!! //needs to be used externally
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,13 @@ package ani.dantotsu.settings.saving
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import ani.dantotsu.connections.comments.AuthResponse
|
import ani.dantotsu.connections.comments.AuthResponse
|
||||||
import ani.dantotsu.connections.mal.MAL
|
import ani.dantotsu.connections.mal.MAL
|
||||||
|
import ani.dantotsu.media.SearchHistory
|
||||||
import ani.dantotsu.notifications.comment.CommentStore
|
import ani.dantotsu.notifications.comment.CommentStore
|
||||||
import ani.dantotsu.notifications.subscription.SubscriptionStore
|
import ani.dantotsu.notifications.subscription.SubscriptionStore
|
||||||
import ani.dantotsu.settings.saving.internal.Location
|
import ani.dantotsu.settings.saving.internal.Location
|
||||||
import ani.dantotsu.settings.saving.internal.Pref
|
import ani.dantotsu.settings.saving.internal.Pref
|
||||||
|
|
||||||
enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
|
enum class PrefName(val data: Pref) {
|
||||||
//General
|
//General
|
||||||
SharedUserID(Pref(Location.General, Boolean::class, true)),
|
SharedUserID(Pref(Location.General, Boolean::class, true)),
|
||||||
OfflineView(Pref(Location.General, Int::class, 0)),
|
OfflineView(Pref(Location.General, Int::class, 0)),
|
||||||
|
@ -34,13 +35,13 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
|
||||||
MangaExtensionRepos(Pref(Location.General, Set::class, setOf<String>())),
|
MangaExtensionRepos(Pref(Location.General, Set::class, setOf<String>())),
|
||||||
NovelExtensionRepos(Pref(Location.General, Set::class, setOf<String>())),
|
NovelExtensionRepos(Pref(Location.General, Set::class, setOf<String>())),
|
||||||
AnimeSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
AnimeSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
||||||
AnimeSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
|
|
||||||
MangaSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
MangaSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
||||||
MangaSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
|
SortedAnimeSH(Pref(Location.General, List::class, listOf<SearchHistory>())),
|
||||||
CharacterSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
|
SortedMangaSH(Pref(Location.General, List::class, listOf<SearchHistory>())),
|
||||||
StaffSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
|
SortedCharacterSH(Pref(Location.General, List::class, listOf<SearchHistory>())),
|
||||||
StudioSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
|
SortedStaffSH(Pref(Location.General, List::class, listOf<SearchHistory>())),
|
||||||
UserSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
|
SortedStudioSH(Pref(Location.General, List::class, listOf<SearchHistory>())),
|
||||||
|
SortedUserSH(Pref(Location.General, List::class, listOf<SearchHistory>())),
|
||||||
NovelSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
NovelSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
||||||
CommentNotificationInterval(Pref(Location.General, Int::class, 0)),
|
CommentNotificationInterval(Pref(Location.General, Int::class, 0)),
|
||||||
AnilistNotificationInterval(Pref(Location.General, Int::class, 3)),
|
AnilistNotificationInterval(Pref(Location.General, Int::class, 3)),
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
package ani.dantotsu.settings.saving
|
package ani.dantotsu.settings.saving
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import android.util.Base64
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ObjectInputStream
|
||||||
|
|
||||||
abstract class SharedPreferenceLiveData<T>(
|
abstract class SharedPreferenceLiveData<T>(
|
||||||
val sharedPrefs: SharedPreferences,
|
val sharedPrefs: SharedPreferences,
|
||||||
|
@ -78,6 +82,41 @@ class SharedPreferenceStringSetLiveData(
|
||||||
sharedPrefs.getStringSet(key, defValue)?.toSet() ?: defValue
|
sharedPrefs.getStringSet(key, defValue)?.toSet() ?: defValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
class SharedPreferenceClassLiveData<T>(
|
||||||
|
sharedPrefs: SharedPreferences,
|
||||||
|
key: String,
|
||||||
|
defValue: T
|
||||||
|
) : SharedPreferenceLiveData<T>(sharedPrefs, key, defValue) {
|
||||||
|
override fun getValueFromPreferences(key: String, defValue: T): T {
|
||||||
|
return try {
|
||||||
|
val serialized = sharedPrefs.getString(key, null)
|
||||||
|
if (serialized != null) {
|
||||||
|
val data = Base64.decode(serialized, Base64.DEFAULT)
|
||||||
|
val bis = ByteArrayInputStream(data)
|
||||||
|
val ois = ObjectInputStream(bis)
|
||||||
|
val obj = ois.readObject() as T
|
||||||
|
obj
|
||||||
|
} else {
|
||||||
|
Logger.log("Serialized data is null (key: $key)")
|
||||||
|
defValue
|
||||||
|
}
|
||||||
|
} catch (e: java.io.InvalidClassException) {
|
||||||
|
Logger.log(e)
|
||||||
|
try {
|
||||||
|
sharedPrefs.edit().remove(key).apply()
|
||||||
|
defValue
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Logger.log(e)
|
||||||
|
defValue
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Logger.log(e)
|
||||||
|
defValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun SharedPreferences.intLiveData(key: String, defValue: Int): SharedPreferenceLiveData<Int> {
|
fun SharedPreferences.intLiveData(key: String, defValue: Int): SharedPreferenceLiveData<Int> {
|
||||||
return SharedPreferenceIntLiveData(this, key, defValue)
|
return SharedPreferenceIntLiveData(this, key, defValue)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue