mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
updated homepage UI
This commit is contained in:
parent
fdaf7d34a0
commit
fd7e7ae3e0
8 changed files with 162 additions and 47 deletions
|
@ -35,8 +35,8 @@ android {
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 31
|
targetSdkVersion 31
|
||||||
|
|
||||||
versionCode 35
|
versionCode 36
|
||||||
versionName "2.4.3"
|
versionName "2.4.4"
|
||||||
|
|
||||||
resValue "string", "app_version",
|
resValue "string", "app_version",
|
||||||
"${defaultConfig.versionName}${versionNameSuffix ?: ""}"
|
"${defaultConfig.versionName}${versionNameSuffix ?: ""}"
|
||||||
|
|
|
@ -53,8 +53,9 @@ import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||||
import com.lagradost.cloudstream3.widget.CenterZoomLayoutManager
|
import com.lagradost.cloudstream3.widget.CenterZoomLayoutManager
|
||||||
import kotlinx.android.synthetic.main.fragment_home.*
|
import kotlinx.android.synthetic.main.fragment_home.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
const val HOME_BOOKMARK_VALUE = "home_bookmarked_last"
|
const val HOME_BOOKMARK_VALUE_LIST = "home_bookmarked_last_list"
|
||||||
|
|
||||||
class HomeFragment : Fragment() {
|
class HomeFragment : Fragment() {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -164,7 +165,11 @@ class HomeFragment : Fragment() {
|
||||||
private fun reloadStored() {
|
private fun reloadStored() {
|
||||||
context?.let { ctx ->
|
context?.let { ctx ->
|
||||||
homeViewModel.loadResumeWatching(ctx)
|
homeViewModel.loadResumeWatching(ctx)
|
||||||
homeViewModel.loadStoredData(ctx, WatchType.fromInternalId(ctx.getKey(HOME_BOOKMARK_VALUE)))
|
val list = EnumSet.noneOf(WatchType::class.java)
|
||||||
|
ctx.getKey<IntArray>(HOME_BOOKMARK_VALUE_LIST)?.map { WatchType.fromInternalId(it) }?.let {
|
||||||
|
list.addAll(it)
|
||||||
|
}
|
||||||
|
homeViewModel.loadStoredData(ctx, list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,9 +306,46 @@ class HomeFragment : Fragment() {
|
||||||
activity?.loadHomepageList(item)
|
activity?.loadHomepageList(item)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
val toggleList = listOf(
|
||||||
|
Pair(home_type_watching_btt, WatchType.WATCHING),
|
||||||
|
Pair(home_type_completed_btt, WatchType.COMPLETED),
|
||||||
|
Pair(home_type_dropped_btt, WatchType.DROPPED),
|
||||||
|
Pair(home_type_on_hold_btt, WatchType.ONHOLD),
|
||||||
|
Pair(home_plan_to_watch_btt, WatchType.PLANTOWATCH),
|
||||||
|
)
|
||||||
|
|
||||||
|
for (item in toggleList) {
|
||||||
|
val watch = item.second
|
||||||
|
item.first?.setOnClickListener { itemView ->
|
||||||
|
val list = EnumSet.noneOf(WatchType::class.java)
|
||||||
|
itemView.context.getKey<IntArray>(HOME_BOOKMARK_VALUE_LIST)?.map { WatchType.fromInternalId(it) }?.let {
|
||||||
|
list.addAll(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.contains(watch)) {
|
||||||
|
list.remove(watch)
|
||||||
|
} else {
|
||||||
|
list.add(watch)
|
||||||
|
}
|
||||||
|
homeViewModel.loadStoredData(itemView.context, list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
observe(homeViewModel.availableWatchStatusTypes) { availableWatchStatusTypes ->
|
observe(homeViewModel.availableWatchStatusTypes) { availableWatchStatusTypes ->
|
||||||
context?.setKey(HOME_BOOKMARK_VALUE, availableWatchStatusTypes.first.internalId)
|
context?.setKey(
|
||||||
home_bookmark_select?.setOnClickListener {
|
HOME_BOOKMARK_VALUE_LIST,
|
||||||
|
availableWatchStatusTypes.first.map { it.internalId }.toIntArray()
|
||||||
|
)
|
||||||
|
|
||||||
|
for (item in toggleList) {
|
||||||
|
val watch = item.second
|
||||||
|
item.first?.apply {
|
||||||
|
isVisible = availableWatchStatusTypes.second.contains(watch)
|
||||||
|
isSelected = availableWatchStatusTypes.first.contains(watch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*home_bookmark_select?.setOnClickListener {
|
||||||
it.popupMenuNoIcons(availableWatchStatusTypes.second.map { type ->
|
it.popupMenuNoIcons(availableWatchStatusTypes.second.map { type ->
|
||||||
Pair(
|
Pair(
|
||||||
type.internalId,
|
type.internalId,
|
||||||
|
@ -313,18 +355,20 @@ class HomeFragment : Fragment() {
|
||||||
homeViewModel.loadStoredData(it.context, WatchType.fromInternalId(this.itemId))
|
homeViewModel.loadStoredData(it.context, WatchType.fromInternalId(this.itemId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
home_bookmarked_parent_item_title?.text = getString(availableWatchStatusTypes.first.stringRes)
|
home_bookmarked_parent_item_title?.text = getString(availableWatchStatusTypes.first.stringRes)*/
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(homeViewModel.bookmarks) { bookmarks ->
|
observe(homeViewModel.bookmarks) { pair ->
|
||||||
home_bookmarked_holder.isVisible = bookmarks.isNotEmpty()
|
home_bookmarked_holder.isVisible = pair.first
|
||||||
|
|
||||||
|
val bookmarks = pair.second
|
||||||
(home_bookmarked_child_recyclerview?.adapter as HomeChildItemAdapter?)?.cardList = bookmarks
|
(home_bookmarked_child_recyclerview?.adapter as HomeChildItemAdapter?)?.cardList = bookmarks
|
||||||
home_bookmarked_child_recyclerview?.adapter?.notifyDataSetChanged()
|
home_bookmarked_child_recyclerview?.adapter?.notifyDataSetChanged()
|
||||||
|
|
||||||
home_bookmarked_child_more_info.setOnClickListener {
|
home_bookmarked_child_more_info?.setOnClickListener {
|
||||||
activity?.loadHomepageList(
|
activity?.loadHomepageList(
|
||||||
HomePageList(
|
HomePageList(
|
||||||
home_bookmarked_parent_item_title?.text?.toString() ?: getString(R.string.error_bookmarks_text),
|
getString(R.string.error_bookmarks_text), //home_bookmarked_parent_item_title?.text?.toString() ?: getString(R.string.error_bookmarks_text),
|
||||||
bookmarks
|
bookmarks
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -444,8 +488,8 @@ class HomeFragment : Fragment() {
|
||||||
home_change_api_loading?.isFocusableInTouchMode = true
|
home_change_api_loading?.isFocusableInTouchMode = true
|
||||||
home_change_api?.isFocusable = true
|
home_change_api?.isFocusable = true
|
||||||
home_change_api?.isFocusableInTouchMode = true
|
home_change_api?.isFocusableInTouchMode = true
|
||||||
home_bookmark_select?.isFocusable = true
|
// home_bookmark_select?.isFocusable = true
|
||||||
home_bookmark_select?.isFocusableInTouchMode = true
|
// home_bookmark_select?.isFocusableInTouchMode = true
|
||||||
}
|
}
|
||||||
|
|
||||||
for (syncApi in OAuth2API.OAuth2Apis) {
|
for (syncApi in OAuth2API.OAuth2Apis) {
|
||||||
|
@ -458,7 +502,5 @@ class HomeFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -29,6 +29,7 @@ import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class HomeViewModel : ViewModel() {
|
class HomeViewModel : ViewModel() {
|
||||||
private var repo: APIRepository? = null
|
private var repo: APIRepository? = null
|
||||||
|
@ -46,10 +47,10 @@ class HomeViewModel : ViewModel() {
|
||||||
return APIRepository(apis.first { it.hasMainPage })
|
return APIRepository(apis.first { it.hasMainPage })
|
||||||
}
|
}
|
||||||
|
|
||||||
private val _availableWatchStatusTypes = MutableLiveData<Pair<WatchType, List<WatchType>>>()
|
private val _availableWatchStatusTypes = MutableLiveData<Pair<EnumSet<WatchType>, EnumSet<WatchType>>>()
|
||||||
val availableWatchStatusTypes: LiveData<Pair<WatchType, List<WatchType>>> = _availableWatchStatusTypes
|
val availableWatchStatusTypes: LiveData<Pair<EnumSet<WatchType>, EnumSet<WatchType>>> = _availableWatchStatusTypes
|
||||||
private val _bookmarks = MutableLiveData<List<SearchResponse>>()
|
private val _bookmarks = MutableLiveData<Pair<Boolean, List<SearchResponse>>>()
|
||||||
val bookmarks: LiveData<List<SearchResponse>> = _bookmarks
|
val bookmarks: LiveData<Pair<Boolean, List<SearchResponse>>> = _bookmarks
|
||||||
|
|
||||||
private val _resumeWatching = MutableLiveData<List<SearchResponse>>()
|
private val _resumeWatching = MutableLiveData<List<SearchResponse>>()
|
||||||
val resumeWatching: LiveData<List<SearchResponse>> = _resumeWatching
|
val resumeWatching: LiveData<List<SearchResponse>> = _resumeWatching
|
||||||
|
@ -89,14 +90,14 @@ class HomeViewModel : ViewModel() {
|
||||||
_resumeWatching.postValue(resumeWatchingResult)
|
_resumeWatching.postValue(resumeWatchingResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadStoredData(context: Context, preferredWatchStatus: WatchType?) = viewModelScope.launch {
|
fun loadStoredData(context: Context, preferredWatchStatus: EnumSet<WatchType>?) = viewModelScope.launch {
|
||||||
val watchStatusIds = withContext(Dispatchers.IO) {
|
val watchStatusIds = withContext(Dispatchers.IO) {
|
||||||
context.getAllWatchStateIds().map { id ->
|
context.getAllWatchStateIds().map { id ->
|
||||||
Pair(id, context.getResultWatchState(id))
|
Pair(id, context.getResultWatchState(id))
|
||||||
}
|
}
|
||||||
}.distinctBy { it.first }
|
}.distinctBy { it.first }
|
||||||
val length = WatchType.values().size
|
val length = WatchType.values().size
|
||||||
val currentWatchTypes = HashSet<WatchType>()
|
val currentWatchTypes = EnumSet.noneOf(WatchType::class.java)
|
||||||
|
|
||||||
for (watch in watchStatusIds) {
|
for (watch in watchStatusIds) {
|
||||||
currentWatchTypes.add(watch.second)
|
currentWatchTypes.add(watch.second)
|
||||||
|
@ -108,25 +109,26 @@ class HomeViewModel : ViewModel() {
|
||||||
currentWatchTypes.remove(WatchType.NONE)
|
currentWatchTypes.remove(WatchType.NONE)
|
||||||
|
|
||||||
if (currentWatchTypes.size <= 0) {
|
if (currentWatchTypes.size <= 0) {
|
||||||
_bookmarks.postValue(ArrayList())
|
_bookmarks.postValue(Pair(false, ArrayList()))
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
val watchPrefNotNull = preferredWatchStatus ?: currentWatchTypes.first()
|
val watchPrefNotNull = preferredWatchStatus ?: EnumSet.of(currentWatchTypes.first())
|
||||||
val watchStatus =
|
//if (currentWatchTypes.any { watchPrefNotNull.contains(it) }) watchPrefNotNull else listOf(currentWatchTypes.first())
|
||||||
if (currentWatchTypes.contains(watchPrefNotNull)) watchPrefNotNull else currentWatchTypes.first()
|
|
||||||
_availableWatchStatusTypes.postValue(
|
_availableWatchStatusTypes.postValue(
|
||||||
Pair(
|
Pair(
|
||||||
watchStatus,
|
watchPrefNotNull,
|
||||||
currentWatchTypes.sortedBy { it.internalId }.toList()
|
currentWatchTypes,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val list = withContext(Dispatchers.IO) {
|
val list = withContext(Dispatchers.IO) {
|
||||||
watchStatusIds.filter { it.second == watchStatus }
|
watchStatusIds.filter { watchPrefNotNull.contains(it.second) }
|
||||||
.mapNotNull { context.getBookmarkedData(it.first) }
|
.mapNotNull { context.getBookmarkedData(it.first) }
|
||||||
.sortedBy { -it.latestUpdatedTime }
|
.sortedBy { -it.latestUpdatedTime }
|
||||||
}
|
}
|
||||||
_bookmarks.postValue(list)
|
_bookmarks.postValue(Pair(true,list))
|
||||||
}
|
}
|
||||||
|
|
||||||
private var onGoingLoad: Job? = null
|
private var onGoingLoad: Job? = null
|
||||||
|
|
5
app/src/main/res/color/toggle_button.xml
Normal file
5
app/src/main/res/color/toggle_button.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_selected="true" android:color="?attr/colorPrimaryDark"/>
|
||||||
|
<item android:color="@color/transparent"/>
|
||||||
|
</selector>
|
5
app/src/main/res/color/toggle_button_outline.xml
Normal file
5
app/src/main/res/color/toggle_button_outline.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_selected="true" android:color="?attr/colorPrimary"/>
|
||||||
|
<item android:color="?attr/iconColor"/>
|
||||||
|
</selector>
|
5
app/src/main/res/color/toggle_button_text.xml
Normal file
5
app/src/main/res/color/toggle_button_text.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_selected="true" android:color="@color/white"/>
|
||||||
|
<item android:color="?attr/textColor"/>
|
||||||
|
</selector>
|
|
@ -332,28 +332,68 @@
|
||||||
|
|
||||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||||
android:id="@+id/home_bookmarked_child_more_info"
|
android:id="@+id/home_bookmarked_child_more_info"
|
||||||
android:padding="12dp"
|
android:paddingTop="5dp"
|
||||||
|
android:paddingBottom="5dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
<ImageView
|
<HorizontalScrollView
|
||||||
|
android:fadingEdge="horizontal"
|
||||||
|
android:requiresFadingEdge="horizontal"
|
||||||
|
android:layout_marginEnd="50dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
android:nextFocusLeft="@id/nav_rail_view"
|
android:nextFocusLeft="@id/nav_rail_view"
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
android:nextFocusRight="@id/home_plan_to_watch_btt"
|
||||||
|
android:nextFocusDown="@id/home_bookmarked_child_recyclerview"
|
||||||
|
android:nextFocusUp="@id/home_watch_child_recyclerview"
|
||||||
|
|
||||||
android:tint="?attr/textColor"
|
android:id="@+id/home_type_watching_btt"
|
||||||
|
android:text="@string/type_watching"
|
||||||
|
style="@style/RoundedSelectableButton"/>
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:nextFocusLeft="@id/home_type_watching_btt"
|
||||||
|
android:nextFocusRight="@id/home_type_on_hold_btt"
|
||||||
|
android:nextFocusDown="@id/home_bookmarked_child_recyclerview"
|
||||||
|
android:nextFocusUp="@id/home_watch_child_recyclerview"
|
||||||
|
|
||||||
android:id="@+id/home_bookmark_select"
|
android:id="@+id/home_plan_to_watch_btt"
|
||||||
android:src="@drawable/ic_baseline_filter_list_24"
|
android:text="@string/type_plan_to_watch"
|
||||||
android:layout_width="24dp"
|
style="@style/RoundedSelectableButton"/>
|
||||||
android:layout_height="24dp"
|
<com.google.android.material.button.MaterialButton
|
||||||
android:contentDescription="@string/filter_bookmarks">
|
android:nextFocusLeft="@id/home_plan_to_watch_btt"
|
||||||
</ImageView>
|
android:nextFocusRight="@id/home_type_dropped_btt"
|
||||||
<TextView
|
android:nextFocusDown="@id/home_bookmarked_child_recyclerview"
|
||||||
android:layout_gravity="center_vertical"
|
android:nextFocusUp="@id/home_watch_child_recyclerview"
|
||||||
android:layout_marginStart="40dp"
|
|
||||||
android:id="@+id/home_bookmarked_parent_item_title"
|
android:id="@+id/home_type_on_hold_btt"
|
||||||
style="@style/WatchHeaderText"
|
android:text="@string/type_on_hold"
|
||||||
tools:text="Bookmarked"
|
style="@style/RoundedSelectableButton"/>
|
||||||
/>
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:nextFocusLeft="@id/home_type_on_hold_btt"
|
||||||
|
android:nextFocusRight="@id/home_type_completed_btt"
|
||||||
|
android:nextFocusDown="@id/home_bookmarked_child_recyclerview"
|
||||||
|
android:nextFocusUp="@id/home_watch_child_recyclerview"
|
||||||
|
|
||||||
|
android:id="@+id/home_type_dropped_btt"
|
||||||
|
android:text="@string/type_dropped"
|
||||||
|
style="@style/RoundedSelectableButton"/>
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:nextFocusLeft="@id/home_type_dropped_btt"
|
||||||
|
android:nextFocusDown="@id/home_bookmarked_child_recyclerview"
|
||||||
|
android:nextFocusUp="@id/home_watch_child_recyclerview"
|
||||||
|
|
||||||
|
android:id="@+id/home_type_completed_btt"
|
||||||
|
android:text="@string/type_completed"
|
||||||
|
style="@style/RoundedSelectableButton"/>
|
||||||
|
</LinearLayout>
|
||||||
|
</HorizontalScrollView>
|
||||||
<ImageView
|
<ImageView
|
||||||
android:tint="?attr/textColor"
|
android:tint="?attr/textColor"
|
||||||
android:layout_marginEnd="5dp"
|
android:layout_marginEnd="5dp"
|
||||||
|
|
|
@ -306,6 +306,22 @@
|
||||||
<item name="rippleColor">?attr/textColor</item>
|
<item name="rippleColor">?attr/textColor</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="RoundedSelectableButton">
|
||||||
|
<item name="backgroundTint">@color/toggle_button</item>
|
||||||
|
<item name="rippleColor">@color/textColor</item>
|
||||||
|
<item name="android:textColor">@color/toggle_button_text</item>
|
||||||
|
<item name="cornerRadius">100dp</item>
|
||||||
|
<item name="strokeWidth">1dp</item>
|
||||||
|
<item name="strokeColor">@color/toggle_button_outline</item>
|
||||||
|
<item name="android:layout_width">wrap_content</item>
|
||||||
|
<item name="android:layout_height">45dp</item>
|
||||||
|
<item name="android:padding">0dp</item>
|
||||||
|
<!--<item name="android:layout_marginStart">10dp</item>-->
|
||||||
|
<item name="android:layout_marginEnd">5dp</item>
|
||||||
|
<item name="textAllCaps">false</item>
|
||||||
|
<item name="android:textSize">13sp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="MultiSelectButton" parent="BlackButton">
|
<style name="MultiSelectButton" parent="BlackButton">
|
||||||
<item name="android:layout_height">40dp</item>
|
<item name="android:layout_height">40dp</item>
|
||||||
<item name="android:layout_width">wrap_content</item>
|
<item name="android:layout_width">wrap_content</item>
|
||||||
|
|
Loading…
Reference in a new issue