Merge pull request #559 from rebelonion/dev

Dev
This commit is contained in:
rebel onion 2025-01-06 08:29:48 -06:00 committed by GitHub
commit f606bef2a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
106 changed files with 951 additions and 612 deletions

View file

@ -18,7 +18,9 @@ import ani.dantotsu.Mapper
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.buildMarkwon import ani.dantotsu.buildMarkwon
import ani.dantotsu.client import ani.dantotsu.client
import ani.dantotsu.connections.comments.CommentsAPI
import ani.dantotsu.currContext import ani.dantotsu.currContext
import ani.dantotsu.decodeBase64ToString
import ani.dantotsu.logError import ani.dantotsu.logError
import ani.dantotsu.openLinkInBrowser import ani.dantotsu.openLinkInBrowser
import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefManager
@ -37,26 +39,88 @@ import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
object AppUpdater { object AppUpdater {
private val fallbackStableUrl: String
get() = "aHR0cHM6Ly9hcGkuZGFudG90c3UuYXBwL3VwZGF0ZXMvc3RhYmxl".decodeBase64ToString()
private val fallbackBetaUrl: String
get() = "aHR0cHM6Ly9hcGkuZGFudG90c3UuYXBwL3VwZGF0ZXMvYmV0YQ==".decodeBase64ToString()
@Serializable
data class FallbackResponse(
val version: String,
val changelog: String,
val downloadUrl: String? = null
)
private suspend fun fetchUpdateInfo(repo: String, isDebug: Boolean): Pair<String, String>? {
return try {
fetchFromGithub(repo, isDebug)
} catch (e: Exception) {
Logger.log("Github fetch failed, trying fallback: ${e.message}")
try {
fetchFromFallback(isDebug)
} catch (e: Exception) {
Logger.log("Fallback fetch failed: ${e.message}")
null
}
}
}
private suspend fun fetchFromGithub(repo: String, isDebug: Boolean): Pair<String, String> {
return if (isDebug) {
val res = client.get("https://api.github.com/repos/$repo/releases")
.parsed<JsonArray>().map {
Mapper.json.decodeFromJsonElement<GithubResponse>(it)
}
val r = res.filter { it.prerelease }.filter { !it.tagName.contains("fdroid") }
.maxByOrNull {
it.timeStamp()
} ?: throw Exception("No Pre Release Found")
val v = r.tagName.substringAfter("v", "")
(r.body ?: "") to v.ifEmpty { throw Exception("Weird Version : ${r.tagName}") }
} else {
val res = client.get("https://raw.githubusercontent.com/$repo/main/stable.md").text
res to res.substringAfter("# ").substringBefore("\n")
}
}
private suspend fun fetchFromFallback(isDebug: Boolean): Pair<String, String> {
val url = if (isDebug) fallbackBetaUrl else fallbackStableUrl
val response = CommentsAPI.requestBuilder().get(url).parsed<FallbackResponse>()
return response.changelog to response.version
}
private suspend fun fetchApkUrl(repo: String, version: String, isDebug: Boolean): String? {
return try {
fetchApkUrlFromGithub(repo, version)
} catch (e: Exception) {
Logger.log("Github APK fetch failed, trying fallback: ${e.message}")
try {
fetchApkUrlFromFallback(version, isDebug)
} catch (e: Exception) {
Logger.log("Fallback APK fetch failed: ${e.message}")
null
}
}
}
private suspend fun fetchApkUrlFromGithub(repo: String, version: String): String? {
val apks = client.get("https://api.github.com/repos/$repo/releases/tags/v$version")
.parsed<GithubResponse>().assets?.filter {
it.browserDownloadURL.endsWith(".apk")
}
return apks?.firstOrNull()?.browserDownloadURL
}
private suspend fun fetchApkUrlFromFallback(version: String, isDebug: Boolean): String? {
val url = if (isDebug) fallbackBetaUrl else fallbackStableUrl
return CommentsAPI.requestBuilder().get("$url/$version").parsed<FallbackResponse>().downloadUrl
}
suspend fun check(activity: FragmentActivity, post: Boolean = false) { suspend fun check(activity: FragmentActivity, post: Boolean = false) {
if (post) snackString(currContext()?.getString(R.string.checking_for_update)) if (post) snackString(currContext()?.getString(R.string.checking_for_update))
val repo = activity.getString(R.string.repo) val repo = activity.getString(R.string.repo)
tryWithSuspend { tryWithSuspend {
val (md, version) = if (BuildConfig.DEBUG) { val (md, version) = fetchUpdateInfo(repo, BuildConfig.DEBUG) ?: return@tryWithSuspend
val res = client.get("https://api.github.com/repos/$repo/releases")
.parsed<JsonArray>().map {
Mapper.json.decodeFromJsonElement<GithubResponse>(it)
}
val r = res.filter { it.prerelease }.filter { !it.tagName.contains("fdroid") }
.maxByOrNull {
it.timeStamp()
} ?: throw Exception("No Pre Release Found")
val v = r.tagName.substringAfter("v", "")
(r.body ?: "") to v.ifEmpty { throw Exception("Weird Version : ${r.tagName}") }
} else {
val res =
client.get("https://raw.githubusercontent.com/$repo/main/stable.md").text
res to res.substringAfter("# ").substringBefore("\n")
}
Logger.log("Git Version : $version") Logger.log("Git Version : $version")
val dontShow = PrefManager.getCustomVal("dont_ask_for_update_$version", false) val dontShow = PrefManager.getCustomVal("dont_ask_for_update_$version", false)
@ -69,7 +133,7 @@ object AppUpdater {
) )
addView( addView(
TextView(activity).apply { TextView(activity).apply {
val markWon = try { //slower phones can destroy the activity before this is done val markWon = try {
buildMarkwon(activity, false) buildMarkwon(activity, false)
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
return@runOnUiThread return@runOnUiThread
@ -89,17 +153,11 @@ object AppUpdater {
setPositiveButton(currContext()!!.getString(R.string.lets_go)) { setPositiveButton(currContext()!!.getString(R.string.lets_go)) {
MainScope().launch(Dispatchers.IO) { MainScope().launch(Dispatchers.IO) {
try { try {
val apks = val apkUrl = fetchApkUrl(repo, version, BuildConfig.DEBUG)
client.get("https://api.github.com/repos/$repo/releases/tags/v$version") if (apkUrl != null) {
.parsed<GithubResponse>().assets?.filter { activity.downloadUpdate(version, apkUrl)
it.browserDownloadURL.endsWith( } else {
".apk" openLinkInBrowser("https://github.com/repos/$repo/releases/tag/v$version")
)
}
val apkToDownload = apks?.first()
apkToDownload?.browserDownloadURL.apply {
if (this != null) activity.downloadUpdate(version, this)
else openLinkInBrowser("https://github.com/repos/$repo/releases/tag/v$version")
} }
} catch (e: Exception) { } catch (e: Exception) {
logError(e) logError(e)
@ -112,8 +170,7 @@ object AppUpdater {
} }
show(activity.supportFragmentManager, "dialog") show(activity.supportFragmentManager, "dialog")
} }
} } else {
else {
if (post) snackString(currContext()?.getString(R.string.no_update_found)) if (post) snackString(currContext()?.getString(R.string.no_update_found))
} }
} }
@ -144,8 +201,7 @@ object AppUpdater {
//Blatantly kanged from https://github.com/LagradOst/CloudStream-3/blob/master/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt //Blatantly kanged from https://github.com/LagradOst/CloudStream-3/blob/master/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt
private fun Activity.downloadUpdate(version: String, url: String): Boolean { private fun Activity.downloadUpdate(version: String, url: String) {
toast(getString(R.string.downloading_update, version)) toast(getString(R.string.downloading_update, version))
val downloadManager = this.getSystemService<DownloadManager>()!! val downloadManager = this.getSystemService<DownloadManager>()!!
@ -167,7 +223,7 @@ object AppUpdater {
logError(e) logError(e)
-1 -1
} }
if (id == -1L) return true if (id == -1L) return
ContextCompat.registerReceiver( ContextCompat.registerReceiver(
this, this,
object : BroadcastReceiver() { object : BroadcastReceiver() {
@ -188,7 +244,6 @@ object AppUpdater {
}, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE), }, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE),
ContextCompat.RECEIVER_EXPORTED ContextCompat.RECEIVER_EXPORTED
) )
return true
} }
private fun openApk(context: Context, uri: Uri) { private fun openApk(context: Context, uri: Uri) {

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> `<?xml version="1.0" encoding="utf-8"?>
<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">
@ -113,10 +113,8 @@
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<data android:host="*"/>
<data android:mimeType="application/epub+zip"/> <data android:mimeType="application/epub+zip"/>
<data android:mimeType="application/x-mobipocket-ebook" /> <data android:mimeType="application/x-mobipocket-ebook" />
<data android:mimeType="application/vnd.amazon.ebook" /> <data android:mimeType="application/vnd.amazon.ebook" />
@ -385,10 +383,10 @@
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" /> <data android:scheme="content" />
<data android:scheme="file" />
<data android:mimeType="*/*" /> <data android:mimeType="*/*" />
<data android:pathPattern=".*\\.ani" /> <data android:pathPattern=".*\\.ani" />
<data android:pathPattern=".*\\.sani" /> <data android:pathPattern=".*\\.sani" />
<data android:host="*" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />

View file

@ -107,9 +107,9 @@ class App : MultiDexApplication() {
if (PrefManager.getVal<Int>(PrefName.CommentsEnabled) == 0) { if (PrefManager.getVal<Int>(PrefName.CommentsEnabled) == 0) {
if (BuildConfig.FLAVOR.contains("fdroid")) { if (BuildConfig.FLAVOR.contains("fdroid")) {
PrefManager.setVal(PrefName.CommentsEnabled, 2) PrefManager.setVal(PrefName.CommentsEnabled, 2)
} else { } else {
PrefManager.setVal(PrefName.CommentsEnabled, 1) PrefManager.setVal(PrefName.CommentsEnabled, 1)
} }
} }
@ -136,9 +136,9 @@ class App : MultiDexApplication() {
downloadAddonManager = Injekt.get() downloadAddonManager = Injekt.get()
torrentAddonManager.init() torrentAddonManager.init()
downloadAddonManager.init() downloadAddonManager.init()
if (PrefManager.getVal<Int>(PrefName.CommentsEnabled) == 1) { if (PrefManager.getVal<Int>(PrefName.CommentsEnabled) == 1) {
CommentsAPI.fetchAuthToken(this@App) CommentsAPI.fetchAuthToken(this@App)
} }
val useAlarmManager = PrefManager.getVal<Boolean>(PrefName.UseAlarmManager) val useAlarmManager = PrefManager.getVal<Boolean>(PrefName.UseAlarmManager)
val scheduler = TaskScheduler.create(this@App, useAlarmManager) val scheduler = TaskScheduler.create(this@App, useAlarmManager)

View file

@ -117,7 +117,6 @@ import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withC
import com.bumptech.glide.load.resource.gif.GifDrawable import com.bumptech.glide.load.resource.gif.GifDrawable
import com.bumptech.glide.request.RequestListener import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.target.Target import com.bumptech.glide.request.target.Target
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.bottomnavigation.BottomNavigationView
@ -138,12 +137,9 @@ import io.noties.markwon.html.TagHandlerNoOp
import io.noties.markwon.image.AsyncDrawable import io.noties.markwon.image.AsyncDrawable
import io.noties.markwon.image.glide.GlideImagesPlugin import io.noties.markwon.image.glide.GlideImagesPlugin
import jp.wasabeef.glide.transformations.BlurTransformation import jp.wasabeef.glide.transformations.BlurTransformation
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope import kotlinx.coroutines.MainScope
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import nl.joery.animatedbottombar.AnimatedBottomBar import nl.joery.animatedbottombar.AnimatedBottomBar
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -157,6 +153,8 @@ import java.util.TimeZone
import java.util.Timer import java.util.Timer
import java.util.TimerTask import java.util.TimerTask
import kotlin.collections.set import kotlin.collections.set
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi
import kotlin.math.log2 import kotlin.math.log2
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@ -854,6 +852,7 @@ fun savePrefsToDownloads(
} }
) )
} }
@SuppressLint("StringFormatMatches") @SuppressLint("StringFormatMatches")
fun savePrefs(serialized: String, path: String, title: String, context: Context): File? { fun savePrefs(serialized: String, path: String, title: String, context: Context): File? {
var file = File(path, "$title.ani") var file = File(path, "$title.ani")
@ -921,6 +920,7 @@ fun shareImage(title: String, bitmap: Bitmap, context: Context) {
intent.putExtra(Intent.EXTRA_STREAM, contentUri) intent.putExtra(Intent.EXTRA_STREAM, contentUri)
context.startActivity(Intent.createChooser(intent, "Share $title")) context.startActivity(Intent.createChooser(intent, "Share $title"))
} }
@SuppressLint("StringFormatMatches") @SuppressLint("StringFormatMatches")
fun saveImage(image: Bitmap, path: String, imageFileName: String): File? { fun saveImage(image: Bitmap, path: String, imageFileName: String): File? {
val imageFile = File(path, "$imageFileName.png") val imageFile = File(path, "$imageFileName.png")
@ -1467,6 +1467,7 @@ fun buildMarkwon(
} }
return false return false
} }
override fun onLoadFailed( override fun onLoadFailed(
e: GlideException?, e: GlideException?,
model: Any?, model: Any?,
@ -1495,9 +1496,9 @@ fun buildMarkwon(
} }
fun getYoutubeId(url: String): String { fun getYoutubeId(url: String): String {
val regex = """(?:youtube\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|(?:youtu\.be|youtube\.com)/)([^"&?/\s]{11})|youtube\.com/""".toRegex() val regex =
"""(?:youtube\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|(?:youtu\.be|youtube\.com)/)([^"&?/\s]{11})|youtube\.com/""".toRegex()
val matchResult = regex.find(url) val matchResult = regex.find(url)
return matchResult?.groupValues?.getOrNull(1) ?: "" return matchResult?.groupValues?.getOrNull(1) ?: ""
} }
@ -1524,3 +1525,13 @@ fun getLanguageName(language: String): String? {
} }
return null return null
} }
@OptIn(ExperimentalEncodingApi::class)
fun String.decodeBase64ToString(): String {
return try {
String(Base64.decode(this), Charsets.UTF_8)
} catch (e: Exception) {
Logger.log(e)
""
}
}

View file

@ -26,9 +26,17 @@ interface DownloadAddonApiV2 {
statCallback: (Double) -> Unit statCallback: (Double) -> Unit
): Long ): Long
suspend fun customFFMpeg(command: String, videoUrls: List<String>, logCallback: (String) -> Unit): Long suspend fun customFFMpeg(
command: String,
videoUrls: List<String>,
logCallback: (String) -> Unit
): Long
suspend fun customFFProbe(command: String, videoUrls: List<String>, logCallback: (String) -> Unit) suspend fun customFFProbe(
command: String,
videoUrls: List<String>,
logCallback: (String) -> Unit
)
fun getState(sessionId: Long): String fun getState(sessionId: Long): String

View file

@ -6,11 +6,11 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.addons.AddonDownloader.Companion.hasUpdate import ani.dantotsu.addons.AddonDownloader.Companion.hasUpdate
import ani.dantotsu.addons.AddonInstallReceiver
import ani.dantotsu.addons.AddonListener import ani.dantotsu.addons.AddonListener
import ani.dantotsu.addons.AddonLoader import ani.dantotsu.addons.AddonLoader
import ani.dantotsu.addons.AddonManager import ani.dantotsu.addons.AddonManager
import ani.dantotsu.addons.LoadResult import ani.dantotsu.addons.LoadResult
import ani.dantotsu.addons.AddonInstallReceiver
import ani.dantotsu.media.AddonType import ani.dantotsu.media.AddonType
import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.settings.saving.PrefName

View file

@ -41,7 +41,8 @@ class TorrentServerService : Service() {
flags: Int, flags: Int,
startId: Int, startId: Int,
): Int { ): Int {
extension = Injekt.get<TorrentAddonManager>().extension?.extension ?: return START_NOT_STICKY extension =
Injekt.get<TorrentAddonManager>().extension?.extension ?: return START_NOT_STICKY
intent?.let { intent?.let {
if (it.action != null) { if (it.action != null) {
when (it.action) { when (it.action) {

View file

@ -8,7 +8,6 @@ import androidx.media3.common.util.UnstableApi
import androidx.media3.database.StandaloneDatabaseProvider import androidx.media3.database.StandaloneDatabaseProvider
import ani.dantotsu.addons.download.DownloadAddonManager import ani.dantotsu.addons.download.DownloadAddonManager
import ani.dantotsu.addons.torrent.TorrentAddonManager import ani.dantotsu.addons.torrent.TorrentAddonManager
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.download.DownloadsManager import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.media.manga.MangaCache import ani.dantotsu.media.manga.MangaCache
import ani.dantotsu.parsers.novel.NovelExtensionManager import ani.dantotsu.parsers.novel.NovelExtensionManager

View file

@ -145,7 +145,10 @@ class AnilistMutations {
return result?.get("errors") == null return result?.get("errors") == null
} }
suspend fun updateCustomLists(animeCustomLists: List<String>?, mangaCustomLists: List<String>?): Boolean { suspend fun updateCustomLists(
animeCustomLists: List<String>?,
mangaCustomLists: List<String>?
): Boolean {
val query = """ val query = """
mutation (${"$"}animeListOptions: MediaListOptionsInput, ${"$"}mangaListOptions: MediaListOptionsInput) { mutation (${"$"}animeListOptions: MediaListOptionsInput, ${"$"}mangaListOptions: MediaListOptionsInput) {
UpdateUser(animeListOptions: ${"$"}animeListOptions, mangaListOptions: ${"$"}mangaListOptions) { UpdateUser(animeListOptions: ${"$"}animeListOptions, mangaListOptions: ${"$"}mangaListOptions) {
@ -291,7 +294,8 @@ class AnilistMutations {
isFollower isFollower
} }
} }
""".trimIndent()) """.trimIndent()
)
} }
suspend fun toggleLike(id: Int, type: String): ToggleLike? { suspend fun toggleLike(id: Int, type: String): ToggleLike? {
@ -302,7 +306,8 @@ class AnilistMutations {
__typename __typename
} }
} }
""".trimIndent()) """.trimIndent()
)
} }
suspend fun postActivity(text: String, edit: Int? = null): String { suspend fun postActivity(text: String, edit: Int? = null): String {
@ -316,10 +321,16 @@ class AnilistMutations {
""".trimIndent() """.trimIndent()
val result = executeQuery<JsonObject>(query) val result = executeQuery<JsonObject>(query)
val errors = result?.get("errors") val errors = result?.get("errors")
return errors?.toString() ?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success") return errors?.toString() ?: (currContext()?.getString(ani.dantotsu.R.string.success)
?: "Success")
} }
suspend fun postMessage(userId: Int, text: String, edit: Int? = null, isPrivate: Boolean = false): String { suspend fun postMessage(
userId: Int,
text: String,
edit: Int? = null,
isPrivate: Boolean = false
): String {
val encodedText = text.replace("", "").stringSanitizer() val encodedText = text.replace("", "").stringSanitizer()
val query = """ val query = """
mutation { mutation {
@ -335,7 +346,8 @@ class AnilistMutations {
""".trimIndent() """.trimIndent()
val result = executeQuery<JsonObject>(query) val result = executeQuery<JsonObject>(query)
val errors = result?.get("errors") val errors = result?.get("errors")
return errors?.toString() ?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success") return errors?.toString() ?: (currContext()?.getString(ani.dantotsu.R.string.success)
?: "Success")
} }
suspend fun postReply(activityId: Int, text: String, edit: Int? = null): String { suspend fun postReply(activityId: Int, text: String, edit: Int? = null): String {
@ -353,7 +365,8 @@ class AnilistMutations {
""".trimIndent() """.trimIndent()
val result = executeQuery<JsonObject>(query) val result = executeQuery<JsonObject>(query)
val errors = result?.get("errors") val errors = result?.get("errors")
return errors?.toString() ?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success") return errors?.toString() ?: (currContext()?.getString(ani.dantotsu.R.string.success)
?: "Success")
} }
suspend fun postReview(summary: String, body: String, mediaId: Int, score: Int): String { suspend fun postReview(summary: String, body: String, mediaId: Int, score: Int): String {
@ -373,7 +386,8 @@ class AnilistMutations {
""".trimIndent() """.trimIndent()
val result = executeQuery<JsonObject>(query) val result = executeQuery<JsonObject>(query)
val errors = result?.get("errors") val errors = result?.get("errors")
return errors?.toString() ?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success") return errors?.toString() ?: (currContext()?.getString(ani.dantotsu.R.string.success)
?: "Success")
} }
suspend fun deleteActivityReply(activityId: Int): Boolean { suspend fun deleteActivityReply(activityId: Int): Boolean {

View file

@ -359,19 +359,24 @@ class AnilistSearch : ViewModel() {
var searched = false var searched = false
var notSet = true var notSet = true
lateinit var aniMangaSearchResults: AniMangaSearchResults lateinit var aniMangaSearchResults: AniMangaSearchResults
private val aniMangaResult: MutableLiveData<AniMangaSearchResults?> = MutableLiveData<AniMangaSearchResults?>(null) private val aniMangaResult: MutableLiveData<AniMangaSearchResults?> =
MutableLiveData<AniMangaSearchResults?>(null)
lateinit var characterSearchResults: CharacterSearchResults lateinit var characterSearchResults: CharacterSearchResults
private val characterResult: MutableLiveData<CharacterSearchResults?> = MutableLiveData<CharacterSearchResults?>(null) private val characterResult: MutableLiveData<CharacterSearchResults?> =
MutableLiveData<CharacterSearchResults?>(null)
lateinit var studioSearchResults: StudioSearchResults lateinit var studioSearchResults: StudioSearchResults
private val studioResult: MutableLiveData<StudioSearchResults?> = MutableLiveData<StudioSearchResults?>(null) private val studioResult: MutableLiveData<StudioSearchResults?> =
MutableLiveData<StudioSearchResults?>(null)
lateinit var staffSearchResults: StaffSearchResults lateinit var staffSearchResults: StaffSearchResults
private val staffResult: MutableLiveData<StaffSearchResults?> = MutableLiveData<StaffSearchResults?>(null) private val staffResult: MutableLiveData<StaffSearchResults?> =
MutableLiveData<StaffSearchResults?>(null)
lateinit var userSearchResults: UserSearchResults lateinit var userSearchResults: UserSearchResults
private val userResult: MutableLiveData<UserSearchResults?> = MutableLiveData<UserSearchResults?>(null) private val userResult: MutableLiveData<UserSearchResults?> =
MutableLiveData<UserSearchResults?>(null)
fun <T> getSearch(type: SearchType): MutableLiveData<T?> { fun <T> getSearch(type: SearchType): MutableLiveData<T?> {
return when (type) { return when (type) {
@ -517,12 +522,13 @@ class AnilistSearch : ViewModel() {
) )
) )
private suspend fun loadNextCharacterPage(r: CharacterSearchResults) = characterResult.postValue( private suspend fun loadNextCharacterPage(r: CharacterSearchResults) =
Anilist.query.searchCharacters( characterResult.postValue(
r.page + 1, Anilist.query.searchCharacters(
r.search, r.page + 1,
r.search,
)
) )
)
private suspend fun loadNextStudiosPage(r: StudioSearchResults) = studioResult.postValue( private suspend fun loadNextStudiosPage(r: StudioSearchResults) = studioResult.postValue(
Anilist.query.searchStudios( Anilist.query.searchStudios(

View file

@ -34,7 +34,8 @@ fun characterInformation(includeMediaInfo: Boolean) = """
month month
day day
} }
${if (includeMediaInfo) """ ${
if (includeMediaInfo) """
media(page: 0,sort:[POPULARITY_DESC,SCORE_DESC]) { media(page: 0,sort:[POPULARITY_DESC,SCORE_DESC]) {
$standardPageInformation $standardPageInformation
edges { edges {
@ -79,7 +80,8 @@ fun characterInformation(includeMediaInfo: Boolean) = """
} }
} }
} }
}""".prepare() else ""} }""".prepare() else ""
}
""".prepare() """.prepare()
fun studioInformation(page: Int, perPage: Int) = """ fun studioInformation(page: Int, perPage: Int) = """

View file

@ -14,6 +14,7 @@ data class FeedResponse(
val page: ActivityPage val page: ActivityPage
) : java.io.Serializable ) : java.io.Serializable
} }
@Serializable @Serializable
data class ActivityPage( data class ActivityPage(
@SerialName("activities") @SerialName("activities")

View file

@ -189,7 +189,7 @@ data class MediaTitle(
// The currently authenticated users preferred title language. Default romaji for non-authenticated // The currently authenticated users preferred title language. Default romaji for non-authenticated
@SerialName("userPreferred") var userPreferred: String, @SerialName("userPreferred") var userPreferred: String,
): java.io.Serializable ) : java.io.Serializable
@Serializable @Serializable
enum class MediaType { enum class MediaType {
@ -239,6 +239,7 @@ data class AiringSchedule(
// The associate media of the airing episode // The associate media of the airing episode
@SerialName("media") var media: Media?, @SerialName("media") var media: Media?,
) )
@Serializable @Serializable
data class MediaStreamingEpisode( data class MediaStreamingEpisode(
// The title of the episode // The title of the episode
@ -253,6 +254,7 @@ data class MediaStreamingEpisode(
// The site location of the streaming episode // The site location of the streaming episode
@SerialName("site") var site: String?, @SerialName("site") var site: String?,
) )
@Serializable @Serializable
data class MediaCoverImage( data class MediaCoverImage(
// The cover image url of the media at its largest size. If this size isn't available, large will be provided instead. // The cover image url of the media at its largest size. If this size isn't available, large will be provided instead.

View file

@ -69,7 +69,7 @@ data class User(
// The user's previously used names. // The user's previously used names.
// @SerialName("previousNames") var previousNames: List<UserPreviousName>?, // @SerialName("previousNames") var previousNames: List<UserPreviousName>?,
): java.io.Serializable ) : java.io.Serializable
@Serializable @Serializable
data class UserOptions( data class UserOptions(
@ -123,8 +123,10 @@ data class UserStatisticTypes(
enum class UserTitleLanguage { enum class UserTitleLanguage {
@SerialName("ENGLISH") @SerialName("ENGLISH")
ENGLISH, ENGLISH,
@SerialName("ROMAJI") @SerialName("ROMAJI")
ROMAJI, ROMAJI,
@SerialName("NATIVE") @SerialName("NATIVE")
NATIVE NATIVE
} }
@ -133,8 +135,10 @@ enum class UserTitleLanguage {
enum class UserStaffNameLanguage { enum class UserStaffNameLanguage {
@SerialName("ROMAJI_WESTERN") @SerialName("ROMAJI_WESTERN")
ROMAJI_WESTERN, ROMAJI_WESTERN,
@SerialName("ROMAJI") @SerialName("ROMAJI")
ROMAJI, ROMAJI,
@SerialName("NATIVE") @SerialName("NATIVE")
NATIVE NATIVE
} }
@ -143,12 +147,16 @@ enum class UserStaffNameLanguage {
enum class ScoreFormat { enum class ScoreFormat {
@SerialName("POINT_100") @SerialName("POINT_100")
POINT_100, POINT_100,
@SerialName("POINT_10_DECIMAL") @SerialName("POINT_10_DECIMAL")
POINT_10_DECIMAL, POINT_10_DECIMAL,
@SerialName("POINT_10") @SerialName("POINT_10")
POINT_10, POINT_10,
@SerialName("POINT_5") @SerialName("POINT_5")
POINT_5, POINT_5,
@SerialName("POINT_3") @SerialName("POINT_3")
POINT_3, POINT_3,
} }

View file

@ -372,6 +372,7 @@ object CommentsAPI {
} }
errorMessage("Failed to login after multiple attempts") errorMessage("Failed to login after multiple attempts")
} }
private fun errorMessage(reason: String) { private fun errorMessage(reason: String) {
if (commentsEnabled) Logger.log(reason) if (commentsEnabled) Logger.log(reason)
if (isOnline && commentsEnabled) snackString(reason) if (isOnline && commentsEnabled) snackString(reason)
@ -410,7 +411,7 @@ object CommentsAPI {
return map return map
} }
private fun requestBuilder(client: OkHttpClient = Injekt.get<NetworkHelper>().client): Requests { fun requestBuilder(client: OkHttpClient = Injekt.get<NetworkHelper>().client): Requests {
return Requests( return Requests(
client, client,
headerBuilder() headerBuilder()

View file

@ -8,8 +8,8 @@ import ani.dantotsu.settings.saving.PrefName
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import kotlin.coroutines.CoroutineContext
import java.util.concurrent.TimeUnit.SECONDS import java.util.concurrent.TimeUnit.SECONDS
import kotlin.coroutines.CoroutineContext
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
open class RPC(val token: String, val coroutineContext: CoroutineContext) { open class RPC(val token: String, val coroutineContext: CoroutineContext) {
@ -34,6 +34,7 @@ open class RPC(val token: String, val coroutineContext: CoroutineContext) {
val stopTimestamp: Long? = null, val stopTimestamp: Long? = null,
val buttons: MutableList<Link> = mutableListOf() val buttons: MutableList<Link> = mutableListOf()
) )
suspend fun createPresence(data: RPCData): String { suspend fun createPresence(data: RPCData): String {
val json = Json { val json = Json {
encodeDefaults = true encodeDefaults = true

View file

@ -30,7 +30,6 @@ import ani.dantotsu.bottomBar
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.currActivity import ani.dantotsu.currActivity
import ani.dantotsu.currContext import ani.dantotsu.currContext
import ani.dantotsu.download.DownloadCompat
import ani.dantotsu.download.DownloadCompat.Companion.loadMediaCompat import ani.dantotsu.download.DownloadCompat.Companion.loadMediaCompat
import ani.dantotsu.download.DownloadCompat.Companion.loadOfflineAnimeModelCompat import ani.dantotsu.download.DownloadCompat.Companion.loadOfflineAnimeModelCompat
import ani.dantotsu.download.DownloadedType import ani.dantotsu.download.DownloadedType
@ -209,7 +208,9 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
setMessage("Are you sure you want to delete ${item.title}?") setMessage("Are you sure you want to delete ${item.title}?")
setPosButton(R.string.yes) { setPosButton(R.string.yes) {
downloadManager.removeMedia(item.title, type) downloadManager.removeMedia(item.title, type)
val mediaIds = PrefManager.getAnimeDownloadPreferences().all?.filter { it.key.contains(item.title) }?.values ?: emptySet() val mediaIds =
PrefManager.getAnimeDownloadPreferences().all?.filter { it.key.contains(item.title) }?.values
?: emptySet()
if (mediaIds.isEmpty()) { if (mediaIds.isEmpty()) {
snackString("No media found") // if this happens, terrible things have happened snackString("No media found") // if this happens, terrible things have happened
} }
@ -287,10 +288,12 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
} }
downloadsJob = Job() downloadsJob = Job()
CoroutineScope(Dispatchers.IO + downloadsJob).launch { CoroutineScope(Dispatchers.IO + downloadsJob).launch {
val animeTitles = downloadManager.animeDownloadedTypes.map { it.titleName.findValidName() }.distinct() val animeTitles =
downloadManager.animeDownloadedTypes.map { it.titleName.findValidName() }.distinct()
val newAnimeDownloads = mutableListOf<OfflineAnimeModel>() val newAnimeDownloads = mutableListOf<OfflineAnimeModel>()
for (title in animeTitles) { for (title in animeTitles) {
val tDownloads = downloadManager.animeDownloadedTypes.filter { it.titleName.findValidName() == title } val tDownloads =
downloadManager.animeDownloadedTypes.filter { it.titleName.findValidName() == title }
val download = tDownloads.firstOrNull() ?: continue val download = tDownloads.firstOrNull() ?: continue
val offlineAnimeModel = loadOfflineAnimeModel(download) val offlineAnimeModel = loadOfflineAnimeModel(download)
if (offlineAnimeModel.title == "unknown") offlineAnimeModel.title = title if (offlineAnimeModel.title == "unknown") offlineAnimeModel.title = title

View file

@ -177,6 +177,7 @@ object Helper {
downloadManager downloadManager
} }
} }
@Deprecated("exoplayer download manager is no longer used") @Deprecated("exoplayer download manager is no longer used")
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
fun getSimpleCache(context: Context): SimpleCache { fun getSimpleCache(context: Context): SimpleCache {
@ -189,6 +190,7 @@ object Helper {
simpleCache!! simpleCache!!
} }
} }
@Synchronized @Synchronized
@Deprecated("exoplayer download manager is no longer used") @Deprecated("exoplayer download manager is no longer used")
private fun getDownloadDirectory(context: Context): File { private fun getDownloadDirectory(context: Context): File {
@ -200,12 +202,16 @@ object Helper {
} }
return downloadDirectory!! return downloadDirectory!!
} }
@Deprecated("exoplayer download manager is no longer used") @Deprecated("exoplayer download manager is no longer used")
private var download: DownloadManager? = null private var download: DownloadManager? = null
@Deprecated("exoplayer download manager is no longer used") @Deprecated("exoplayer download manager is no longer used")
private const val DOWNLOAD_CONTENT_DIRECTORY = "Anime_Downloads" private const val DOWNLOAD_CONTENT_DIRECTORY = "Anime_Downloads"
@Deprecated("exoplayer download manager is no longer used") @Deprecated("exoplayer download manager is no longer used")
private var simpleCache: SimpleCache? = null private var simpleCache: SimpleCache? = null
@Deprecated("exoplayer download manager is no longer used") @Deprecated("exoplayer download manager is no longer used")
private var downloadDirectory: File? = null private var downloadDirectory: File? = null
} }

View file

@ -22,9 +22,9 @@ import androidx.recyclerview.widget.RecyclerView
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.Refresh import ani.dantotsu.Refresh
import ani.dantotsu.bottomBar import ani.dantotsu.bottomBar
import ani.dantotsu.connections.anilist.AniMangaSearchResults
import ani.dantotsu.connections.anilist.Anilist import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.AnilistAnimeViewModel import ani.dantotsu.connections.anilist.AnilistAnimeViewModel
import ani.dantotsu.connections.anilist.AniMangaSearchResults
import ani.dantotsu.connections.anilist.getUserId import ani.dantotsu.connections.anilist.getUserId
import ani.dantotsu.databinding.FragmentAnimeBinding import ani.dantotsu.databinding.FragmentAnimeBinding
import ani.dantotsu.media.MediaAdaptor import ani.dantotsu.media.MediaAdaptor
@ -277,8 +277,9 @@ class AnimeFragment : Fragment() {
running = true running = true
scope.launch { scope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
Anilist.userid = PrefManager.getNullableVal<String>(PrefName.AnilistUserId, null) Anilist.userid =
?.toIntOrNull() PrefManager.getNullableVal<String>(PrefName.AnilistUserId, null)
?.toIntOrNull()
if (Anilist.userid == null) { if (Anilist.userid == null) {
getUserId(requireContext()) { getUserId(requireContext()) {
load() load()

View file

@ -20,7 +20,6 @@ import androidx.viewpager2.widget.ViewPager2
import ani.dantotsu.MediaPageTransformer import ani.dantotsu.MediaPageTransformer
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.AnilistSearch.SearchType.Companion.toAnilistString
import ani.dantotsu.databinding.ItemAnimePageBinding import ani.dantotsu.databinding.ItemAnimePageBinding
import ani.dantotsu.databinding.LayoutTrendingBinding import ani.dantotsu.databinding.LayoutTrendingBinding
import ani.dantotsu.getAppString import ani.dantotsu.getAppString
@ -266,7 +265,15 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
} }
} }
fun init(adaptor: MediaAdaptor, recyclerView: RecyclerView, progress: View, title: View , more: View , string: String, media : MutableList<Media>) { fun init(
adaptor: MediaAdaptor,
recyclerView: RecyclerView,
progress: View,
title: View,
more: View,
string: String,
media: MutableList<Media>
) {
progress.visibility = View.GONE progress.visibility = View.GONE
recyclerView.adapter = adaptor recyclerView.adapter = adaptor
recyclerView.layoutManager = recyclerView.layoutManager =

View file

@ -469,7 +469,9 @@ class HomeFragment : Fragment() {
scope.launch { scope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
// Get user data first // Get user data first
Anilist.userid = PrefManager.getNullableVal<String>(PrefName.AnilistUserId, null)?.toIntOrNull() Anilist.userid =
PrefManager.getNullableVal<String>(PrefName.AnilistUserId, null)
?.toIntOrNull()
if (Anilist.userid == null) { if (Anilist.userid == null) {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
getUserId(requireContext()) { getUserId(requireContext()) {

View file

@ -102,7 +102,7 @@ class LoginFragment : Fragment() {
requireActivity().customAlertDialog().apply { requireActivity().customAlertDialog().apply {
setTitle("Enter Password") setTitle("Enter Password")
setCustomView(dialogView.root) setCustomView(dialogView.root)
setPosButton(R.string.ok){ setPosButton(R.string.ok) {
val editText = dialogView.userAgentTextBox val editText = dialogView.userAgentTextBox
if (editText.text?.isNotBlank() == true) { if (editText.text?.isNotBlank() == true) {
editText.text?.toString()?.trim()?.toCharArray(password) editText.text?.toString()?.trim()?.toCharArray(password)

View file

@ -20,9 +20,9 @@ import androidx.recyclerview.widget.RecyclerView
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.Refresh import ani.dantotsu.Refresh
import ani.dantotsu.bottomBar import ani.dantotsu.bottomBar
import ani.dantotsu.connections.anilist.AniMangaSearchResults
import ani.dantotsu.connections.anilist.Anilist import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.AnilistMangaViewModel import ani.dantotsu.connections.anilist.AnilistMangaViewModel
import ani.dantotsu.connections.anilist.AniMangaSearchResults
import ani.dantotsu.connections.anilist.getUserId import ani.dantotsu.connections.anilist.getUserId
import ani.dantotsu.databinding.FragmentMangaBinding import ani.dantotsu.databinding.FragmentMangaBinding
import ani.dantotsu.media.MediaAdaptor import ani.dantotsu.media.MediaAdaptor
@ -169,7 +169,10 @@ class MangaFragment : Fragment() {
} }
model.getPopularManga().observe(viewLifecycleOwner) { model.getPopularManga().observe(viewLifecycleOwner) {
if (it != null) { if (it != null) {
mangaPageAdapter.updateTrendingManga(MediaAdaptor(0, it, requireActivity()), it) mangaPageAdapter.updateTrendingManga(
MediaAdaptor(0, it, requireActivity()),
it
)
} }
} }
model.getPopularManhwa().observe(viewLifecycleOwner) { model.getPopularManhwa().observe(viewLifecycleOwner) {
@ -262,8 +265,9 @@ class MangaFragment : Fragment() {
running = true running = true
scope.launch { scope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
Anilist.userid = PrefManager.getNullableVal<String>(PrefName.AnilistUserId, null) Anilist.userid =
?.toIntOrNull() PrefManager.getNullableVal<String>(PrefName.AnilistUserId, null)
?.toIntOrNull()
if (Anilist.userid == null) { if (Anilist.userid == null) {
getUserId(requireContext()) { getUserId(requireContext()) {
load() load()

View file

@ -266,10 +266,10 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
adaptor: MediaAdaptor, adaptor: MediaAdaptor,
recyclerView: RecyclerView, recyclerView: RecyclerView,
progress: View, progress: View,
title: View , title: View,
more: View , more: View,
string: String, string: String,
media : MutableList<Media> media: MutableList<Media>
) { ) {
progress.visibility = View.GONE progress.visibility = View.GONE
recyclerView.adapter = adaptor recyclerView.adapter = adaptor

View file

@ -38,7 +38,7 @@ class CircleView(context: Context, attrs: AttributeSet?) : View(context, attrs)
fun setColor(int: Int) { fun setColor(int: Int) {
paint.color = if (int < booleanList.size && booleanList[int]) { paint.color = if (int < booleanList.size && booleanList[int]) {
Color.GRAY Color.GRAY
} else { } else {
if (isUser) secondColor else primaryColor if (isUser) secondColor else primaryColor
} }
@ -58,7 +58,7 @@ class CircleView(context: Context, attrs: AttributeSet?) : View(context, attrs)
} else { } else {
val effectiveAngle = totalAngle / parts val effectiveAngle = totalAngle / parts
for (i in 0 until parts) { for (i in 0 until parts) {
val startAngle = i * (effectiveAngle + gapAngle) -90f val startAngle = i * (effectiveAngle + gapAngle) - 90f
path.reset() path.reset()
path.addArc( path.addArc(
centerX - radius, centerX - radius,
@ -74,7 +74,7 @@ class CircleView(context: Context, attrs: AttributeSet?) : View(context, attrs)
} }
fun setParts(parts: Int, list : List<Boolean> = mutableListOf(), isUser: Boolean) { fun setParts(parts: Int, list: List<Boolean> = mutableListOf(), isUser: Boolean) {
this.parts = parts this.parts = parts
this.booleanList = list this.booleanList = list
this.isUser = isUser this.isUser = isUser

View file

@ -46,8 +46,8 @@ class StatusActivity : AppCompatActivity(), StoriesCallback {
val key = "activities" val key = "activities"
val watchedActivity = PrefManager.getCustomVal<Set<Int>>(key, setOf()) val watchedActivity = PrefManager.getCustomVal<Set<Int>>(key, setOf())
if (activity.getOrNull(position) != null) { if (activity.getOrNull(position) != null) {
val startFrom = findFirstNonMatch(watchedActivity, activity[position].activity ) val startFrom = findFirstNonMatch(watchedActivity, activity[position].activity)
val startIndex = if ( startFrom > 0) startFrom else 0 val startIndex = if (startFrom > 0) startFrom else 0
binding.stories.setStoriesList( binding.stories.setStoriesList(
activityList = activity[position].activity, activityList = activity[position].activity,
startIndex = startIndex + 1 startIndex = startIndex + 1
@ -58,6 +58,7 @@ class StatusActivity : AppCompatActivity(), StoriesCallback {
} }
} }
private fun findFirstNonMatch(watchedActivity: Set<Int>, activity: List<Activity>): Int { private fun findFirstNonMatch(watchedActivity: Set<Int>, activity: List<Activity>): Int {
for (activityItem in activity) { for (activityItem in activity) {
if (activityItem.id !in watchedActivity) { if (activityItem.id !in watchedActivity) {
@ -86,13 +87,14 @@ class StatusActivity : AppCompatActivity(), StoriesCallback {
binding.stories.pause() binding.stories.pause()
} }
} }
override fun onStoriesEnd() { override fun onStoriesEnd() {
position += 1 position += 1
if (position < activity.size) { if (position < activity.size) {
val key = "activities" val key = "activities"
val watchedActivity = PrefManager.getCustomVal<Set<Int>>(key, setOf()) val watchedActivity = PrefManager.getCustomVal<Set<Int>>(key, setOf())
val startFrom = findFirstNonMatch(watchedActivity, activity[position].activity ) val startFrom = findFirstNonMatch(watchedActivity, activity[position].activity)
val startIndex= if ( startFrom > 0) startFrom else 0 val startIndex = if (startFrom > 0) startFrom else 0
binding.stories.startAnimation(slideOutLeft) binding.stories.startAnimation(slideOutLeft)
binding.stories.setStoriesList(activity[position].activity, startIndex + 1) binding.stories.setStoriesList(activity[position].activity, startIndex + 1)
binding.stories.startAnimation(slideInRight) binding.stories.startAnimation(slideInRight)
@ -106,15 +108,16 @@ class StatusActivity : AppCompatActivity(), StoriesCallback {
if (position >= 0 && activity[position].activity.isNotEmpty()) { if (position >= 0 && activity[position].activity.isNotEmpty()) {
val key = "activities" val key = "activities"
val watchedActivity = PrefManager.getCustomVal<Set<Int>>(key, setOf()) val watchedActivity = PrefManager.getCustomVal<Set<Int>>(key, setOf())
val startFrom = findFirstNonMatch(watchedActivity, activity[position].activity ) val startFrom = findFirstNonMatch(watchedActivity, activity[position].activity)
val startIndex = if ( startFrom > 0) startFrom else 0 val startIndex = if (startFrom > 0) startFrom else 0
binding.stories.startAnimation(slideOutRight) binding.stories.startAnimation(slideOutRight)
binding.stories.setStoriesList(activity[position].activity,startIndex + 1) binding.stories.setStoriesList(activity[position].activity, startIndex + 1)
binding.stories.startAnimation(slideInLeft) binding.stories.startAnimation(slideInLeft)
} else { } else {
finish() finish()
} }
} }
companion object { companion object {
var user: ArrayList<User> = arrayListOf() var user: ArrayList<User> = arrayListOf()
} }

View file

@ -262,8 +262,6 @@ class Stories @JvmOverloads constructor(
} }
private fun rightPanelTouch() { private fun rightPanelTouch() {
Logger.log("rightPanelTouch: $storyIndex") Logger.log("rightPanelTouch: $storyIndex")
if (storyIndex == activityList.size) { if (storyIndex == activityList.size) {
@ -366,8 +364,8 @@ class Stories @JvmOverloads constructor(
if ( if (
story.status?.contains("completed") == false && story.status?.contains("completed") == false &&
!story.status.contains("plans") && !story.status.contains("plans") &&
!story.status.contains("repeating")&& !story.status.contains("repeating") &&
!story.status.contains("paused")&& !story.status.contains("paused") &&
!story.status.contains("dropped") !story.status.contains("dropped")
) { ) {
"of ${story.media?.title?.userPreferred}" "of ${story.media?.title?.userPreferred}"
@ -469,6 +467,7 @@ class Stories @JvmOverloads constructor(
} }
} }
} }
private var startClickTime = 0L private var startClickTime = 0L
private var startX = 0f private var startX = 0f
private var startY = 0f private var startY = 0f
@ -478,7 +477,8 @@ class Stories @JvmOverloads constructor(
onTouchView(view, event) onTouchView(view, event)
return true return true
} }
private fun onTouchView(view: View, event: MotionEvent, isText: Boolean = false){
private fun onTouchView(view: View, event: MotionEvent, isText: Boolean = false) {
val maxClickDuration = 200 val maxClickDuration = 200
val screenWidth = view.width val screenWidth = view.width
val leftHalf = screenWidth / 2 val leftHalf = screenWidth / 2
@ -492,6 +492,7 @@ class Stories @JvmOverloads constructor(
pause() pause()
isLongPress = false isLongPress = false
} }
MotionEvent.ACTION_MOVE -> { MotionEvent.ACTION_MOVE -> {
val deltaX = event.x - startX val deltaX = event.x - startX
val deltaY = event.y - startY val deltaY = event.y - startY
@ -499,6 +500,7 @@ class Stories @JvmOverloads constructor(
isLongPress = true isLongPress = true
} }
} }
MotionEvent.ACTION_UP -> { MotionEvent.ACTION_UP -> {
val clickDuration = Calendar.getInstance().timeInMillis - startClickTime val clickDuration = Calendar.getInstance().timeInMillis - startClickTime
if (isText) { if (isText) {

View file

@ -46,7 +46,7 @@ class UserStatusAdapter(private val user: ArrayList<User>) :
.putExtra("type", "activity"), .putExtra("type", "activity"),
null null
) )
}else{ } else {
ContextCompat.startActivity( ContextCompat.startActivity(
itemView.context, itemView.context,
Intent( Intent(
@ -76,10 +76,15 @@ class UserStatusAdapter(private val user: ArrayList<User>) :
setAnimation(b.root.context, b.root) setAnimation(b.root.context, b.root)
val user = user[position] val user = user[position]
b.profileUserAvatar.loadImage(user.pfp) b.profileUserAvatar.loadImage(user.pfp)
b.profileUserName.text = if (Anilist.userid == user.id) getAppString(R.string.your_story) else user.name b.profileUserName.text =
if (Anilist.userid == user.id) getAppString(R.string.your_story) else user.name
val watchedActivity = PrefManager.getCustomVal<Set<Int>>("activities", setOf()) val watchedActivity = PrefManager.getCustomVal<Set<Int>>("activities", setOf())
val booleanList = user.activity.map { watchedActivity.contains(it.id) } val booleanList = user.activity.map { watchedActivity.contains(it.id) }
b.profileUserStatusIndicator.setParts(user.activity.size, booleanList, user.id == Anilist.userid) b.profileUserStatusIndicator.setParts(
user.activity.size,
booleanList,
user.id == Anilist.userid
)
} }

View file

@ -55,7 +55,11 @@ class CharacterAdapter(
).toBundle() ).toBundle()
) )
} }
itemView.setOnLongClickListener { copyToClipboard(characterList[bindingAdapterPosition].name ?: ""); true } itemView.setOnLongClickListener {
copyToClipboard(
characterList[bindingAdapterPosition].name ?: ""
); true
}
} }
} }
} }

View file

@ -7,11 +7,9 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.buildMarkwon
import ani.dantotsu.currActivity import ani.dantotsu.currActivity
import ani.dantotsu.databinding.ItemCharacterDetailsBinding import ani.dantotsu.databinding.ItemCharacterDetailsBinding
import ani.dantotsu.others.SpoilerPlugin
import io.noties.markwon.Markwon
import io.noties.markwon.SoftBreakAddsNewLinePlugin
class CharacterDetailsAdapter(private val character: Character, private val activity: Activity) : class CharacterDetailsAdapter(private val character: Character, private val activity: Activity) :
RecyclerView.Adapter<CharacterDetailsAdapter.GenreViewHolder>() { RecyclerView.Adapter<CharacterDetailsAdapter.GenreViewHolder>() {
@ -24,7 +22,9 @@ class CharacterDetailsAdapter(private val character: Character, private val acti
override fun onBindViewHolder(holder: GenreViewHolder, position: Int) { override fun onBindViewHolder(holder: GenreViewHolder, position: Int) {
val binding = holder.binding val binding = holder.binding
val desc = val desc =
(if (character.age != "null") "${currActivity()!!.getString(R.string.age)} ${character.age}" else "") + (if (character.id == 4004)
"![za wardo](https://media1.tenor.com/m/_z1tmCJnL2wAAAAd/za-warudo.gif) \n" else "") +
(if (character.age != "null") "${currActivity()!!.getString(R.string.age)} ${character.age}" else "") +
(if (character.dateOfBirth.toString() != "") (if (character.dateOfBirth.toString() != "")
"${currActivity()!!.getString(R.string.birthday)} ${character.dateOfBirth.toString()}" else "") + "${currActivity()!!.getString(R.string.birthday)} ${character.dateOfBirth.toString()}" else "") +
(if (character.gender != "null") (if (character.gender != "null")
@ -41,8 +41,7 @@ class CharacterDetailsAdapter(private val character: Character, private val acti
} else "") + "\n" + character.description } else "") + "\n" + character.description
binding.characterDesc.isTextSelectable binding.characterDesc.isTextSelectable
val markWon = Markwon.builder(activity).usePlugin(SoftBreakAddsNewLinePlugin.create()) val markWon = buildMarkwon(activity)
.usePlugin(SpoilerPlugin()).build()
markWon.setMarkdown(binding.characterDesc, desc.replace("~!", "||").replace("!~", "||")) markWon.setMarkdown(binding.characterDesc, desc.replace("~!", "||").replace("!~", "||"))
binding.voiceActorRecycler.adapter = AuthorAdapter(character.voiceActor ?: arrayListOf()) binding.voiceActorRecycler.adapter = AuthorAdapter(character.voiceActor ?: arrayListOf())
binding.voiceActorRecycler.layoutManager = LinearLayoutManager( binding.voiceActorRecycler.layoutManager = LinearLayoutManager(

View file

@ -9,7 +9,7 @@ import android.view.animation.Animation
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import ani.dantotsu.databinding.ItemSearchHeaderBinding import ani.dantotsu.databinding.ItemSearchHeaderBinding
abstract class HeaderInterface: RecyclerView.Adapter<HeaderInterface.SearchHeaderViewHolder>() { abstract class HeaderInterface : RecyclerView.Adapter<HeaderInterface.SearchHeaderViewHolder>() {
private val itemViewType = 6969 private val itemViewType = 6969
var search: Runnable? = null var search: Runnable? = null
var requestFocus: Runnable? = null var requestFocus: Runnable? = null

View file

@ -147,7 +147,7 @@ fun Media?.deleteFromList(
scope.launch { scope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
this@deleteFromList?.let { media -> this@deleteFromList?.let { media ->
val _id = id ?: Anilist.query.userMediaDetails(media).userListId; val _id = id ?: Anilist.query.userMediaDetails(media).userListId
_id?.let { listId -> _id?.let { listId ->
try { try {
Anilist.mutation.deleteList(listId) Anilist.mutation.deleteList(listId)

View file

@ -251,10 +251,12 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
fun total() { fun total() {
val text = SpannableStringBuilder().apply { val text = SpannableStringBuilder().apply {
val white = this@MediaDetailsActivity.getThemeColor(com.google.android.material.R.attr.colorOnBackground) val white =
this@MediaDetailsActivity.getThemeColor(com.google.android.material.R.attr.colorOnBackground)
if (media.userStatus != null) { if (media.userStatus != null) {
append(if (media.anime != null) getString(R.string.watched_num) else getString(R.string.read_num)) append(if (media.anime != null) getString(R.string.watched_num) else getString(R.string.read_num))
val colorSecondary = getThemeColor(com.google.android.material.R.attr.colorSecondary) val colorSecondary =
getThemeColor(com.google.android.material.R.attr.colorSecondary)
bold { color(colorSecondary) { append("${media.userProgress}") } } bold { color(colorSecondary) { append("${media.userProgress}") } }
append( append(
if (media.anime != null) getString(R.string.episodes_out_of) else getString( if (media.anime != null) getString(R.string.episodes_out_of) else getString(

View file

@ -100,6 +100,7 @@ class MediaDetailsViewModel : ViewModel() {
if (kitsuEpisodes.value == null) kitsuEpisodes.postValue(Kitsu.getKitsuEpisodesDetails(s)) if (kitsuEpisodes.value == null) kitsuEpisodes.postValue(Kitsu.getKitsuEpisodesDetails(s))
} }
} }
private val anifyEpisodes: MutableLiveData<Map<String, Episode>> = private val anifyEpisodes: MutableLiveData<Map<String, Episode>> =
MutableLiveData<Map<String, Episode>>(null) MutableLiveData<Map<String, Episode>>(null)

View file

@ -18,9 +18,8 @@ import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.statusBarHeight import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager import ani.dantotsu.themes.ThemeManager
import java.util.ArrayList
class MediaListViewActivity: AppCompatActivity() { class MediaListViewActivity : AppCompatActivity() {
private lateinit var binding: ActivityMediaListViewBinding private lateinit var binding: ActivityMediaListViewBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -52,7 +51,8 @@ class MediaListViewActivity: AppCompatActivity() {
binding.listAppBar.setBackgroundColor(primaryColor) binding.listAppBar.setBackgroundColor(primaryColor)
binding.listTitle.setTextColor(primaryTextColor) binding.listTitle.setTextColor(primaryTextColor)
val screenWidth = resources.displayMetrics.run { widthPixels / density } val screenWidth = resources.displayMetrics.run { widthPixels / density }
val mediaList = passedMedia ?: intent.getSerialized("media") as? ArrayList<Media> ?: ArrayList() val mediaList =
passedMedia ?: intent.getSerialized("media") as? ArrayList<Media> ?: ArrayList()
if (passedMedia != null) passedMedia = null if (passedMedia != null) passedMedia = null
val view = PrefManager.getCustomVal("mediaView", 0) val view = PrefManager.getCustomVal("mediaView", 0)
var mediaView: View = when (view) { var mediaView: View = when (view) {

View file

@ -44,7 +44,10 @@ class MediaSocialAdapter(
profileUserName.text = user.name profileUserName.text = user.name
profileInfo.apply { profileInfo.apply {
text = when (user.status) { text = when (user.status) {
"CURRENT" -> if (type == "ANIME") getAppString(R.string.watching) else getAppString(R.string.reading) "CURRENT" -> if (type == "ANIME") getAppString(R.string.watching) else getAppString(
R.string.reading
)
else -> user.status ?: "" else -> user.status ?: ""
} }
visibility = View.VISIBLE visibility = View.VISIBLE
@ -63,10 +66,12 @@ class MediaSocialAdapter(
profileCompactProgressContainer.visibility = View.VISIBLE profileCompactProgressContainer.visibility = View.VISIBLE
profileUserAvatar.setOnClickListener { profileUserAvatar.setOnClickListener {
ContextCompat.startActivity(root.context, ContextCompat.startActivity(
root.context,
Intent(root.context, ProfileActivity::class.java) Intent(root.context, ProfileActivity::class.java)
.putExtra("userId", user.id), .putExtra("userId", user.id),
null) null
)
} }
profileUserAvatarContainer.setOnLongClickListener { profileUserAvatarContainer.setOnLongClickListener {
ImageViewDialog.newInstance( ImageViewDialog.newInstance(

View file

@ -1,23 +1,15 @@
package ani.dantotsu.media package ani.dantotsu.media
import android.app.Activity
import android.content.Intent import android.content.Intent
import android.view.View import android.view.View
import androidx.activity.ComponentActivity
import androidx.core.app.ActivityOptionsCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.util.Pair
import androidx.core.view.ViewCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.api.Query import ani.dantotsu.connections.anilist.api.Query
import ani.dantotsu.databinding.ItemReviewsBinding import ani.dantotsu.databinding.ItemReviewsBinding
import ani.dantotsu.loadImage import ani.dantotsu.loadImage
import ani.dantotsu.openImage import ani.dantotsu.openImage
import ani.dantotsu.others.ImageViewDialog
import ani.dantotsu.profile.ProfileActivity import ani.dantotsu.profile.ProfileActivity
import ani.dantotsu.profile.activity.ActivityItemBuilder import ani.dantotsu.profile.activity.ActivityItemBuilder
import ani.dantotsu.toast import ani.dantotsu.toast
@ -40,7 +32,7 @@ class ReviewAdapter(
binding.reviewUserAvatar.loadImage(review.user?.avatar?.medium) binding.reviewUserAvatar.loadImage(review.user?.avatar?.medium)
binding.reviewText.text = review.summary binding.reviewText.text = review.summary
binding.reviewPostTime.text = ActivityItemBuilder.getDateTime(review.createdAt) binding.reviewPostTime.text = ActivityItemBuilder.getDateTime(review.createdAt)
val text = "[${review.score/ 10.0f}]" val text = "[${review.score / 10.0f}]"
binding.reviewTag.text = text binding.reviewTag.text = text
binding.root.setOnClickListener { binding.root.setOnClickListener {
ContextCompat.startActivity( ContextCompat.startActivity(
@ -85,6 +77,7 @@ class ReviewAdapter(
override fun initializeViewBinding(view: View): ItemReviewsBinding { override fun initializeViewBinding(view: View): ItemReviewsBinding {
return ItemReviewsBinding.bind(view) return ItemReviewsBinding.bind(view)
} }
private fun userVote(type: String) { private fun userVote(type: String) {
when (type) { when (type) {
"NO_VOTE" -> { "NO_VOTE" -> {

View file

@ -20,7 +20,6 @@ import ani.dantotsu.initActivity
import ani.dantotsu.loadImage import ani.dantotsu.loadImage
import ani.dantotsu.navBarHeight import ani.dantotsu.navBarHeight
import ani.dantotsu.openImage import ani.dantotsu.openImage
import ani.dantotsu.others.ImageViewDialog
import ani.dantotsu.profile.ProfileActivity import ani.dantotsu.profile.ProfileActivity
import ani.dantotsu.profile.activity.ActivityItemBuilder import ani.dantotsu.profile.activity.ActivityItemBuilder
import ani.dantotsu.statusBarHeight import ani.dantotsu.statusBarHeight
@ -52,8 +51,9 @@ class ReviewViewActivity : AppCompatActivity() {
binding.userAvatar.loadImage(review.user?.avatar?.medium) binding.userAvatar.loadImage(review.user?.avatar?.medium)
binding.userTime.text = ActivityItemBuilder.getDateTime(review.createdAt) binding.userTime.text = ActivityItemBuilder.getDateTime(review.createdAt)
binding.userContainer.setOnClickListener { binding.userContainer.setOnClickListener {
startActivity(Intent(this, ProfileActivity::class.java) startActivity(
.putExtra("userId", review.user?.id) Intent(this, ProfileActivity::class.java)
.putExtra("userId", review.user?.id)
) )
} }
binding.userAvatar.openImage( binding.userAvatar.openImage(
@ -61,8 +61,9 @@ class ReviewViewActivity : AppCompatActivity() {
review.user?.avatar?.medium ?: "" review.user?.avatar?.medium ?: ""
) )
binding.userAvatar.setOnClickListener { binding.userAvatar.setOnClickListener {
startActivity(Intent(this, ProfileActivity::class.java) startActivity(
.putExtra("userId", review.user?.id) Intent(this, ProfileActivity::class.java)
.putExtra("userId", review.user?.id)
) )
} }
binding.profileUserBio.settings.loadWithOverviewMode = true binding.profileUserBio.settings.loadWithOverviewMode = true

View file

@ -13,10 +13,10 @@ import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import ani.dantotsu.connections.anilist.AniMangaSearchResults
import ani.dantotsu.connections.anilist.Anilist import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.AnilistSearch import ani.dantotsu.connections.anilist.AnilistSearch
import ani.dantotsu.connections.anilist.AnilistSearch.SearchType import ani.dantotsu.connections.anilist.AnilistSearch.SearchType
import ani.dantotsu.connections.anilist.AniMangaSearchResults
import ani.dantotsu.connections.anilist.CharacterSearchResults import ani.dantotsu.connections.anilist.CharacterSearchResults
import ani.dantotsu.connections.anilist.StaffSearchResults import ani.dantotsu.connections.anilist.StaffSearchResults
import ani.dantotsu.connections.anilist.StudioSearchResults import ani.dantotsu.connections.anilist.StudioSearchResults
@ -377,7 +377,10 @@ class SearchActivity : AppCompatActivity() {
} }
SearchType.CHARACTER -> { SearchType.CHARACTER -> {
characterAdaptor.notifyItemRangeRemoved(0, model.characterSearchResults.results.size) characterAdaptor.notifyItemRangeRemoved(
0,
model.characterSearchResults.results.size
)
model.characterSearchResults.results.clear() model.characterSearchResults.results.clear()
} }

View file

@ -57,6 +57,7 @@ class SearchAdapter(private val activity: SearchActivity, private val type: Sear
searchHistoryAdapter = SearchHistoryAdapter(type) { searchHistoryAdapter = SearchHistoryAdapter(type) {
binding.searchBarText.setText(it) binding.searchBarText.setText(it)
binding.searchBarText.setSelection(it.length)
} }
binding.searchHistoryList.layoutManager = LinearLayoutManager(binding.root.context) binding.searchHistoryList.layoutManager = LinearLayoutManager(binding.root.context)
binding.searchHistoryList.adapter = searchHistoryAdapter binding.searchHistoryList.adapter = searchHistoryAdapter

View file

@ -346,7 +346,9 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
binding.searchGenresGrid.isChecked = false binding.searchGenresGrid.isChecked = false
binding.searchFilterTags.adapter = binding.searchFilterTags.adapter =
FilterChipAdapter(Anilist.tags?.get(activity.aniMangaResult.isAdult) ?: listOf()) { chip -> FilterChipAdapter(
Anilist.tags?.get(activity.aniMangaResult.isAdult) ?: listOf()
) { chip ->
val tag = chip.text.toString() val tag = chip.text.toString()
chip.isChecked = selectedTags.contains(tag) chip.isChecked = selectedTags.contains(tag)
chip.isCloseIconVisible = exTags.contains(tag) chip.isCloseIconVisible = exTags.contains(tag)

View file

@ -55,7 +55,11 @@ class StudioAdapter(
).toBundle() ).toBundle()
) )
} }
itemView.setOnLongClickListener { copyToClipboard(studioList[bindingAdapterPosition].name ?: ""); true } itemView.setOnLongClickListener {
copyToClipboard(
studioList[bindingAdapterPosition].name
); true
}
} }
} }
} }

View file

@ -31,6 +31,7 @@ class SupportingSearchAdapter(private val activity: SearchActivity, private val
searchHistoryAdapter = SearchHistoryAdapter(type) { searchHistoryAdapter = SearchHistoryAdapter(type) {
binding.searchBarText.setText(it) binding.searchBarText.setText(it)
binding.searchBarText.setSelection(it.length)
} }
binding.searchHistoryList.layoutManager = LinearLayoutManager(binding.root.context) binding.searchHistoryList.layoutManager = LinearLayoutManager(binding.root.context)
binding.searchHistoryList.adapter = searchHistoryAdapter binding.searchHistoryList.adapter = searchHistoryAdapter

View file

@ -20,8 +20,8 @@ import ani.dantotsu.R
import ani.dantotsu.currActivity import ani.dantotsu.currActivity
import ani.dantotsu.currContext import ani.dantotsu.currContext
import ani.dantotsu.databinding.DialogLayoutBinding import ani.dantotsu.databinding.DialogLayoutBinding
import ani.dantotsu.databinding.ItemMediaSourceBinding
import ani.dantotsu.databinding.ItemChipBinding import ani.dantotsu.databinding.ItemChipBinding
import ani.dantotsu.databinding.ItemMediaSourceBinding
import ani.dantotsu.displayTimer import ani.dantotsu.displayTimer
import ani.dantotsu.isOnline import ani.dantotsu.isOnline
import ani.dantotsu.loadImage import ani.dantotsu.loadImage
@ -61,7 +61,8 @@ class AnimeWatchAdapter(
private var _binding: ItemMediaSourceBinding? = null private var _binding: ItemMediaSourceBinding? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val bind = ItemMediaSourceBinding.inflate(LayoutInflater.from(parent.context), parent, false) val bind =
ItemMediaSourceBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(bind) return ViewHolder(bind)
} }
@ -285,7 +286,7 @@ class AnimeWatchAdapter(
fragment.requireContext().customAlertDialog().apply { fragment.requireContext().customAlertDialog().apply {
setTitle(" Delete Progress for all episodes of ${media.nameRomaji}") setTitle(" Delete Progress for all episodes of ${media.nameRomaji}")
setMessage("This will delete all the locally stored progress for all episodes") setMessage("This will delete all the locally stored progress for all episodes")
setPosButton(R.string.ok){ setPosButton(R.string.ok) {
val prefix = "${media.id}_" val prefix = "${media.id}_"
val regex = Regex("^${prefix}\\d+$") val regex = Regex("^${prefix}\\d+$")
@ -300,7 +301,7 @@ class AnimeWatchAdapter(
} }
} }
resetProgressDef.text = getString(currContext()!!,R.string.clear_stored_episode) resetProgressDef.text = getString(currContext()!!, R.string.clear_stored_episode)
// Hidden // Hidden
mangaScanlatorContainer.visibility = View.GONE mangaScanlatorContainer.visibility = View.GONE
@ -327,7 +328,7 @@ class AnimeWatchAdapter(
fragment.requireContext().customAlertDialog().apply { fragment.requireContext().customAlertDialog().apply {
setTitle(" Delete Progress for all episodes of ${media.nameRomaji}") setTitle(" Delete Progress for all episodes of ${media.nameRomaji}")
setMessage("This will delete all the locally stored progress for all episodes") setMessage("This will delete all the locally stored progress for all episodes")
setPosButton(R.string.ok){ setPosButton(R.string.ok) {
val prefix = "${media.id}_" val prefix = "${media.id}_"
val regex = Regex("^${prefix}\\d+$") val regex = Regex("^${prefix}\\d+$")
@ -478,7 +479,8 @@ class AnimeWatchAdapter(
binding.sourceProgressBar.visibility = View.GONE binding.sourceProgressBar.visibility = View.GONE
val sourceFound = media.anime.episodes!!.isNotEmpty() val sourceFound = media.anime.episodes!!.isNotEmpty()
val isDownloadedSource = watchSources[media.selected!!.sourceIndex] is OfflineAnimeParser val isDownloadedSource =
watchSources[media.selected!!.sourceIndex] is OfflineAnimeParser
if (isDownloadedSource) { if (isDownloadedSource) {
binding.sourceNotFound.text = if (sourceFound) { binding.sourceNotFound.text = if (sourceFound) {
@ -487,7 +489,8 @@ class AnimeWatchAdapter(
currActivity()!!.getString(R.string.download_not_found) currActivity()!!.getString(R.string.download_not_found)
} }
} else { } else {
binding.sourceNotFound.text = currActivity()!!.getString(R.string.source_not_found) binding.sourceNotFound.text =
currActivity()!!.getString(R.string.source_not_found)
} }
binding.sourceNotFound.isGone = sourceFound binding.sourceNotFound.isGone = sourceFound

View file

@ -1,7 +1,6 @@
package ani.dantotsu.media.anime package ani.dantotsu.media.anime
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@ -28,10 +27,8 @@ import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import ani.dantotsu.FileUrl
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.addons.download.DownloadAddonManager import ani.dantotsu.addons.download.DownloadAddonManager
import ani.dantotsu.connections.anilist.api.MediaStreamingEpisode
import ani.dantotsu.databinding.FragmentMediaSourceBinding import ani.dantotsu.databinding.FragmentMediaSourceBinding
import ani.dantotsu.download.DownloadedType import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager import ani.dantotsu.download.DownloadsManager
@ -49,7 +46,6 @@ import ani.dantotsu.media.MediaType
import ani.dantotsu.navBarHeight import ani.dantotsu.navBarHeight
import ani.dantotsu.notifications.subscription.SubscriptionHelper import ani.dantotsu.notifications.subscription.SubscriptionHelper
import ani.dantotsu.notifications.subscription.SubscriptionHelper.Companion.saveSubscription import ani.dantotsu.notifications.subscription.SubscriptionHelper.Companion.saveSubscription
import ani.dantotsu.others.Anify
import ani.dantotsu.others.LanguageMapper import ani.dantotsu.others.LanguageMapper
import ani.dantotsu.parsers.AnimeParser import ani.dantotsu.parsers.AnimeParser
import ani.dantotsu.parsers.AnimeSources import ani.dantotsu.parsers.AnimeSources
@ -236,13 +232,16 @@ class AnimeWatchFragment : Fragment() {
episodes.forEach { (i, episode) -> episodes.forEach { (i, episode) ->
if (media.anime?.anifyEpisodes != null) { if (media.anime?.anifyEpisodes != null) {
if (media.anime!!.anifyEpisodes!!.containsKey(i)) { if (media.anime!!.anifyEpisodes!!.containsKey(i)) {
episode.desc = media.anime!!.anifyEpisodes!![i]?.desc ?: episode.desc episode.desc =
media.anime!!.anifyEpisodes!![i]?.desc ?: episode.desc
episode.title = if (MediaNameAdapter.removeEpisodeNumberCompletely( episode.title = if (MediaNameAdapter.removeEpisodeNumberCompletely(
episode.title ?: "" episode.title ?: ""
).isBlank() ).isBlank()
) media.anime!!.anifyEpisodes!![i]?.title ?: episode.title else episode.title ) media.anime!!.anifyEpisodes!![i]?.title
?: episode.title else episode.title
?: media.anime!!.anifyEpisodes!![i]?.title ?: episode.title ?: media.anime!!.anifyEpisodes!![i]?.title ?: episode.title
episode.thumb = media.anime!!.anifyEpisodes!![i]?.thumb ?: episode.thumb episode.thumb =
media.anime!!.anifyEpisodes!![i]?.thumb ?: episode.thumb
} }
} }
@ -255,13 +254,16 @@ class AnimeWatchFragment : Fragment() {
} }
if (media.anime?.kitsuEpisodes != null) { if (media.anime?.kitsuEpisodes != null) {
if (media.anime!!.kitsuEpisodes!!.containsKey(i)) { if (media.anime!!.kitsuEpisodes!!.containsKey(i)) {
episode.desc = media.anime!!.kitsuEpisodes!![i]?.desc ?: episode.desc episode.desc =
media.anime!!.kitsuEpisodes!![i]?.desc ?: episode.desc
episode.title = if (MediaNameAdapter.removeEpisodeNumberCompletely( episode.title = if (MediaNameAdapter.removeEpisodeNumberCompletely(
episode.title ?: "" episode.title ?: ""
).isBlank() ).isBlank()
) media.anime!!.kitsuEpisodes!![i]?.title ?: episode.title else episode.title ) media.anime!!.kitsuEpisodes!![i]?.title
?: media.anime!!.kitsuEpisodes!![i]?.title ?: episode.title ?: episode.title else episode.title
episode.thumb = media.anime!!.kitsuEpisodes!![i]?.thumb ?: episode.thumb ?: media.anime!!.kitsuEpisodes!![i]?.title ?: episode.title
episode.thumb =
media.anime!!.kitsuEpisodes!![i]?.thumb ?: episode.thumb
} }
} }
} }
@ -400,29 +402,30 @@ class AnimeWatchFragment : Fragment() {
requireContext() requireContext()
.customAlertDialog() .customAlertDialog()
.apply { .apply {
setTitle("Select a Source") setTitle("Select a Source")
singleChoiceItems(names) { which -> singleChoiceItems(names) { which ->
selectedSetting = allSettings[which] selectedSetting = allSettings[which]
itemSelected = true itemSelected = true
requireActivity().runOnUiThread { requireActivity().runOnUiThread {
val fragment = AnimeSourcePreferencesFragment().getInstance(selectedSetting.id) { val fragment =
changeUIVisibility(true) AnimeSourcePreferencesFragment().getInstance(selectedSetting.id) {
loadEpisodes(media.selected!!.sourceIndex, true) changeUIVisibility(true)
loadEpisodes(media.selected!!.sourceIndex, true)
}
parentFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.slide_up, R.anim.slide_down)
.replace(R.id.fragmentExtensionsContainer, fragment)
.addToBackStack(null)
.commit()
} }
parentFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.slide_up, R.anim.slide_down)
.replace(R.id.fragmentExtensionsContainer, fragment)
.addToBackStack(null)
.commit()
} }
} onDismiss {
onDismiss { if (!itemSelected) {
if (!itemSelected) { changeUIVisibility(true)
changeUIVisibility(true) }
} }
show()
} }
show()
}
} else { } else {
// If there's only one setting, proceed with the fragment transaction // If there's only one setting, proceed with the fragment transaction
requireActivity().runOnUiThread { requireActivity().runOnUiThread {

View file

@ -1,6 +1,5 @@
package ani.dantotsu.media.anime package ani.dantotsu.media.anime
import android.app.AlertDialog
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 +12,6 @@ import androidx.media3.common.util.UnstableApi
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.connections.updateProgress import ani.dantotsu.connections.updateProgress
import ani.dantotsu.currContext
import ani.dantotsu.databinding.ItemEpisodeCompactBinding import ani.dantotsu.databinding.ItemEpisodeCompactBinding
import ani.dantotsu.databinding.ItemEpisodeGridBinding import ani.dantotsu.databinding.ItemEpisodeGridBinding
import ani.dantotsu.databinding.ItemEpisodeListBinding import ani.dantotsu.databinding.ItemEpisodeListBinding

View file

@ -12,8 +12,6 @@ import android.content.Intent
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.Configuration import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.Color
import android.graphics.drawable.Animatable import android.graphics.drawable.Animatable
import android.hardware.SensorManager import android.hardware.SensorManager
import android.media.AudioManager import android.media.AudioManager
@ -72,12 +70,10 @@ import androidx.media3.common.MimeTypes
import androidx.media3.common.PlaybackException import androidx.media3.common.PlaybackException
import androidx.media3.common.PlaybackParameters import androidx.media3.common.PlaybackParameters
import androidx.media3.common.Player import androidx.media3.common.Player
import androidx.media3.common.text.Cue
import androidx.media3.common.text.CueGroup
import androidx.media3.common.TrackGroup import androidx.media3.common.TrackGroup
import androidx.media3.common.TrackSelectionOverride import androidx.media3.common.TrackSelectionOverride
import androidx.media3.common.Tracks import androidx.media3.common.Tracks
import androidx.media3.common.util.Util import androidx.media3.common.text.CueGroup
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.datasource.DataSource import androidx.media3.datasource.DataSource
import androidx.media3.datasource.DefaultDataSource import androidx.media3.datasource.DefaultDataSource
@ -137,11 +133,11 @@ import ani.dantotsu.others.AniSkip
import ani.dantotsu.others.AniSkip.getType import ani.dantotsu.others.AniSkip.getType
import ani.dantotsu.others.LanguageMapper import ani.dantotsu.others.LanguageMapper
import ani.dantotsu.others.ResettableTimer import ani.dantotsu.others.ResettableTimer
import ani.dantotsu.others.Xubtitle
import ani.dantotsu.others.getSerialized import ani.dantotsu.others.getSerialized
import ani.dantotsu.parsers.AnimeSources import ani.dantotsu.parsers.AnimeSources
import ani.dantotsu.parsers.HAnimeSources import ani.dantotsu.parsers.HAnimeSources
import ani.dantotsu.parsers.Subtitle import ani.dantotsu.parsers.Subtitle
import ani.dantotsu.others.Xubtitle
import ani.dantotsu.parsers.SubtitleType import ani.dantotsu.parsers.SubtitleType
import ani.dantotsu.parsers.Video import ani.dantotsu.parsers.Video
import ani.dantotsu.parsers.VideoExtractor import ani.dantotsu.parsers.VideoExtractor
@ -164,6 +160,7 @@ import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability import com.google.android.gms.common.GoogleApiAvailability
import com.google.android.material.slider.Slider import com.google.android.material.slider.Slider
import com.lagradost.nicehttp.ignoreAllSSLErrors import com.lagradost.nicehttp.ignoreAllSSLErrors
import io.github.anilbeesetti.nextlib.media3ext.ffdecoder.NextRenderersFactory
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -171,7 +168,6 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import io.github.anilbeesetti.nextlib.media3ext.ffdecoder.NextRenderersFactory
import java.util.Calendar import java.util.Calendar
import java.util.Locale import java.util.Locale
import java.util.Timer import java.util.Timer
@ -237,7 +233,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
private var downloadId: String? = null private var downloadId: String? = null
private var hasExtSubtitles = false private var hasExtSubtitles = false
private var audioLanguages = mutableListOf<Pair<String,String>>() private var audioLanguages = mutableListOf<Pair<String, String>>()
companion object { companion object {
var initialized = false var initialized = false
@ -408,14 +404,14 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize) textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize)
textView.apply { textView.apply {
when (PrefManager.getVal<Int>(PrefName.Outline)) { when (PrefManager.getVal<Int>(PrefName.Outline)) {
0 -> applyOutline(secondaryColor, subStroke) 0 -> applyOutline(secondaryColor, subStroke)
1 -> applyShineEffect(secondaryColor) 1 -> applyShineEffect(secondaryColor)
2 -> applyDropShadow(secondaryColor, subStroke) 2 -> applyDropShadow(secondaryColor, subStroke)
3 -> {} 3 -> {}
else -> applyOutline(secondaryColor, subStroke) else -> applyOutline(secondaryColor, subStroke)
} }
} }
textView.alpha = textView.alpha =
when (PrefManager.getVal<Boolean>(PrefName.Subtitles)) { when (PrefManager.getVal<Boolean>(PrefName.Subtitles)) {
@ -423,8 +419,9 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
false -> 0f false -> 0f
} }
val textElevation = PrefManager.getVal<Float>(PrefName.SubBottomMargin) / 50 * resources.displayMetrics.heightPixels val textElevation =
textView.translationY = -textElevation PrefManager.getVal<Float>(PrefName.SubBottomMargin) / 50 * resources.displayMetrics.heightPixels
textView.translationY = -textElevation
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -1309,13 +1306,13 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
} }
private fun discordRPC(){ private fun discordRPC() {
val context = this val context = this
val ep = episode val ep = episode
val offline: Boolean = PrefManager.getVal(PrefName.OfflineMode) val offline: Boolean = PrefManager.getVal(PrefName.OfflineMode)
val incognito: Boolean = PrefManager.getVal(PrefName.Incognito) val incognito: Boolean = PrefManager.getVal(PrefName.Incognito)
val rpcenabled: Boolean = PrefManager.getVal(PrefName.rpcEnabled) val rpcenabled: Boolean = PrefManager.getVal(PrefName.rpcEnabled)
if ((isOnline(context) && !offline) && Discord.token != null && !incognito && rpcenabled) { if ((isOnline(context) && !offline) && Discord.token != null && !incognito && rpcenabled) {
lifecycleScope.launch { lifecycleScope.launch {
val discordMode = PrefManager.getCustomVal("discord_mode", "dantotsu") val discordMode = PrefManager.getCustomVal("discord_mode", "dantotsu")
val buttons = when (discordMode) { val buttons = when (discordMode) {
@ -1340,7 +1337,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
else -> mutableListOf() else -> mutableListOf()
} }
val startTimestamp = Calendar.getInstance() val startTimestamp = Calendar.getInstance()
val durationInSeconds = if (exoPlayer.duration != C.TIME_UNSET) (exoPlayer.duration / 1000).toInt() else 1440 val durationInSeconds =
if (exoPlayer.duration != C.TIME_UNSET) (exoPlayer.duration / 1000).toInt() else 1440
val endTimestamp = Calendar.getInstance().apply { val endTimestamp = Calendar.getInstance().apply {
timeInMillis = startTimestamp.timeInMillis timeInMillis = startTimestamp.timeInMillis
@ -1376,6 +1374,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
} }
} }
} }
private fun initPlayer() { private fun initPlayer() {
checkNotch() checkNotch()
@ -1451,7 +1450,13 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
null -> { null -> {
when (episode.selectedSubtitle) { when (episode.selectedSubtitle) {
null -> null null -> null
-1 -> ext.subtitles.find { it.language.contains( lang, ignoreCase = true ) || it.language.contains( getLanguageCode(lang), ignoreCase = true ) } -1 -> ext.subtitles.find {
it.language.contains(
lang,
ignoreCase = true
) || it.language.contains(getLanguageCode(lang), ignoreCase = true)
}
else -> ext.subtitles.getOrNull(episode.selectedSubtitle!!) else -> ext.subtitles.getOrNull(episode.selectedSubtitle!!)
} }
} }
@ -1704,17 +1709,17 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
.build() .build()
hideSystemBars() hideSystemBars()
val useExtensionDecoder = PrefManager.getVal<Boolean>(PrefName.UseAdditionalCodec) val useExtensionDecoder = PrefManager.getVal<Boolean>(PrefName.UseAdditionalCodec)
val decoder = if (useExtensionDecoder) { val decoder = if (useExtensionDecoder) {
DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER
} else { } else {
DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF
} }
val renderersFactory = NextRenderersFactory(this) val renderersFactory = NextRenderersFactory(this)
.setEnableDecoderFallback(true) .setEnableDecoderFallback(true)
.setExtensionRendererMode(decoder) .setExtensionRendererMode(decoder)
exoPlayer = ExoPlayer.Builder(this, renderersFactory) exoPlayer = ExoPlayer.Builder(this, renderersFactory)
.setMediaSourceFactory(DefaultMediaSourceFactory(cacheFactory)) .setMediaSourceFactory(DefaultMediaSourceFactory(cacheFactory))
.setTrackSelector(trackSelector) .setTrackSelector(trackSelector)
@ -1738,13 +1743,13 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
var activeSubtitles = ArrayDeque<String>(3) var activeSubtitles = ArrayDeque<String>(3)
var lastSubtitle: String? = null var lastSubtitle: String? = null
var lastPosition: Long = 0 var lastPosition: Long = 0
override fun onCues(cueGroup: CueGroup) { override fun onCues(cueGroup: CueGroup) {
if (PrefManager.getVal<Boolean>(PrefName.TextviewSubtitles)) { if (PrefManager.getVal<Boolean>(PrefName.TextviewSubtitles)) {
exoSubtitleView.visibility = View.GONE exoSubtitleView.visibility = View.GONE
customSubtitleView.visibility = View.VISIBLE customSubtitleView.visibility = View.VISIBLE
val newCues = cueGroup.cues.map { it.text.toString() ?: "" } val newCues = cueGroup.cues.map { it.text.toString() }
if (newCues.isEmpty()) { if (newCues.isEmpty()) {
customSubtitleView.text = "" customSubtitleView.text = ""
activeSubtitles.clear() activeSubtitles.clear()
@ -1752,23 +1757,25 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
lastPosition = 0 lastPosition = 0
return return
} }
val currentPosition = exoPlayer.currentPosition val currentPosition = exoPlayer.currentPosition
if ((lastSubtitle?.length ?: 0) < 20 || (lastPosition != 0L && currentPosition - lastPosition > 1500)) { if ((lastSubtitle?.length
?: 0) < 20 || (lastPosition != 0L && currentPosition - lastPosition > 1500)
) {
activeSubtitles.clear() activeSubtitles.clear()
} }
for (newCue in newCues) { for (newCue in newCues) {
if (newCue !in activeSubtitles) { if (newCue !in activeSubtitles) {
if (activeSubtitles.size >= 2) { if (activeSubtitles.size >= 2) {
activeSubtitles.removeLast() activeSubtitles.removeLast()
} }
activeSubtitles.addFirst(newCue) activeSubtitles.addFirst(newCue)
lastSubtitle = newCue lastSubtitle = newCue
lastPosition = currentPosition lastPosition = currentPosition
} }
} }
customSubtitleView.text = activeSubtitles.joinToString("\n") customSubtitleView.text = activeSubtitles.joinToString("\n")
} else { } else {
@ -1779,8 +1786,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
} }
}) })
applySubtitleStyles(customSubtitleView) applySubtitleStyles(customSubtitleView)
setupSubFormatting(playerView) setupSubFormatting(playerView)
try { try {
val rightNow = Calendar.getInstance() val rightNow = Calendar.getInstance()

View file

@ -2,7 +2,6 @@ package ani.dantotsu.media.anime
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.app.AlertDialog
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.ComponentName import android.content.ComponentName
import android.content.DialogInterface import android.content.DialogInterface
@ -446,7 +445,7 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
var subtitleToDownload: Subtitle? = null var subtitleToDownload: Subtitle? = null
requireActivity().customAlertDialog().apply { requireActivity().customAlertDialog().apply {
setTitle(R.string.download_subtitle) setTitle(R.string.download_subtitle)
singleChoiceItems(subtitleNames.toTypedArray()) {which -> singleChoiceItems(subtitleNames.toTypedArray()) { which ->
subtitleToDownload = subtitles[which] subtitleToDownload = subtitles[which]
} }
setPosButton(R.string.download) { setPosButton(R.string.download) {
@ -483,7 +482,7 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
) )
} else { } else {
val downloadAddonManager: DownloadAddonManager = Injekt.get() val downloadAddonManager: DownloadAddonManager = Injekt.get()
if (!downloadAddonManager.isAvailable()){ if (!downloadAddonManager.isAvailable()) {
val context = currContext() ?: requireContext() val context = currContext() ?: requireContext()
context.customAlertDialog().apply { context.customAlertDialog().apply {
setTitle(R.string.download_addon_not_installed) setTitle(R.string.download_addon_not_installed)
@ -564,17 +563,21 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
snackString(R.string.no_video_selected) snackString(R.string.no_video_selected)
} }
} }
fun checkAudioTracks() { fun checkAudioTracks() {
val audioTracks = extractor.audioTracks.map { it.lang } val audioTracks = extractor.audioTracks.map { it.lang }
if (audioTracks.isNotEmpty()) { if (audioTracks.isNotEmpty()) {
val audioNamesArray = audioTracks.toTypedArray() val audioNamesArray = audioTracks.toTypedArray()
val checkedItems = BooleanArray(audioNamesArray.size) { false } val checkedItems = BooleanArray(audioNamesArray.size) { false }
currContext.customAlertDialog().apply{ // ToTest currContext.customAlertDialog().apply { // ToTest
setTitle(R.string.download_audio_tracks) setTitle(R.string.download_audio_tracks)
multiChoiceItems(audioNamesArray, checkedItems) { multiChoiceItems(audioNamesArray, checkedItems) {
it.forEachIndexed { index, isChecked -> it.forEachIndexed { index, isChecked ->
val audioPair = Pair(extractor.audioTracks[index].url, extractor.audioTracks[index].lang) val audioPair = Pair(
extractor.audioTracks[index].url,
extractor.audioTracks[index].lang
)
if (isChecked) { if (isChecked) {
selectedAudioTracks.add(audioPair) selectedAudioTracks.add(audioPair)
} else { } else {
@ -606,7 +609,8 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
setTitle(R.string.download_subtitle) setTitle(R.string.download_subtitle)
multiChoiceItems(subtitleNamesArray, checkedItems) { multiChoiceItems(subtitleNamesArray, checkedItems) {
it.forEachIndexed { index, isChecked -> it.forEachIndexed { index, isChecked ->
val subtitlePair = Pair(subtitles[index].file.url, subtitles[index].language) val subtitlePair =
Pair(subtitles[index].file.url, subtitles[index].language)
if (isChecked) { if (isChecked) {
selectedSubtitles.add(subtitlePair) selectedSubtitles.add(subtitlePair)
} else { } else {

View file

@ -63,8 +63,12 @@ class TrackGroupDialogFragment(
override fun onBindViewHolder(holder: StreamViewHolder, position: Int) { override fun onBindViewHolder(holder: StreamViewHolder, position: Int) {
val binding = holder.binding val binding = holder.binding
trackGroups[position].let { trackGroup -> trackGroups[position].let { trackGroup ->
if (overrideTrackNames?.getOrNull(position - (trackGroups.size - (overrideTrackNames?.size?:0))) != null) { if (overrideTrackNames?.getOrNull(
val pair = overrideTrackNames!![position - (trackGroups.size - overrideTrackNames!!.size)] position - (trackGroups.size - (overrideTrackNames?.size ?: 0))
) != null
) {
val pair =
overrideTrackNames!![position - (trackGroups.size - overrideTrackNames!!.size)]
binding.subtitleTitle.text = binding.subtitleTitle.text =
"[${pair.second}] ${pair.first}" "[${pair.second}] ${pair.first}"
} else when (val language = trackGroup.getTrackFormat(0).language?.lowercase()) { } else when (val language = trackGroup.getTrackFormat(0).language?.lowercase()) {

View file

@ -15,7 +15,6 @@ import ani.dantotsu.databinding.ItemCommentsBinding
import ani.dantotsu.getAppString import ani.dantotsu.getAppString
import ani.dantotsu.loadImage import ani.dantotsu.loadImage
import ani.dantotsu.openImage import ani.dantotsu.openImage
import ani.dantotsu.others.ImageViewDialog
import ani.dantotsu.profile.ProfileActivity import ani.dantotsu.profile.ProfileActivity
import ani.dantotsu.setAnimation import ani.dantotsu.setAnimation
import ani.dantotsu.snackString import ani.dantotsu.snackString

View file

@ -2,7 +2,6 @@ package ani.dantotsu.media.comments
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Context.INPUT_METHOD_SERVICE import android.content.Context.INPUT_METHOD_SERVICE
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.os.Bundle import android.os.Bundle
@ -12,7 +11,6 @@ import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.core.animation.doOnEnd import androidx.core.animation.doOnEnd
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
@ -33,7 +31,6 @@ import ani.dantotsu.setBaseline
import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString import ani.dantotsu.snackString
import ani.dantotsu.toast
import ani.dantotsu.util.Logger import ani.dantotsu.util.Logger
import ani.dantotsu.util.customAlertDialog import ani.dantotsu.util.customAlertDialog
import com.xwray.groupie.GroupieAdapter import com.xwray.groupie.GroupieAdapter
@ -587,19 +584,19 @@ class CommentsFragment : Fragment() {
private fun showCommentRulesDialog() { private fun showCommentRulesDialog() {
activity.customAlertDialog().apply { activity.customAlertDialog().apply {
setTitle("Commenting Rules") setTitle("Commenting Rules")
.setMessage( .setMessage(
"🚨 BREAK ANY RULE = YOU'RE GONE\n\n" + "🚨 BREAK ANY RULE = YOU'RE GONE\n\n" +
"1. NO RACISM, DISCRIMINATION, OR HATE SPEECH\n" + "1. NO RACISM, DISCRIMINATION, OR HATE SPEECH\n" +
"2. NO SPAMMING OR SELF-PROMOTION\n" + "2. NO SPAMMING OR SELF-PROMOTION\n" +
"3. ABSOLUTELY NO NSFW CONTENT\n" + "3. ABSOLUTELY NO NSFW CONTENT\n" +
"4. ENGLISH ONLY NO EXCEPTIONS\n" + "4. ENGLISH ONLY NO EXCEPTIONS\n" +
"5. NO IMPERSONATION, HARASSMENT, OR ABUSE\n" + "5. NO IMPERSONATION, HARASSMENT, OR ABUSE\n" +
"6. NO ILLEGAL CONTENT OR EXTREME DISRESPECT TOWARDS ANY FANDOM\n" + "6. NO ILLEGAL CONTENT OR EXTREME DISRESPECT TOWARDS ANY FANDOM\n" +
"7. DO NOT REQUEST OR SHARE REPOSITORIES/EXTENSIONS\n" + "7. DO NOT REQUEST OR SHARE REPOSITORIES/EXTENSIONS\n" +
"8. SPOILERS ALLOWED ONLY WITH SPOILER TAGS AND A WARNING\n" + "8. SPOILERS ALLOWED ONLY WITH SPOILER TAGS AND A WARNING\n" +
"9. NO SEXUALIZING OR INAPPROPRIATE COMMENTS ABOUT MINOR CHARACTERS\n" + "9. NO SEXUALIZING OR INAPPROPRIATE COMMENTS ABOUT MINOR CHARACTERS\n" +
"10. IF IT'S WRONG, DON'T POST IT!\n\n" "10. IF IT'S WRONG, DON'T POST IT!\n\n"
) )
setPosButton("I Understand") { setPosButton("I Understand") {
PrefManager.setVal(PrefName.FirstComment, false) PrefManager.setVal(PrefName.FirstComment, false)
processComment() processComment()

View file

@ -1,6 +1,5 @@
package ani.dantotsu.media.manga package ani.dantotsu.media.manga
import android.app.AlertDialog
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup

View file

@ -22,8 +22,8 @@ import ani.dantotsu.currActivity
import ani.dantotsu.currContext import ani.dantotsu.currContext
import ani.dantotsu.databinding.CustomDialogLayoutBinding import ani.dantotsu.databinding.CustomDialogLayoutBinding
import ani.dantotsu.databinding.DialogLayoutBinding import ani.dantotsu.databinding.DialogLayoutBinding
import ani.dantotsu.databinding.ItemMediaSourceBinding
import ani.dantotsu.databinding.ItemChipBinding import ani.dantotsu.databinding.ItemChipBinding
import ani.dantotsu.databinding.ItemMediaSourceBinding
import ani.dantotsu.isOnline import ani.dantotsu.isOnline
import ani.dantotsu.loadImage import ani.dantotsu.loadImage
import ani.dantotsu.media.Media import ani.dantotsu.media.Media
@ -75,7 +75,8 @@ class MangaReadAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val bind = ItemMediaSourceBinding.inflate(LayoutInflater.from(parent.context), parent, false) val bind =
ItemMediaSourceBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(bind) return ViewHolder(bind)
} }
@ -99,11 +100,11 @@ class MangaReadAdapter(
} }
val offline = !isOnline(binding.root.context) || PrefManager.getVal(PrefName.OfflineMode) val offline = !isOnline(binding.root.context) || PrefManager.getVal(PrefName.OfflineMode)
//for removing saved progress //for removing saved progress
binding.sourceTitle.setOnLongClickListener{ binding.sourceTitle.setOnLongClickListener {
fragment.requireContext().customAlertDialog().apply { fragment.requireContext().customAlertDialog().apply {
setTitle(" Delete Progress for all chapters of ${media.nameRomaji}") setTitle(" Delete Progress for all chapters of ${media.nameRomaji}")
setMessage("This will delete all the locally stored progress for chapters") setMessage("This will delete all the locally stored progress for chapters")
setPosButton(R.string.ok){ setPosButton(R.string.ok) {
clearCustomValsForMedia("${media.id}", "_Chapter") clearCustomValsForMedia("${media.id}", "_Chapter")
clearCustomValsForMedia("${media.id}", "_Vol") clearCustomValsForMedia("${media.id}", "_Vol")
snackString("Deleted the progress of Chapters for ${media.nameRomaji}") snackString("Deleted the progress of Chapters for ${media.nameRomaji}")
@ -286,7 +287,7 @@ class MangaReadAdapter(
fragment.requireContext().customAlertDialog().apply { fragment.requireContext().customAlertDialog().apply {
setTitle(" Delete Progress for all chapters of ${media.nameRomaji}") setTitle(" Delete Progress for all chapters of ${media.nameRomaji}")
setMessage("This will delete all the locally stored progress for chapters") setMessage("This will delete all the locally stored progress for chapters")
setPosButton(R.string.ok){ setPosButton(R.string.ok) {
// Usage // Usage
clearCustomValsForMedia("${media.id}", "_Chapter") clearCustomValsForMedia("${media.id}", "_Chapter")
clearCustomValsForMedia("${media.id}", "_Vol") clearCustomValsForMedia("${media.id}", "_Vol")
@ -297,7 +298,7 @@ class MangaReadAdapter(
show() show()
} }
} }
resetProgressDef.text = getString(currContext()!!,R.string.clear_stored_chapter) resetProgressDef.text = getString(currContext()!!, R.string.clear_stored_chapter)
// Scanlator // Scanlator
mangaScanlatorContainer.isVisible = options.count() > 1 mangaScanlatorContainer.isVisible = options.count() > 1
@ -331,12 +332,17 @@ class MangaReadAdapter(
val checkBox = CheckBox(currContext()).apply { val checkBox = CheckBox(currContext()).apply {
text = option text = option
setOnCheckedChangeListener { _, _ -> setOnCheckedChangeListener { _, _ ->
tickAllButton.setImageResource(getToggleImageResource(checkboxContainer)) tickAllButton.setImageResource(
getToggleImageResource(
checkboxContainer
)
)
} }
} }
if (media.selected!!.scanlators != null) { if (media.selected!!.scanlators != null) {
checkBox.isChecked = media.selected!!.scanlators?.contains(option) != true checkBox.isChecked =
media.selected!!.scanlators?.contains(option) != true
scanlatorSelectionListener?.onScanlatorsSelected() scanlatorSelectionListener?.onScanlatorsSelected()
} else { } else {
checkBox.isChecked = true checkBox.isChecked = true
@ -488,10 +494,12 @@ class MangaReadAdapter(
} }
} }
val formattedChapters = filteredChapters.map { val formattedChapters = filteredChapters.map {
MediaNameAdapter.findChapterNumber(it.value.number)?.toInt()?.toString() to it.key MediaNameAdapter.findChapterNumber(it.value.number)?.toInt()
?.toString() to it.key
} }
if (formattedChapters.any { it.first == continueNumber }) { if (formattedChapters.any { it.first == continueNumber }) {
var continueEp = media.manga.chapters!![formattedChapters.first { it.first == continueNumber }.second] var continueEp =
media.manga.chapters!![formattedChapters.first { it.first == continueNumber }.second]
binding.sourceContinue.visibility = View.VISIBLE binding.sourceContinue.visibility = View.VISIBLE
handleProgress( handleProgress(
binding.itemMediaProgressCont, binding.itemMediaProgressCont,
@ -501,9 +509,11 @@ class MangaReadAdapter(
continueEp!!.number continueEp!!.number
) )
if ((binding.itemMediaProgress.layoutParams as LinearLayout.LayoutParams).weight > 0.8f) { if ((binding.itemMediaProgress.layoutParams as LinearLayout.LayoutParams).weight > 0.8f) {
val numberPlusOne = formattedChapters.indexOfFirst { it.first?.toIntOrNull() == continueNumber.toInt() + 1 } val numberPlusOne =
formattedChapters.indexOfFirst { it.first?.toIntOrNull() == continueNumber.toInt() + 1 }
if (numberPlusOne != -1) { if (numberPlusOne != -1) {
continueEp = media.manga.chapters!![formattedChapters[numberPlusOne].second] continueEp =
media.manga.chapters!![formattedChapters[numberPlusOne].second]
} }
} }
binding.itemMediaImage.loadImage(media.banner ?: media.cover) binding.itemMediaImage.loadImage(media.banner ?: media.cover)
@ -530,7 +540,8 @@ class MangaReadAdapter(
binding.sourceProgressBar.visibility = View.GONE binding.sourceProgressBar.visibility = View.GONE
val sourceFound = filteredChapters.isNotEmpty() val sourceFound = filteredChapters.isNotEmpty()
val isDownloadedSource = mangaReadSources[media.selected!!.sourceIndex] is OfflineMangaParser val isDownloadedSource =
mangaReadSources[media.selected!!.sourceIndex] is OfflineMangaParser
if (isDownloadedSource) { if (isDownloadedSource) {
binding.sourceNotFound.text = if (sourceFound) { binding.sourceNotFound.text = if (sourceFound) {
@ -539,7 +550,8 @@ class MangaReadAdapter(
currActivity()!!.getString(R.string.download_not_found) currActivity()!!.getString(R.string.download_not_found)
} }
} else { } else {
binding.sourceNotFound.text = currActivity()!!.getString(R.string.source_not_found) binding.sourceNotFound.text =
currActivity()!!.getString(R.string.source_not_found)
} }
binding.sourceNotFound.isGone = sourceFound binding.sourceNotFound.isGone = sourceFound

View file

@ -261,13 +261,14 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
val chapters = loadedChapters[media.selected!!.sourceIndex] val chapters = loadedChapters[media.selected!!.sourceIndex]
if (chapters != null) { if (chapters != null) {
headerAdapter.options = getScanlators(chapters) headerAdapter.options = getScanlators(chapters)
val filteredChapters = if (model.mangaReadSources?.get(media.selected!!.sourceIndex) is OfflineMangaParser) { val filteredChapters =
chapters if (model.mangaReadSources?.get(media.selected!!.sourceIndex) is OfflineMangaParser) {
} else { chapters
chapters.filterNot { (_, chapter) -> } else {
chapter.scanlator in headerAdapter.hiddenScanlators chapters.filterNot { (_, chapter) ->
chapter.scanlator in headerAdapter.hiddenScanlators
}
} }
}
media.manga?.chapters = filteredChapters.toMutableMap() media.manga?.chapters = filteredChapters.toMutableMap()
@ -397,17 +398,18 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
selectedSetting = allSettings[which] selectedSetting = allSettings[which]
itemSelected = true itemSelected = true
val fragment = MangaSourcePreferencesFragment().getInstance(selectedSetting.id) { val fragment =
changeUIVisibility(true) MangaSourcePreferencesFragment().getInstance(selectedSetting.id) {
loadChapters(media.selected!!.sourceIndex, true) changeUIVisibility(true)
} loadChapters(media.selected!!.sourceIndex, true)
}
parentFragmentManager.beginTransaction() parentFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.slide_up, R.anim.slide_down) .setCustomAnimations(R.anim.slide_up, R.anim.slide_down)
.replace(R.id.fragmentExtensionsContainer, fragment) .replace(R.id.fragmentExtensionsContainer, fragment)
.addToBackStack(null) .addToBackStack(null)
.commit() .commit()
} }
onDismiss{ onDismiss {
if (!itemSelected) { if (!itemSelected) {
changeUIVisibility(true) changeUIVisibility(true)
} }
@ -590,7 +592,9 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
// Find latest chapter for subscription // Find latest chapter for subscription
selected.latest = selected.latest =
media.manga?.chapters?.values?.maxOfOrNull { MediaNameAdapter.findChapterNumber(it.number) ?: 0f } ?: 0f media.manga?.chapters?.values?.maxOfOrNull {
MediaNameAdapter.findChapterNumber(it.number) ?: 0f
} ?: 0f
selected.latest = selected.latest =
media.userProgress?.toFloat()?.takeIf { selected.latest < it } ?: selected.latest media.userProgress?.toFloat()?.takeIf { selected.latest < it } ?: selected.latest

View file

@ -78,7 +78,8 @@ class ChapterLoaderDialog : BottomSheetDialogFragment() {
_binding = BottomSheetSelectorBinding.inflate(inflater, container, false) _binding = BottomSheetSelectorBinding.inflate(inflater, container, false)
val window = dialog?.window val window = dialog?.window
window?.statusBarColor = Color.TRANSPARENT window?.statusBarColor = Color.TRANSPARENT
window?.navigationBarColor = requireContext().getThemeColor(com.google.android.material.R.attr.colorSurface) window?.navigationBarColor =
requireContext().getThemeColor(com.google.android.material.R.attr.colorSurface)
return binding.root return binding.root
} }

View file

@ -2,7 +2,6 @@ package ani.dantotsu.media.manga.mangareader
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.Configuration import android.content.res.Configuration
@ -58,8 +57,6 @@ import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsViewModel import ani.dantotsu.media.MediaDetailsViewModel
import ani.dantotsu.media.MediaNameAdapter import ani.dantotsu.media.MediaNameAdapter
import ani.dantotsu.media.MediaSingleton import ani.dantotsu.media.MediaSingleton
import ani.dantotsu.media.anime.ExoplayerView
import ani.dantotsu.media.anime.ExoplayerView.Companion
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.others.ImageViewDialog import ani.dantotsu.others.ImageViewDialog
@ -196,8 +193,9 @@ class MangaReaderActivity : AppCompatActivity() {
finish() finish()
return@addCallback return@addCallback
} }
val chapter = (MediaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!.number) val chapter =
?.minus(1L) ?: 0).toString() (MediaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!.number)
?.minus(1L) ?: 0).toString()
if (chapter == "0.0" && PrefManager.getVal(PrefName.ChapterZeroReader) if (chapter == "0.0" && PrefManager.getVal(PrefName.ChapterZeroReader)
// Not asking individually or incognito // Not asking individually or incognito
&& !showProgressDialog && !PrefManager.getVal<Boolean>(PrefName.Incognito) && !showProgressDialog && !PrefManager.getVal<Boolean>(PrefName.Incognito)

View file

@ -55,6 +55,7 @@ class Swipy @JvmOverloads constructor(
else else
VerticalPosition.Top VerticalPosition.Top
} }
!it.canScrollVertically(1) -> VerticalPosition.Bottom !it.canScrollVertically(1) -> VerticalPosition.Bottom
!it.canScrollVertically(-1) -> VerticalPosition.Top !it.canScrollVertically(-1) -> VerticalPosition.Top
else -> VerticalPosition.None else -> VerticalPosition.None
@ -67,6 +68,7 @@ class Swipy @JvmOverloads constructor(
else else
HorizontalPosition.Left HorizontalPosition.Left
} }
!it.canScrollHorizontally(1) -> HorizontalPosition.Right !it.canScrollHorizontally(1) -> HorizontalPosition.Right
!it.canScrollHorizontally(-1) -> HorizontalPosition.Left !it.canScrollHorizontally(-1) -> HorizontalPosition.Left
else -> HorizontalPosition.None else -> HorizontalPosition.None
@ -97,12 +99,14 @@ class Swipy @JvmOverloads constructor(
initialDown = if (vertical) ev.getY(0) else ev.getX(0) initialDown = if (vertical) ev.getY(0) else ev.getX(0)
isBeingDragged = false isBeingDragged = false
} }
MotionEvent.ACTION_MOVE -> { MotionEvent.ACTION_MOVE -> {
val pointerIndex = ev.findPointerIndex(activePointerId) val pointerIndex = ev.findPointerIndex(activePointerId)
if (pointerIndex >= 0) { if (pointerIndex >= 0) {
startDragging(if (vertical) ev.getY(pointerIndex) else ev.getX(pointerIndex)) startDragging(if (vertical) ev.getY(pointerIndex) else ev.getX(pointerIndex))
} }
} }
MotionEvent.ACTION_POINTER_UP -> onSecondaryPointerUp(ev) MotionEvent.ACTION_POINTER_UP -> onSecondaryPointerUp(ev)
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
isBeingDragged = false isBeingDragged = false
@ -122,6 +126,7 @@ class Swipy @JvmOverloads constructor(
activePointerId = ev.getPointerId(0) activePointerId = ev.getPointerId(0)
isBeingDragged = false isBeingDragged = false
} }
MotionEvent.ACTION_MOVE -> { MotionEvent.ACTION_MOVE -> {
pointerIndex = ev.findPointerIndex(activePointerId) pointerIndex = ev.findPointerIndex(activePointerId)
if (pointerIndex >= 0) { if (pointerIndex >= 0) {
@ -130,28 +135,36 @@ class Swipy @JvmOverloads constructor(
if (isBeingDragged) handleDrag(pos) if (isBeingDragged) handleDrag(pos)
} }
} }
MotionEvent.ACTION_POINTER_DOWN -> { MotionEvent.ACTION_POINTER_DOWN -> {
pointerIndex = ev.actionIndex pointerIndex = ev.actionIndex
if (pointerIndex >= 0) activePointerId = ev.getPointerId(pointerIndex) if (pointerIndex >= 0) activePointerId = ev.getPointerId(pointerIndex)
} }
MotionEvent.ACTION_POINTER_UP -> onSecondaryPointerUp(ev) MotionEvent.ACTION_POINTER_UP -> onSecondaryPointerUp(ev)
MotionEvent.ACTION_UP -> { MotionEvent.ACTION_UP -> {
resetSwipes() resetSwipes()
pointerIndex = ev.findPointerIndex(activePointerId) pointerIndex = ev.findPointerIndex(activePointerId)
if (pointerIndex >= 0) finishSpinner(if (vertical) ev.getY(pointerIndex) else ev.getX(pointerIndex)) if (pointerIndex >= 0) finishSpinner(
if (vertical) ev.getY(pointerIndex) else ev.getX(
pointerIndex
)
)
activePointerId = INVALID_POINTER activePointerId = INVALID_POINTER
return false return false
} }
MotionEvent.ACTION_CANCEL -> return false MotionEvent.ACTION_CANCEL -> return false
} }
return true return true
} }
private fun startDragging(pos: Float) { private fun startDragging(pos: Float) {
val posDiff = if ((vertical && verticalPos == VerticalPosition.Top) || (!vertical && horizontalPos == HorizontalPosition.Left)) val posDiff =
pos - initialDown if ((vertical && verticalPos == VerticalPosition.Top) || (!vertical && horizontalPos == HorizontalPosition.Left))
else pos - initialDown
initialDown - pos else
initialDown - pos
if (posDiff > touchSlop && !isBeingDragged) { if (posDiff > touchSlop && !isBeingDragged) {
initialMotion = initialDown + touchSlop initialMotion = initialDown + touchSlop
isBeingDragged = true isBeingDragged = true
@ -185,7 +198,7 @@ class Swipy @JvmOverloads constructor(
leftBeingSwiped.invoke(0f) leftBeingSwiped.invoke(0f)
} }
} }
private fun finishSpinner(overscrollDistance: Float) { private fun finishSpinner(overscrollDistance: Float) {
if (vertical) { if (vertical) {
val totalDragDistance = Resources.getSystem().displayMetrics.heightPixels / dragDivider val totalDragDistance = Resources.getSystem().displayMetrics.heightPixels / dragDivider

View file

@ -14,8 +14,6 @@ import ani.dantotsu.setAnimation
import ani.dantotsu.snackString import ani.dantotsu.snackString
import ani.dantotsu.util.Logger import ani.dantotsu.util.Logger
import ani.dantotsu.util.customAlertDialog import ani.dantotsu.util.customAlertDialog
import com.bumptech.glide.Glide
import com.bumptech.glide.load.model.GlideUrl
class NovelResponseAdapter( class NovelResponseAdapter(
val fragment: NovelReadFragment, val fragment: NovelReadFragment,
@ -41,7 +39,8 @@ class NovelResponseAdapter(
setAnimation(fragment.requireContext(), holder.binding.root) setAnimation(fragment.requireContext(), holder.binding.root)
binding.itemMediaImage.loadImage(novel.coverUrl, 400, 0) binding.itemMediaImage.loadImage(novel.coverUrl, 400, 0)
val color =fragment.requireContext().getThemeColor(com.google.android.material.R.attr.colorOnBackground) val color = fragment.requireContext()
.getThemeColor(com.google.android.material.R.attr.colorOnBackground)
binding.itemEpisodeTitle.text = novel.name binding.itemEpisodeTitle.text = novel.name
binding.itemEpisodeFiller.text = binding.itemEpisodeFiller.text =
if (downloadedCheckCallback.downloadedCheck(novel)) { if (downloadedCheckCallback.downloadedCheck(novel)) {

View file

@ -50,10 +50,10 @@ class ListViewModel : ViewModel() {
search, search,
ignoreCase = true ignoreCase = true
) == true || media.synonyms.any { it.contains(search, ignoreCase = true) } || ) == true || media.synonyms.any { it.contains(search, ignoreCase = true) } ||
media.nameRomaji.contains( media.nameRomaji.contains(
search, search,
ignoreCase = true ignoreCase = true
) )
} as ArrayList<Media> } as ArrayList<Media>
}.toMutableMap() }.toMutableMap()

View file

@ -22,13 +22,13 @@ class AlarmManagerScheduler(private val context: Context) : TaskScheduler {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = when { val intent = when {
taskType == TaskType.COMMENT_NOTIFICATION && PrefManager.getVal<Int>(PrefName.CommentsEnabled) == 1 -> taskType == TaskType.COMMENT_NOTIFICATION && PrefManager.getVal<Int>(PrefName.CommentsEnabled) == 1 ->
Intent(context, CommentNotificationReceiver::class.java) Intent(context, CommentNotificationReceiver::class.java)
taskType == TaskType.ANILIST_NOTIFICATION -> taskType == TaskType.ANILIST_NOTIFICATION ->
Intent(context, AnilistNotificationReceiver::class.java) Intent(context, AnilistNotificationReceiver::class.java)
taskType == TaskType.SUBSCRIPTION_NOTIFICATION -> taskType == TaskType.SUBSCRIPTION_NOTIFICATION ->
Intent(context, SubscriptionNotificationReceiver::class.java) Intent(context, SubscriptionNotificationReceiver::class.java)
else -> return else -> return
@ -63,13 +63,13 @@ class AlarmManagerScheduler(private val context: Context) : TaskScheduler {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = when { val intent = when {
taskType == TaskType.COMMENT_NOTIFICATION && PrefManager.getVal<Int>(PrefName.CommentsEnabled) == 1 -> taskType == TaskType.COMMENT_NOTIFICATION && PrefManager.getVal<Int>(PrefName.CommentsEnabled) == 1 ->
Intent(context, CommentNotificationReceiver::class.java) Intent(context, CommentNotificationReceiver::class.java)
taskType == TaskType.ANILIST_NOTIFICATION -> taskType == TaskType.ANILIST_NOTIFICATION ->
Intent(context, AnilistNotificationReceiver::class.java) Intent(context, AnilistNotificationReceiver::class.java)
taskType == TaskType.SUBSCRIPTION_NOTIFICATION -> taskType == TaskType.SUBSCRIPTION_NOTIFICATION ->
Intent(context, SubscriptionNotificationReceiver::class.java) Intent(context, SubscriptionNotificationReceiver::class.java)
else -> return else -> return

View file

@ -5,7 +5,6 @@ import ani.dantotsu.currContext
import ani.dantotsu.media.Media import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaNameAdapter import ani.dantotsu.media.MediaNameAdapter
import ani.dantotsu.media.Selected import ani.dantotsu.media.Selected
import ani.dantotsu.media.emptyMedia
import ani.dantotsu.parsers.AnimeParser import ani.dantotsu.parsers.AnimeParser
import ani.dantotsu.parsers.AnimeSources import ani.dantotsu.parsers.AnimeSources
import ani.dantotsu.parsers.BaseParser import ani.dantotsu.parsers.BaseParser
@ -63,11 +62,11 @@ class SubscriptionHelper {
val show = parser.loadSavedShowResponse(subscribeMedia.id) val show = parser.loadSavedShowResponse(subscribeMedia.id)
?: forceLoadShowResponse(subscribeMedia, selected, parser) ?: forceLoadShowResponse(subscribeMedia, selected, parser)
?: throw Exception( ?: throw Exception(
currContext()?.getString( currContext()?.getString(
R.string.failed_to_load_data, R.string.failed_to_load_data,
subscribeMedia.id subscribeMedia.id
)
) )
)
show.sAnime?.let { show.sAnime?.let {
parser.getLatestEpisode( parser.getLatestEpisode(
show.link, show.extra, show.link, show.extra,
@ -103,11 +102,11 @@ class SubscriptionHelper {
val show = parser.loadSavedShowResponse(subscribeMedia.id) val show = parser.loadSavedShowResponse(subscribeMedia.id)
?: forceLoadShowResponse(subscribeMedia, selected, parser) ?: forceLoadShowResponse(subscribeMedia, selected, parser)
?: throw Exception( ?: throw Exception(
currContext()?.getString( currContext()?.getString(
R.string.failed_to_load_data, R.string.failed_to_load_data,
subscribeMedia.id subscribeMedia.id
)
) )
)
show.sManga?.let { show.sManga?.let {
parser.getLatestChapter( parser.getLatestChapter(
show.link, show.extra, show.link, show.extra,
@ -123,7 +122,11 @@ class SubscriptionHelper {
} }
} }
private suspend fun forceLoadShowResponse(subscribeMedia: SubscribeMedia, selected: Selected, parser: BaseParser): ShowResponse? { private suspend fun forceLoadShowResponse(
subscribeMedia: SubscribeMedia,
selected: Selected,
parser: BaseParser
): ShowResponse? {
val tempMedia = Media( val tempMedia = Media(
id = subscribeMedia.id, id = subscribeMedia.id,
name = null, name = null,

View file

@ -127,8 +127,10 @@ class SubscriptionNotificationTask : Task {
banner = media.banner banner = media.banner
) )
) )
PrefManager.setVal(PrefName.UnreadCommentNotifications, PrefManager.setVal(
PrefManager.getVal<Int>(PrefName.UnreadCommentNotifications) + 1) PrefName.UnreadCommentNotifications,
PrefManager.getVal<Int>(PrefName.UnreadCommentNotifications) + 1
)
val notification = createNotification( val notification = createNotification(
context.applicationContext, context.applicationContext,
media, media,
@ -240,7 +242,7 @@ class SubscriptionNotificationTask : Task {
if (newStore.size >= 100) { if (newStore.size >= 100) {
newStore.remove(newStore.minByOrNull { it.time }) newStore.remove(newStore.minByOrNull { it.time })
} }
if (newStore.any { it.title == notification.title && it.content == notification.content}) { if (newStore.any { it.title == notification.title && it.content == notification.content }) {
return return
} }

View file

@ -4,7 +4,6 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import ani.dantotsu.R import ani.dantotsu.R
@ -37,7 +36,7 @@ class OfflineFragment : Fragment() {
PrefManager.setVal(PrefName.OfflineMode, false) PrefManager.setVal(PrefName.OfflineMode, false)
startMainActivity(requireActivity()) startMainActivity(requireActivity())
} else { } else {
if (isOnline(requireContext()) ) { if (isOnline(requireContext())) {
startMainActivity(requireActivity()) startMainActivity(requireActivity())
} }
} }

View file

@ -10,7 +10,7 @@ import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.decodeFromJsonElement import kotlinx.serialization.json.decodeFromJsonElement
object Anify { object Anify {
suspend fun fetchAndParseMetadata(id :Int): Map<String, Episode> { suspend fun fetchAndParseMetadata(id: Int): Map<String, Episode> {
val response = client.get("https://anify.eltik.cc/content-metadata/$id") val response = client.get("https://anify.eltik.cc/content-metadata/$id")
.parsed<JsonArray>().map { .parsed<JsonArray>().map {
Mapper.json.decodeFromJsonElement<AnifyElement>(it) Mapper.json.decodeFromJsonElement<AnifyElement>(it)
@ -24,15 +24,16 @@ object Anify {
) )
} ?: emptyMap() } ?: emptyMap()
} }
@Serializable @Serializable
data class AnifyElement ( data class AnifyElement(
@SerialName("providerId") @SerialName("providerId")
val providerID: String? = null, val providerID: String? = null,
val data: List<Datum>? = null val data: List<Datum>? = null
) )
@Serializable @Serializable
data class Datum ( data class Datum(
val id: String? = null, val id: String? = null,
val description: String? = null, val description: String? = null,
val hasDub: Boolean? = null, val hasDub: Boolean? = null,

View file

@ -13,132 +13,132 @@ import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.AppCompatTextView
class Xubtitle class Xubtitle
@JvmOverloads @JvmOverloads
constructor( constructor(
context: Context, context: Context,
attrs: AttributeSet? = null, attrs: AttributeSet? = null,
defStyleAttr: Int = 0, defStyleAttr: Int = 0,
) : AppCompatTextView(context, attrs, defStyleAttr) { ) : AppCompatTextView(context, attrs, defStyleAttr) {
private var outlineThickness: Float = 0f private var outlineThickness: Float = 0f
private var effectColor: Int = currentTextColor private var effectColor: Int = currentTextColor
private var currentEffect: Effect = Effect.NONE private var currentEffect: Effect = Effect.NONE
private val shadowPaint = Paint().apply { isAntiAlias = true } private val shadowPaint = Paint().apply { isAntiAlias = true }
private val outlinePaint = Paint().apply { isAntiAlias = true } private val outlinePaint = Paint().apply { isAntiAlias = true }
private var shineShader: Shader? = null private var shineShader: Shader? = null
enum class Effect { enum class Effect {
NONE, NONE,
OUTLINE, OUTLINE,
SHINE, SHINE,
DROP_SHADOW, DROP_SHADOW,
} }
override fun onDraw(canvas: Canvas) { override fun onDraw(canvas: Canvas) {
val text = text.toString() val text = text.toString()
val textPaint = val textPaint =
TextPaint(paint).apply { TextPaint(paint).apply {
color = currentTextColor color = currentTextColor
} }
val staticLayout = val staticLayout =
StaticLayout.Builder StaticLayout.Builder
.obtain(text, 0, text.length, textPaint, width) .obtain(text, 0, text.length, textPaint, width)
.setAlignment(Layout.Alignment.ALIGN_CENTER) .setAlignment(Layout.Alignment.ALIGN_CENTER)
.setLineSpacing(0f, 1f) .setLineSpacing(0f, 1f)
.build() .build()
when (currentEffect) { when (currentEffect) {
Effect.OUTLINE -> { Effect.OUTLINE -> {
textPaint.style = Paint.Style.STROKE textPaint.style = Paint.Style.STROKE
textPaint.strokeWidth = outlineThickness textPaint.strokeWidth = outlineThickness
textPaint.color = effectColor textPaint.color = effectColor
staticLayout.draw(canvas) staticLayout.draw(canvas)
textPaint.style = Paint.Style.FILL textPaint.style = Paint.Style.FILL
textPaint.color = currentTextColor textPaint.color = currentTextColor
staticLayout.draw(canvas) staticLayout.draw(canvas)
} }
Effect.DROP_SHADOW -> { Effect.DROP_SHADOW -> {
setLayerType(LAYER_TYPE_SOFTWARE, null) setLayerType(LAYER_TYPE_SOFTWARE, null)
textPaint.setShadowLayer(outlineThickness, 4f, 4f, effectColor) textPaint.setShadowLayer(outlineThickness, 4f, 4f, effectColor)
staticLayout.draw(canvas) staticLayout.draw(canvas)
textPaint.clearShadowLayer() textPaint.clearShadowLayer()
} }
Effect.SHINE -> { Effect.SHINE -> {
val shadowShader = val shadowShader =
LinearGradient( LinearGradient(
0f, 0f,
0f, 0f,
width.toFloat(), width.toFloat(),
height.toFloat(), height.toFloat(),
intArrayOf(Color.WHITE, effectColor, Color.BLACK), intArrayOf(Color.WHITE, effectColor, Color.BLACK),
null, null,
Shader.TileMode.CLAMP, Shader.TileMode.CLAMP,
)
val shadowPaint =
Paint().apply {
isAntiAlias = true
style = Paint.Style.FILL
textSize = textPaint.textSize
typeface = textPaint.typeface
shader = shadowShader
}
canvas.drawText(
text,
x + 4f, // Shadow offset
y + 4f,
shadowPaint,
) )
val shader = val shadowPaint =
LinearGradient( Paint().apply {
0f, isAntiAlias = true
0f, style = Paint.Style.FILL
width.toFloat(), textSize = textPaint.textSize
height.toFloat(), typeface = textPaint.typeface
intArrayOf(effectColor, Color.WHITE, Color.WHITE), shader = shadowShader
null, }
Shader.TileMode.CLAMP,
)
textPaint.shader = shader
staticLayout.draw(canvas)
textPaint.shader = null
}
Effect.NONE -> { canvas.drawText(
staticLayout.draw(canvas) text,
} x + 4f, // Shadow offset
y + 4f,
shadowPaint,
)
val shader =
LinearGradient(
0f,
0f,
width.toFloat(),
height.toFloat(),
intArrayOf(effectColor, Color.WHITE, Color.WHITE),
null,
Shader.TileMode.CLAMP,
)
textPaint.shader = shader
staticLayout.draw(canvas)
textPaint.shader = null
}
Effect.NONE -> {
staticLayout.draw(canvas)
} }
} }
}
fun applyOutline( fun applyOutline(
color: Int, color: Int,
outlineThickness: Float, outlineThickness: Float,
) { ) {
this.effectColor = color this.effectColor = color
this.outlineThickness = outlineThickness this.outlineThickness = outlineThickness
currentEffect = Effect.OUTLINE currentEffect = Effect.OUTLINE
} }
// Too hard for me to figure it out // Too hard for me to figure it out
fun applyShineEffect(color: Int) { fun applyShineEffect(color: Int) {
this.effectColor = color this.effectColor = color
currentEffect = Effect.SHINE currentEffect = Effect.SHINE
} }
fun applyDropShadow( fun applyDropShadow(
color: Int, color: Int,
outlineThickness: Float, outlineThickness: Float,
) { ) {
this.effectColor = color this.effectColor = color
this.outlineThickness = outlineThickness this.outlineThickness = outlineThickness
currentEffect = Effect.DROP_SHADOW currentEffect = Effect.DROP_SHADOW
} }
} }

View file

@ -1,4 +1,3 @@
package ani.dantotsu.parsers package ani.dantotsu.parsers
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
@ -6,7 +5,6 @@ import ani.dantotsu.FileUrl
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.currContext import ani.dantotsu.currContext
import ani.dantotsu.media.Media import ani.dantotsu.media.Media
import ani.dantotsu.okHttpClient
import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.util.Logger import ani.dantotsu.util.Logger
import eu.kanade.tachiyomi.animesource.model.SAnime import eu.kanade.tachiyomi.animesource.model.SAnime

View file

@ -168,7 +168,7 @@ class ExtensionTestItem(
return return
} }
val serverResultStart = System.currentTimeMillis() val serverResultStart = System.currentTimeMillis()
val serverResult = extension.loadImages("", chapterResult.first().sChapter) val serverResult = extension.loadImages("", chapterResult.first().sChapter)
serverResultData.time = (System.currentTimeMillis() - serverResultStart).toInt() serverResultData.time = (System.currentTimeMillis() - serverResultStart).toInt()
serverResultData.size = serverResult.size serverResultData.size = serverResult.size
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
@ -266,8 +266,10 @@ class ExtensionTestItem(
) )
binding.searchResultText.isVisible = true binding.searchResultText.isVisible = true
if (searchResultData.size == 0) { if (searchResultData.size == 0) {
val text = context.getString(R.string.title_search_test, val text = context.getString(
context.getString(R.string.no_results_found)) R.string.title_search_test,
context.getString(R.string.no_results_found)
)
binding.searchResultText.text = text binding.searchResultText.text = text
binding.searchResultText.setCompoundDrawablesWithIntrinsicBounds( binding.searchResultText.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_circle_cancel, 0, 0, 0 R.drawable.ic_circle_cancel, 0, 0, 0
@ -277,8 +279,10 @@ class ExtensionTestItem(
) )
return return
} }
val text = context.getString(R.string.title_search_test, val text = context.getString(
context.getString(R.string.results_found, searchResultData.size.toString())) R.string.title_search_test,
context.getString(R.string.results_found, searchResultData.size.toString())
)
binding.searchResultText.text = text + "\n${searchResultData.time}ms" binding.searchResultText.text = text + "\n${searchResultData.time}ms"
binding.searchResultText.setCompoundDrawablesWithIntrinsicBounds( binding.searchResultText.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_circle_check, 0, 0, 0 R.drawable.ic_circle_check, 0, 0, 0
@ -297,13 +301,21 @@ class ExtensionTestItem(
) )
binding.episodeResultText.isVisible = true binding.episodeResultText.isVisible = true
if (episodeResultData.size == 0) { if (episodeResultData.size == 0) {
val text = when(extensionType) { val text = when (extensionType) {
"anime" -> context.getString(R.string.episode_search_test, "anime" -> context.getString(
context.getString(R.string.no_results_found)) R.string.episode_search_test,
"manga" -> context.getString(R.string.chapter_search_test, context.getString(R.string.no_results_found)
context.getString(R.string.no_results_found)) )
else -> context.getString(R.string.book_search_test,
context.getString(R.string.no_results_found)) "manga" -> context.getString(
R.string.chapter_search_test,
context.getString(R.string.no_results_found)
)
else -> context.getString(
R.string.book_search_test,
context.getString(R.string.no_results_found)
)
} }
binding.episodeResultText.text = text binding.episodeResultText.text = text
binding.episodeResultText.setCompoundDrawablesWithIntrinsicBounds( binding.episodeResultText.setCompoundDrawablesWithIntrinsicBounds(
@ -314,13 +326,21 @@ class ExtensionTestItem(
) )
return return
} }
val text = when(extensionType) { val text = when (extensionType) {
"anime" -> context.getString(R.string.episode_search_test, "anime" -> context.getString(
context.getString(R.string.results_found, episodeResultData.size.toString())) R.string.episode_search_test,
"manga" -> context.getString(R.string.chapter_search_test, context.getString(R.string.results_found, episodeResultData.size.toString())
context.getString(R.string.results_found, episodeResultData.size.toString())) )
else -> context.getString(R.string.book_search_test,
context.getString(R.string.results_found, episodeResultData.size.toString())) "manga" -> context.getString(
R.string.chapter_search_test,
context.getString(R.string.results_found, episodeResultData.size.toString())
)
else -> context.getString(
R.string.book_search_test,
context.getString(R.string.results_found, episodeResultData.size.toString())
)
} }
binding.episodeResultText.text = text + "\n${episodeResultData.time}ms" binding.episodeResultText.text = text + "\n${episodeResultData.time}ms"
binding.episodeResultText.setCompoundDrawablesWithIntrinsicBounds( binding.episodeResultText.setCompoundDrawablesWithIntrinsicBounds(
@ -348,13 +368,21 @@ class ExtensionTestItem(
) )
binding.serverResultText.isVisible = true binding.serverResultText.isVisible = true
if (serverResultData.size == 0) { if (serverResultData.size == 0) {
val text = when(extensionType) { val text = when (extensionType) {
"anime" -> context.getString(R.string.video_search_test, "anime" -> context.getString(
context.getString(R.string.no_results_found)) R.string.video_search_test,
"manga" -> context.getString(R.string.image_search_test, context.getString(R.string.no_results_found)
context.getString(R.string.no_results_found)) )
else -> context.getString(R.string.book_search_test,
context.getString(R.string.no_results_found)) "manga" -> context.getString(
R.string.image_search_test,
context.getString(R.string.no_results_found)
)
else -> context.getString(
R.string.book_search_test,
context.getString(R.string.no_results_found)
)
} }
binding.serverResultText.text = text + "\n${serverResultData.time}ms" binding.serverResultText.text = text + "\n${serverResultData.time}ms"
binding.serverResultText.setCompoundDrawablesWithIntrinsicBounds( binding.serverResultText.setCompoundDrawablesWithIntrinsicBounds(
@ -365,13 +393,21 @@ class ExtensionTestItem(
) )
return return
} }
val text = when(extensionType) { val text = when (extensionType) {
"anime" -> context.getString(R.string.video_search_test, "anime" -> context.getString(
context.getString(R.string.results_found, serverResultData.size.toString())) R.string.video_search_test,
"manga" -> context.getString(R.string.image_search_test, context.getString(R.string.results_found, serverResultData.size.toString())
context.getString(R.string.results_found, serverResultData.size.toString())) )
else -> context.getString(R.string.book_search_test,
context.getString(R.string.results_found, serverResultData.size.toString())) "manga" -> context.getString(
R.string.image_search_test,
context.getString(R.string.results_found, serverResultData.size.toString())
)
else -> context.getString(
R.string.book_search_test,
context.getString(R.string.results_found, serverResultData.size.toString())
)
} }
binding.serverResultText.text = text binding.serverResultText.text = text
binding.serverResultText.setCompoundDrawablesWithIntrinsicBounds( binding.serverResultText.setCompoundDrawablesWithIntrinsicBounds(

View file

@ -110,7 +110,7 @@ class ExtensionTestSettingsBottomDialog : BottomSheetDialogFragment() {
} }
private fun setupAdapter() { private fun setupAdapter() {
val namesAndUrls: Map<String,Drawable?> = when (extensionType) { val namesAndUrls: Map<String, Drawable?> = when (extensionType) {
"anime" -> animeExtension.installedExtensionsFlow.value.associate { it.name to it.icon } "anime" -> animeExtension.installedExtensionsFlow.value.associate { it.name to it.icon }
"manga" -> mangaExtensions.installedExtensionsFlow.value.associate { it.name to it.icon } "manga" -> mangaExtensions.installedExtensionsFlow.value.associate { it.name to it.icon }
"novel" -> novelExtensions.installedExtensionsFlow.value.associate { it.name to it.icon } "novel" -> novelExtensions.installedExtensionsFlow.value.associate { it.name to it.icon }

View file

@ -33,7 +33,7 @@ class OfflineMangaParser : MangaParser() {
directory.listFiles().forEach { directory.listFiles().forEach {
val scanlator = downloadManager.mangaDownloadedTypes.find { items -> val scanlator = downloadManager.mangaDownloadedTypes.find { items ->
items.titleName == mangaLink && items.titleName == mangaLink &&
items.chapterName == it.name items.chapterName == it.name
}?.scanlator ?: "Unknown" }?.scanlator ?: "Unknown"
if (it.isDirectory) { if (it.isDirectory) {
val chapter = MangaChapter( val chapter = MangaChapter(

View file

@ -73,6 +73,7 @@ class ParserTestActivity : AppCompatActivity() {
} }
} }
} }
"manga" -> { "manga" -> {
ExtensionTestSettingsBottomDialog.extensionsToTest.forEach { name -> ExtensionTestSettingsBottomDialog.extensionsToTest.forEach { name ->
val extension = val extension =
@ -89,6 +90,7 @@ class ParserTestActivity : AppCompatActivity() {
} }
} }
} }
"novel" -> { "novel" -> {
ExtensionTestSettingsBottomDialog.extensionsToTest.forEach { name -> ExtensionTestSettingsBottomDialog.extensionsToTest.forEach { name ->
val extension = val extension =

View file

@ -120,8 +120,10 @@ class NovelExtensionManager(private val context: Context) {
* @param extension The anime extension to be installed. * @param extension The anime extension to be installed.
*/ */
fun installExtension(extension: NovelExtension.Available): Observable<InstallStep> { fun installExtension(extension: NovelExtension.Available): Observable<InstallStep> {
return installer.downloadAndInstall(api.getNovelApkUrl(extension), extension.pkgName, return installer.downloadAndInstall(
extension.name, MediaType.NOVEL) api.getNovelApkUrl(extension), extension.pkgName,
extension.name, MediaType.NOVEL
)
} }
/** /**

View file

@ -53,7 +53,8 @@ class ChartBuilder {
scrollPos: Float? = null, scrollPos: Float? = null,
normalize: Boolean = false normalize: Boolean = false
): AAOptions { ): AAOptions {
val primaryColor = context.getThemeColor(com.google.android.material.R.attr.colorPrimary) val primaryColor =
context.getThemeColor(com.google.android.material.R.attr.colorPrimary)
var chartType = passedChartType var chartType = passedChartType
var aaChartType = passedAaChartType var aaChartType = passedAaChartType
var categories = passedCategories var categories = passedCategories
@ -303,7 +304,8 @@ class ChartBuilder {
} }
private fun setColors(aaOptions: AAOptions, context: Context) { private fun setColors(aaOptions: AAOptions, context: Context) {
val backgroundColor = context.getThemeColor(com.google.android.material.R.attr.colorSurfaceVariant) val backgroundColor =
context.getThemeColor(com.google.android.material.R.attr.colorSurfaceVariant)
val backgroundStyle = AAStyle().color( val backgroundStyle = AAStyle().color(
AAColor.rgbaColor( AAColor.rgbaColor(
Color.red(backgroundColor), Color.red(backgroundColor),
@ -312,7 +314,8 @@ class ChartBuilder {
1f 1f
) )
) )
val colorOnBackground = context.getThemeColor(com.google.android.material.R.attr.colorOnSurface) val colorOnBackground =
context.getThemeColor(com.google.android.material.R.attr.colorOnSurface)
val onBackgroundStyle = AAStyle().color( val onBackgroundStyle = AAStyle().color(
AAColor.rgbaColor( AAColor.rgbaColor(
Color.red(colorOnBackground), Color.red(colorOnBackground),

View file

@ -36,10 +36,10 @@ class FollowerItem(
} }
override fun getLayout(): Int { override fun getLayout(): Int {
return if(grid) R.layout.item_follower_grid else R.layout.item_follower return if (grid) R.layout.item_follower_grid else R.layout.item_follower
} }
override fun initializeViewBinding(view: View): ViewBinding { override fun initializeViewBinding(view: View): ViewBinding {
return if(grid) ItemFollowerGridBinding.bind(view) else ItemFollowerBinding.bind(view) return if (grid) ItemFollowerGridBinding.bind(view) else ItemFollowerBinding.bind(view)
} }
} }

View file

@ -156,17 +156,28 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
openLinkInBrowser(getString(R.string.anilist_link, user.name)) openLinkInBrowser(getString(R.string.anilist_link, user.name))
true true
} }
R.id.action_share_profile -> { R.id.action_share_profile -> {
val shareIntent = Intent(Intent.ACTION_SEND) val shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.type = "text/plain" shareIntent.type = "text/plain"
shareIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.anilist_link, user.name)) shareIntent.putExtra(
startActivity(Intent.createChooser(shareIntent, "Share Profile")) Intent.EXTRA_TEXT,
getString(R.string.anilist_link, user.name)
)
startActivity(
Intent.createChooser(
shareIntent,
"Share Profile"
)
)
true true
} }
R.id.action_copy_user_id -> { R.id.action_copy_user_id -> {
copyToClipboard(user.id.toString(), true) copyToClipboard(user.id.toString(), true)
true true
} }
else -> false else -> false
} }
} }

View file

@ -35,11 +35,11 @@ class UsersAdapter(private val user: MutableList<User>, private val grid: Boolea
parent, parent,
false false
) else ) else
ItemFollowerBinding.inflate( ItemFollowerBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
false false
) )
) )
} }

View file

@ -16,8 +16,8 @@ import ani.dantotsu.profile.User
import ani.dantotsu.profile.UsersDialogFragment import ani.dantotsu.profile.UsersDialogFragment
import ani.dantotsu.setAnimation import ani.dantotsu.setAnimation
import ani.dantotsu.snackString import ani.dantotsu.snackString
import ani.dantotsu.util.AniMarkdown.Companion.getBasicAniHTML
import ani.dantotsu.util.ActivityMarkdownCreator import ani.dantotsu.util.ActivityMarkdownCreator
import ani.dantotsu.util.AniMarkdown.Companion.getBasicAniHTML
import com.xwray.groupie.GroupieAdapter import com.xwray.groupie.GroupieAdapter
import com.xwray.groupie.viewbinding.BindableItem import com.xwray.groupie.viewbinding.BindableItem
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -52,14 +52,19 @@ class ActivityItem(
} }
binding.activityRepliesContainer.setOnClickListener { binding.activityRepliesContainer.setOnClickListener {
RepliesBottomDialog.newInstance(activity.id) RepliesBottomDialog.newInstance(activity.id)
.show((context as FragmentActivity).supportFragmentManager, "replies") .show((context as FragmentActivity).supportFragmentManager, "replies")
} }
binding.replyCount.text = activity.replyCount.toString() binding.replyCount.text = activity.replyCount.toString()
binding.activityReplies.setColorFilter(ContextCompat.getColor(binding.root.context, R.color.bg_opp)) binding.activityReplies.setColorFilter(
ContextCompat.getColor(
binding.root.context,
R.color.bg_opp
)
)
binding.activityLikeContainer.setOnLongClickListener { binding.activityLikeContainer.setOnLongClickListener {
UsersDialogFragment().apply { UsersDialogFragment().apply {
userList(userList) userList(userList)
show((context as FragmentActivity).supportFragmentManager, "dialog") show((context as FragmentActivity).supportFragmentManager, "dialog")
} }
true true
} }
@ -84,7 +89,8 @@ class ActivityItem(
} }
} }
} }
binding.activityDelete.isVisible = activity.userId == Anilist.userid || activity.messenger?.id == Anilist.userid binding.activityDelete.isVisible =
activity.userId == Anilist.userid || activity.messenger?.id == Anilist.userid
binding.activityDelete.setOnClickListener { binding.activityDelete.setOnClickListener {
scope.launch { scope.launch {
val res = Anilist.mutation.deleteActivity(activity.id) val res = Anilist.mutation.deleteActivity(activity.id)
@ -161,7 +167,8 @@ class ActivityItem(
"MessageActivity" -> { "MessageActivity" -> {
binding.activityBannerContainer.visibility = View.GONE binding.activityBannerContainer.visibility = View.GONE
binding.activityContent.visibility = View.VISIBLE binding.activityContent.visibility = View.VISIBLE
binding.activityPrivate.visibility = if (activity.isPrivate == true) View.VISIBLE else View.GONE binding.activityPrivate.visibility =
if (activity.isPrivate == true) View.VISIBLE else View.GONE
if (!(context as android.app.Activity).isDestroyed) { if (!(context as android.app.Activity).isDestroyed) {
val markwon = buildMarkwon(context, false) val markwon = buildMarkwon(context, false)
markwon.setMarkdown( markwon.setMarkdown(

View file

@ -14,8 +14,8 @@ import ani.dantotsu.loadImage
import ani.dantotsu.profile.User import ani.dantotsu.profile.User
import ani.dantotsu.profile.UsersDialogFragment import ani.dantotsu.profile.UsersDialogFragment
import ani.dantotsu.snackString import ani.dantotsu.snackString
import ani.dantotsu.util.AniMarkdown.Companion.getBasicAniHTML
import ani.dantotsu.util.ActivityMarkdownCreator import ani.dantotsu.util.ActivityMarkdownCreator
import ani.dantotsu.util.AniMarkdown.Companion.getBasicAniHTML
import com.xwray.groupie.GroupieAdapter import com.xwray.groupie.GroupieAdapter
import com.xwray.groupie.viewbinding.BindableItem import com.xwray.groupie.viewbinding.BindableItem
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -26,7 +26,7 @@ import kotlinx.coroutines.withContext
class ActivityReplyItem( class ActivityReplyItem(
private val reply: ActivityReply, private val reply: ActivityReply,
private val parentId : Int, private val parentId: Int,
private val fragActivity: FragmentActivity, private val fragActivity: FragmentActivity,
private val parentAdapter: GroupieAdapter, private val parentAdapter: GroupieAdapter,
private val clickCallback: (Int, type: String) -> Unit, private val clickCallback: (Int, type: String) -> Unit,
@ -46,7 +46,7 @@ class ActivityReplyItem(
binding.activityLike.setColorFilter(if (reply.isLiked) likeColor else notLikeColor) binding.activityLike.setColorFilter(if (reply.isLiked) likeColor else notLikeColor)
val markwon = buildMarkwon(context) val markwon = buildMarkwon(context)
markwon.setMarkdown(binding.activityContent, getBasicAniHTML(reply.text)) markwon.setMarkdown(binding.activityContent, getBasicAniHTML(reply.text))
val userList = arrayListOf<User>() val userList = arrayListOf<User>()
reply.likes?.forEach { i -> reply.likes?.forEach { i ->
userList.add(User(i.id, i.name.toString(), i.avatar?.medium, i.bannerImage)) userList.add(User(i.id, i.name.toString(), i.avatar?.medium, i.bannerImage))

View file

@ -1,26 +1,21 @@
package ani.dantotsu.profile.activity package ani.dantotsu.profile.activity
import android.content.res.Configuration
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.core.view.updateMargins
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.databinding.ActivityFeedBinding
import ani.dantotsu.databinding.ActivityNotificationBinding import ani.dantotsu.databinding.ActivityNotificationBinding
import ani.dantotsu.initActivity import ani.dantotsu.initActivity
import ani.dantotsu.navBarHeight import ani.dantotsu.navBarHeight
import ani.dantotsu.profile.activity.ActivityFragment.Companion.ActivityType
import ani.dantotsu.statusBarHeight import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.profile.activity.ActivityFragment.Companion.ActivityType
import ani.dantotsu.profile.notification.NotificationActivity
import nl.joery.animatedbottombar.AnimatedBottomBar import nl.joery.animatedbottombar.AnimatedBottomBar
class FeedActivity : AppCompatActivity() { class FeedActivity : AppCompatActivity() {
@ -50,9 +45,12 @@ class FeedActivity : AppCompatActivity() {
binding.notificationBack.setOnClickListener { onBackPressedDispatcher.onBackPressed() } binding.notificationBack.setOnClickListener { onBackPressedDispatcher.onBackPressed() }
val getOne = intent.getIntExtra("activityId", -1) val getOne = intent.getIntExtra("activityId", -1)
if (getOne != -1) { navBar.visibility = View.GONE } if (getOne != -1) {
navBar.visibility = View.GONE
}
binding.notificationViewPager.isUserInputEnabled = false binding.notificationViewPager.isUserInputEnabled = false
binding.notificationViewPager.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle, getOne) binding.notificationViewPager.adapter =
ViewPagerAdapter(supportFragmentManager, lifecycle, getOne)
binding.notificationViewPager.setOffscreenPageLimit(4) binding.notificationViewPager.setOffscreenPageLimit(4)
binding.notificationViewPager.setCurrentItem(selected, false) binding.notificationViewPager.setCurrentItem(selected, false)
navBar.selectTabAt(selected) navBar.selectTabAt(selected)
@ -83,7 +81,11 @@ class FeedActivity : AppCompatActivity() {
override fun createFragment(position: Int): Fragment { override fun createFragment(position: Int): Fragment {
return when (position) { return when (position) {
0 -> ActivityFragment.newInstance(if (activityId != -1) ActivityType.ONE else ActivityType.USER, activityId = activityId) 0 -> ActivityFragment.newInstance(
if (activityId != -1) ActivityType.ONE else ActivityType.USER,
activityId = activityId
)
else -> ActivityFragment.newInstance(ActivityType.GLOBAL) else -> ActivityFragment.newInstance(ActivityType.GLOBAL)
} }
} }

View file

@ -9,17 +9,20 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.databinding.ActivityNotificationBinding import ani.dantotsu.databinding.ActivityNotificationBinding
import ani.dantotsu.initActivity import ani.dantotsu.initActivity
import ani.dantotsu.navBarHeight import ani.dantotsu.navBarHeight
import ani.dantotsu.profile.notification.NotificationFragment.Companion.NotificationType.COMMENT
import ani.dantotsu.profile.notification.NotificationFragment.Companion.NotificationType.MEDIA
import ani.dantotsu.profile.notification.NotificationFragment.Companion.NotificationType.ONE
import ani.dantotsu.profile.notification.NotificationFragment.Companion.NotificationType.SUBSCRIPTION
import ani.dantotsu.profile.notification.NotificationFragment.Companion.NotificationType.USER
import ani.dantotsu.profile.notification.NotificationFragment.Companion.newInstance
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.statusBarHeight import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.profile.notification.NotificationFragment.Companion.NotificationType.*
import ani.dantotsu.profile.notification.NotificationFragment.Companion.newInstance
import nl.joery.animatedbottombar.AnimatedBottomBar import nl.joery.animatedbottombar.AnimatedBottomBar
class NotificationActivity : AppCompatActivity() { class NotificationActivity : AppCompatActivity() {
@ -58,7 +61,8 @@ class NotificationActivity : AppCompatActivity() {
val getOne = intent.getIntExtra("activityId", -1) val getOne = intent.getIntExtra("activityId", -1)
if (getOne != -1) navBar.isVisible = false if (getOne != -1) navBar.isVisible = false
binding.notificationViewPager.isUserInputEnabled = false binding.notificationViewPager.isUserInputEnabled = false
binding.notificationViewPager.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle, getOne, CommentsEnabled) binding.notificationViewPager.adapter =
ViewPagerAdapter(supportFragmentManager, lifecycle, getOne, CommentsEnabled)
binding.notificationViewPager.setCurrentItem(selected, false) binding.notificationViewPager.setCurrentItem(selected, false)
navBar.selectTabAt(selected) navBar.selectTabAt(selected)
navBar.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener { navBar.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener {

View file

@ -60,7 +60,8 @@ class NotificationItem(
PrefName.SubscriptionNotificationStore, PrefName.SubscriptionNotificationStore,
null null
) ?: listOf() ) ?: listOf()
val newList = list.filter { (it.time / 1000L).toInt() != notification.createdAt} val newList =
list.filter { (it.time / 1000L).toInt() != notification.createdAt }
PrefManager.setVal(PrefName.SubscriptionNotificationStore, newList) PrefManager.setVal(PrefName.SubscriptionNotificationStore, newList)
parentAdapter.remove(this@NotificationItem) parentAdapter.remove(this@NotificationItem)
} }

View file

@ -33,7 +33,7 @@ class RepoItem(
val url: String, val url: String,
private val mediaType: MediaType, private val mediaType: MediaType,
val onRemove: (String, MediaType) -> Unit val onRemove: (String, MediaType) -> Unit
) :BindableItem<ItemRepoBinding>() { ) : BindableItem<ItemRepoBinding>() {
override fun getLayout() = R.layout.item_repo override fun getLayout() = R.layout.item_repo
override fun bind(viewBinding: ItemRepoBinding, position: Int) { override fun bind(viewBinding: ItemRepoBinding, position: Int) {
@ -88,7 +88,7 @@ class AddRepositoryBottomSheet : BottomSheetDialogFragment() {
) )
adapter.addAll(repositories.map { RepoItem(it, mediaType, ::onRepositoryRemoved) }) adapter.addAll(repositories.map { RepoItem(it, mediaType, ::onRepositoryRemoved) })
binding.repositoryInput.hint = when(mediaType) { binding.repositoryInput.hint = when (mediaType) {
MediaType.ANIME -> getString(R.string.anime_add_repository) MediaType.ANIME -> getString(R.string.anime_add_repository)
MediaType.MANGA -> getString(R.string.manga_add_repository) MediaType.MANGA -> getString(R.string.manga_add_repository)
MediaType.NOVEL -> getString(R.string.novel_add_repository) MediaType.NOVEL -> getString(R.string.novel_add_repository)
@ -110,7 +110,8 @@ class AddRepositoryBottomSheet : BottomSheetDialogFragment() {
binding.repositoryInput.setOnEditorActionListener { textView, action, keyEvent -> binding.repositoryInput.setOnEditorActionListener { textView, action, keyEvent ->
if (action == EditorInfo.IME_ACTION_DONE || if (action == EditorInfo.IME_ACTION_DONE ||
(keyEvent?.action == KeyEvent.ACTION_UP && keyEvent.keyCode == KeyEvent.KEYCODE_ENTER)) { (keyEvent?.action == KeyEvent.ACTION_UP && keyEvent.keyCode == KeyEvent.KEYCODE_ENTER)
) {
val url = textView.text.toString() val url = textView.text.toString()
if (url.isNotBlank()) { if (url.isNotBlank()) {
val error = isValidUrl(url) val error = isValidUrl(url)
@ -215,6 +216,7 @@ class AddRepositoryBottomSheet : BottomSheetDialogFragment() {
Injekt.get<AnimeExtensionManager>().findAvailableExtensions() Injekt.get<AnimeExtensionManager>().findAvailableExtensions()
} }
} }
MediaType.MANGA -> { MediaType.MANGA -> {
val manga = val manga =
PrefManager.getVal<Set<String>>(PrefName.MangaExtensionRepos) PrefManager.getVal<Set<String>>(PrefName.MangaExtensionRepos)
@ -224,6 +226,7 @@ class AddRepositoryBottomSheet : BottomSheetDialogFragment() {
Injekt.get<MangaExtensionManager>().findAvailableExtensions() Injekt.get<MangaExtensionManager>().findAvailableExtensions()
} }
} }
MediaType.NOVEL -> { MediaType.NOVEL -> {
val novel = val novel =
PrefManager.getVal<Set<String>>(PrefName.NovelExtensionRepos) PrefManager.getVal<Set<String>>(PrefName.NovelExtensionRepos)
@ -247,6 +250,7 @@ class AddRepositoryBottomSheet : BottomSheetDialogFragment() {
Injekt.get<AnimeExtensionManager>().findAvailableExtensions() Injekt.get<AnimeExtensionManager>().findAvailableExtensions()
} }
} }
MediaType.MANGA -> { MediaType.MANGA -> {
val manga = val manga =
PrefManager.getVal<Set<String>>(PrefName.MangaExtensionRepos) PrefManager.getVal<Set<String>>(PrefName.MangaExtensionRepos)
@ -256,6 +260,7 @@ class AddRepositoryBottomSheet : BottomSheetDialogFragment() {
Injekt.get<MangaExtensionManager>().findAvailableExtensions() Injekt.get<MangaExtensionManager>().findAvailableExtensions()
} }
} }
MediaType.NOVEL -> { MediaType.NOVEL -> {
val novel = val novel =
PrefManager.getVal<Set<String>>(PrefName.NovelExtensionRepos) PrefManager.getVal<Set<String>>(PrefName.NovelExtensionRepos)

View file

@ -56,7 +56,8 @@ class AnilistSettingsActivity : AppCompatActivity() {
} }
val currentTitleLang = Anilist.titleLanguage val currentTitleLang = Anilist.titleLanguage
val titleFormat = UserTitleLanguage.entries.firstOrNull { it.name == currentTitleLang } ?: UserTitleLanguage.ENGLISH val titleFormat = UserTitleLanguage.entries.firstOrNull { it.name == currentTitleLang }
?: UserTitleLanguage.ENGLISH
settingsAnilistTitleLanguage.setText(titleLang[titleFormat.ordinal]) settingsAnilistTitleLanguage.setText(titleLang[titleFormat.ordinal])
settingsAnilistTitleLanguage.setAdapter( settingsAnilistTitleLanguage.setAdapter(
@ -78,7 +79,9 @@ class AnilistSettingsActivity : AppCompatActivity() {
} }
val currentStaffNameLang = Anilist.staffNameLanguage val currentStaffNameLang = Anilist.staffNameLanguage
val staffNameFormat = UserStaffNameLanguage.entries.firstOrNull { it.name == currentStaffNameLang } ?: UserStaffNameLanguage.ROMAJI_WESTERN val staffNameFormat =
UserStaffNameLanguage.entries.firstOrNull { it.name == currentStaffNameLang }
?: UserStaffNameLanguage.ROMAJI_WESTERN
settingsAnilistStaffLanguage.setText(staffNameLang[staffNameFormat.ordinal]) settingsAnilistStaffLanguage.setText(staffNameLang[staffNameFormat.ordinal])
settingsAnilistStaffLanguage.setAdapter( settingsAnilistStaffLanguage.setAdapter(
@ -99,8 +102,9 @@ class AnilistSettingsActivity : AppCompatActivity() {
settingsAnilistStaffLanguage.clearFocus() settingsAnilistStaffLanguage.clearFocus()
} }
val currentMergeTimeDisplay = activityMergeTimeMap.entries.firstOrNull { it.value == Anilist.activityMergeTime }?.key val currentMergeTimeDisplay =
?: "${Anilist.activityMergeTime} mins" activityMergeTimeMap.entries.firstOrNull { it.value == Anilist.activityMergeTime }?.key
?: "${Anilist.activityMergeTime} mins"
settingsAnilistActivityMergeTime.setText(currentMergeTimeDisplay) settingsAnilistActivityMergeTime.setText(currentMergeTimeDisplay)
settingsAnilistActivityMergeTime.setAdapter( settingsAnilistActivityMergeTime.setAdapter(
ArrayAdapter(context, R.layout.item_dropdown, activityMergeTimeMap.keys.toList()) ArrayAdapter(context, R.layout.item_dropdown, activityMergeTimeMap.keys.toList())
@ -117,7 +121,8 @@ class AnilistSettingsActivity : AppCompatActivity() {
} }
val currentScoreFormat = Anilist.scoreFormat val currentScoreFormat = Anilist.scoreFormat
val scoreFormat = ScoreFormat.entries.firstOrNull{ it.name == currentScoreFormat } ?: ScoreFormat.POINT_100 val scoreFormat = ScoreFormat.entries.firstOrNull { it.name == currentScoreFormat }
?: ScoreFormat.POINT_100
settingsAnilistScoreFormat.setText(scoreFormats[scoreFormat.ordinal]) settingsAnilistScoreFormat.setText(scoreFormats[scoreFormat.ordinal])
settingsAnilistScoreFormat.setAdapter( settingsAnilistScoreFormat.setAdapter(
ArrayAdapter(context, R.layout.item_dropdown, scoreFormats) ArrayAdapter(context, R.layout.item_dropdown, scoreFormats)
@ -139,7 +144,8 @@ class AnilistSettingsActivity : AppCompatActivity() {
settingsAnilistScoreFormat.clearFocus() settingsAnilistScoreFormat.clearFocus()
} }
val currentRowOrder = rowOrderMap.entries.firstOrNull { it.value == Anilist.rowOrder }?.key ?: "Score" val currentRowOrder =
rowOrderMap.entries.firstOrNull { it.value == Anilist.rowOrder }?.key ?: "Score"
settingsAnilistRowOrder.setText(currentRowOrder) settingsAnilistRowOrder.setText(currentRowOrder)
settingsAnilistRowOrder.setAdapter( settingsAnilistRowOrder.setAdapter(
ArrayAdapter(context, R.layout.item_dropdown, rowOrderMap.keys.toList()) ArrayAdapter(context, R.layout.item_dropdown, rowOrderMap.keys.toList())
@ -155,7 +161,8 @@ class AnilistSettingsActivity : AppCompatActivity() {
settingsAnilistRowOrder.clearFocus() settingsAnilistRowOrder.clearFocus()
} }
val containers = listOf(binding.animeCustomListsContainer, binding.mangaCustomListsContainer) val containers =
listOf(binding.animeCustomListsContainer, binding.mangaCustomListsContainer)
val customLists = listOf(Anilist.animeCustomLists, Anilist.mangaCustomLists) val customLists = listOf(Anilist.animeCustomLists, Anilist.mangaCustomLists)
val buttons = listOf(binding.addAnimeListButton, binding.addMangaListButton) val buttons = listOf(binding.addAnimeListButton, binding.addMangaListButton)
@ -175,7 +182,8 @@ class AnilistSettingsActivity : AppCompatActivity() {
saveCustomLists() saveCustomLists()
} }
val currentTimezone = Anilist.timezone?.let { Anilist.getDisplayTimezone(it, context) } ?: context.getString(R.string.selected_no_time_zone) val currentTimezone = Anilist.timezone?.let { Anilist.getDisplayTimezone(it, context) }
?: context.getString(R.string.selected_no_time_zone)
settingsAnilistTimezone.setText(currentTimezone) settingsAnilistTimezone.setText(currentTimezone)
settingsAnilistTimezone.setAdapter( settingsAnilistTimezone.setAdapter(
ArrayAdapter(context, R.layout.item_dropdown, Anilist.timeZone) ArrayAdapter(context, R.layout.item_dropdown, Anilist.timeZone)

View file

@ -169,8 +169,12 @@ class ExtensionsActivity : AppCompatActivity() {
customAlertDialog().apply { customAlertDialog().apply {
setTitle("Language") setTitle("Language")
singleChoiceItems(languageOptions, index) { selected -> singleChoiceItems(languageOptions, index) { selected ->
PrefManager.setVal(PrefName.LangSort, LanguageMapper.Companion.Language.entries[selected].code) PrefManager.setVal(
val currentFragment = supportFragmentManager.findFragmentByTag("f${viewPager.currentItem}") PrefName.LangSort,
LanguageMapper.Companion.Language.entries[selected].code
)
val currentFragment =
supportFragmentManager.findFragmentByTag("f${viewPager.currentItem}")
if (currentFragment is SearchQueryHandler) { if (currentFragment is SearchQueryHandler) {
currentFragment.notifyDataChanged() currentFragment.notifyDataChanged()
} }

View file

@ -70,7 +70,7 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
if (allSettings.isNotEmpty()) { if (allSettings.isNotEmpty()) {
var selectedSetting = allSettings[0] var selectedSetting = allSettings[0]
if (allSettings.size > 1) { if (allSettings.size > 1) {
val names = allSettings.map { LanguageMapper.getLanguageName(it.lang) } val names = allSettings.map { getLanguageName(it.lang) }
.toTypedArray() .toTypedArray()
var selectedIndex = 0 var selectedIndex = 0
requireContext().customAlertDialog().apply { requireContext().customAlertDialog().apply {

View file

@ -290,7 +290,8 @@ class PlayerSettingsActivity :
PrefManager.setVal(PrefName.UseInternalCast, isChecked) PrefManager.setVal(PrefName.UseInternalCast, isChecked)
} }
binding.playerSettingsAdditionalCodec.isChecked = PrefManager.getVal(PrefName.UseAdditionalCodec) binding.playerSettingsAdditionalCodec.isChecked =
PrefManager.getVal(PrefName.UseAdditionalCodec)
binding.playerSettingsAdditionalCodec.setOnCheckedChangeListener { _, isChecked -> binding.playerSettingsAdditionalCodec.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.UseAdditionalCodec, isChecked) PrefManager.setVal(PrefName.UseAdditionalCodec, isChecked)
} }

View file

@ -6,9 +6,9 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import ani.dantotsu.BottomSheetDialogFragment import ani.dantotsu.BottomSheetDialogFragment
import ani.dantotsu.databinding.BottomSheetProxyBinding import ani.dantotsu.databinding.BottomSheetProxyBinding
import ani.dantotsu.restartApp
import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.restartApp
class ProxyDialogFragment : BottomSheetDialogFragment() { class ProxyDialogFragment : BottomSheetDialogFragment() {
private var _binding: BottomSheetProxyBinding? = null private var _binding: BottomSheetProxyBinding? = null
@ -16,8 +16,10 @@ class ProxyDialogFragment : BottomSheetDialogFragment() {
private var proxyHost: String? = PrefManager.getVal<String>(PrefName.Socks5ProxyHost).orEmpty() private var proxyHost: String? = PrefManager.getVal<String>(PrefName.Socks5ProxyHost).orEmpty()
private var proxyPort: String? = PrefManager.getVal<String>(PrefName.Socks5ProxyPort).orEmpty() private var proxyPort: String? = PrefManager.getVal<String>(PrefName.Socks5ProxyPort).orEmpty()
private var proxyUsername: String? = PrefManager.getVal<String>(PrefName.Socks5ProxyUsername).orEmpty() private var proxyUsername: String? =
private var proxyPassword: String? = PrefManager.getVal<String>(PrefName.Socks5ProxyPassword).orEmpty() PrefManager.getVal<String>(PrefName.Socks5ProxyUsername).orEmpty()
private var proxyPassword: String? =
PrefManager.getVal<String>(PrefName.Socks5ProxyPassword).orEmpty()
private var authEnabled: Boolean = PrefManager.getVal<Boolean>(PrefName.ProxyAuthEnabled) private var authEnabled: Boolean = PrefManager.getVal<Boolean>(PrefName.ProxyAuthEnabled)
private val proxyEnabled: Boolean = PrefManager.getVal<Boolean>(PrefName.EnableSocks5Proxy) private val proxyEnabled: Boolean = PrefManager.getVal<Boolean>(PrefName.EnableSocks5Proxy)

View file

@ -142,8 +142,10 @@ class SettingsAboutActivity : AppCompatActivity() {
icon = R.drawable.ic_incognito_24, icon = R.drawable.ic_incognito_24,
onClick = { onClick = {
val text = TextView(context) val text = TextView(context)
val pPLink = "https://raw.githubusercontent.com/rebelonion/Dantotsu/main/privacy_policy.md" val pPLink =
val backup = "https://gcore.jsdelivr.net/gh/rebelonion/dantotsu/privacy_policy.md" "https://raw.githubusercontent.com/rebelonion/Dantotsu/main/privacy_policy.md"
val backup =
"https://gcore.jsdelivr.net/gh/rebelonion/dantotsu/privacy_policy.md"
text.text = getString(R.string.loading) text.text = getString(R.string.loading)
val markWon = try { val markWon = try {
buildMarkwon(this@SettingsAboutActivity, false) buildMarkwon(this@SettingsAboutActivity, false)
@ -177,7 +179,7 @@ class SettingsAboutActivity : AppCompatActivity() {
} }
), ),
) )
) )
binding.settingsRecyclerView.layoutManager = binding.settingsRecyclerView.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)

View file

@ -211,16 +211,16 @@ class SettingsAccountActivity : AppCompatActivity() {
binding.settingsRecyclerView.adapter = SettingsAdapter( binding.settingsRecyclerView.adapter = SettingsAdapter(
arrayListOf( arrayListOf(
Settings( Settings(
type = 2, type = 2,
name = getString(R.string.enable_rpc), name = getString(R.string.enable_rpc),
desc = getString(R.string.enable_rpc_desc), desc = getString(R.string.enable_rpc_desc),
icon = R.drawable.interests_24, icon = R.drawable.interests_24,
isChecked = PrefManager.getVal(PrefName.rpcEnabled), isChecked = PrefManager.getVal(PrefName.rpcEnabled),
switch = { isChecked, _ -> switch = { isChecked, _ ->
PrefManager.setVal(PrefName.rpcEnabled, isChecked) PrefManager.setVal(PrefName.rpcEnabled, isChecked)
}, },
isVisible = Discord.token != null isVisible = Discord.token != null
), ),
Settings( Settings(
type = 1, type = 1,
name = getString(R.string.anilist_settings), name = getString(R.string.anilist_settings),
@ -235,30 +235,31 @@ class SettingsAccountActivity : AppCompatActivity() {
isActivity = true isActivity = true
), ),
Settings( Settings(
type = 2, type = 2,
name = getString(R.string.comments_button), name = getString(R.string.comments_button),
desc = getString(R.string.comments_button_desc), desc = getString(R.string.comments_button_desc),
icon = R.drawable.ic_round_comment_24, icon = R.drawable.ic_round_comment_24,
isChecked = PrefManager.getVal<Int>(PrefName.CommentsEnabled) == 1, isChecked = PrefManager.getVal<Int>(PrefName.CommentsEnabled) == 1,
switch = { isChecked, _ -> switch = { isChecked, _ ->
PrefManager.setVal(PrefName.CommentsEnabled, if (isChecked) 1 else 2 ) PrefManager.setVal(PrefName.CommentsEnabled, if (isChecked) 1 else 2)
reload() reload()
}, },
isVisible = Anilist.token != null isVisible = Anilist.token != null
), ),
) )
) )
binding.settingsRecyclerView.layoutManager = binding.settingsRecyclerView.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
} }
fun reload() { fun reload() {
snackString(getString(R.string.restart_app_extra)) snackString(getString(R.string.restart_app_extra))
//snackString(R.string.restart_app_extra) //snackString(R.string.restart_app_extra)
//?.setDuration(Snackbar.LENGTH_LONG) //?.setDuration(Snackbar.LENGTH_LONG)
//?.setAction(R.string.do_it) { //?.setAction(R.string.do_it) {
//startMainActivity(this@SettingsAccountActivity) //startMainActivity(this@SettingsAccountActivity)
//} Disabled for now. Doesn't update the ADDRESS even after this //} Disabled for now. Doesn't update the ADDRESS even after this
} }
} }

View file

@ -11,8 +11,8 @@ import androidx.recyclerview.widget.LinearLayoutManager
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.addons.AddonDownloader import ani.dantotsu.addons.AddonDownloader
import ani.dantotsu.addons.download.DownloadAddonManager import ani.dantotsu.addons.download.DownloadAddonManager
import ani.dantotsu.addons.torrent.TorrentServerService
import ani.dantotsu.addons.torrent.TorrentAddonManager import ani.dantotsu.addons.torrent.TorrentAddonManager
import ani.dantotsu.addons.torrent.TorrentServerService
import ani.dantotsu.databinding.ActivitySettingsAddonsBinding import ani.dantotsu.databinding.ActivitySettingsAddonsBinding
import ani.dantotsu.databinding.ItemSettingsBinding import ani.dantotsu.databinding.ItemSettingsBinding
import ani.dantotsu.initActivity import ani.dantotsu.initActivity

View file

@ -8,8 +8,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.CheckBox
import android.widget.EditText
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.biometric.BiometricManager import androidx.biometric.BiometricManager
@ -231,7 +229,7 @@ class SettingsCommonActivity : AppCompatActivity() {
} }
} }
setNegButton(R.string.cancel) setNegButton(R.string.cancel)
setNeutralButton(R.string.remove){ setNeutralButton(R.string.remove) {
PrefManager.setVal(PrefName.AppPassword, "") PrefManager.setVal(PrefName.AppPassword, "")
PrefManager.setVal(PrefName.BiometricToken, "") PrefManager.setVal(PrefName.BiometricToken, "")
PrefManager.setVal(PrefName.OverridePassword, false) PrefManager.setVal(PrefName.OverridePassword, false)
@ -315,10 +313,10 @@ class SettingsCommonActivity : AppCompatActivity() {
desc = getString(R.string.change_download_location_desc), desc = getString(R.string.change_download_location_desc),
icon = R.drawable.ic_round_source_24, icon = R.drawable.ic_round_source_24,
onClick = { onClick = {
context.customAlertDialog().apply{ context.customAlertDialog().apply {
setTitle(R.string.change_download_location) setTitle(R.string.change_download_location)
setMessage(R.string.download_location_msg) setMessage(R.string.download_location_msg)
setPosButton(R.string.ok){ setPosButton(R.string.ok) {
val oldUri = PrefManager.getVal<String>(PrefName.DownloadsDir) val oldUri = PrefManager.getVal<String>(PrefName.DownloadsDir)
launcher.registerForCallback { success -> launcher.registerForCallback { success ->
if (success) { if (success) {

View file

@ -59,7 +59,8 @@ class SettingsDialogFragment : BottomSheetDialogFragment() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val window = dialog?.window val window = dialog?.window
window?.statusBarColor = Color.CYAN window?.statusBarColor = Color.CYAN
window?.navigationBarColor = requireContext().getThemeColor(com.google.android.material.R.attr.colorSurface) window?.navigationBarColor =
requireContext().getThemeColor(com.google.android.material.R.attr.colorSurface)
val notificationIcon = if (Anilist.unreadNotificationCount > 0) { val notificationIcon = if (Anilist.unreadNotificationCount > 0) {
R.drawable.ic_round_notifications_active_24 R.drawable.ic_round_notifications_active_24
} else { } else {
@ -70,7 +71,7 @@ class SettingsDialogFragment : BottomSheetDialogFragment() {
if (Anilist.token != null) { if (Anilist.token != null) {
binding.settingsLogin.setText(R.string.logout) binding.settingsLogin.setText(R.string.logout)
binding.settingsLogin.setOnClickListener { binding.settingsLogin.setOnClickListener {
requireContext().customAlertDialog().apply{ requireContext().customAlertDialog().apply {
setTitle(R.string.logout) setTitle(R.string.logout)
setMessage(R.string.logout_confirm) setMessage(R.string.logout_confirm)
setPosButton(R.string.yes) { setPosButton(R.string.yes) {

View file

@ -26,11 +26,8 @@ import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.util.customAlertDialog import ani.dantotsu.util.customAlertDialog
import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.base.BasePreferences
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
class SettingsExtensionsActivity : AppCompatActivity() { class SettingsExtensionsActivity : AppCompatActivity() {
private lateinit var binding: ActivitySettingsExtensionsBinding private lateinit var binding: ActivitySettingsExtensionsBinding

View file

@ -1,6 +1,5 @@
package ani.dantotsu.settings package ani.dantotsu.settings
import android.app.AlertDialog
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View

View file

@ -82,9 +82,18 @@ class SettingsNotificationActivity : AppCompatActivity() {
setTitle(R.string.subscriptions_checking_time) setTitle(R.string.subscriptions_checking_time)
singleChoiceItems(timeNames, curTime) { i -> singleChoiceItems(timeNames, curTime) { i ->
curTime = i curTime = i
it.settingsTitle.text = getString(R.string.subscriptions_checking_time_s, timeNames[i]) it.settingsTitle.text = getString(
PrefManager.setVal(PrefName.SubscriptionNotificationInterval, curTime) R.string.subscriptions_checking_time_s,
TaskScheduler.create(context, PrefManager.getVal(PrefName.UseAlarmManager)).scheduleAllTasks(context) timeNames[i]
)
PrefManager.setVal(
PrefName.SubscriptionNotificationInterval,
curTime
)
TaskScheduler.create(
context,
PrefManager.getVal(PrefName.UseAlarmManager)
).scheduleAllTasks(context)
} }
show() show()
} }
@ -124,8 +133,9 @@ class SettingsNotificationActivity : AppCompatActivity() {
.setMultiChoiceItems( .setMultiChoiceItems(
types.map { name -> types.map { name ->
name.replace("_", " ").lowercase().replaceFirstChar { name.replace("_", " ").lowercase().replaceFirstChar {
if (it.isLowerCase()) it.titlecase(Locale.ROOT) else it.toString() if (it.isLowerCase()) it.titlecase(Locale.ROOT) else it.toString()
} }.toTypedArray(), }
}.toTypedArray(),
selected selected
) { _, which, isChecked -> ) { _, which, isChecked ->
val type = types[which] val type = types[which]

View file

@ -47,7 +47,8 @@ class SettingsThemeActivity : AppCompatActivity(), SimpleDialog.OnDialogResultLi
val mainIntent = Intent.makeRestartActivityTask( val mainIntent = Intent.makeRestartActivityTask(
packageManager.getLaunchIntentForPackage(packageName)!!.component packageManager.getLaunchIntentForPackage(packageName)!!.component
) )
val component = ComponentName(packageName, SettingsActivity::class.qualifiedName!!) val component =
ComponentName(packageName, SettingsActivity::class.qualifiedName!!)
try { try {
startActivity(Intent().setComponent(component)) startActivity(Intent().setComponent(component))
} catch (e: Exception) { } catch (e: Exception) {

View file

@ -41,5 +41,6 @@ class SubscriptionItem(
override fun getLayout(): Int = R.layout.item_subscription override fun getLayout(): Int = R.layout.item_subscription
override fun initializeViewBinding(view: View): ItemSubscriptionBinding = ItemSubscriptionBinding.bind(view) override fun initializeViewBinding(view: View): ItemSubscriptionBinding =
ItemSubscriptionBinding.bind(view)
} }

View file

@ -1,6 +1,5 @@
package ani.dantotsu.settings package ani.dantotsu.settings
import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.view.View import android.view.View
@ -36,7 +35,8 @@ class SubscriptionSource(
true true
} }
binding.extensionIconImageView.visibility = View.VISIBLE binding.extensionIconImageView.visibility = View.VISIBLE
val layoutParams = binding.extensionIconImageView.layoutParams as ViewGroup.MarginLayoutParams val layoutParams =
binding.extensionIconImageView.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.leftMargin = 28 layoutParams.leftMargin = 28
binding.extensionIconImageView.layoutParams = layoutParams binding.extensionIconImageView.layoutParams = layoutParams
@ -55,11 +55,12 @@ class SubscriptionSource(
private fun updateSubscriptionCount() { private fun updateSubscriptionCount() {
binding.subscriptionCount.text = subscriptions.size.toString() binding.subscriptionCount.text = subscriptions.size.toString()
binding.subscriptionCount.visibility = if (subscriptions.isEmpty()) View.GONE else View.VISIBLE binding.subscriptionCount.visibility =
if (subscriptions.isEmpty()) View.GONE else View.VISIBLE
} }
private fun showRemoveAllSubscriptionsDialog(context: Context) { private fun showRemoveAllSubscriptionsDialog(context: Context) {
context.customAlertDialog().apply{ context.customAlertDialog().apply {
setTitle(R.string.remove_all_subscriptions) setTitle(R.string.remove_all_subscriptions)
setMessage(R.string.remove_all_subscriptions_desc, parserName) setMessage(R.string.remove_all_subscriptions_desc, parserName)
setPosButton(R.string.ok) { removeAllSubscriptions() } setPosButton(R.string.ok) { removeAllSubscriptions() }
@ -96,9 +97,11 @@ class SubscriptionSource(
val startPosition = adapter.getAdapterPosition(this) + 1 val startPosition = adapter.getAdapterPosition(this) + 1
if (isExpanded) { if (isExpanded) {
subscriptions.forEachIndexed { index, subscribeMedia -> subscriptions.forEachIndexed { index, subscribeMedia ->
adapter.add(startPosition + index, SubscriptionItem(subscribeMedia.id, subscribeMedia, adapter) { removedId -> adapter.add(
removeSubscription(removedId) startPosition + index,
}) SubscriptionItem(subscribeMedia.id, subscribeMedia, adapter) { removedId ->
removeSubscription(removedId)
})
} }
} else { } else {
repeat(subscriptions.size) { repeat(subscriptions.size) {
@ -109,5 +112,6 @@ class SubscriptionSource(
override fun getLayout(): Int = R.layout.item_extension override fun getLayout(): Int = R.layout.item_extension
override fun initializeViewBinding(view: View): ItemExtensionBinding = ItemExtensionBinding.bind(view) override fun initializeViewBinding(view: View): ItemExtensionBinding =
ItemExtensionBinding.bind(view)
} }

View file

@ -67,10 +67,13 @@ class SubscriptionsBottomDialog : BottomSheetDialogFragment() {
return when { return when {
animeExtension.installedExtensionsFlow.value.any { it.name == parserName } -> animeExtension.installedExtensionsFlow.value.any { it.name == parserName } ->
animeExtension.installedExtensionsFlow.value.find { it.name == parserName }?.icon animeExtension.installedExtensionsFlow.value.find { it.name == parserName }?.icon
mangaExtensions.installedExtensionsFlow.value.any { it.name == parserName } -> mangaExtensions.installedExtensionsFlow.value.any { it.name == parserName } ->
mangaExtensions.installedExtensionsFlow.value.find { it.name == parserName }?.icon mangaExtensions.installedExtensionsFlow.value.find { it.name == parserName }?.icon
novelExtensions.installedExtensionsFlow.value.any { it.name == parserName } -> novelExtensions.installedExtensionsFlow.value.any { it.name == parserName } ->
novelExtensions.installedExtensionsFlow.value.find { it.name == parserName }?.icon novelExtensions.installedExtensionsFlow.value.find { it.name == parserName }?.icon
else -> null else -> null
} }
} }

View file

@ -1,6 +1,5 @@
package ani.dantotsu.settings package ani.dantotsu.settings
import android.app.AlertDialog
import android.os.Bundle import android.os.Bundle
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@ -43,7 +42,8 @@ class UserInterfaceSettingsActivity : AppCompatActivity() {
setTitle(getString(R.string.home_layout_show)) setTitle(getString(R.string.home_layout_show))
multiChoiceItems( multiChoiceItems(
items = views, items = views,
checkedItems = PrefManager.getVal<List<Boolean>>(PrefName.HomeLayout).toBooleanArray() checkedItems = PrefManager.getVal<List<Boolean>>(PrefName.HomeLayout)
.toBooleanArray()
) { selectedItems -> ) { selectedItems ->
for (i in selectedItems.indices) { for (i in selectedItems.indices) {
set[i] = selectedItems[i] set[i] = selectedItems[i]
@ -69,7 +69,8 @@ class UserInterfaceSettingsActivity : AppCompatActivity() {
PrefManager.setVal(PrefName.ImmersiveMode, isChecked) PrefManager.setVal(PrefName.ImmersiveMode, isChecked)
restartApp() restartApp()
} }
binding.uiSettingsHideRedDot.isChecked = !PrefManager.getVal<Boolean>(PrefName.ShowNotificationRedDot) binding.uiSettingsHideRedDot.isChecked =
!PrefManager.getVal<Boolean>(PrefName.ShowNotificationRedDot)
binding.uiSettingsHideRedDot.setOnCheckedChangeListener { _, isChecked -> binding.uiSettingsHideRedDot.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.ShowNotificationRedDot, !isChecked) PrefManager.setVal(PrefName.ShowNotificationRedDot, !isChecked)
} }

View file

@ -2,13 +2,7 @@ package ani.dantotsu.settings.extensionprefs
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.graphics.Typeface
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.preference.DialogPreference import androidx.preference.DialogPreference
@ -38,10 +32,12 @@ class AnimeSourcePreferencesFragment : PreferenceFragmentCompat() {
preferenceManager.createPreferenceScreen(requireContext()) preferenceManager.createPreferenceScreen(requireContext())
} }
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
ThemeManager(requireActivity()).applyTheme() ThemeManager(requireActivity()).applyTheme()
} }
private var onCloseAction: (() -> Unit)? = null private var onCloseAction: (() -> Unit)? = null
override fun onDestroyView() { override fun onDestroyView() {
@ -104,7 +100,8 @@ class InitialAnimeSourcePreferencesFragment(
preferenceManager.createPreferenceScreen(requireContext()) preferenceManager.createPreferenceScreen(requireContext())
} }
//set background color //set background color
val color = requireContext().getThemeColor(com.google.android.material.R.attr.backgroundColor,) val color =
requireContext().getThemeColor(com.google.android.material.R.attr.backgroundColor)
view?.setBackgroundColor(color) view?.setBackgroundColor(color)
} }

Some files were not shown because too many files have changed in this diff Show more