Skip to content

Commit

Permalink
Local history: add/remove entries when marking multiple episodes
Browse files Browse the repository at this point in the history
  • Loading branch information
UweTrottmann committed Mar 7, 2024
1 parent e5d9aa2 commit 1e14d6b
Show file tree
Hide file tree
Showing 14 changed files with 181 additions and 148 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Version 72
----------
*in development*

* 🔧 Add history entry when marking multiple episodes as watched.
* 🔨 Android 5: use correct color for show status and stream search configure button.

#### 72.0.4 🧪
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.battlelancer.seriesguide.provider.SeriesGuideContract
import com.battlelancer.seriesguide.provider.SgRoomDatabase
import com.battlelancer.seriesguide.shows.database.SgEpisode2Numbers
import com.battlelancer.seriesguide.shows.episodes.EpisodeTools
import com.battlelancer.seriesguide.shows.history.SgActivityHelper
import com.battlelancer.seriesguide.shows.tools.LatestEpisodeUpdateTask
import com.google.flatbuffers.FlatBufferBuilder

Expand All @@ -37,17 +38,19 @@ abstract class BaseEpisodesJob(
*/
@CallSuper
override fun applyLocalChanges(context: Context, requiresNetworkJob: Boolean): Boolean {
val episodes: List<SgEpisode2Numbers> = getAffectedEpisodes(context)

// prepare network job
var networkJobInfo: ByteArray? = null
if (requiresNetworkJob) {
networkJobInfo = prepareNetworkJob(context)
networkJobInfo = prepareNetworkJob(episodes)
if (networkJobInfo == null) {
return false
}
}

// apply local updates
val updated = applyDatabaseChanges(context)
val updated = applyDatabaseChanges(context, episodes)
if (!updated) {
return false
}
Expand All @@ -66,24 +69,27 @@ abstract class BaseEpisodesJob(
return true
}

protected abstract fun applyDatabaseChanges(context: Context): Boolean
protected abstract fun applyDatabaseChanges(
context: Context,
episodes: List<SgEpisode2Numbers>
): Boolean

/**
* Note: Ensure episodes are ordered by season number (lowest first),
* then episode number (lowest first).
*/
protected abstract fun getEpisodesForNetworkJob(context: Context): List<SgEpisode2Numbers>
protected abstract fun getAffectedEpisodes(context: Context): List<SgEpisode2Numbers>

/**
* Returns the number of plays to upload to Cloud (Trakt currently not supported)
* based on the current number of plays (before [.applyLocalChanges].
*/
protected abstract fun getPlaysForNetworkJob(plays: Int): Int

private fun prepareNetworkJob(context: Context): ByteArray? {
// store affected episodes for network part
val episodes = getEpisodesForNetworkJob(context)

/**
* Store affected episodes for network job.
*/
private fun prepareNetworkJob(episodes: List<SgEpisode2Numbers>): ByteArray? {
val builder = FlatBufferBuilder(0)

val episodeInfos = IntArray(episodes.size)
Expand Down Expand Up @@ -122,4 +128,21 @@ abstract class BaseEpisodesJob(
}
LatestEpisodeUpdateTask.updateLatestEpisodeFor(context, showId)
}

/**
* Add or remove watch activity entries for episodes. Only used for watch jobs.
*/
protected fun updateActivity(context: Context, episodes: List<SgEpisode2Numbers>) {
val showTmdbIdOrZero =
SgRoomDatabase.getInstance(context).sgShow2Helper().getShowTmdbId(showId)
val episodeTmdbIds = episodes.mapNotNull { it.tmdbId }

if (showTmdbIdOrZero == 0 && episodeTmdbIds.isEmpty()) return

if (EpisodeTools.isWatched(flagValue)) {
SgActivityHelper.addActivitiesForEpisodes(context, showTmdbIdOrZero, episodeTmdbIds)
} else if (EpisodeTools.isUnwatched(flagValue)) {
SgActivityHelper.removeActivitiesForEpisodes(context, episodeTmdbIds)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright 2023 Uwe Trottmann
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017, 2018, 2021-2024 Uwe Trottmann

package com.battlelancer.seriesguide.jobs.episodes;

Expand Down Expand Up @@ -49,7 +49,7 @@ protected long getShowId() {

@NonNull
@Override
protected List<SgEpisode2Numbers> getEpisodesForNetworkJob(@NonNull Context context) {
protected List<SgEpisode2Numbers> getAffectedEpisodes(@NonNull Context context) {
List<SgEpisode2Numbers> list = new ArrayList<>();
list.add(episode);
return list;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ package com.battlelancer.seriesguide.jobs.episodes

import android.content.Context
import com.battlelancer.seriesguide.provider.SgRoomDatabase
import com.battlelancer.seriesguide.shows.database.SgEpisode2Numbers

class EpisodeCollectedJob(
episodeId: Long, private val isCollected: Boolean
) : EpisodeBaseJob(episodeId, if (isCollected) 1 else 0, JobAction.EPISODE_COLLECTION) {
override fun applyDatabaseChanges(context: Context): Boolean {
override fun applyDatabaseChanges(
context: Context,
episodes: List<SgEpisode2Numbers>
): Boolean {
val updated = SgRoomDatabase.getInstance(context).sgEpisode2Helper()
.updateCollected(episodeId, isCollected)
return updated == 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ package com.battlelancer.seriesguide.jobs.episodes
import android.content.Context
import com.battlelancer.seriesguide.appwidget.ListWidgetProvider
import com.battlelancer.seriesguide.provider.SgRoomDatabase
import com.battlelancer.seriesguide.shows.database.SgEpisode2Numbers
import com.battlelancer.seriesguide.shows.episodes.EpisodeFlags
import com.battlelancer.seriesguide.shows.episodes.EpisodeTools
import com.battlelancer.seriesguide.shows.history.SgActivityHelper

class EpisodeWatchedJob(
episodeId: Long,
Expand Down Expand Up @@ -49,31 +49,10 @@ class EpisodeWatchedJob(
}
}

override fun applyLocalChanges(context: Context, requiresNetworkJob: Boolean): Boolean {
if (!super.applyLocalChanges(context, requiresNetworkJob)) {
return false
}

// set a new last watched episode
// set last watched time to now if marking as watched or skipped
val unwatched = EpisodeTools.isUnwatched(flagValue)
updateLastWatched(context, getLastWatchedEpisodeId(context), !unwatched)

if (EpisodeTools.isWatched(flagValue)) {
// create activity entry for watched episode
SgActivityHelper.addActivity(context, episodeId, showId)
} else if (unwatched) {
// remove any previous activity entries for this episode
// use case: user accidentally toggled watched flag
SgActivityHelper.removeActivity(context, episodeId)
}

ListWidgetProvider.notifyDataChanged(context)

return true
}

override fun applyDatabaseChanges(context: Context): Boolean {
override fun applyDatabaseChanges(
context: Context,
episodes: List<SgEpisode2Numbers>
): Boolean {
val episodeHelper = SgRoomDatabase.getInstance(context).sgEpisode2Helper()
val flagValue = flagValue
val rowsUpdated: Int = when (flagValue) {
Expand All @@ -82,7 +61,20 @@ class EpisodeWatchedJob(
EpisodeFlags.UNWATCHED -> episodeHelper.setNotWatchedAndRemovePlays(episodeId)
else -> throw IllegalArgumentException("Flag value not supported")
}
return rowsUpdated == 1
val isSuccessful = rowsUpdated == 1

if (isSuccessful) {
// set a new last watched episode
// set last watched time to now if marking as watched or skipped
val unwatched = EpisodeTools.isUnwatched(flagValue)
updateLastWatched(context, getLastWatchedEpisodeId(context), !unwatched)

// Add or remove activity entry
updateActivity(context, episodes)

ListWidgetProvider.notifyDataChanged(context)
}
return isSuccessful
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,28 @@ class EpisodeWatchedUpToJob(
private val episodeNumber: Int
) : BaseEpisodesJob(EpisodeFlags.WATCHED, JobAction.EPISODE_WATCHED_FLAG) {

override fun applyLocalChanges(context: Context, requiresNetworkJob: Boolean): Boolean {
if (!super.applyLocalChanges(context, requiresNetworkJob)) {
return false
}

// we don't care about the last watched episode value
// always update last watched time, this type only marks as watched
updateLastWatched(context, -1, true)
override fun applyDatabaseChanges(
context: Context,
episodes: List<SgEpisode2Numbers>
): Boolean {
val rowsUpdated = SgRoomDatabase.getInstance(context).sgEpisode2Helper()
.setWatchedUpToAndAddPlay(showId, episodeFirstAired, episodeNumber)
val isSuccessful = rowsUpdated >= 0 // -1 means error

ListWidgetProvider.notifyDataChanged(context)
if (isSuccessful) {
// we don't care about the last watched episode value
// always update last watched time, this type only marks as watched
updateLastWatched(context, -1, true)

return true
}
// Add or remove activity entries
updateActivity(context, episodes)

override fun applyDatabaseChanges(context: Context): Boolean {
val rowsUpdated = SgRoomDatabase.getInstance(context).sgEpisode2Helper()
.setWatchedUpToAndAddPlay(showId, episodeFirstAired, episodeNumber)
return rowsUpdated >= 0 // -1 means error
ListWidgetProvider.notifyDataChanged(context)
}
return isSuccessful
}

override fun getEpisodesForNetworkJob(context: Context): List<SgEpisode2Numbers> {
override fun getAffectedEpisodes(context: Context): List<SgEpisode2Numbers> {
return SgRoomDatabase.getInstance(context).sgEpisode2Helper()
.getEpisodeNumbersForWatchedUpTo(showId, episodeFirstAired, episodeNumber)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright 2023 Uwe Trottmann
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017, 2018, 2023 Uwe Trottmann

package com.battlelancer.seriesguide.jobs.episodes;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ class SeasonCollectedJob(
seasonId: Long,
private val isCollected: Boolean
) : SeasonBaseJob(seasonId, if (isCollected) 1 else 0, JobAction.EPISODE_COLLECTION) {
override fun applyDatabaseChanges(context: Context): Boolean {
override fun applyDatabaseChanges(context: Context, episodes: List<SgEpisode2Numbers>): Boolean {
val rowsUpdated = SgRoomDatabase.getInstance(context).sgEpisode2Helper()
.updateCollectedOfSeason(seasonId, isCollected)
return rowsUpdated >= 0 // -1 means error.
}

override fun getEpisodesForNetworkJob(context: Context): List<SgEpisode2Numbers> {
override fun getAffectedEpisodes(context: Context): List<SgEpisode2Numbers> {
return SgRoomDatabase.getInstance(context).sgEpisode2Helper()
.getEpisodeNumbersOfSeason(seasonId)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ class SeasonWatchedJob(seasonId: Long, episodeFlags: Int) :
}
}

override fun applyDatabaseChanges(context: Context): Boolean {
override fun applyDatabaseChanges(
context: Context,
episodes: List<SgEpisode2Numbers>
): Boolean {
val database = SgRoomDatabase.getInstance(context)
val helper = database.sgEpisode2Helper()
val rowsUpdated = when (flagValue) {
Expand All @@ -45,18 +48,23 @@ class SeasonWatchedJob(seasonId: Long, episodeFlags: Int) :
EpisodeFlags.UNWATCHED -> helper.setSeasonNotWatchedAndRemovePlays(seasonId)
else -> throw IllegalArgumentException("Flag value not supported")
}
val isSuccessful = rowsUpdated >= 0 // -1 means error.

// set a new last watched episode
// set last watched time to now if marking as watched or skipped
val unwatched = EpisodeTools.isUnwatched(flagValue)
updateLastWatched(context, getLastWatchedEpisodeId(context), !unwatched)
if (isSuccessful) {
// set a new last watched episode
// set last watched time to now if marking as watched or skipped
val unwatched = EpisodeTools.isUnwatched(flagValue)
updateLastWatched(context, getLastWatchedEpisodeId(context), !unwatched)

ListWidgetProvider.notifyDataChanged(context)
// Add or remove activity entries
updateActivity(context, episodes)

return rowsUpdated >= 0 // -1 means error.
ListWidgetProvider.notifyDataChanged(context)
}
return isSuccessful
}

override fun getEpisodesForNetworkJob(context: Context): List<SgEpisode2Numbers> {
override fun getAffectedEpisodes(context: Context): List<SgEpisode2Numbers> {
val helper = SgRoomDatabase.getInstance(context).sgEpisode2Helper()
return if (EpisodeTools.isUnwatched(flagValue)) {
// set unwatched
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ class ShowCollectedJob(
private val isCollected: Boolean
) : ShowBaseJob(showId, if (isCollected) 1 else 0, JobAction.EPISODE_COLLECTION) {

override fun applyDatabaseChanges(context: Context): Boolean {
override fun applyDatabaseChanges(
context: Context,
episodes: List<SgEpisode2Numbers>
): Boolean {
val rowsUpdated = SgRoomDatabase.getInstance(context).sgEpisode2Helper()
.updateCollectedOfShowExcludeSpecials(showId, isCollected)
return rowsUpdated >= 0 // -1 means error.
}

override fun getEpisodesForNetworkJob(context: Context): List<SgEpisode2Numbers> {
override fun getAffectedEpisodes(context: Context): List<SgEpisode2Numbers> {
return SgRoomDatabase.getInstance(context).sgEpisode2Helper()
.getEpisodeNumbersOfShow(showId)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,16 @@ class ShowWatchedJob(
if (!super.applyLocalChanges(context, requiresNetworkJob)) {
return false
}
val lastWatchedEpisodeId =
if (EpisodeTools.isUnwatched(flagValue)) {
0L /* just reset */
} else {
-1L /* we don't care */
}

// set a new last watched episode
// set last watched time to now if marking as watched or skipped
updateLastWatched(context, lastWatchedEpisodeId, !EpisodeTools.isUnwatched(flagValue))

ListWidgetProvider.notifyDataChanged(context)

return true
}

override fun applyDatabaseChanges(context: Context): Boolean {
override fun applyDatabaseChanges(
context: Context,
episodes: List<SgEpisode2Numbers>
): Boolean {
val helper = SgRoomDatabase.getInstance(context).sgEpisode2Helper()
val rowsUpdated: Int = when (flagValue) {
EpisodeFlags.UNWATCHED -> helper.setShowNotWatchedAndRemovePlays(showId)
Expand All @@ -51,10 +44,29 @@ class ShowWatchedJob(
throw IllegalArgumentException("Flag value not supported")
}
}
return rowsUpdated >= 0 // -1 means error.
val isSuccessful = rowsUpdated >= 0 // -1 means error

if (isSuccessful) {
val lastWatchedEpisodeId =
if (EpisodeTools.isUnwatched(flagValue)) {
0L /* just reset */
} else {
-1L /* we don't care */
}

// set a new last watched episode
// set last watched time to now if marking as watched or skipped
updateLastWatched(context, lastWatchedEpisodeId, !EpisodeTools.isUnwatched(flagValue))

// Add or remove activity entries
updateActivity(context, episodes)

ListWidgetProvider.notifyDataChanged(context)
}
return isSuccessful
}

override fun getEpisodesForNetworkJob(context: Context): List<SgEpisode2Numbers> {
override fun getAffectedEpisodes(context: Context): List<SgEpisode2Numbers> {
val helper = SgRoomDatabase.getInstance(context).sgEpisode2Helper()
return if (EpisodeTools.isUnwatched(flagValue)) {
// set unwatched
Expand Down
Loading

0 comments on commit 1e14d6b

Please sign in to comment.