change to UI

This commit is contained in:
LagradOst 2021-12-26 01:05:10 +01:00
parent 9d2e924ac1
commit 2a1e0d98a3
15 changed files with 355 additions and 54 deletions

View file

@ -268,6 +268,10 @@ fun parseRating(ratingString: String?): Int? {
return (floatRating * 10).toInt()
}
fun MainAPI.fixUrlNull(url : String?) : String? {
return fixUrl(url ?: return null)
}
fun MainAPI.fixUrl(url: String): String {
if (url.startsWith("http")) {
return url

View file

@ -31,17 +31,6 @@ open class VidstreamProviderTemplate : MainAPI() {
// If getMainPage() is functional, used to display the homepage in app, an optional, but highly encouraged endevour.
override val hasMainPage = true
// Sometimes on sites the urls can be something like "/movie.html" which translates to "*full site url*/movie.html" in the browser
private fun fixUrl(url: String): String {
return if (url.startsWith("//")) {
"https:$url"
} else if (url.startsWith("/")) {
"$mainUrl$url"
} else {
url
}
}
// Searching returns a SearchResponse, which can be one of the following: AnimeSearchResponse, MovieSearchResponse, TorrentSearchResponse, TvSeriesSearchResponse
// Each of the classes requires some different data, but always has some critical things like name, poster and url.
override fun search(query: String): ArrayList<SearchResponse> {

View file

@ -14,13 +14,16 @@ class APIRepository(val api: MainAPI) {
val noneApi = object : MainAPI() {
override val name = "None"
override val supportedTypes = emptySet<TvType>()
}
val randomApi = object : MainAPI() {
override val name = "Random"
override val supportedTypes = emptySet<TvType>()
}
val noneRepo = APIRepository(noneApi)
}
val hasMainPage: Boolean get() = api.hasMainPage
val name: String get() = api.name
val mainUrl: String get() = api.mainUrl

View file

@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.ui.home
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.net.Uri
@ -9,9 +10,9 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.TextView
import android.widget.*
import androidx.core.view.isVisible
import androidx.core.widget.NestedScrollView
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager
@ -19,6 +20,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSnapHelper
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.button.MaterialButton
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.apis
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
@ -58,6 +60,7 @@ import kotlinx.android.synthetic.main.fragment_home.*
import java.util.*
const val HOME_BOOKMARK_VALUE_LIST = "home_bookmarked_last_list"
const val HOME_PREF_HOMEPAGE = "home_pref_homepage"
class HomeFragment : Fragment() {
companion object {
@ -102,6 +105,126 @@ class HomeFragment : Fragment() {
bottomSheetDialogBuilder.show()
}
fun Context.selectHomepage(selectedApiName: String?, callback: (String) -> Unit) {
println("CURRENT $selectedApiName")
val validAPIs = filterProviderByPreferredMedia().toMutableList()
validAPIs.add(0, randomApi)
validAPIs.add(0, noneApi)
//val builder: AlertDialog.Builder = AlertDialog.Builder(this)
//builder.setView(R.layout.home_select_mainpage)
val builder =
BottomSheetDialog(this)
builder.setContentView(R.layout.home_select_mainpage)
builder.show()
builder.let { dialog ->
//dialog.window?.setGravity(Gravity.BOTTOM)
var currentApiName = selectedApiName
var currentValidApis: MutableList<MainAPI> = mutableListOf()
val preSelectedTypes = this.getKey<List<String>>(HOME_PREF_HOMEPAGE)
?.mapNotNull { listName -> TvType.values().firstOrNull { it.name == listName } }?.toMutableList()
?: mutableListOf(TvType.Movie, TvType.TvSeries)
val anime = dialog.findViewById<MaterialButton>(R.id.home_select_anime)
val cartoons = dialog.findViewById<MaterialButton>(R.id.home_select_cartoons)
val tvs = dialog.findViewById<MaterialButton>(R.id.home_select_tv_series)
val docs = dialog.findViewById<MaterialButton>(R.id.home_select_documentaries)
val movies = dialog.findViewById<MaterialButton>(R.id.home_select_movies)
val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)
val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt)
cancelBtt?.setOnClickListener {
dialog.dismissSafe()
}
applyBtt?.setOnClickListener {
if (currentApiName != selectedApiName) {
currentApiName?.let(callback)
}
dialog.dismissSafe()
}
val listView = dialog.findViewById<ListView>(R.id.listview1)
val arrayAdapter = ArrayAdapter<String>(this, R.layout.sort_bottom_single_choice)
listView?.adapter = arrayAdapter
listView?.choiceMode = AbsListView.CHOICE_MODE_SINGLE
listView?.setOnItemClickListener { _, _, i, _ ->
if (!currentValidApis.isNullOrEmpty()) {
currentApiName = currentValidApis[i].name
//to switch to apply simply remove this
currentApiName?.let(callback)
dialog.dismissSafe()
}
}
val pairList = listOf(
Pair(anime, listOf(TvType.Anime, TvType.ONA, TvType.AnimeMovie)),
Pair(cartoons, listOf(TvType.Cartoon)),
Pair(tvs, listOf(TvType.TvSeries)),
Pair(docs, listOf(TvType.Documentary)),
Pair(movies, listOf(TvType.Movie, TvType.Torrent))
)
fun updateList() {
this.setKey(HOME_PREF_HOMEPAGE, preSelectedTypes)
arrayAdapter.clear()
currentValidApis = validAPIs.filter { api ->
api.hasMainPage && api.supportedTypes.any {
preSelectedTypes.contains(it)
}
}.toMutableList()
currentValidApis.addAll(0, validAPIs.subList(0, 2))
val names = currentValidApis.map { it.name }
val index = names.indexOf(currentApiName)
println("INDEX: $index")
listView?.setItemChecked(index, true)
arrayAdapter.notifyDataSetChanged()
arrayAdapter.addAll(names)
arrayAdapter.notifyDataSetChanged()
}
for ((button, validTypes) in pairList) {
val isValid = validAPIs.any { api -> validTypes.any { api.supportedTypes.contains(it) } }
button?.isVisible = isValid
if (isValid) {
fun buttonContains(): Boolean {
return preSelectedTypes.any { validTypes.contains(it) }
}
button?.isSelected = buttonContains()
button?.setOnClickListener {
preSelectedTypes.clear()
preSelectedTypes.addAll(validTypes)
for ((otherButton, _) in pairList) {
otherButton?.isSelected = false
}
button.isSelected = true
updateList()
}
button?.setOnLongClickListener {
if (!buttonContains()) {
button.isSelected = true
preSelectedTypes.addAll(validTypes)
} else {
button.isSelected = false
preSelectedTypes.removeAll(validTypes)
}
updateList()
return@setOnLongClickListener true
}
}
}
updateList()
}
}
}
private val homeViewModel: HomeViewModel by activityViewModels()
@ -131,13 +254,16 @@ class HomeFragment : Fragment() {
}
private val apiChangeClickListener = View.OnClickListener { view ->
val validAPIs = view.context?.filterProviderByPreferredMedia()?.toMutableList() ?: mutableListOf()
view.context.selectHomepage(currentApiName) { api ->
homeViewModel.loadAndCancel(api)
}
/*val validAPIs = view.context?.filterProviderByPreferredMedia()?.toMutableList() ?: mutableListOf()
validAPIs.add(0, randomApi)
validAPIs.add(0, noneApi)
view.popupMenuNoIconsAndNoStringRes(validAPIs.mapIndexed { index, api -> Pair(index, api.name) }) {
homeViewModel.loadAndCancel(validAPIs[itemId].name)
}
}*/
}
override fun onConfigurationChanged(newConfig: Configuration) {
@ -170,6 +296,8 @@ class HomeFragment : Fragment() {
}
}*/
var currentApiName: String? = null
@SuppressLint("SetTextI18n")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -177,8 +305,10 @@ class HomeFragment : Fragment() {
home_change_api.setOnClickListener(apiChangeClickListener)
home_change_api_loading.setOnClickListener(apiChangeClickListener)
home_api_fab.setOnClickListener(apiChangeClickListener)
observe(homeViewModel.apiName) { apiName ->
currentApiName = apiName
setKey(HOMEPAGE_API, apiName)
home_provider_name?.text = apiName
home_provider_meta_info?.isVisible = false
@ -312,7 +442,11 @@ class HomeFragment : Fragment() {
for (item in toggleList) {
val watch = item.second
item.first?.setOnClickListener { itemView ->
item.first?.setOnClickListener {
homeViewModel.loadStoredData(EnumSet.of(watch))
}
item.first?.setOnLongClickListener { itemView ->
val list = EnumSet.noneOf(WatchType::class.java)
itemView.context.getKey<IntArray>(HOME_BOOKMARK_VALUE_LIST)?.map { WatchType.fromInternalId(it) }?.let {
list.addAll(it)
@ -324,10 +458,6 @@ class HomeFragment : Fragment() {
list.add(watch)
}
homeViewModel.loadStoredData(list)
}
item.first?.setOnLongClickListener {
homeViewModel.loadStoredData(EnumSet.of(watch))
return@setOnLongClickListener true
}
}
@ -478,17 +608,35 @@ class HomeFragment : Fragment() {
homeViewModel.loadAndCancel(apiName)
}
home_loaded.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { view, _, scrollY, _, oldScrollY ->
val dy = scrollY - oldScrollY
if (dy > 0) { //check for scroll down
home_api_fab?.hide()
} else if (dy < -5) {
if (view?.context?.isTvSettings() == false) {
home_api_fab?.show()
}
}
})
// nice profile pic on homepage
home_profile_picture_holder?.isVisible = false
context?.let { ctx ->
// just in case
if (ctx.isTvSettings()) {
home_api_fab?.isVisible = false
home_change_api?.isVisible = true
home_change_api_loading?.isVisible = true
home_change_api_loading?.isFocusable = true
home_change_api_loading?.isFocusableInTouchMode = true
home_change_api?.isFocusable = true
home_change_api?.isFocusableInTouchMode = true
// home_bookmark_select?.isFocusable = true
// home_bookmark_select?.isFocusableInTouchMode = true
} else {
home_api_fab?.isVisible = true
home_change_api?.isVisible = false
home_change_api_loading?.isVisible = false
}
for (syncApi in OAuth2API.OAuth2Apis) {

View file

@ -118,7 +118,7 @@ class SearchFragment : Fragment() {
if (apiNamesSetting != null && langs != null) {
val apiNames = apis.filter { langs.contains(it.lang) }.map { it.name }
val builder =
AlertDialog.Builder(searchView.context, R.style.AlertDialogCustom).setView(R.layout.provider_list)
AlertDialog.Builder(searchView.context).setView(R.layout.provider_list)
val dialog = builder.create()
dialog.show()

View file

@ -345,6 +345,12 @@ object UIHelper {
}
}
fun Dialog?.dismissSafe() {
if (this?.isShowing == true) {
this.dismiss()
}
}
/**id, stringRes */
@SuppressLint("RestrictedApi")
fun View.popupMenuNoIcons(

View file

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?attr/iconGrayBackground"/>
<solid android:color="?attr/boxItemBackground"/>
<corners android:topLeftRadius="16dp"
android:topRightRadius="16dp"/>
</shape>

View file

@ -4,7 +4,6 @@
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:background="?attr/primaryBlackBackground"
android:layout_height="match_parent">
<TextView
@ -26,9 +25,9 @@
android:nextFocusLeft="@id/apply_btt"
android:id="@+id/listview1"
android:layout_marginTop="-10dp"
android:layout_marginBottom="60dp"
android:paddingTop="10dp"
android:requiresFadingEdge="vertical"
tools:listitem="@layout/sort_bottom_single_choice"
android:layout_width="match_parent"
android:layout_height="match_parent"

View file

@ -369,17 +369,17 @@
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:paddingHorizontal="5dp"
android:clipToPadding="false"
android:descendantFocusability="afterDescendants"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:id="@+id/home_watch_child_recyclerview"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:listitem="@layout/home_result_grid"
/>
<androidx.recyclerview.widget.RecyclerView
android:paddingHorizontal="5dp"
android:clipToPadding="false"
android:descendantFocusability="afterDescendants"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:id="@+id/home_watch_child_recyclerview"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:listitem="@layout/home_result_grid"
/>
</LinearLayout>
@ -484,4 +484,12 @@
/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:visibility="gone"
tools:visibility="visible"
android:id="@+id/home_api_fab"
app:icon="@drawable/ic_baseline_filter_list_24"
style="@style/ExtendedFloatingActionButton"
tools:ignore="ContentDescription">
</com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton>
</FrameLayout>

View file

@ -654,20 +654,9 @@
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:visibility="gone"
tools:visibility="visible"
app:elevation="0dp"
android:textStyle="bold"
app:backgroundTint="?attr/primaryGrayBackground"
app:tint="?attr/colorPrimary"
android:textColor="?attr/colorPrimary"
app:iconTint="?attr/colorPrimary"
android:layout_margin="16dp"
android:id="@+id/result_bookmark_fab"
android:layout_gravity="end|bottom"
app:icon="@drawable/ic_baseline_bookmark_24"
android:textAllCaps="false"
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/ExtendedFloatingActionButton"
tools:ignore="ContentDescription">
</com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton>
<fragment

View file

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<ListView
android:clipToPadding="false"
android:nextFocusRight="@id/cancel_btt"
android:nextFocusLeft="@id/apply_btt"
android:id="@+id/listview1"
android:minHeight="0dp"
android:layout_marginTop="10dp"
android:requiresFadingEdge="vertical"
tools:listitem="@layout/sort_bottom_single_choice"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_rowWeight="1"
/>
<HorizontalScrollView
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:clipToPadding="true"
android:fadingEdge="horizontal"
android:requiresFadingEdge="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<!-- android:minWidth="0dp"
app:iconTint="?attr/textColor"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
app:iconGravity="textStart"
app:iconPadding="0dp"
android:layout_height="35dp"-->
<!-- <com.google.android.material.button.MaterialButton
android:nextFocusRight="@id/home_select_tv_series"
app:icon="@drawable/ic_baseline_close_24"
android:id="@+id/home_select_none"
style="@style/RoundedSelectableButtonIcon"/>-->
<com.google.android.material.button.MaterialButton
android:nextFocusRight="@id/home_select_tv_series"
android:id="@+id/home_select_movies"
android:text="@string/movies"
style="@style/RoundedSelectableButton"/>
<com.google.android.material.button.MaterialButton
android:nextFocusLeft="@id/home_select_movies"
android:nextFocusRight="@id/home_select_anime"
android:id="@+id/home_select_tv_series"
android:text="@string/tv_series"
style="@style/RoundedSelectableButton"/>
<com.google.android.material.button.MaterialButton
android:nextFocusLeft="@id/home_select_tv_series"
android:nextFocusRight="@id/home_select_cartoons"
android:id="@+id/home_select_anime"
android:text="@string/anime"
style="@style/RoundedSelectableButton"/>
<com.google.android.material.button.MaterialButton
android:nextFocusLeft="@id/home_select_anime"
android:nextFocusRight="@id/home_select_documentaries"
android:id="@+id/home_select_cartoons"
android:text="@string/cartoons"
style="@style/RoundedSelectableButton"/>
<com.google.android.material.button.MaterialButton
android:nextFocusLeft="@id/home_select_cartoons"
android:id="@+id/home_select_documentaries"
android:text="@string/documentaries"
style="@style/RoundedSelectableButton"/>
</LinearLayout>
</HorizontalScrollView>
<LinearLayout
android:visibility="gone"
android:id="@+id/apply_btt_holder"
android:orientation="horizontal"
android:layout_gravity="bottom"
android:gravity="bottom|end"
android:layout_width="match_parent"
android:layout_height="60dp">
<com.google.android.material.button.MaterialButton
style="@style/WhiteButton"
android:layout_gravity="center_vertical|end"
android:text="@string/sort_apply"
android:id="@+id/apply_btt"
android:layout_width="wrap_content"
/>
<com.google.android.material.button.MaterialButton
style="@style/BlackButton"
android:layout_gravity="center_vertical|end"
android:text="@string/sort_cancel"
android:id="@+id/cancel_btt"
android:layout_width="wrap_content"
/>
</LinearLayout>
</LinearLayout>

View file

@ -39,6 +39,7 @@
android:id="@+id/sort_providers"
android:background="?attr/primaryBlackBackground"
android:requiresFadingEdge="vertical"
tools:listitem="@layout/sort_bottom_single_choice"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -95,6 +96,7 @@
android:id="@+id/sort_subtitles"
android:background="?attr/primaryBlackBackground"
android:requiresFadingEdge="vertical"
tools:listitem="@layout/sort_bottom_single_choice"
android:layout_width="match_parent"
android:layout_rowWeight="1"

View file

@ -40,6 +40,7 @@
android:layout_marginTop="-10dp"
android:layout_marginBottom="60dp"
android:paddingTop="10dp"
android:requiresFadingEdge="vertical"
tools:listitem="@layout/sort_bottom_single_choice"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -56,6 +57,7 @@
android:layout_marginTop="-10dp"
android:layout_marginBottom="60dp"
android:paddingTop="10dp"
android:requiresFadingEdge="vertical"
tools:listitem="@layout/sort_bottom_single_choice"
android:layout_width="match_parent"
android:layout_height="match_parent"

View file

@ -30,6 +30,7 @@
android:paddingTop="10dp"
android:id="@+id/sort_providers"
android:background="?attr/primaryBlackBackground"
android:requiresFadingEdge="vertical"
tools:listitem="@layout/sort_bottom_single_choice"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -60,6 +61,7 @@
android:paddingTop="10dp"
android:id="@+id/sort_subtitles"
android:background="?attr/primaryBlackBackground"
android:requiresFadingEdge="vertical"
tools:listitem="@layout/sort_bottom_single_choice"
android:layout_width="match_parent"
android:layout_rowWeight="1"

View file

@ -22,6 +22,11 @@
<item name="bottomSheetDialogTheme">@style/AppBottomSheetDialogTheme</item>
<item name="searchViewStyle">@style/AppSearchViewStyle</item>
<item name="tabStyle">@style/Theme.Widget.Tabs</item>
<item name="android:divider">@color/transparent</item>
<item name="divider">@color/transparent</item>
<item name="android:dividerHeight">0dp</item>
<item name="showDividers">none</item>
<item name="android:listViewStyle">@style/ListViewStyle</item>
<item name="castExpandedControllerStyle">
@style/CustomCastExpandedController
@ -57,6 +62,10 @@
<item name="white">#FFF</item>
</style>
<style name="ListViewStyle" parent="Widget.AppCompat.ListView">
<item name="android:divider">@null</item>
</style>
<style name="AmoledModeLight" parent="AmoledMode">
<item name="primaryGrayBackground">@color/amoledModeLight</item>
</style>
@ -160,6 +169,7 @@
<item name="android:navigationBarColor">?attr/primaryGrayBackground</item>
<item name="android:windowBackground">?attr/primaryBlackBackground</item>
</style>
<style name="AppSearchViewStyle"
parent="Theme.MaterialComponents.NoActionBar">
<item name="android:searchIcon">@drawable/search_icon</item>
@ -167,18 +177,25 @@
<item name="android:background">@color/transparent</item>
<item name="android:fontFamily">@font/google_sans</item>
</style>
<style name="AppBottomSheetDialogTheme"
parent="Theme.Design.Light.BottomSheetDialog">
<style name="AppBottomSheetDialogTheme">
<item name="android:windowCloseOnTouchOutside">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowAnimationStyle">@style/Animation.Design.BottomSheetDialog</item>
<item name="bottomSheetStyle">@style/AppModalStyle</item>
</style>
<style name="AppModalStyle"
parent="Widget.Design.BottomSheet.Modal">
<style name="AppModalStyle">
<item name="android:windowCloseOnTouchOutside">true</item>
<item name="behavior_hideable">true</item>
<item name="behavior_skipCollapsed">true</item>
<item name="shapeAppearance">@null</item>
<item name="shapeAppearanceOverlay">@null</item>
<item name="backgroundTint">?android:attr/colorBackground</item>
<item name="android:background">@drawable/rounded_dialog</item>
<item name="behavior_peekHeight">512dp</item>
</style>
<style name="PreferenceTheme" parent="@style/AppTheme">
</style>
@ -306,6 +323,30 @@
<item name="rippleColor">?attr/textColor</item>
</style>
<style name="RoundedSelectableButtonIcon" parent="RoundedSelectableButton">
<item name="minWidth">0dp</item>
<item name="iconTint">?attr/textColor</item>
<item name="iconGravity">textStart</item>
<item name="iconPadding">0dp</item>
<item name="android:layout_width">35dp</item>
<!--<item name="android:layout_height">35dp</item>-->
</style>
<style name="ExtendedFloatingActionButton">
<item name="elevation">0dp</item>
<item name="android:textStyle">bold</item>
<item name="backgroundTint">?attr/primaryGrayBackground</item>
<item name="tint">?attr/colorPrimary</item>
<item name="textColor">?attr/colorPrimary</item>
<item name="iconTint">?attr/textColor</item>
<item name="android:layout_margin">16dp</item>
<item name="android:layout_gravity">end|bottom</item>
<item name="textAllCaps">false</item>
<item name="android:gravity">center</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
</style>
<style name="RoundedSelectableButton">
<item name="backgroundTint">@color/toggle_button</item>
<item name="rippleColor">@color/textColor</item>