added primitive search history & added appCategory = video

fixed #874 and #878
This commit is contained in:
LagradOst 2022-03-29 20:34:00 +02:00
parent 71da2233d9
commit 279605e6ae
6 changed files with 246 additions and 16 deletions

View file

@ -27,7 +27,8 @@
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:fullBackupContent="@xml/backup_descriptor"
tools:targetApi="m">
android:appCategory="video"
tools:targetApi="o">
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.lagradost.cloudstream3.utils.CastOptionsProvider"/>

View file

@ -23,6 +23,7 @@ import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
import com.lagradost.cloudstream3.APIHolder.getApiFromName
import com.lagradost.cloudstream3.APIHolder.getApiSettings
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.observe
@ -164,7 +165,8 @@ class SearchFragment : Fragment() {
val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)
val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt)
val pairList = HomeFragment.getPairList(anime, cartoons, tvs, docs, movies,asian)
val pairList =
HomeFragment.getPairList(anime, cartoons, tvs, docs, movies, asian)
cancelBtt?.setOnClickListener {
dialog.dismissSafe()
@ -277,10 +279,21 @@ class SearchFragment : Fragment() {
search_select_asian,
)
val settingsManager = context?.let { PreferenceManager.getDefaultSharedPreferences(it) }
val isAdvancedSearch = settingsManager?.getBoolean("advanced_search", true) ?: true
selectedSearchTypes = context?.getKey<List<String>>(SEARCH_PREF_TAGS)
?.mapNotNull { listName -> TvType.values().firstOrNull { it.name == listName } }
?.toMutableList()
?: mutableListOf(TvType.Movie, TvType.TvSeries)
fun updateSelectedList(list: MutableList<TvType>) {
selectedSearchTypes = list
for ((button, validTypes) in pairList) {
button?.isSelected = selectedSearchTypes.any { validTypes.contains(it) }
}
}
context?.filterProviderByPreferredMedia()?.let { validAPIs ->
for ((button, validTypes) in pairList) {
val isValid =
@ -339,10 +352,25 @@ class SearchFragment : Fragment() {
override fun onQueryTextChange(newText: String): Boolean {
//searchViewModel.quickSearch(newText)
val showHistory = newText.isBlank()
searchViewModel.clearSearch()
searchViewModel.updateHistory()
search_history_recycler?.isVisible = showHistory
search_master_recycler?.isVisible = !showHistory && isAdvancedSearch
search_autofit_results?.isVisible = !showHistory && !isAdvancedSearch
return true
}
})
observe(searchViewModel.currentHistory) { list ->
(search_history_recycler.adapter as? SearchHistoryAdaptor?)?.updateList(list)
}
searchViewModel.updateHistory()
observe(searchViewModel.searchResponse) {
when (it) {
is Resource.Success -> {
@ -406,15 +434,31 @@ class SearchFragment : Fragment() {
activity?.loadHomepageList(item)
})
val historyAdapter = SearchHistoryAdaptor(mutableListOf()) { click ->
val searchItem = click.item
when (click.clickAction) {
SEARCH_HISTORY_OPEN -> {
searchViewModel.clearSearch()
if (searchItem.type.isNotEmpty())
updateSelectedList(searchItem.type.toMutableList())
main_search?.setQuery(searchItem.searchText, true)
}
SEARCH_HISTORY_REMOVE -> {
removeKey(SEARCH_HISTORY_KEY, searchItem.key)
searchViewModel.updateHistory()
}
else -> {
// wth are you doing???
}
}
}
search_history_recycler?.adapter = historyAdapter
search_history_recycler?.layoutManager = GridLayoutManager(context, 1)
search_master_recycler?.adapter = masterAdapter
search_master_recycler?.layoutManager = GridLayoutManager(context, 1)
val settingsManager = context?.let { PreferenceManager.getDefaultSharedPreferences(it) }
val isAdvancedSearch = settingsManager?.getBoolean("advanced_search", true) ?: true
search_master_recycler?.isVisible = isAdvancedSearch
search_autofit_results?.isVisible = !isAdvancedSearch
// SubtitlesFragment.push(activity)
//searchViewModel.search("iron man")
//(activity as AppCompatActivity).loadResult("https://shiro.is/overlord-dubbed", "overlord-dubbed", "Shiro")

View file

@ -0,0 +1,103 @@
package com.lagradost.cloudstream3.ui.search
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.TvType
import kotlinx.android.synthetic.main.search_history_item.view.*
data class SearchHistoryItem(
@JsonProperty("searchedAt") val searchedAt: Long,
@JsonProperty("searchText") val searchText: String,
@JsonProperty("type") val type: List<TvType>,
@JsonProperty("key") val key: String,
)
data class SearchHistoryCallback(
val item: SearchHistoryItem,
val clickAction: Int,
)
const val SEARCH_HISTORY_OPEN = 0
const val SEARCH_HISTORY_REMOVE = 1
class SearchHistoryAdaptor(
private val cardList: MutableList<SearchHistoryItem>,
private val clickCallback: (SearchHistoryCallback) -> Unit,
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return CardViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.search_history_item, parent, false),
clickCallback,
)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is CardViewHolder -> {
holder.bind(cardList[position])
}
}
}
override fun getItemCount(): Int {
return cardList.size
}
fun updateList(newList: List<SearchHistoryItem>) {
val diffResult = DiffUtil.calculateDiff(
SearchHistoryDiffCallback(this.cardList, newList)
)
cardList.clear()
cardList.addAll(newList)
diffResult.dispatchUpdatesTo(this)
}
class CardViewHolder
constructor(
itemView: View,
private val clickCallback: (SearchHistoryCallback) -> Unit,
) :
RecyclerView.ViewHolder(itemView) {
private val removeButton: ImageView = itemView.home_history_remove
private val openButton: View = itemView.home_history_tab
private val title: TextView = itemView.home_history_title
fun bind(card: SearchHistoryItem) {
title.text = card.searchText
removeButton.setOnClickListener {
clickCallback.invoke(SearchHistoryCallback(card, SEARCH_HISTORY_REMOVE))
}
openButton.setOnClickListener {
clickCallback.invoke(SearchHistoryCallback(card, SEARCH_HISTORY_OPEN))
}
}
}
}
class SearchHistoryDiffCallback(
private val oldList: List<SearchHistoryItem>,
private val newList: List<SearchHistoryItem>
) :
DiffUtil.Callback() {
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
oldList[oldItemPosition].searchText == newList[newItemPosition].searchText
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
oldList[oldItemPosition] == newList[newItemPosition]
}

View file

@ -6,11 +6,15 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.apis
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.getKeys
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.SyncApis
import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.ui.APIRepository
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
@ -21,22 +25,28 @@ data class OnGoingSearch(
val data: Resource<List<SearchResponse>>
)
class SearchViewModel : ViewModel() {
private val _searchResponse: MutableLiveData<Resource<ArrayList<SearchResponse>>> =
MutableLiveData()
val searchResponse: LiveData<Resource<ArrayList<SearchResponse>>> get() = _searchResponse
const val SEARCH_HISTORY_KEY = "search_history"
private val _currentSearch: MutableLiveData<ArrayList<OnGoingSearch>> = MutableLiveData()
val currentSearch: LiveData<ArrayList<OnGoingSearch>> get() = _currentSearch
class SearchViewModel : ViewModel() {
private val _searchResponse: MutableLiveData<Resource<List<SearchResponse>>> =
MutableLiveData()
val searchResponse: LiveData<Resource<List<SearchResponse>>> get() = _searchResponse
private val _currentSearch: MutableLiveData<List<OnGoingSearch>> = MutableLiveData()
val currentSearch: LiveData<List<OnGoingSearch>> get() = _currentSearch
private val _currentHistory: MutableLiveData<List<SearchHistoryItem>> = MutableLiveData()
val currentHistory: LiveData<List<SearchHistoryItem>> get() = _currentHistory
private val repos = apis.map { APIRepository(it) }
private val syncApis = SyncApis
private fun clearSearch() {
fun clearSearch() {
_searchResponse.postValue(Resource.Success(ArrayList()))
_currentSearch.postValue(emptyList())
}
var onGoingSearch: Job? = null
private var onGoingSearch: Job? = null
fun searchAndCancel(
query: String,
isMainApis: Boolean = true,
@ -68,6 +78,15 @@ class SearchViewModel : ViewModel() {
)
}
fun updateHistory() = viewModelScope.launch {
ioSafe {
val items = getKeys(SEARCH_HISTORY_KEY)?.mapNotNull {
getKey<SearchHistoryItem>(it)
}?.sortedByDescending { it.searchedAt } ?: emptyList()
_currentHistory.postValue(items)
}
}
private fun search(
query: String,
isMainApis: Boolean = true,
@ -80,6 +99,18 @@ class SearchViewModel : ViewModel() {
return@launch
}
val key = query.hashCode().toString()
setKey(
SEARCH_HISTORY_KEY,
key,
SearchHistoryItem(
searchedAt = System.currentTimeMillis(),
searchText = query,
type = emptyList(), // TODO implement tv type
key = key,
)
)
_searchResponse.postValue(Resource.Loading())
val currentList = ArrayList<OnGoingSearch>()

View file

@ -81,6 +81,7 @@
app:tint="?attr/textColor"
android:contentDescription="@string/change_providers_img_des" />
</FrameLayout>
<HorizontalScrollView
android:paddingStart="10dp"
android:paddingEnd="10dp"
@ -144,6 +145,7 @@
<com.lagradost.cloudstream3.ui.AutofitRecyclerView
android:visibility="gone"
android:nextFocusLeft="@id/nav_rail_view"
android:descendantFocusability="afterDescendants"
@ -160,6 +162,7 @@
android:orientation="vertical" />
<androidx.recyclerview.widget.RecyclerView
android:visibility="gone"
android:nextFocusLeft="@id/nav_rail_view"
android:descendantFocusability="afterDescendants"
@ -168,4 +171,15 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/homepage_parent" />
<androidx.recyclerview.widget.RecyclerView
android:visibility="visible"
android:nextFocusLeft="@id/nav_rail_view"
android:descendantFocusability="afterDescendants"
android:background="?attr/primaryBlackBackground"
android:id="@+id/search_history_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/search_history_item" />
</LinearLayout>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="@+id/home_history_tab"
android:nextFocusRight="@id/home_history_remove">
<TextView
android:id="@+id/home_history_title"
android:textColor="?attr/textColor"
android:textSize="18sp"
tools:text="Hello World"
android:padding="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<ImageView
android:padding="10dp"
android:id="@+id/home_history_remove"
android:nextFocusLeft="@id/home_history_tab"
android:src="@drawable/ic_baseline_close_24"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical|end"
android:layout_height="match_parent"
app:tint="?attr/white"
tools:ignore="ContentDescription"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>