This commit is contained in:
rebelonion 2024-01-18 01:09:30 -06:00
parent ff02280239
commit 664b5a4bdd
46 changed files with 317 additions and 190 deletions

View file

@ -180,7 +180,9 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
return view return view
} }
@OptIn(UnstableApi::class) private fun grid(){
@OptIn(UnstableApi::class)
private fun grid() {
gridView.setOnItemClickListener { parent, view, position, id -> gridView.setOnItemClickListener { parent, view, position, id ->
// Get the OfflineAnimeModel that was clicked // Get the OfflineAnimeModel that was clicked
val item = adapter.getItem(position) as OfflineAnimeModel val item = adapter.getItem(position) as OfflineAnimeModel
@ -211,7 +213,10 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
builder.setMessage("Are you sure you want to delete ${item.title}?") builder.setMessage("Are you sure you want to delete ${item.title}?")
builder.setPositiveButton("Yes") { _, _ -> builder.setPositiveButton("Yes") { _, _ ->
downloadManager.removeMedia(item.title, type) downloadManager.removeMedia(item.title, type)
val mediaIds = requireContext().getSharedPreferences(getString(R.string.anime_downloads), Context.MODE_PRIVATE) val mediaIds = requireContext().getSharedPreferences(
getString(R.string.anime_downloads),
Context.MODE_PRIVATE
)
?.all?.filter { it.key.contains(item.title) }?.values ?: emptySet() ?.all?.filter { it.key.contains(item.title) }?.values ?: emptySet()
if (mediaIds.isEmpty()) { if (mediaIds.isEmpty()) {
snackString("No media found") // if this happens, terrible things have happened snackString("No media found") // if this happens, terrible things have happened
@ -231,6 +236,7 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
true true
} }
} }
override fun onSearchQuery(query: String) { override fun onSearchQuery(query: String) {
adapter.onSearchQuery(query) adapter.onSearchQuery(query)
} }
@ -254,7 +260,8 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
} }
} }
val scrollTop = view.findViewById<CardView>(R.id.mangaPageScrollTop) val scrollTop = view.findViewById<CardView>(R.id.mangaPageScrollTop)
scrollTop.translationY = -(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat() scrollTop.translationY =
-(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat()
val visible = false val visible = false
fun animate() { fun animate() {
@ -401,9 +408,13 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
mediaModel.status == currActivity()!!.getString(R.string.status_releasing) mediaModel.status == currActivity()!!.getString(R.string.status_releasing)
val isUserScored = mediaModel.userScore != 0 val isUserScored = mediaModel.userScore != 0
val watchedEpisodes = (mediaModel.userProgress ?: "~").toString() val watchedEpisodes = (mediaModel.userProgress ?: "~").toString()
val totalEpisode = if (mediaModel.anime?.nextAiringEpisode != null) (mediaModel.anime.nextAiringEpisode.toString() + " | " + (mediaModel.anime.totalEpisodes ?: "~").toString()) else (mediaModel.anime?.totalEpisodes ?: "~").toString() val totalEpisode =
if (mediaModel.anime?.nextAiringEpisode != null) (mediaModel.anime.nextAiringEpisode.toString() + " | " + (mediaModel.anime.totalEpisodes
?: "~").toString()) else (mediaModel.anime?.totalEpisodes ?: "~").toString()
val chapters = " Chapters" val chapters = " Chapters"
val totalEpisodesList = if (mediaModel.anime?.nextAiringEpisode != null) (mediaModel.anime.nextAiringEpisode.toString()) else (mediaModel.anime?.totalEpisodes ?: "~").toString() val totalEpisodesList =
if (mediaModel.anime?.nextAiringEpisode != null) (mediaModel.anime.nextAiringEpisode.toString()) else (mediaModel.anime?.totalEpisodes
?: "~").toString()
return OfflineAnimeModel( return OfflineAnimeModel(
title, title,
score, score,

View file

@ -1,7 +1,8 @@
package ani.dantotsu.download.anime package ani.dantotsu.download.anime
import android.net.Uri import android.net.Uri
data class OfflineAnimeModel (
data class OfflineAnimeModel(
val title: String, val title: String,
val score: String, val score: String,
val totalEpisode: String, val totalEpisode: String,

View file

@ -171,11 +171,13 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
gridView.scheduleLayoutAnimation() gridView.scheduleLayoutAnimation()
grid() grid()
val total = view.findViewById<TextView>(R.id.total) val total = view.findViewById<TextView>(R.id.total)
total.text = if (gridView.count > 0) "Manga and Novels (${gridView.count})" else "Empty List" total.text =
if (gridView.count > 0) "Manga and Novels (${gridView.count})" else "Empty List"
return view return view
} }
private fun grid(){
private fun grid() {
gridView.setOnItemClickListener { parent, view, position, id -> gridView.setOnItemClickListener { parent, view, position, id ->
// Get the OfflineMangaModel that was clicked // Get the OfflineMangaModel that was clicked
val item = adapter.getItem(position) as OfflineMangaModel val item = adapter.getItem(position) as OfflineMangaModel
@ -220,6 +222,7 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
true true
} }
} }
override fun onSearchQuery(query: String) { override fun onSearchQuery(query: String) {
adapter.onSearchQuery(query) adapter.onSearchQuery(query)
} }
@ -243,7 +246,8 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
} }
} }
val scrollTop = view.findViewById<CardView>(R.id.mangaPageScrollTop) val scrollTop = view.findViewById<CardView>(R.id.mangaPageScrollTop)
scrollTop.translationY = -(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat() scrollTop.translationY =
-(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat()
val visible = false val visible = false
fun animate() { fun animate() {

View file

@ -1,7 +1,6 @@
package ani.dantotsu.home package ani.dantotsu.home
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.drawable.Animatable import android.graphics.drawable.Animatable
import android.os.Build import android.os.Build

View file

@ -140,6 +140,7 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
fun updateHeight() { fun updateHeight() {
trendingViewPager!!.updateLayoutParams { height += statusBarHeight } trendingViewPager!!.updateLayoutParams { height += statusBarHeight }
} }
fun updateTrending(adaptor: MediaAdaptor) { fun updateTrending(adaptor: MediaAdaptor) {
binding.mangaTrendingProgressBar.visibility = View.GONE binding.mangaTrendingProgressBar.visibility = View.GONE
binding.mangaTrendingViewPager.adapter = adaptor binding.mangaTrendingViewPager.adapter = adaptor

View file

@ -1,24 +1,19 @@
package ani.dantotsu.media package ani.dantotsu.media
import android.app.Activity import android.app.Activity
import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import androidx.annotation.OptIn
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.media3.common.util.UnstableApi
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.currActivity
import ani.dantotsu.currContext import ani.dantotsu.currContext
import ani.dantotsu.loadData import ani.dantotsu.loadData
import ani.dantotsu.logger import ani.dantotsu.logger
import ani.dantotsu.media.anime.Episode import ani.dantotsu.media.anime.Episode
import ani.dantotsu.media.anime.ExoplayerView
import ani.dantotsu.media.anime.SelectorDialogFragment import ani.dantotsu.media.anime.SelectorDialogFragment
import ani.dantotsu.media.manga.MangaChapter import ani.dantotsu.media.manga.MangaChapter
import ani.dantotsu.others.AniSkip import ani.dantotsu.others.AniSkip
@ -260,7 +255,12 @@ class MediaDetailsViewModel : ViewModel() {
} }
media.selected = this.loadSelected(media) media.selected = this.loadSelected(media)
val selector = val selector =
SelectorDialogFragment.newInstance(media.selected!!.server, launch, prevEp, isDownload) SelectorDialogFragment.newInstance(
media.selected!!.server,
launch,
prevEp,
isDownload
)
selector.show(manager, "dialog") selector.show(manager, "dialog")
} }
} }

View file

@ -166,11 +166,17 @@ class AnimeWatchFragment : Fragment() {
if (!loaded) { if (!loaded) {
model.watchSources = if (media.isAdult) HAnimeSources else AnimeSources model.watchSources = if (media.isAdult) HAnimeSources else AnimeSources
val offlineMode = model.watchSources!!.isDownloadedSource(media.selected!!.sourceIndex) val offlineMode =
model.watchSources!!.isDownloadedSource(media.selected!!.sourceIndex)
headerAdapter = AnimeWatchAdapter(it, this, model.watchSources!!) headerAdapter = AnimeWatchAdapter(it, this, model.watchSources!!)
episodeAdapter = episodeAdapter =
EpisodeAdapter(style ?: uiSettings.animeDefaultView, media, this, offlineMode = offlineMode) EpisodeAdapter(
style ?: uiSettings.animeDefaultView,
media,
this,
offlineMode = offlineMode
)
binding.animeSourceRecycler.adapter = binding.animeSourceRecycler.adapter =
ConcatAdapter(headerAdapter, episodeAdapter) ConcatAdapter(headerAdapter, episodeAdapter)
@ -421,7 +427,10 @@ class AnimeWatchFragment : Fragment() {
fun onAnimeEpisodeStopDownloadClick(i: String) { fun onAnimeEpisodeStopDownloadClick(i: String) {
val cancelIntent = Intent().apply { val cancelIntent = Intent().apply {
action = AnimeDownloaderService.ACTION_CANCEL_DOWNLOAD action = AnimeDownloaderService.ACTION_CANCEL_DOWNLOAD
putExtra(AnimeDownloaderService.EXTRA_TASK_NAME, AnimeDownloaderService.AnimeDownloadTask.getTaskName(media.mainName(), i)) putExtra(
AnimeDownloaderService.EXTRA_TASK_NAME,
AnimeDownloaderService.AnimeDownloadTask.getTaskName(media.mainName(), i)
)
} }
requireContext().sendBroadcast(cancelIntent) requireContext().sendBroadcast(cancelIntent)
@ -447,12 +456,12 @@ class AnimeWatchFragment : Fragment() {
) )
val taskName = AnimeDownloaderService.AnimeDownloadTask.getTaskName(media.mainName(), i) val taskName = AnimeDownloaderService.AnimeDownloadTask.getTaskName(media.mainName(), i)
val id = requireContext().getSharedPreferences( val id = requireContext().getSharedPreferences(
ContextCompat.getString(requireContext(), R.string.anime_downloads), ContextCompat.getString(requireContext(), R.string.anime_downloads),
Context.MODE_PRIVATE Context.MODE_PRIVATE
).getString( ).getString(
taskName, taskName,
"" ""
) ?: "" ) ?: ""
requireContext().getSharedPreferences( requireContext().getSharedPreferences(
ContextCompat.getString(requireContext(), R.string.anime_downloads), ContextCompat.getString(requireContext(), R.string.anime_downloads),
Context.MODE_PRIVATE Context.MODE_PRIVATE

View file

@ -75,7 +75,6 @@ import ani.dantotsu.media.MediaDetailsViewModel
import ani.dantotsu.media.SubtitleDownloader import ani.dantotsu.media.SubtitleDownloader
import ani.dantotsu.others.AniSkip import ani.dantotsu.others.AniSkip
import ani.dantotsu.others.AniSkip.getType import ani.dantotsu.others.AniSkip.getType
import ani.dantotsu.others.Download.download
import ani.dantotsu.others.LangSet import ani.dantotsu.others.LangSet
import ani.dantotsu.others.ResettableTimer import ani.dantotsu.others.ResettableTimer
import ani.dantotsu.others.getSerialized import ani.dantotsu.others.getSerialized

View file

@ -6,7 +6,6 @@ import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.util.TypedValue import android.util.TypedValue
import android.view.HapticFeedbackConstants import android.view.HapticFeedbackConstants
import android.view.LayoutInflater import android.view.LayoutInflater

View file

@ -7,9 +7,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import ani.dantotsu.App
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.currContext
import ani.dantotsu.databinding.FragmentOfflineBinding import ani.dantotsu.databinding.FragmentOfflineBinding
import ani.dantotsu.isOnline import ani.dantotsu.isOnline
import ani.dantotsu.navBarHeight import ani.dantotsu.navBarHeight

View file

@ -169,7 +169,8 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
} catch (e: Exception) { } catch (e: Exception) {
sourceLanguage = 0 sourceLanguage = 0
extension.sources[sourceLanguage] extension.sources[sourceLanguage]
} as? AnimeHttpSource ?: (extension.sources[sourceLanguage] as? AnimeCatalogueSource ?: return emptyList()) } as? AnimeHttpSource ?: (extension.sources[sourceLanguage] as? AnimeCatalogueSource
?: return emptyList())
return try { return try {
val res = source.fetchSearchAnime(1, query, source.getFilterList()).awaitSingle() val res = source.fetchSearchAnime(1, query, source.getFilterList()).awaitSingle()
logger("query: $query") logger("query: $query")

View file

@ -11,9 +11,10 @@ class NotificationClickReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) { override fun onReceive(context: Context, intent: Intent?) {
context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit() context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit()
.putBoolean("incognito", false) .putBoolean("incognito", false)
.apply() .apply()
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(INCOGNITO_CHANNEL_ID) notificationManager.cancel(INCOGNITO_CHANNEL_ID)
} }

View file

@ -4,7 +4,6 @@ import android.app.Activity
import android.content.Context import android.content.Context
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.Bitmap import android.graphics.Bitmap
import android.os.Build
import android.view.Window import android.view.Window
import android.view.WindowManager import android.view.WindowManager
import ani.dantotsu.R import ani.dantotsu.R
@ -72,7 +71,7 @@ class ThemeManager(private val context: Activity) {
} else { } else {
winParams.flags = winParams.flags and bits.inv() winParams.flags = winParams.flags and bits.inv()
} }
win.setAttributes(winParams) win.attributes = winParams
} }
private fun applyDynamicColors( private fun applyDynamicColors(

View file

@ -20,7 +20,10 @@ class BasePreferences(
fun acraEnabled() = preferenceStore.getBoolean("acra.enable", true) fun acraEnabled() = preferenceStore.getBoolean("acra.enable", true)
fun deviceHasPip() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && context.packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) fun deviceHasPip() =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && context.packageManager.hasSystemFeature(
PackageManager.FEATURE_PICTURE_IN_PICTURE
)
enum class ExtensionInstaller(val titleResId: String) { enum class ExtensionInstaller(val titleResId: String) {
LEGACY("Legacy"), LEGACY("Legacy"),

View file

@ -1,8 +1,8 @@
package eu.kanade.domain.base package eu.kanade.domain.base
import android.content.Context import android.content.Context
import eu.kanade.tachiyomi.util.system.hasMiuiPackageInstaller
import eu.kanade.domain.base.BasePreferences.ExtensionInstaller import eu.kanade.domain.base.BasePreferences.ExtensionInstaller
import eu.kanade.tachiyomi.util.system.hasMiuiPackageInstaller
import eu.kanade.tachiyomi.util.system.isShizukuInstalled import eu.kanade.tachiyomi.util.system.isShizukuInstalled
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import tachiyomi.core.preference.Preference import tachiyomi.core.preference.Preference
@ -19,14 +19,14 @@ class ExtensionInstallerPreference(
override fun key() = "extension_installer" override fun key() = "extension_installer"
val entries
val entries get() = BasePreferences.ExtensionInstaller.values().run { get() = ExtensionInstaller.values().run {
if (context.hasMiuiPackageInstaller) { if (context.hasMiuiPackageInstaller) {
filter { it != BasePreferences.ExtensionInstaller.PACKAGEINSTALLER } filter { it != ExtensionInstaller.PACKAGEINSTALLER }
} else { } else {
toList() toList()
}
} }
}
override fun defaultValue() = if (context.hasMiuiPackageInstaller) { override fun defaultValue() = if (context.hasMiuiPackageInstaller) {
ExtensionInstaller.LEGACY ExtensionInstaller.LEGACY
@ -39,9 +39,11 @@ class ExtensionInstallerPreference(
ExtensionInstaller.PACKAGEINSTALLER -> { ExtensionInstaller.PACKAGEINSTALLER -> {
if (context.hasMiuiPackageInstaller) return ExtensionInstaller.LEGACY if (context.hasMiuiPackageInstaller) return ExtensionInstaller.LEGACY
} }
ExtensionInstaller.SHIZUKU -> { ExtensionInstaller.SHIZUKU -> {
if (!context.isShizukuInstalled) return defaultValue() if (!context.isShizukuInstalled) return defaultValue()
} }
else -> {} else -> {}
} }
return value return value

View file

@ -1,3 +1,4 @@
NOTICE NOTICE
This software includes code modified from Aniyomi, available at https://github.com/aniyomiorg/aniyomi/. This software includes code modified from Aniyomi, available
at https://github.com/aniyomiorg/aniyomi/.

View file

@ -38,9 +38,6 @@ open class Video(
@Transient @Transient
@Volatile @Volatile
var status: State = State.QUEUE var status: State = State.QUEUE
set(value) {
field = value
}
@Transient @Transient
private val _progressFlow = MutableStateFlow(0) private val _progressFlow = MutableStateFlow(0)

View file

@ -69,7 +69,11 @@ sealed class AndroidPreference<T>(
key: String, key: String,
defaultValue: String, defaultValue: String,
) : AndroidPreference<String>(preferences, keyFlow, key, defaultValue) { ) : AndroidPreference<String>(preferences, keyFlow, key, defaultValue) {
override fun read(preferences: SharedPreferences, key: String, defaultValue: String): String { override fun read(
preferences: SharedPreferences,
key: String,
defaultValue: String
): String {
return try { return try {
preferences.getString(key, defaultValue) ?: defaultValue preferences.getString(key, defaultValue) ?: defaultValue
} catch (e: ClassCastException) { } catch (e: ClassCastException) {
@ -145,7 +149,11 @@ sealed class AndroidPreference<T>(
key: String, key: String,
defaultValue: Boolean, defaultValue: Boolean,
) : AndroidPreference<Boolean>(preferences, keyFlow, key, defaultValue) { ) : AndroidPreference<Boolean>(preferences, keyFlow, key, defaultValue) {
override fun read(preferences: SharedPreferences, key: String, defaultValue: Boolean): Boolean { override fun read(
preferences: SharedPreferences,
key: String,
defaultValue: Boolean
): Boolean {
return try { return try {
preferences.getBoolean(key, defaultValue) preferences.getBoolean(key, defaultValue)
} catch (e: ClassCastException) { } catch (e: ClassCastException) {
@ -164,7 +172,11 @@ sealed class AndroidPreference<T>(
key: String, key: String,
defaultValue: Set<String>, defaultValue: Set<String>,
) : AndroidPreference<Set<String>>(preferences, keyFlow, key, defaultValue) { ) : AndroidPreference<Set<String>>(preferences, keyFlow, key, defaultValue) {
override fun read(preferences: SharedPreferences, key: String, defaultValue: Set<String>): Set<String> { override fun read(
preferences: SharedPreferences,
key: String,
defaultValue: Set<String>
): Set<String> {
return try { return try {
preferences.getStringSet(key, defaultValue) ?: defaultValue preferences.getStringSet(key, defaultValue) ?: defaultValue
} catch (e: ClassCastException) { } catch (e: ClassCastException) {

View file

@ -68,7 +68,8 @@ class AndroidPreferenceStore(
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
private val SharedPreferences.keyFlow private val SharedPreferences.keyFlow
get() = callbackFlow { get() = callbackFlow {
val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key: String? -> trySend(key) } val listener =
SharedPreferences.OnSharedPreferenceChangeListener { _, key: String? -> trySend(key) }
registerOnSharedPreferenceChangeListener(listener) registerOnSharedPreferenceChangeListener(listener)
awaitClose { awaitClose {
unregisterOnSharedPreferenceChangeListener(listener) unregisterOnSharedPreferenceChangeListener(listener)

View file

@ -1,37 +1,16 @@
package tachiyomi.core.util.system package tachiyomi.core.util.system
import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources import android.content.res.Resources
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.BitmapRegionDecoder
import android.graphics.Color
import android.graphics.Matrix import android.graphics.Matrix
import android.graphics.Rect import android.graphics.Rect
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.webkit.MimeTypeMap
import androidx.annotation.ColorInt
import androidx.core.graphics.alpha
import androidx.core.graphics.applyCanvas import androidx.core.graphics.applyCanvas
import androidx.core.graphics.blue
import androidx.core.graphics.createBitmap import androidx.core.graphics.createBitmap
import androidx.core.graphics.get
import androidx.core.graphics.green
import androidx.core.graphics.red
import com.hippo.unifile.UniFile
import logcat.LogPriority
import java.io.BufferedInputStream
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.InputStream import java.io.InputStream
import java.net.URLConnection
import kotlin.math.abs
import kotlin.math.max import kotlin.math.max
import kotlin.math.min
object ImageUtil { object ImageUtil {

View file

@ -6,6 +6,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import ani.dantotsu.MainActivity import ani.dantotsu.MainActivity
import eu.kanade.tachiyomi.core.Constants import eu.kanade.tachiyomi.core.Constants
/** /**
* Global [BroadcastReceiver] that runs on UI thread * Global [BroadcastReceiver] that runs on UI thread
* Pending Broadcasts should be made from here. * Pending Broadcasts should be made from here.
@ -28,7 +29,12 @@ class NotificationReceiver {
action = Constants.SHORTCUT_EXTENSIONS action = Constants.SHORTCUT_EXTENSIONS
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
} }
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) return PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
} }

View file

@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.extension.anime.util.AnimeExtensionInstallReceiver
import eu.kanade.tachiyomi.extension.anime.util.AnimeExtensionInstaller import eu.kanade.tachiyomi.extension.anime.util.AnimeExtensionInstaller
import eu.kanade.tachiyomi.extension.anime.util.AnimeExtensionLoader import eu.kanade.tachiyomi.extension.anime.util.AnimeExtensionLoader
import eu.kanade.tachiyomi.util.preference.plusAssign import eu.kanade.tachiyomi.util.preference.plusAssign
import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
@ -57,20 +56,24 @@ class AnimeExtensionManager(
private val iconMap = mutableMapOf<String, Drawable>() private val iconMap = mutableMapOf<String, Drawable>()
private val _installedAnimeExtensionsFlow = MutableStateFlow(emptyList<AnimeExtension.Installed>()) private val _installedAnimeExtensionsFlow =
MutableStateFlow(emptyList<AnimeExtension.Installed>())
val installedExtensionsFlow = _installedAnimeExtensionsFlow.asStateFlow() val installedExtensionsFlow = _installedAnimeExtensionsFlow.asStateFlow()
private var subLanguagesEnabledOnFirstRun = preferences.enabledLanguages().isSet() private var subLanguagesEnabledOnFirstRun = preferences.enabledLanguages().isSet()
fun getAppIconForSource(sourceId: Long): Drawable? { fun getAppIconForSource(sourceId: Long): Drawable? {
val pkgName = _installedAnimeExtensionsFlow.value.find { ext -> ext.sources.any { it.id == sourceId } }?.pkgName val pkgName =
_installedAnimeExtensionsFlow.value.find { ext -> ext.sources.any { it.id == sourceId } }?.pkgName
if (pkgName != null) { if (pkgName != null) {
return iconMap[pkgName] ?: iconMap.getOrPut(pkgName) { context.packageManager.getApplicationIcon(pkgName) } return iconMap[pkgName]
?: iconMap.getOrPut(pkgName) { context.packageManager.getApplicationIcon(pkgName) }
} }
return null return null
} }
private val _availableAnimeExtensionsFlow = MutableStateFlow(emptyList<AnimeExtension.Available>()) private val _availableAnimeExtensionsFlow =
MutableStateFlow(emptyList<AnimeExtension.Available>())
val availableExtensionsFlow = _availableAnimeExtensionsFlow.asStateFlow() val availableExtensionsFlow = _availableAnimeExtensionsFlow.asStateFlow()
private var availableAnimeExtensionsSourcesData: Map<Long, AnimeSourceData> = emptyMap() private var availableAnimeExtensionsSourcesData: Map<Long, AnimeSourceData> = emptyMap()
@ -84,7 +87,8 @@ class AnimeExtensionManager(
fun getSourceData(id: Long) = availableAnimeExtensionsSourcesData[id] fun getSourceData(id: Long) = availableAnimeExtensionsSourcesData[id]
private val _untrustedAnimeExtensionsFlow = MutableStateFlow(emptyList<AnimeExtension.Untrusted>()) private val _untrustedAnimeExtensionsFlow =
MutableStateFlow(emptyList<AnimeExtension.Untrusted>())
val untrustedExtensionsFlow = _untrustedAnimeExtensionsFlow.asStateFlow() val untrustedExtensionsFlow = _untrustedAnimeExtensionsFlow.asStateFlow()
init { init {
@ -213,8 +217,9 @@ class AnimeExtensionManager(
* @param extension The anime extension to be updated. * @param extension The anime extension to be updated.
*/ */
fun updateExtension(extension: AnimeExtension.Installed): Observable<InstallStep> { fun updateExtension(extension: AnimeExtension.Installed): Observable<InstallStep> {
val availableExt = _availableAnimeExtensionsFlow.value.find { it.pkgName == extension.pkgName } val availableExt =
?: return Observable.empty() _availableAnimeExtensionsFlow.value.find { it.pkgName == extension.pkgName }
?: return Observable.empty()
return installExtension(availableExt) return installExtension(availableExt)
} }
@ -251,20 +256,27 @@ class AnimeExtensionManager(
* @param signature The signature to whitelist. * @param signature The signature to whitelist.
*/ */
fun trustSignature(signature: String) { fun trustSignature(signature: String) {
val untrustedSignatures = _untrustedAnimeExtensionsFlow.value.map { it.signatureHash }.toSet() val untrustedSignatures =
_untrustedAnimeExtensionsFlow.value.map { it.signatureHash }.toSet()
if (signature !in untrustedSignatures) return if (signature !in untrustedSignatures) return
AnimeExtensionLoader.trustedSignatures += signature AnimeExtensionLoader.trustedSignatures += signature
preferences.trustedSignatures() += signature preferences.trustedSignatures() += signature
val nowTrustedAnimeExtensions = _untrustedAnimeExtensionsFlow.value.filter { it.signatureHash == signature } val nowTrustedAnimeExtensions =
_untrustedAnimeExtensionsFlow.value.filter { it.signatureHash == signature }
_untrustedAnimeExtensionsFlow.value -= nowTrustedAnimeExtensions _untrustedAnimeExtensionsFlow.value -= nowTrustedAnimeExtensions
val ctx = context val ctx = context
launchNow { launchNow {
nowTrustedAnimeExtensions nowTrustedAnimeExtensions
.map { animeextension -> .map { animeextension ->
async { AnimeExtensionLoader.loadExtensionFromPkgName(ctx, animeextension.pkgName) } async {
AnimeExtensionLoader.loadExtensionFromPkgName(
ctx,
animeextension.pkgName
)
}
} }
.map { it.await() } .map { it.await() }
.forEach { result -> .forEach { result ->
@ -307,11 +319,13 @@ class AnimeExtensionManager(
* @param pkgName The package name of the uninstalled application. * @param pkgName The package name of the uninstalled application.
*/ */
private fun unregisterAnimeExtension(pkgName: String) { private fun unregisterAnimeExtension(pkgName: String) {
val installedAnimeExtension = _installedAnimeExtensionsFlow.value.find { it.pkgName == pkgName } val installedAnimeExtension =
_installedAnimeExtensionsFlow.value.find { it.pkgName == pkgName }
if (installedAnimeExtension != null) { if (installedAnimeExtension != null) {
_installedAnimeExtensionsFlow.value -= installedAnimeExtension _installedAnimeExtensionsFlow.value -= installedAnimeExtension
} }
val untrustedAnimeExtension = _untrustedAnimeExtensionsFlow.value.find { it.pkgName == pkgName } val untrustedAnimeExtension =
_untrustedAnimeExtensionsFlow.value.find { it.pkgName == pkgName }
if (untrustedAnimeExtension != null) { if (untrustedAnimeExtension != null) {
_untrustedAnimeExtensionsFlow.value -= untrustedAnimeExtension _untrustedAnimeExtensionsFlow.value -= untrustedAnimeExtension
} }
@ -354,13 +368,15 @@ class AnimeExtensionManager(
} }
private fun AnimeExtension.Installed.updateExists(availableAnimeExtension: AnimeExtension.Available? = null): Boolean { private fun AnimeExtension.Installed.updateExists(availableAnimeExtension: AnimeExtension.Available? = null): Boolean {
val availableExt = availableAnimeExtension ?: _availableAnimeExtensionsFlow.value.find { it.pkgName == pkgName } val availableExt = availableAnimeExtension
?: _availableAnimeExtensionsFlow.value.find { it.pkgName == pkgName }
if (isUnofficial || availableExt == null) return false if (isUnofficial || availableExt == null) return false
return (availableExt.versionCode > versionCode || availableExt.libVersion > libVersion) return (availableExt.versionCode > versionCode || availableExt.libVersion > libVersion)
} }
private fun updatePendingUpdatesCount() { private fun updatePendingUpdatesCount() {
preferences.animeExtensionUpdatesCount().set(_installedAnimeExtensionsFlow.value.count { it.hasUpdate }) preferences.animeExtensionUpdatesCount()
.set(_installedAnimeExtensionsFlow.value.count { it.hasUpdate })
} }
} }

View file

@ -73,7 +73,10 @@ internal class AnimeExtensionGithubApi {
} }
} }
suspend fun checkForUpdates(context: Context, fromAvailableExtensionList: Boolean = false): List<AnimeExtension.Installed>? { suspend fun checkForUpdates(
context: Context,
fromAvailableExtensionList: Boolean = false
): List<AnimeExtension.Installed>? {
// Limit checks to once a day at most // Limit checks to once a day at most
if (fromAvailableExtensionList && Date().time < lastExtCheck.get() + 1.days.inWholeMilliseconds) { if (fromAvailableExtensionList && Date().time < lastExtCheck.get() + 1.days.inWholeMilliseconds) {
return null return null
@ -161,8 +164,10 @@ private fun AnimeExtensionJsonObject.extractLibVersion(): Double {
return version.substringBeforeLast('.').toDouble() return version.substringBeforeLast('.').toDouble()
} }
private const val REPO_URL_PREFIX = "https://raw.githubusercontent.com/aniyomiorg/aniyomi-extensions/repo/" private const val REPO_URL_PREFIX =
private const val FALLBACK_REPO_URL_PREFIX = "https://gcore.jsdelivr.net/gh/aniyomiorg/aniyomi-extensions@repo/" "https://raw.githubusercontent.com/aniyomiorg/aniyomi-extensions/repo/"
private const val FALLBACK_REPO_URL_PREFIX =
"https://gcore.jsdelivr.net/gh/aniyomiorg/aniyomi-extensions@repo/"
@Serializable @Serializable
private data class AnimeExtensionJsonObject( private data class AnimeExtensionJsonObject(

View file

@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.extension.anime.util
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.others.LangSet import ani.dantotsu.others.LangSet
import ani.dantotsu.themes.ThemeManager
import eu.kanade.tachiyomi.extension.InstallStep import eu.kanade.tachiyomi.extension.InstallStep
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
import eu.kanade.tachiyomi.util.system.hasMiuiPackageInstaller import eu.kanade.tachiyomi.util.system.hasMiuiPackageInstaller
@ -27,7 +27,7 @@ class AnimeExtensionInstallActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
LangSet.setLocale(this) LangSet.setLocale(this)
ThemeManager(this).applyTheme() ThemeManager(this).applyTheme()
val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE) val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE)
.setDataAndType(intent.data, intent.type) .setDataAndType(intent.data, intent.type)

View file

@ -62,6 +62,7 @@ internal class AnimeExtensionInstallReceiver(private val listener: Listener) :
} }
} }
} }
Intent.ACTION_PACKAGE_REPLACED -> { Intent.ACTION_PACKAGE_REPLACED -> {
launchNow { launchNow {
when (val result = getExtensionFromIntent(context, intent)) { when (val result = getExtensionFromIntent(context, intent)) {
@ -72,6 +73,7 @@ internal class AnimeExtensionInstallReceiver(private val listener: Listener) :
} }
} }
} }
Intent.ACTION_PACKAGE_REMOVED -> { Intent.ACTION_PACKAGE_REMOVED -> {
if (isReplacing(intent)) return if (isReplacing(intent)) return

View file

@ -77,7 +77,11 @@ internal class AnimeExtensionInstaller(private val context: Context) {
val request = DownloadManager.Request(downloadUri) val request = DownloadManager.Request(downloadUri)
.setTitle(extension.name) .setTitle(extension.name)
.setMimeType(APK_MIME) .setMimeType(APK_MIME)
.setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, downloadUri.lastPathSegment) .setDestinationInExternalFilesDir(
context,
Environment.DIRECTORY_DOWNLOADS,
downloadUri.lastPathSegment
)
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
val id = downloadManager.enqueue(request) val id = downloadManager.enqueue(request)
@ -144,6 +148,7 @@ internal class AnimeExtensionInstaller(private val context: Context) {
context.startActivity(intent) context.startActivity(intent)
} }
else -> { else -> {
val intent = val intent =
AnimeExtensionInstallService.getIntent(context, downloadId, uri, installer) AnimeExtensionInstallService.getIntent(context, downloadId, uri, installer)

View file

@ -73,7 +73,10 @@ internal class MangaExtensionGithubApi {
} }
} }
suspend fun checkForUpdates(context: Context, fromAvailableExtensionList: Boolean = false): List<MangaExtension.Installed>? { suspend fun checkForUpdates(
context: Context,
fromAvailableExtensionList: Boolean = false
): List<MangaExtension.Installed>? {
// Limit checks to once a day at most // Limit checks to once a day at most
if (fromAvailableExtensionList && Date().time < lastExtCheck.get() + 1.days.inWholeMilliseconds) { if (fromAvailableExtensionList && Date().time < lastExtCheck.get() + 1.days.inWholeMilliseconds) {
return null return null
@ -161,7 +164,8 @@ internal class MangaExtensionGithubApi {
} }
private const val REPO_URL_PREFIX = "https://raw.githubusercontent.com/keiyoushi/extensions/main/" private const val REPO_URL_PREFIX = "https://raw.githubusercontent.com/keiyoushi/extensions/main/"
private const val FALLBACK_REPO_URL_PREFIX = "https://gcore.jsdelivr.net/gh/keiyoushi/extensions@main/" private const val FALLBACK_REPO_URL_PREFIX =
"https://gcore.jsdelivr.net/gh/keiyoushi/extensions@main/"
@Serializable @Serializable
private data class ExtensionJsonObject( private data class ExtensionJsonObject(

View file

@ -23,7 +23,10 @@ class PackageInstallerInstallerManga(private val service: Service) : InstallerMa
private val packageActionReceiver = object : BroadcastReceiver() { private val packageActionReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
when (intent.getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE)) { when (intent.getIntExtra(
PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE
)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> { PackageInstaller.STATUS_PENDING_USER_ACTION -> {
val userAction = intent.getParcelableExtraCompat<Intent>(Intent.EXTRA_INTENT) val userAction = intent.getParcelableExtraCompat<Intent>(Intent.EXTRA_INTENT)
if (userAction == null) { if (userAction == null) {
@ -34,9 +37,11 @@ class PackageInstallerInstallerManga(private val service: Service) : InstallerMa
userAction.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) userAction.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
service.startActivity(userAction) service.startActivity(userAction)
} }
PackageInstaller.STATUS_FAILURE_ABORTED -> { PackageInstaller.STATUS_FAILURE_ABORTED -> {
continueQueue(InstallStep.Idle) continueQueue(InstallStep.Idle)
} }
PackageInstaller.STATUS_SUCCESS -> continueQueue(InstallStep.Installed) PackageInstaller.STATUS_SUCCESS -> continueQueue(InstallStep.Installed)
else -> continueQueue(InstallStep.Error) else -> continueQueue(InstallStep.Error)
} }
@ -52,7 +57,8 @@ class PackageInstallerInstallerManga(private val service: Service) : InstallerMa
super.processEntry(entry) super.processEntry(entry)
activeSession = null activeSession = null
try { try {
val installParams = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL) val installParams =
PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
installParams.setRequireUserAction(PackageInstaller.SessionParams.USER_ACTION_NOT_REQUIRED) installParams.setRequireUserAction(PackageInstaller.SessionParams.USER_ACTION_NOT_REQUIRED)
} }
@ -60,7 +66,8 @@ class PackageInstallerInstallerManga(private val service: Service) : InstallerMa
val fileSize = service.getUriSize(entry.uri) ?: throw IllegalStateException() val fileSize = service.getUriSize(entry.uri) ?: throw IllegalStateException()
installParams.setSize(fileSize) installParams.setSize(fileSize)
val inputStream = service.contentResolver.openInputStream(entry.uri) ?: throw IllegalStateException() val inputStream =
service.contentResolver.openInputStream(entry.uri) ?: throw IllegalStateException()
val session = packageInstaller.openSession(activeSession!!.second) val session = packageInstaller.openSession(activeSession!!.second)
val outputStream = session.openWrite(entry.downloadId.toString(), 0, fileSize) val outputStream = session.openWrite(entry.downloadId.toString(), 0, fileSize)
session.use { session.use {
@ -108,7 +115,12 @@ class PackageInstallerInstallerManga(private val service: Service) : InstallerMa
} }
init { init {
ContextCompat.registerReceiver(service, packageActionReceiver, IntentFilter(INSTALL_ACTION), ContextCompat.RECEIVER_EXPORTED) ContextCompat.registerReceiver(
service,
packageActionReceiver,
IntentFilter(INSTALL_ACTION),
ContextCompat.RECEIVER_EXPORTED
)
} }
} }

View file

@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.extension.manga.util
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.others.LangSet import ani.dantotsu.others.LangSet
import ani.dantotsu.themes.ThemeManager
import eu.kanade.tachiyomi.extension.InstallStep import eu.kanade.tachiyomi.extension.InstallStep
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
import eu.kanade.tachiyomi.util.system.hasMiuiPackageInstaller import eu.kanade.tachiyomi.util.system.hasMiuiPackageInstaller
@ -27,7 +27,7 @@ class MangaExtensionInstallActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
LangSet.setLocale(this) LangSet.setLocale(this)
ThemeManager(this).applyTheme() ThemeManager(this).applyTheme()
val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE) val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE)
.setDataAndType(intent.data, intent.type) .setDataAndType(intent.data, intent.type)

View file

@ -62,6 +62,7 @@ internal class MangaExtensionInstallReceiver(private val listener: Listener) :
} }
} }
} }
Intent.ACTION_PACKAGE_REPLACED -> { Intent.ACTION_PACKAGE_REPLACED -> {
launchNow { launchNow {
when (val result = getExtensionFromIntent(context, intent)) { when (val result = getExtensionFromIntent(context, intent)) {
@ -72,6 +73,7 @@ internal class MangaExtensionInstallReceiver(private val listener: Listener) :
} }
} }
} }
Intent.ACTION_PACKAGE_REMOVED -> { Intent.ACTION_PACKAGE_REMOVED -> {
if (isReplacing(intent)) return if (isReplacing(intent)) return

View file

@ -3,9 +3,7 @@ package eu.kanade.tachiyomi.extension.manga.util
import android.app.Service import android.app.Service
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ServiceInfo import android.content.pm.ServiceInfo
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.IBinder import android.os.IBinder
@ -34,8 +32,12 @@ class MangaExtensionInstallService : Service() {
setProgress(100, 100, true) setProgress(100, 100, true)
}.build() }.build()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(Notifications.ID_EXTENSION_INSTALLER, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC) startForeground(
}else{ Notifications.ID_EXTENSION_INSTALLER,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
)
} else {
startForeground(Notifications.ID_EXTENSION_INSTALLER, notification) startForeground(Notifications.ID_EXTENSION_INSTALLER, notification)
} }
} }
@ -53,7 +55,10 @@ class MangaExtensionInstallService : Service() {
if (installer == null) { if (installer == null) {
installer = when (installerUsed) { installer = when (installerUsed) {
BasePreferences.ExtensionInstaller.PACKAGEINSTALLER -> PackageInstallerInstallerManga(this) BasePreferences.ExtensionInstaller.PACKAGEINSTALLER -> PackageInstallerInstallerManga(
this
)
else -> { else -> {
logcat(LogPriority.ERROR) { "Not implemented for installer $installerUsed" } logcat(LogPriority.ERROR) { "Not implemented for installer $installerUsed" }
stopSelf() stopSelf()

View file

@ -41,15 +41,18 @@ internal object MangaExtensionLoader {
const val LIB_VERSION_MIN = 1.2 const val LIB_VERSION_MIN = 1.2
const val LIB_VERSION_MAX = 1.5 const val LIB_VERSION_MAX = 1.5
private const val PACKAGE_FLAGS = PackageManager.GET_CONFIGURATIONS or PackageManager.GET_SIGNATURES private const val PACKAGE_FLAGS =
PackageManager.GET_CONFIGURATIONS or PackageManager.GET_SIGNATURES
// inorichi's key // inorichi's key
private const val officialSignature = "7ce04da7773d41b489f4693a366c36bcd0a11fc39b547168553c285bd7348e23" private const val officialSignature =
"7ce04da7773d41b489f4693a366c36bcd0a11fc39b547168553c285bd7348e23"
/** /**
* List of the trusted signatures. * List of the trusted signatures.
*/ */
var trustedSignatures = mutableSetOf<String>() + preferences.trustedSignatures().get() + officialSignature var trustedSignatures =
mutableSetOf<String>() + preferences.trustedSignatures().get() + officialSignature
/** /**
* Return a list of all the installed extensions initialized concurrently. * Return a list of all the installed extensions initialized concurrently.
@ -105,7 +108,11 @@ internal object MangaExtensionLoader {
* @param pkgName The package name of the extension to load. * @param pkgName The package name of the extension to load.
* @param pkgInfo The package info of the extension. * @param pkgInfo The package info of the extension.
*/ */
private fun loadMangaExtension(context: Context, pkgName: String, pkgInfo: PackageInfo): MangaLoadResult { private fun loadMangaExtension(
context: Context,
pkgName: String,
pkgInfo: PackageInfo
): MangaLoadResult {
val pkgManager = context.packageManager val pkgManager = context.packageManager
val appInfo = try { val appInfo = try {
@ -116,7 +123,8 @@ internal object MangaExtensionLoader {
return MangaLoadResult.Error return MangaLoadResult.Error
} }
val extName = pkgManager.getApplicationLabel(appInfo).toString().substringAfter("Tachiyomi: ") val extName =
pkgManager.getApplicationLabel(appInfo).toString().substringAfter("Tachiyomi: ")
val versionName = pkgInfo.versionName val versionName = pkgInfo.versionName
val versionCode = PackageInfoCompat.getLongVersionCode(pkgInfo) val versionCode = PackageInfoCompat.getLongVersionCode(pkgInfo)
@ -130,7 +138,7 @@ internal object MangaExtensionLoader {
if (libVersion == null || libVersion < LIB_VERSION_MIN || libVersion > LIB_VERSION_MAX) { if (libVersion == null || libVersion < LIB_VERSION_MIN || libVersion > LIB_VERSION_MAX) {
logcat(LogPriority.WARN) { logcat(LogPriority.WARN) {
"Lib version is $libVersion, while only versions " + "Lib version is $libVersion, while only versions " +
"$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed" "$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed"
} }
return MangaLoadResult.Error return MangaLoadResult.Error
} }

View file

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.network
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import ani.dantotsu.Mapper import ani.dantotsu.Mapper
import ani.dantotsu.defaultHeaders
import com.lagradost.nicehttp.Requests import com.lagradost.nicehttp.Requests
import eu.kanade.tachiyomi.network.interceptor.CloudflareInterceptor import eu.kanade.tachiyomi.network.interceptor.CloudflareInterceptor
import eu.kanade.tachiyomi.network.interceptor.UncaughtExceptionInterceptor import eu.kanade.tachiyomi.network.interceptor.UncaughtExceptionInterceptor
@ -31,42 +30,40 @@ class NetworkHelper(
CloudflareInterceptor(context, cookieJar, ::defaultUserAgentProvider) CloudflareInterceptor(context, cookieJar, ::defaultUserAgentProvider)
} }
private fun baseClientBuilder(callTimout: Int = 2): OkHttpClient.Builder private fun baseClientBuilder(callTimout: Int = 2): OkHttpClient.Builder {
{ val builder = OkHttpClient.Builder()
val builder = OkHttpClient.Builder() .cookieJar(cookieJar)
.cookieJar(cookieJar) .connectTimeout(30, TimeUnit.SECONDS)
.connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS) .callTimeout(callTimout.toLong(), TimeUnit.MINUTES)
.callTimeout(callTimout.toLong(), TimeUnit.MINUTES) .addInterceptor(UncaughtExceptionInterceptor())
.addInterceptor(UncaughtExceptionInterceptor()) .addInterceptor(userAgentInterceptor)
.addInterceptor(userAgentInterceptor)
if (preferences.verboseLogging().get()) { if (preferences.verboseLogging().get()) {
val httpLoggingInterceptor = HttpLoggingInterceptor().apply { val httpLoggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.HEADERS level = HttpLoggingInterceptor.Level.HEADERS
}
builder.addNetworkInterceptor(httpLoggingInterceptor)
} }
builder.addNetworkInterceptor(httpLoggingInterceptor)
when (preferences.dohProvider().get()) {
PREF_DOH_CLOUDFLARE -> builder.dohCloudflare()
PREF_DOH_GOOGLE -> builder.dohGoogle()
PREF_DOH_ADGUARD -> builder.dohAdGuard()
PREF_DOH_QUAD9 -> builder.dohQuad9()
PREF_DOH_ALIDNS -> builder.dohAliDNS()
PREF_DOH_DNSPOD -> builder.dohDNSPod()
PREF_DOH_360 -> builder.doh360()
PREF_DOH_QUAD101 -> builder.dohQuad101()
PREF_DOH_MULLVAD -> builder.dohMullvad()
PREF_DOH_CONTROLD -> builder.dohControlD()
PREF_DOH_NJALLA -> builder.dohNajalla()
PREF_DOH_SHECAN -> builder.dohShecan()
PREF_DOH_LIBREDNS -> builder.dohLibreDNS()
}
return builder
} }
when (preferences.dohProvider().get()) {
PREF_DOH_CLOUDFLARE -> builder.dohCloudflare()
PREF_DOH_GOOGLE -> builder.dohGoogle()
PREF_DOH_ADGUARD -> builder.dohAdGuard()
PREF_DOH_QUAD9 -> builder.dohQuad9()
PREF_DOH_ALIDNS -> builder.dohAliDNS()
PREF_DOH_DNSPOD -> builder.dohDNSPod()
PREF_DOH_360 -> builder.doh360()
PREF_DOH_QUAD101 -> builder.dohQuad101()
PREF_DOH_MULLVAD -> builder.dohMullvad()
PREF_DOH_CONTROLD -> builder.dohControlD()
PREF_DOH_NJALLA -> builder.dohNajalla()
PREF_DOH_SHECAN -> builder.dohShecan()
PREF_DOH_LIBREDNS -> builder.dohLibreDNS()
}
return builder
}
val client by lazy { baseClientBuilder().cache(Cache(cacheDir, cacheSize)).build() } val client by lazy { baseClientBuilder().cache(Cache(cacheDir, cacheSize)).build() }
@ -80,15 +77,15 @@ class NetworkHelper(
} }
val requestClient = Requests( val requestClient = Requests(
client, client,
mapOf( mapOf(
"User-Agent" to "User-Agent" to
defaultUserAgentProvider() defaultUserAgentProvider()
.format(Build.VERSION.RELEASE, Build.MODEL) .format(Build.VERSION.RELEASE, Build.MODEL)
), ),
defaultCacheTime = 6, defaultCacheTime = 6,
defaultCacheTimeUnit = TimeUnit.HOURS, defaultCacheTimeUnit = TimeUnit.HOURS,
responseParser = Mapper responseParser = Mapper
) )
fun defaultUserAgentProvider() = preferences.defaultUserAgent().get().trim() fun defaultUserAgentProvider() = preferences.defaultUserAgent().get().trim()

View file

@ -1,7 +1,5 @@
package eu.kanade.tachiyomi.network package eu.kanade.tachiyomi.network
import eu.kanade.tachiyomi.network.ProgressListener
import eu.kanade.tachiyomi.network.ProgressResponseBody
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.DeserializationStrategy

View file

@ -9,7 +9,10 @@ import okio.Source
import okio.buffer import okio.buffer
import java.io.IOException import java.io.IOException
class ProgressResponseBody(private val responseBody: ResponseBody, private val progressListener: ProgressListener) : ResponseBody() { class ProgressResponseBody(
private val responseBody: ResponseBody,
private val progressListener: ProgressListener
) : ResponseBody() {
private val bufferedSource: BufferedSource by lazy { private val bufferedSource: BufferedSource by lazy {
source(responseBody.source()).buffer() source(responseBody.source()).buffer()
@ -36,7 +39,11 @@ class ProgressResponseBody(private val responseBody: ResponseBody, private val p
val bytesRead = super.read(sink, byteCount) val bytesRead = super.read(sink, byteCount)
// read() returns the number of bytes read, or -1 if this source is exhausted. // read() returns the number of bytes read, or -1 if this source is exhausted.
totalBytesRead += if (bytesRead != -1L) bytesRead else 0 totalBytesRead += if (bytesRead != -1L) bytesRead else 0
progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1L) progressListener.update(
totalBytesRead,
responseBody.contentLength(),
bytesRead == -1L
)
return bytesRead return bytesRead
} }
} }

View file

@ -95,7 +95,17 @@ private fun isRequestHeaderSafe(_name: String, _value: String): Boolean {
val name = _name.lowercase(Locale.ENGLISH) val name = _name.lowercase(Locale.ENGLISH)
val value = _value.lowercase(Locale.ENGLISH) val value = _value.lowercase(Locale.ENGLISH)
if (name in unsafeHeaderNames || name.startsWith("proxy-")) return false if (name in unsafeHeaderNames || name.startsWith("proxy-")) return false
if (name == "connection" && value == "upgrade") return false return !(name == "connection" && value == "upgrade")
return true
} }
private val unsafeHeaderNames = listOf("content-length", "host", "trailer", "te", "upgrade", "cookie2", "keep-alive", "transfer-encoding", "set-cookie")
private val unsafeHeaderNames = listOf(
"content-length",
"host",
"trailer",
"te",
"upgrade",
"cookie2",
"keep-alive",
"transfer-encoding",
"set-cookie"
)

View file

@ -33,7 +33,8 @@ interface MangaSource {
"Use the 1.x API instead", "Use the 1.x API instead",
ReplaceWith("getMangaDetails"), ReplaceWith("getMangaDetails"),
) )
fun fetchMangaDetails(manga: SManga): Observable<SManga> = throw IllegalStateException("Not used") fun fetchMangaDetails(manga: SManga): Observable<SManga> =
throw IllegalStateException("Not used")
/** /**
* Returns an observable with all the available chapters for a manga. * Returns an observable with all the available chapters for a manga.
@ -44,7 +45,8 @@ interface MangaSource {
"Use the 1.x API instead", "Use the 1.x API instead",
ReplaceWith("getChapterList"), ReplaceWith("getChapterList"),
) )
fun fetchChapterList(manga: SManga): Observable<List<SChapter>> = throw IllegalStateException("Not used") fun fetchChapterList(manga: SManga): Observable<List<SChapter>> =
throw IllegalStateException("Not used")
/** /**
* Returns an observable with the list of pages a chapter has. Pages should be returned * Returns an observable with the list of pages a chapter has. Pages should be returned

View file

@ -31,7 +31,8 @@ class AndroidAnimeSourceManager(
private val stubSourcesMap = ConcurrentHashMap<Long, StubAnimeSource>() private val stubSourcesMap = ConcurrentHashMap<Long, StubAnimeSource>()
override val catalogueSources: Flow<List<AnimeCatalogueSource>> = sourcesMapFlow.map { it.values.filterIsInstance<AnimeCatalogueSource>() } override val catalogueSources: Flow<List<AnimeCatalogueSource>> =
sourcesMapFlow.map { it.values.filterIsInstance<AnimeCatalogueSource>() }
init { init {
scope.launch { scope.launch {
@ -66,9 +67,11 @@ class AndroidAnimeSourceManager(
} }
} }
override fun getOnlineSources() = sourcesMapFlow.value.values.filterIsInstance<AnimeHttpSource>() override fun getOnlineSources() =
sourcesMapFlow.value.values.filterIsInstance<AnimeHttpSource>()
override fun getCatalogueSources() = sourcesMapFlow.value.values.filterIsInstance<AnimeCatalogueSource>() override fun getCatalogueSources() =
sourcesMapFlow.value.values.filterIsInstance<AnimeCatalogueSource>()
override fun getStubSources(): List<StubAnimeSource> { override fun getStubSources(): List<StubAnimeSource> {
val onlineSourceIds = getOnlineSources().map { it.id } val onlineSourceIds = getOnlineSources().map { it.id }

View file

@ -31,7 +31,8 @@ class AndroidMangaSourceManager(
private val stubSourcesMap = ConcurrentHashMap<Long, StubMangaSource>() private val stubSourcesMap = ConcurrentHashMap<Long, StubMangaSource>()
override val catalogueSources: Flow<List<CatalogueSource>> = sourcesMapFlow.map { it.values.filterIsInstance<CatalogueSource>() } override val catalogueSources: Flow<List<CatalogueSource>> =
sourcesMapFlow.map { it.values.filterIsInstance<CatalogueSource>() }
init { init {
scope.launch { scope.launch {
@ -67,7 +68,8 @@ class AndroidMangaSourceManager(
override fun getOnlineSources() = sourcesMapFlow.value.values.filterIsInstance<HttpSource>() override fun getOnlineSources() = sourcesMapFlow.value.values.filterIsInstance<HttpSource>()
override fun getCatalogueSources() = sourcesMapFlow.value.values.filterIsInstance<CatalogueSource>() override fun getCatalogueSources() =
sourcesMapFlow.value.values.filterIsInstance<CatalogueSource>()
override fun getStubSources(): List<StubMangaSource> { override fun getStubSources(): List<StubMangaSource> {
val onlineSourceIds = getOnlineSources().map { it.id } val onlineSourceIds = getOnlineSources().map { it.id }

View file

@ -3,7 +3,9 @@ package eu.kanade.tachiyomi.source.model
sealed class Filter<T>(val name: String, var state: T) { sealed class Filter<T>(val name: String, var state: T) {
open class Header(name: String) : Filter<Any>(name, 0) open class Header(name: String) : Filter<Any>(name, 0)
open class Separator(name: String = "") : Filter<Any>(name, 0) open class Separator(name: String = "") : Filter<Any>(name, 0)
abstract class Select<V>(name: String, val values: Array<V>, state: Int = 0) : Filter<Int>(name, state) abstract class Select<V>(name: String, val values: Array<V>, state: Int = 0) :
Filter<Int>(name, state)
abstract class Text(name: String, state: String = "") : Filter<String>(name, state) abstract class Text(name: String, state: String = "") : Filter<String>(name, state)
abstract class CheckBox(name: String, state: Boolean = false) : Filter<Boolean>(name, state) abstract class CheckBox(name: String, state: Boolean = false) : Filter<Boolean>(name, state)
abstract class TriState(name: String, state: Int = STATE_IGNORE) : Filter<Int>(name, state) { abstract class TriState(name: String, state: Int = STATE_IGNORE) : Filter<Int>(name, state) {

View file

@ -21,11 +21,10 @@ import androidx.core.graphics.blue
import androidx.core.graphics.green import androidx.core.graphics.green
import androidx.core.graphics.red import androidx.core.graphics.red
import androidx.core.net.toUri import androidx.core.net.toUri
import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.util.lang.truncateCenter import eu.kanade.tachiyomi.util.lang.truncateCenter
import logcat.LogPriority import logcat.LogPriority
import tachiyomi.core.util.system.logcat import tachiyomi.core.util.system.logcat
import ani.dantotsu.toast
import com.hippo.unifile.UniFile
import java.io.File import java.io.File
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -59,7 +58,8 @@ fun Context.copyToClipboard(label: String, content: String) {
* @param permission the permission to check. * @param permission the permission to check.
* @return true if it has permissions. * @return true if it has permissions.
*/ */
fun Context.hasPermission(permission: String) = PermissionChecker.checkSelfPermission(this, permission) == PermissionChecker.PERMISSION_GRANTED fun Context.hasPermission(permission: String) =
PermissionChecker.checkSelfPermission(this, permission) == PermissionChecker.PERMISSION_GRANTED
/** /**
* Returns the color for the given attribute. * Returns the color for the given attribute.
@ -67,7 +67,8 @@ fun Context.hasPermission(permission: String) = PermissionChecker.checkSelfPermi
* @param resource the attribute. * @param resource the attribute.
* @param alphaFactor the alpha number [0,1]. * @param alphaFactor the alpha number [0,1].
*/ */
@ColorInt fun Context.getResourceColor(@AttrRes resource: Int, alphaFactor: Float = 1f): Int { @ColorInt
fun Context.getResourceColor(@AttrRes resource: Int, alphaFactor: Float = 1f): Int {
val typedArray = obtainStyledAttributes(intArrayOf(resource)) val typedArray = obtainStyledAttributes(intArrayOf(resource))
val color = typedArray.getColor(0, 0) val color = typedArray.getColor(0, 0)
typedArray.recycle() typedArray.recycle()
@ -80,7 +81,8 @@ fun Context.hasPermission(permission: String) = PermissionChecker.checkSelfPermi
return color return color
} }
@ColorInt fun Context.getThemeColor(attr: Int): Int { @ColorInt
fun Context.getThemeColor(attr: Int): Int {
val tv = TypedValue() val tv = TypedValue()
return if (this.theme.resolveAttribute(attr, tv, true)) { return if (this.theme.resolveAttribute(attr, tv, true)) {
if (tv.resourceId != 0) { if (tv.resourceId != 0) {
@ -137,7 +139,10 @@ fun Context.openInBrowser(uri: Uri, forceDefaultBrowser: Boolean = false) {
private fun Context.defaultBrowserPackageName(): String? { private fun Context.defaultBrowserPackageName(): String? {
val browserIntent = Intent(Intent.ACTION_VIEW, "http://".toUri()) val browserIntent = Intent(Intent.ACTION_VIEW, "http://".toUri())
val resolveInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val resolveInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
packageManager.resolveActivity(browserIntent, PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())) packageManager.resolveActivity(
browserIntent,
PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())
)
} else { } else {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
packageManager.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY) packageManager.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY)
@ -184,7 +189,6 @@ val Context.hasMiuiPackageInstaller get() = isPackageInstalled("com.miui.package
val Context.isShizukuInstalled get() = false val Context.isShizukuInstalled get() = false
fun Context.getApplicationIcon(pkgName: String): Drawable? { fun Context.getApplicationIcon(pkgName: String): Drawable? {
return try { return try {
packageManager.getApplicationIcon(pkgName) packageManager.getApplicationIcon(pkgName)

View file

@ -16,6 +16,7 @@ fun Uri.toShareIntent(context: Context, type: String = "image/*", message: Strin
"http", "https" -> { "http", "https" -> {
putExtra(Intent.EXTRA_TEXT, uri.toString()) putExtra(Intent.EXTRA_TEXT, uri.toString())
} }
"content" -> { "content" -> {
message?.let { putExtra(Intent.EXTRA_TEXT, it) } message?.let { putExtra(Intent.EXTRA_TEXT, it) }
putExtra(Intent.EXTRA_STREAM, uri) putExtra(Intent.EXTRA_STREAM, uri)

View file

@ -10,7 +10,11 @@ import androidx.annotation.StringRes
* @param resource the text resource. * @param resource the text resource.
* @param duration the duration of the toast. Defaults to short. * @param duration the duration of the toast. Defaults to short.
*/ */
fun Context.toast(@StringRes resource: Int, duration: Int = Toast.LENGTH_SHORT, block: (Toast) -> Unit = {}): Toast { fun Context.toast(
@StringRes resource: Int,
duration: Int = Toast.LENGTH_SHORT,
block: (Toast) -> Unit = {}
): Toast {
return toast(getString(resource), duration, block) return toast(getString(resource), duration, block)
} }
@ -20,7 +24,11 @@ fun Context.toast(@StringRes resource: Int, duration: Int = Toast.LENGTH_SHORT,
* @param text the text to display. * @param text the text to display.
* @param duration the duration of the toast. Defaults to short. * @param duration the duration of the toast. Defaults to short.
*/ */
fun Context.toast(text: String?, duration: Int = Toast.LENGTH_SHORT, block: (Toast) -> Unit = {}): Toast { fun Context.toast(
text: String?,
duration: Int = Toast.LENGTH_SHORT,
block: (Toast) -> Unit = {}
): Toast {
return Toast.makeText(applicationContext, text.orEmpty(), duration).also { return Toast.makeText(applicationContext, text.orEmpty(), duration).also {
block(it) block(it)
it.show() it.show()

View file

@ -30,7 +30,11 @@ object EpisodeRecognition {
*/ */
private val unwantedWhiteSpace = Regex("""\s(?=extra|special|omake)""") private val unwantedWhiteSpace = Regex("""\s(?=extra|special|omake)""")
fun parseEpisodeNumber(animeTitle: String, episodeName: String, episodeNumber: Float? = null): Float { fun parseEpisodeNumber(
animeTitle: String,
episodeName: String,
episodeNumber: Float? = null
): Float {
// If episode number is known return. // If episode number is known return.
if (episodeNumber != null && (episodeNumber == -2f || episodeNumber > -1f)) { if (episodeNumber != null && (episodeNumber == -2f || episodeNumber > -1f)) {
return episodeNumber return episodeNumber

View file

@ -1,5 +1,6 @@
package tachiyomi.source.local.entries.anime package tachiyomi.source.local.entries.anime
//import eu.kanade.tachiyomi.util.storage.toFFmpegString
import android.content.Context import android.content.Context
import eu.kanade.tachiyomi.animesource.AnimeCatalogueSource import eu.kanade.tachiyomi.animesource.AnimeCatalogueSource
import eu.kanade.tachiyomi.animesource.AnimeSource import eu.kanade.tachiyomi.animesource.AnimeSource
@ -8,15 +9,11 @@ import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.AnimesPage import eu.kanade.tachiyomi.animesource.model.AnimesPage
import eu.kanade.tachiyomi.animesource.model.SAnime import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.DiskUtil
//import eu.kanade.tachiyomi.util.storage.toFFmpegString
import kotlinx.serialization.json.Json
import rx.Observable import rx.Observable
import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.lang.withIOContext
import tachiyomi.domain.entries.anime.model.Anime import tachiyomi.domain.entries.anime.model.Anime
import tachiyomi.source.local.filter.anime.AnimeOrderBy import tachiyomi.source.local.filter.anime.AnimeOrderBy
import uy.kohesive.injekt.injectLazy
import java.io.File import java.io.File
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -27,7 +24,7 @@ class LocalAnimeSource(
private val POPULAR_FILTERS = AnimeFilterList(AnimeOrderBy.Popular(context)) private val POPULAR_FILTERS = AnimeFilterList(AnimeOrderBy.Popular(context))
private val LATEST_FILTERS = AnimeFilterList(AnimeOrderBy.Latest(context)) private val LATEST_FILTERS = AnimeFilterList(AnimeOrderBy.Latest(context))
override val name ="Local anime source" override val name = "Local anime source"
override val id: Long = ID override val id: Long = ID
@ -42,7 +39,11 @@ class LocalAnimeSource(
override fun fetchLatestUpdates(page: Int) = fetchSearchAnime(page, "", LATEST_FILTERS) override fun fetchLatestUpdates(page: Int) = fetchSearchAnime(page, "", LATEST_FILTERS)
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> { override fun fetchSearchAnime(
page: Int,
query: String,
filters: AnimeFilterList
): Observable<AnimesPage> {
//return emptyObservable() //return emptyObservable()
return Observable.just(AnimesPage(emptyList(), false)) return Observable.just(AnimesPage(emptyList(), false))
} }
@ -63,7 +64,8 @@ class LocalAnimeSource(
override fun getFilterList() = AnimeFilterList(AnimeOrderBy.Popular(context)) override fun getFilterList() = AnimeFilterList(AnimeOrderBy.Popular(context))
// Unused stuff // Unused stuff
override suspend fun getVideoList(episode: SEpisode) = throw UnsupportedOperationException("Unused") override suspend fun getVideoList(episode: SEpisode) =
throw UnsupportedOperationException("Unused")
companion object { companion object {
const val ID = 0L const val ID = 0L

View file

@ -37,7 +37,11 @@ class LocalMangaSource(
override fun fetchLatestUpdates(page: Int) = fetchSearchManga(page, "", LATEST_FILTERS) override fun fetchLatestUpdates(page: Int) = fetchSearchManga(page, "", LATEST_FILTERS)
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> { override fun fetchSearchManga(
page: Int,
query: String,
filters: FilterList
): Observable<MangasPage> {
return Observable.just(MangasPage(emptyList(), false)) return Observable.just(MangasPage(emptyList(), false))
} }
@ -55,7 +59,8 @@ class LocalMangaSource(
override fun getFilterList() = FilterList(MangaOrderBy.Popular(context)) override fun getFilterList() = FilterList(MangaOrderBy.Popular(context))
// Unused stuff // Unused stuff
override suspend fun getPageList(chapter: SChapter) = throw UnsupportedOperationException("Unused") override suspend fun getPageList(chapter: SChapter) =
throw UnsupportedOperationException("Unused")
companion object { companion object {
const val ID = 0L const val ID = 0L