Skip to content

Commit

Permalink
fix: ordering of search history
Browse files Browse the repository at this point in the history
  • Loading branch information
rebelonion committed Jan 3, 2025
1 parent 7b8af6e commit 0d365d5
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 31 deletions.
58 changes: 38 additions & 20 deletions app/src/main/java/ani/dantotsu/media/SearchHistoryAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,52 +10,70 @@ import ani.dantotsu.R
import ani.dantotsu.connections.anilist.AnilistSearch.SearchType
import ani.dantotsu.databinding.ItemSearchHistoryBinding
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.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) :
ListAdapter<String, SearchHistoryAdapter.SearchHistoryViewHolder>(
DIFF_CALLBACK_INSTALLED
) {
private var searchHistoryLiveData: SharedPreferenceStringSetLiveData? = null
private var searchHistory: MutableSet<String>? = null
private var searchHistoryLiveData: SharedPreferenceClassLiveData<List<SearchHistory>>? = null
private var searchHistory: MutableList<SearchHistory>? = null
private var historyType: PrefName = when (type) {
SearchType.ANIME -> PrefName.AnimeSearchHistory
SearchType.MANGA -> PrefName.MangaSearchHistory
SearchType.CHARACTER -> PrefName.CharacterSearchHistory
SearchType.STAFF -> PrefName.StaffSearchHistory
SearchType.STUDIO -> PrefName.StudioSearchHistory
SearchType.USER -> PrefName.UserSearchHistory
SearchType.ANIME -> PrefName.SortedAnimeSH
SearchType.MANGA -> PrefName.SortedMangaSH
SearchType.CHARACTER -> PrefName.SortedCharacterSH
SearchType.STAFF -> PrefName.SortedStaffSH
SearchType.STUDIO -> PrefName.SortedStudioSH
SearchType.USER -> PrefName.SortedUserSH
}

private fun MutableList<SearchHistory>?.sorted(): List<String>? =
this?.sortedByDescending { it.time }?.map { it.search }

init {
searchHistoryLiveData =
PrefManager.getLiveVal(historyType, mutableSetOf<String>()).asLiveStringSet()
searchHistoryLiveData?.observeForever {
searchHistory = it.toMutableSet()
submitList(searchHistory?.toList())
PrefManager.getLiveVal(historyType, mutableListOf<SearchHistory>()).asLiveClass()
searchHistoryLiveData?.observeForever { data ->
searchHistory = data.toMutableList()
submitList(searchHistory?.sorted())
}
}

fun remove(item: String) {
searchHistory?.remove(item)
searchHistory?.let { list ->
list.removeAll { it.search == item }
}
PrefManager.setVal(historyType, searchHistory)
submitList(searchHistory?.toList())
submitList(searchHistory?.sorted())
}

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
searchHistory?.add(item)
submitList(searchHistory?.toList())
searchHistory?.add(SearchHistory(item, System.currentTimeMillis()))
if ((searchHistory?.size ?: 0) > maxSize) {
searchHistory?.removeAt(
searchHistory?.sorted()?.lastIndex ?: 0
)
}
submitList(searchHistory?.sorted())
PrefManager.setVal(historyType, searchHistory)
}

fun clearHistory() {
searchHistory?.clear()
PrefManager.setVal(historyType, searchHistory)
submitList(searchHistory?.toList())
submitList(searchHistory?.sorted())
}

override fun onCreateViewHolder(
Expand Down
14 changes: 10 additions & 4 deletions app/src/main/java/ani/dantotsu/settings/saving/PrefManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -255,9 +255,6 @@ object PrefManager {
return allEntries
}




@Suppress("UNCHECKED_CAST")
fun <T> getLiveVal(prefName: PrefName, default: T): SharedPreferenceLiveData<T> {
val pref = getPrefLocation(prefName.data.prefLocation)
Expand Down Expand Up @@ -298,7 +295,11 @@ object PrefManager {
default as Set<String>
) as SharedPreferenceLiveData<T>

else -> throw IllegalArgumentException("Type not supported")
else -> SharedPreferenceClassLiveData(
pref,
prefName.name,
default
)
}
}

Expand Down Expand Up @@ -326,6 +327,11 @@ object PrefManager {
this as? SharedPreferenceStringSetLiveData
?: 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 =
animeDownloadsPreferences!! //needs to be used externally

Expand Down
15 changes: 8 additions & 7 deletions app/src/main/java/ani/dantotsu/settings/saving/Preferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ package ani.dantotsu.settings.saving
import android.graphics.Color
import ani.dantotsu.connections.comments.AuthResponse
import ani.dantotsu.connections.mal.MAL
import ani.dantotsu.media.SearchHistory
import ani.dantotsu.notifications.comment.CommentStore
import ani.dantotsu.notifications.subscription.SubscriptionStore
import ani.dantotsu.settings.saving.internal.Location
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
SharedUserID(Pref(Location.General, Boolean::class, true)),
OfflineView(Pref(Location.General, Int::class, 0)),
Expand All @@ -34,13 +35,13 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
MangaExtensionRepos(Pref(Location.General, Set::class, setOf<String>())),
NovelExtensionRepos(Pref(Location.General, Set::class, setOf<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>())),
MangaSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
CharacterSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
StaffSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
StudioSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
UserSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
SortedAnimeSH(Pref(Location.General, List::class, listOf<SearchHistory>())),
SortedMangaSH(Pref(Location.General, List::class, listOf<SearchHistory>())),
SortedCharacterSH(Pref(Location.General, List::class, listOf<SearchHistory>())),
SortedStaffSH(Pref(Location.General, List::class, listOf<SearchHistory>())),
SortedStudioSH(Pref(Location.General, List::class, listOf<SearchHistory>())),
SortedUserSH(Pref(Location.General, List::class, listOf<SearchHistory>())),
NovelSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
CommentNotificationInterval(Pref(Location.General, Int::class, 0)),
AnilistNotificationInterval(Pref(Location.General, Int::class, 3)),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package ani.dantotsu.settings.saving

import android.content.SharedPreferences
import android.util.Base64
import androidx.lifecycle.LiveData
import ani.dantotsu.util.Logger
import java.io.ByteArrayInputStream
import java.io.ObjectInputStream

abstract class SharedPreferenceLiveData<T>(
val sharedPrefs: SharedPreferences,
Expand Down Expand Up @@ -78,6 +82,41 @@ class SharedPreferenceStringSetLiveData(
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")
fun SharedPreferences.intLiveData(key: String, defValue: Int): SharedPreferenceLiveData<Int> {
return SharedPreferenceIntLiveData(this, key, defValue)
Expand Down

0 comments on commit 0d365d5

Please sign in to comment.