diff --git a/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingRemoteViewsFactory.kt b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingRemoteViewsFactory.kt index 0991b2a4..799b2518 100644 --- a/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingRemoteViewsFactory.kt +++ b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingRemoteViewsFactory.kt @@ -9,10 +9,19 @@ import android.widget.RemoteViews import android.widget.RemoteViewsService import ani.dantotsu.R import ani.dantotsu.connections.anilist.Anilist +import ani.dantotsu.media.Media import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.util.BitmapUtil.Companion.roundCorners import ani.dantotsu.util.Logger +import com.google.gson.GsonBuilder +import com.google.gson.InstanceCreator +import eu.kanade.tachiyomi.animesource.model.SAnime +import eu.kanade.tachiyomi.animesource.model.SAnimeImpl +import eu.kanade.tachiyomi.animesource.model.SEpisode +import eu.kanade.tachiyomi.animesource.model.SEpisodeImpl +import eu.kanade.tachiyomi.source.model.SChapter +import eu.kanade.tachiyomi.source.model.SChapterImpl import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking import java.io.InputStream @@ -49,19 +58,98 @@ class UpcomingRemoteViewsFactory(private val context: Context) : private fun fillWidgetItems() { refreshing = true val userId = PrefManager.getVal(PrefName.AnilistUserId) - runBlocking(Dispatchers.IO) { - val upcoming = Anilist.query.getUpcomingAnime(userId) - upcoming.forEach { - widgetItems.add( - WidgetItem( - it.userPreferredName, - timeUntil(it.timeUntilAiring ?: 0), - it.cover ?: "", - it.id + val prefs = context.getSharedPreferences(UpcomingWidget.PREFS_NAME, Context.MODE_PRIVATE) + val lastUpdated = prefs.getLong(UpcomingWidget.LAST_UPDATE, 0) + val serializedMedia = prefs.getString(UpcomingWidget.PREF_SERIALIZED_MEDIA, "") + if (System.currentTimeMillis() - lastUpdated > 1000 * 60 * 60 * 4 || serializedMedia.isNullOrEmpty()) { + runBlocking(Dispatchers.IO) { + val upcoming = Anilist.query.getUpcomingAnime(userId) + upcoming.forEach { + widgetItems.add( + WidgetItem( + it.userPreferredName, + timeUntil(it.timeUntilAiring ?: 0), + it.cover ?: "", + it.id + ) ) - ) + } + prefs.edit().putLong(UpcomingWidget.LAST_UPDATE, System.currentTimeMillis()).apply() + val serialized = serializeMedia(upcoming) + if (serialized != null) { + prefs.edit().putString(UpcomingWidget.PREF_SERIALIZED_MEDIA, serialized).apply() + } else { + prefs.edit().putString(UpcomingWidget.PREF_SERIALIZED_MEDIA, "").apply() + Logger.log("Error serializing media") + } + refreshing = false } + } else { refreshing = false + val timeSinceLastUpdate = System.currentTimeMillis() - lastUpdated + val media = deserializeMedia(serializedMedia) + if (media != null) { + media.forEach { + widgetItems.add( + WidgetItem( + it.userPreferredName, + timeUntil(it.timeUntilAiring?.minus(timeSinceLastUpdate) ?: 0), + it.cover ?: "", + it.id + ) + ) + } + } else { + prefs.edit().putString(UpcomingWidget.PREF_SERIALIZED_MEDIA, "").apply() + prefs.edit().putLong(UpcomingWidget.LAST_UPDATE, 0).apply() + Logger.log("Error deserializing media") + fillWidgetItems() + } + } + + } + + private fun serializeMedia(media: List): String? { + return try { + val gson = GsonBuilder() + .registerTypeAdapter(SChapter::class.java, InstanceCreator { + SChapterImpl() // Provide an instance of SChapterImpl + }) + .registerTypeAdapter(SAnime::class.java, InstanceCreator { + SAnimeImpl() // Provide an instance of SAnimeImpl + }) + .registerTypeAdapter(SEpisode::class.java, InstanceCreator { + SEpisodeImpl() // Provide an instance of SEpisodeImpl + }) + .create() + val json = gson.toJson(media) + json + } catch (e: Exception) { + Logger.log("Error serializing media: $e") + Logger.log(e) + null + } + } + + private fun deserializeMedia(json: String): List? { + return try { + val gson = GsonBuilder() + .registerTypeAdapter(SChapter::class.java, InstanceCreator { + SChapterImpl() // Provide an instance of SChapterImpl + }) + .registerTypeAdapter(SAnime::class.java, InstanceCreator { + SAnimeImpl() // Provide an instance of SAnimeImpl + }) + .registerTypeAdapter(SEpisode::class.java, InstanceCreator { + SEpisodeImpl() // Provide an instance of SEpisodeImpl + }) + .create() + val media = gson.fromJson(json, Array::class.java).toList() + media + } catch (e: Exception) { + Logger.log("Error deserializing media: $e") + Logger.log(e) + null } } diff --git a/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidget.kt b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidget.kt index fc8850f3..62f31d05 100644 --- a/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidget.kt +++ b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidget.kt @@ -132,6 +132,8 @@ class UpcomingWidget : AppWidgetProvider() { const val PREF_BACKGROUND_FADE = "background_fade" const val PREF_TITLE_TEXT_COLOR = "title_text_color" const val PREF_COUNTDOWN_TEXT_COLOR = "countdown_text_color" + const val PREF_SERIALIZED_MEDIA = "serialized_media" + const val LAST_UPDATE = "last_update" } }