Redo how alert dialog and callbacks are done, update messages, and support bookmarks if added from the home page

This commit is contained in:
Luna712 2023-10-16 14:03:59 -06:00
parent c444a2f162
commit fc168c0ab0
5 changed files with 221 additions and 219 deletions

View file

@ -355,21 +355,25 @@ class HomeParentItemAdapterPreview(
showApply = false, showApply = false,
{}) { {}) {
val newValue = WatchType.values()[it] val newValue = WatchType.values()[it]
homePreviewBookmark.setCompoundDrawablesWithIntrinsicBounds(
null,
ContextCompat.getDrawable(
homePreviewBookmark.context,
newValue.iconRes
),
null,
null
)
homePreviewBookmark.setText(newValue.stringRes)
ResultViewModel2.updateWatchStatus( ResultViewModel2().updateWatchStatus(
item, newValue,
newValue fab.context,
) item
) { statusChanged: Boolean ->
if (statusChanged) {
homePreviewBookmark.setCompoundDrawablesWithIntrinsicBounds(
null,
ContextCompat.getDrawable(
homePreviewBookmark.context,
newValue.iconRes
),
null,
null
)
homePreviewBookmark.setText(newValue.stringRes)
}
}
} }
} }
} }

View file

@ -430,42 +430,36 @@ open class ResultFragmentPhone : FullScreenPlayer() {
} }
}) })
resultSubscribe.setOnClickListener { resultSubscribe.setOnClickListener {
val isSubscribed = viewModel.toggleSubscriptionStatus(context) { newStatus: Boolean? ->
viewModel.toggleSubscriptionStatus(context) ?: return@setOnClickListener if (newStatus == null) return@toggleSubscriptionStatus
if (viewModel.subscribeStatus.value == isSubscribed) { val message = if (newStatus) {
return@setOnClickListener // Kinda icky to have this here, but it works.
SubscriptionWorkManager.enqueuePeriodicWork(context)
R.string.subscription_new
} else {
R.string.subscription_deleted
}
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)
} }
val message = if (isSubscribed) {
// Kinda icky to have this here, but it works.
SubscriptionWorkManager.enqueuePeriodicWork(context)
R.string.subscription_new
} else {
R.string.subscription_deleted
}
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)
} }
resultFavorite.setOnClickListener { resultFavorite.setOnClickListener {
val isFavorite = viewModel.toggleFavoriteStatus(context) { newStatus: Boolean? ->
viewModel.toggleFavoriteStatus(context) ?: return@setOnClickListener if (newStatus == null) return@toggleFavoriteStatus
if (viewModel.favoriteStatus.value == isFavorite) { val message = if (newStatus) {
return@setOnClickListener 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)
} }
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

View file

@ -557,21 +557,19 @@ class ResultFragmentTv : Fragment() {
setIconResource(drawable) setIconResource(drawable)
setText(text) setText(text)
setOnClickListener { setOnClickListener {
val isFavorite = viewModel.toggleFavoriteStatus(context) ?: return@setOnClickListener viewModel.toggleFavoriteStatus(context) { newStatus: Boolean? ->
if (newStatus == null) return@toggleFavoriteStatus
if (viewModel.favoriteStatus.value == isFavorite) { val message = if (newStatus) {
return@setOnClickListener 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)
} }
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)
} }
} }
} }

View file

@ -29,7 +29,6 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.getMalId
import com.lagradost.cloudstream3.LoadResponse.Companion.isMovie import com.lagradost.cloudstream3.LoadResponse.Companion.isMovie
import com.lagradost.cloudstream3.metaproviders.SyncRedirector import com.lagradost.cloudstream3.metaproviders.SyncRedirector
import com.lagradost.cloudstream3.mvvm.* import com.lagradost.cloudstream3.mvvm.*
import com.lagradost.cloudstream3.services.SubscriptionWorkManager
import com.lagradost.cloudstream3.syncproviders.AccountManager import com.lagradost.cloudstream3.syncproviders.AccountManager
import com.lagradost.cloudstream3.syncproviders.SyncAPI import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
@ -83,11 +82,6 @@ import kotlinx.coroutines.*
import java.io.File import java.io.File
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
interface AlertDialogResponseCallback {
fun onUserResponse(action: Boolean)
fun onUserResponseReplace(duplicateId: Int)
}
/** This starts at 1 */ /** This starts at 1 */
data class EpisodeRange( data class EpisodeRange(
@ -463,33 +457,6 @@ class ResultViewModel2 : ViewModel() {
return this?.firstOrNull { it.season == season } return this?.firstOrNull { it.season == season }
} }
fun updateWatchStatus(currentResponse: LoadResponse, status: WatchType) {
val currentId = currentResponse.getId()
val currentWatchType = getResultWatchState(currentId)
setResultWatchState(currentId, status.internalId)
val current = getBookmarkedData(currentId)
val currentTime = System.currentTimeMillis()
setBookmarkedData(
currentId,
DataStoreHelper.BookmarkedData(
current?.bookmarkedTime ?: currentTime,
currentTime,
currentId,
currentResponse.name,
currentResponse.year,
currentResponse.url,
currentResponse.apiName,
currentResponse.type,
currentResponse.posterUrl
)
)
if (currentWatchType != status) {
MainActivity.bookmarksUpdatedEvent(true)
}
}
private fun filterName(name: String?): String? { private fun filterName(name: String?): String? {
if (name == null) return null if (name == null) return null
Regex("[eE]pisode [0-9]*(.*)").find(name)?.groupValues?.get(1)?.let { Regex("[eE]pisode [0-9]*(.*)").find(name)?.groupValues?.get(1)?.let {
@ -844,32 +811,57 @@ class ResultViewModel2 : ViewModel() {
val selectPopup: LiveData<SelectPopup?> = _selectPopup val selectPopup: LiveData<SelectPopup?> = _selectPopup
fun updateWatchStatus(status: WatchType, context: Context?) { fun updateWatchStatus(
val currentStatus = _watchStatus.value ?: return status: WatchType,
if (status == currentStatus) return context: Context?,
loadResponse: LoadResponse? = null,
statusChangeCallback: ((Boolean) -> Unit)? = null
) {
val response = loadResponse ?: currentResponse ?: return
val response = currentResponse ?: return val currentId = response.getId()
val currentStatus = getResultWatchState(currentId)
if (status == currentStatus) return
checkAndWarnDuplicates( checkAndWarnDuplicates(
context, context,
R.string.bookmarks_duplicate_title, R.string.duplicate_message_bookmarks,
R.string.bookmarks_duplicate_message,
response.name, response.name,
response.year, response.year,
getAllBookmarkedDataByWatchType()[status] ?: emptyList(), getAllBookmarkedDataByWatchType()[status] ?: emptyList()
object : AlertDialogResponseCallback { ) { userResponse: Boolean, duplicateId: Int? ->
override fun onUserResponseReplace(duplicateId: Int) { if (!userResponse) return@checkAndWarnDuplicates
deleteBookmarkedData(duplicateId)
}
override fun onUserResponse(action: Boolean) { if (duplicateId != null) {
if (!action) return deleteBookmarkedData(duplicateId)
updateWatchStatus(response, status)
_watchStatus.postValue(status)
}
} }
)
setResultWatchState(currentId, status.internalId)
val current = getBookmarkedData(currentId)
val currentTime = System.currentTimeMillis()
setBookmarkedData(
currentId,
DataStoreHelper.BookmarkedData(
current?.bookmarkedTime ?: currentTime,
currentTime,
currentId,
response.name,
response.year,
response.url,
response.apiName,
response.type,
response.posterUrl
)
)
MainActivity.bookmarksUpdatedEvent(true)
_watchStatus.postValue(status)
statusChangeCallback?.invoke(true)
}
} }
private fun startChromecast( private fun startChromecast(
@ -886,7 +878,10 @@ class ResultViewModel2 : ViewModel() {
/** /**
* @return true if the new status is Subscribed, false if not. Null if not possible to subscribe. * @return true if the new status is Subscribed, false if not. Null if not possible to subscribe.
**/ **/
fun toggleSubscriptionStatus(context: Context?): Boolean? { fun toggleSubscriptionStatus(
context: Context?,
statusChangeCallback: ((Boolean?) -> Unit)? = null
): Boolean? {
val isSubscribed = _subscribeStatus.value ?: return null val isSubscribed = _subscribeStatus.value ?: return null
val response = currentResponse ?: return null val response = currentResponse ?: return null
if (response !is EpisodeResponse) return null if (response !is EpisodeResponse) return null
@ -895,53 +890,48 @@ class ResultViewModel2 : ViewModel() {
if (isSubscribed) { if (isSubscribed) {
removeSubscribedData(currentId) removeSubscribedData(currentId)
statusChangeCallback?.invoke(false)
_subscribeStatus.postValue(false) _subscribeStatus.postValue(false)
return false return false
} else { } else {
checkAndWarnDuplicates( checkAndWarnDuplicates(
context, context,
R.string.subscriptions_duplicate_title, R.string.duplicate_message_subscriptions,
R.string.subscriptions_duplicate_message,
response.name, response.name,
response.year, response.year,
getAllSubscriptions(), getAllSubscriptions(),
object : AlertDialogResponseCallback { ) { userResponse: Boolean, duplicateId: Int? ->
override fun onUserResponseReplace(duplicateId: Int) { if (!userResponse) {
removeSubscribedData(duplicateId) statusChangeCallback?.invoke(null)
} return@checkAndWarnDuplicates
override fun onUserResponse(action: Boolean) {
if (!action) return
val current = getSubscribedData(currentId)
setSubscribedData(
currentId,
DataStoreHelper.SubscribedData(
current?.subscribedTime ?: unixTimeMS,
unixTimeMS,
response.getLatestEpisodes(),
currentId,
response.name,
response.year,
response.url,
response.apiName,
response.type,
response.posterUrl
)
)
_subscribeStatus.postValue(true)
SubscriptionWorkManager.enqueuePeriodicWork(context)
val name = (page.value as? Resource.Success)?.value?.title
?: txt(R.string.no_data).asStringNull(context) ?: ""
showToast(txt(R.string.subscription_new, name), Toast.LENGTH_SHORT)
}
} }
)
if (duplicateId != null) {
removeSubscribedData(duplicateId)
}
val current = getSubscribedData(currentId)
setSubscribedData(
currentId,
DataStoreHelper.SubscribedData(
current?.subscribedTime ?: unixTimeMS,
unixTimeMS,
response.getLatestEpisodes(),
currentId,
response.name,
response.year,
response.url,
response.apiName,
response.type,
response.posterUrl
)
)
_subscribeStatus.postValue(true)
statusChangeCallback?.invoke(true)
}
return _subscribeStatus.value return _subscribeStatus.value
} }
@ -950,7 +940,10 @@ class ResultViewModel2 : ViewModel() {
/** /**
* @return true if added to favorites, false if not. Null if not possible to favorite. * @return true if added to favorites, false if not. Null if not possible to favorite.
**/ **/
fun toggleFavoriteStatus(context: Context?): Boolean? { fun toggleFavoriteStatus(
context: Context?,
statusChangeCallback: ((Boolean?) -> Unit)? = null
): Boolean? {
val isFavorite = _favoriteStatus.value ?: return null val isFavorite = _favoriteStatus.value ?: return null
val response = currentResponse ?: return null val response = currentResponse ?: return null
@ -958,50 +951,47 @@ class ResultViewModel2 : ViewModel() {
if (isFavorite) { if (isFavorite) {
removeFavoritesData(currentId) removeFavoritesData(currentId)
statusChangeCallback?.invoke(false)
_favoriteStatus.postValue(false) _favoriteStatus.postValue(false)
return false return false
} else { } else {
checkAndWarnDuplicates( checkAndWarnDuplicates(
context, context,
R.string.favorites_duplicate_title, R.string.duplicate_message_favorites,
R.string.favorites_duplicate_message,
response.name, response.name,
response.year, response.year,
getAllFavorites(), getAllFavorites(),
object : AlertDialogResponseCallback { ) { userResponse: Boolean, duplicateId: Int? ->
override fun onUserResponseReplace(duplicateId: Int) { if (!userResponse) {
removeFavoritesData(duplicateId) statusChangeCallback?.invoke(null)
} return@checkAndWarnDuplicates
override fun onUserResponse(action: Boolean) {
if (!action) return
val current = getFavoritesData(currentId)
setFavoritesData(
currentId,
DataStoreHelper.FavoritesData(
current?.favoritesTime ?: unixTimeMS,
unixTimeMS,
currentId,
response.name,
response.year,
response.url,
response.apiName,
response.type,
response.posterUrl
)
)
_favoriteStatus.postValue(true)
val name = (page.value as? Resource.Success)?.value?.title
?: txt(R.string.no_data).asStringNull(context) ?: ""
showToast(txt(R.string.favorite_added, name), Toast.LENGTH_SHORT)
}
} }
)
if (duplicateId != null) {
removeFavoritesData(duplicateId)
}
val current = getFavoritesData(currentId)
setFavoritesData(
currentId,
DataStoreHelper.FavoritesData(
current?.favoritesTime ?: unixTimeMS,
unixTimeMS,
currentId,
response.name,
response.year,
response.url,
response.apiName,
response.type,
response.posterUrl
)
)
_favoriteStatus.postValue(true)
statusChangeCallback?.invoke(true)
}
return _favoriteStatus.value return _favoriteStatus.value
} }
@ -1009,46 +999,49 @@ class ResultViewModel2 : ViewModel() {
private fun checkAndWarnDuplicates( private fun checkAndWarnDuplicates(
context: Context?, context: Context?,
title: Int,
message: Int, message: Int,
name: String, name: String,
year: Int?, year: Int?,
data: List<DataStoreHelper.BaseSearchResponse>, data: List<DataStoreHelper.BaseSearchResponse>,
callback: AlertDialogResponseCallback alertCallback: (Boolean, Int?) -> Unit
) { ) {
// TODO support checking IMDB ID rather than name + year when available // TODO support checking IMDB ID rather than name + year when available
val duplicateEntry = data.find { it.name == name && it.year == year } val duplicateEntry = data.find { it.name == name && it.year == year }
if (duplicateEntry == null || context == null) { if (duplicateEntry == null || context == null) {
callback.onUserResponse(true) alertCallback.invoke(true, null)
return return
} }
val builder: AlertDialog.Builder = AlertDialog.Builder(context) val builder: AlertDialog.Builder = AlertDialog.Builder(context)
builder.setTitle(title) val dialogClickListener =
builder.setMessage(message) DialogInterface.OnClickListener { _, which ->
when (which) {
builder.setNeutralButton(R.string.replace) { _, _ -> DialogInterface.BUTTON_POSITIVE -> {
// Replace current entry with new one alertCallback.invoke(true, null)
val duplicateId = duplicateEntry.id }
if (duplicateId != null) { DialogInterface.BUTTON_NEGATIVE -> {
callback.onUserResponseReplace(duplicateId) alertCallback.invoke(false, null)
}
DialogInterface.BUTTON_NEUTRAL -> {
alertCallback.invoke(true, duplicateEntry.id)
}
}
} }
callback.onUserResponse(true) builder.setTitle(R.string.duplicate_title)
} .setMessage(
context.getString(message).format(
builder.setNegativeButton(R.string.cancel) { _, _ -> duplicateEntry.name,
// Don't add duplicate context.getString(
callback.onUserResponse(false) getResultWatchState(duplicateEntry.id ?: 0).stringRes
} )
)
builder.setPositiveButton(R.string.add_anyway) { _, _ -> )
// Add anyway .setPositiveButton(R.string.duplicate_add, dialogClickListener)
callback.onUserResponse(true) .setNegativeButton(R.string.duplicate_cancel, dialogClickListener)
} .setNeutralButton(R.string.duplicate_replace, dialogClickListener)
.show().setDefaultFocus()
builder.show().setDefaultFocus()
} }
private fun startChromecast( private fun startChromecast(

View file

@ -686,21 +686,34 @@
<string name="qualities">Qualities</string> <string name="qualities">Qualities</string>
<string name="profile_background_des">Profile background</string> <string name="profile_background_des">Profile background</string>
<string name="unable_to_inflate">UI was unable to be created correctly, this is a MAJOR BUG and should be reported immediately %s</string> <string name="unable_to_inflate">UI was unable to be created correctly, this is a MAJOR BUG and should be reported immediately %s</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="favorites_list_name">Favorites</string>
<string name="favorite_added">%s added to favorites</string> <string name="favorite_added">%s added to favorites</string>
<string name="favorite_removed">%s removed from favorites</string> <string name="favorite_removed">%s removed from favorites</string>
<string name="action_add_to_favorites">Add to favorites</string> <string name="action_add_to_favorites">Add to favorites</string>
<string name="action_remove_from_favorites">Remove from favorites</string> <string name="action_remove_from_favorites">Remove from favorites</string>
<string name="subscriptions_duplicate_title">Possible Duplicate Subscription</string>
<string name="subscriptions_duplicate_message">A possible duplicate with the same name already exists in your subscrptions.</string> <string name="duplicate_title">Possible Duplicate Found</string>
<string name="favorites_duplicate_title">Possible Duplicate Found</string> <string name="duplicate_add">Add</string>
<string name="favorites_duplicate_message">A possible duplicate with the same name already exists in your favorites.</string> <string name="duplicate_replace">Replace</string>
<string name="add_anyway">Add Anyway</string> <string name="duplicate_cancel" translatable="false">@string/sort_cancel</string>
<string name="replace">Replace</string> <string name="duplicate_message_bookmarks">
<string name="bookmarks_duplicate_title">Possible Duplicate Found</string> A possible duplicate with the same title \'%s\' and watch status \'%s\' already exists in your library.
<string name="bookmarks_duplicate_message">A possible duplicate with the same name and watch status already exists in your library.</string>
\n\nDo you want to still add this to item, replace the existing one, or cancel the action?
</string>
<string name="duplicate_message_subscriptions">
A possible duplicate with the same title \'%s\' already exists in your subscriptions.
\n\nDo you want to still subscribe to this item, replace the existing subscription, or cancel the action?
</string>
<string name="duplicate_message_favorites">
A possible duplicate with the same title \'%s\' already exists in your favorites.
\n\nDo you want to still add this to item, replace the existing one, or cancel the action?
</string>
<string name="tv_no_focus_tag" translatable="false">tv_no_focus_tag</string>
</resources> </resources>