viewmodel dialogs

This commit is contained in:
LagradOst 2022-08-03 02:04:03 +02:00
parent 64ea5e2f4b
commit a99713fe0c
17 changed files with 655 additions and 192 deletions

View File

@ -1114,6 +1114,7 @@ data class NextAiring(
data class SeasonData(
val season: Int,
val name: String? = null,
val displaySeason : Int? = null, // will use season if null
)
interface EpisodeResponse {

View File

@ -332,6 +332,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
if (str.contains(appString)) {
for (api in OAuth2Apis) {
if (str.contains("/${api.redirectUrl}")) {
val activity = this
ioSafe {
Log.i(TAG, "handleAppIntent $str")
val isSuccessful = api.handleRedirect(str)
@ -342,10 +343,10 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
Log.i(TAG, "failed to authenticate ${api.name}")
}
this.runOnUiThread {
activity.runOnUiThread {
try {
showToast(
this,
activity,
getString(if (isSuccessful) R.string.authenticated_user else R.string.authenticated_user_fail).format(
api.name
)

View File

@ -54,7 +54,7 @@ class GogoanimeProvider : MainAPI() {
secretKeyString: String,
encrypt: Boolean = true
): String {
println("IV: $iv, Key: $secretKeyString, encrypt: $encrypt, Message: $string")
//println("IV: $iv, Key: $secretKeyString, encrypt: $encrypt, Message: $string")
val ivParameterSpec = IvParameterSpec(iv.toByteArray())
val secretKey = SecretKeySpec(secretKeyString.toByteArray(), "AES")
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")

View File

@ -51,6 +51,32 @@ fun <T> LifecycleOwner.observeDirectly(liveData: LiveData<T>, action: (t: T) ->
action(currentValue)
}
inline fun <reified T : Any> some(value: T?): Some<T> {
return if (value == null) {
Some.None
} else {
Some.Success(value)
}
}
sealed class Some<out T> {
data class Success<out T>(val value: T) : Some<T>()
object None : Some<Nothing>()
override fun toString(): String {
return when(this) {
is None -> "None"
is Success -> "Some(${value.toString()})"
}
}
}
sealed class ResourceSome<out T> {
data class Success<out T>(val value: T) : ResourceSome<T>()
object None : ResourceSome<Nothing>()
data class Loading(val data: Any? = null) : ResourceSome<Nothing>()
}
sealed class Resource<out T> {
data class Success<out T>(val value: T) : Resource<T>()
data class Failure(

View File

@ -125,6 +125,7 @@ class GeneratorPlayer : FullScreenPlayer() {
private fun loadExtractorJob(extractorLink: ExtractorLink?) {
currentVerifyLink?.cancel()
extractorLink?.let {
currentVerifyLink = ioSafe {
if (it.extractorData != null) {
@ -488,7 +489,9 @@ class GeneratorPlayer : FullScreenPlayer() {
.setView(R.layout.player_select_source_and_subs)
val sourceDialog = sourceBuilder.create()
selectSourceDialog = sourceDialog
sourceDialog.show()
val providerList = sourceDialog.sort_providers
val subtitleList = sourceDialog.sort_subtitles

View File

@ -1,6 +1,7 @@
package com.lagradost.cloudstream3.ui.result
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Intent
import android.content.Intent.*
import android.content.res.ColorStateList
@ -15,6 +16,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.AbsListView
import android.widget.ArrayAdapter
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isGone
@ -28,15 +30,13 @@ import com.discord.panels.PanelsChildGestureRegionObserver
import com.google.android.gms.cast.framework.CastButtonFactory
import com.google.android.gms.cast.framework.CastContext
import com.google.android.gms.cast.framework.CastState
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.button.MaterialButton
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.getApiFromName
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.mvvm.*
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
@ -54,8 +54,10 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant
import com.lagradost.cloudstream3.utils.UIHelper
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
@ -68,6 +70,7 @@ import kotlinx.android.synthetic.main.fragment_trailer.*
import kotlinx.android.synthetic.main.result_recommendations.*
import kotlinx.android.synthetic.main.result_sync.*
import kotlinx.android.synthetic.main.trailer_custom_layout.*
import kotlinx.coroutines.runBlocking
const val START_ACTION_NORMAL = 0
const val START_ACTION_RESUME_LATEST = 1
@ -206,8 +209,6 @@ class ResultFragment : ResultTrailerPlayer() {
private var updateUIListener: (() -> Unit)? = null
}
private var currentLoadingCount =
0 // THIS IS USED TO PREVENT LATE EVENTS, AFTER DISMISS WAS CLICKED
private lateinit var viewModel: ResultViewModel2 //by activityViewModels()
private lateinit var syncModel: SyncViewModel
@ -418,7 +419,8 @@ class ResultFragment : ResultTrailerPlayer() {
viewModel.reloadEpisodes()
}
var apiName: String = ""
var loadingDialog: Dialog? = null
var popupDialog: Dialog? = null
@SuppressLint("SetTextI18n")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -466,7 +468,7 @@ class ResultFragment : ResultTrailerPlayer() {
// activity?.fixPaddingStatusbar(result_toolbar)
val url = arguments?.getString(URL_BUNDLE)
apiName = arguments?.getString(API_NAME_BUNDLE) ?: return
val apiName = arguments?.getString(API_NAME_BUNDLE) ?: return
startAction = arguments?.getInt(START_ACTION_BUNDLE) ?: START_ACTION_NORMAL
startValue = arguments?.getInt(START_VALUE_BUNDLE)
val resumeEpisode = arguments?.getInt(EPISODE_BUNDLE)
@ -862,16 +864,16 @@ class ResultFragment : ResultTrailerPlayer() {
*/
observe(viewModel.episodes) { episodes ->
when (episodes) {
is Resource.Failure -> {
is ResourceSome.None -> {
result_episode_loading?.isVisible = false
//result_episodes?.isVisible = false
result_episodes?.isVisible = false
}
is Resource.Loading -> {
is ResourceSome.Loading -> {
result_episode_loading?.isVisible = true
// result_episodes?.isVisible = false
result_episodes?.isVisible = false
}
is Resource.Success -> {
//result_episodes?.isVisible = true
is ResourceSome.Success -> {
result_episodes?.isVisible = true
result_episode_loading?.isVisible = false
(result_episodes?.adapter as? EpisodeAdapter?)?.updateList(episodes.value)
}
@ -879,7 +881,7 @@ class ResultFragment : ResultTrailerPlayer() {
}
observe(viewModel.selectedSeason) { text ->
result_season_button?.setText(text)
result_season_button.setText(text)
// If the season button is visible the result season button will be next focus down
if (result_season_button?.isVisible == true)
@ -901,6 +903,70 @@ class ResultFragment : ResultTrailerPlayer() {
}
}
observe(viewModel.selectPopup) { popup ->
println("POPUPSTATUS:$popup")
when (popup) {
is Some.Success -> {
popupDialog?.dismissSafe(activity)
popupDialog = activity?.let { act ->
val pop = popup.value
val options = pop.getOptions(act)
val title = pop.getTitle(act)
act.showBottomDialogInstant(
options, title, {
popupDialog = null
pop.callback(context ?: return@showBottomDialogInstant, null)
}, {
popupDialog = null
pop.callback(context ?: return@showBottomDialogInstant, it)
}
)
}
}
is Some.None -> {
popupDialog?.dismissSafe(activity)
popupDialog = null
}
}
//showBottomDialogInstant
}
observe(viewModel.loadedLinks) { load ->
when (load) {
is Some.Success -> {
if(loadingDialog?.isShowing != true) {
loadingDialog?.dismissSafe(activity)
loadingDialog = null
}
loadingDialog = loadingDialog ?: context?.let { ctx ->
val builder =
BottomSheetDialog(ctx)
builder.setContentView(R.layout.bottom_loading)
builder.setOnDismissListener {
loadingDialog = null
viewModel.cancelLinks()
}
//builder.setOnCancelListener {
// it?.dismiss()
//}
builder.setCanceledOnTouchOutside(true)
builder.show()
builder
}
}
is Some.None -> {
loadingDialog?.dismissSafe(activity)
loadingDialog = null
}
}
}
observe(viewModel.selectedRange) { range ->
result_episode_select.setText(range)
@ -933,7 +999,8 @@ class ResultFragment : ResultTrailerPlayer() {
}
observe(viewModel.rangeSelections) { range ->
result_episode_select.setOnClickListener { view ->
println("RANGE:$range")
result_episode_select?.setOnClickListener { view ->
view?.context?.let { ctx ->
val names = range
.mapNotNull { (text, r) ->
@ -987,6 +1054,33 @@ class ResultFragment : ResultTrailerPlayer() {
setRecommendations(recommendations, null)
}
observe(viewModel.movie) { data ->
when (data) {
is ResourceSome.Success -> {
data.value.let { (text, ep) ->
result_play_movie.setText(text)
result_play_movie?.setOnClickListener {
viewModel.handleAction(
activity,
EpisodeClickEvent(ACTION_CLICK_DEFAULT, ep)
)
}
result_play_movie?.setOnLongClickListener {
viewModel.handleAction(
activity,
EpisodeClickEvent(ACTION_SHOW_OPTIONS, ep)
)
return@setOnLongClickListener true
}
}
}
else -> {
result_play_movie?.isVisible = false
}
}
}
observe(viewModel.page) { data ->
when (data) {
is Resource.Success -> {
@ -1006,9 +1100,32 @@ class ResultFragment : ResultTrailerPlayer() {
result_cast_text.setText(d.actorsText)
result_next_airing.setText(d.nextAiringEpisode)
result_next_airing_time.setText(d.nextAiringDate)
result_poster.setImage(d.posterImage)
result_play_movie.setText(d.playMovieText)
if (d.posterImage != null && context?.isTrueTvSettings() == false)
result_poster_holder?.setOnClickListener {
try {
context?.let { ctx ->
runBlocking {
val sourceBuilder = AlertDialog.Builder(ctx)
sourceBuilder.setView(R.layout.result_poster)
val sourceDialog = sourceBuilder.create()
sourceDialog.show()
sourceDialog.findViewById<ImageView?>(R.id.imgPoster)
?.apply {
setImage(d.posterImage)
setOnClickListener {
sourceDialog.dismissSafe()
}
}
}
}
} catch (e: Exception) {
logError(e)
}
}
result_cast_items?.isVisible = d.actors != null
@ -1016,6 +1133,7 @@ class ResultFragment : ResultTrailerPlayer() {
updateList(d.actors ?: emptyList())
}
result_open_in_browser?.isGone = d.url.isBlank()
result_open_in_browser?.setOnClickListener {
val i = Intent(ACTION_VIEW)
i.data = Uri.parse(d.url)
@ -1238,15 +1356,14 @@ class ResultFragment : ResultTrailerPlayer() {
Kitsu.isEnabled =
settingsManager.getBoolean(ctx.getString(R.string.show_kitsu_posters_key), true)
val tempUrl = url
if (tempUrl != null) {
if (url != null) {
result_reload_connectionerror.setOnClickListener {
viewModel.load(tempUrl, apiName, showFillers, DubStatus.Dubbed, 0, 0) //TODO FIX
viewModel.load(url, apiName, showFillers, DubStatus.Dubbed, 0, 0) //TODO FIX
}
result_reload_connection_open_in_browser?.setOnClickListener {
val i = Intent(ACTION_VIEW)
i.data = Uri.parse(tempUrl)
i.data = Uri.parse(url)
try {
startActivity(i)
} catch (e: Exception) {
@ -1256,7 +1373,7 @@ class ResultFragment : ResultTrailerPlayer() {
result_open_in_browser?.setOnClickListener {
val i = Intent(ACTION_VIEW)
i.data = Uri.parse(tempUrl)
i.data = Uri.parse(url)
try {
startActivity(i)
} catch (e: Exception) {
@ -1267,7 +1384,7 @@ class ResultFragment : ResultTrailerPlayer() {
// bloats the navigation on tv
if (context?.isTrueTvSettings() == false) {
result_meta_site?.setOnClickListener {
it.context?.openBrowser(tempUrl)
it.context?.openBrowser(url)
}
result_meta_site?.isFocusable = true
} else {
@ -1276,7 +1393,7 @@ class ResultFragment : ResultTrailerPlayer() {
if (restart || !viewModel.hasLoaded()) {
//viewModel.clear()
viewModel.load(tempUrl, apiName, showFillers, DubStatus.Dubbed, 0, 0) //TODO FIX
viewModel.load(url, apiName, showFillers, DubStatus.Dubbed, 0, 0) //TODO FIX
}
}
}

View File

@ -36,17 +36,16 @@ import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator
import com.lagradost.cloudstream3.ui.player.SubtitleData
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
import com.lagradost.cloudstream3.utils.AppUtils.isConnectedToChromecast
import com.lagradost.cloudstream3.utils.CastHelper.startCast
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.DataStore.setKey
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultWatchState
import com.lagradost.cloudstream3.utils.UIHelper.checkWrite
import com.lagradost.cloudstream3.utils.UIHelper.navigate
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.*
import java.io.File
import java.util.concurrent.TimeUnit
@ -86,7 +85,6 @@ data class ResultData(
val yearText: UiText?,
val nextAiringDate: UiText?,
val nextAiringEpisode: UiText?,
val playMovieText: UiText?,
val plotHeaderText: UiText,
)
@ -118,7 +116,7 @@ fun LoadResponse.toResultData(repo: APIRepository): ResultData {
val hours: Long = TimeUnit.SECONDS.toHours(seconds) - days * 24
val minute =
TimeUnit.SECONDS.toMinutes(seconds) - TimeUnit.SECONDS.toHours(seconds) * 60
nextAiringEpisode = when {
nextAiringDate = when {
days > 0 -> {
txt(
R.string.next_episode_time_day_format,
@ -138,11 +136,11 @@ fun LoadResponse.toResultData(repo: APIRepository): ResultData {
)
else -> null
}?.also {
nextAiringDate = txt(R.string.next_episode_format, airing.episode)
nextAiringEpisode = txt(R.string.next_episode_format, airing.episode)
}
}
}
val dur = duration
return ResultData(
syncData = syncData,
plotHeaderText = txt(
@ -151,14 +149,6 @@ fun LoadResponse.toResultData(repo: APIRepository): ResultData {
else -> R.string.result_plot
}
),
playMovieText = txt(
when (this.type) {
TvType.Live -> R.string.play_livestream_button
TvType.Torrent -> R.string.play_torrent_button
TvType.Movie, TvType.AnimeMovie -> R.string.play_movie_button
else -> null
}
),
nextAiringDate = nextAiringDate,
nextAiringEpisode = nextAiringEpisode,
posterImage = img(
@ -192,7 +182,7 @@ fun LoadResponse.toResultData(repo: APIRepository): ResultData {
TvType.Live -> R.string.live_singular
}
),
yearText = txt(year),
yearText = txt(year?.toString()),
apiName = txt(apiName),
ratingText = rating?.div(1000f)?.let { txt(R.string.rating_format, it) },
vpnText = txt(
@ -204,7 +194,10 @@ fun LoadResponse.toResultData(repo: APIRepository): ResultData {
),
metaText =
if (repo.providerType == ProviderType.MetaProvider) txt(R.string.provider_info_meta) else null,
durationText = txt(R.string.duration_format, duration),
durationText = if (dur == null || dur <= 0) null else txt(
R.string.duration_format,
dur
),
onGoingText = if (this is EpisodeResponse) {
txt(
when (showStatus) {
@ -245,21 +238,43 @@ sealed class SelectPopup {
val map: Int?,
val callback: (Int?) -> Unit
) : SelectPopup()
}
fun SelectPopup.transformResult(context: Context, input: Int?): Int? {
if (input == null) return null
return when (this) {
is SelectArray -> context.resources.getIntArray(map ?: return input).getOrNull(input)
?: input
is SelectText -> input
}
fun SelectPopup.callback(context: Context, input: Int?) {
val ret = transformResult(context, input)
return when (this) {
is SelectPopup.SelectArray -> callback(ret)
is SelectPopup.SelectText -> callback(ret)
}
}
fun SelectPopup.getOptions(context: Context): List<String> {
return when (this) {
is SelectArray -> context.resources.getStringArray(options).toList()
is SelectText -> options.map { it.asString(context) }
fun SelectPopup.transformResult(context: Context, input: Int?): Int? {
if (input == null) return null
return when (this) {
is SelectPopup.SelectArray -> context.resources.getIntArray(map ?: return input)
.getOrNull(input)
?: input
is SelectPopup.SelectText -> input
}
}
fun SelectPopup.getTitle(context: Context): String {
return when (this) {
is SelectPopup.SelectArray -> text.asString(context)
is SelectPopup.SelectText -> text.asString(context)
}
}
fun SelectPopup.getOptions(context: Context): List<String> {
return when (this) {
is SelectPopup.SelectArray -> {
val cmap = this.map?.let { context.resources.getIntArray(it) }
context.resources.getStringArray(options).toList().filterIndexed { index, s ->
true
}
}
is SelectPopup.SelectText -> options.map { it.asString(context) }
}
}
@ -274,6 +289,8 @@ class ResultViewModel2 : ViewModel() {
/** map<dub, map<season, List<episode>>> */
private var currentEpisodes: Map<EpisodeIndexer, List<ResultEpisode>> = mapOf()
private var currentRanges: Map<EpisodeIndexer, List<EpisodeRange>> = mapOf()
private var currentSeasons: Set<Int> = setOf()
private var currentDubStatus: Set<DubStatus> = setOf()
private var currentMeta: SyncAPI.SyncResult? = null
private var currentSync: Map<String, String>? = null
private var currentIndex: EpisodeIndexer? = null
@ -294,13 +311,17 @@ class ResultViewModel2 : ViewModel() {
MutableLiveData(Resource.Loading())
val page: LiveData<Resource<ResultData>> = _page
private val _episodes: MutableLiveData<Resource<List<ResultEpisode>>> =
MutableLiveData(Resource.Loading())
val episodes: LiveData<Resource<List<ResultEpisode>>> = _episodes
private val _episodes: MutableLiveData<ResourceSome<List<ResultEpisode>>> =
MutableLiveData(ResourceSome.Loading())
val episodes: LiveData<ResourceSome<List<ResultEpisode>>> = _episodes
private val _episodesCountText: MutableLiveData<UiText?> =
MutableLiveData(null)
val episodesCountText: LiveData<UiText?> = _episodesCountText
private val _movie: MutableLiveData<ResourceSome<Pair<UiText, ResultEpisode>>> =
MutableLiveData(ResourceSome.None)
val movie: LiveData<ResourceSome<Pair<UiText, ResultEpisode>>> = _movie
private val _episodesCountText: MutableLiveData<Some<UiText>> =
MutableLiveData(Some.None)
val episodesCountText: LiveData<Some<UiText>> = _episodesCountText
private val _trailers: MutableLiveData<List<TrailerData>> = MutableLiveData(mutableListOf())
val trailers: LiveData<List<TrailerData>> = _trailers
@ -318,24 +339,23 @@ class ResultViewModel2 : ViewModel() {
MutableLiveData(emptyList())
val seasonSelections: LiveData<List<Pair<UiText?, Int>>> = _seasonSelections
private val _recommendations: MutableLiveData<List<SearchResponse>> =
MutableLiveData(emptyList())
val recommendations: LiveData<List<SearchResponse>> = _recommendations
private val _selectedRange: MutableLiveData<UiText?> =
MutableLiveData(null)
val selectedRange: LiveData<UiText?> = _selectedRange
private val _selectedRange: MutableLiveData<Some<UiText>> =
MutableLiveData(Some.None)
val selectedRange: LiveData<Some<UiText>> = _selectedRange
private val _selectedSeason: MutableLiveData<UiText?> =
MutableLiveData(null)
val selectedSeason: LiveData<UiText?> = _selectedSeason
private val _selectedSeason: MutableLiveData<Some<UiText>> =
MutableLiveData(Some.None)
val selectedSeason: LiveData<Some<UiText>> = _selectedSeason
private val _selectedDubStatus: MutableLiveData<UiText?> = MutableLiveData(null)
val selectedDubStatus: LiveData<UiText?> = _selectedDubStatus
private val _selectedDubStatus: MutableLiveData<Some<UiText>> = MutableLiveData(Some.None)
val selectedDubStatus: LiveData<Some<UiText>> = _selectedDubStatus
private val _loadedLinks: MutableLiveData<LinkProgress?> = MutableLiveData(null)
val loadedLinks: LiveData<LinkProgress?> = _loadedLinks
private val _loadedLinks: MutableLiveData<Some<LinkProgress>> = MutableLiveData(Some.None)
val loadedLinks: LiveData<Some<LinkProgress>> = _loadedLinks
companion object {
const val TAG = "RVM2"
@ -680,8 +700,8 @@ class ResultViewModel2 : ViewModel() {
private val _watchStatus: MutableLiveData<WatchType> = MutableLiveData(WatchType.NONE)
val watchStatus: LiveData<WatchType> get() = _watchStatus
private val _selectPopup: MutableLiveData<SelectPopup?> = MutableLiveData(null)
val selectPopup: LiveData<SelectPopup?> get() = _selectPopup
private val _selectPopup: MutableLiveData<Some<SelectPopup>> = MutableLiveData(Some.None)
val selectPopup: LiveData<Some<SelectPopup>> get() = _selectPopup
fun updateWatchStatus(status: WatchType) {
val currentId = currentId ?: return
@ -707,14 +727,15 @@ class ResultViewModel2 : ViewModel() {
)
}
private suspend fun startChromecast(
private fun startChromecast(
activity: Activity?,
result: ResultEpisode,
isVisible: Boolean = true
) {
if (activity == null) return
val data = loadLinks(result, isVisible = isVisible, isCasting = true)
startChromecast(activity, result, data.links, data.subs, 0)
loadLinks(result, isVisible = isVisible, isCasting = true) { data ->
startChromecast(activity, result, data.links, data.subs, 0)
}
}
private fun startChromecast(
@ -742,51 +763,100 @@ class ResultViewModel2 : ViewModel() {
)
}
private val popupCallback: ((Int) -> Unit)? = null
fun cancelLinks() {
println("called::cancelLinks")
currentLoadLinkJob?.cancel()
_loadedLinks.postValue(null)
currentLoadLinkJob = null
_loadedLinks.postValue(Some.None)
}
private fun postPopup(text: UiText, options: List<UiText>, callback: suspend (Int?) -> Unit) {
_selectPopup.postValue(
some(SelectPopup.SelectText(
text,
options
) { value ->
viewModelScope.launch {
_selectPopup.postValue(Some.None)
callback.invoke(value)
}
})
)
}
private fun postPopup(
text: UiText,
options: Int,
values: Int,
callback: suspend (Int?) -> Unit
) {
_selectPopup.postValue(
some(SelectPopup.SelectArray(
text,
options,
values
) { value ->
viewModelScope.launch {
_selectPopup.value = Some.None
callback.invoke(value)
}
})
)
}
fun loadLinks(
result: ResultEpisode,
isVisible: Boolean,
isCasting: Boolean,
clearCache: Boolean = false,
work: suspend (CoroutineScope.(LinkLoadingResult) -> Unit)
) {
currentLoadLinkJob?.cancel()
currentLoadLinkJob = ioSafe {
val links = loadLinks(
result,
isVisible = isVisible,
isCasting = isCasting,
clearCache = clearCache
)
if (!this.isActive) return@ioSafe
work(links)
}
}
private var currentLoadLinkJob: Job? = null
private suspend fun acquireSingleLink(
private fun acquireSingleLink(
result: ResultEpisode,
isCasting: Boolean,
text: UiText,
callback: (Pair<LinkLoadingResult, Int>) -> Unit,
) {
currentLoadLinkJob = viewModelScope.launch {
val links = loadLinks(result, isVisible = true, isCasting = isCasting)
_selectPopup.postValue(
SelectPopup.SelectText(
text,
links.links.map { txt("${it.name} ${Qualities.getStringByInt(it.quality)}") }) {
callback.invoke(links to (it ?: return@SelectText))
})
loadLinks(result, isVisible = true, isCasting = isCasting) { links ->
postPopup(
text,
links.links.map { txt("${it.name} ${Qualities.getStringByInt(it.quality)}") }) {
callback.invoke(links to (it ?: return@postPopup))
}
}
}
private suspend fun acquireSingleSubtitle(
private fun acquireSingleSubtitle(
result: ResultEpisode,
isCasting: Boolean,
text: UiText,
callback: (Pair<LinkLoadingResult, Int>) -> Unit,
) {
currentLoadLinkJob = viewModelScope.launch {
val links = loadLinks(result, isVisible = true, isCasting = isCasting)
_selectPopup.postValue(
SelectPopup.SelectText(
text,
links.subs.map { txt(it.name) }) {
callback.invoke(links to (it ?: return@SelectText))
})
loadLinks(result, isVisible = true, isCasting = isCasting) { links ->
postPopup(
text,
links.subs.map { txt(it.name) })
{
callback.invoke(links to (it ?: return@postPopup))
}
}
}
suspend fun loadLinks(
suspend fun CoroutineScope.loadLinks(
result: ResultEpisode,
isVisible: Boolean,
isCasting: Boolean,
@ -797,11 +867,12 @@ class ResultViewModel2 : ViewModel() {
val links: MutableSet<ExtractorLink> = mutableSetOf()
val subs: MutableSet<SubtitleData> = mutableSetOf()
fun updatePage() {
if (isVisible) {
_loadedLinks.postValue(LinkProgress(links.size, subs.size))
if (isVisible && isActive) {
_loadedLinks.postValue(some(LinkProgress(links.size, subs.size)))
}
}
try {
updatePage()
tempGenerator.generateLinks(clearCache, isCasting, { (link, _) ->
if (link != null) {
links += link
@ -814,7 +885,7 @@ class ResultViewModel2 : ViewModel() {
} catch (e: Exception) {
logError(e)
} finally {
_loadedLinks.postValue(null)
_loadedLinks.postValue(Some.None)
}
return LinkLoadingResult(sortUrls(links), sortSubs(subs))
@ -884,20 +955,22 @@ class ResultViewModel2 : ViewModel() {
private suspend fun handleEpisodeClickEvent(activity: Activity?, click: EpisodeClickEvent) {
when (click.action) {
ACTION_SHOW_OPTIONS -> {
_selectPopup.postValue(
SelectPopup.SelectArray(
txt(""), // TODO FIX
R.array.episode_long_click_options,
R.array.episode_long_click_options_values
) { result ->
if (result == null) return@SelectArray
viewModelScope.launch {
handleEpisodeClickEvent(
activity,
click.copy(action = result)
)
}
})
postPopup(
txt(
activity?.getNameFull(
click.data.name,
click.data.episode,
click.data.season
) ?: ""
), // TODO FIX
R.array.episode_long_click_options,
R.array.episode_long_click_options_values
) { result ->
handleEpisodeClickEvent(
activity,
click.copy(action = result ?: return@postPopup)
)
}
}
ACTION_CLICK_DEFAULT -> {
activity?.let { ctx ->
@ -986,7 +1059,14 @@ class ResultViewModel2 : ViewModel() {
}
}
ACTION_RELOAD_EPISODE -> {
loadLinks(click.data, isVisible = false, isCasting = false, clearCache = true)
ioSafe {
loadLinks(
click.data,
isVisible = false,
isCasting = false,
clearCache = true
)
}
}
ACTION_CHROME_CAST_MIRROR -> {
acquireSingleLink(
@ -1030,8 +1110,12 @@ class ResultViewModel2 : ViewModel() {
startChromecast(activity, click.data)
}
ACTION_PLAY_EPISODE_IN_VLC_PLAYER -> {
currentLoadLinkJob = viewModelScope.launch {
playWithVlc(activity, loadLinks(click.data, true, true), click.data.id)
loadLinks(click.data, isVisible = true, isCasting = true) { links ->
playWithVlc(
activity,
links,
click.data.id
)
}
}
ACTION_PLAY_EPISODE_IN_PLAYER -> {
@ -1176,6 +1260,13 @@ class ResultViewModel2 : ViewModel() {
postEpisodeRange(currentIndex?.copy(season = season), currentRange)
}
private fun getMovie(): ResultEpisode? {
return currentEpisodes.entries.firstOrNull()?.value?.firstOrNull()?.let { ep ->
val posDur = DataStoreHelper.getViewPos(ep.id)
ep.copy(position = posDur?.position ?: 0, duration = posDur?.duration ?: 0)
}
}
private fun getEpisodes(indexer: EpisodeIndexer, range: EpisodeRange): List<ResultEpisode> {
val startIndex = range.startIndex
val length = range.length
@ -1192,15 +1283,50 @@ class ResultViewModel2 : ViewModel() {
?: emptyList()
}
private fun postMovie() {
val response = currentResponse
_episodes.postValue(ResourceSome.None)
if (response == null) {
_movie.postValue(ResourceSome.None)
return
}
val text = txt(
when (response.type) {
TvType.Torrent -> R.string.play_torrent_button
else -> {
if (response.type.isLiveStream())
R.string.play_livestream_button
else if (response.type.isMovieType()) // this wont break compatibility as you only need to override isMovieType
R.string.play_movie_button
else null
}
}
)
val data = getMovie()
_episodes.postValue(ResourceSome.None)
if (text == null || data == null) {
_movie.postValue(ResourceSome.None)
} else {
_movie.postValue(ResourceSome.Success(text to data))
}
}
fun reloadEpisodes() {
_episodes.postValue(
Resource.Success(
getEpisodes(
currentIndex ?: return,
currentRange ?: return
if (currentResponse?.isMovie() == true) {
postMovie()
} else {
_episodes.postValue(
ResourceSome.Success(
getEpisodes(
currentIndex ?: return,
currentRange ?: return
)
)
)
)
_movie.postValue(ResourceSome.None)
}
}
private fun postEpisodeRange(indexer: EpisodeIndexer?, range: EpisodeRange?) {
@ -1208,45 +1334,79 @@ class ResultViewModel2 : ViewModel() {
return
}
val size = currentEpisodes[indexer]?.size
_episodesCountText.postValue(
txt(
R.string.episode_format,
txt(if (size == 1) R.string.episode else R.string.episodes),
size
)
)
val episodes = currentEpisodes[indexer]
val ranges = currentRanges[indexer]
val size = episodes?.size
val isMovie = currentResponse?.isMovie() == true
currentIndex = indexer
currentRange = range
_rangeSelections.postValue(ranges?.map { r ->
val text = txt(R.string.episodes_range, r.startEpisode, r.endEpisode)
text to r
} ?: emptyList())
_episodesCountText.postValue(
some(
if (isMovie) null else
txt(
R.string.episode_format,
size,
txt(if (size == 1) R.string.episode else R.string.episodes),
)
)
)
_selectedSeason.postValue(
when (indexer.season) {
0 -> txt(R.string.no_season)
else -> txt(R.string.season_format, R.string.season, indexer.season) //TODO FIX
}
some(
if (isMovie || currentSeasons.size <= 1) null else
when (indexer.season) {
0 -> txt(R.string.no_season)
else -> txt(
R.string.season_format,
txt(R.string.season),
indexer.season
) //TODO FIX DISPLAYNAME
}
)
)
_selectedRange.postValue(
if ((currentRanges[indexer]?.size ?: 0) > 1) {
txt(R.string.episodes_range, range.startEpisode, range.endEpisode)
} else {
null
}
some(
if (isMovie) null else if ((currentRanges[indexer]?.size ?: 0) > 1) {
txt(R.string.episodes_range, range.startEpisode, range.endEpisode)
} else {
null
}
)
)
_selectedDubStatus.postValue(
some(
if (isMovie || currentDubStatus.size <= 1) null else
txt(indexer.dubStatus)
)
)
_selectedDubStatus.postValue(txt(indexer.dubStatus))
//TODO SET KEYS
preferStartEpisode = range.startEpisode
preferStartSeason = indexer.season
preferDubStatus = indexer.dubStatus
generator = currentEpisodes[indexer]?.let { list ->
RepoLinkGenerator(list)
generator = if (isMovie) {
getMovie()?.let { RepoLinkGenerator(listOf(it)) }
} else {
episodes?.let { list ->
RepoLinkGenerator(list)
}
}
val ret = getEpisodes(indexer, range)
_episodes.postValue(Resource.Success(ret))
if (isMovie) {
postMovie()
} else {
val ret = getEpisodes(indexer, range)
_episodes.postValue(ResourceSome.Success(ret))
}
}
private suspend fun postSuccessful(
@ -1262,11 +1422,13 @@ class ResultViewModel2 : ViewModel() {
}
private suspend fun postEpisodes(loadResponse: LoadResponse, updateFillers: Boolean) {
_episodes.postValue(Resource.Loading())
_episodes.postValue(ResourceSome.Loading())
val mainId = loadResponse.getId()
currentId = mainId
_watchStatus.postValue(getResultWatchState(mainId))
if (updateFillers && loadResponse is AnimeLoadResponse) {
updateFillers(loadResponse.name)
}
@ -1425,10 +1587,30 @@ class ResultViewModel2 : ViewModel() {
}
}
val seasonsSelection = mutableSetOf<Int>()
val dubSelection = mutableSetOf<DubStatus>()
allEpisodes.keys.forEach { key ->
seasonsSelection += key.season
dubSelection += key.dubStatus
}
currentDubStatus = dubSelection
currentSeasons = seasonsSelection
_dubSubSelections.postValue(dubSelection.map { txt(it) to it })
if (loadResponse is EpisodeResponse) {
_seasonSelections.postValue(seasonsSelection.map { seasonNumber ->
val name =
loadResponse.seasonNames?.firstOrNull { it.season == seasonNumber }?.name?.let { seasonData ->
txt(seasonData)
} ?: txt(R.string.season_format, txt(R.string.season), seasonNumber)
name to seasonNumber
})
}
currentEpisodes = allEpisodes
val ranges = getRanges(allEpisodes)
currentRanges = ranges
// this takes the indexer most preferable by the user given the current sorting
val min = ranges.keys.minByOrNull { index ->
kotlin.math.abs(
@ -1464,7 +1646,7 @@ class ResultViewModel2 : ViewModel() {
) =
viewModelScope.launch {
_page.postValue(Resource.Loading(url))
_episodes.postValue(Resource.Loading(url))
_episodes.postValue(ResourceSome.Loading())
preferDubStatus = dubStatus
currentShowFillers = showFillers

View File

@ -8,6 +8,7 @@ import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.core.view.isGone
import androidx.core.view.isVisible
import com.lagradost.cloudstream3.mvvm.Some
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.AppUtils.html
import com.lagradost.cloudstream3.utils.UIHelper.setImage
@ -152,3 +153,11 @@ fun TextView?.setTextHtml(text: UiText?) {
this.text = str.html()
}
}
fun TextView?.setTextHtml(text: Some<UiText>) {
setTextHtml(if(text is Some.Success) text.value else null)
}
fun TextView?.setText(text: Some<UiText>) {
setText(if(text is Some.Success) text.value else null)
}

View File

@ -179,21 +179,21 @@ object AppUtils {
@WorkerThread
fun Context.addProgramsToContinueWatching(data: List<DataStoreHelper.ResumeWatchingResult>) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
val context = this
ioSafe {
data.forEach { episodeInfo ->
try {
val (program, id) = getWatchNextProgramByVideoId(episodeInfo.url, this)
val nextProgram = buildWatchNextProgramUri(this, episodeInfo)
val (program, id) = getWatchNextProgramByVideoId(episodeInfo.url, context)
val nextProgram = buildWatchNextProgramUri(context, episodeInfo)
// If the program is already in the Watch Next row, update it
if (program != null && id != null) {
PreviewChannelHelper(this).updateWatchNextProgram(
PreviewChannelHelper(context).updateWatchNextProgram(
nextProgram,
id,
)
} else {
PreviewChannelHelper(this)
PreviewChannelHelper(context)
.publishWatchNextProgram(nextProgram)
}
} catch (e: Exception) {

View File

@ -12,7 +12,7 @@ object Coroutines {
}
}
fun ioSafe(work: suspend (() -> Unit)): Job {
fun ioSafe(work: suspend (CoroutineScope.() -> Unit)): Job {
return CoroutineScope(Dispatchers.IO).launch {
try {
work()
@ -22,7 +22,7 @@ object Coroutines {
}
}
suspend fun <T> ioWork(work: suspend (() -> T)): T {
suspend fun <T> ioWork(work: suspend (CoroutineScope.() -> T)): T {
return withContext(Dispatchers.IO) {
work()
}

View File

@ -12,6 +12,9 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSet
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
import com.lagradost.cloudstream3.utils.UIHelper.setImage
import kotlinx.android.synthetic.main.add_account_input.*
import kotlinx.android.synthetic.main.add_account_input.text1
import kotlinx.android.synthetic.main.bottom_selection_dialog_direct.*
object SingleSelectionHelper {
fun Activity?.showOptionSelectStringRes(
@ -21,7 +24,7 @@ object SingleSelectionHelper {
tvOptions: List<Int> = listOf(),
callback: (Pair<Boolean, Int>) -> Unit
) {
if(this == null) return
if (this == null) return
this.showOptionSelect(
view,
@ -39,7 +42,7 @@ object SingleSelectionHelper {
tvOptions: List<String>,
callback: (Pair<Boolean, Int>) -> Unit
) {
if(this == null) return
if (this == null) return
if (this.isTvSettings()) {
val builder =
@ -86,42 +89,44 @@ object SingleSelectionHelper {
showApply: Boolean,
isMultiSelect: Boolean,
callback: (List<Int>) -> Unit,
dismissCallback: () -> Unit
dismissCallback: () -> Unit,
itemLayout: Int = R.layout.sort_bottom_single_choice
) {
if(this == null) return
if (this == null) return
val realShowApply = showApply || isMultiSelect
val listView = dialog.findViewById<ListView>(R.id.listview1)!!
val textView = dialog.findViewById<TextView>(R.id.text1)!!
val applyButton = dialog.findViewById<TextView>(R.id.apply_btt)!!
val cancelButton = dialog.findViewById<TextView>(R.id.cancel_btt)!!
val applyHolder = dialog.findViewById<LinearLayout>(R.id.apply_btt_holder)!!
val listView = dialog.listview1//.findViewById<ListView>(R.id.listview1)!!
val textView = dialog.text1//.findViewById<TextView>(R.id.text1)!!
val applyButton = dialog.apply_btt//.findViewById<TextView>(R.id.apply_btt)
val cancelButton = dialog.cancel_btt//findViewById<TextView>(R.id.cancel_btt)
val applyHolder = dialog.apply_btt_holder//.findViewById<LinearLayout>(R.id.apply_btt_holder)
applyHolder.isVisible = realShowApply
applyHolder?.isVisible = realShowApply
if (!realShowApply) {
val params = listView.layoutParams as LinearLayout.LayoutParams
params.setMargins(listView.marginLeft, listView.marginTop, listView.marginRight, 0)
listView.layoutParams = params
}
textView.text = name
textView?.text = name
textView?.isGone = name.isBlank()
val arrayAdapter = ArrayAdapter<String>(this, R.layout.sort_bottom_single_choice)
val arrayAdapter = ArrayAdapter<String>(this, itemLayout)
arrayAdapter.addAll(items)
listView.adapter = arrayAdapter
listView?.adapter = arrayAdapter
if (isMultiSelect) {
listView.choiceMode = AbsListView.CHOICE_MODE_MULTIPLE
listView?.choiceMode = AbsListView.CHOICE_MODE_MULTIPLE
} else {
listView.choiceMode = AbsListView.CHOICE_MODE_SINGLE
listView?.choiceMode = AbsListView.CHOICE_MODE_SINGLE
}
for (select in selectedIndex) {
listView.setItemChecked(select, true)
listView?.setItemChecked(select, true)
}
selectedIndex.minOrNull()?.let {
listView.setSelection(it)
listView?.setSelection(it)
}
// var lastSelectedIndex = if(selectedIndex.isNotEmpty()) selectedIndex.first() else -1
@ -130,7 +135,7 @@ object SingleSelectionHelper {
dismissCallback.invoke()
}
listView.setOnItemClickListener { _, _, which, _ ->
listView?.setOnItemClickListener { _, _, which, _ ->
// lastSelectedIndex = which
if (realShowApply) {
if (!isMultiSelect) {
@ -142,7 +147,7 @@ object SingleSelectionHelper {
}
}
if (realShowApply) {
applyButton.setOnClickListener {
applyButton?.setOnClickListener {
val list = ArrayList<Int>()
for (index in 0 until listView.count) {
if (listView.checkedItemPositions[index])
@ -151,7 +156,7 @@ object SingleSelectionHelper {
callback.invoke(list)
dialog.dismissSafe(this)
}
cancelButton.setOnClickListener {
cancelButton?.setOnClickListener {
dialog.dismissSafe(this)
}
}
@ -166,7 +171,7 @@ object SingleSelectionHelper {
callback: (String) -> Unit,
dismissCallback: () -> Unit
) {
if(this == null) return
if (this == null) return
val inputView = dialog.findViewById<EditText>(R.id.nginx_text_input)!!
val textView = dialog.findViewById<TextView>(R.id.text1)!!
@ -205,7 +210,7 @@ object SingleSelectionHelper {
dismissCallback: () -> Unit,
callback: (List<Int>) -> Unit,
) {
if(this == null) return
if (this == null) return
val builder =
AlertDialog.Builder(this, R.style.AlertDialogCustom)
@ -224,7 +229,7 @@ object SingleSelectionHelper {
dismissCallback: () -> Unit,
callback: (Int) -> Unit,
) {
if(this == null) return
if (this == null) return
val builder =
AlertDialog.Builder(this, R.style.AlertDialogCustom)
@ -271,6 +276,31 @@ object SingleSelectionHelper {
)
}
fun Activity.showBottomDialogInstant(
items: List<String>,
name: String,
dismissCallback: () -> Unit,
callback: (Int) -> Unit,
): BottomSheetDialog {
val builder =
BottomSheetDialog(this)
builder.setContentView(R.layout.bottom_selection_dialog_direct)
builder.show()
showDialog(
builder,
items,
listOf(),
name,
showApply = false,
isMultiSelect = false,
callback = { if (it.isNotEmpty()) callback.invoke(it.first()) },
dismissCallback = dismissCallback,
itemLayout = R.layout.sort_bottom_single_choice_no_checkmark
)
return builder
}
fun Activity.showNginxTextInputDialog(
name: String,
value: String,

View 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/text1"
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"
android:text="@string/loading_chromecast"
android:layout_height="wrap_content" />
<androidx.core.widget.ContentLoadingProgressBar
android:layout_marginBottom="-6.5dp"
android:indeterminate="true"
style="@android:style/Widget.Material.ProgressBar.Horizontal"
android:layout_gravity="center"
android:indeterminateTint="?attr/colorPrimary"
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:progressTint="?attr/colorPrimary"
android:layout_height="15dp">
</androidx.core.widget.ContentLoadingProgressBar>
</LinearLayout>

View File

@ -0,0 +1,34 @@
<?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/text1"
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" />
<ListView
android:nextFocusRight="@id/cancel_btt"
android:nextFocusLeft="@id/apply_btt"
android:id="@+id/listview1"
android:layout_marginBottom="60dp"
android:paddingTop="10dp"
android:requiresFadingEdge="vertical"
tools:listitem="@layout/sort_bottom_single_choice_no_checkmark"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_rowWeight="1" />
</LinearLayout>

View File

@ -843,7 +843,6 @@
<LinearLayout
android:id="@+id/result_next_airing_holder"
android:layout_gravity="start"
android:paddingBottom="15dp"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

View File

@ -12,6 +12,6 @@
android:scaleType="fitCenter"
android:adjustViewBounds="true"
android:src="@drawable/default_cover"
android:background="#fffff0"
android:background="?attr/primaryGrayBackground"
android:contentDescription="@string/poster_image" />
</LinearLayout>

View File

@ -0,0 +1,22 @@
<!--<CheckedTextView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeightSmall"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:textColor="?attr/textColor"
tools:text="Example Text"
android:background="?attr/bitDarkerGrayBackground"
android:checkMark="?android:attr/listChoiceIndicatorSingle"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"/>
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
style="@style/NoCheckLabel"
tools:text="hello"
android:textStyle="normal"
android:textColor="?attr/textColor"
android:id="@android:id/text1" />

View File

@ -448,7 +448,15 @@
<item name="android:textColor">?attr/textColor</item>
</style>
<style name="CheckLabel" parent="@style/AppTextViewStyle">
<style name="CheckLabel" parent="@style/NoCheckLabel">
<!-- <item name="drawableTint">@color/check_selection_color</item>-->
<!-- Set color in the drawable instead of tint to allow multiple drawables-->
<item name="android:checkMark">?android:attr/listChoiceIndicatorSingle</item>
<item name="drawableStartCompat">@drawable/ic_baseline_check_24_listview</item>
</style>
<style name="NoCheckLabel" parent="@style/AppTextViewStyle">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
@ -458,15 +466,13 @@
<item name="android:gravity">center_vertical</item>
<item name="android:paddingStart">12dp</item>
<item name="android:paddingEnd">12dp</item>
<item name="android:checkMark">?android:attr/listChoiceIndicatorSingle</item>
<item name="android:ellipsize">marquee</item>
<item name="android:foreground">?attr/selectableItemBackgroundBorderless</item>
<item name="android:drawablePadding">20dp</item>
<!-- <item name="drawableTint">@color/check_selection_color</item>-->
<!-- Set color in the drawable instead of tint to allow multiple drawables-->
<item name="drawableStartCompat">@drawable/ic_baseline_check_24_listview</item>
</style>
<style name="BlackButton" parent="NiceButton">
<item name="strokeColor">?attr/textColor</item>
<item name="backgroundTint">?attr/iconGrayBackground</item>