chore: lint performance optimization

This includes shadowed variables, unnecessary parameters, layouts with string literals, items that cause performance bottlenecks, and the merge of extension types into only the necessary separate classes.
This commit is contained in:
TwistedUmbrellaX 2024-03-14 09:23:30 -04:00
parent 958aa634b1
commit 37ec165319
111 changed files with 1561 additions and 2091 deletions

View file

@ -86,7 +86,7 @@ class App : MultiDexApplication() {
Thread.setDefaultUncaughtExceptionHandler(FinalExceptionHandler())
Logger.log("App: Logging started")
initializeNetwork(baseContext)
initializeNetwork()
setupNotificationChannels()
if (!LogcatLogger.isInstalled) {

View file

@ -159,16 +159,16 @@ class MainActivity : AppCompatActivity() {
}
}
val _bottomBar = findViewById<AnimatedBottomBar>(R.id.navbar)
val bottomNavBar = findViewById<AnimatedBottomBar>(R.id.navbar)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val backgroundDrawable = _bottomBar.background as GradientDrawable
val backgroundDrawable = bottomNavBar.background as GradientDrawable
val currentColor = backgroundDrawable.color?.defaultColor ?: 0
val semiTransparentColor = (currentColor and 0x00FFFFFF) or 0xF9000000.toInt()
backgroundDrawable.setColor(semiTransparentColor)
_bottomBar.background = backgroundDrawable
bottomNavBar.background = backgroundDrawable
}
_bottomBar.background = ContextCompat.getDrawable(this, R.drawable.bottom_nav_gray)
bottomNavBar.background = ContextCompat.getDrawable(this, R.drawable.bottom_nav_gray)
val offset = try {
val statusBarHeightId = resources.getIdentifier("status_bar_height", "dimen", "android")
@ -337,7 +337,7 @@ class MainActivity : AppCompatActivity() {
startActivity(Intent(this, NoInternet::class.java))
} else {
val model: AnilistHomeViewModel by viewModels()
model.genres.observe(this) { it ->
model.genres.observe(this) {
if (it != null) {
if (it) {
val navbar = binding.includedNavbar.navbar
@ -362,7 +362,7 @@ class MainActivity : AppCompatActivity() {
mainViewPager.setCurrentItem(newIndex, false)
}
})
if (mainViewPager.getCurrentItem() != selectedOption) {
if (mainViewPager.currentItem != selectedOption) {
navbar.selectTabAt(selectedOption)
mainViewPager.post {
mainViewPager.setCurrentItem(

View file

@ -1,6 +1,5 @@
package ani.dantotsu
import android.content.Context
import android.os.Build
import androidx.fragment.app.FragmentActivity
import ani.dantotsu.others.webview.CloudFlare
@ -35,7 +34,7 @@ lateinit var defaultHeaders: Map<String, String>
lateinit var okHttpClient: OkHttpClient
lateinit var client: Requests
fun initializeNetwork(context: Context) {
fun initializeNetwork() {
val networkHelper = Injekt.get<NetworkHelper>()

View file

@ -387,6 +387,7 @@ class AnilistQueries {
returnArray.addAll(map.values)
return returnArray
}
@Suppress("UNCHECKED_CAST")
val list = PrefManager.getNullableCustomVal(
"continueAnimeList",
listOf<Int>(),
@ -544,6 +545,7 @@ class AnilistQueries {
returnMap["current$type"] = returnArray
return
}
@Suppress("UNCHECKED_CAST")
val list = PrefManager.getNullableCustomVal(
"continueAnimeList",
listOf<Int>(),
@ -573,6 +575,7 @@ class AnilistQueries {
subMap[m.id] = m
}
}
@Suppress("UNCHECKED_CAST")
val list = PrefManager.getNullableCustomVal(
"continueAnimeList",
listOf<Int>(),
@ -734,7 +737,7 @@ class AnilistQueries {
}
sorted["All"] = all
val listSort: String = if (anime) PrefManager.getVal(PrefName.AnimeListSortOrder)
val listSort: String? = if (anime) PrefManager.getVal(PrefName.AnimeListSortOrder)
else PrefManager.getVal(PrefName.MangaListSortOrder)
val sort = listSort ?: sortOrder ?: options?.rowOrder
for (i in sorted.keys) {

View file

@ -112,8 +112,8 @@ class AnilistHomeViewModel : ViewModel() {
suspend fun loadMain(context: FragmentActivity) {
Anilist.getSavedToken()
MAL.getSavedToken(context)
Discord.getSavedToken(context)
MAL.getSavedToken()
Discord.getSavedToken()
if (!BuildConfig.FLAVOR.contains("fdroid")) {
if (PrefManager.getVal(PrefName.CheckUpdate)) AppUpdater.check(context)
}
@ -159,7 +159,7 @@ class AnilistAnimeViewModel : ViewModel() {
fun getPopular(): LiveData<SearchResults?> = animePopular
suspend fun loadPopular(
type: String,
search_val: String? = null,
searchVal: String? = null,
genres: ArrayList<String>? = null,
sort: String = Anilist.sortBy[1],
onList: Boolean = true,
@ -167,7 +167,7 @@ class AnilistAnimeViewModel : ViewModel() {
animePopular.postValue(
Anilist.query.search(
type,
search = search_val,
search = searchVal,
onList = if (onList) null else false,
sort = sort,
genres = genres
@ -231,7 +231,7 @@ class AnilistMangaViewModel : ViewModel() {
fun getPopular(): LiveData<SearchResults?> = mangaPopular
suspend fun loadPopular(
type: String,
search_val: String? = null,
searchVal: String? = null,
genres: ArrayList<String>? = null,
sort: String = Anilist.sortBy[1],
onList: Boolean = true,
@ -239,7 +239,7 @@ class AnilistMangaViewModel : ViewModel() {
mangaPopular.postValue(
Anilist.query.search(
type,
search = search_val,
search = searchVal,
onList = if (onList) null else false,
sort = sort,
genres = genres

View file

@ -20,14 +20,14 @@ object Discord {
var avatar: String? = null
fun getSavedToken(context: Context): Boolean {
fun getSavedToken(): Boolean {
token = PrefManager.getVal(
PrefName.DiscordToken, null as String?
)
return token != null
}
fun saveToken(context: Context, token: String) {
fun saveToken(token: String) {
PrefManager.setVal(PrefName.DiscordToken, token)
}

View file

@ -5,16 +5,12 @@ import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.IBinder
import android.os.PowerManager
import android.provider.MediaStore
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
@ -37,7 +33,6 @@ import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import java.io.File
import java.io.OutputStreamWriter
class DiscordService : Service() {
private var heartbeat: Int = 0
@ -162,8 +157,8 @@ class DiscordService : Service() {
inner class DiscordWebSocketListener : WebSocketListener() {
var retryAttempts = 0
val maxRetryAttempts = 10
private var retryAttempts = 0
private val maxRetryAttempts = 10
override fun onOpen(webSocket: WebSocket, response: Response) {
super.onOpen(webSocket, response)
this@DiscordService.webSocket = webSocket
@ -232,7 +227,7 @@ class DiscordService : Service() {
resume()
resume = false
} else {
identify(webSocket, baseContext)
identify(webSocket)
log("WebSocket: Identified")
}
}
@ -245,13 +240,13 @@ class DiscordService : Service() {
}
}
fun identify(webSocket: WebSocket, context: Context) {
private fun identify(webSocket: WebSocket) {
val properties = JsonObject()
properties.addProperty("os", "linux")
properties.addProperty("browser", "unknown")
properties.addProperty("device", "unknown")
val d = JsonObject()
d.addProperty("token", getToken(context))
d.addProperty("token", getToken())
d.addProperty("intents", 0)
d.add("properties", properties)
val payload = JsonObject()
@ -311,7 +306,7 @@ class DiscordService : Service() {
}
}
fun getToken(context: Context): String {
fun getToken(): String {
val token = PrefManager.getVal(PrefName.DiscordToken, null as String?)
return if (token == null) {
log("WebSocket: Token not found")
@ -375,10 +370,10 @@ class DiscordService : Service() {
log("WebSocket: Simple Test Presence Saved")
}
fun setPresence(String: String) {
fun setPresence(string: String) {
log("WebSocket: Sending Presence payload")
log(String)
webSocket.send(String)
log(string)
webSocket.send(string)
}
fun log(string: String) {
@ -388,7 +383,7 @@ class DiscordService : Service() {
fun resume() {
log("Sending Resume payload")
val d = JsonObject()
d.addProperty("token", getToken(baseContext))
d.addProperty("token", getToken())
d.addProperty("session_id", sessionId)
d.addProperty("seq", sequence)
val json = JsonObject()
@ -404,8 +399,7 @@ class DiscordService : Service() {
Thread.sleep(heartbeat.toLong())
heartbeatSend(webSocket, sequence)
log("WebSocket: Heartbeat Sent")
} catch (e: InterruptedException) {
}
} catch (ignored: InterruptedException) { }
}
}

View file

@ -75,7 +75,7 @@ class Login : AppCompatActivity() {
}
Toast.makeText(this, "Logged in successfully", Toast.LENGTH_SHORT).show()
finish()
saveToken(this, token)
saveToken(token)
startMainActivity(this@Login)
}

View file

@ -5,7 +5,6 @@ import android.content.Context
import android.net.Uri
import android.util.Base64
import androidx.browser.customtabs.CustomTabsIntent
import androidx.fragment.app.FragmentActivity
import ani.dantotsu.R
import ani.dantotsu.client
import ani.dantotsu.currContext
@ -64,7 +63,7 @@ object MAL {
}
suspend fun getSavedToken(context: FragmentActivity): Boolean {
suspend fun getSavedToken(): Boolean {
return tryWithSuspend(false) {
var res: ResponseToken =
PrefManager.getNullableVal<ResponseToken>(PrefName.MALToken, null)
@ -77,7 +76,7 @@ object MAL {
} ?: false
}
fun removeSavedToken(context: Context) {
fun removeSavedToken() {
token = null
username = null
userid = null

View file

@ -3,6 +3,7 @@ package ani.dantotsu.download
import android.content.Context
import android.os.Environment
import android.widget.Toast
import ani.dantotsu.media.MediaType
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import com.google.gson.Gson
@ -15,11 +16,11 @@ class DownloadsManager(private val context: Context) {
private val downloadsList = loadDownloads().toMutableList()
val mangaDownloadedTypes: List<DownloadedType>
get() = downloadsList.filter { it.type == DownloadedType.Type.MANGA }
get() = downloadsList.filter { it.type == MediaType.MANGA }
val animeDownloadedTypes: List<DownloadedType>
get() = downloadsList.filter { it.type == DownloadedType.Type.ANIME }
get() = downloadsList.filter { it.type == MediaType.ANIME }
val novelDownloadedTypes: List<DownloadedType>
get() = downloadsList.filter { it.type == DownloadedType.Type.NOVEL }
get() = downloadsList.filter { it.type == MediaType.NOVEL }
private fun saveDownloads() {
val jsonString = gson.toJson(downloadsList)
@ -47,14 +48,8 @@ class DownloadsManager(private val context: Context) {
saveDownloads()
}
fun removeMedia(title: String, type: DownloadedType.Type) {
val subDirectory = if (type == DownloadedType.Type.MANGA) {
"Manga"
} else if (type == DownloadedType.Type.ANIME) {
"Anime"
} else {
"Novel"
}
fun removeMedia(title: String, type: MediaType) {
val subDirectory = type.asText()
val directory = File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/$subDirectory/$title"
@ -71,53 +66,45 @@ class DownloadsManager(private val context: Context) {
cleanDownloads()
}
when (type) {
DownloadedType.Type.MANGA -> {
downloadsList.removeAll { it.title == title && it.type == DownloadedType.Type.MANGA }
MediaType.MANGA -> {
downloadsList.removeAll { it.title == title && it.type == MediaType.MANGA }
}
DownloadedType.Type.ANIME -> {
downloadsList.removeAll { it.title == title && it.type == DownloadedType.Type.ANIME }
MediaType.ANIME -> {
downloadsList.removeAll { it.title == title && it.type == MediaType.ANIME }
}
DownloadedType.Type.NOVEL -> {
downloadsList.removeAll { it.title == title && it.type == DownloadedType.Type.NOVEL }
MediaType.NOVEL -> {
downloadsList.removeAll { it.title == title && it.type == MediaType.NOVEL }
}
}
saveDownloads()
}
private fun cleanDownloads() {
cleanDownload(DownloadedType.Type.MANGA)
cleanDownload(DownloadedType.Type.ANIME)
cleanDownload(DownloadedType.Type.NOVEL)
cleanDownload(MediaType.MANGA)
cleanDownload(MediaType.ANIME)
cleanDownload(MediaType.NOVEL)
}
private fun cleanDownload(type: DownloadedType.Type) {
private fun cleanDownload(type: MediaType) {
// remove all folders that are not in the downloads list
val subDirectory = if (type == DownloadedType.Type.MANGA) {
"Manga"
} else if (type == DownloadedType.Type.ANIME) {
"Anime"
} else {
"Novel"
}
val subDirectory = type.asText()
val directory = File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/$subDirectory"
)
val downloadsSubLists = if (type == DownloadedType.Type.MANGA) {
mangaDownloadedTypes
} else if (type == DownloadedType.Type.ANIME) {
animeDownloadedTypes
} else {
novelDownloadedTypes
val downloadsSubLists = when (type) {
MediaType.MANGA -> mangaDownloadedTypes
MediaType.ANIME -> animeDownloadedTypes
else -> novelDownloadedTypes
}
if (directory.exists()) {
val files = directory.listFiles()
if (files != null) {
for (file in files) {
if (!downloadsSubLists.any { it.title == file.name }) {
val deleted = file.deleteRecursively()
file.deleteRecursively()
}
}
}
@ -153,7 +140,7 @@ class DownloadsManager(private val context: Context) {
return downloadsList.contains(downloadedType)
}
fun queryDownload(title: String, chapter: String, type: DownloadedType.Type? = null): Boolean {
fun queryDownload(title: String, chapter: String, type: MediaType? = null): Boolean {
return if (type == null) {
downloadsList.any { it.title == title && it.chapter == chapter }
} else {
@ -162,21 +149,25 @@ class DownloadsManager(private val context: Context) {
}
private fun removeDirectory(downloadedType: DownloadedType) {
val directory = if (downloadedType.type == DownloadedType.Type.MANGA) {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/Manga/${downloadedType.title}/${downloadedType.chapter}"
)
} else if (downloadedType.type == DownloadedType.Type.ANIME) {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/Anime/${downloadedType.title}/${downloadedType.chapter}"
)
} else {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/Novel/${downloadedType.title}/${downloadedType.chapter}"
)
val directory = when (downloadedType.type) {
MediaType.MANGA -> {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/Manga/${downloadedType.title}/${downloadedType.chapter}"
)
}
MediaType.ANIME -> {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/Anime/${downloadedType.title}/${downloadedType.chapter}"
)
}
else -> {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/Novel/${downloadedType.title}/${downloadedType.chapter}"
)
}
}
// Check if the directory exists and delete it recursively
@ -193,21 +184,25 @@ class DownloadsManager(private val context: Context) {
}
fun exportDownloads(downloadedType: DownloadedType) { //copies to the downloads folder available to the user
val directory = if (downloadedType.type == DownloadedType.Type.MANGA) {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/Manga/${downloadedType.title}/${downloadedType.chapter}"
)
} else if (downloadedType.type == DownloadedType.Type.ANIME) {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/Anime/${downloadedType.title}/${downloadedType.chapter}"
)
} else {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/Novel/${downloadedType.title}/${downloadedType.chapter}"
)
val directory = when (downloadedType.type) {
MediaType.MANGA -> {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/Manga/${downloadedType.title}/${downloadedType.chapter}"
)
}
MediaType.ANIME -> {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/Anime/${downloadedType.title}/${downloadedType.chapter}"
)
}
else -> {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/Novel/${downloadedType.title}/${downloadedType.chapter}"
)
}
}
val destination = File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
@ -225,13 +220,17 @@ class DownloadsManager(private val context: Context) {
}
}
fun purgeDownloads(type: DownloadedType.Type) {
val directory = if (type == DownloadedType.Type.MANGA) {
File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "Dantotsu/Manga")
} else if (type == DownloadedType.Type.ANIME) {
File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "Dantotsu/Anime")
} else {
File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "Dantotsu/Novel")
fun purgeDownloads(type: MediaType) {
val directory = when (type) {
MediaType.MANGA -> {
File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "Dantotsu/Manga")
}
MediaType.ANIME -> {
File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "Dantotsu/Anime")
}
else -> {
File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "Dantotsu/Novel")
}
}
if (directory.exists()) {
val deleted = directory.deleteRecursively()
@ -255,56 +254,53 @@ class DownloadsManager(private val context: Context) {
fun getDirectory(
context: Context,
type: DownloadedType.Type,
type: MediaType,
title: String,
chapter: String? = null
): File {
return if (type == DownloadedType.Type.MANGA) {
if (chapter != null) {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$mangaLocation/$title/$chapter"
)
} else {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$mangaLocation/$title"
)
return when (type) {
MediaType.MANGA -> {
if (chapter != null) {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$mangaLocation/$title/$chapter"
)
} else {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$mangaLocation/$title"
)
}
}
} else if (type == DownloadedType.Type.ANIME) {
if (chapter != null) {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$animeLocation/$title/$chapter"
)
} else {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$animeLocation/$title"
)
MediaType.ANIME -> {
if (chapter != null) {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$animeLocation/$title/$chapter"
)
} else {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$animeLocation/$title"
)
}
}
} else {
if (chapter != null) {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$novelLocation/$title/$chapter"
)
} else {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$novelLocation/$title"
)
else -> {
if (chapter != null) {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$novelLocation/$title/$chapter"
)
} else {
File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"$novelLocation/$title"
)
}
}
}
}
}
}
data class DownloadedType(val title: String, val chapter: String, val type: Type) : Serializable {
enum class Type {
MANGA,
ANIME,
NOVEL
}
}
data class DownloadedType(val title: String, val chapter: String, val type: MediaType) : Serializable

View file

@ -27,14 +27,15 @@ import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.download.video.ExoplayerDownloadService
import ani.dantotsu.download.video.Helper
import ani.dantotsu.util.Logger
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaType
import ani.dantotsu.media.SubtitleDownloader
import ani.dantotsu.media.anime.AnimeWatchFragment
import ani.dantotsu.parsers.Subtitle
import ani.dantotsu.parsers.Video
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import com.google.gson.GsonBuilder
import com.google.gson.InstanceCreator
import eu.kanade.tachiyomi.animesource.model.SAnime
@ -242,7 +243,7 @@ class AnimeDownloaderService : Service() {
DownloadedType(
task.title,
task.episode,
DownloadedType.Type.ANIME,
MediaType.ANIME,
)
)
}
@ -273,7 +274,7 @@ class AnimeDownloaderService : Service() {
DownloadedType(
task.title,
task.episode,
DownloadedType.Type.ANIME,
MediaType.ANIME,
)
)
Injekt.get<CrashlyticsInterface>().logException(
@ -302,7 +303,7 @@ class AnimeDownloaderService : Service() {
DownloadedType(
task.title,
task.episode,
DownloadedType.Type.ANIME,
MediaType.ANIME,
)
)
currentTasks.removeAll { it.getTaskName() == task.getTaskName() }

View file

@ -34,15 +34,16 @@ import ani.dantotsu.currContext
import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.initActivity
import ani.dantotsu.util.Logger
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsActivity
import ani.dantotsu.media.MediaType
import ani.dantotsu.navBarHeight
import ani.dantotsu.setSafeOnClickListener
import ani.dantotsu.settings.SettingsDialogFragment
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import com.google.android.material.card.MaterialCardView
import com.google.android.material.imageview.ShapeableImageView
import com.google.android.material.textfield.TextInputLayout
@ -188,8 +189,7 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
gridView.setOnItemLongClickListener { _, _, position, _ ->
// Get the OfflineAnimeModel that was clicked
val item = adapter.getItem(position) as OfflineAnimeModel
val type: DownloadedType.Type =
DownloadedType.Type.ANIME
val type: MediaType = MediaType.ANIME
// Alert dialog to confirm deletion
val builder =
@ -293,11 +293,7 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
}
private fun getMedia(downloadedType: DownloadedType): Media? {
val type = when (downloadedType.type) {
DownloadedType.Type.MANGA -> "Manga"
DownloadedType.Type.ANIME -> "Anime"
else -> "Novel"
}
val type = downloadedType.type.asText()
val directory = File(
currContext()?.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/$type/${downloadedType.title}"
@ -327,11 +323,7 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
}
private fun loadOfflineAnimeModel(downloadedType: DownloadedType): OfflineAnimeModel {
val type = when (downloadedType.type) {
DownloadedType.Type.MANGA -> "Manga"
DownloadedType.Type.ANIME -> "Anime"
else -> "Novel"
}
val type = downloadedType.type.asText()
val directory = File(
currContext()?.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/$type/${downloadedType.title}"

View file

@ -21,8 +21,8 @@ import ani.dantotsu.R
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.util.Logger
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaType
import ani.dantotsu.media.manga.ImageData
import ani.dantotsu.media.manga.MangaReadFragment.Companion.ACTION_DOWNLOAD_FAILED
import ani.dantotsu.media.manga.MangaReadFragment.Companion.ACTION_DOWNLOAD_FINISHED
@ -30,6 +30,7 @@ import ani.dantotsu.media.manga.MangaReadFragment.Companion.ACTION_DOWNLOAD_PROG
import ani.dantotsu.media.manga.MangaReadFragment.Companion.ACTION_DOWNLOAD_STARTED
import ani.dantotsu.media.manga.MangaReadFragment.Companion.EXTRA_CHAPTER_NUMBER
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import com.google.gson.GsonBuilder
import com.google.gson.InstanceCreator
import eu.kanade.tachiyomi.data.notification.Notifications.CHANNEL_DOWNLOADER_PROGRESS
@ -211,8 +212,7 @@ class MangaDownloaderService : Service() {
while (bitmap == null && retryCount < task.retries) {
bitmap = image.fetchAndProcessImage(
image.page,
image.source,
this@MangaDownloaderService
image.source
)
retryCount++
}
@ -246,7 +246,7 @@ class MangaDownloaderService : Service() {
DownloadedType(
task.title,
task.chapter,
DownloadedType.Type.MANGA
MediaType.MANGA
)
)
broadcastDownloadFinished(task.chapter)

View file

@ -31,15 +31,16 @@ import ani.dantotsu.currContext
import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.initActivity
import ani.dantotsu.util.Logger
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsActivity
import ani.dantotsu.media.MediaType
import ani.dantotsu.navBarHeight
import ani.dantotsu.setSafeOnClickListener
import ani.dantotsu.settings.SettingsDialogFragment
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import com.google.android.material.card.MaterialCardView
import com.google.android.material.imageview.ShapeableImageView
import com.google.android.material.textfield.TextInputLayout
@ -179,11 +180,11 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
gridView.setOnItemLongClickListener { _, _, position, _ ->
// Get the OfflineMangaModel that was clicked
val item = adapter.getItem(position) as OfflineMangaModel
val type: DownloadedType.Type =
val type: MediaType =
if (downloadManager.mangaDownloadedTypes.any { it.title == item.title }) {
DownloadedType.Type.MANGA
MediaType.MANGA
} else {
DownloadedType.Type.NOVEL
MediaType.NOVEL
}
// Alert dialog to confirm deletion
val builder =
@ -289,11 +290,7 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
}
private fun getMedia(downloadedType: DownloadedType): Media? {
val type = when (downloadedType.type) {
DownloadedType.Type.MANGA -> "Manga"
DownloadedType.Type.ANIME -> "Anime"
else -> "Novel"
}
val type = downloadedType.type.asText()
val directory = File(
currContext()?.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/$type/${downloadedType.title}"
@ -317,11 +314,7 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
}
private fun loadOfflineMangaModel(downloadedType: DownloadedType): OfflineMangaModel {
val type = when (downloadedType.type) {
DownloadedType.Type.MANGA -> "Manga"
DownloadedType.Type.ANIME -> "Anime"
else -> "Novel"
}
val type = downloadedType.type.asText()
val directory = File(
currContext()?.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
"Dantotsu/$type/${downloadedType.title}"

View file

@ -20,10 +20,11 @@ import ani.dantotsu.R
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.util.Logger
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaType
import ani.dantotsu.media.novel.NovelReadFragment
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import com.google.gson.GsonBuilder
import com.google.gson.InstanceCreator
import eu.kanade.tachiyomi.data.notification.Notifications
@ -335,7 +336,7 @@ class NovelDownloaderService : Service() {
DownloadedType(
task.title,
task.chapter,
DownloadedType.Type.NOVEL
MediaType.NOVEL
)
)
broadcastDownloadFinished(task.originalLink)

View file

@ -9,7 +9,6 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.util.Log
import androidx.annotation.OptIn
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
@ -37,6 +36,7 @@ import ani.dantotsu.download.anime.AnimeDownloaderService
import ani.dantotsu.download.anime.AnimeServiceDataSingleton
import ani.dantotsu.logError
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaType
import ani.dantotsu.okHttpClient
import ani.dantotsu.parsers.Subtitle
import ani.dantotsu.parsers.SubtitleType
@ -49,13 +49,14 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.File
import java.io.IOException
import java.util.concurrent.*
import java.util.concurrent.Executors
@SuppressLint("UnsafeOptInUsageError")
object Helper {
private var simpleCache: SimpleCache? = null
@SuppressLint("UnsafeOptInUsageError")
fun downloadVideo(context: Context, video: Video, subtitle: Subtitle?) {
val dataSourceFactory = DataSource.Factory {
val dataSource: HttpDataSource =
@ -157,16 +158,14 @@ object Helper {
download: Download,
finalException: Exception?
) {
if (download.state == Download.STATE_COMPLETED) {
Logger.log("Download Completed")
} else if (download.state == Download.STATE_FAILED) {
Logger.log("Download Failed")
} else if (download.state == Download.STATE_STOPPED) {
Logger.log("Download Stopped")
} else if (download.state == Download.STATE_QUEUED) {
Logger.log("Download Queued")
} else if (download.state == Download.STATE_DOWNLOADING) {
Logger.log("Download Downloading")
when (download.state) {
Download.STATE_COMPLETED -> Logger.log("Download Completed")
Download.STATE_FAILED -> Logger.log("Download Failed")
Download.STATE_STOPPED -> Logger.log("Download Stopped")
Download.STATE_QUEUED -> Logger.log("Download Queued")
Download.STATE_DOWNLOADING -> Logger.log("Download Downloading")
Download.STATE_REMOVING -> Logger.log("Download Removing")
Download.STATE_RESTARTING -> Logger.log("Download Restarting")
}
}
}
@ -220,7 +219,7 @@ object Helper {
val downloadsManger = Injekt.get<DownloadsManager>()
val downloadCheck = downloadsManger
.queryDownload(title, episode, DownloadedType.Type.ANIME)
.queryDownload(title, episode, MediaType.ANIME)
if (downloadCheck) {
AlertDialog.Builder(context, R.style.MyPopup)
@ -243,7 +242,7 @@ object Helper {
DownloadedType(
title,
episode,
DownloadedType.Type.ANIME
MediaType.ANIME
)
)
AnimeServiceDataSingleton.downloadQueue.offer(animeDownloadTask)

View file

@ -167,8 +167,7 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
trendHandler = Handler(Looper.getMainLooper())
trendRun = Runnable {
binding.animeTrendingViewPager.currentItem =
binding.animeTrendingViewPager.currentItem + 1
binding.animeTrendingViewPager.currentItem += 1
}
binding.animeTrendingViewPager.registerOnPageChangeCallback(
object : ViewPager2.OnPageChangeCallback() {

View file

@ -66,8 +66,8 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
currContext()?.theme?.resolveAttribute(android.R.attr.windowBackground, typedValue, true)
val color = typedValue.data
textInputLayout.boxBackgroundColor = (color and 0x00FFFFFF) or 0x28000000.toInt()
materialCardView.setCardBackgroundColor((color and 0x00FFFFFF) or 0x28000000.toInt())
textInputLayout.boxBackgroundColor = (color and 0x00FFFFFF) or 0x28000000
materialCardView.setCardBackgroundColor((color and 0x00FFFFFF) or 0x28000000)
binding.mangaTitleContainer.updatePadding(top = statusBarHeight)

View file

@ -6,7 +6,6 @@ import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
@ -16,8 +15,8 @@ import androidx.lifecycle.lifecycleScope
import ani.dantotsu.R
import ani.dantotsu.Refresh
import ani.dantotsu.databinding.ActivityListBinding
import ani.dantotsu.hideSystemBarsExtendView
import ani.dantotsu.media.user.ListViewPagerAdapter
import ani.dantotsu.navBarHeight
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.statusBarHeight
@ -73,10 +72,7 @@ class CalendarActivity : AppCompatActivity() {
} else {
binding.root.fitsSystemWindows = false
requestWindowFeature(Window.FEATURE_NO_TITLE)
window.setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN
)
hideSystemBarsExtendView()
binding.settingsContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = statusBarHeight
}

View file

@ -2,7 +2,6 @@ package ani.dantotsu.media
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.graphics.Rect
import android.content.res.Configuration
@ -13,9 +12,7 @@ import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
@ -243,13 +240,13 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
@SuppressLint("ResourceType")
fun total() {
val text = SpannableStringBuilder().apply {
val typedValue = TypedValue()
val mediaTypedValue = TypedValue()
this@MediaDetailsActivity.theme.resolveAttribute(
com.google.android.material.R.attr.colorOnBackground,
typedValue,
mediaTypedValue,
true
)
val white = typedValue.data
val white = mediaTypedValue.data
if (media.userStatus != null) {
append(if (media.anime != null) getString(R.string.watched_num) else getString(R.string.read_num))
val typedValue = TypedValue()

View file

@ -52,12 +52,16 @@ class MediaDetailsViewModel : ViewModel() {
it
}
if (isDownload) {
data.sourceIndex = if (media.anime != null) {
AnimeSources.list.size - 1
} else if (media.format == "MANGA" || media.format == "ONE_SHOT") {
MangaSources.list.size - 1
} else {
NovelSources.list.size - 1
data.sourceIndex = when {
media.anime != null -> {
AnimeSources.list.size - 1
}
media.format == "MANGA" || media.format == "ONE_SHOT" -> {
MangaSources.list.size - 1
}
else -> {
NovelSources.list.size - 1
}
}
}
return data
@ -152,10 +156,10 @@ class MediaDetailsViewModel : ViewModel() {
watchSources?.get(i)?.apply {
if (!post && !allowsPreloading) return@apply
ep.sEpisode?.let {
loadByVideoServers(link, ep.extra, it) {
if (it.videos.isNotEmpty()) {
list.add(it)
ep.extractorCallback?.invoke(it)
loadByVideoServers(link, ep.extra, it) { extractor ->
if (extractor.videos.isNotEmpty()) {
list.add(extractor)
ep.extractorCallback?.invoke(extractor)
}
}
}

View file

@ -0,0 +1,26 @@
package ani.dantotsu.media
enum class MediaType {
ANIME,
MANGA,
NOVEL;
fun asText(): String {
return when (this) {
ANIME -> "Anime"
MANGA -> "Manga"
NOVEL -> "Novel"
}
}
companion object {
fun fromText(string : String): MediaType {
return when (string) {
"Anime" -> ANIME
"Manga" -> MANGA
"Novel" -> NOVEL
else -> { ANIME }
}
}
}
}

View file

@ -65,7 +65,7 @@ class SourceSearchDialogFragment : BottomSheetDialogFragment() {
i = media!!.selected!!.sourceIndex
val source = if (media!!.anime != null) {
(if (!media!!.isAdult) AnimeSources else HAnimeSources)[i!!]
(if (media!!.isAdult) HAnimeSources else AnimeSources)[i!!]
} else {
anime = false
(if (media!!.isAdult) HMangaSources else MangaSources)[i!!]

View file

@ -17,7 +17,7 @@ class SubtitleDownloader {
companion object {
//doesn't really download the subtitles -\_(o_o)_/-
suspend fun loadSubtitleType(context: Context, url: String): SubtitleType =
suspend fun loadSubtitleType(url: String): SubtitleType =
withContext(Dispatchers.IO) {
// Initialize the NetworkHelper instance. Replace this line based on how you usually initialize it
val networkHelper = Injekt.get<NetworkHelper>()
@ -60,7 +60,7 @@ class SubtitleDownloader {
if (!directory.exists()) { //just in case
directory.mkdirs()
}
val type = loadSubtitleType(context, url)
val type = loadSubtitleType(url)
val subtiteFile = File(directory, "subtitle.${type}")
if (subtiteFile.exists()) {
subtiteFile.delete()

View file

@ -7,7 +7,7 @@ import java.util.regex.Pattern
class AnimeNameAdapter {
companion object {
const val episodeRegex =
"(episode|episodio|ep|e)[\\s:.\\-]*([\\d]+\\.?[\\d]*)[\\s:.\\-]*\\(?\\s*(sub|subbed|dub|dubbed)*\\s*\\)?\\s*"
"(episode|episodio|ep|e)[\\s:.\\-]*(\\d+\\.?\\d*)[\\s:.\\-]*\\(?\\s*(sub|subbed|dub|dubbed)*\\s*\\)?\\s*"
const val failedEpisodeNumberRegex =
"(?<!part\\s)\\b(\\d+)\\b"
const val seasonRegex = "(season|s)[\\s:.\\-]*(\\d+)[\\s:.\\-]*"
@ -114,7 +114,7 @@ class AnimeNameAdapter {
val regexPattern = Regex(episodeRegex, RegexOption.IGNORE_CASE)
val removedNumber = text.replace(regexPattern, "")
return if (removedNumber.equals(text, true)) { // if nothing was removed
val failedEpisodeNumberPattern: Regex =
val failedEpisodeNumberPattern =
Regex(failedEpisodeNumberRegex, RegexOption.IGNORE_CASE)
failedEpisodeNumberPattern.replace(removedNumber) { mr ->
mr.value.replaceFirst(mr.groupValues[1], "")

View file

@ -29,19 +29,24 @@ import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import ani.dantotsu.*
import ani.dantotsu.FileUrl
import ani.dantotsu.R
import ani.dantotsu.databinding.FragmentAnimeWatchBinding
import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.download.anime.AnimeDownloaderService
import ani.dantotsu.download.video.ExoplayerDownloadService
import ani.dantotsu.dp
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsActivity
import ani.dantotsu.media.MediaDetailsViewModel
import ani.dantotsu.media.MediaType
import ani.dantotsu.navBarHeight
import ani.dantotsu.others.LanguageMapper
import ani.dantotsu.parsers.AnimeParser
import ani.dantotsu.parsers.AnimeSources
import ani.dantotsu.parsers.HAnimeSources
import ani.dantotsu.setNavigationTheme
import ani.dantotsu.settings.extensionprefs.AnimeSourcePreferencesFragment
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
@ -433,7 +438,7 @@ class AnimeWatchFragment : Fragment() {
DownloadedType(
media.mainName(),
i,
DownloadedType.Type.ANIME
MediaType.ANIME
)
)
episodeAdapter.purgeDownload(i)
@ -445,7 +450,7 @@ class AnimeWatchFragment : Fragment() {
DownloadedType(
media.mainName(),
i,
DownloadedType.Type.ANIME
MediaType.ANIME
)
)
val taskName = AnimeDownloaderService.AnimeDownloadTask.getTaskName(media.mainName(), i)

View file

@ -13,14 +13,16 @@ import androidx.lifecycle.coroutineScope
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.offline.DownloadIndex
import androidx.recyclerview.widget.RecyclerView
import ani.dantotsu.*
import ani.dantotsu.R
import ani.dantotsu.connections.updateProgress
import ani.dantotsu.currContext
import ani.dantotsu.databinding.ItemEpisodeCompactBinding
import ani.dantotsu.databinding.ItemEpisodeGridBinding
import ani.dantotsu.databinding.ItemEpisodeListBinding
import ani.dantotsu.download.anime.AnimeDownloaderService
import ani.dantotsu.download.video.Helper
import ani.dantotsu.media.Media
import ani.dantotsu.setAnimation
import ani.dantotsu.settings.saving.PrefManager
import com.bumptech.glide.Glide
import com.bumptech.glide.load.model.GlideUrl
@ -427,7 +429,7 @@ class EpisodeAdapter(
if (bytes < 0) return null
val unit = 1000
if (bytes < unit) return "$bytes B"
val exp = (Math.log(bytes.toDouble()) / ln(unit.toDouble())).toInt()
val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt()
val pre = ("KMGTPE")[exp - 1]
return String.format("%.1f %sB", bytes / unit.toDouble().pow(exp.toDouble()), pre)
}

View file

@ -16,7 +16,10 @@ import android.graphics.Color
import android.graphics.drawable.Animatable
import android.hardware.SensorManager
import android.media.AudioManager
import android.media.AudioManager.*
import android.media.AudioManager.AUDIOFOCUS_GAIN
import android.media.AudioManager.AUDIOFOCUS_LOSS
import android.media.AudioManager.AUDIOFOCUS_LOSS_TRANSIENT
import android.media.AudioManager.STREAM_MUSIC
import android.net.Uri
import android.os.Build
import android.os.Bundle
@ -27,8 +30,18 @@ import android.provider.Settings.System
import android.util.AttributeSet
import android.util.Rational
import android.util.TypedValue
import android.view.*
import android.view.KeyEvent.*
import android.view.GestureDetector
import android.view.KeyEvent
import android.view.KeyEvent.ACTION_UP
import android.view.KeyEvent.KEYCODE_B
import android.view.KeyEvent.KEYCODE_DPAD_LEFT
import android.view.KeyEvent.KEYCODE_DPAD_RIGHT
import android.view.KeyEvent.KEYCODE_N
import android.view.KeyEvent.KEYCODE_SPACE
import android.view.MotionEvent
import android.view.OrientationEventListener
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils
import android.widget.AdapterView
import android.widget.ImageButton
@ -46,27 +59,43 @@ import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope
import androidx.media3.cast.CastPlayer
import androidx.media3.cast.SessionAvailabilityListener
import androidx.media3.common.*
import androidx.media3.common.C
import androidx.media3.common.C.AUDIO_CONTENT_TYPE_MOVIE
import androidx.media3.common.C.TRACK_TYPE_VIDEO
import androidx.media3.common.MediaItem
import androidx.media3.common.MimeTypes
import androidx.media3.common.PlaybackException
import androidx.media3.common.PlaybackParameters
import androidx.media3.common.Player
import androidx.media3.common.TrackSelectionOverride
import androidx.media3.common.Tracks
import androidx.media3.common.util.UnstableApi
import androidx.media3.common.util.Util
import androidx.media3.datasource.DataSource
import androidx.media3.datasource.DefaultDataSourceFactory
import androidx.media3.datasource.DefaultDataSource
import androidx.media3.datasource.HttpDataSource
import androidx.media3.datasource.cache.CacheDataSource
import androidx.media3.datasource.okhttp.OkHttpDataSource
import androidx.media3.exoplayer.DefaultLoadControl
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
import androidx.media3.exoplayer.util.EventLogger
import androidx.media3.session.MediaSession
import androidx.media3.ui.*
import androidx.media3.ui.CaptionStyleCompat.*
import androidx.media3.exoplayer.DefaultLoadControl
import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.CaptionStyleCompat
import androidx.media3.ui.CaptionStyleCompat.EDGE_TYPE_DEPRESSED
import androidx.media3.ui.CaptionStyleCompat.EDGE_TYPE_DROP_SHADOW
import androidx.media3.ui.CaptionStyleCompat.EDGE_TYPE_NONE
import androidx.media3.ui.CaptionStyleCompat.EDGE_TYPE_OUTLINE
import androidx.media3.ui.DefaultTimeBar
import androidx.media3.ui.PlayerView
import androidx.media3.ui.SubtitleView
import androidx.mediarouter.app.MediaRouteButton
import ani.dantotsu.*
import ani.dantotsu.GesturesListener
import ani.dantotsu.NoPaddingArrayAdapter
import ani.dantotsu.R
import ani.dantotsu.brightnessConverter
import ani.dantotsu.circularReveal
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.connections.discord.Discord
@ -75,19 +104,38 @@ import ani.dantotsu.connections.discord.DiscordServiceRunningSingleton
import ani.dantotsu.connections.discord.RPC
import ani.dantotsu.connections.updateProgress
import ani.dantotsu.databinding.ActivityExoplayerBinding
import ani.dantotsu.defaultHeaders
import ani.dantotsu.download.video.Helper
import ani.dantotsu.dp
import ani.dantotsu.getCurrentBrightnessValue
import ani.dantotsu.hideSystemBars
import ani.dantotsu.hideSystemBarsExtendView
import ani.dantotsu.isOnline
import ani.dantotsu.logError
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsViewModel
import ani.dantotsu.media.SubtitleDownloader
import ani.dantotsu.okHttpClient
import ani.dantotsu.others.AniSkip
import ani.dantotsu.others.AniSkip.getType
import ani.dantotsu.others.ResettableTimer
import ani.dantotsu.others.getSerialized
import ani.dantotsu.parsers.*
import ani.dantotsu.parsers.AnimeSources
import ani.dantotsu.parsers.HAnimeSources
import ani.dantotsu.parsers.Subtitle
import ani.dantotsu.parsers.SubtitleType
import ani.dantotsu.parsers.Video
import ani.dantotsu.parsers.VideoExtractor
import ani.dantotsu.parsers.VideoType
import ani.dantotsu.px
import ani.dantotsu.settings.PlayerSettingsActivity
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
import ani.dantotsu.startMainActivity
import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.toast
import ani.dantotsu.tryWithSuspend
import ani.dantotsu.util.Logger
import com.bumptech.glide.Glide
import com.google.android.gms.cast.framework.CastButtonFactory
@ -103,8 +151,11 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.util.*
import java.util.concurrent.*
import java.util.Calendar
import java.util.Timer
import java.util.TimerTask
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import kotlin.math.max
import kotlin.math.min
import kotlin.math.roundToInt
@ -344,15 +395,14 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
isCastApiAvailable = GoogleApiAvailability.getInstance()
.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS
try {
castContext = CastContext.getSharedInstance(this)
castContext = CastContext.getSharedInstance(this, Executors.newSingleThreadExecutor()).result
castPlayer = CastPlayer(castContext!!)
castPlayer!!.setSessionAvailabilityListener(this)
} catch (e: Exception) {
isCastApiAvailable = false
}
WindowCompat.setDecorFitsSystemWindows(window, false)
hideSystemBars()
hideSystemBarsExtendView()
onBackPressedDispatcher.addCallback(this) {
finishAndRemoveTask()
@ -397,21 +447,25 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
orientationListener =
object : OrientationEventListener(this, SensorManager.SENSOR_DELAY_UI) {
override fun onOrientationChanged(orientation: Int) {
if (orientation in 45..135) {
if (rotation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE) {
exoRotate.visibility = View.VISIBLE
when (orientation) {
in 45..135 -> {
if (rotation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE) {
exoRotate.visibility = View.VISIBLE
}
rotation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
}
rotation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
} else if (orientation in 225..315) {
if (rotation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
exoRotate.visibility = View.VISIBLE
in 225..315 -> {
if (rotation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
exoRotate.visibility = View.VISIBLE
}
rotation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
}
rotation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
} else if (orientation in 315..360 || orientation in 0..45) {
if (rotation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
exoRotate.visibility = View.VISIBLE
in 315..360, in 0..45 -> {
if (rotation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
exoRotate.visibility = View.VISIBLE
}
rotation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
rotation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
}
}
@ -943,7 +997,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
episodeArr = episodes.keys.toList()
currentEpisodeIndex = episodeArr.indexOf(media.anime!!.selectedEpisode!!)
episodeTitleArr = arrayListOf<String>()
episodeTitleArr = arrayListOf()
episodes.forEach {
val episode = it.value
val cleanedTitle = AnimeNameAdapter.removeEpisodeNumberCompletely(episode.title ?: "")
@ -1054,7 +1108,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
RPC.Link(getString(R.string.view_anime), media.shareLink ?: ""),
RPC.Link(
"Stream on Dantotsu",
"https://github.com/rebelonion/Dantotsu/"
getString(R.string.github)
)
)
)
@ -1266,6 +1320,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
media.anime!!.selectedEpisode!!
)
@Suppress("UNCHECKED_CAST")
val list = (PrefManager.getNullableCustomVal("continueAnimeList", listOf<Int>(), List::class.java) as List<Int>).toMutableList()
if (list.contains(media.id)) list.remove(media.id)
list.add(media.id)
@ -1303,9 +1358,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
if (subtitle != null) {
//var localFile: String? = null
if (subtitle?.type == SubtitleType.UNKNOWN) {
val context = this
runBlocking {
val type = SubtitleDownloader.loadSubtitleType(context, subtitle!!.file.url)
val type = SubtitleDownloader.loadSubtitleType(subtitle!!.file.url)
val fileUri = Uri.parse(subtitle!!.file.url)
sub = MediaItem.SubtitleConfiguration
.Builder(fileUri)
@ -1360,8 +1414,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
}
dataSource
}
val dafuckDataSourceFactory =
DefaultDataSourceFactory(this, Util.getUserAgent(this, R.string.app_name.toString()))
val dafuckDataSourceFactory = DefaultDataSource.Factory(this)
cacheFactory = CacheDataSource.Factory().apply {
setCache(Helper.getSimpleCache(this@ExoplayerView))
if (ext.server.offline) {
@ -1737,28 +1790,26 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
timer = null
return
}
if (timer == null) {
timer = object : CountDownTimer(5000, 1000) {
override fun onTick(millisUntilFinished: Long) {
if (new == null){
skipTimeButton.visibility = View.GONE
exoSkip.visibility = View.VISIBLE
disappeared = false
functionstarted = false
cancelTimer()
}
}
override fun onFinish() {
timer = object : CountDownTimer(5000, 1000) {
override fun onTick(millisUntilFinished: Long) {
if (new == null) {
skipTimeButton.visibility = View.GONE
exoSkip.visibility = View.VISIBLE
disappeared = true
disappeared = false
functionstarted = false
cancelTimer()
}
}
timer?.start()
override fun onFinish() {
skipTimeButton.visibility = View.GONE
exoSkip.visibility = View.VISIBLE
disappeared = true
functionstarted = false
cancelTimer()
}
}
timer?.start()
}
if (PrefManager.getVal(PrefName.ShowTimeStampButton)) {

View file

@ -29,6 +29,7 @@ import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.TimeZone
import kotlin.math.abs
import kotlin.math.sqrt
@ -258,6 +259,7 @@ class CommentItem(val comment: Comment,
private fun removeSubCommentIds(){
subCommentIds.forEach { id ->
@Suppress("UNCHECKED_CAST")
val parentComments = parentSection.groups as? List<CommentItem> ?: emptyList()
val commentToRemove = parentComments.find { it.comment.commentId == id }
commentToRemove?.let {
@ -290,7 +292,7 @@ class CommentItem(val comment: Comment,
@SuppressLint("SimpleDateFormat")
private fun formatTimestamp(timestamp: String): String {
return try {
val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ROOT)
dateFormat.timeZone = TimeZone.getTimeZone("UTC")
val parsedDate = dateFormat.parse(timestamp)
val currentDate = Date()
@ -315,7 +317,7 @@ class CommentItem(val comment: Comment,
companion object {
@SuppressLint("SimpleDateFormat")
fun timestampToMillis(timestamp: String): Long {
val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ROOT)
dateFormat.timeZone = TimeZone.getTimeZone("UTC")
val parsedDate = dateFormat.parse(timestamp)
return parsedDate?.time ?: 0

View file

@ -2,7 +2,6 @@ package ani.dantotsu.media.manga
import android.content.ContentResolver
import android.content.ContentValues
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
@ -10,8 +9,8 @@ import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.util.LruCache
import ani.dantotsu.util.Logger
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.online.HttpSource
import kotlinx.coroutines.Dispatchers
@ -25,8 +24,7 @@ data class ImageData(
) {
suspend fun fetchAndProcessImage(
page: Page,
httpSource: HttpSource,
context: Context
httpSource: HttpSource
): Bitmap? {
return withContext(Dispatchers.IO) {
try {

View file

@ -5,8 +5,8 @@ import java.util.regex.Pattern
class MangaNameAdapter {
companion object {
const val chapterRegex = "(chapter|chap|ch|c)[\\s:.\\-]*([\\d]+\\.?[\\d]*)[\\s:.\\-]*"
const val filedChapterNumberRegex = "(?<!part\\s)\\b(\\d+)\\b"
private const val chapterRegex = "(chapter|chap|ch|c)[\\s:.\\-]*(\\d+\\.?\\d*)[\\s:.\\-]*"
private const val filedChapterNumberRegex = "(?<!part\\s)\\b(\\d+)\\b"
fun findChapterNumber(text: String): Float? {
val pattern: Pattern = Pattern.compile(chapterRegex, Pattern.CASE_INSENSITIVE)
val matcher: Matcher = pattern.matcher(text)

View file

@ -30,21 +30,25 @@ import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import ani.dantotsu.*
import ani.dantotsu.R
import ani.dantotsu.databinding.FragmentAnimeWatchBinding
import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.download.manga.MangaDownloaderService
import ani.dantotsu.download.manga.MangaServiceDataSingleton
import ani.dantotsu.dp
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsActivity
import ani.dantotsu.media.MediaDetailsViewModel
import ani.dantotsu.media.MediaType
import ani.dantotsu.media.manga.mangareader.ChapterLoaderDialog
import ani.dantotsu.navBarHeight
import ani.dantotsu.others.LanguageMapper
import ani.dantotsu.parsers.DynamicMangaParser
import ani.dantotsu.parsers.HMangaSources
import ani.dantotsu.parsers.MangaParser
import ani.dantotsu.parsers.MangaSources
import ani.dantotsu.setNavigationTheme
import ani.dantotsu.settings.extensionprefs.MangaSourcePreferencesFragment
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
@ -492,7 +496,7 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
DownloadedType(
media.mainName(),
i,
DownloadedType.Type.MANGA
MediaType.MANGA
)
)
chapterAdapter.deleteDownload(i)
@ -510,7 +514,7 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
DownloadedType(
media.mainName(),
i,
DownloadedType.Type.MANGA
MediaType.MANGA
)
)
chapterAdapter.purgeDownload(i)

View file

@ -13,10 +13,14 @@ import androidx.core.view.GestureDetectorCompat
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import ani.dantotsu.*
import ani.dantotsu.FileUrl
import ani.dantotsu.GesturesListener
import ani.dantotsu.R
import ani.dantotsu.media.manga.MangaCache
import ani.dantotsu.media.manga.MangaChapter
import ani.dantotsu.px
import ani.dantotsu.settings.CurrentReaderSettings
import ani.dantotsu.tryWithSuspend
import com.alexvasilkov.gestures.views.GestureFrameLayout
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
@ -118,13 +122,13 @@ abstract class BaseImageAdapter(
abstract suspend fun loadImage(position: Int, parent: View): Boolean
companion object {
suspend fun Context.loadBitmap_old(
suspend fun Context.loadBitmapOld(
link: FileUrl,
transforms: List<BitmapTransformation>
): Bitmap? { //still used in some places
return tryWithSuspend {
withContext(Dispatchers.IO) {
Glide.with(this@loadBitmap_old)
Glide.with(this@loadBitmapOld)
.asBitmap()
.let {
if (link.url.startsWith("file://")) {
@ -168,8 +172,7 @@ abstract class BaseImageAdapter(
mangaCache.get(link.url)?.let { imageData ->
val bitmap = imageData.fetchAndProcessImage(
imageData.page,
imageData.source,
context = this@loadBitmap
imageData.source
)
it.load(bitmap)
.skipMemoryCache(true)

View file

@ -10,8 +10,19 @@ import android.content.res.Resources
import android.graphics.Bitmap
import android.os.Build
import android.os.Bundle
import android.view.*
import android.view.KeyEvent.*
import android.view.HapticFeedbackConstants
import android.view.KeyEvent
import android.view.KeyEvent.ACTION_DOWN
import android.view.KeyEvent.KEYCODE_DPAD_DOWN
import android.view.KeyEvent.KEYCODE_DPAD_UP
import android.view.KeyEvent.KEYCODE_PAGE_DOWN
import android.view.KeyEvent.KEYCODE_PAGE_UP
import android.view.KeyEvent.KEYCODE_VOLUME_DOWN
import android.view.KeyEvent.KEYCODE_VOLUME_UP
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.animation.OvershootInterpolator
import android.widget.AdapterView
import android.widget.CheckBox
@ -27,7 +38,9 @@ import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.PagerSnapHelper
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import ani.dantotsu.*
import ani.dantotsu.GesturesListener
import ani.dantotsu.NoPaddingArrayAdapter
import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.connections.discord.Discord
@ -35,7 +48,12 @@ import ani.dantotsu.connections.discord.DiscordService
import ani.dantotsu.connections.discord.DiscordServiceRunningSingleton
import ani.dantotsu.connections.discord.RPC
import ani.dantotsu.connections.updateProgress
import ani.dantotsu.currContext
import ani.dantotsu.databinding.ActivityMangaReaderBinding
import ani.dantotsu.dp
import ani.dantotsu.hideSystemBarsExtendView
import ani.dantotsu.isOnline
import ani.dantotsu.logError
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsViewModel
import ani.dantotsu.media.MediaSingleton
@ -46,14 +64,25 @@ import ani.dantotsu.others.ImageViewDialog
import ani.dantotsu.parsers.HMangaSources
import ani.dantotsu.parsers.MangaImage
import ani.dantotsu.parsers.MangaSources
import ani.dantotsu.px
import ani.dantotsu.setSafeOnClickListener
import ani.dantotsu.settings.CurrentReaderSettings
import ani.dantotsu.settings.CurrentReaderSettings.Companion.applyWebtoon
import ani.dantotsu.settings.CurrentReaderSettings.Directions.*
import ani.dantotsu.settings.CurrentReaderSettings.DualPageModes.*
import ani.dantotsu.settings.CurrentReaderSettings.Layouts.*
import ani.dantotsu.settings.CurrentReaderSettings.Directions.BOTTOM_TO_TOP
import ani.dantotsu.settings.CurrentReaderSettings.Directions.LEFT_TO_RIGHT
import ani.dantotsu.settings.CurrentReaderSettings.Directions.RIGHT_TO_LEFT
import ani.dantotsu.settings.CurrentReaderSettings.Directions.TOP_TO_BOTTOM
import ani.dantotsu.settings.CurrentReaderSettings.DualPageModes.Automatic
import ani.dantotsu.settings.CurrentReaderSettings.DualPageModes.Force
import ani.dantotsu.settings.CurrentReaderSettings.DualPageModes.No
import ani.dantotsu.settings.CurrentReaderSettings.Layouts.CONTINUOUS_PAGED
import ani.dantotsu.settings.CurrentReaderSettings.Layouts.PAGED
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.showSystemBarsRetractView
import ani.dantotsu.snackString
import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.tryWith
import com.alexvasilkov.gestures.views.GestureFrameLayout
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
@ -66,7 +95,8 @@ import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.util.*
import java.util.Timer
import java.util.TimerTask
import kotlin.math.min
import kotlin.properties.Delegates
@ -88,7 +118,6 @@ class MangaReaderActivity : AppCompatActivity() {
private var isContVisible = false
private var showProgressDialog = true
private var hidescrollbar = false
private var maxChapterPage = 0L
private var currentChapterPage = 0L
@ -123,7 +152,7 @@ class MangaReaderActivity : AppCompatActivity() {
}
private fun hideSystemBars() {
if (PrefManager.getVal<Boolean>(PrefName.ShowSystemBars))
if (PrefManager.getVal(PrefName.ShowSystemBars))
showSystemBarsRetractView()
else
hideSystemBarsExtendView()
@ -368,7 +397,7 @@ class MangaReaderActivity : AppCompatActivity() {
RPC.Link(getString(R.string.view_manga), media.shareLink ?: ""),
RPC.Link(
"Stream on Dantotsu",
"https://github.com/rebelonion/Dantotsu/"
getString(R.string.github)
)
)
)
@ -740,12 +769,12 @@ class MangaReaderActivity : AppCompatActivity() {
goneTimer.schedule(timerTask, controllerDuration)
}
enum class pressPos {
enum class PressPos {
LEFT, RIGHT, CENTER
}
fun handleController(shouldShow: Boolean? = null, event: MotionEvent? = null) {
var pressLocation = pressPos.CENTER
var pressLocation = PressPos.CENTER
if (!sliding) {
if (event != null && defaultSettings.layout == PAGED) {
if (event.action != MotionEvent.ACTION_UP) return
@ -755,23 +784,23 @@ class MangaReaderActivity : AppCompatActivity() {
//if in the 1st 1/5th of the screen width, left and lower than 1/5th of the screen height, left
if (screenWidth / 5 in x + 1..<y) {
pressLocation = if (defaultSettings.direction == RIGHT_TO_LEFT || defaultSettings.direction == BOTTOM_TO_TOP) {
pressPos.RIGHT
PressPos.RIGHT
} else {
pressPos.LEFT
PressPos.LEFT
}
}
//if in the last 1/5th of the screen width, right and lower than 1/5th of the screen height, right
else if (x > screenWidth - screenWidth / 5 && y > screenWidth / 5) {
pressLocation = if (defaultSettings.direction == RIGHT_TO_LEFT || defaultSettings.direction == BOTTOM_TO_TOP) {
pressPos.LEFT
PressPos.LEFT
} else {
pressPos.RIGHT
PressPos.RIGHT
}
}
}
// if pressLocation is left or right go to previous or next page (paged mode only)
if (pressLocation == pressPos.LEFT) {
if (pressLocation == PressPos.LEFT) {
if (binding.mangaReaderPager.currentItem > 0) {
//if the current images zoomed in, go back to normal before going to previous page
@ -782,7 +811,7 @@ class MangaReaderActivity : AppCompatActivity() {
return
}
} else if (pressLocation == pressPos.RIGHT) {
} else if (pressLocation == PressPos.RIGHT) {
if (binding.mangaReaderPager.currentItem < maxChapterPage - 1) {
//if the current images zoomed in, go back to normal before going to next page
if (imageAdapter?.isZoomed() == true) {
@ -960,7 +989,7 @@ class MangaReaderActivity : AppCompatActivity() {
if (!incognito && PrefManager.getCustomVal(
"${media.id}_save_progress",
true
) && if (media.isAdult) PrefManager.getVal<Boolean>(PrefName.UpdateForHReader) else true
) && if (media.isAdult) PrefManager.getVal(PrefName.UpdateForHReader) else true
)
updateProgress(
media,

View file

@ -9,7 +9,6 @@ import android.os.Environment
import android.os.Handler
import android.os.Looper
import android.os.Parcelable
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -28,6 +27,7 @@ import ani.dantotsu.download.novel.NovelDownloaderService
import ani.dantotsu.download.novel.NovelServiceDataSingleton
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsViewModel
import ani.dantotsu.media.MediaType
import ani.dantotsu.media.novel.novelreader.NovelReaderActivity
import ani.dantotsu.navBarHeight
import ani.dantotsu.parsers.ShowResponse
@ -90,7 +90,7 @@ class NovelReadFragment : Fragment(),
DownloadedType(
media.mainName(),
novel.name,
DownloadedType.Type.NOVEL
MediaType.NOVEL
)
)
) {
@ -122,7 +122,7 @@ class NovelReadFragment : Fragment(),
DownloadedType(
media.mainName(),
novel.name,
DownloadedType.Type.NOVEL
MediaType.NOVEL
)
)
}
@ -133,7 +133,7 @@ class NovelReadFragment : Fragment(),
DownloadedType(
media.mainName(),
novel.name,
DownloadedType.Type.NOVEL
MediaType.NOVEL
)
)
}

View file

@ -6,7 +6,6 @@ import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu
@ -17,7 +16,7 @@ import androidx.lifecycle.lifecycleScope
import ani.dantotsu.R
import ani.dantotsu.Refresh
import ani.dantotsu.databinding.ActivityListBinding
import ani.dantotsu.navBarHeight
import ani.dantotsu.hideSystemBarsExtendView
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.statusBarHeight
@ -71,10 +70,7 @@ class ListActivity : AppCompatActivity() {
} else {
binding.root.fitsSystemWindows = false
requestWindowFeature(Window.FEATURE_NO_TITLE)
window.setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN
)
hideSystemBarsExtendView()
binding.settingsContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = statusBarHeight
}

View file

@ -11,7 +11,7 @@ class AndroidBug5497Workaround private constructor(activity: Activity, private v
private val frameLayoutParams: FrameLayout.LayoutParams
init {
val content = activity.findViewById(android.R.id.content) as FrameLayout
val content: FrameLayout = activity.findViewById(android.R.id.content)
mChildOfContent = content.getChildAt(0)
mChildOfContent.viewTreeObserver.addOnGlobalLayoutListener { possiblyResizeChildOfContent() }
frameLayoutParams = mChildOfContent.layoutParams as FrameLayout.LayoutParams

View file

@ -14,7 +14,7 @@ import ani.dantotsu.R
import ani.dantotsu.databinding.BottomSheetImageBinding
import ani.dantotsu.downloadsPermission
import ani.dantotsu.media.manga.mangareader.BaseImageAdapter.Companion.loadBitmap
import ani.dantotsu.media.manga.mangareader.BaseImageAdapter.Companion.loadBitmap_old
import ani.dantotsu.media.manga.mangareader.BaseImageAdapter.Companion.loadBitmapOld
import ani.dantotsu.media.manga.mangareader.BaseImageAdapter.Companion.mergeBitmap
import ani.dantotsu.openLinkInBrowser
import ani.dantotsu.saveImageToDownloads
@ -84,9 +84,9 @@ class ImageViewDialog : BottomSheetDialogFragment() {
viewLifecycleOwner.lifecycleScope.launch {
val binding = _binding ?: return@launch
var bitmap = context.loadBitmap_old(image, trans1 ?: listOf())
var bitmap = context.loadBitmapOld(image, trans1 ?: listOf())
var bitmap2 =
if (image2 != null) context.loadBitmap_old(image2, trans2 ?: listOf()) else null
if (image2 != null) context.loadBitmapOld(image2, trans2 ?: listOf()) else null
if (bitmap == null) {
bitmap = context.loadBitmap(image, trans1 ?: listOf())
bitmap2 =

View file

@ -1,9 +1,11 @@
package ani.dantotsu.others
import android.content.Context
import android.content.res.Resources
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.util.TypedValue
import androidx.appcompat.widget.AppCompatTextView
import ani.dantotsu.R
@ -54,14 +56,14 @@ class OutlineTextView : AppCompatTextView {
setStrokeWidth(strokeWidth)
}
private val Float.toPx get() = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, this, Resources.getSystem().displayMetrics
)
private fun setStrokeWidth(width: Float) {
strokeWidth = width.toPx(context)
strokeWidth = width.toPx
}
private fun Float.toPx(context: Context) =
(this * context.resources.displayMetrics.scaledDensity + 0.5F)
override fun invalidate() {
if (isDrawing) return
super.invalidate()

View file

@ -12,19 +12,19 @@ import androidx.appcompat.app.AppCompatActivity
import ani.dantotsu.R
import ani.dantotsu.themes.ThemeManager
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.util.system.getSerializableExtraCompat
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class CookieCatcher : AppCompatActivity() {
@SuppressLint("SetJavaScriptEnabled")
@Suppress("UNCHECKED_CAST")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ThemeManager(this).applyTheme()
//get url from intent
val url = intent.getStringExtra("url") ?: "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
val headers: Map<String, String> = intent.getSerializableExtra("headers") as? Map<String, String> ?: emptyMap()
val url = intent.getStringExtra("url") ?: getString(R.string.cursed_yt)
val headers: Map<String, String> = intent.getSerializableExtraCompat("headers") as? Map<String, String> ?: emptyMap()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val process = Application.getProcessName()

View file

@ -11,11 +11,11 @@ import android.os.Environment
import android.provider.MediaStore
import ani.dantotsu.FileUrl
import ani.dantotsu.currContext
import ani.dantotsu.util.Logger
import ani.dantotsu.media.anime.AnimeNameAdapter
import ani.dantotsu.media.manga.ImageData
import ani.dantotsu.media.manga.MangaCache
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import eu.kanade.tachiyomi.animesource.AnimeCatalogueSource
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimesPage
@ -59,8 +59,6 @@ class AniyomiAdapter {
fun aniyomiToAnimeParser(extension: AnimeExtension.Installed): DynamicAnimeParser {
return DynamicAnimeParser(extension)
}
}
class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
@ -192,7 +190,7 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
// Group by season, sort within each season, and then renumber while keeping episode number 0 as is
val seasonGroups =
res.groupBy { AnimeNameAdapter.findSeasonNumber(it.name) ?: 0 }
seasonGroups.keys.sortedBy { it.toInt() }
seasonGroups.keys.sortedBy { it }
.flatMap { season ->
seasonGroups[season]?.sortedBy { it.episode_number }?.map { episode ->
if (episode.episode_number != 0f) { // Skip renumbering for episode number 0
@ -209,7 +207,7 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
} ?: emptyList()
}
}
return sortedEpisodes.map { SEpisodeToEpisode(it) }
return sortedEpisodes.map { sEpisodeToEpisode(it) }
} catch (e: Exception) {
Logger.log("Exception: $e")
}
@ -244,7 +242,7 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
return try {
val videos = source.getVideoList(sEpisode)
videos.map { VideoToVideoServer(it) }
videos.map { videoToVideoServer(it) }
} catch (e: Exception) {
Logger.log("Exception occurred: ${e.message}")
emptyList()
@ -296,7 +294,7 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
}
}
private fun SEpisodeToEpisode(sEpisode: SEpisode): Episode {
private fun sEpisodeToEpisode(sEpisode: SEpisode): Episode {
//if the float episode number is a whole number, convert it to an int
val episodeNumberInt =
if (sEpisode.episode_number % 1 == 0f) {
@ -324,7 +322,7 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
)
}
private fun VideoToVideoServer(video: Video): VideoServer {
private fun videoToVideoServer(video: Video): VideoServer {
return VideoServer(
video.quality,
video.url,
@ -363,7 +361,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
return try {
val res = source.getChapterList(sManga)
val reversedRes = res.reversed()
val chapterList = reversedRes.map { SChapterToMangaChapter(it) }
val chapterList = reversedRes.map { sChapterToMangaChapter(it) }
Logger.log("chapterList size: ${chapterList.size}")
Logger.log("chapterList: ${chapterList[1].title}")
Logger.log("chapterList: ${chapterList[1].description}")
@ -382,7 +380,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
sourceLanguage = 0
extension.sources[sourceLanguage]
} as? HttpSource ?: return emptyList()
var imageDataList: List<ImageData> = listOf()
val imageDataList: MutableList<ImageData> = mutableListOf()
val ret = coroutineScope {
try {
Logger.log("source.name " + source.name)
@ -632,7 +630,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
}
private fun SChapterToMangaChapter(sChapter: SChapter): MangaChapter {
private fun sChapterToMangaChapter(sChapter: SChapter): MangaChapter {
return MangaChapter(
sChapter.name,
sChapter.url,
@ -676,8 +674,8 @@ class VideoServerPassthrough(val videoServer: VideoServer) : VideoExtractor() {
get() = videoServer
override suspend fun extract(): VideoContainer {
val vidList = listOfNotNull(videoServer.video?.let { AniVideoToSaiVideo(it) })
val subList = videoServer.video?.subtitleTracks?.map { TrackToSubtitle(it) } ?: emptyList()
val vidList = listOfNotNull(videoServer.video?.let { aniVideoToSaiVideo(it) })
val subList = videoServer.video?.subtitleTracks?.map { trackToSubtitle(it) } ?: emptyList()
return if (vidList.isNotEmpty()) {
VideoContainer(vidList, subList)
@ -686,7 +684,7 @@ class VideoServerPassthrough(val videoServer: VideoServer) : VideoExtractor() {
}
}
private fun AniVideoToSaiVideo(aniVideo: Video): ani.dantotsu.parsers.Video {
private fun aniVideoToSaiVideo(aniVideo: Video): ani.dantotsu.parsers.Video {
// Find the number value from the .quality string
val number = Regex("""\d+""").find(aniVideo.quality)?.value?.toInt() ?: 0
@ -789,9 +787,9 @@ class VideoServerPassthrough(val videoServer: VideoServer) : VideoExtractor() {
}
private fun TrackToSubtitle(track: Track): Subtitle {
private fun trackToSubtitle(track: Track): Subtitle {
//use Dispatchers.IO to make a HTTP request to determine the subtitle type
var type: SubtitleType? = null
var type: SubtitleType?
runBlocking {
type = findSubtitleType(track.url)
}

View file

@ -4,6 +4,7 @@ import android.net.Uri
import android.os.Environment
import ani.dantotsu.currContext
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.media.MediaType
import ani.dantotsu.media.anime.AnimeNameAdapter
import ani.dantotsu.tryWithSuspend
import eu.kanade.tachiyomi.animesource.model.SAnime
@ -132,16 +133,16 @@ class OfflineVideoExtractor(val videoServer: VideoServer) : VideoExtractor() {
currContext()?.let {
DownloadsManager.getDirectory(
it,
ani.dantotsu.download.DownloadedType.Type.ANIME,
MediaType.ANIME,
title,
episode
).listFiles()?.forEach {
if (it.name.contains("subtitle")) {
).listFiles()?.forEach { file ->
if (file.name.contains("subtitle")) {
return listOf(
Subtitle(
"Downloaded Subtitle",
Uri.fromFile(it).toString(),
determineSubtitletype(it.absolutePath)
Uri.fromFile(file).toString(),
determineSubtitletype(file.absolutePath)
)
)
}

View file

@ -1,7 +1,6 @@
package ani.dantotsu.parsers.novel
import android.os.FileObserver
import android.util.Log
import ani.dantotsu.parsers.novel.FileObserver.fileObserver
import ani.dantotsu.util.Logger
import java.io.File

View file

@ -10,7 +10,6 @@ import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.util.Log
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.net.toUri
@ -63,7 +62,7 @@ internal class NovelExtensionInstaller(private val context: Context) {
* @param url The url of the apk.
* @param extension The extension to install.
*/
fun downloadAndInstall(url: String, extension: NovelExtension) = Observable.defer {
fun downloadAndInstall(url: String, extension: NovelExtension): Observable<InstallStep> = Observable.defer {
val pkgName = extension.pkgName
val oldDownload = activeDownloads[pkgName]

View file

@ -5,11 +5,10 @@ import android.content.pm.PackageInfo
import android.content.pm.PackageManager.GET_SIGNATURES
import android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES
import android.os.Build
import android.util.Log
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.util.Logger
import ani.dantotsu.parsers.NovelInterface
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
import dalvik.system.PathClassLoader
import eu.kanade.tachiyomi.util.lang.Hash
import uy.kohesive.injekt.Injekt
@ -134,10 +133,10 @@ internal object NovelExtensionLoader {
}
Logger.log("isFileWritable: ${file.canWrite()}")
val classLoader = PathClassLoader(file.absolutePath, null, context.classLoader)
val className =
val extensionClassName =
"some.random.novelextensions.${className.lowercase(Locale.getDefault())}.$className"
val loadedClass = classLoader.loadClass(className)
val instance = loadedClass.newInstance()
val loadedClass = classLoader.loadClass(extensionClassName)
val instance = loadedClass.getDeclaredConstructor().newInstance()
val novelInterfaceInstance = instance as? NovelInterface
listOfNotNull(novelInterfaceInstance)
} catch (e: Exception) {

View file

@ -34,6 +34,7 @@ import ani.dantotsu.setSlideIn
import ani.dantotsu.setSlideUp
import ani.dantotsu.util.AniMarkdown.Companion.getFullAniHTML
import ani.dantotsu.util.Logger
import eu.kanade.tachiyomi.util.system.getSerializableCompat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -58,7 +59,7 @@ class ProfileFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
activity = requireActivity() as ProfileActivity
user = arguments?.getSerializable("user") as Query.UserProfile
user = arguments?.getSerializableCompat<Query.UserProfile>("user") as Query.UserProfile
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
model.setData(user.id)
}

View file

@ -20,6 +20,7 @@ import ani.dantotsu.profile.ChartBuilder.Companion.StatType
import ani.dantotsu.statusBarHeight
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartType
import com.xwray.groupie.GroupieAdapter
import eu.kanade.tachiyomi.util.system.getSerializableCompat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -48,7 +49,7 @@ class StatsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
activity = requireActivity() as ProfileActivity
user = arguments?.getSerializable("user") as Query.UserProfile
user = arguments?.getSerializableCompat<Query.UserProfile>("user") as Query.UserProfile
binding.statisticList.adapter = adapter
binding.statisticList.recycledViewPool.setMaxRecycledViews(0, 0)
@ -95,7 +96,7 @@ class StatsFragment :
}
} else {
stats.removeAll(
stats.filter { it?.id == Anilist.userid }
stats.filter { it?.id == Anilist.userid }.toSet()
)
loadStats(type == MediaType.ANIME)
}
@ -445,6 +446,7 @@ class StatsFragment :
}.toMutableList()
chartPackets.clear()
chartPackets.addAll(standardizedPackets)
@Suppress("UNCHECKED_CAST")
val genreChart = ChartBuilder.buildChart(
activity,
ChartType.TwoDimensional,
@ -499,6 +501,7 @@ class StatsFragment :
}.toMutableList()
chartPackets.clear()
chartPackets.addAll(standardizedPackets)
@Suppress("UNCHECKED_CAST")
val tagChart = ChartBuilder.buildChart(
activity,
ChartType.TwoDimensional,
@ -553,6 +556,7 @@ class StatsFragment :
}.toMutableList()
chartPackets.clear()
chartPackets.addAll(standardizedPackets)
@Suppress("UNCHECKED_CAST")
val countryChart = ChartBuilder.buildChart(
activity,
ChartType.OneDimensional,
@ -609,6 +613,7 @@ class StatsFragment :
}.toMutableList()
chartPackets.clear()
chartPackets.addAll(standardizedPackets)
@Suppress("UNCHECKED_CAST")
val voiceActorsChart = ChartBuilder.buildChart(
activity,
ChartType.TwoDimensional,
@ -663,6 +668,7 @@ class StatsFragment :
}.toMutableList()
chartPackets.clear()
chartPackets.addAll(standardizedPackets)
@Suppress("UNCHECKED_CAST")
val studioChart = ChartBuilder.buildChart(
activity,
ChartType.TwoDimensional,
@ -720,6 +726,7 @@ class StatsFragment :
}.toMutableList()
chartPackets.clear()
chartPackets.addAll(standardizedPackets)
@Suppress("UNCHECKED_CAST")
val staffChart = ChartBuilder.buildChart(
activity,
ChartType.TwoDimensional,

View file

@ -61,7 +61,7 @@ class FeedActivity : AppCompatActivity() {
}
})
binding.listBack.setOnClickListener {
onBackPressed()
onBackPressedDispatcher.onBackPressed()
}
}

View file

@ -58,7 +58,7 @@ class NotificationActivity : AppCompatActivity() {
binding.followerGrid.visibility = ViewGroup.GONE
binding.followerList.visibility = ViewGroup.GONE
binding.listBack.setOnClickListener {
onBackPressed()
onBackPressedDispatcher.onBackPressed()
}
binding.listProgressBar.visibility = ViewGroup.VISIBLE
val activityId = intent.getIntExtra("activityId", -1)

View file

@ -46,7 +46,6 @@ import ani.dantotsu.databinding.ActivitySettingsAboutBinding
import ani.dantotsu.databinding.ActivitySettingsAccountsBinding
import ani.dantotsu.databinding.ActivitySettingsAnimeBinding
import ani.dantotsu.databinding.ActivitySettingsBinding
import ani.dantotsu.download.DownloadedType
import ani.dantotsu.databinding.ActivitySettingsCommonBinding
import ani.dantotsu.databinding.ActivitySettingsExtensionsBinding
import ani.dantotsu.databinding.ActivitySettingsMangaBinding
@ -57,7 +56,7 @@ import ani.dantotsu.download.video.ExoplayerDownloadService
import ani.dantotsu.downloadsPermission
import ani.dantotsu.initActivity
import ani.dantotsu.loadImage
import ani.dantotsu.util.Logger
import ani.dantotsu.media.MediaType
import ani.dantotsu.navBarHeight
import ani.dantotsu.notifications.TaskScheduler
import ani.dantotsu.notifications.anilist.AnilistNotificationWorker
@ -81,6 +80,7 @@ import ani.dantotsu.startMainActivity
import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.toast
import ani.dantotsu.util.Logger
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textfield.TextInputEditText
import eltos.simpledialogfragment.SimpleDialog
@ -151,13 +151,13 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
salt
)
} catch (e: Exception) {
toast("Incorrect password")
toast(getString(R.string.incorrect_password))
return@passwordAlertDialog
}
if (PreferencePackager.unpack(decryptedJson))
restartApp()
} else {
toast("Password cannot be empty")
toast(getString(R.string.password_cannot_be_empty))
}
}
} else if (name.endsWith(".ani")) {
@ -165,11 +165,11 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
if (PreferencePackager.unpack(decryptedJson))
restartApp()
} else {
toast("Unknown file type")
toast(getString(R.string.unknown_file_type))
}
} catch (e: Exception) {
e.printStackTrace()
toast("Error importing settings")
toast(getString(R.string.error_importing_settings))
}
}
}
@ -254,7 +254,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
}
val tag = "colorPicker"
CustomColorDialog().title("Custom Theme")
CustomColorDialog().title(R.string.custom_theme)
.colorPreset(originalColor)
.colors(this, SimpleColorDialog.MATERIAL_COLOR_PALLET)
.allowCustom(true)
@ -271,7 +271,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
val managers = arrayOf("Default", "1DM", "ADM")
val downloadManagerDialog =
AlertDialog.Builder(this, R.style.MyPopup).setTitle("Download Manager")
AlertDialog.Builder(this, R.style.MyPopup).setTitle(R.string.download_manager)
var downloadManager: Int = PrefManager.getVal(PrefName.DownloadManager)
bindingCommon.settingsDownloadManager.setOnClickListener {
val dialog = downloadManagerDialog.setSingleChoiceItems(
@ -291,7 +291,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
val filteredLocations = Location.entries.filter { it.exportable }
selectedArray.addAll(List(filteredLocations.size - 1) { false })
val dialog = AlertDialog.Builder(this, R.style.MyPopup)
.setTitle("Import/Export Settings")
.setTitle(R.string.import_export_settings)
.setMultiChoiceItems(
filteredLocations.map { it.name }.toTypedArray(),
selectedArray.toBooleanArray()
@ -346,7 +346,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
.setMessage(getString(R.string.purge_confirm, getString(R.string.anime)))
.setPositiveButton(R.string.yes) { dialog, _ ->
val downloadsManager = Injekt.get<DownloadsManager>()
downloadsManager.purgeDownloads(DownloadedType.Type.ANIME)
downloadsManager.purgeDownloads(MediaType.ANIME)
DownloadService.sendRemoveAllDownloads(
this,
ExoplayerDownloadService::class.java,
@ -354,7 +354,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
)
dialog.dismiss()
}
.setNegativeButton("No") { dialog, _ ->
.setNegativeButton(R.string.no) { dialog, _ ->
dialog.dismiss()
}
.create()
@ -368,10 +368,10 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
.setMessage(getString(R.string.purge_confirm, getString(R.string.manga)))
.setPositiveButton(R.string.yes) { dialog, _ ->
val downloadsManager = Injekt.get<DownloadsManager>()
downloadsManager.purgeDownloads(DownloadedType.Type.MANGA)
downloadsManager.purgeDownloads(MediaType.MANGA)
dialog.dismiss()
}
.setNegativeButton("No") { dialog, _ ->
.setNegativeButton(R.string.no) { dialog, _ ->
dialog.dismiss()
}
.create()
@ -385,10 +385,10 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
.setMessage(getString(R.string.purge_confirm, getString(R.string.novels)))
.setPositiveButton(R.string.yes) { dialog, _ ->
val downloadsManager = Injekt.get<DownloadsManager>()
downloadsManager.purgeDownloads(DownloadedType.Type.NOVEL)
downloadsManager.purgeDownloads(MediaType.NOVEL)
dialog.dismiss()
}
.setNegativeButton("No") { dialog, _ ->
.setNegativeButton(R.string.no) { dialog, _ ->
dialog.dismiss()
}
.create()
@ -423,16 +423,16 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
val alertDialog = AlertDialog.Builder(this, R.style.MyPopup)
.setTitle("User Agent")
.setView(dialogView)
.setPositiveButton("OK") { dialog, _ ->
.setPositiveButton(getString(R.string.ok)) { dialog, _ ->
PrefManager.setVal(PrefName.DefaultUserAgent, editText.text.toString())
dialog.dismiss()
}
.setNeutralButton("Reset") { dialog, _ ->
.setNeutralButton(getString(R.string.reset)) { dialog, _ ->
PrefManager.removeVal(PrefName.DefaultUserAgent)
editText.setText("")
dialog.dismiss()
}
.setNegativeButton("Cancel") { dialog, _ ->
.setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
dialog.dismiss()
}
.create()
@ -613,7 +613,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
lifecycleScope.launch {
it.pop()
}
openLinkInBrowser("https://www.buymeacoffee.com/rebelonion")
openLinkInBrowser(getString(R.string.coffee))
}
lifecycleScope.launch {
binding.settingBuyMeCoffee.pop()
@ -905,7 +905,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
if (MAL.token != null) {
bindingAccounts.settingsMALLogin.setText(R.string.logout)
bindingAccounts.settingsMALLogin.setOnClickListener {
MAL.removeSavedToken(it.context)
MAL.removeSavedToken()
restartMainActivity.isEnabled = true
reload()
}
@ -1060,7 +1060,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
box?.setSingleLine()
val dialog = AlertDialog.Builder(this, R.style.MyPopup)
.setTitle("Enter Password")
.setTitle(getString(R.string.enter_password))
.setView(dialogView)
.setPositiveButton("OK", null)
.setNegativeButton("Cancel") { dialog, _ ->
@ -1076,7 +1076,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
dialog.dismiss()
callback(password)
} else {
toast("Password cannot be empty")
toast(getString(R.string.password_cannot_be_empty))
}
}
box?.setOnEditorActionListener { _, actionId, _ ->
@ -1090,7 +1090,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
val subtitleTextView = dialogView.findViewById<TextView>(R.id.subtitle)
subtitleTextView?.visibility = View.VISIBLE
if (!isExporting)
subtitleTextView?.text = "Enter your password to decrypt the file"
subtitleTextView?.text = getString(R.string.enter_password_to_decrypt_file)
dialog.window?.setDimAmount(0.8f)

View file

@ -12,7 +12,6 @@ import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import ani.dantotsu.BottomSheetDialogFragment
import ani.dantotsu.MainActivity
import ani.dantotsu.profile.ProfileActivity
import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.databinding.BottomSheetSettingsBinding
@ -25,13 +24,15 @@ import ani.dantotsu.home.MangaFragment
import ani.dantotsu.home.NoInternet
import ani.dantotsu.incognitoNotification
import ani.dantotsu.loadImage
import ani.dantotsu.profile.activity.NotificationActivity
import ani.dantotsu.offline.OfflineFragment
import ani.dantotsu.profile.ProfileActivity
import ani.dantotsu.profile.activity.FeedActivity
import ani.dantotsu.profile.activity.NotificationActivity
import ani.dantotsu.setSafeOnClickListener
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.startMainActivity
import eu.kanade.tachiyomi.util.system.getSerializableCompat
import java.util.Timer
import kotlin.concurrent.schedule
@ -42,7 +43,7 @@ class SettingsDialogFragment : BottomSheetDialogFragment() {
private lateinit var pageType: PageType
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
pageType = arguments?.getSerializable("pageType") as? PageType ?: PageType.HOME
pageType = arguments?.getSerializableCompat("pageType") as? PageType ?: PageType.HOME
}
override fun onCreateView(

View file

@ -41,13 +41,14 @@ import kotlinx.coroutines.withContext
class NovelExtensionsViewModelFactory(
private val novelExtensionManager: NovelExtensionManager
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return NovelExtensionsViewModel(novelExtensionManager) as T
}
}
class NovelExtensionsViewModel(
private val novelExtensionManager: NovelExtensionManager
novelExtensionManager: NovelExtensionManager
) : ViewModel() {
private val searchQuery = MutableStateFlow("")
private var currentPagingSource: NovelExtensionPagingSource? = null
@ -102,21 +103,20 @@ class NovelExtensionPagingSource(
} else {
availableExtensions.filter { it.name.contains(query, ignoreCase = true) }
}
val filternfsw = filteredExtensions
/*val filternfsw = if(isNsfwEnabled) { currently not implemented
filteredExtensions
} else {
filteredExtensions.filterNot { it.isNsfw }
}*/
return try {
val sublist = filternfsw.subList(
val sublist = filteredExtensions.subList(
fromIndex = position,
toIndex = (position + params.loadSize).coerceAtMost(filternfsw.size)
toIndex = (position + params.loadSize).coerceAtMost(filteredExtensions.size)
)
LoadResult.Page(
data = sublist,
prevKey = if (position == 0) null else position - params.loadSize,
nextKey = if (position + params.loadSize >= filternfsw.size) null else position + params.loadSize
nextKey = if (position + params.loadSize >= filteredExtensions.size) null else position + params.loadSize
)
} catch (e: Exception) {
LoadResult.Error(e)

View file

@ -6,7 +6,7 @@ import ani.dantotsu.util.ColorEditor.Companion.toHexColor
class AniMarkdown { //istg anilist has the worst api
companion object {
private fun convertNestedImageToHtml(markdown: String): String {
val regex = """\[\!\[(.*?)\]\((.*?)\)\]\((.*?)\)""".toRegex()
val regex = """\[!\[(.*?)]\((.*?)\)]\((.*?)\)""".toRegex()
return regex.replace(markdown) { matchResult ->
val altText = matchResult.groupValues[1]
val imageUrl = matchResult.groupValues[2]
@ -16,7 +16,7 @@ class AniMarkdown { //istg anilist has the worst api
}
private fun convertImageToHtml(markdown: String): String {
val regex = """\!\[(.*?)\]\((.*?)\)""".toRegex()
val regex = """!\[(.*?)]\((.*?)\)""".toRegex()
return regex.replace(markdown) { matchResult ->
val altText = matchResult.groupValues[1]
val imageUrl = matchResult.groupValues[2]
@ -25,7 +25,7 @@ class AniMarkdown { //istg anilist has the worst api
}
private fun convertLinkToHtml(markdown: String): String {
val regex = """\[(.*?)\]\((.*?)\)""".toRegex()
val regex = """\[(.*?)]\((.*?)\)""".toRegex()
return regex.replace(markdown) { matchResult ->
val linkText = matchResult.groupValues[1]
val linkUrl = matchResult.groupValues[2]
@ -50,7 +50,7 @@ class AniMarkdown { //istg anilist has the worst api
private fun underlineToHtml(html: String): String {
return html.replace("(?s)___(.*?)___".toRegex(), "<br><em><strong>$1</strong></em><br>")
.replace("(?s)__(.*?)__".toRegex(), "<br><strong>$1</strong><br>")
.replace("(?s)[\\s]+_([^_]+)_[\\s]+".toRegex(), "<em>$1</em>")
.replace("(?s)\\s+_([^_]+)_\\s+".toRegex(), "<em>$1</em>")
}
fun getBasicAniHTML(html: String): String {

View file

@ -1,7 +1,6 @@
package ani.dantotsu.widgets
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.widget.RemoteViews
@ -12,7 +11,7 @@ import java.io.InputStream
import java.net.HttpURLConnection
import java.net.URL
class CurrentlyAiringRemoteViewsFactory(private val context: Context, intent: Intent) :
class CurrentlyAiringRemoteViewsFactory(private val context: Context) :
RemoteViewsService.RemoteViewsFactory {
private var widgetItems = mutableListOf<WidgetItem>()

View file

@ -7,6 +7,6 @@ import ani.dantotsu.util.Logger
class CurrentlyAiringRemoteViewsService : RemoteViewsService() {
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
Logger.log("CurrentlyAiringRemoteViewsFactory onGetViewFactory")
return CurrentlyAiringRemoteViewsFactory(applicationContext, intent)
return CurrentlyAiringRemoteViewsFactory(applicationContext)
}
}