mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Merge branch 'recloudstream:master' into master
This commit is contained in:
commit
69d87b7b36
31 changed files with 714 additions and 206 deletions
|
@ -51,7 +51,7 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://developer.android.com/about/versions/14/behavior-changes-14#safer-dynamic-code-loading
|
// https://developer.android.com/about/versions/14/behavior-changes-14#safer-dynamic-code-loading
|
||||||
compileSdk = 33 // android 14 is fucked
|
compileSdk = 34 // android 14 is fucked
|
||||||
buildToolsVersion = "34.0.0"
|
buildToolsVersion = "34.0.0"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
@ -157,7 +157,7 @@ dependencies {
|
||||||
implementation("androidx.test.ext:junit-ktx:1.1.5")
|
implementation("androidx.test.ext:junit-ktx:1.1.5")
|
||||||
testImplementation("org.json:json:20230618")
|
testImplementation("org.json:json:20230618")
|
||||||
|
|
||||||
implementation("androidx.core:core-ktx:1.10.1") // need 34 for higher
|
implementation("androidx.core:core-ktx:1.12.0") // need 34 for higher
|
||||||
implementation("androidx.appcompat:appcompat:1.6.1") // need target 32 for 1.5.0
|
implementation("androidx.appcompat:appcompat:1.6.1") // need target 32 for 1.5.0
|
||||||
|
|
||||||
// dont change this to 1.6.0 it looks ugly af
|
// dont change this to 1.6.0 it looks ugly af
|
||||||
|
@ -165,10 +165,10 @@ dependencies {
|
||||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||||
|
|
||||||
// need 34 for higher
|
// need 34 for higher
|
||||||
implementation("androidx.navigation:navigation-fragment-ktx:2.6.0")
|
implementation("androidx.navigation:navigation-fragment-ktx:2.7.4")
|
||||||
implementation("androidx.navigation:navigation-ui-ktx:2.6.0")
|
implementation("androidx.navigation:navigation-ui-ktx:2.7.4")
|
||||||
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.1")
|
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.2")
|
||||||
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
|
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
|
||||||
|
|
||||||
testImplementation("junit:junit:4.13.2")
|
testImplementation("junit:junit:4.13.2")
|
||||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||||
|
@ -232,7 +232,7 @@ dependencies {
|
||||||
// Networking
|
// Networking
|
||||||
// implementation("com.squareup.okhttp3:okhttp:4.9.2")
|
// implementation("com.squareup.okhttp3:okhttp:4.9.2")
|
||||||
// implementation("com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.1")
|
// implementation("com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.1")
|
||||||
implementation("com.github.Blatzar:NiceHttp:0.4.3")
|
implementation("com.github.Blatzar:NiceHttp:0.4.4") // http library
|
||||||
// To fix SSL fuckery on android 9
|
// To fix SSL fuckery on android 9
|
||||||
implementation("org.conscrypt:conscrypt-android:2.5.2")
|
implementation("org.conscrypt:conscrypt-android:2.5.2")
|
||||||
// Util to skip the URI file fuckery 🙏
|
// Util to skip the URI file fuckery 🙏
|
||||||
|
|
|
@ -19,6 +19,7 @@ import com.lagradost.cloudstream3.databinding.FragmentSearchBinding
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentSearchTvBinding
|
import com.lagradost.cloudstream3.databinding.FragmentSearchTvBinding
|
||||||
import com.lagradost.cloudstream3.databinding.HomeResultGridBinding
|
import com.lagradost.cloudstream3.databinding.HomeResultGridBinding
|
||||||
import com.lagradost.cloudstream3.databinding.HomepageParentBinding
|
import com.lagradost.cloudstream3.databinding.HomepageParentBinding
|
||||||
|
import com.lagradost.cloudstream3.databinding.HomepageParentEmulatorBinding
|
||||||
import com.lagradost.cloudstream3.databinding.HomepageParentTvBinding
|
import com.lagradost.cloudstream3.databinding.HomepageParentTvBinding
|
||||||
import com.lagradost.cloudstream3.databinding.PlayerCustomLayoutBinding
|
import com.lagradost.cloudstream3.databinding.PlayerCustomLayoutBinding
|
||||||
import com.lagradost.cloudstream3.databinding.PlayerCustomLayoutTvBinding
|
import com.lagradost.cloudstream3.databinding.PlayerCustomLayoutTvBinding
|
||||||
|
@ -119,8 +120,9 @@ class ExampleInstrumentedTest {
|
||||||
// testAllLayouts<HomeScrollViewBinding>(activity, R.layout.home_scroll_view, R.layout.home_scroll_view_tv)
|
// testAllLayouts<HomeScrollViewBinding>(activity, R.layout.home_scroll_view, R.layout.home_scroll_view_tv)
|
||||||
// testAllLayouts<HomeScrollViewTvBinding>(activity, R.layout.home_scroll_view, R.layout.home_scroll_view_tv)
|
// testAllLayouts<HomeScrollViewTvBinding>(activity, R.layout.home_scroll_view, R.layout.home_scroll_view_tv)
|
||||||
|
|
||||||
testAllLayouts<HomepageParentTvBinding>(activity, R.layout.homepage_parent_tv, R.layout.homepage_parent)
|
testAllLayouts<HomepageParentTvBinding>(activity, R.layout.homepage_parent_tv, R.layout.homepage_parent_emulator, R.layout.homepage_parent)
|
||||||
testAllLayouts<HomepageParentBinding>(activity, R.layout.homepage_parent_tv, R.layout.homepage_parent)
|
testAllLayouts<HomepageParentEmulatorBinding>(activity, R.layout.homepage_parent_tv, R.layout.homepage_parent_emulator, R.layout.homepage_parent)
|
||||||
|
testAllLayouts<HomepageParentBinding>(activity, R.layout.homepage_parent_tv, R.layout.homepage_parent_emulator, R.layout.homepage_parent)
|
||||||
|
|
||||||
testAllLayouts<FragmentLibraryTvBinding>(activity, R.layout.fragment_library_tv, R.layout.fragment_library)
|
testAllLayouts<FragmentLibraryTvBinding>(activity, R.layout.fragment_library_tv, R.layout.fragment_library)
|
||||||
testAllLayouts<FragmentLibraryBinding>(activity, R.layout.fragment_library_tv, R.layout.fragment_library)
|
testAllLayouts<FragmentLibraryBinding>(activity, R.layout.fragment_library_tv, R.layout.fragment_library)
|
||||||
|
|
|
@ -662,7 +662,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
val isAtHome =
|
val isAtHome =
|
||||||
navController?.currentDestination?.matchDestination(R.id.navigation_home) == true
|
navController?.currentDestination?.matchDestination(R.id.navigation_home) == true
|
||||||
|
|
||||||
if (isAtHome && isTrueTvSettings()) {
|
if (isAtHome && isTvSettings()) {
|
||||||
showConfirmExitDialog()
|
showConfirmExitDialog()
|
||||||
} else {
|
} else {
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
|
|
|
@ -8,7 +8,9 @@ import com.lagradost.cloudstream3.syncproviders.SyncIdName
|
||||||
import com.lagradost.cloudstream3.ui.WatchType
|
import com.lagradost.cloudstream3.ui.WatchType
|
||||||
import com.lagradost.cloudstream3.ui.library.ListSorting
|
import com.lagradost.cloudstream3.ui.library.ListSorting
|
||||||
import com.lagradost.cloudstream3.ui.result.txt
|
import com.lagradost.cloudstream3.ui.result.txt
|
||||||
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioWork
|
import com.lagradost.cloudstream3.utils.Coroutines.ioWork
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllFavorites
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllSubscriptions
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllSubscriptions
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllWatchStateIds
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllWatchStateIds
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData
|
||||||
|
@ -69,29 +71,52 @@ class LocalList : SyncAPI {
|
||||||
}?.distinctBy { it.first } ?: return null
|
}?.distinctBy { it.first } ?: return null
|
||||||
|
|
||||||
val list = ioWork {
|
val list = ioWork {
|
||||||
watchStatusIds.groupBy {
|
val isTrueTv = isTrueTvSettings()
|
||||||
it.second.stringRes
|
|
||||||
}.mapValues { group ->
|
val baseMap = WatchType.values().filter { it != WatchType.NONE }.associate {
|
||||||
|
// None is not something to display
|
||||||
|
it.stringRes to emptyList<SyncAPI.LibraryItem>()
|
||||||
|
} + mapOf(
|
||||||
|
R.string.favorites_list_name to emptyList()
|
||||||
|
) + if (!isTrueTv) {
|
||||||
|
mapOf(
|
||||||
|
R.string.subscription_list_name to emptyList()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
emptyMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
val watchStatusMap = watchStatusIds.groupBy { it.second.stringRes }.mapValues { group ->
|
||||||
group.value.mapNotNull {
|
group.value.mapNotNull {
|
||||||
getBookmarkedData(it.first)?.toLibraryItem(it.first.toString())
|
getBookmarkedData(it.first)?.toLibraryItem(it.first.toString())
|
||||||
}
|
}
|
||||||
} + mapOf(R.string.subscription_list_name to getAllSubscriptions().mapNotNull {
|
}
|
||||||
|
|
||||||
|
val favoritesMap = mapOf(R.string.favorites_list_name to getAllFavorites().mapNotNull {
|
||||||
it.toLibraryItem()
|
it.toLibraryItem()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Don't show subscriptions on TV
|
||||||
|
val result = if (isTrueTv) {
|
||||||
|
baseMap + watchStatusMap + favoritesMap
|
||||||
|
} else {
|
||||||
|
val subscriptionsMap = mapOf(R.string.subscription_list_name to getAllSubscriptions().mapNotNull {
|
||||||
|
it.toLibraryItem()
|
||||||
|
})
|
||||||
|
|
||||||
|
baseMap + watchStatusMap + subscriptionsMap + favoritesMap
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
val baseMap = WatchType.values().filter { it != WatchType.NONE }.associate {
|
|
||||||
// None is not something to display
|
|
||||||
it.stringRes to emptyList<SyncAPI.LibraryItem>()
|
|
||||||
} + mapOf(R.string.subscription_list_name to emptyList())
|
|
||||||
|
|
||||||
return SyncAPI.LibraryMetadata(
|
return SyncAPI.LibraryMetadata(
|
||||||
(baseMap + list).map { SyncAPI.LibraryList(txt(it.key), it.value) },
|
list.map { SyncAPI.LibraryList(txt(it.key), it.value) },
|
||||||
setOf(
|
setOf(
|
||||||
ListSorting.AlphabeticalA,
|
ListSorting.AlphabeticalA,
|
||||||
ListSorting.AlphabeticalZ,
|
ListSorting.AlphabeticalZ,
|
||||||
// ListSorting.UpdatedNew,
|
ListSorting.UpdatedNew,
|
||||||
// ListSorting.UpdatedOld,
|
ListSorting.UpdatedOld,
|
||||||
// ListSorting.RatingHigh,
|
// ListSorting.RatingHigh,
|
||||||
// ListSorting.RatingLow,
|
// ListSorting.RatingLow,
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,7 +15,8 @@ import com.lagradost.cloudstream3.ui.result.FOCUS_SELF
|
||||||
import com.lagradost.cloudstream3.ui.result.setLinearListLayout
|
import com.lagradost.cloudstream3.ui.result.setLinearListLayout
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchFragment.Companion.filterSearchResponse
|
import com.lagradost.cloudstream3.ui.search.SearchFragment.Companion.filterSearchResponse
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
|
||||||
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.isRecyclerScrollable
|
import com.lagradost.cloudstream3.utils.AppUtils.isRecyclerScrollable
|
||||||
|
|
||||||
class LoadClickCallback(
|
class LoadClickCallback(
|
||||||
|
@ -34,11 +35,13 @@ open class ParentItemAdapter(
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
|
|
||||||
val root = LayoutInflater.from(parent.context).inflate(
|
val layoutResId = when {
|
||||||
if (isTvSettings()) R.layout.homepage_parent_tv else R.layout.homepage_parent,
|
isTrueTvSettings() -> R.layout.homepage_parent_tv
|
||||||
parent,
|
parent.context.isEmulatorSettings() -> R.layout.homepage_parent_emulator
|
||||||
false
|
else -> R.layout.homepage_parent
|
||||||
)
|
}
|
||||||
|
|
||||||
|
val root = LayoutInflater.from(parent.context).inflate(layoutResId, parent, false)
|
||||||
|
|
||||||
val binding = HomepageParentBinding.bind(root)
|
val binding = HomepageParentBinding.bind(root)
|
||||||
|
|
||||||
|
@ -234,7 +237,7 @@ open class ParentItemAdapter(
|
||||||
})
|
})
|
||||||
|
|
||||||
//(recyclerView.adapter as HomeChildItemAdapter).notifyDataSetChanged()
|
//(recyclerView.adapter as HomeChildItemAdapter).notifyDataSetChanged()
|
||||||
if (!isTvSettings()) {
|
if (!isTrueTvSettings()) {
|
||||||
title.setOnClickListener {
|
title.setOnClickListener {
|
||||||
moreInfoClickCallback.invoke(expand)
|
moreInfoClickCallback.invoke(expand)
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ import com.lagradost.cloudstream3.ui.result.setLinearListLayout
|
||||||
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_LOAD
|
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_LOAD
|
||||||
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_SHOW_METADATA
|
import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_SHOW_METADATA
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
||||||
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||||
|
@ -81,6 +82,28 @@ class HomeParentItemAdapterPreview(
|
||||||
parent,
|
parent,
|
||||||
false
|
false
|
||||||
) else FragmentHomeHeadBinding.inflate(inflater, parent, false)
|
) else FragmentHomeHeadBinding.inflate(inflater, parent, false)
|
||||||
|
|
||||||
|
if (binding is FragmentHomeHeadTvBinding && parent.context.isEmulatorSettings()) {
|
||||||
|
binding.homeBookmarkParentItemMoreInfo.isVisible = true
|
||||||
|
|
||||||
|
val marginInDp = 50
|
||||||
|
val density = binding.horizontalScrollChips.context.resources.displayMetrics.density
|
||||||
|
val marginInPixels = (marginInDp * density).toInt()
|
||||||
|
|
||||||
|
val params = binding.horizontalScrollChips.layoutParams as ViewGroup.MarginLayoutParams
|
||||||
|
params.marginEnd = marginInPixels
|
||||||
|
binding.horizontalScrollChips.layoutParams = params
|
||||||
|
binding.homeWatchParentItemTitle.setCompoundDrawablesWithIntrinsicBounds(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
ContextCompat.getDrawable(
|
||||||
|
parent.context,
|
||||||
|
R.drawable.ic_baseline_arrow_forward_24
|
||||||
|
),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
HeaderViewHolder(
|
HeaderViewHolder(
|
||||||
binding,
|
binding,
|
||||||
viewModel,
|
viewModel,
|
||||||
|
@ -553,12 +576,19 @@ class HomeParentItemAdapterPreview(
|
||||||
resumeHolder.isVisible = resumeWatching.isNotEmpty()
|
resumeHolder.isVisible = resumeWatching.isNotEmpty()
|
||||||
resumeAdapter.updateList(resumeWatching)
|
resumeAdapter.updateList(resumeWatching)
|
||||||
|
|
||||||
if (binding is FragmentHomeHeadBinding) {
|
if (
|
||||||
binding.homeWatchParentItemTitle.setOnClickListener {
|
binding is FragmentHomeHeadBinding ||
|
||||||
|
binding is FragmentHomeHeadTvBinding &&
|
||||||
|
binding.root.context.isEmulatorSettings()
|
||||||
|
) {
|
||||||
|
val title = (binding as? FragmentHomeHeadBinding)?.homeWatchParentItemTitle
|
||||||
|
?: (binding as? FragmentHomeHeadTvBinding)?.homeWatchParentItemTitle
|
||||||
|
|
||||||
|
title?.setOnClickListener {
|
||||||
viewModel.popup(
|
viewModel.popup(
|
||||||
HomeViewModel.ExpandableHomepageList(
|
HomeViewModel.ExpandableHomepageList(
|
||||||
HomePageList(
|
HomePageList(
|
||||||
binding.homeWatchParentItemTitle.text.toString(),
|
title.text.toString(),
|
||||||
resumeWatching,
|
resumeWatching,
|
||||||
false
|
false
|
||||||
), 1, false
|
), 1, false
|
||||||
|
@ -576,8 +606,15 @@ class HomeParentItemAdapterPreview(
|
||||||
bookmarkHolder.isVisible = visible
|
bookmarkHolder.isVisible = visible
|
||||||
bookmarkAdapter.updateList(list)
|
bookmarkAdapter.updateList(list)
|
||||||
|
|
||||||
if (binding is FragmentHomeHeadBinding) {
|
if (
|
||||||
binding.homeBookmarkParentItemTitle.setOnClickListener {
|
binding is FragmentHomeHeadBinding ||
|
||||||
|
binding is FragmentHomeHeadTvBinding &&
|
||||||
|
binding.root.context.isEmulatorSettings()
|
||||||
|
) {
|
||||||
|
val title = (binding as? FragmentHomeHeadBinding)?.homeBookmarkParentItemTitle
|
||||||
|
?: (binding as? FragmentHomeHeadTvBinding)?.homeBookmarkParentItemTitle
|
||||||
|
|
||||||
|
title?.setOnClickListener {
|
||||||
val items = toggleList.map { it.first }.filter { it.isChecked }
|
val items = toggleList.map { it.first }.filter { it.isChecked }
|
||||||
if (items.isEmpty()) return@setOnClickListener // we don't want to show an empty dialog
|
if (items.isEmpty()) return@setOnClickListener // we don't want to show an empty dialog
|
||||||
val textSum = items
|
val textSum = items
|
||||||
|
|
|
@ -8,12 +8,14 @@ import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.util.TypedValue
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.ViewGroup.FOCUS_AFTER_DESCENDANTS
|
import android.view.ViewGroup.FOCUS_AFTER_DESCENDANTS
|
||||||
import android.view.ViewGroup.FOCUS_BLOCK_DESCENDANTS
|
import android.view.ViewGroup.FOCUS_BLOCK_DESCENDANTS
|
||||||
import android.view.animation.AlphaAnimation
|
import android.view.animation.AlphaAnimation
|
||||||
|
import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
@ -137,6 +139,13 @@ class LibraryFragment : Fragment() {
|
||||||
tag = "tv_no_focus_tag"
|
tag = "tv_no_focus_tag"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the color for the search exit icon to the correct theme text color
|
||||||
|
val searchExitIcon = binding?.mainSearch?.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)
|
||||||
|
val searchExitIconColor = TypedValue()
|
||||||
|
|
||||||
|
activity?.theme?.resolveAttribute(android.R.attr.textColor, searchExitIconColor, true)
|
||||||
|
searchExitIcon?.setColorFilter(searchExitIconColor.data)
|
||||||
|
|
||||||
binding?.mainSearch?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
binding?.mainSearch?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||||
override fun onQueryTextSubmit(query: String?): Boolean {
|
override fun onQueryTextSubmit(query: String?): Boolean {
|
||||||
libraryViewModel.sort(ListSorting.Query, query)
|
libraryViewModel.sort(ListSorting.Query, query)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.TypedValue
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -215,10 +216,16 @@ class QuickSearchFragment : Fragment() {
|
||||||
binding?.quickSearch?.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)
|
binding?.quickSearch?.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)
|
||||||
|
|
||||||
//val searchMagIcon =
|
//val searchMagIcon =
|
||||||
// binding.quickSearch.findViewById<ImageView>(androidx.appcompat.R.id.search_mag_icon)
|
// binding?.quickSearch?.findViewById<ImageView>(androidx.appcompat.R.id.search_mag_icon)
|
||||||
|
|
||||||
//searchMagIcon?.scaleX = 0.65f
|
// searchMagIcon?.scaleX = 0.65f
|
||||||
//searchMagIcon?.scaleY = 0.65f
|
// searchMagIcon?.scaleY = 0.65f
|
||||||
|
|
||||||
|
// Set the color for the search exit icon to the correct theme text color
|
||||||
|
val searchExitIconColor = TypedValue()
|
||||||
|
|
||||||
|
activity?.theme?.resolveAttribute(android.R.attr.textColor, searchExitIconColor, true)
|
||||||
|
searchExitIcon?.setColorFilter(searchExitIconColor.data)
|
||||||
|
|
||||||
binding?.quickSearch?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
binding?.quickSearch?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||||
override fun onQueryTextSubmit(query: String): Boolean {
|
override fun onQueryTextSubmit(query: String): Boolean {
|
||||||
|
|
|
@ -17,7 +17,6 @@ import android.view.animation.DecelerateInterpolator
|
||||||
import android.widget.AbsListView
|
import android.widget.AbsListView
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.NestedScrollView
|
import androidx.core.widget.NestedScrollView
|
||||||
|
@ -66,6 +65,7 @@ import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant
|
||||||
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogText
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper
|
import com.lagradost.cloudstream3.utils.UIHelper
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
||||||
|
@ -445,6 +445,20 @@ open class ResultFragmentPhone : FullScreenPlayer() {
|
||||||
?: txt(R.string.no_data).asStringNull(context) ?: ""
|
?: txt(R.string.no_data).asStringNull(context) ?: ""
|
||||||
CommonActivity.showToast(txt(message, name), Toast.LENGTH_SHORT)
|
CommonActivity.showToast(txt(message, name), Toast.LENGTH_SHORT)
|
||||||
}
|
}
|
||||||
|
resultFavorite.setOnClickListener {
|
||||||
|
val isFavorite =
|
||||||
|
viewModel.toggleFavoriteStatus() ?: return@setOnClickListener
|
||||||
|
|
||||||
|
val message = if (isFavorite) {
|
||||||
|
R.string.favorite_added
|
||||||
|
} else {
|
||||||
|
R.string.favorite_removed
|
||||||
|
}
|
||||||
|
|
||||||
|
val name = (viewModel.page.value as? Resource.Success)?.value?.title
|
||||||
|
?: txt(R.string.no_data).asStringNull(context) ?: ""
|
||||||
|
CommonActivity.showToast(txt(message, name), Toast.LENGTH_SHORT)
|
||||||
|
}
|
||||||
mediaRouteButton.apply {
|
mediaRouteButton.apply {
|
||||||
val chromecastSupport = api?.hasChromecastSupport == true
|
val chromecastSupport = api?.hasChromecastSupport == true
|
||||||
alpha = if (chromecastSupport) 1f else 0.3f
|
alpha = if (chromecastSupport) 1f else 0.3f
|
||||||
|
@ -564,6 +578,19 @@ open class ResultFragmentPhone : FullScreenPlayer() {
|
||||||
binding?.resultSubscribe?.setImageResource(drawable)
|
binding?.resultSubscribe?.setImageResource(drawable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
observeNullable(viewModel.favoriteStatus) { isFavorite ->
|
||||||
|
binding?.resultFavorite?.isVisible = isFavorite != null
|
||||||
|
if (isFavorite == null) return@observeNullable
|
||||||
|
|
||||||
|
val drawable = if (isFavorite) {
|
||||||
|
R.drawable.ic_baseline_favorite_24
|
||||||
|
} else {
|
||||||
|
R.drawable.ic_baseline_favorite_border_24
|
||||||
|
}
|
||||||
|
|
||||||
|
binding?.resultFavorite?.setImageResource(drawable)
|
||||||
|
}
|
||||||
|
|
||||||
observe(viewModel.trailers) { trailers ->
|
observe(viewModel.trailers) { trailers ->
|
||||||
setTrailers(trailers.flatMap { it.mirros }) // I dont care about subtitles yet!
|
setTrailers(trailers.flatMap { it.mirros }) // I dont care about subtitles yet!
|
||||||
}
|
}
|
||||||
|
@ -654,14 +681,13 @@ open class ResultFragmentPhone : FullScreenPlayer() {
|
||||||
resultPoster.setImage(d.posterImage)
|
resultPoster.setImage(d.posterImage)
|
||||||
resultPosterBackground.setImage(d.posterBackgroundImage)
|
resultPosterBackground.setImage(d.posterBackgroundImage)
|
||||||
resultDescription.setTextHtml(d.plotText)
|
resultDescription.setTextHtml(d.plotText)
|
||||||
resultDescription.setOnClickListener { view ->
|
resultDescription.setOnClickListener {
|
||||||
// todo bottom view?
|
activity?.let { activity ->
|
||||||
view.context?.let { ctx ->
|
activity.showBottomDialogText(
|
||||||
val builder: AlertDialog.Builder =
|
d.titleText.asString(activity),
|
||||||
AlertDialog.Builder(ctx, R.style.AlertDialogCustom)
|
d.plotText.asString(activity).html(),
|
||||||
builder.setMessage(d.plotText.asString(ctx).html())
|
{}
|
||||||
.setTitle(d.plotHeaderText.asString(ctx))
|
)
|
||||||
.show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -852,16 +878,11 @@ open class ResultFragmentPhone : FullScreenPlayer() {
|
||||||
setRecommendations(recommendations, null)
|
setRecommendations(recommendations, null)
|
||||||
}
|
}
|
||||||
observe(viewModel.episodeSynopsis) { description ->
|
observe(viewModel.episodeSynopsis) { description ->
|
||||||
// TODO bottom dialog
|
activity?.let { activity ->
|
||||||
view.context?.let { ctx ->
|
activity.showBottomDialogText(
|
||||||
val builder: AlertDialog.Builder =
|
activity.getString(R.string.synopsis),
|
||||||
AlertDialog.Builder(ctx, R.style.AlertDialogCustom)
|
description.html()
|
||||||
builder.setMessage(description.html())
|
) { viewModel.releaseEpisodeSynopsis() }
|
||||||
.setTitle(R.string.synopsis)
|
|
||||||
.setOnDismissListener {
|
|
||||||
viewModel.releaseEpisodeSynopsis()
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
context?.let { ctx ->
|
context?.let { ctx ->
|
||||||
|
|
|
@ -8,6 +8,7 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.animation.DecelerateInterpolator
|
import android.view.animation.DecelerateInterpolator
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
@ -17,6 +18,7 @@ import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
||||||
|
import com.lagradost.cloudstream3.CommonActivity
|
||||||
import com.lagradost.cloudstream3.DubStatus
|
import com.lagradost.cloudstream3.DubStatus
|
||||||
import com.lagradost.cloudstream3.LoadResponse
|
import com.lagradost.cloudstream3.LoadResponse
|
||||||
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
|
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
|
||||||
|
@ -265,6 +267,7 @@ class ResultFragmentTv : Fragment() {
|
||||||
resultEpisodesShow.onFocusChangeListener = rightListener
|
resultEpisodesShow.onFocusChangeListener = rightListener
|
||||||
resultDescription.onFocusChangeListener = leftListener
|
resultDescription.onFocusChangeListener = leftListener
|
||||||
resultBookmarkButton.onFocusChangeListener = leftListener
|
resultBookmarkButton.onFocusChangeListener = leftListener
|
||||||
|
resultFavoriteButton.onFocusChangeListener = leftListener
|
||||||
resultEpisodesShow.setOnClickListener {
|
resultEpisodesShow.setOnClickListener {
|
||||||
// toggle, to make it more touch accessable just in case someone thinks that a
|
// toggle, to make it more touch accessable just in case someone thinks that a
|
||||||
// tv layout is better but is using a touch device
|
// tv layout is better but is using a touch device
|
||||||
|
@ -283,7 +286,8 @@ class ResultFragmentTv : Fragment() {
|
||||||
resultPlaySeries,
|
resultPlaySeries,
|
||||||
resultResumeSeries,
|
resultResumeSeries,
|
||||||
resultPlayTrailer,
|
resultPlayTrailer,
|
||||||
resultBookmarkButton
|
resultBookmarkButton,
|
||||||
|
resultFavoriteButton
|
||||||
)
|
)
|
||||||
for (requestView in views) {
|
for (requestView in views) {
|
||||||
if (!requestView.isVisible) continue
|
if (!requestView.isVisible) continue
|
||||||
|
@ -424,6 +428,7 @@ class ResultFragmentTv : Fragment() {
|
||||||
val aboveCast = listOf(
|
val aboveCast = listOf(
|
||||||
binding?.resultEpisodesShow,
|
binding?.resultEpisodesShow,
|
||||||
binding?.resultBookmarkButton,
|
binding?.resultBookmarkButton,
|
||||||
|
binding?.resultFavoriteButton,
|
||||||
).firstOrNull {
|
).firstOrNull {
|
||||||
it?.isVisible == true
|
it?.isVisible == true
|
||||||
}
|
}
|
||||||
|
@ -532,9 +537,45 @@ class ResultFragmentTv : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
observeNullable(viewModel.favoriteStatus) { isFavorite ->
|
||||||
|
binding?.resultFavoriteButton?.apply {
|
||||||
|
isVisible = isFavorite != null
|
||||||
|
if (isFavorite == null) return@observeNullable
|
||||||
|
|
||||||
|
val drawable = if (isFavorite) {
|
||||||
|
R.drawable.ic_baseline_favorite_24
|
||||||
|
} else {
|
||||||
|
R.drawable.ic_baseline_favorite_border_24
|
||||||
|
}
|
||||||
|
|
||||||
|
val text = if (isFavorite) {
|
||||||
|
R.string.action_remove_from_favorites
|
||||||
|
} else {
|
||||||
|
R.string.action_add_to_favorites
|
||||||
|
}
|
||||||
|
|
||||||
|
setIconResource(drawable)
|
||||||
|
setText(text)
|
||||||
|
setOnClickListener {
|
||||||
|
val isFavorite = viewModel.toggleFavoriteStatus() ?: return@setOnClickListener
|
||||||
|
|
||||||
|
val message = if (isFavorite) {
|
||||||
|
R.string.favorite_added
|
||||||
|
} else {
|
||||||
|
R.string.favorite_removed
|
||||||
|
}
|
||||||
|
|
||||||
|
val name = (viewModel.page.value as? Resource.Success)?.value?.title
|
||||||
|
?: txt(R.string.no_data).asStringNull(context) ?: ""
|
||||||
|
CommonActivity.showToast(txt(message, name), Toast.LENGTH_SHORT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
observeNullable(viewModel.movie) { data ->
|
observeNullable(viewModel.movie) { data ->
|
||||||
binding?.apply {
|
binding?.apply {
|
||||||
resultPlayMovie.isVisible = data is Resource.Success
|
resultPlayMovie.isVisible = data is Resource.Success
|
||||||
|
resultPlaySeries.isVisible = data == null
|
||||||
seriesHolder.isVisible = data == null
|
seriesHolder.isVisible = data == null
|
||||||
resultEpisodesShow.isVisible = data == null
|
resultEpisodesShow.isVisible = data == null
|
||||||
|
|
||||||
|
@ -764,12 +805,14 @@ class ResultFragmentTv : Fragment() {
|
||||||
R.drawable.profile_bg_red,
|
R.drawable.profile_bg_red,
|
||||||
R.drawable.profile_bg_teal
|
R.drawable.profile_bg_teal
|
||||||
).random()
|
).random()
|
||||||
|
//Change poster crop area to 20% from Top
|
||||||
|
backgroundPoster.cropYCenterOffsetPct = 0.20F
|
||||||
|
|
||||||
backgroundPoster.setImage(
|
backgroundPoster.setImage(
|
||||||
d.posterBackgroundImage ?: UiImage.Drawable(error),
|
d.posterBackgroundImage ?: UiImage.Drawable(error),
|
||||||
radius = 0,
|
radius = 0,
|
||||||
errorImageDrawable = error
|
errorImageDrawable = error
|
||||||
)
|
)
|
||||||
|
|
||||||
resultComingSoon.isVisible = d.comingSoon
|
resultComingSoon.isVisible = d.comingSoon
|
||||||
resultDataHolder.isGone = d.comingSoon
|
resultDataHolder.isGone = d.comingSoon
|
||||||
UIHelper.populateChips(resultTag, d.tags)
|
UIHelper.populateChips(resultTag, d.tags)
|
||||||
|
|
|
@ -51,11 +51,14 @@ import com.lagradost.cloudstream3.utils.Coroutines.ioWork
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioWorkSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioWorkSafe
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getDub
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getDub
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getFavoritesData
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultEpisode
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultEpisode
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultSeason
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultSeason
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultWatchState
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultWatchState
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.removeFavoritesData
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.setDub
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.setDub
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.setFavoritesData
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultEpisode
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultEpisode
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultSeason
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultSeason
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||||
|
@ -425,6 +428,9 @@ class ResultViewModel2 : ViewModel() {
|
||||||
private val _subscribeStatus: MutableLiveData<Boolean?> = MutableLiveData(null)
|
private val _subscribeStatus: MutableLiveData<Boolean?> = MutableLiveData(null)
|
||||||
val subscribeStatus: LiveData<Boolean?> = _subscribeStatus
|
val subscribeStatus: LiveData<Boolean?> = _subscribeStatus
|
||||||
|
|
||||||
|
private val _favoriteStatus: MutableLiveData<Boolean?> = MutableLiveData(null)
|
||||||
|
val favoriteStatus: LiveData<Boolean?> = _favoriteStatus
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "RVM2"
|
const val TAG = "RVM2"
|
||||||
//private const val EPISODE_RANGE_SIZE = 20
|
//private const val EPISODE_RANGE_SIZE = 20
|
||||||
|
@ -868,6 +874,40 @@ class ResultViewModel2 : ViewModel() {
|
||||||
return !isSubscribed
|
return !isSubscribed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if added to favorites, false if not. Null if not possible to favorite.
|
||||||
|
**/
|
||||||
|
fun toggleFavoriteStatus(): Boolean? {
|
||||||
|
val isFavorite = _favoriteStatus.value ?: return null
|
||||||
|
val response = currentResponse ?: return null
|
||||||
|
|
||||||
|
val currentId = response.getId()
|
||||||
|
|
||||||
|
if (isFavorite) {
|
||||||
|
removeFavoritesData(currentId)
|
||||||
|
} else {
|
||||||
|
val current = getFavoritesData(currentId)
|
||||||
|
|
||||||
|
setFavoritesData(
|
||||||
|
currentId,
|
||||||
|
DataStoreHelper.FavoritesData(
|
||||||
|
currentId,
|
||||||
|
current?.favoritesTime ?: unixTimeMS,
|
||||||
|
unixTimeMS,
|
||||||
|
response.name,
|
||||||
|
response.url,
|
||||||
|
response.apiName,
|
||||||
|
response.type,
|
||||||
|
response.posterUrl,
|
||||||
|
response.year
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
_favoriteStatus.postValue(!isFavorite)
|
||||||
|
return !isFavorite
|
||||||
|
}
|
||||||
|
|
||||||
private fun startChromecast(
|
private fun startChromecast(
|
||||||
activity: Activity?,
|
activity: Activity?,
|
||||||
result: ResultEpisode,
|
result: ResultEpisode,
|
||||||
|
@ -1750,6 +1790,12 @@ class ResultViewModel2 : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun postFavorites(loadResponse: LoadResponse) {
|
||||||
|
val id = loadResponse.getId()
|
||||||
|
val isFavorite = getFavoritesData(id) != null
|
||||||
|
_favoriteStatus.postValue(isFavorite)
|
||||||
|
}
|
||||||
|
|
||||||
private fun postEpisodeRange(indexer: EpisodeIndexer?, range: EpisodeRange?) {
|
private fun postEpisodeRange(indexer: EpisodeIndexer?, range: EpisodeRange?) {
|
||||||
if (range == null || indexer == null) {
|
if (range == null || indexer == null) {
|
||||||
return
|
return
|
||||||
|
@ -1887,6 +1933,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
currentResponse = loadResponse
|
currentResponse = loadResponse
|
||||||
postPage(loadResponse, apiRepository)
|
postPage(loadResponse, apiRepository)
|
||||||
postSubscription(loadResponse)
|
postSubscription(loadResponse)
|
||||||
|
postFavorites(loadResponse)
|
||||||
if (updateEpisodes)
|
if (updateEpisodes)
|
||||||
postEpisodes(loadResponse, updateFillers)
|
postEpisodes(loadResponse, updateFillers)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.ui.search
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.TypedValue
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -231,9 +232,15 @@ class SearchFragment : Fragment() {
|
||||||
val searchExitIcon =
|
val searchExitIcon =
|
||||||
binding?.mainSearch?.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)
|
binding?.mainSearch?.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)
|
||||||
// val searchMagIcon =
|
// val searchMagIcon =
|
||||||
// main_search.findViewById<ImageView>(androidx.appcompat.R.id.search_mag_icon)
|
// binding?.mainSearch?.findViewById<ImageView>(androidx.appcompat.R.id.search_mag_icon)
|
||||||
//searchMagIcon.scaleX = 0.65f
|
// searchMagIcon.scaleX = 0.65f
|
||||||
//searchMagIcon.scaleY = 0.65f
|
// searchMagIcon.scaleY = 0.65f
|
||||||
|
|
||||||
|
// Set the color for the search exit icon to the correct theme text color
|
||||||
|
val searchExitIconColor = TypedValue()
|
||||||
|
|
||||||
|
activity?.theme?.resolveAttribute(android.R.attr.textColor, searchExitIconColor, true)
|
||||||
|
searchExitIcon?.setColorFilter(searchExitIconColor.data)
|
||||||
|
|
||||||
selectedApis = DataStoreHelper.searchPreferenceProviders.toMutableSet()
|
selectedApis = DataStoreHelper.searchPreferenceProviders.toMutableSet()
|
||||||
|
|
||||||
|
|
|
@ -187,13 +187,13 @@ class SettingsFragment : Fragment() {
|
||||||
}
|
}
|
||||||
binding?.apply {
|
binding?.apply {
|
||||||
listOf(
|
listOf(
|
||||||
settingsGeneral to R.id.action_navigation_settings_to_navigation_settings_general,
|
settingsGeneral to R.id.action_navigation_global_to_navigation_settings_general,
|
||||||
settingsPlayer to R.id.action_navigation_settings_to_navigation_settings_player,
|
settingsPlayer to R.id.action_navigation_global_to_navigation_settings_player,
|
||||||
settingsCredits to R.id.action_navigation_settings_to_navigation_settings_account,
|
settingsCredits to R.id.action_navigation_global_to_navigation_settings_account,
|
||||||
settingsUi to R.id.action_navigation_settings_to_navigation_settings_ui,
|
settingsUi to R.id.action_navigation_global_to_navigation_settings_ui,
|
||||||
settingsProviders to R.id.action_navigation_settings_to_navigation_settings_providers,
|
settingsProviders to R.id.action_navigation_global_to_navigation_settings_providers,
|
||||||
settingsUpdates to R.id.action_navigation_settings_to_navigation_settings_updates,
|
settingsUpdates to R.id.action_navigation_global_to_navigation_settings_updates,
|
||||||
settingsExtensions to R.id.action_navigation_settings_to_navigation_settings_extensions,
|
settingsExtensions to R.id.action_navigation_global_to_navigation_settings_extensions,
|
||||||
).forEach { (view, navigationId) ->
|
).forEach { (view, navigationId) ->
|
||||||
view.apply {
|
view.apply {
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
|
|
|
@ -42,6 +42,7 @@ const val VIDEO_WATCH_STATE = "video_watch_state"
|
||||||
const val RESULT_WATCH_STATE = "result_watch_state"
|
const val RESULT_WATCH_STATE = "result_watch_state"
|
||||||
const val RESULT_WATCH_STATE_DATA = "result_watch_state_data"
|
const val RESULT_WATCH_STATE_DATA = "result_watch_state_data"
|
||||||
const val RESULT_SUBSCRIBED_STATE_DATA = "result_subscribed_state_data"
|
const val RESULT_SUBSCRIBED_STATE_DATA = "result_subscribed_state_data"
|
||||||
|
const val RESULT_FAVORITES_STATE_DATA = "result_favorites_state_data"
|
||||||
const val RESULT_RESUME_WATCHING = "result_resume_watching_2" // changed due to id changes
|
const val RESULT_RESUME_WATCHING = "result_resume_watching_2" // changed due to id changes
|
||||||
const val RESULT_RESUME_WATCHING_OLD = "result_resume_watching"
|
const val RESULT_RESUME_WATCHING_OLD = "result_resume_watching"
|
||||||
const val RESULT_RESUME_WATCHING_HAS_MIGRATED = "result_resume_watching_migrated"
|
const val RESULT_RESUME_WATCHING_HAS_MIGRATED = "result_resume_watching_migrated"
|
||||||
|
@ -406,6 +407,33 @@ object DataStoreHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class FavoritesData(
|
||||||
|
@JsonProperty("id") override var id: Int?,
|
||||||
|
@JsonProperty("favoritesTime") val favoritesTime: Long,
|
||||||
|
@JsonProperty("latestUpdatedTime") val latestUpdatedTime: Long,
|
||||||
|
@JsonProperty("name") override val name: String,
|
||||||
|
@JsonProperty("url") override val url: String,
|
||||||
|
@JsonProperty("apiName") override val apiName: String,
|
||||||
|
@JsonProperty("type") override var type: TvType? = null,
|
||||||
|
@JsonProperty("posterUrl") override var posterUrl: String?,
|
||||||
|
@JsonProperty("year") val year: Int?,
|
||||||
|
@JsonProperty("quality") override var quality: SearchQuality? = null,
|
||||||
|
@JsonProperty("posterHeaders") override var posterHeaders: Map<String, String>? = null,
|
||||||
|
) : SearchResponse {
|
||||||
|
fun toLibraryItem(): SyncAPI.LibraryItem? {
|
||||||
|
return SyncAPI.LibraryItem(
|
||||||
|
name,
|
||||||
|
url,
|
||||||
|
id?.toString() ?: return null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
latestUpdatedTime,
|
||||||
|
apiName, type, posterUrl, posterHeaders, quality, this.id
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data class ResumeWatchingResult(
|
data class ResumeWatchingResult(
|
||||||
@JsonProperty("name") override val name: String,
|
@JsonProperty("name") override val name: String,
|
||||||
@JsonProperty("url") override val url: String,
|
@JsonProperty("url") override val url: String,
|
||||||
|
@ -579,6 +607,29 @@ object DataStoreHelper {
|
||||||
return getKey("$currentAccount/$RESULT_SUBSCRIBED_STATE_DATA", id.toString())
|
return getKey("$currentAccount/$RESULT_SUBSCRIBED_STATE_DATA", id.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getAllFavorites(): List<FavoritesData> {
|
||||||
|
return getKeys("$currentAccount/$RESULT_FAVORITES_STATE_DATA")?.mapNotNull {
|
||||||
|
getKey(it)
|
||||||
|
} ?: emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeFavoritesData(id: Int?) {
|
||||||
|
if (id == null) return
|
||||||
|
AccountManager.localListApi.requireLibraryRefresh = true
|
||||||
|
removeKey("$currentAccount/$RESULT_FAVORITES_STATE_DATA", id.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setFavoritesData(id: Int?, data: FavoritesData) {
|
||||||
|
if (id == null) return
|
||||||
|
setKey("$currentAccount/$RESULT_FAVORITES_STATE_DATA", id.toString(), data)
|
||||||
|
AccountManager.localListApi.requireLibraryRefresh = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFavoritesData(id: Int?): FavoritesData? {
|
||||||
|
if (id == null) return null
|
||||||
|
return getKey("$currentAccount/$RESULT_FAVORITES_STATE_DATA", id.toString())
|
||||||
|
}
|
||||||
|
|
||||||
fun setViewPos(id: Int?, pos: Long, dur: Long) {
|
fun setViewPos(id: Int?, pos: Long, dur: Long) {
|
||||||
if (id == null) return
|
if (id == null) return
|
||||||
if (dur < 30_000) return // too short
|
if (dur < 30_000) return // too short
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
package com.lagradost.cloudstream3.utils
|
||||||
|
//Reference: https://stackoverflow.com/a/29055283
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Matrix
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
class PercentageCropImageView : androidx.appcompat.widget.AppCompatImageView {
|
||||||
|
private var mCropYCenterOffsetPct: Float? = null
|
||||||
|
private var mCropXCenterOffsetPct: Float? = null
|
||||||
|
constructor(context: Context?) : super(context!!)
|
||||||
|
constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs)
|
||||||
|
constructor(
|
||||||
|
context: Context?, attrs: AttributeSet?,
|
||||||
|
defStyle: Int
|
||||||
|
) : super(context!!, attrs, defStyle)
|
||||||
|
|
||||||
|
var cropYCenterOffsetPct: Float
|
||||||
|
get() = mCropYCenterOffsetPct!!
|
||||||
|
set(cropYCenterOffsetPct) {
|
||||||
|
require(cropYCenterOffsetPct <= 1.0) { "Value too large: Must be <= 1.0" }
|
||||||
|
mCropYCenterOffsetPct = cropYCenterOffsetPct
|
||||||
|
}
|
||||||
|
var cropXCenterOffsetPct: Float
|
||||||
|
get() = mCropXCenterOffsetPct!!
|
||||||
|
set(cropXCenterOffsetPct) {
|
||||||
|
require(cropXCenterOffsetPct <= 1.0) { "Value too large: Must be <= 1.0" }
|
||||||
|
mCropXCenterOffsetPct = cropXCenterOffsetPct
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun myConfigureBounds() {
|
||||||
|
if (this.scaleType == ScaleType.MATRIX) {
|
||||||
|
|
||||||
|
val d = this.drawable
|
||||||
|
if (d != null) {
|
||||||
|
val dWidth = d.intrinsicWidth
|
||||||
|
val dHeight = d.intrinsicHeight
|
||||||
|
val m = Matrix()
|
||||||
|
val vWidth = width - this.paddingLeft - this.paddingRight
|
||||||
|
val vHeight = height - this.paddingTop - this.paddingBottom
|
||||||
|
val scale: Float
|
||||||
|
var dx = 0f
|
||||||
|
var dy = 0f
|
||||||
|
if (dWidth * vHeight > vWidth * dHeight) {
|
||||||
|
val cropXCenterOffsetPct =
|
||||||
|
if (mCropXCenterOffsetPct != null) mCropXCenterOffsetPct!!.toFloat() else 0.5f
|
||||||
|
scale = vHeight.toFloat() / dHeight.toFloat()
|
||||||
|
dx = (vWidth - dWidth * scale) * cropXCenterOffsetPct
|
||||||
|
} else {
|
||||||
|
val cropYCenterOffsetPct =
|
||||||
|
if (mCropYCenterOffsetPct != null) mCropYCenterOffsetPct!!.toFloat() else 0f
|
||||||
|
scale = vWidth.toFloat() / dWidth.toFloat()
|
||||||
|
dy = (vHeight - dHeight * scale) * cropYCenterOffsetPct
|
||||||
|
}
|
||||||
|
m.setScale(scale, scale)
|
||||||
|
m.postTranslate((dx + 0.5f).toInt().toFloat(), (dy + 0.5f).toInt().toFloat())
|
||||||
|
this.imageMatrix = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// These 3 methods call configureBounds in ImageView.java class, which
|
||||||
|
// adjusts the matrix in a call to center_crop (android's built-in
|
||||||
|
// scaling and centering crop method). We also want to trigger
|
||||||
|
// in the same place, but using our own matrix, which is then set
|
||||||
|
// directly at line 588 of ImageView.java and then copied over
|
||||||
|
// as the draw matrix at line 942 of ImageView.java
|
||||||
|
override fun setFrame(l: Int, t: Int, r: Int, b: Int): Boolean {
|
||||||
|
val changed = super.setFrame(l, t, r, b)
|
||||||
|
myConfigureBounds()
|
||||||
|
return changed
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setImageDrawable(d: Drawable?) {
|
||||||
|
super.setImageDrawable(d)
|
||||||
|
myConfigureBounds()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setImageResource(resId: Int) {
|
||||||
|
super.setImageResource(resId)
|
||||||
|
myConfigureBounds()
|
||||||
|
}
|
||||||
|
// In case you can change the ScaleType in code you have to call redraw()
|
||||||
|
//fullsizeImageView.setScaleType(ScaleType.FIT_CENTER);
|
||||||
|
//fullsizeImageView.redraw();
|
||||||
|
fun redraw() {
|
||||||
|
val d = this.drawable
|
||||||
|
if (d != null) {
|
||||||
|
// Force toggle to recalculate our bounds
|
||||||
|
setImageDrawable(null)
|
||||||
|
setImageDrawable(d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.utils
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
|
import android.text.Spanned
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.AbsListView
|
import android.widget.AbsListView
|
||||||
|
@ -19,6 +20,7 @@ import androidx.core.view.marginRight
|
||||||
import androidx.core.view.marginTop
|
import androidx.core.view.marginTop
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
|
import com.lagradost.cloudstream3.databinding.BottomTextDialogBinding
|
||||||
import com.lagradost.cloudstream3.databinding.BottomSelectionDialogBinding
|
import com.lagradost.cloudstream3.databinding.BottomSelectionDialogBinding
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
|
@ -363,4 +365,24 @@ object SingleSelectionHelper {
|
||||||
dismissCallback
|
dismissCallback
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Activity.showBottomDialogText(
|
||||||
|
title: String,
|
||||||
|
text: Spanned,
|
||||||
|
dismissCallback: () -> Unit
|
||||||
|
) {
|
||||||
|
val binding = BottomTextDialogBinding.inflate(layoutInflater)
|
||||||
|
val dialog = BottomSheetDialog(this)
|
||||||
|
|
||||||
|
dialog.setContentView(binding.root)
|
||||||
|
|
||||||
|
binding.dialogTitle.text = title
|
||||||
|
binding.dialogText.text = text
|
||||||
|
|
||||||
|
dialog.setOnDismissListener {
|
||||||
|
dismissCallback.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,9 +178,10 @@ object UIHelper {
|
||||||
fun Activity?.navigate(@IdRes navigation: Int, arguments: Bundle? = null) {
|
fun Activity?.navigate(@IdRes navigation: Int, arguments: Bundle? = null) {
|
||||||
try {
|
try {
|
||||||
if (this is FragmentActivity) {
|
if (this is FragmentActivity) {
|
||||||
(supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as? NavHostFragment?)?.navController?.navigate(
|
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as? NavHostFragment?
|
||||||
navigation, arguments
|
navHostFragment?.navController?.let {
|
||||||
)
|
it.navigate(navigation, arguments)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
logError(t)
|
logError(t)
|
||||||
|
|
33
app/src/main/res/layout/bottom_text_dialog.xml
Normal file
33
app/src/main/res/layout/bottom_text_dialog.xml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/dialog_title"
|
||||||
|
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_rowWeight="1"
|
||||||
|
tools:text="Test"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/dialog_text"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||||
|
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:requiresFadingEdge="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_rowWeight="1" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -9,7 +9,7 @@
|
||||||
android:layout_margin="5dp"
|
android:layout_margin="5dp"
|
||||||
android:foreground="@drawable/outline_drawable"
|
android:foreground="@drawable/outline_drawable"
|
||||||
app:cardBackgroundColor="@color/transparent"
|
app:cardBackgroundColor="@color/transparent"
|
||||||
|
android:focusable="true"
|
||||||
app:cardCornerRadius="@dimen/rounded_image_radius"
|
app:cardCornerRadius="@dimen/rounded_image_radius"
|
||||||
app:cardElevation="0dp">
|
app:cardElevation="0dp">
|
||||||
|
|
||||||
|
|
|
@ -232,7 +232,9 @@
|
||||||
android:layout_marginStart="@dimen/navbar_width"
|
android:layout_marginStart="@dimen/navbar_width"
|
||||||
android:layout_marginEnd="0dp"
|
android:layout_marginEnd="0dp"
|
||||||
android:padding="12dp"
|
android:padding="12dp"
|
||||||
android:text="@string/continue_watching" />
|
android:text="@string/continue_watching"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
app:drawableTint="?attr/white" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/home_watch_child_recyclerview"
|
android:id="@+id/home_watch_child_recyclerview"
|
||||||
|
@ -258,7 +260,15 @@
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/home_bookmark_parent_item_title"
|
||||||
|
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?android:attr/selectableItemBackground">
|
||||||
|
|
||||||
<HorizontalScrollView
|
<HorizontalScrollView
|
||||||
|
android:id="@+id/horizontal_scroll_chips"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fadingEdge="horizontal"
|
android:fadingEdge="horizontal"
|
||||||
|
@ -344,6 +354,18 @@
|
||||||
</com.google.android.material.chip.ChipGroup>
|
</com.google.android.material.chip.ChipGroup>
|
||||||
</HorizontalScrollView>
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/home_bookmark_parent_item_more_info"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:contentDescription="@string/home_more_info"
|
||||||
|
android:src="@drawable/ic_baseline_arrow_forward_24"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:drawableTint="?attr/white" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/home_bookmarked_child_recyclerview"
|
android:id="@+id/home_bookmarked_child_recyclerview"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -140,6 +140,7 @@
|
||||||
android:layout_gravity="end"
|
android:layout_gravity="end"
|
||||||
android:background="@drawable/player_button_tv_attr_no_bg"
|
android:background="@drawable/player_button_tv_attr_no_bg"
|
||||||
android:contentDescription="@string/account"
|
android:contentDescription="@string/account"
|
||||||
|
android:focusable="true"
|
||||||
android:nextFocusLeft="@id/home_preview_search_button"
|
android:nextFocusLeft="@id/home_preview_search_button"
|
||||||
android:nextFocusRight="@id/home_switch_account"
|
android:nextFocusRight="@id/home_switch_account"
|
||||||
android:nextFocusDown="@id/home_change_api"
|
android:nextFocusDown="@id/home_change_api"
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginEnd="25dp"
|
||||||
|
|
||||||
android:iconifiedByDefault="false"
|
android:iconifiedByDefault="false"
|
||||||
android:imeOptions="actionSearch"
|
android:imeOptions="actionSearch"
|
||||||
|
@ -81,6 +82,7 @@
|
||||||
app:queryBackground="@color/transparent"
|
app:queryBackground="@color/transparent"
|
||||||
app:queryHint="@string/search_hint"
|
app:queryHint="@string/search_hint"
|
||||||
app:searchIcon="@drawable/search_icon"
|
app:searchIcon="@drawable/search_icon"
|
||||||
|
app:closeIcon="@drawable/ic_baseline_close_24"
|
||||||
tools:ignore="RtlSymmetry">
|
tools:ignore="RtlSymmetry">
|
||||||
|
|
||||||
</androidx.appcompat.widget.SearchView>
|
</androidx.appcompat.widget.SearchView>
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
android:padding="2dp"
|
android:padding="2dp"
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
android:background="?selectableItemBackgroundBorderless"
|
||||||
android:contentDescription="@string/change_providers_img_des"
|
android:contentDescription="@string/change_providers_img_des"
|
||||||
|
android:focusable="true"
|
||||||
android:nextFocusLeft="@id/nav_rail_view"
|
android:nextFocusLeft="@id/nav_rail_view"
|
||||||
android:nextFocusRight="@id/library_sort"
|
android:nextFocusRight="@id/library_sort"
|
||||||
android:tag="@string/tv_no_focus_tag"
|
android:tag="@string/tv_no_focus_tag"
|
||||||
|
@ -52,6 +53,7 @@
|
||||||
android:layout_marginStart="10dp"
|
android:layout_marginStart="10dp"
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
android:background="?selectableItemBackgroundBorderless"
|
||||||
android:contentDescription="@string/change_providers_img_des"
|
android:contentDescription="@string/change_providers_img_des"
|
||||||
|
android:focusable="true"
|
||||||
android:nextFocusLeft="@id/provider_selector"
|
android:nextFocusLeft="@id/provider_selector"
|
||||||
android:nextFocusRight="@id/list_selector"
|
android:nextFocusRight="@id/list_selector"
|
||||||
android:tag="@string/tv_no_focus_tag"
|
android:tag="@string/tv_no_focus_tag"
|
||||||
|
@ -67,6 +69,7 @@
|
||||||
android:layout_marginStart="10dp"
|
android:layout_marginStart="10dp"
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
android:background="?selectableItemBackgroundBorderless"
|
||||||
android:contentDescription="@string/change_providers_img_des"
|
android:contentDescription="@string/change_providers_img_des"
|
||||||
|
android:focusable="true"
|
||||||
android:nextFocusLeft="@id/library_sort"
|
android:nextFocusLeft="@id/library_sort"
|
||||||
android:nextFocusRight="@id/main_search"
|
android:nextFocusRight="@id/main_search"
|
||||||
android:tag="@string/tv_no_focus_tag"
|
android:tag="@string/tv_no_focus_tag"
|
||||||
|
@ -99,6 +102,7 @@
|
||||||
app:queryBackground="@color/transparent"
|
app:queryBackground="@color/transparent"
|
||||||
app:queryHint="@string/search_hint"
|
app:queryHint="@string/search_hint"
|
||||||
app:searchIcon="@drawable/search_icon"
|
app:searchIcon="@drawable/search_icon"
|
||||||
|
app:closeIcon="@drawable/ic_baseline_close_24"
|
||||||
tools:ignore="RtlSymmetry">
|
tools:ignore="RtlSymmetry">
|
||||||
|
|
||||||
</androidx.appcompat.widget.SearchView>
|
</androidx.appcompat.widget.SearchView>
|
||||||
|
|
|
@ -74,7 +74,7 @@
|
||||||
android:nextFocusUp="@id/result_back"
|
android:nextFocusUp="@id/result_back"
|
||||||
android:nextFocusDown="@id/result_description"
|
android:nextFocusDown="@id/result_description"
|
||||||
android:nextFocusLeft="@id/result_add_sync"
|
android:nextFocusLeft="@id/result_add_sync"
|
||||||
android:nextFocusRight="@id/result_share"
|
android:nextFocusRight="@id/result_favorite"
|
||||||
|
|
||||||
tools:visibility="visible"
|
tools:visibility="visible"
|
||||||
|
|
||||||
|
@ -89,10 +89,27 @@
|
||||||
android:layout_gravity="end|center_vertical"
|
android:layout_gravity="end|center_vertical"
|
||||||
app:tint="?attr/textColor" />
|
app:tint="?attr/textColor" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:nextFocusUp="@id/result_back"
|
||||||
|
android:nextFocusDown="@id/result_description"
|
||||||
|
android:nextFocusLeft="@id/result_subscribe"
|
||||||
|
android:nextFocusRight="@id/result_share"
|
||||||
|
|
||||||
|
android:id="@+id/result_favorite"
|
||||||
|
android:layout_width="25dp"
|
||||||
|
android:layout_height="25dp"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
android:elevation="10dp"
|
||||||
|
|
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
android:src="@drawable/ic_baseline_favorite_border_24"
|
||||||
|
android:layout_gravity="end|center_vertical"
|
||||||
|
app:tint="?attr/textColor" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:nextFocusUp="@id/result_back"
|
android:nextFocusUp="@id/result_back"
|
||||||
android:nextFocusDown="@id/result_description"
|
android:nextFocusDown="@id/result_description"
|
||||||
android:nextFocusLeft="@id/result_subscribe"
|
android:nextFocusLeft="@id/result_favorite"
|
||||||
android:nextFocusRight="@id/result_open_in_browser"
|
android:nextFocusRight="@id/result_open_in_browser"
|
||||||
|
|
||||||
android:id="@+id/result_share"
|
android:id="@+id/result_share"
|
||||||
|
|
|
@ -124,28 +124,27 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
||||||
android:textColor="?attr/textColor" />
|
android:textColor="?attr/textColor" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/background_poster_holder"
|
android:id="@+id/background_poster_holder"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="150dp"
|
android:layout_height="250dp"
|
||||||
android:visibility="visible">
|
android:visibility="visible">
|
||||||
|
|
||||||
<ImageView
|
<com.lagradost.cloudstream3.utils.PercentageCropImageView
|
||||||
android:id="@+id/background_poster"
|
android:id="@+id/background_poster"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="250dp"
|
android:layout_height="275dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:alpha="0.8"
|
android:alpha="0.8"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="matrix"
|
||||||
tools:src="@drawable/profile_bg_dark_blue" />
|
tools:src="@drawable/profile_bg_dark_blue" >
|
||||||
|
</com.lagradost.cloudstream3.utils.PercentageCropImageView>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="100dp"
|
android:layout_height="120dp"
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:src="@drawable/background_shadow">
|
android:src="@drawable/background_shadow">
|
||||||
|
|
||||||
</ImageView>
|
</ImageView>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
@ -155,7 +154,6 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -166,8 +164,70 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="100dp"
|
android:orientation="vertical"
|
||||||
android:orientation="horizontal">
|
android:layout_marginTop="175dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="The Perfect Run The Perfect Run" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/result_next_airing_holder"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="start"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_episodes_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
android:textSize="17sp"
|
||||||
|
android:textStyle="normal"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:text="8 Episodes" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_next_airing"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textColor="?attr/grayTextColor"
|
||||||
|
android:textSize="17sp"
|
||||||
|
android:textStyle="normal"
|
||||||
|
tools:text="Episode 1022 will be released in" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/result_next_airing_time"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:gravity="start"
|
||||||
|
android:textColor="?attr/textColor"
|
||||||
|
android:textSize="17sp"
|
||||||
|
android:textStyle="normal"
|
||||||
|
tools:text="5d 3h 30m" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginTop="10dp">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="250dp"
|
android:layout_width="250dp"
|
||||||
|
@ -176,67 +236,11 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/result_title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ellipsize="marquee"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:textColor="?attr/textColor"
|
|
||||||
android:textSize="20sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
tools:text="The Perfect Run The Perfect Run" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/result_next_airing_holder"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="start"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/result_episodes_text"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:layout_marginEnd="20dp"
|
|
||||||
android:textColor="?attr/textColor"
|
|
||||||
android:textSize="17sp"
|
|
||||||
android:textStyle="normal"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:text="8 Episodes" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/result_next_airing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textColor="?attr/grayTextColor"
|
|
||||||
android:textSize="17sp"
|
|
||||||
android:textStyle="normal"
|
|
||||||
tools:text="Episode 1022 will be released in" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/result_next_airing_time"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:gravity="start"
|
|
||||||
android:textColor="?attr/textColor"
|
|
||||||
android:textSize="17sp"
|
|
||||||
android:textStyle="normal"
|
|
||||||
tools:text="5d 3h 30m" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/result_movie_parent"
|
android:id="@+id/result_movie_parent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="start"
|
android:layout_gravity="start"
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:animateLayoutChanges="true"
|
android:animateLayoutChanges="true"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
@ -310,19 +314,30 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
||||||
style="@style/ResultButtonTV"
|
style="@style/ResultButtonTV"
|
||||||
android:nextFocusRight="@id/result_description"
|
android:nextFocusRight="@id/result_description"
|
||||||
android:nextFocusUp="@id/result_play_trailer"
|
android:nextFocusUp="@id/result_play_trailer"
|
||||||
android:nextFocusDown="@id/result_episodes_show"
|
android:nextFocusDown="@id/result_favorite_button"
|
||||||
|
|
||||||
android:text="@string/type_none"
|
android:text="@string/type_none"
|
||||||
android:visibility="visible"
|
android:visibility="visible"
|
||||||
app:icon="@drawable/ic_baseline_bookmark_24" />
|
app:icon="@drawable/ic_baseline_bookmark_24" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/result_favorite_button"
|
||||||
|
style="@style/ResultButtonTV"
|
||||||
|
android:nextFocusRight="@id/result_description"
|
||||||
|
android:nextFocusUp="@id/result_bookmark_button"
|
||||||
|
android:nextFocusDown="@id/result_episodes_show"
|
||||||
|
|
||||||
|
android:text="@string/action_add_to_favorites"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:icon="@drawable/ic_baseline_favorite_border_24" />
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/result_episodes_show"
|
android:id="@+id/result_episodes_show"
|
||||||
style="@style/ResultButtonTV"
|
style="@style/ResultButtonTV"
|
||||||
|
|
||||||
android:nextFocusRight="@id/redirect_to_episodes"
|
android:nextFocusRight="@id/redirect_to_episodes"
|
||||||
android:nextFocusUp="@id/result_bookmark_button"
|
android:nextFocusUp="@id/result_favorite_button"
|
||||||
android:nextFocusDown="@id/result_cast_items"
|
android:nextFocusDown="@id/result_cast_items"
|
||||||
|
|
||||||
android:text="@string/episodes"
|
android:text="@string/episodes"
|
||||||
|
@ -404,6 +419,7 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
||||||
android:fadingEdgeLength="30dp"
|
android:fadingEdgeLength="30dp"
|
||||||
android:foreground="@drawable/outline_drawable"
|
android:foreground="@drawable/outline_drawable"
|
||||||
android:maxLines="7"
|
android:maxLines="7"
|
||||||
|
android:focusable="true"
|
||||||
android:nextFocusUp="@id/result_back"
|
android:nextFocusUp="@id/result_back"
|
||||||
android:nextFocusDown="@id/result_bookmark_button"
|
android:nextFocusDown="@id/result_bookmark_button"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
app:queryBackground="@color/transparent"
|
app:queryBackground="@color/transparent"
|
||||||
app:queryHint="@string/search_hint"
|
app:queryHint="@string/search_hint"
|
||||||
app:searchIcon="@drawable/search_icon"
|
app:searchIcon="@drawable/search_icon"
|
||||||
|
app:closeIcon="@drawable/ic_baseline_close_24"
|
||||||
tools:ignore="RtlSymmetry">
|
tools:ignore="RtlSymmetry">
|
||||||
|
|
||||||
<requestFocus />
|
<requestFocus />
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
app:queryBackground="@color/transparent"
|
app:queryBackground="@color/transparent"
|
||||||
app:queryHint="@string/search_hint"
|
app:queryHint="@string/search_hint"
|
||||||
app:searchIcon="@drawable/search_icon"
|
app:searchIcon="@drawable/search_icon"
|
||||||
|
app:closeIcon="@drawable/ic_baseline_close_24"
|
||||||
tools:ignore="RtlSymmetry">
|
tools:ignore="RtlSymmetry">
|
||||||
|
|
||||||
<requestFocus />
|
<requestFocus />
|
||||||
|
|
35
app/src/main/res/layout/homepage_parent_emulator.xml
Normal file
35
app/src/main/res/layout/homepage_parent_emulator.xml
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout 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="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/home_child_more_info"
|
||||||
|
style="@style/WatchHeaderText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/navbar_width"
|
||||||
|
android:layout_marginEnd="0dp"
|
||||||
|
android:padding="12dp"
|
||||||
|
tools:text="@string/continue_watching"
|
||||||
|
app:drawableRightCompat="@drawable/ic_baseline_arrow_forward_24"
|
||||||
|
app:drawableTint="?attr/white"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:contentDescription="@string/home_more_info"/>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/home_child_recyclerview"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:descendantFocusability="afterDescendants"
|
||||||
|
android:nextFocusUp="@id/home_child_more_info"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="@dimen/navbar_width"
|
||||||
|
android:paddingEnd="5dp"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:listitem="@layout/home_result_grid" />
|
||||||
|
</LinearLayout>
|
|
@ -17,14 +17,15 @@
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/quick_search_back"
|
android:id="@+id/quick_search_back"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:foregroundGravity="center"
|
android:foregroundGravity="center"
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
android:src="@drawable/ic_baseline_arrow_back_24"
|
android:src="@drawable/ic_baseline_arrow_back_24"
|
||||||
app:tint="@android:color/white"
|
app:tint="@android:color/white"
|
||||||
android:layout_width="25dp"
|
android:focusable="true"
|
||||||
android:layout_height="wrap_content">
|
android:layout_width="25dp"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<requestFocus />
|
<requestFocus />
|
||||||
</ImageView>
|
</ImageView>
|
||||||
|
@ -48,6 +49,8 @@
|
||||||
app:queryBackground="@color/transparent"
|
app:queryBackground="@color/transparent"
|
||||||
|
|
||||||
app:searchIcon="@drawable/search_icon"
|
app:searchIcon="@drawable/search_icon"
|
||||||
|
app:closeIcon="@drawable/ic_baseline_close_24"
|
||||||
|
|
||||||
android:paddingStart="-10dp"
|
android:paddingStart="-10dp"
|
||||||
android:iconifiedByDefault="false"
|
android:iconifiedByDefault="false"
|
||||||
app:queryHint="@string/search_hint"
|
app:queryHint="@string/search_hint"
|
||||||
|
|
|
@ -331,57 +331,56 @@
|
||||||
app:exitAnim="@anim/exit_anim"
|
app:exitAnim="@anim/exit_anim"
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
app:popExitAnim="@anim/exit_anim"
|
app:popExitAnim="@anim/exit_anim"
|
||||||
tools:layout="@layout/main_settings">
|
tools:layout="@layout/main_settings" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_navigation_settings_to_navigation_settings_ui"
|
android:id="@+id/action_navigation_global_to_navigation_settings_ui"
|
||||||
app:destination="@id/navigation_settings_ui"
|
app:destination="@id/navigation_settings_ui"
|
||||||
app:enterAnim="@anim/enter_anim"
|
app:enterAnim="@anim/enter_anim"
|
||||||
app:exitAnim="@anim/exit_anim"
|
app:exitAnim="@anim/exit_anim"
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_navigation_settings_to_navigation_settings_providers"
|
android:id="@+id/action_navigation_global_to_navigation_settings_providers"
|
||||||
app:destination="@id/navigation_settings_providers"
|
app:destination="@id/navigation_settings_providers"
|
||||||
app:enterAnim="@anim/enter_anim"
|
app:enterAnim="@anim/enter_anim"
|
||||||
app:exitAnim="@anim/exit_anim"
|
app:exitAnim="@anim/exit_anim"
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_navigation_settings_to_navigation_settings_player"
|
android:id="@+id/action_navigation_global_to_navigation_settings_player"
|
||||||
app:destination="@id/navigation_settings_player"
|
app:destination="@id/navigation_settings_player"
|
||||||
app:enterAnim="@anim/enter_anim"
|
app:enterAnim="@anim/enter_anim"
|
||||||
app:exitAnim="@anim/exit_anim"
|
app:exitAnim="@anim/exit_anim"
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_navigation_settings_to_navigation_settings_updates"
|
android:id="@+id/action_navigation_global_to_navigation_settings_updates"
|
||||||
app:destination="@id/navigation_settings_updates"
|
app:destination="@id/navigation_settings_updates"
|
||||||
app:enterAnim="@anim/enter_anim"
|
app:enterAnim="@anim/enter_anim"
|
||||||
app:exitAnim="@anim/exit_anim"
|
app:exitAnim="@anim/exit_anim"
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_navigation_settings_to_navigation_settings_account"
|
android:id="@+id/action_navigation_global_to_navigation_settings_account"
|
||||||
app:destination="@id/navigation_settings_account"
|
app:destination="@id/navigation_settings_account"
|
||||||
app:enterAnim="@anim/enter_anim"
|
app:enterAnim="@anim/enter_anim"
|
||||||
app:exitAnim="@anim/exit_anim"
|
app:exitAnim="@anim/exit_anim"
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_navigation_settings_to_navigation_settings_general"
|
android:id="@+id/action_navigation_global_to_navigation_settings_general"
|
||||||
app:destination="@id/navigation_settings_general"
|
app:destination="@id/navigation_settings_general"
|
||||||
app:enterAnim="@anim/enter_anim"
|
app:enterAnim="@anim/enter_anim"
|
||||||
app:exitAnim="@anim/exit_anim"
|
app:exitAnim="@anim/exit_anim"
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_navigation_settings_to_navigation_settings_extensions"
|
android:id="@+id/action_navigation_global_to_navigation_settings_extensions"
|
||||||
app:destination="@id/navigation_settings_extensions"
|
app:destination="@id/navigation_settings_extensions"
|
||||||
app:enterAnim="@anim/enter_anim"
|
app:enterAnim="@anim/enter_anim"
|
||||||
app:exitAnim="@anim/exit_anim"
|
app:exitAnim="@anim/exit_anim"
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
</fragment>
|
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/navigation_subtitles"
|
android:id="@+id/navigation_subtitles"
|
||||||
|
|
|
@ -690,4 +690,9 @@
|
||||||
|
|
||||||
<string name="tv_no_focus_tag" translatable="false">tv_no_focus_tag</string>
|
<string name="tv_no_focus_tag" translatable="false">tv_no_focus_tag</string>
|
||||||
<string name="already_voted">You have already voted</string>
|
<string name="already_voted">You have already voted</string>
|
||||||
|
<string name="favorites_list_name">Favorites</string>
|
||||||
|
<string name="favorite_added">%s added to favorites</string>
|
||||||
|
<string name="favorite_removed">%s removed from favorites</string>
|
||||||
|
<string name="action_add_to_favorites">Add to favorites</string>
|
||||||
|
<string name="action_remove_from_favorites">Remove from favorites</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue