various bugfixes
This commit is contained in:
parent
0b9f2bb019
commit
dc959796e6
26 changed files with 685 additions and 289 deletions
|
@ -2,6 +2,13 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.software.leanback"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.touchscreen"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
@ -10,7 +17,8 @@
|
||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||||
android:maxSdkVersion="32" />
|
android:maxSdkVersion="32" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||||
|
android:maxSdkVersion="32" />
|
||||||
|
|
||||||
<!-- For background jobs -->
|
<!-- For background jobs -->
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
@ -47,7 +55,7 @@
|
||||||
android:theme="@style/Theme.Dantotsu"
|
android:theme="@style/Theme.Dantotsu"
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
tools:ignore="AllowBackup"
|
tools:ignore="AllowBackup"
|
||||||
>
|
android:banner="@drawable/ic_banner_foreground">
|
||||||
<activity
|
<activity
|
||||||
android:name="ani.dantotsu.media.novel.novelreader.NovelReaderActivity"
|
android:name="ani.dantotsu.media.novel.novelreader.NovelReaderActivity"
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
|
@ -206,9 +214,12 @@
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.Main" />
|
||||||
|
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name="eu.kanade.tachiyomi.extension.manga.util.MangaExtensionInstallActivity"
|
android:name="eu.kanade.tachiyomi.extension.manga.util.MangaExtensionInstallActivity"
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ani.dantotsu.aniyomi.anime.custom
|
||||||
|
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import android.content.Context
|
||||||
import ani.dantotsu.media.manga.MangaCache
|
import ani.dantotsu.media.manga.MangaCache
|
||||||
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
|
@ -28,6 +29,9 @@ class AppModule(val app: Application) : InjektModule {
|
||||||
|
|
||||||
addSingletonFactory { MangaExtensionManager(app) }
|
addSingletonFactory { MangaExtensionManager(app) }
|
||||||
|
|
||||||
|
val sharedPreferences = app.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
|
||||||
|
addSingleton(sharedPreferences)
|
||||||
|
|
||||||
addSingletonFactory {
|
addSingletonFactory {
|
||||||
Json {
|
Json {
|
||||||
ignoreUnknownKeys = true
|
ignoreUnknownKeys = true
|
||||||
|
|
|
@ -1,21 +1,30 @@
|
||||||
package ani.dantotsu.connections.discord
|
package ani.dantotsu.connections.discord
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Application.getProcessName
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import android.webkit.WebViewClient
|
import android.webkit.WebViewClient
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.connections.discord.Discord.saveToken
|
import ani.dantotsu.connections.discord.Discord.saveToken
|
||||||
import ani.dantotsu.startMainActivity
|
import ani.dantotsu.startMainActivity
|
||||||
|
|
||||||
class Login : AppCompatActivity() {
|
class Login : AppCompatActivity() {
|
||||||
|
|
||||||
@SuppressLint("SetJavaScriptEnabled")
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
val process = getProcessName()
|
||||||
|
if (packageName != process) WebView.setDataDirectorySuffix(process)
|
||||||
|
}
|
||||||
setContentView(R.layout.activity_discord)
|
setContentView(R.layout.activity_discord)
|
||||||
|
|
||||||
val webView = findViewById<WebView>(R.id.discordWebview)
|
val webView = findViewById<WebView>(R.id.discordWebview)
|
||||||
|
|
||||||
webView.apply {
|
webView.apply {
|
||||||
settings.javaScriptEnabled = true
|
settings.javaScriptEnabled = true
|
||||||
settings.databaseEnabled = true
|
settings.databaseEnabled = true
|
||||||
|
|
|
@ -113,6 +113,10 @@ data class Media(
|
||||||
this.relation = mediaEdge.relationType?.toString()
|
this.relation = mediaEdge.relationType?.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun mainName() = nameMAL ?: name ?: nameRomaji
|
fun mainName() = name ?: nameMAL ?: nameRomaji
|
||||||
fun mangaName() = if (countryOfOrigin != "JP") mainName() else nameRomaji
|
fun mangaName() = if (countryOfOrigin != "JP") mainName() else nameRomaji
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object MediaSingleton {
|
||||||
|
var media: Media? = null
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package ani.dantotsu.media
|
package ani.dantotsu.media
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
|
@ -40,6 +42,8 @@ import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.MainScope
|
import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
class MediaDetailsViewModel : ViewModel() {
|
class MediaDetailsViewModel : ViewModel() {
|
||||||
val scrolledToTop = MutableLiveData(true)
|
val scrolledToTop = MutableLiveData(true)
|
||||||
|
@ -48,11 +52,13 @@ class MediaDetailsViewModel : ViewModel() {
|
||||||
saveData("$id-select", data, activity)
|
saveData("$id-select", data, activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun loadSelected(media: Media): Selected {
|
fun loadSelected(media: Media): Selected {
|
||||||
|
val sharedPreferences = Injekt.get<SharedPreferences>()
|
||||||
val data = loadData<Selected>("${media.id}-select") ?: Selected().let {
|
val data = loadData<Selected>("${media.id}-select") ?: Selected().let {
|
||||||
it.sourceIndex = if (media.isAdult) 0 else when (media.anime != null) {
|
it.sourceIndex = if (media.isAdult) 0 else when (media.anime != null) {
|
||||||
true -> loadData("settings_def_anime_source_s_r") ?: 0
|
true -> sharedPreferences.getInt("settings_def_anime_source_s_r", 0)
|
||||||
else -> loadData("settings_def_manga_source_s_r") ?: 0
|
else -> sharedPreferences.getInt(("settings_def_manga_source_s_r"), 0)
|
||||||
}
|
}
|
||||||
it.preferDub = loadData("settings_prefer_dub") ?: false
|
it.preferDub = loadData("settings_prefer_dub") ?: false
|
||||||
saveSelected(media.id, it)
|
saveSelected(media.id, it)
|
||||||
|
|
|
@ -9,6 +9,8 @@ import ani.dantotsu.databinding.ItemEpisodeCompactBinding
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.setAnimation
|
import ani.dantotsu.setAnimation
|
||||||
import ani.dantotsu.connections.updateProgress
|
import ani.dantotsu.connections.updateProgress
|
||||||
|
import java.util.regex.Matcher
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
class MangaChapterAdapter(
|
class MangaChapterAdapter(
|
||||||
private var type: Int,
|
private var type: Int,
|
||||||
|
@ -63,12 +65,12 @@ class MangaChapterAdapter(
|
||||||
val ep = arr[position]
|
val ep = arr[position]
|
||||||
binding.itemEpisodeNumber.text = ep.number
|
binding.itemEpisodeNumber.text = ep.number
|
||||||
if (media.userProgress != null) {
|
if (media.userProgress != null) {
|
||||||
if ((ep.number.toFloatOrNull() ?: 9999f) <= media.userProgress!!.toFloat())
|
if ((MangaNameAdapter.findChapterNumber(ep.number) ?: 9999f) <= media.userProgress!!.toFloat())
|
||||||
binding.itemEpisodeViewedCover.visibility = View.VISIBLE
|
binding.itemEpisodeViewedCover.visibility = View.VISIBLE
|
||||||
else {
|
else {
|
||||||
binding.itemEpisodeViewedCover.visibility = View.GONE
|
binding.itemEpisodeViewedCover.visibility = View.GONE
|
||||||
binding.itemEpisodeCont.setOnLongClickListener {
|
binding.itemEpisodeCont.setOnLongClickListener {
|
||||||
updateProgress(media, ep.number)
|
updateProgress(media, MangaNameAdapter.findChapterNumber(ep.number).toString())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,14 +93,14 @@ class MangaChapterAdapter(
|
||||||
} else binding.itemChapterTitle.visibility = View.GONE
|
} else binding.itemChapterTitle.visibility = View.GONE
|
||||||
|
|
||||||
if (media.userProgress != null) {
|
if (media.userProgress != null) {
|
||||||
if ((ep.number.toFloatOrNull() ?: 9999f) <= media.userProgress!!.toFloat()) {
|
if ((MangaNameAdapter.findChapterNumber(ep.number) ?: 9999f) <= media.userProgress!!.toFloat()) {
|
||||||
binding.itemEpisodeViewedCover.visibility = View.VISIBLE
|
binding.itemEpisodeViewedCover.visibility = View.VISIBLE
|
||||||
binding.itemEpisodeViewed.visibility = View.VISIBLE
|
binding.itemEpisodeViewed.visibility = View.VISIBLE
|
||||||
} else {
|
} else {
|
||||||
binding.itemEpisodeViewedCover.visibility = View.GONE
|
binding.itemEpisodeViewedCover.visibility = View.GONE
|
||||||
binding.itemEpisodeViewed.visibility = View.GONE
|
binding.itemEpisodeViewed.visibility = View.GONE
|
||||||
binding.root.setOnLongClickListener {
|
binding.root.setOnLongClickListener {
|
||||||
updateProgress(media, ep.number)
|
updateProgress(media, MangaNameAdapter.findChapterNumber(ep.number).toString())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,4 +115,6 @@ class MangaChapterAdapter(
|
||||||
fun updateType(t: Int) {
|
fun updateType(t: Int) {
|
||||||
type = t
|
type = t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package ani.dantotsu.media.manga
|
||||||
|
|
||||||
|
import java.util.regex.Matcher
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
class MangaNameAdapter {
|
||||||
|
companion object {
|
||||||
|
fun findChapterNumber(text: String): Float? {
|
||||||
|
val regex = "(chapter|chap|ch|c)[\\s:.\\-]*([\\d]+\\.?[\\d]*)"
|
||||||
|
val pattern: Pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE)
|
||||||
|
val matcher: Matcher = pattern.matcher(text)
|
||||||
|
|
||||||
|
return if (matcher.find()) {
|
||||||
|
matcher.group(2)?.toFloat()
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ import ani.dantotsu.currActivity
|
||||||
import ani.dantotsu.databinding.BottomSheetSelectorBinding
|
import ani.dantotsu.databinding.BottomSheetSelectorBinding
|
||||||
import ani.dantotsu.media.manga.MangaChapter
|
import ani.dantotsu.media.manga.MangaChapter
|
||||||
import ani.dantotsu.media.MediaDetailsViewModel
|
import ani.dantotsu.media.MediaDetailsViewModel
|
||||||
|
import ani.dantotsu.media.MediaSingleton
|
||||||
import ani.dantotsu.others.getSerialized
|
import ani.dantotsu.others.getSerialized
|
||||||
import ani.dantotsu.tryWith
|
import ani.dantotsu.tryWith
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -49,7 +50,8 @@ class ChapterLoaderDialog : BottomSheetDialogFragment() {
|
||||||
activity?.runOnUiThread {
|
activity?.runOnUiThread {
|
||||||
tryWith { dismiss() }
|
tryWith { dismiss() }
|
||||||
if(launch) {
|
if(launch) {
|
||||||
val intent = Intent(activity, MangaReaderActivity::class.java).apply { putExtra("media", m) }
|
MediaSingleton.media = m
|
||||||
|
val intent = Intent(activity, MangaReaderActivity::class.java)//.apply { putExtra("media", m) }
|
||||||
activity.startActivity(intent)
|
activity.startActivity(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,10 @@ import ani.dantotsu.connections.updateProgress
|
||||||
import ani.dantotsu.databinding.ActivityMangaReaderBinding
|
import ani.dantotsu.databinding.ActivityMangaReaderBinding
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.media.MediaDetailsViewModel
|
import ani.dantotsu.media.MediaDetailsViewModel
|
||||||
|
import ani.dantotsu.media.MediaSingleton
|
||||||
import ani.dantotsu.media.manga.MangaCache
|
import ani.dantotsu.media.manga.MangaCache
|
||||||
import ani.dantotsu.media.manga.MangaChapter
|
import ani.dantotsu.media.manga.MangaChapter
|
||||||
|
import ani.dantotsu.media.manga.MangaNameAdapter
|
||||||
import ani.dantotsu.others.ImageViewDialog
|
import ani.dantotsu.others.ImageViewDialog
|
||||||
import ani.dantotsu.others.getSerialized
|
import ani.dantotsu.others.getSerialized
|
||||||
import ani.dantotsu.parsers.HMangaSources
|
import ani.dantotsu.parsers.HMangaSources
|
||||||
|
@ -46,7 +48,12 @@ import ani.dantotsu.settings.UserInterfaceSettings
|
||||||
import com.alexvasilkov.gestures.views.GestureFrameLayout
|
import com.alexvasilkov.gestures.views.GestureFrameLayout
|
||||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
|
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
|
||||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||||
|
import com.google.firebase.crashlytics.ktx.crashlytics
|
||||||
|
import com.google.firebase.ktx.Firebase
|
||||||
|
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
@ -164,10 +171,13 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||||
|
|
||||||
media = if (model.getMedia().value == null)
|
media = if (model.getMedia().value == null)
|
||||||
try {
|
try {
|
||||||
(intent.getSerialized("media")) ?: return
|
//(intent.getSerialized("media")) ?: return
|
||||||
|
MediaSingleton.media ?: return
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logError(e)
|
logError(e)
|
||||||
return
|
return
|
||||||
|
} finally {
|
||||||
|
MediaSingleton.media = null
|
||||||
}
|
}
|
||||||
else model.getMedia().value ?: return
|
else model.getMedia().value ?: return
|
||||||
model.setMedia(media)
|
model.setMedia(media)
|
||||||
|
@ -180,6 +190,29 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||||
|
|
||||||
model.mangaReadSources = if (media.isAdult) HMangaSources else MangaSources
|
model.mangaReadSources = if (media.isAdult) HMangaSources else MangaSources
|
||||||
binding.mangaReaderSource.visibility = if (settings.showSource) View.VISIBLE else View.GONE
|
binding.mangaReaderSource.visibility = if (settings.showSource) View.VISIBLE else View.GONE
|
||||||
|
if(model.mangaReadSources!!.names.isEmpty()){
|
||||||
|
//try to reload sources
|
||||||
|
try {
|
||||||
|
if (media.isAdult) {
|
||||||
|
val mangaSources = MangaSources
|
||||||
|
val scope = lifecycleScope
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
mangaSources.init(Injekt.get<MangaExtensionManager>().installedExtensionsFlow)
|
||||||
|
}
|
||||||
|
model.mangaReadSources = mangaSources
|
||||||
|
}else{
|
||||||
|
val mangaSources = HMangaSources
|
||||||
|
val scope = lifecycleScope
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
mangaSources.init(Injekt.get<MangaExtensionManager>().installedExtensionsFlow)
|
||||||
|
}
|
||||||
|
model.mangaReadSources = mangaSources
|
||||||
|
}
|
||||||
|
}catch (e: Exception){
|
||||||
|
Firebase.crashlytics.recordException(e)
|
||||||
|
logError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
binding.mangaReaderSource.text = model.mangaReadSources!!.names[media.selected!!.sourceIndex]
|
binding.mangaReaderSource.text = model.mangaReadSources!!.names[media.selected!!.sourceIndex]
|
||||||
|
|
||||||
binding.mangaReaderTitle.text = media.userPreferredName
|
binding.mangaReaderTitle.text = media.userPreferredName
|
||||||
|
@ -677,7 +710,7 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||||
progressDialog?.setCancelable(false)
|
progressDialog?.setCancelable(false)
|
||||||
?.setPositiveButton(getString(R.string.yes)) { dialog, _ ->
|
?.setPositiveButton(getString(R.string.yes)) { dialog, _ ->
|
||||||
saveData("${media.id}_save_progress", true)
|
saveData("${media.id}_save_progress", true)
|
||||||
updateProgress(media, media.manga!!.selectedChapter!!)
|
updateProgress(media, MangaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!).toString())
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
runnable.run()
|
runnable.run()
|
||||||
}
|
}
|
||||||
|
@ -689,7 +722,7 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||||
progressDialog?.show()
|
progressDialog?.show()
|
||||||
} else {
|
} else {
|
||||||
if (loadData<Boolean>("${media.id}_save_progress") != false && if (media.isAdult) settings.updateForH else true)
|
if (loadData<Boolean>("${media.id}_save_progress") != false && if (media.isAdult) settings.updateForH else true)
|
||||||
updateProgress(media, media.manga!!.selectedChapter!!)
|
updateProgress(media, MangaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!).toString())
|
||||||
runnable.run()
|
runnable.run()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -171,6 +171,17 @@ abstract class AnimeParser : BaseParser() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EmptyAnimeParser: AnimeParser() {
|
||||||
|
override val name: String = "None"
|
||||||
|
override val saveName: String = "None"
|
||||||
|
|
||||||
|
override val isDubAvailableSeparately: Boolean = false
|
||||||
|
override suspend fun loadEpisodes(animeLink: String, extra: Map<String, String>?, sAnime: SAnime): List<Episode> = emptyList()
|
||||||
|
override suspend fun loadVideoServers(episodeLink: String, extra: Map<String, String>?, sEpisode: SEpisode): List<VideoServer> = emptyList()
|
||||||
|
|
||||||
|
override suspend fun search(query: String): List<ShowResponse> = emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class for containing Episode data of a particular parser
|
* A class for containing Episode data of a particular parser
|
||||||
* **/
|
* **/
|
||||||
|
|
|
@ -66,6 +66,7 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
|
||||||
override val saveName = extension.name
|
override val saveName = extension.name
|
||||||
override val hostUrl = extension.sources.first().name
|
override val hostUrl = extension.sources.first().name
|
||||||
override val isDubAvailableSeparately = false
|
override val isDubAvailableSeparately = false
|
||||||
|
override val isNSFW = extension.isNsfw
|
||||||
override suspend fun loadEpisodes(animeLink: String, extra: Map<String, String>?, sAnime: SAnime): List<Episode> {
|
override suspend fun loadEpisodes(animeLink: String, extra: Map<String, String>?, sAnime: SAnime): List<Episode> {
|
||||||
val source = extension.sources.first()
|
val source = extension.sources.first()
|
||||||
if (source is AnimeCatalogueSource) {
|
if (source is AnimeCatalogueSource) {
|
||||||
|
@ -176,6 +177,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
|
||||||
override val name = extension.name
|
override val name = extension.name
|
||||||
override val saveName = extension.name
|
override val saveName = extension.name
|
||||||
override val hostUrl = extension.sources.first().name
|
override val hostUrl = extension.sources.first().name
|
||||||
|
override val isNSFW = extension.isNsfw
|
||||||
|
|
||||||
override suspend fun loadChapters(mangaLink: String, extra: Map<String, String>?, sManga: SManga): List<MangaChapter> {
|
override suspend fun loadChapters(mangaLink: String, extra: Map<String, String>?, sManga: SManga): List<MangaChapter> {
|
||||||
val source = extension.sources.first() as? CatalogueSource ?: return emptyList()
|
val source = extension.sources.first() as? CatalogueSource ?: return emptyList()
|
||||||
|
@ -385,22 +387,22 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
|
||||||
|
|
||||||
|
|
||||||
private fun SChapterToMangaChapter(sChapter: SChapter): MangaChapter {
|
private fun SChapterToMangaChapter(sChapter: SChapter): MangaChapter {
|
||||||
val parsedChapterTitle = parseChapterTitle(sChapter.name)
|
/*val parsedChapterTitle = parseChapterTitle(sChapter.name)
|
||||||
val number = if (sChapter.chapter_number.toInt() != -1){
|
val number = if (sChapter.chapter_number.toInt() != -1){
|
||||||
sChapter.chapter_number.toString()
|
sChapter.chapter_number.toString()
|
||||||
} else if(parsedChapterTitle.first != null || parsedChapterTitle.second != null){
|
} else if(parsedChapterTitle.first != null || parsedChapterTitle.second != null){
|
||||||
(parsedChapterTitle.first ?: "") + "." + (parsedChapterTitle.second ?: "")
|
(parsedChapterTitle.first ?: "") + "." + (parsedChapterTitle.second ?: "")
|
||||||
}else{
|
}else{
|
||||||
sChapter.name
|
sChapter.name
|
||||||
}
|
}*/
|
||||||
return MangaChapter(
|
return MangaChapter(
|
||||||
number,
|
sChapter.name,
|
||||||
sChapter.url,
|
sChapter.url,
|
||||||
if (parsedChapterTitle.first != null || parsedChapterTitle.second != null) {
|
//if (parsedChapterTitle.first != null || parsedChapterTitle.second != null) {
|
||||||
parsedChapterTitle.third
|
// parsedChapterTitle.third
|
||||||
} else {
|
//} else {
|
||||||
sChapter.name
|
sChapter.name,
|
||||||
},
|
//},
|
||||||
null,
|
null,
|
||||||
sChapter
|
sChapter
|
||||||
)
|
)
|
||||||
|
|
|
@ -80,8 +80,8 @@ abstract class BaseParser {
|
||||||
} else {
|
} else {
|
||||||
val romajiRatio = FuzzySearch.ratio(closestRomaji?.name ?: "", mediaObj.nameRomaji)
|
val romajiRatio = FuzzySearch.ratio(closestRomaji?.name ?: "", mediaObj.nameRomaji)
|
||||||
val mainNameRatio = FuzzySearch.ratio(response.name, mediaObj.mainName())
|
val mainNameRatio = FuzzySearch.ratio(response.name, mediaObj.mainName())
|
||||||
logger("Fuzzy ratio for closest match in results: $mainNameRatio")
|
logger("Fuzzy ratio for closest match in results: $mainNameRatio for ${response.name}")
|
||||||
logger("Fuzzy ratio for closest match in RomajiResults: $romajiRatio")
|
logger("Fuzzy ratio for closest match in RomajiResults: $romajiRatio for ${closestRomaji?.name ?: "None"}")
|
||||||
|
|
||||||
if (romajiRatio > mainNameRatio) {
|
if (romajiRatio > mainNameRatio) {
|
||||||
logger("RomajiResults has a closer match. Replacing response.")
|
logger("RomajiResults has a closer match. Replacing response.")
|
||||||
|
|
|
@ -11,9 +11,11 @@ import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||||
abstract class WatchSources : BaseSources() {
|
abstract class WatchSources : BaseSources() {
|
||||||
|
|
||||||
override operator fun get(i: Int): AnimeParser {
|
override operator fun get(i: Int): AnimeParser {
|
||||||
return (list.getOrNull(i)?:list[0]).get.value as AnimeParser
|
return (list.getOrNull(i) ?: list.firstOrNull())?.get?.value as? AnimeParser
|
||||||
|
?: EmptyAnimeParser()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
suspend fun loadEpisodesFromMedia(i: Int, media: Media): MutableMap<String, Episode> {
|
suspend fun loadEpisodesFromMedia(i: Int, media: Media): MutableMap<String, Episode> {
|
||||||
return tryWithSuspend(true) {
|
return tryWithSuspend(true) {
|
||||||
val res = get(i).autoSearch(media) ?: return@tryWithSuspend mutableMapOf()
|
val res = get(i).autoSearch(media) ?: return@tryWithSuspend mutableMapOf()
|
||||||
|
@ -40,7 +42,8 @@ abstract class WatchSources : BaseSources() {
|
||||||
abstract class MangaReadSources : BaseSources() {
|
abstract class MangaReadSources : BaseSources() {
|
||||||
|
|
||||||
override operator fun get(i: Int): MangaParser {
|
override operator fun get(i: Int): MangaParser {
|
||||||
return (list.getOrNull(i)?:list[0]).get.value as MangaParser
|
return (list.getOrNull(i)?:list.firstOrNull())?.get?.value as? MangaParser
|
||||||
|
?: EmptyMangaParser()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun loadChaptersFromMedia(i: Int, media: Media): MutableMap<String, MangaChapter> {
|
suspend fun loadChaptersFromMedia(i: Int, media: Media): MutableMap<String, MangaChapter> {
|
||||||
|
|
|
@ -33,7 +33,7 @@ abstract class MangaParser : BaseParser() {
|
||||||
* **/
|
* **/
|
||||||
abstract suspend fun loadImages(chapterLink: String, sChapter: SChapter): List<MangaImage>
|
abstract suspend fun loadImages(chapterLink: String, sChapter: SChapter): List<MangaImage>
|
||||||
|
|
||||||
override suspend fun autoSearch(mediaObj: Media): ShowResponse? {
|
/*override suspend fun autoSearch(mediaObj: Media): ShowResponse? {
|
||||||
var response = loadSavedShowResponse(mediaObj.id)
|
var response = loadSavedShowResponse(mediaObj.id)
|
||||||
if (response != null) {
|
if (response != null) {
|
||||||
saveShowResponse(mediaObj.id, response, true)
|
saveShowResponse(mediaObj.id, response, true)
|
||||||
|
@ -48,11 +48,22 @@ abstract class MangaParser : BaseParser() {
|
||||||
saveShowResponse(mediaObj.id, response)
|
saveShowResponse(mediaObj.id, response)
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
}
|
}*/
|
||||||
|
|
||||||
open fun getTransformation(): BitmapTransformation? = null
|
open fun getTransformation(): BitmapTransformation? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EmptyMangaParser: MangaParser() {
|
||||||
|
override val name: String = "None"
|
||||||
|
override val saveName: String = "None"
|
||||||
|
|
||||||
|
override suspend fun loadChapters(mangaLink: String, extra: Map<String, String>?, sManga: SManga): List<MangaChapter> = emptyList()
|
||||||
|
|
||||||
|
override suspend fun loadImages(chapterLink: String, sChapter: SChapter): List<MangaImage> = emptyList()
|
||||||
|
|
||||||
|
override suspend fun search(query: String): List<ShowResponse> = emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
data class MangaChapter(
|
data class MangaChapter(
|
||||||
/**
|
/**
|
||||||
* Number of the Chapter in "String",
|
* Number of the Chapter in "String",
|
||||||
|
|
|
@ -29,7 +29,9 @@ object MangaSources : MangaReadSources() {
|
||||||
}
|
}
|
||||||
|
|
||||||
object HMangaSources : MangaReadSources() {
|
object HMangaSources : MangaReadSources() {
|
||||||
val aList: List<Lazier<BaseParser>> = lazyList(
|
val aList: List<Lazier<BaseParser>> = lazyList()
|
||||||
)
|
suspend fun init(fromExtensions: StateFlow<List<MangaExtension.Installed>>) {
|
||||||
|
//todo
|
||||||
|
}
|
||||||
override val list = listOf(aList,MangaSources.list).flatten()
|
override val list = listOf(aList,MangaSources.list).flatten()
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,9 @@ import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.ContextCompat.getSystemService
|
import androidx.core.content.ContextCompat.getSystemService
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.databinding.FragmentAnimeExtensionsBinding
|
import ani.dantotsu.databinding.FragmentAnimeExtensionsBinding
|
||||||
|
@ -33,7 +35,8 @@ import rx.android.schedulers.AndroidSchedulers
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
class AnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
class AnimeExtensionsFragment : Fragment(),
|
||||||
|
SearchQueryHandler {
|
||||||
private var _binding: FragmentAnimeExtensionsBinding? = null
|
private var _binding: FragmentAnimeExtensionsBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
@ -42,104 +45,115 @@ class AnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
private lateinit var extensionsRecyclerView: RecyclerView
|
private lateinit var extensionsRecyclerView: RecyclerView
|
||||||
private lateinit var allextenstionsRecyclerView: RecyclerView
|
private lateinit var allextenstionsRecyclerView: RecyclerView
|
||||||
private val animeExtensionManager: AnimeExtensionManager = Injekt.get<AnimeExtensionManager>()
|
private val animeExtensionManager: AnimeExtensionManager = Injekt.get<AnimeExtensionManager>()
|
||||||
private val extensionsAdapter = AnimeExtensionsAdapter ({ pkg ->
|
private val extensionsAdapter = AnimeExtensionsAdapter({ pkg ->
|
||||||
if(pkg.hasUpdate){
|
if (isAdded) { // Check if the fragment is currently added to its activity
|
||||||
|
val context = requireContext() // Store context in a variable
|
||||||
val notificationManager =
|
val notificationManager =
|
||||||
requireContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // Initialize NotificationManager once
|
||||||
animeExtensionManager.updateExtension(pkg)
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
if (pkg.hasUpdate) {
|
||||||
.subscribe(
|
animeExtensionManager.updateExtension(pkg)
|
||||||
{ installStep ->
|
.observeOn(AndroidSchedulers.mainThread()) // Observe on main thread
|
||||||
val builder = NotificationCompat.Builder(
|
.subscribe(
|
||||||
requireContext(),
|
{ installStep ->
|
||||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
val builder = NotificationCompat.Builder(
|
||||||
)
|
context,
|
||||||
.setSmallIcon(R.drawable.ic_round_sync_24)
|
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||||
.setContentTitle("Updating extension")
|
)
|
||||||
.setContentText("Step: $installStep")
|
.setSmallIcon(R.drawable.ic_round_sync_24)
|
||||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
.setContentTitle("Updating extension")
|
||||||
notificationManager.notify(1, builder.build())
|
.setContentText("Step: $installStep")
|
||||||
},
|
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||||
{ error ->
|
notificationManager.notify(1, builder.build())
|
||||||
val builder = NotificationCompat.Builder(
|
},
|
||||||
requireContext(),
|
{ error ->
|
||||||
Notifications.CHANNEL_DOWNLOADER_ERROR
|
Log.e("AnimeExtensionsAdapter", "Error: ", error) // Log the error
|
||||||
)
|
val builder = NotificationCompat.Builder(
|
||||||
.setSmallIcon(R.drawable.ic_round_info_24)
|
context,
|
||||||
.setContentTitle("Update failed")
|
Notifications.CHANNEL_DOWNLOADER_ERROR
|
||||||
.setContentText("Error: ${error.message}")
|
)
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
.setSmallIcon(R.drawable.ic_round_info_24)
|
||||||
notificationManager.notify(1, builder.build())
|
.setContentTitle("Update failed")
|
||||||
},
|
.setContentText("Error: ${error.message}")
|
||||||
{
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||||
val builder = NotificationCompat.Builder(
|
notificationManager.notify(1, builder.build())
|
||||||
requireContext(),
|
},
|
||||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
{
|
||||||
)
|
val builder = NotificationCompat.Builder(
|
||||||
.setSmallIcon(androidx.media3.ui.R.drawable.exo_ic_check)
|
context,
|
||||||
.setContentTitle("Update complete")
|
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||||
.setContentText("The extension has been successfully updated.")
|
)
|
||||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
.setSmallIcon(androidx.media3.ui.R.drawable.exo_ic_check)
|
||||||
notificationManager.notify(1, builder.build())
|
.setContentTitle("Update complete")
|
||||||
}
|
.setContentText("The extension has been successfully updated.")
|
||||||
)
|
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||||
}else {
|
notificationManager.notify(1, builder.build())
|
||||||
animeExtensionManager.uninstallExtension(pkg.pkgName)
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
animeExtensionManager.uninstallExtension(pkg.pkgName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, skipIcons)
|
}, skipIcons)
|
||||||
|
|
||||||
private val allExtensionsAdapter = AllAnimeExtensionsAdapter(lifecycleScope, { pkgName ->
|
private val allExtensionsAdapter = AllAnimeExtensionsAdapter(lifecycleScope, { pkgName ->
|
||||||
|
|
||||||
val notificationManager =
|
val notificationManager =
|
||||||
requireContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
requireContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
|
||||||
// Start the installation process
|
// Start the installation process
|
||||||
animeExtensionManager.installExtension(pkgName)
|
animeExtensionManager.installExtension(pkgName)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
{ installStep ->
|
{ installStep ->
|
||||||
val builder = NotificationCompat.Builder(
|
val builder = NotificationCompat.Builder(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||||
)
|
)
|
||||||
.setSmallIcon(R.drawable.ic_round_sync_24)
|
.setSmallIcon(R.drawable.ic_round_sync_24)
|
||||||
.setContentTitle("Installing extension")
|
.setContentTitle("Installing extension")
|
||||||
.setContentText("Step: $installStep")
|
.setContentText("Step: $installStep")
|
||||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||||
notificationManager.notify(1, builder.build())
|
notificationManager.notify(1, builder.build())
|
||||||
},
|
},
|
||||||
{ error ->
|
{ error ->
|
||||||
val builder = NotificationCompat.Builder(
|
val builder = NotificationCompat.Builder(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
Notifications.CHANNEL_DOWNLOADER_ERROR
|
Notifications.CHANNEL_DOWNLOADER_ERROR
|
||||||
)
|
)
|
||||||
.setSmallIcon(R.drawable.ic_round_info_24)
|
.setSmallIcon(R.drawable.ic_round_info_24)
|
||||||
.setContentTitle("Installation failed")
|
.setContentTitle("Installation failed")
|
||||||
.setContentText("Error: ${error.message}")
|
.setContentText("Error: ${error.message}")
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||||
notificationManager.notify(1, builder.build())
|
notificationManager.notify(1, builder.build())
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
val builder = NotificationCompat.Builder(
|
val builder = NotificationCompat.Builder(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||||
)
|
)
|
||||||
.setSmallIcon(androidx.media3.ui.R.drawable.exo_ic_check)
|
.setSmallIcon(androidx.media3.ui.R.drawable.exo_ic_check)
|
||||||
.setContentTitle("Installation complete")
|
.setContentTitle("Installation complete")
|
||||||
.setContentText("The extension has been successfully installed.")
|
.setContentText("The extension has been successfully installed.")
|
||||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||||
notificationManager.notify(1, builder.build())
|
notificationManager.notify(1, builder.build())
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}, skipIcons)
|
}, skipIcons)
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
_binding = FragmentAnimeExtensionsBinding.inflate(inflater, container, false)
|
_binding = FragmentAnimeExtensionsBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
extensionsRecyclerView = binding.animeExtensionsRecyclerView
|
extensionsRecyclerView = binding.animeExtensionsRecyclerView
|
||||||
extensionsRecyclerView.layoutManager = LinearLayoutManager( requireContext())
|
extensionsRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||||
extensionsRecyclerView.adapter = extensionsAdapter
|
extensionsRecyclerView.adapter = extensionsAdapter
|
||||||
|
|
||||||
allextenstionsRecyclerView = binding.allAnimeExtensionsRecyclerView
|
allextenstionsRecyclerView = binding.allAnimeExtensionsRecyclerView
|
||||||
allextenstionsRecyclerView.layoutManager = LinearLayoutManager( requireContext())
|
allextenstionsRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||||
allextenstionsRecyclerView.adapter = allExtensionsAdapter
|
allextenstionsRecyclerView.adapter = allExtensionsAdapter
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
|
@ -156,11 +170,11 @@ class AnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
Pair(availableExtensions, installedExtensions)
|
Pair(availableExtensions, installedExtensions)
|
||||||
}.collect { pair ->
|
}.collect { pair ->
|
||||||
val (availableExtensions, installedExtensions) = pair
|
val (availableExtensions, installedExtensions) = pair
|
||||||
|
|
||||||
allExtensionsAdapter.updateData(availableExtensions, installedExtensions)
|
allExtensionsAdapter.updateData(availableExtensions, installedExtensions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val extensionsRecyclerView: RecyclerView = binding.animeExtensionsRecyclerView
|
val extensionsRecyclerView: RecyclerView = binding.animeExtensionsRecyclerView
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +183,6 @@ class AnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
allExtensionsAdapter.filter("") // Reset the filter
|
allExtensionsAdapter.filter("") // Reset the filter
|
||||||
allextenstionsRecyclerView.visibility = View.VISIBLE
|
allextenstionsRecyclerView.visibility = View.VISIBLE
|
||||||
extensionsRecyclerView.visibility = View.VISIBLE
|
extensionsRecyclerView.visibility = View.VISIBLE
|
||||||
println("asdf: ${allExtensionsAdapter.getItemCount()}")
|
|
||||||
} else {
|
} else {
|
||||||
allExtensionsAdapter.filter(query)
|
allExtensionsAdapter.filter(query)
|
||||||
allextenstionsRecyclerView.visibility = View.VISIBLE
|
allextenstionsRecyclerView.visibility = View.VISIBLE
|
||||||
|
@ -182,14 +195,17 @@ class AnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class AnimeExtensionsAdapter(private val onUninstallClicked: (AnimeExtension.Installed) -> Unit, skipIcons: Boolean) : RecyclerView.Adapter<AnimeExtensionsAdapter.ViewHolder>() {
|
private class AnimeExtensionsAdapter(
|
||||||
|
private val onUninstallClicked: (AnimeExtension.Installed) -> Unit,
|
||||||
|
skipIcons: Boolean
|
||||||
|
) : ListAdapter<AnimeExtension.Installed, AnimeExtensionsAdapter.ViewHolder>(
|
||||||
|
DIFF_CALLBACK_INSTALLED
|
||||||
|
) {
|
||||||
|
|
||||||
private var extensions: List<AnimeExtension.Installed> = emptyList()
|
|
||||||
val skipIcons = skipIcons
|
val skipIcons = skipIcons
|
||||||
|
|
||||||
fun updateData(newExtensions: List<AnimeExtension.Installed>) {
|
fun updateData(newExtensions: List<AnimeExtension.Installed>) {
|
||||||
extensions = newExtensions
|
submitList(newExtensions) // Use submitList instead of manual list handling
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
@ -199,15 +215,20 @@ class AnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val extension = extensions[position]
|
val extension = getItem(position) // Use getItem() from ListAdapter
|
||||||
holder.extensionNameTextView.text = extension.name
|
holder.extensionNameTextView.text = extension.name
|
||||||
if (!skipIcons) {
|
if (!skipIcons) {
|
||||||
holder.extensionIconImageView.setImageDrawable(extension.icon)
|
holder.extensionIconImageView.setImageDrawable(extension.icon)
|
||||||
}
|
}
|
||||||
if(extension.hasUpdate){
|
if (extension.hasUpdate) {
|
||||||
holder.closeTextView.text = "Update"
|
holder.closeTextView.text = "Update"
|
||||||
holder.closeTextView.setTextColor(ContextCompat.getColor(holder.itemView.context, R.color.warning))
|
holder.closeTextView.setTextColor(
|
||||||
}else{
|
ContextCompat.getColor(
|
||||||
|
holder.itemView.context,
|
||||||
|
R.color.warning
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
holder.closeTextView.text = "Uninstall"
|
holder.closeTextView.text = "Uninstall"
|
||||||
}
|
}
|
||||||
holder.closeTextView.setOnClickListener {
|
holder.closeTextView.setOnClickListener {
|
||||||
|
@ -215,59 +236,91 @@ class AnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int = extensions.size
|
|
||||||
|
|
||||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
||||||
val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView)
|
val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView)
|
||||||
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val DIFF_CALLBACK_INSTALLED =
|
||||||
|
object : DiffUtil.ItemCallback<AnimeExtension.Installed>() {
|
||||||
|
override fun areItemsTheSame(
|
||||||
|
oldItem: AnimeExtension.Installed,
|
||||||
|
newItem: AnimeExtension.Installed
|
||||||
|
): Boolean {
|
||||||
|
return oldItem.pkgName == newItem.pkgName
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(
|
||||||
|
oldItem: AnimeExtension.Installed,
|
||||||
|
newItem: AnimeExtension.Installed
|
||||||
|
): Boolean {
|
||||||
|
return oldItem == newItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AllAnimeExtensionsAdapter(private val coroutineScope: CoroutineScope,
|
|
||||||
private val onButtonClicked: (AnimeExtension.Available) -> Unit, skipIcons: Boolean) : RecyclerView.Adapter<AllAnimeExtensionsAdapter.ViewHolder>() {
|
private class AllAnimeExtensionsAdapter(
|
||||||
private var extensions: List<AnimeExtension.Available> = emptyList()
|
private val coroutineScope: CoroutineScope,
|
||||||
|
private val onButtonClicked: (AnimeExtension.Available) -> Unit,
|
||||||
|
skipIcons: Boolean
|
||||||
|
) : ListAdapter<AnimeExtension.Available, AllAnimeExtensionsAdapter.ViewHolder>(
|
||||||
|
DIFF_CALLBACK_AVAILABLE
|
||||||
|
) {
|
||||||
val skipIcons = skipIcons
|
val skipIcons = skipIcons
|
||||||
|
|
||||||
fun updateData(newExtensions: List<AnimeExtension.Available>, installedExtensions: List<AnimeExtension.Installed> = emptyList()) {
|
fun updateData(
|
||||||
val installedPkgNames = installedExtensions.map { it.pkgName }.toSet()
|
newExtensions: List<AnimeExtension.Available>,
|
||||||
extensions = newExtensions.filter { it.pkgName !in installedPkgNames }
|
installedExtensions: List<AnimeExtension.Installed> = emptyList()
|
||||||
filteredExtensions = extensions
|
) {
|
||||||
notifyDataSetChanged()
|
coroutineScope.launch(Dispatchers.Default) {
|
||||||
|
val installedPkgNames = installedExtensions.map { it.pkgName }.toSet()
|
||||||
|
val filteredExtensions = newExtensions.filter { it.pkgName !in installedPkgNames }
|
||||||
|
|
||||||
|
// Switch back to main thread to update UI
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
submitList(filteredExtensions)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AllAnimeExtensionsAdapter.ViewHolder {
|
|
||||||
|
override fun onCreateViewHolder(
|
||||||
|
parent: ViewGroup,
|
||||||
|
viewType: Int
|
||||||
|
): AllAnimeExtensionsAdapter.ViewHolder {
|
||||||
val view = LayoutInflater.from(parent.context)
|
val view = LayoutInflater.from(parent.context)
|
||||||
.inflate(R.layout.item_extension_all, parent, false)
|
.inflate(R.layout.item_extension_all, parent, false)
|
||||||
return ViewHolder(view)
|
return ViewHolder(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val extension = filteredExtensions[position]
|
val extension = getItem(position)
|
||||||
|
|
||||||
holder.extensionNameTextView.text = extension.name
|
holder.extensionNameTextView.text = extension.name
|
||||||
|
|
||||||
if (!skipIcons) {
|
if (!skipIcons) {
|
||||||
coroutineScope.launch {
|
Glide.with(holder.itemView.context)
|
||||||
val drawable = urlToDrawable(holder.itemView.context, extension.iconUrl)
|
.load(extension.iconUrl)
|
||||||
holder.extensionIconImageView.setImageDrawable(drawable)
|
.into(holder.extensionIconImageView)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
holder.closeTextView.text = "Install"
|
holder.closeTextView.text = "Install"
|
||||||
holder.closeTextView.setOnClickListener {
|
holder.closeTextView.setOnClickListener {
|
||||||
onButtonClicked(extension)
|
onButtonClicked(extension)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int = filteredExtensions.size
|
|
||||||
|
|
||||||
private var filteredExtensions: List<AnimeExtension.Available> = emptyList()
|
|
||||||
|
|
||||||
fun filter(query: String) {
|
fun filter(query: String) {
|
||||||
filteredExtensions = if (query.isEmpty()) {
|
val filteredExtensions = if (query.isEmpty()) {
|
||||||
extensions
|
currentList
|
||||||
} else {
|
} else {
|
||||||
extensions.filter { it.name.contains(query, ignoreCase = true) }
|
currentList.filter { it.name.contains(query, ignoreCase = true) }
|
||||||
}
|
}
|
||||||
notifyDataSetChanged()
|
submitList(filteredExtensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
@ -276,18 +329,24 @@ class AnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun urlToDrawable(context: Context, url: String): Drawable? {
|
companion object {
|
||||||
return withContext(Dispatchers.IO) {
|
val DIFF_CALLBACK_AVAILABLE =
|
||||||
try {
|
object : DiffUtil.ItemCallback<AnimeExtension.Available>() {
|
||||||
return@withContext Glide.with(context)
|
override fun areItemsTheSame(
|
||||||
.load(url)
|
oldItem: AnimeExtension.Available,
|
||||||
.submit()
|
newItem: AnimeExtension.Available
|
||||||
.get()
|
): Boolean {
|
||||||
} catch (e: Exception) {
|
return oldItem.pkgName == newItem.pkgName
|
||||||
e.printStackTrace()
|
}
|
||||||
return@withContext null
|
|
||||||
|
override fun areContentsTheSame(
|
||||||
|
oldItem: AnimeExtension.Available,
|
||||||
|
newItem: AnimeExtension.Available
|
||||||
|
): Boolean {
|
||||||
|
return oldItem == newItem
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -13,6 +13,7 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.ProgressBar
|
||||||
import android.widget.SearchView
|
import android.widget.SearchView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
|
@ -49,17 +50,13 @@ import uy.kohesive.injekt.injectLazy
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
class ExtensionsActivity : AppCompatActivity() {
|
class ExtensionsActivity : AppCompatActivity() {
|
||||||
private val restartMainActivity = object : OnBackPressedCallback(false) {
|
private val restartMainActivity = object : OnBackPressedCallback(false) {
|
||||||
override fun handleOnBackPressed() = startMainActivity(this@ExtensionsActivity)
|
override fun handleOnBackPressed() = startMainActivity(this@ExtensionsActivity)
|
||||||
}
|
}
|
||||||
lateinit var binding: ActivityExtensionsBinding
|
lateinit var binding: ActivityExtensionsBinding
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
@ -132,4 +129,4 @@ class ExtensionsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
interface SearchQueryHandler {
|
interface SearchQueryHandler {
|
||||||
fun updateContentBasedOnQuery(query: String?)
|
fun updateContentBasedOnQuery(query: String?)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,26 +11,96 @@ import ani.dantotsu.initActivity
|
||||||
class FAQActivity : AppCompatActivity() {
|
class FAQActivity : AppCompatActivity() {
|
||||||
private lateinit var binding: ActivityFaqBinding
|
private lateinit var binding: ActivityFaqBinding
|
||||||
|
|
||||||
private val faqs = listOf(
|
private val faqs by lazy {
|
||||||
|
listOf(
|
||||||
|
|
||||||
Triple(R.drawable.ic_round_help_24, currContext()!!.getString(R.string.question_1), currContext()!!.getString(R.string.answer_1)),
|
Triple(
|
||||||
Triple(R.drawable.ic_round_auto_awesome_24, currContext()!!.getString(R.string.question_2), currContext()!!.getString(R.string.answer_2)),
|
R.drawable.ic_round_help_24,
|
||||||
Triple(R.drawable.ic_round_auto_awesome_24, currContext()!!.getString(R.string.question_17), currContext()!!.getString(R.string.answer_17)),
|
currContext()!!.getString(R.string.question_1),
|
||||||
Triple(R.drawable.ic_round_download_24, currContext()!!.getString(R.string.question_3), currContext()!!.getString(R.string.answer_3)),
|
currContext()!!.getString(R.string.answer_1)
|
||||||
Triple(R.drawable.ic_round_help_24, currContext()!!.getString(R.string.question_16), currContext()!!.getString(R.string.answer_16)),
|
),
|
||||||
Triple(R.drawable.ic_round_dns_24, currContext()!!.getString(R.string.question_4), currContext()!!.getString(R.string.answer_4)),
|
Triple(
|
||||||
Triple(R.drawable.ic_baseline_screen_lock_portrait_24, currContext()!!.getString(R.string.question_5), currContext()!!.getString(R.string.answer_5)),
|
R.drawable.ic_round_auto_awesome_24,
|
||||||
Triple(R.drawable.ic_anilist, currContext()!!.getString(R.string.question_6), currContext()!!.getString(R.string.answer_6)),
|
currContext()!!.getString(R.string.question_2),
|
||||||
Triple(R.drawable.ic_round_movie_filter_24, currContext()!!.getString(R.string.question_7), currContext()!!.getString(R.string.answer_7)),
|
currContext()!!.getString(R.string.answer_2)
|
||||||
Triple(R.drawable.ic_round_menu_book_24, currContext()!!.getString(R.string.question_8), currContext()!!.getString(R.string.answer_8)),
|
),
|
||||||
Triple(R.drawable.ic_round_lock_open_24, currContext()!!.getString(R.string.question_9), currContext()!!.getString(R.string.answer_9)),
|
Triple(
|
||||||
Triple(R.drawable.ic_round_smart_button_24, currContext()!!.getString(R.string.question_10), currContext()!!.getString(R.string.answer_10)),
|
R.drawable.ic_round_auto_awesome_24,
|
||||||
Triple(R.drawable.ic_round_smart_button_24, currContext()!!.getString(R.string.question_11), currContext()!!.getString(R.string.answer_11)),
|
currContext()!!.getString(R.string.question_17),
|
||||||
Triple(R.drawable.ic_round_info_24, currContext()!!.getString(R.string.question_12), currContext()!!.getString(R.string.answer_12)),
|
currContext()!!.getString(R.string.answer_17)
|
||||||
Triple(R.drawable.ic_round_help_24, currContext()!!.getString(R.string.question_13), currContext()!!.getString(R.string.answer_13)),
|
),
|
||||||
Triple(R.drawable.ic_round_art_track_24, currContext()!!.getString(R.string.question_14), currContext()!!.getString(R.string.answer_14)),
|
Triple(
|
||||||
Triple(R.drawable.ic_round_video_settings_24, currContext()!!.getString(R.string.question_15), currContext()!!.getString(R.string.answer_15))
|
R.drawable.ic_round_download_24,
|
||||||
|
currContext()!!.getString(R.string.question_3),
|
||||||
|
currContext()!!.getString(R.string.answer_3)
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
R.drawable.ic_round_help_24,
|
||||||
|
currContext()!!.getString(R.string.question_16),
|
||||||
|
currContext()!!.getString(R.string.answer_16)
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
R.drawable.ic_round_dns_24,
|
||||||
|
currContext()!!.getString(R.string.question_4),
|
||||||
|
currContext()!!.getString(R.string.answer_4)
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
R.drawable.ic_baseline_screen_lock_portrait_24,
|
||||||
|
currContext()!!.getString(R.string.question_5),
|
||||||
|
currContext()!!.getString(R.string.answer_5)
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
R.drawable.ic_anilist,
|
||||||
|
currContext()!!.getString(R.string.question_6),
|
||||||
|
currContext()!!.getString(R.string.answer_6)
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
R.drawable.ic_round_movie_filter_24,
|
||||||
|
currContext()!!.getString(R.string.question_7),
|
||||||
|
currContext()!!.getString(R.string.answer_7)
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
R.drawable.ic_round_menu_book_24,
|
||||||
|
currContext()!!.getString(R.string.question_8),
|
||||||
|
currContext()!!.getString(R.string.answer_8)
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
R.drawable.ic_round_lock_open_24,
|
||||||
|
currContext()!!.getString(R.string.question_9),
|
||||||
|
currContext()!!.getString(R.string.answer_9)
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
R.drawable.ic_round_smart_button_24,
|
||||||
|
currContext()!!.getString(R.string.question_10),
|
||||||
|
currContext()!!.getString(R.string.answer_10)
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
R.drawable.ic_round_smart_button_24,
|
||||||
|
currContext()!!.getString(R.string.question_11),
|
||||||
|
currContext()!!.getString(R.string.answer_11)
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
R.drawable.ic_round_info_24,
|
||||||
|
currContext()!!.getString(R.string.question_12),
|
||||||
|
currContext()!!.getString(R.string.answer_12)
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
R.drawable.ic_round_help_24,
|
||||||
|
currContext()!!.getString(R.string.question_13),
|
||||||
|
currContext()!!.getString(R.string.answer_13)
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
R.drawable.ic_round_art_track_24,
|
||||||
|
currContext()!!.getString(R.string.question_14),
|
||||||
|
currContext()!!.getString(R.string.answer_14)
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
R.drawable.ic_round_video_settings_24,
|
||||||
|
currContext()!!.getString(R.string.question_15),
|
||||||
|
currContext()!!.getString(R.string.answer_15)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.app.NotificationManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -13,7 +14,9 @@ import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.databinding.FragmentMangaBinding
|
import ani.dantotsu.databinding.FragmentMangaBinding
|
||||||
|
@ -32,7 +35,8 @@ import rx.android.schedulers.AndroidSchedulers
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
class MangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
class MangaExtensionsFragment : Fragment(),
|
||||||
|
SearchQueryHandler {
|
||||||
private var _binding: FragmentMangaExtensionsBinding? = null
|
private var _binding: FragmentMangaExtensionsBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
@ -40,52 +44,58 @@ class MangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
|
|
||||||
private lateinit var extensionsRecyclerView: RecyclerView
|
private lateinit var extensionsRecyclerView: RecyclerView
|
||||||
private lateinit var allextenstionsRecyclerView: RecyclerView
|
private lateinit var allextenstionsRecyclerView: RecyclerView
|
||||||
private val mangaExtensionManager:MangaExtensionManager = Injekt.get<MangaExtensionManager>()
|
private val mangaExtensionManager: MangaExtensionManager = Injekt.get<MangaExtensionManager>()
|
||||||
private val extensionsAdapter = MangaExtensionsAdapter ({ pkg ->
|
private val extensionsAdapter = MangaExtensionsAdapter({ pkg ->
|
||||||
if(pkg.hasUpdate){
|
if (isAdded) { // Check if the fragment is currently added to its activity
|
||||||
|
val context = requireContext() // Store context in a variable
|
||||||
val notificationManager =
|
val notificationManager =
|
||||||
requireContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // Initialize NotificationManager once
|
||||||
mangaExtensionManager.updateExtension(pkg)
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
if (pkg.hasUpdate) {
|
||||||
.subscribe(
|
mangaExtensionManager.updateExtension(pkg)
|
||||||
{ installStep ->
|
.observeOn(AndroidSchedulers.mainThread()) // Observe on main thread
|
||||||
val builder = NotificationCompat.Builder(
|
.subscribe(
|
||||||
requireContext(),
|
{ installStep ->
|
||||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
val builder = NotificationCompat.Builder(
|
||||||
)
|
context,
|
||||||
.setSmallIcon(R.drawable.ic_round_sync_24)
|
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||||
.setContentTitle("Updating extension")
|
)
|
||||||
.setContentText("Step: $installStep")
|
.setSmallIcon(R.drawable.ic_round_sync_24)
|
||||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
.setContentTitle("Updating extension")
|
||||||
notificationManager.notify(1, builder.build())
|
.setContentText("Step: $installStep")
|
||||||
},
|
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||||
{ error ->
|
notificationManager.notify(1, builder.build())
|
||||||
val builder = NotificationCompat.Builder(
|
},
|
||||||
requireContext(),
|
{ error ->
|
||||||
Notifications.CHANNEL_DOWNLOADER_ERROR
|
Log.e("MangaExtensionsAdapter", "Error: ", error) // Log the error
|
||||||
)
|
val builder = NotificationCompat.Builder(
|
||||||
.setSmallIcon(R.drawable.ic_round_info_24)
|
context,
|
||||||
.setContentTitle("Update failed")
|
Notifications.CHANNEL_DOWNLOADER_ERROR
|
||||||
.setContentText("Error: ${error.message}")
|
)
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
.setSmallIcon(R.drawable.ic_round_info_24)
|
||||||
notificationManager.notify(1, builder.build())
|
.setContentTitle("Update failed")
|
||||||
},
|
.setContentText("Error: ${error.message}")
|
||||||
{
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||||
val builder = NotificationCompat.Builder(
|
notificationManager.notify(1, builder.build())
|
||||||
requireContext(),
|
},
|
||||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
{
|
||||||
)
|
val builder = NotificationCompat.Builder(
|
||||||
.setSmallIcon(androidx.media3.ui.R.drawable.exo_ic_check)
|
context,
|
||||||
.setContentTitle("Update complete")
|
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||||
.setContentText("The extension has been successfully updated.")
|
)
|
||||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
.setSmallIcon(androidx.media3.ui.R.drawable.exo_ic_check)
|
||||||
notificationManager.notify(1, builder.build())
|
.setContentTitle("Update complete")
|
||||||
}
|
.setContentText("The extension has been successfully updated.")
|
||||||
)
|
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||||
}else {
|
notificationManager.notify(1, builder.build())
|
||||||
mangaExtensionManager.uninstallExtension(pkg.pkgName)
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
mangaExtensionManager.uninstallExtension(pkg.pkgName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, skipIcons)
|
}, skipIcons)
|
||||||
|
|
||||||
private val allExtensionsAdapter =
|
private val allExtensionsAdapter =
|
||||||
AllMangaExtensionsAdapter(lifecycleScope, { pkgName ->
|
AllMangaExtensionsAdapter(lifecycleScope, { pkgName ->
|
||||||
|
|
||||||
|
@ -132,15 +142,19 @@ class MangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
)
|
)
|
||||||
}, skipIcons)
|
}, skipIcons)
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
_binding = FragmentMangaExtensionsBinding.inflate(inflater, container, false)
|
_binding = FragmentMangaExtensionsBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
extensionsRecyclerView = binding.mangaExtensionsRecyclerView
|
extensionsRecyclerView = binding.mangaExtensionsRecyclerView
|
||||||
extensionsRecyclerView.layoutManager = LinearLayoutManager( requireContext())
|
extensionsRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||||
extensionsRecyclerView.adapter = extensionsAdapter
|
extensionsRecyclerView.adapter = extensionsAdapter
|
||||||
|
|
||||||
allextenstionsRecyclerView = binding.allMangaExtensionsRecyclerView
|
allextenstionsRecyclerView = binding.allMangaExtensionsRecyclerView
|
||||||
allextenstionsRecyclerView.layoutManager = LinearLayoutManager( requireContext())
|
allextenstionsRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||||
allextenstionsRecyclerView.adapter = allExtensionsAdapter
|
allextenstionsRecyclerView.adapter = allExtensionsAdapter
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
|
@ -161,7 +175,6 @@ class MangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val extensionsRecyclerView: RecyclerView = binding.mangaExtensionsRecyclerView
|
val extensionsRecyclerView: RecyclerView = binding.mangaExtensionsRecyclerView
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,14 +194,18 @@ class MangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
super.onDestroyView();_binding = null
|
super.onDestroyView();_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MangaExtensionsAdapter(private val onUninstallClicked: (MangaExtension.Installed) -> Unit, skipIcons: Boolean) : RecyclerView.Adapter<MangaExtensionsAdapter.ViewHolder>() {
|
private class MangaExtensionsAdapter(
|
||||||
|
private val onUninstallClicked: (MangaExtension.Installed) -> Unit,
|
||||||
|
skipIcons: Boolean
|
||||||
|
) : ListAdapter<MangaExtension.Installed, MangaExtensionsAdapter.ViewHolder>(
|
||||||
|
DIFF_CALLBACK_INSTALLED
|
||||||
|
) {
|
||||||
|
|
||||||
private var extensions: List<MangaExtension.Installed> = emptyList()
|
|
||||||
val skipIcons = skipIcons
|
val skipIcons = skipIcons
|
||||||
|
|
||||||
|
// Use submitList to update data
|
||||||
fun updateData(newExtensions: List<MangaExtension.Installed>) {
|
fun updateData(newExtensions: List<MangaExtension.Installed>) {
|
||||||
extensions = newExtensions
|
submitList(newExtensions)
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
@ -198,75 +215,118 @@ class MangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val extension = extensions[position]
|
val extension = getItem(position) // Use getItem from ListAdapter
|
||||||
|
|
||||||
holder.extensionNameTextView.text = extension.name
|
holder.extensionNameTextView.text = extension.name
|
||||||
if(!skipIcons) {
|
if (!skipIcons) {
|
||||||
holder.extensionIconImageView.setImageDrawable(extension.icon)
|
holder.extensionIconImageView.setImageDrawable(extension.icon)
|
||||||
}
|
}
|
||||||
if(extension.hasUpdate){
|
|
||||||
|
if (extension.hasUpdate) {
|
||||||
holder.closeTextView.text = "Update"
|
holder.closeTextView.text = "Update"
|
||||||
holder.closeTextView.setTextColor(ContextCompat.getColor(holder.itemView.context, R.color.warning))
|
holder.closeTextView.setTextColor(
|
||||||
}else{
|
ContextCompat.getColor(
|
||||||
|
holder.itemView.context,
|
||||||
|
R.color.warning
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
holder.closeTextView.text = "Uninstall"
|
holder.closeTextView.text = "Uninstall"
|
||||||
}
|
}
|
||||||
|
|
||||||
holder.closeTextView.setOnClickListener {
|
holder.closeTextView.setOnClickListener {
|
||||||
onUninstallClicked(extension)
|
onUninstallClicked(extension)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int = extensions.size
|
|
||||||
|
|
||||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
||||||
val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView)
|
val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView)
|
||||||
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val DIFF_CALLBACK_INSTALLED =
|
||||||
|
object : DiffUtil.ItemCallback<MangaExtension.Installed>() {
|
||||||
|
override fun areItemsTheSame(
|
||||||
|
oldItem: MangaExtension.Installed,
|
||||||
|
newItem: MangaExtension.Installed
|
||||||
|
): Boolean {
|
||||||
|
return oldItem.pkgName == newItem.pkgName
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(
|
||||||
|
oldItem: MangaExtension.Installed,
|
||||||
|
newItem: MangaExtension.Installed
|
||||||
|
): Boolean {
|
||||||
|
return oldItem == newItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AllMangaExtensionsAdapter(private val coroutineScope: CoroutineScope,
|
|
||||||
private val onButtonClicked: (MangaExtension.Available) -> Unit, skipIcons: Boolean) : RecyclerView.Adapter<AllMangaExtensionsAdapter.ViewHolder>() {
|
|
||||||
private var extensions: List<MangaExtension.Available> = emptyList()
|
|
||||||
val skipIcons = skipIcons
|
|
||||||
|
|
||||||
fun updateData(newExtensions: List<MangaExtension.Available>, installedExtensions: List<MangaExtension.Installed> = emptyList()) {
|
private class AllMangaExtensionsAdapter(
|
||||||
val installedPkgNames = installedExtensions.map { it.pkgName }.toSet()
|
private val coroutineScope: CoroutineScope,
|
||||||
extensions = newExtensions.filter { it.pkgName !in installedPkgNames }
|
private val onButtonClicked: (MangaExtension.Available) -> Unit,
|
||||||
filteredExtensions = extensions
|
skipIcons: Boolean
|
||||||
notifyDataSetChanged()
|
) : ListAdapter<MangaExtension.Available, AllMangaExtensionsAdapter.ViewHolder>(
|
||||||
|
DIFF_CALLBACK_AVAILABLE
|
||||||
|
) {
|
||||||
|
init {
|
||||||
|
setHasStableIds(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AllMangaExtensionsAdapter.ViewHolder {
|
|
||||||
|
val skipIcons = skipIcons
|
||||||
|
|
||||||
|
// Use submitList to update the data
|
||||||
|
fun updateData(
|
||||||
|
newExtensions: List<MangaExtension.Available>,
|
||||||
|
installedExtensions: List<MangaExtension.Installed> = emptyList()
|
||||||
|
) {
|
||||||
|
coroutineScope.launch(Dispatchers.Default) {
|
||||||
|
val installedPkgNames = installedExtensions.map { it.pkgName }.toSet()
|
||||||
|
val filteredExtensions = newExtensions.filter { it.pkgName !in installedPkgNames }
|
||||||
|
|
||||||
|
// Switch back to main thread to update UI
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
submitList(filteredExtensions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
val view = LayoutInflater.from(parent.context)
|
val view = LayoutInflater.from(parent.context)
|
||||||
.inflate(R.layout.item_extension_all, parent, false)
|
.inflate(R.layout.item_extension_all, parent, false)
|
||||||
return ViewHolder(view)
|
return ViewHolder(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val extension = filteredExtensions[position]
|
val extension = getItem(position) // Use getItem from ListAdapter
|
||||||
|
|
||||||
holder.extensionNameTextView.text = extension.name
|
holder.extensionNameTextView.text = extension.name
|
||||||
if (!skipIcons) {
|
if (!skipIcons) {
|
||||||
coroutineScope.launch {
|
Glide.with(holder.itemView.context)
|
||||||
val drawable = urlToDrawable(holder.itemView.context, extension.iconUrl)
|
.load(extension.iconUrl)
|
||||||
holder.extensionIconImageView.setImageDrawable(drawable)
|
.into(holder.extensionIconImageView)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
holder.closeTextView.text = "Install"
|
holder.closeTextView.text = "Install"
|
||||||
holder.closeTextView.setOnClickListener {
|
holder.closeTextView.setOnClickListener {
|
||||||
onButtonClicked(extension)
|
onButtonClicked(extension)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int = filteredExtensions.size
|
// Filtering function
|
||||||
|
|
||||||
private var filteredExtensions: List<MangaExtension.Available> = emptyList()
|
|
||||||
|
|
||||||
fun filter(query: String) {
|
fun filter(query: String) {
|
||||||
filteredExtensions = if (query.isEmpty()) {
|
val filteredExtensions = if (query.isEmpty()) {
|
||||||
extensions
|
currentList
|
||||||
} else {
|
} else {
|
||||||
extensions.filter { it.name.contains(query, ignoreCase = true) }
|
currentList.filter { it.name.contains(query, ignoreCase = true) }
|
||||||
}
|
}
|
||||||
notifyDataSetChanged()
|
submitList(filteredExtensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
@ -275,18 +335,24 @@ class MangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun urlToDrawable(context: Context, url: String): Drawable? {
|
companion object {
|
||||||
return withContext(Dispatchers.IO) {
|
val DIFF_CALLBACK_AVAILABLE =
|
||||||
try {
|
object : DiffUtil.ItemCallback<MangaExtension.Available>() {
|
||||||
return@withContext Glide.with(context)
|
override fun areItemsTheSame(
|
||||||
.load(url)
|
oldItem: MangaExtension.Available,
|
||||||
.submit()
|
newItem: MangaExtension.Available
|
||||||
.get()
|
): Boolean {
|
||||||
} catch (e: Exception) {
|
return oldItem.pkgName == newItem.pkgName
|
||||||
e.printStackTrace()
|
}
|
||||||
return@withContext null
|
|
||||||
|
override fun areContentsTheSame(
|
||||||
|
oldItem: MangaExtension.Available,
|
||||||
|
newItem: MangaExtension.Available
|
||||||
|
): Boolean {
|
||||||
|
return oldItem == newItem
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -100,16 +100,18 @@ OS Version: $CODENAME $RELEASE ($SDK_INT)
|
||||||
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit().putBoolean("use_material_you", isChecked).apply()
|
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit().putBoolean("use_material_you", isChecked).apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
val animeSource = loadData<Int>("settings_def_anime_source_s")?.let { if (it >= AnimeSources.names.size) 0 else it } ?: 0
|
//val animeSource = loadData<Int>("settings_def_anime_source_s")?.let { if (it >= AnimeSources.names.size) 0 else it } ?: 0
|
||||||
if (MangaSources.names.isNotEmpty() && animeSource in 0 until MangaSources.names.size) {
|
val animeSource = getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getInt("settings_def_anime_source_s_r", 0)
|
||||||
binding.mangaSource.setText(MangaSources.names[animeSource], false)
|
if (AnimeSources.names.isNotEmpty() && animeSource in 0 until AnimeSources.names.size) {
|
||||||
|
binding.animeSource.setText(AnimeSources.names[animeSource], false)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.animeSource.setAdapter(ArrayAdapter(this, R.layout.item_dropdown, AnimeSources.names))
|
binding.animeSource.setAdapter(ArrayAdapter(this, R.layout.item_dropdown, AnimeSources.names))
|
||||||
|
|
||||||
binding.animeSource.setOnItemClickListener { _, _, i, _ ->
|
binding.animeSource.setOnItemClickListener { _, _, i, _ ->
|
||||||
saveData("settings_def_anime_source_s", i)
|
//saveData("settings_def_anime_source_s", i)
|
||||||
|
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit().putInt("settings_def_anime_source_s_r", i).apply()
|
||||||
binding.animeSource.clearFocus()
|
binding.animeSource.clearFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +188,8 @@ OS Version: $CODENAME $RELEASE ($SDK_INT)
|
||||||
saveData("settings_prefer_dub", isChecked)
|
saveData("settings_prefer_dub", isChecked)
|
||||||
}
|
}
|
||||||
|
|
||||||
val mangaSource = loadData<Int>("settings_def_manga_source_s")?.let { if (it >= MangaSources.names.size) 0 else it } ?: 0
|
//val mangaSource = loadData<Int>("settings_def_manga_source_s")?.let { if (it >= MangaSources.names.size) 0 else it } ?: 0
|
||||||
|
val mangaSource = getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getInt("settings_def_manga_source_s_r", 0)
|
||||||
if (MangaSources.names.isNotEmpty() && mangaSource in 0 until MangaSources.names.size) {
|
if (MangaSources.names.isNotEmpty() && mangaSource in 0 until MangaSources.names.size) {
|
||||||
binding.mangaSource.setText(MangaSources.names[mangaSource], false)
|
binding.mangaSource.setText(MangaSources.names[mangaSource], false)
|
||||||
}
|
}
|
||||||
|
@ -196,7 +199,8 @@ OS Version: $CODENAME $RELEASE ($SDK_INT)
|
||||||
|
|
||||||
// Set up the item click listener for the dropdown.
|
// Set up the item click listener for the dropdown.
|
||||||
binding.mangaSource.setOnItemClickListener { _, _, i, _ ->
|
binding.mangaSource.setOnItemClickListener { _, _, i, _ ->
|
||||||
saveData("settings_def_manga_source_s", i)
|
//saveData("settings_def_manga_source_s", i)
|
||||||
|
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit().putInt("settings_def_manga_source_s_r", i).apply()
|
||||||
binding.mangaSource.clearFocus()
|
binding.mangaSource.clearFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,12 @@ import kotlinx.coroutines.withTimeoutOrNull
|
||||||
class SubscriptionHelper {
|
class SubscriptionHelper {
|
||||||
companion object {
|
companion object {
|
||||||
private fun loadSelected(context: Context, mediaId: Int, isAdult: Boolean, isAnime: Boolean): Selected {
|
private fun loadSelected(context: Context, mediaId: Int, isAdult: Boolean, isAnime: Boolean): Selected {
|
||||||
|
val sharedPreferences = context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
|
||||||
val data = loadData<Selected>("${mediaId}-select", context) ?: Selected().let {
|
val data = loadData<Selected>("${mediaId}-select", context) ?: Selected().let {
|
||||||
it.sourceIndex =
|
it.sourceIndex =
|
||||||
if (isAdult) 0
|
if (isAdult) 0
|
||||||
else if (isAnime) {loadData("settings_def_anime_source_s_r", context) ?: 0}
|
else if (isAnime) {sharedPreferences.getInt("settings_def_anime_source_s_r",0)}
|
||||||
else loadData("settings_def_manga_source_s_r", context) ?: 0
|
else {sharedPreferences.getInt("settings_def_manga_source_s_r",0)}
|
||||||
it.preferDub = loadData("settings_prefer_dub", context) ?: false
|
it.preferDub = loadData("settings_prefer_dub", context) ?: false
|
||||||
it
|
it
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import rx.subjects.Subject
|
import rx.subjects.Subject
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
data class Track(val url: String, val lang: String)
|
data class Track(val url: String, val lang: String)
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ open class Video(
|
||||||
// "url", "language-label-2", "url2", "language-label-2"
|
// "url", "language-label-2", "url2", "language-label-2"
|
||||||
val subtitleTracks: List<Track> = emptyList(),
|
val subtitleTracks: List<Track> = emptyList(),
|
||||||
val audioTracks: List<Track> = emptyList(),
|
val audioTracks: List<Track> = emptyList(),
|
||||||
) : ProgressListener {
|
) : Serializable, ProgressListener {
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
constructor(
|
constructor(
|
||||||
|
|
67
app/src/main/res/drawable-v24/ic_banner_foreground.xml
Normal file
67
app/src/main/res/drawable-v24/ic_banner_foreground.xml
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
|
android:width="320dp"
|
||||||
|
android:height="180dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<group android:scaleX="0.6666667"
|
||||||
|
android:scaleY="0.6666667"
|
||||||
|
android:translateX="18"
|
||||||
|
android:translateY="18">
|
||||||
|
<group android:scaleX="0.5625"
|
||||||
|
android:translateX="-5.535">
|
||||||
|
<path
|
||||||
|
android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||||
|
android:fillType="evenOdd">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient
|
||||||
|
android:startY="49.59793"
|
||||||
|
android:startX="42.9492"
|
||||||
|
android:endY="92.4963"
|
||||||
|
android:endX="85.84757"
|
||||||
|
android:type="linear">
|
||||||
|
<item
|
||||||
|
android:color="#44000000"
|
||||||
|
android:offset="0"/>
|
||||||
|
<item
|
||||||
|
android:color="#00000000"
|
||||||
|
android:offset="1"/>
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||||
|
android:fillColor="#3DDC84"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:strokeColor="#00000000"/>
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<group android:scaleX="0.492"
|
||||||
|
android:scaleY="0.24750866"
|
||||||
|
android:translateX="277.2"
|
||||||
|
android:translateY="73.782364">
|
||||||
|
<group android:translateY="145.33594">
|
||||||
|
<path android:pathData="M12.796875,-0L12.796875,-101.109375L34.171875,-101.109375Q42.828125,-101.109375,50.234375,-100.234375Q57.65625,-99.359375,63.84375,-97.171875Q70.03125,-95,74.703125,-91.375Q79.390625,-87.75,82.765625,-82.125Q86.0625,-76.5,87.75,-68.765625Q89.4375,-61.03125,89.4375,-50.5625Q89.4375,-40.078125,87.75,-32.34375Q86.0625,-24.609375,82.765625,-18.984375Q79.390625,-13.359375,74.703125,-9.734375Q70.03125,-6.125,63.84375,-3.9375Q57.65625,-1.765625,50.234375,-0.875Q42.828125,-0,34.171875,-0L12.796875,-0ZM36.359375,-10.828125Q47.109375,-10.828125,54.59375,-12.96875Q62.09375,-15.125,66.875,-19.96875Q71.578125,-24.828125,73.71875,-32.3125Q75.875,-39.796875,75.875,-50.5625Q75.875,-61.3125,73.71875,-68.796875Q71.578125,-76.296875,66.875,-81.140625Q62.09375,-86,54.59375,-88.140625Q47.109375,-90.28125,36.359375,-90.28125L26.015625,-90.28125L26.015625,-10.828125L36.359375,-10.828125Z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
<path android:pathData="M113.109375,-60.1875L110.015625,-70.03125Q121.828125,-74.75,134.76562,-74.75Q146.07812,-74.75,152.0625,-70.953125Q158.875,-66.59375,158.875,-56.109375L158.875,-27.359375Q158.875,-21.59375,159.01562,-15.546875Q159.09375,-11.953125,159.71875,-8.09375Q160.28125,-4.4375,161.20312,-1.125L149.67188,1.40625Q148.04688,-3.3125,147.625,-9.140625L146.21875,-9.28125Q137.5,1.6875,124,1.6875Q114.15625,1.6875,108.171875,-3.765625Q102.203125,-9.21875,102.203125,-19.125Q102.203125,-26.515625,105.46875,-31.21875Q108.75,-35.9375,114.71875,-39.171875Q124.140625,-44.296875,141.09375,-44.296875Q143.34375,-44.296875,147.14062,-44.15625L147.14062,-54.84375Q147.14062,-59.90625,144.04688,-62.15625Q140.95312,-64.40625,134.34375,-64.40625Q124.703125,-64.40625,113.109375,-60.1875ZM147.14062,-20.53125L147.14062,-35.296875Q145.23438,-35.4375,141.57812,-35.4375Q135.39062,-35.4375,130.1875,-34.390625Q122.453125,-32.84375,118.203125,-29.5Q113.953125,-26.15625,113.953125,-19.90625Q113.953125,-8.65625,126.1875,-8.65625Q132.51562,-8.65625,138,-12.03125Q142.5,-14.84375,147.14062,-20.53125Z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
<path android:pathData="M179.5,-71.859375L191.17188,-74.46875Q192.5,-70.25,193.0625,-66.3125Q193.34375,-64.40625,193.76562,-58.78125L195.25,-58.78125Q199.10938,-65.890625,204.8125,-70.109375Q211.0625,-74.75,218.03125,-74.75Q228.5,-74.75,233.98438,-69.6875Q238.70312,-65.390625,240.53125,-56.53125Q241.71875,-50.484375,241.71875,-38.53125L241.71875,0L229.625,0L229.625,-41.90625Q229.625,-52.390625,227.59375,-56.890625Q224.5625,-63.5625,215.42188,-63.5625Q208.95312,-63.5625,202.76562,-57.375Q198.625,-53.234375,193.90625,-45.21875L193.90625,0L181.8125,0L181.8125,-45Q181.8125,-54.5,181.32812,-61.390625Q181.04688,-65.671875,179.5,-71.859375Z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
<path android:pathData="M269.28125,-89.859375L281.375,-89.859375L281.375,-73.125L305.98438,-73.125L305.98438,-62.9375L281.375,-62.9375L281.375,-20.953125Q281.375,-16.734375,281.625,-14.515625Q281.875,-12.3125,282.85938,-11.046875Q284.6875,-8.515625,290.23438,-8.515625Q293.32812,-8.515625,296.21875,-9.140625Q299.17188,-9.78125,301.625,-10.546875Q303.59375,-6.265625,305.21875,-1.125Q296.92188,1.6875,288.48438,1.6875Q282.35938,1.6875,278.67188,0.3125Q274.98438,-1.0625,272.875,-4.15625Q270.6875,-7.390625,269.98438,-11.890625Q269.28125,-16.390625,269.28125,-24.328125L269.28125,-62.9375L258.73438,-62.9375L258.73438,-73.125L269.28125,-73.125L269.28125,-89.859375Z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
<path android:pathData="M351.03125,-74.75Q354.46875,-74.75,358.1875,-74.21875Q361.92188,-73.6875,365.51562,-72.21875Q369.09375,-70.671875,372.29688,-68.03125Q375.5,-65.390625,377.95312,-61.171875Q380.42188,-56.890625,381.82812,-50.875Q383.23438,-44.859375,383.23438,-36.5625Q383.23438,-28.265625,381.82812,-22.25Q380.42188,-16.25,377.95312,-12.03125Q375.5,-7.734375,372.29688,-5.0625Q369.09375,-2.390625,365.51562,-0.921875Q361.92188,0.640625,358.1875,1.15625Q354.46875,1.6875,351.03125,1.6875Q347.65625,1.6875,343.95312,1.15625Q340.26562,0.640625,336.6875,-0.921875Q333.09375,-2.390625,329.92188,-5.0625Q326.76562,-7.734375,324.3125,-12.03125Q321.84375,-16.25,320.4375,-22.25Q319.03125,-28.265625,319.03125,-36.5625Q319.03125,-44.859375,320.4375,-50.875Q321.84375,-56.890625,324.3125,-61.171875Q326.76562,-65.390625,329.92188,-68.03125Q333.09375,-70.671875,336.6875,-72.21875Q340.26562,-73.6875,343.92188,-74.21875Q347.57812,-74.75,351.03125,-74.75ZM351.03125,-64.828125Q347.01562,-64.828125,343.46875,-63.5625Q339.92188,-62.296875,337.25,-59.140625Q334.5,-55.90625,332.875,-50.484375Q331.26562,-45.078125,331.26562,-36.5625Q331.26562,-28.125,332.875,-22.671875Q334.5,-17.234375,337.25,-14.0625Q339.92188,-10.828125,343.46875,-9.59375Q347.01562,-8.375,351.03125,-8.375Q355.10938,-8.375,358.71875,-9.59375Q362.34375,-10.828125,365.09375,-14.0625Q367.82812,-17.234375,369.40625,-22.671875Q371,-28.125,371,-36.5625Q371,-45.078125,369.40625,-50.484375Q367.82812,-55.90625,365.09375,-59.140625Q362.34375,-62.296875,358.71875,-63.5625Q355.10938,-64.828125,351.03125,-64.828125Z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
<path android:pathData="M408.28125,-89.859375L420.375,-89.859375L420.375,-73.125L444.98438,-73.125L444.98438,-62.9375L420.375,-62.9375L420.375,-20.953125Q420.375,-16.734375,420.625,-14.515625Q420.875,-12.3125,421.85938,-11.046875Q423.6875,-8.515625,429.23438,-8.515625Q432.32812,-8.515625,435.21875,-9.140625Q438.17188,-9.78125,440.625,-10.546875Q442.59375,-6.265625,444.21875,-1.125Q435.92188,1.6875,427.48438,1.6875Q421.35938,1.6875,417.67188,0.3125Q413.98438,-1.0625,411.875,-4.15625Q409.6875,-7.390625,408.98438,-11.890625Q408.28125,-16.390625,408.28125,-24.328125L408.28125,-62.9375L397.73438,-62.9375L397.73438,-73.125L408.28125,-73.125L408.28125,-89.859375Z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
<path android:pathData="M484.54688,-74.75Q490.3125,-74.75,496.10938,-73.546875Q501.90625,-72.359375,506.90625,-70.25Q505.92188,-68,504.85938,-65.8125Q503.8125,-63.640625,502.54688,-61.53125Q500.78125,-62.234375,498.64062,-62.9375Q496.5,-63.640625,494.14062,-64.125Q491.78125,-64.625,489.28125,-64.9375Q486.79688,-65.25,484.40625,-65.25Q481.79688,-65.25,479.375,-64.71875Q476.95312,-64.203125,475.07812,-63Q473.21875,-61.8125,472.09375,-59.875Q470.96875,-57.9375,470.96875,-55.0625Q470.96875,-52.109375,472.23438,-50.09375Q473.5,-48.09375,475.67188,-46.75Q477.85938,-45.421875,480.78125,-44.5Q483.70312,-43.59375,487,-42.828125Q492.14062,-41.5625,496.5625,-39.96875Q501,-38.390625,504.23438,-35.859375Q507.46875,-33.328125,509.29688,-29.59375Q511.125,-25.875,511.125,-20.390625Q511.125,-14.625,508.82812,-10.46875Q506.54688,-6.328125,502.64062,-3.625Q498.75,-0.921875,493.54688,0.375Q488.34375,1.6875,482.4375,1.6875Q479.34375,1.6875,476.0625,1.296875Q472.79688,0.921875,469.59375,0.171875Q466.40625,-0.5625,463.3125,-1.609375Q460.21875,-2.671875,457.46875,-3.9375Q458.45312,-6.1875,459.54688,-8.328125Q460.64062,-10.484375,461.82812,-12.59375Q464.15625,-11.609375,466.75,-10.71875Q469.35938,-9.84375,472.09375,-9.203125Q474.84375,-8.578125,477.51562,-8.1875Q480.1875,-7.8125,482.64062,-7.8125Q485.73438,-7.8125,488.65625,-8.515625Q491.57812,-9.21875,493.85938,-10.71875Q496.14062,-12.234375,497.51562,-14.625Q498.89062,-17.015625,498.89062,-20.390625Q498.89062,-23.5625,497.57812,-25.59375Q496.28125,-27.640625,494.09375,-29Q491.92188,-30.375,489,-31.25Q486.09375,-32.140625,482.85938,-32.90625Q477.9375,-34.109375,473.53125,-35.65625Q469.14062,-37.203125,465.875,-39.6875Q462.60938,-42.1875,460.67188,-45.875Q458.73438,-49.578125,458.73438,-55.0625Q458.73438,-60.1875,460.84375,-63.90625Q462.95312,-67.640625,466.5,-70.03125Q470.0625,-72.421875,474.73438,-73.578125Q479.40625,-74.75,484.54688,-74.75Z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
<path android:pathData="M590.28125,-1.265625L578.6094,1.34375Q577.28125,-2.890625,576.71875,-6.828125Q576.4375,-8.65625,576.0156,-14.28125L574.53125,-14.28125Q570.6719,-7.171875,564.96875,-2.953125Q558.71875,1.6875,551.75,1.6875Q541.28125,1.6875,535.7969,-3.375Q531.0781,-7.671875,529.25,-16.53125Q528.0625,-22.578125,528.0625,-34.53125L528.0625,-73.125L540.15625,-73.125L540.15625,-31.15625Q540.15625,-20.671875,542.1875,-16.171875Q545.21875,-9.5,554.3594,-9.5Q560.8281,-9.5,567.0156,-15.6875Q571.15625,-19.828125,575.875,-27.84375L575.875,-73.125L587.96875,-73.125L587.96875,-27.984375Q587.96875,-18.640625,588.4531,-11.75Q588.7344,-7.453125,590.28125,-1.265625Z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
<path android:pathData="M644.78125,0L644.78125,-95.984375L683.03125,-95.984375L683.03125,0L644.78125,0ZM649.5625,-4.78125L678.25,-4.78125L678.25,-91.203125L649.5625,-91.203125L649.5625,-4.78125Z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</vector>
|
5
app/src/main/res/mipmap-anydpi-v26/ic_banner.xml
Normal file
5
app/src/main/res/mipmap-anydpi-v26/ic_banner.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_banner_background"/>
|
||||||
|
<foreground android:drawable="@drawable/ic_banner_foreground"/>
|
||||||
|
</adaptive-icon>
|
BIN
app/src/main/res/mipmap-xhdpi/ic_banner.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/ic_banner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
4
app/src/main/res/values/ic_banner_background.xml
Normal file
4
app/src/main/res/values/ic_banner_background.xml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_banner_background">#FFFFFF</color>
|
||||||
|
</resources>
|
Loading…
Add table
Add a link
Reference in a new issue