diff --git a/app/build.gradle b/app/build.gradle
index 4064fb4e..b4ab706b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -75,11 +75,11 @@ android {
dependencies {
- // FireBase
+// FireBase
googleImplementation platform('com.google.firebase:firebase-bom:32.7.4')
googleImplementation 'com.google.firebase:firebase-analytics-ktx:21.5.1'
googleImplementation 'com.google.firebase:firebase-crashlytics-ktx:18.6.2'
-// Core
+// Core
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.browser:browser:1.8.0'
implementation 'androidx.core:core-ktx:1.12.0'
@@ -96,7 +96,7 @@ dependencies {
implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.webkit:webkit:1.10.0'
-// Glide
+// Glide
ext.glide_version = '4.16.0'
api "com.github.bumptech.glide:glide:$glide_version"
implementation "com.github.bumptech.glide:glide:$glide_version"
@@ -104,7 +104,7 @@ dependencies {
implementation "com.github.bumptech.glide:okhttp3-integration:$glide_version"
implementation 'jp.wasabeef:glide-transformations:4.3.0'
-// Exoplayer
+// Exoplayer
ext.exo_version = '1.3.0'
implementation "androidx.media3:media3-exoplayer:$exo_version"
implementation "androidx.media3:media3-ui:$exo_version"
@@ -112,14 +112,13 @@ dependencies {
implementation "androidx.media3:media3-exoplayer-dash:$exo_version"
implementation "androidx.media3:media3-datasource-okhttp:$exo_version"
implementation "androidx.media3:media3-session:$exo_version"
- //media3 casting
+// Media3 Casting
implementation "androidx.media3:media3-cast:$exo_version"
- implementation "androidx.mediarouter:mediarouter:1.6.0"
+ implementation "androidx.mediarouter:mediarouter:1.7.0"
-// UI
+// UI
implementation 'com.google.android.material:material:1.11.0'
- //implementation 'nl.joery.animatedbottombar:library:1.1.0'
- implementation 'com.github.rebelonion:AnimatedBottomBar:v1.1.0'
+ implementation 'com.github.RepoDevil:AnimatedBottomBar:7fcb9af'
implementation 'com.flaviofaria:kenburnsview:1.0.7'
implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
implementation 'com.alexvasilkov:gesture-views:2.8.3'
@@ -128,7 +127,7 @@ dependencies {
implementation 'com.github.eltos:simpledialogfragments:v3.7'
implementation 'com.github.AAChartModel:AAChartCore-Kotlin:93972bc'
- // Markwon
+// Markwon
ext.markwon_version = '4.6.2'
implementation "io.noties.markwon:core:$markwon_version"
implementation "io.noties.markwon:editor:$markwon_version"
@@ -138,15 +137,15 @@ dependencies {
implementation "io.noties.markwon:html:$markwon_version"
implementation "io.noties.markwon:image-glide:$markwon_version"
-// Groupie
+// Groupie
ext.groupie_version = '2.10.1'
implementation "com.github.lisawray.groupie:groupie:$groupie_version"
implementation "com.github.lisawray.groupie:groupie-viewbinding:$groupie_version"
-// string matching
+// String Matching
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
-// Aniyomi
+// Aniyomi
implementation 'io.reactivex:rxjava:1.3.8'
implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'ru.beryukhov:flowreactivenetwork:1.0.4'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index cf650323..7cc2e732 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -19,7 +19,7 @@
+ android:maxSdkVersion="29" />
@@ -53,11 +53,13 @@
android:label="@string/app_name"
android:largeHeap="true"
android:requestLegacyExternalStorage="true"
+ android:enableOnBackInvokedCallback="true"
android:roundIcon="${icon_placeholder_round}"
android:supportsRtl="true"
android:theme="@style/Theme.Dantotsu"
android:usesCleartextTraffic="true"
- tools:ignore="AllowBackup">
+ tools:ignore="AllowBackup"
+ tools:targetApi="tiramisu">
@@ -117,6 +119,7 @@
-
@@ -354,11 +353,7 @@
-
(context: Context, layoutId: Int, items: List) :
ArrayAdapter(context, layoutId, items) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
diff --git a/app/src/main/java/ani/dantotsu/MainActivity.kt b/app/src/main/java/ani/dantotsu/MainActivity.kt
index 23d8e508..8a45b6e3 100644
--- a/app/src/main/java/ani/dantotsu/MainActivity.kt
+++ b/app/src/main/java/ani/dantotsu/MainActivity.kt
@@ -5,7 +5,6 @@ import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Intent
import android.content.res.Configuration
-import android.content.res.Resources
import android.graphics.drawable.Animatable
import android.graphics.drawable.GradientDrawable
import android.net.Uri
@@ -14,7 +13,6 @@ import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.provider.Settings
-import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -161,16 +159,16 @@ class MainActivity : AppCompatActivity() {
}
}
- val _bottomBar = findViewById(R.id.navbar)
+ val bottomNavBar = findViewById(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")
@@ -339,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
@@ -364,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(
@@ -467,18 +465,12 @@ class MainActivity : AppCompatActivity() {
window.navigationBarColor = ContextCompat.getColor(this, android.R.color.transparent)
}
- private val Int.toPx get() = TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics
- ).toInt()
-
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
+ val margin = if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) 8 else 32
val params : ViewGroup.MarginLayoutParams =
binding.includedNavbar.navbar.layoutParams as ViewGroup.MarginLayoutParams
- if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
- params.updateMargins(bottom = 8.toPx)
- else
- params.updateMargins(bottom = 32.toPx)
+ params.updateMargins(bottom = margin.toPx)
}
private fun passwordAlertDialog(callback: (CharArray?) -> Unit) {
diff --git a/app/src/main/java/ani/dantotsu/Network.kt b/app/src/main/java/ani/dantotsu/Network.kt
index aa71cb48..91840b3e 100644
--- a/app/src/main/java/ani/dantotsu/Network.kt
+++ b/app/src/main/java/ani/dantotsu/Network.kt
@@ -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
lateinit var okHttpClient: OkHttpClient
lateinit var client: Requests
-fun initializeNetwork(context: Context) {
+fun initializeNetwork() {
val networkHelper = Injekt.get()
diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
index c83fd07f..b0088286 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
@@ -387,6 +387,7 @@ class AnilistQueries {
returnArray.addAll(map.values)
return returnArray
}
+ @Suppress("UNCHECKED_CAST")
val list = PrefManager.getNullableCustomVal(
"continueAnimeList",
listOf(),
@@ -544,6 +545,7 @@ class AnilistQueries {
returnMap["current$type"] = returnArray
return
}
+ @Suppress("UNCHECKED_CAST")
val list = PrefManager.getNullableCustomVal(
"continueAnimeList",
listOf(),
@@ -573,6 +575,7 @@ class AnilistQueries {
subMap[m.id] = m
}
}
+ @Suppress("UNCHECKED_CAST")
val list = PrefManager.getNullableCustomVal(
"continueAnimeList",
listOf(),
@@ -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) {
diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistViewModel.kt b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistViewModel.kt
index 5eb28a79..a4092b91 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistViewModel.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistViewModel.kt
@@ -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 = animePopular
suspend fun loadPopular(
type: String,
- search_val: String? = null,
+ searchVal: String? = null,
genres: ArrayList? = 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 = mangaPopular
suspend fun loadPopular(
type: String,
- search_val: String? = null,
+ searchVal: String? = null,
genres: ArrayList? = 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
diff --git a/app/src/main/java/ani/dantotsu/connections/discord/Discord.kt b/app/src/main/java/ani/dantotsu/connections/discord/Discord.kt
index ea34f1bf..0a2f7b3f 100644
--- a/app/src/main/java/ani/dantotsu/connections/discord/Discord.kt
+++ b/app/src/main/java/ani/dantotsu/connections/discord/Discord.kt
@@ -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)
}
diff --git a/app/src/main/java/ani/dantotsu/connections/discord/DiscordService.kt b/app/src/main/java/ani/dantotsu/connections/discord/DiscordService.kt
index 0a29ab60..7f2c23b0 100644
--- a/app/src/main/java/ani/dantotsu/connections/discord/DiscordService.kt
+++ b/app/src/main/java/ani/dantotsu/connections/discord/DiscordService.kt
@@ -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) { }
}
}
diff --git a/app/src/main/java/ani/dantotsu/connections/discord/Login.kt b/app/src/main/java/ani/dantotsu/connections/discord/Login.kt
index 676f11e2..513da55b 100644
--- a/app/src/main/java/ani/dantotsu/connections/discord/Login.kt
+++ b/app/src/main/java/ani/dantotsu/connections/discord/Login.kt
@@ -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)
}
diff --git a/app/src/main/java/ani/dantotsu/connections/mal/MAL.kt b/app/src/main/java/ani/dantotsu/connections/mal/MAL.kt
index 9eaffdca..770d0e05 100644
--- a/app/src/main/java/ani/dantotsu/connections/mal/MAL.kt
+++ b/app/src/main/java/ani/dantotsu/connections/mal/MAL.kt
@@ -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(PrefName.MALToken, null)
@@ -77,7 +76,7 @@ object MAL {
} ?: false
}
- fun removeSavedToken(context: Context) {
+ fun removeSavedToken() {
token = null
username = null
userid = null
diff --git a/app/src/main/java/ani/dantotsu/download/DownloadsManager.kt b/app/src/main/java/ani/dantotsu/download/DownloadsManager.kt
index 0cbfa1bc..4eb7f5a3 100644
--- a/app/src/main/java/ani/dantotsu/download/DownloadsManager.kt
+++ b/app/src/main/java/ani/dantotsu/download/DownloadsManager.kt
@@ -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
- get() = downloadsList.filter { it.type == DownloadedType.Type.MANGA }
+ get() = downloadsList.filter { it.type == MediaType.MANGA }
val animeDownloadedTypes: List
- get() = downloadsList.filter { it.type == DownloadedType.Type.ANIME }
+ get() = downloadsList.filter { it.type == MediaType.ANIME }
val novelDownloadedTypes: List
- 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
diff --git a/app/src/main/java/ani/dantotsu/download/anime/AnimeDownloaderService.kt b/app/src/main/java/ani/dantotsu/download/anime/AnimeDownloaderService.kt
index 22b20dcb..fc498743 100644
--- a/app/src/main/java/ani/dantotsu/download/anime/AnimeDownloaderService.kt
+++ b/app/src/main/java/ani/dantotsu/download/anime/AnimeDownloaderService.kt
@@ -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().logException(
@@ -302,7 +303,7 @@ class AnimeDownloaderService : Service() {
DownloadedType(
task.title,
task.episode,
- DownloadedType.Type.ANIME,
+ MediaType.ANIME,
)
)
currentTasks.removeAll { it.getTaskName() == task.getTaskName() }
diff --git a/app/src/main/java/ani/dantotsu/download/anime/OfflineAnimeAdapter.kt b/app/src/main/java/ani/dantotsu/download/anime/OfflineAnimeAdapter.kt
index 63cc384a..3ab53d55 100644
--- a/app/src/main/java/ani/dantotsu/download/anime/OfflineAnimeAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/download/anime/OfflineAnimeAdapter.kt
@@ -1,7 +1,6 @@
package ani.dantotsu.download.anime
-import android.annotation.SuppressLint
import android.content.Context
import android.view.LayoutInflater
import android.view.View
@@ -38,7 +37,6 @@ class OfflineAnimeAdapter(
return position.toLong()
}
- @SuppressLint("SetTextI18n")
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val view: View = convertView ?: when (style) {
@@ -61,14 +59,14 @@ class OfflineAnimeAdapter(
if (style == 0) {
val bannerView = view.findViewById(R.id.itemCompactBanner) // for large view
val episodes = view.findViewById(R.id.itemTotal)
- episodes.text = " Episodes"
+ episodes.text = context.getString(R.string.episodes)
bannerView.setImageURI(item.banner ?: item.image)
totalepisodes.text = item.totalEpisodeList
} else if (style == 1) {
val watchedEpisodes =
view.findViewById(R.id.itemCompactUserProgress) // for compact view
watchedEpisodes.text = item.watchedEpisode
- totalepisodes.text = " | " + item.totalEpisode
+ totalepisodes.text = context.getString(R.string.total_divider, item.totalEpisode)
}
// Bind item data to the views
diff --git a/app/src/main/java/ani/dantotsu/download/anime/OfflineAnimeFragment.kt b/app/src/main/java/ani/dantotsu/download/anime/OfflineAnimeFragment.kt
index 4ff5497c..64329759 100644
--- a/app/src/main/java/ani/dantotsu/download/anime/OfflineAnimeFragment.kt
+++ b/app/src/main/java/ani/dantotsu/download/anime/OfflineAnimeFragment.kt
@@ -22,6 +22,7 @@ import androidx.annotation.OptIn
import androidx.appcompat.app.AppCompatActivity
import androidx.cardview.widget.CardView
import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
import androidx.core.view.marginBottom
import androidx.fragment.app.Fragment
import androidx.media3.common.util.UnstableApi
@@ -33,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
@@ -187,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 =
@@ -250,7 +251,7 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
val visibility = first != null && first.top < 0
scrollTop.translationY =
-(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat()
- scrollTop.visibility = if (visibility) View.VISIBLE else View.GONE
+ scrollTop.isVisible = visibility
}
})
initActivity(requireActivity())
@@ -292,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}"
@@ -326,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}"
diff --git a/app/src/main/java/ani/dantotsu/download/manga/MangaDownloaderService.kt b/app/src/main/java/ani/dantotsu/download/manga/MangaDownloaderService.kt
index 188c9dc3..9b884883 100644
--- a/app/src/main/java/ani/dantotsu/download/manga/MangaDownloaderService.kt
+++ b/app/src/main/java/ani/dantotsu/download/manga/MangaDownloaderService.kt
@@ -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)
diff --git a/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaAdapter.kt b/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaAdapter.kt
index 0bc9ef08..8c6aef99 100644
--- a/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaAdapter.kt
@@ -37,7 +37,6 @@ class OfflineMangaAdapter(
return position.toLong()
}
- @SuppressLint("SetTextI18n")
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val view: View = convertView ?: when (style) {
@@ -60,14 +59,14 @@ class OfflineMangaAdapter(
if (style == 0) {
val bannerView = view.findViewById(R.id.itemCompactBanner) // for large view
val chapters = view.findViewById(R.id.itemTotal)
- chapters.text = " Chapters"
+ chapters.text = context.getString(R.string.chapters)
bannerView.setImageURI(item.banner ?: item.image)
totalChapter.text = item.totalChapter
} else if (style == 1) {
val readChapter =
view.findViewById(R.id.itemCompactUserProgress) // for compact view
readChapter.text = item.readChapter
- totalChapter.text = " | " + item.totalChapter
+ totalChapter.text = context.getString(R.string.total_divider, item.totalChapter)
}
// Bind item data to the views
diff --git a/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaFragment.kt b/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaFragment.kt
index 0c97a8df..99250edf 100644
--- a/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaFragment.kt
+++ b/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaFragment.kt
@@ -20,6 +20,7 @@ import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.cardview.widget.CardView
import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
import androidx.core.view.marginBottom
import androidx.fragment.app.Fragment
import ani.dantotsu.R
@@ -30,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
@@ -178,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 =
@@ -234,7 +236,7 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
) {
val first = view.getChildAt(0)
val visibility = first != null && first.top < 0
- scrollTop.visibility = if (visibility) View.VISIBLE else View.GONE
+ scrollTop.isVisible = visibility
scrollTop.translationY =
-(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat()
}
@@ -288,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}"
@@ -316,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}"
diff --git a/app/src/main/java/ani/dantotsu/download/novel/NovelDownloaderService.kt b/app/src/main/java/ani/dantotsu/download/novel/NovelDownloaderService.kt
index 0c3575a3..9cb46d31 100644
--- a/app/src/main/java/ani/dantotsu/download/novel/NovelDownloaderService.kt
+++ b/app/src/main/java/ani/dantotsu/download/novel/NovelDownloaderService.kt
@@ -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)
diff --git a/app/src/main/java/ani/dantotsu/download/video/Helper.kt b/app/src/main/java/ani/dantotsu/download/video/Helper.kt
index 4e82e76c..6cb688fa 100644
--- a/app/src/main/java/ani/dantotsu/download/video/Helper.kt
+++ b/app/src/main/java/ani/dantotsu/download/video/Helper.kt
@@ -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()
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)
diff --git a/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt b/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt
index 2c60b3ac..43c7db04 100644
--- a/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt
@@ -10,6 +10,7 @@ import android.view.ViewGroup
import android.view.animation.LayoutAnimationController
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.lifecycle.MutableLiveData
@@ -21,6 +22,7 @@ import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.currContext
import ani.dantotsu.databinding.ItemAnimePageBinding
+import ani.dantotsu.databinding.LayoutTrendingBinding
import ani.dantotsu.loadImage
import ani.dantotsu.media.CalendarActivity
import ani.dantotsu.media.GenreActivity
@@ -41,6 +43,7 @@ import com.google.android.material.textfield.TextInputLayout
class AnimePageAdapter : RecyclerView.Adapter() {
val ready = MutableLiveData(false)
lateinit var binding: ItemAnimePageBinding
+ private lateinit var trendingBinding: LayoutTrendingBinding
private var trendHandler: Handler? = null
private lateinit var trendRun: Runnable
var trendingViewPager: ViewPager2? = null
@@ -53,14 +56,15 @@ class AnimePageAdapter : RecyclerView.Adapter(R.id.animeSearchBar)
+ val textInputLayout = holder.itemView.findViewById(R.id.searchBar)
val currentColor = textInputLayout.boxBackgroundColor
val semiTransparentColor = (currentColor and 0x00FFFFFF) or 0xA8000000.toInt()
textInputLayout.boxBackgroundColor = semiTransparentColor
val materialCardView =
- holder.itemView.findViewById(R.id.animeUserAvatarContainer)
+ holder.itemView.findViewById(R.id.userAvatarContainer)
materialCardView.setCardBackgroundColor(semiTransparentColor)
val typedValue = TypedValue()
currContext()?.theme?.resolveAttribute(android.R.attr.windowBackground, typedValue, true)
@@ -69,33 +73,29 @@ class AnimePageAdapter : RecyclerView.Adapter {
+ if (PrefManager.getVal(PrefName.SmallView)) trendingBinding.trendingContainer.updateLayoutParams {
bottomMargin = (-108f).px
}
updateAvatar()
- binding.animeSearchBar.hint = "ANIME"
- binding.animeSearchBarText.setOnClickListener {
+ trendingBinding.searchBar.hint = "ANIME"
+ trendingBinding.searchBarText.setOnClickListener {
ContextCompat.startActivity(
it.context,
- Intent(it.context, SearchActivity::class.java).putExtra("type", "ANIME"),
+ Intent(it.context, SearchActivity::class.java).putExtra("type", "MANGA"),
null
)
}
- binding.animeSearchBar.setEndIconOnClickListener {
- binding.animeSearchBarText.performClick()
- }
-
- binding.animeUserAvatar.setSafeOnClickListener {
+ trendingBinding.userAvatar.setSafeOnClickListener {
val dialogFragment =
SettingsDialogFragment.newInstance(SettingsDialogFragment.Companion.PageType.ANIME)
dialogFragment.show((it.context as AppCompatActivity).supportFragmentManager, "dialog")
}
- binding.animeUserAvatar.setOnLongClickListener { view ->
+ trendingBinding.userAvatar.setOnLongClickListener { view ->
ContextCompat.startActivity(
view.context,
Intent(view.context, ProfileActivity::class.java)
@@ -104,8 +104,12 @@ class AnimePageAdapter : RecyclerView.Adapter 0) View.VISIBLE else View.GONE
- binding.animeNotificationCount.text = Anilist.unreadNotificationCount.toString()
+ trendingBinding.searchBar.setEndIconOnClickListener {
+ trendingBinding.searchBar.performClick()
+ }
+
+ trendingBinding.notificationCount.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE
+ trendingBinding.notificationCount.text = Anilist.unreadNotificationCount.toString()
listOf(
binding.animePreviousSeason,
@@ -134,8 +138,7 @@ class AnimePageAdapter : RecyclerView.Adapter 0) View.VISIBLE else View.GONE
- binding.animeNotificationCount.text = Anilist.unreadNotificationCount.toString()
+ trendingBinding.notificationCount.text = Anilist.unreadNotificationCount.toString()
}
}
diff --git a/app/src/main/java/ani/dantotsu/home/HomeFragment.kt b/app/src/main/java/ani/dantotsu/home/HomeFragment.kt
index fae3fedf..917d0fec 100644
--- a/app/src/main/java/ani/dantotsu/home/HomeFragment.kt
+++ b/app/src/main/java/ani/dantotsu/home/HomeFragment.kt
@@ -10,6 +10,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.animation.LayoutAnimationController
import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
@@ -81,7 +82,7 @@ class HomeFragment : Fragment() {
if (!(PrefManager.getVal(PrefName.BannerAnimations) as Boolean)) binding.homeUserBg.pause()
blurImage(binding.homeUserBg, Anilist.bg)
binding.homeUserDataProgressBar.visibility = View.GONE
- binding.homeNotificationCount.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE
+ binding.homeNotificationCount.isVisible = Anilist.unreadNotificationCount > 0
binding.homeNotificationCount.text = Anilist.unreadNotificationCount.toString()
binding.homeAnimeList.setOnClickListener {
@@ -375,7 +376,7 @@ class HomeFragment : Fragment() {
override fun onResume() {
if (!model.loaded) Refresh.activity[1]!!.postValue(true)
if (_binding != null) {
- binding.homeNotificationCount.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE
+ binding.homeNotificationCount.isVisible = Anilist.unreadNotificationCount > 0
binding.homeNotificationCount.text = Anilist.unreadNotificationCount.toString()
}
super.onResume()
diff --git a/app/src/main/java/ani/dantotsu/home/MangaPageAdapter.kt b/app/src/main/java/ani/dantotsu/home/MangaPageAdapter.kt
index 2aef3b6b..7ca0687f 100644
--- a/app/src/main/java/ani/dantotsu/home/MangaPageAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/home/MangaPageAdapter.kt
@@ -10,6 +10,7 @@ import android.view.ViewGroup
import android.view.animation.LayoutAnimationController
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.lifecycle.MutableLiveData
@@ -21,6 +22,7 @@ import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.currContext
import ani.dantotsu.databinding.ItemMangaPageBinding
+import ani.dantotsu.databinding.LayoutTrendingBinding
import ani.dantotsu.loadImage
import ani.dantotsu.media.GenreActivity
import ani.dantotsu.media.MediaAdaptor
@@ -40,6 +42,7 @@ import com.google.android.material.textfield.TextInputLayout
class MangaPageAdapter : RecyclerView.Adapter() {
val ready = MutableLiveData(false)
lateinit var binding: ItemMangaPageBinding
+ private lateinit var trendingBinding: LayoutTrendingBinding
private var trendHandler: Handler? = null
private lateinit var trendRun: Runnable
var trendingViewPager: ViewPager2? = null
@@ -52,33 +55,34 @@ class MangaPageAdapter : RecyclerView.Adapter(R.id.mangaSearchBar)
+ val textInputLayout = holder.itemView.findViewById(R.id.searchBar)
val currentColor = textInputLayout.boxBackgroundColor
val semiTransparentColor = (currentColor and 0x00FFFFFF) or 0xA8000000.toInt()
textInputLayout.boxBackgroundColor = semiTransparentColor
val materialCardView =
- holder.itemView.findViewById(R.id.mangaUserAvatarContainer)
+ holder.itemView.findViewById(R.id.userAvatarContainer)
materialCardView.setCardBackgroundColor(semiTransparentColor)
val typedValue = TypedValue()
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)
+ trendingBinding.titleContainer.updatePadding(top = statusBarHeight)
- if (PrefManager.getVal(PrefName.SmallView)) binding.mangaTrendingContainer.updateLayoutParams {
+ if (PrefManager.getVal(PrefName.SmallView)) trendingBinding.trendingContainer.updateLayoutParams {
bottomMargin = (-108f).px
}
updateAvatar()
- binding.mangaNotificationCount.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE
- binding.mangaNotificationCount.text = Anilist.unreadNotificationCount.toString()
- binding.mangaSearchBar.hint = "MANGA"
- binding.mangaSearchBarText.setOnClickListener {
+ trendingBinding.notificationCount.isVisible = Anilist.unreadNotificationCount > 0
+ trendingBinding.notificationCount.text = Anilist.unreadNotificationCount.toString()
+ trendingBinding.searchBar.hint = "MANGA"
+ trendingBinding.searchBarText.setOnClickListener {
ContextCompat.startActivity(
it.context,
Intent(it.context, SearchActivity::class.java).putExtra("type", "MANGA"),
@@ -86,12 +90,12 @@ class MangaPageAdapter : RecyclerView.Adapter
+ trendingBinding.userAvatar.setOnLongClickListener { view ->
ContextCompat.startActivity(
view.context,
Intent(view.context, ProfileActivity::class.java)
@@ -100,8 +104,8 @@ class MangaPageAdapter : RecyclerView.Adapter 0) View.VISIBLE else View.GONE
- binding.mangaNotificationCount.text = Anilist.unreadNotificationCount.toString()
+ trendingBinding.notificationCount.text = Anilist.unreadNotificationCount.toString()
}
}
diff --git a/app/src/main/java/ani/dantotsu/media/AuthorAdapter.kt b/app/src/main/java/ani/dantotsu/media/AuthorAdapter.kt
index 35195960..431c5ddd 100644
--- a/app/src/main/java/ani/dantotsu/media/AuthorAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/media/AuthorAdapter.kt
@@ -24,7 +24,6 @@ class AuthorAdapter(
return AuthorViewHolder(binding)
}
- @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder:AuthorViewHolder, position: Int) {
val binding = holder.binding
setAnimation(binding.root.context, holder.binding.root)
diff --git a/app/src/main/java/ani/dantotsu/media/CalendarActivity.kt b/app/src/main/java/ani/dantotsu/media/CalendarActivity.kt
index bbe66477..1a9d73e5 100644
--- a/app/src/main/java/ani/dantotsu/media/CalendarActivity.kt
+++ b/app/src/main/java/ani/dantotsu/media/CalendarActivity.kt
@@ -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
@@ -34,7 +33,6 @@ class CalendarActivity : AppCompatActivity() {
private var selectedTabIdx = 1
private val model: OtherDetailsViewModel by viewModels()
- @SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -74,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 {
topMargin = statusBarHeight
}
diff --git a/app/src/main/java/ani/dantotsu/media/CharacterAdapter.kt b/app/src/main/java/ani/dantotsu/media/CharacterAdapter.kt
index d8c4961c..78eeb273 100644
--- a/app/src/main/java/ani/dantotsu/media/CharacterAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/media/CharacterAdapter.kt
@@ -24,12 +24,12 @@ class CharacterAdapter(
return CharacterViewHolder(binding)
}
- @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: CharacterViewHolder, position: Int) {
val binding = holder.binding
setAnimation(binding.root.context, holder.binding.root)
val character = characterList[position]
- binding.itemCompactRelation.text = character.role + " "
+ val whitespace = "${character.role} "
+ binding.itemCompactRelation.text = whitespace
binding.itemCompactImage.loadImage(character.image)
binding.itemCompactTitle.text = character.name
}
diff --git a/app/src/main/java/ani/dantotsu/media/CharacterDetailsActivity.kt b/app/src/main/java/ani/dantotsu/media/CharacterDetailsActivity.kt
index 4778f708..11db3506 100644
--- a/app/src/main/java/ani/dantotsu/media/CharacterDetailsActivity.kt
+++ b/app/src/main/java/ani/dantotsu/media/CharacterDetailsActivity.kt
@@ -8,6 +8,7 @@ import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.math.MathUtils.clamp
+import androidx.core.view.isGone
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.lifecycle.MutableLiveData
@@ -152,7 +153,7 @@ class CharacterDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChang
}
override fun onResume() {
- binding.characterProgress.visibility = if (!loaded) View.VISIBLE else View.GONE
+ binding.characterProgress.isGone = loaded
super.onResume()
}
diff --git a/app/src/main/java/ani/dantotsu/media/CharacterDetailsAdapter.kt b/app/src/main/java/ani/dantotsu/media/CharacterDetailsAdapter.kt
index 2e419492..5c78feb0 100644
--- a/app/src/main/java/ani/dantotsu/media/CharacterDetailsAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/media/CharacterDetailsAdapter.kt
@@ -20,15 +20,16 @@ class CharacterDetailsAdapter(private val character: Character, private val acti
return GenreViewHolder(binding)
}
- @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: GenreViewHolder, position: Int) {
val binding = holder.binding
val desc =
- (if (character.age != "null") currActivity()!!.getString(R.string.age) + " " + character.age else "") +
- (if (character.dateOfBirth.toString() != "") currActivity()!!.getString(R.string.birthday) + " " + character.dateOfBirth.toString() else "") +
- (if (character.gender != "null") currActivity()!!.getString(R.string.gender) + " " + when (character.gender) {
- "Male" -> currActivity()!!.getString(R.string.male)
- "Female" -> currActivity()!!.getString(R.string.female)
+ (if (character.age != "null") "${currActivity()!!.getString(R.string.age)} ${character.age}" else "") +
+ (if (character.dateOfBirth.toString() != "")
+ "${currActivity()!!.getString(R.string.birthday)} ${character.dateOfBirth.toString()}" else "") +
+ (if (character.gender != "null")
+ currActivity()!!.getString(R.string.gender) + " " + when (character.gender) {
+ currActivity()!!.getString(R.string.male) -> currActivity()!!.getString(R.string.male)
+ currActivity()!!.getString(R.string.female) -> currActivity()!!.getString(R.string.female)
else -> character.gender
} else "") + "\n" + character.description
diff --git a/app/src/main/java/ani/dantotsu/media/MediaAdaptor.kt b/app/src/main/java/ani/dantotsu/media/MediaAdaptor.kt
index 8c415e2d..aebd8dbf 100644
--- a/app/src/main/java/ani/dantotsu/media/MediaAdaptor.kt
+++ b/app/src/main/java/ani/dantotsu/media/MediaAdaptor.kt
@@ -17,6 +17,7 @@ import androidx.core.app.ActivityOptionsCompat
import androidx.core.content.ContextCompat
import androidx.core.util.Pair
import androidx.core.view.ViewCompat
+import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView
@@ -85,7 +86,7 @@ class MediaAdaptor(
}
- @SuppressLint("SetTextI18n", "ClickableViewAccessibility")
+ @SuppressLint("ClickableViewAccessibility")
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (type) {
0 -> {
@@ -94,8 +95,8 @@ class MediaAdaptor(
val media = mediaList?.getOrNull(position)
if (media != null) {
b.itemCompactImage.loadImage(media.cover)
- b.itemCompactOngoing.visibility =
- if (media.status == currActivity()!!.getString(R.string.status_releasing)) View.VISIBLE else View.GONE
+ b.itemCompactOngoing.isVisible =
+ media.status == currActivity()!!.getString(R.string.status_releasing)
b.itemCompactTitle.text = media.userPreferredName
b.itemCompactScore.text =
((if (media.userScore == 0) (media.meanScore
@@ -140,8 +141,8 @@ class MediaAdaptor(
if (media != null) {
b.itemCompactImage.loadImage(media.cover)
blurImage(b.itemCompactBanner, media.banner ?: media.cover)
- b.itemCompactOngoing.visibility =
- if (media.status == currActivity()!!.getString(R.string.status_releasing)) View.VISIBLE else View.GONE
+ b.itemCompactOngoing.isVisible =
+ media.status == currActivity()!!.getString(R.string.status_releasing)
b.itemCompactTitle.text = media.userPreferredName
b.itemCompactScore.text =
((if (media.userScore == 0) (media.meanScore
@@ -188,8 +189,8 @@ class MediaAdaptor(
)
)
blurImage(b.itemCompactBanner, media.banner ?: media.cover)
- b.itemCompactOngoing.visibility =
- if (media.status == currActivity()!!.getString(R.string.status_releasing)) View.VISIBLE else View.GONE
+ b.itemCompactOngoing.isVisible =
+ media.status == currActivity()!!.getString(R.string.status_releasing)
b.itemCompactTitle.text = media.userPreferredName
b.itemCompactScore.text =
((if (media.userScore == 0) (media.meanScore
@@ -237,8 +238,8 @@ class MediaAdaptor(
)
)
blurImage(b.itemCompactBanner, media.banner ?: media.cover)
- b.itemCompactOngoing.visibility =
- if (media.status == currActivity()!!.getString(R.string.status_releasing)) View.VISIBLE else View.GONE
+ b.itemCompactOngoing.isVisible =
+ media.status == currActivity()!!.getString(R.string.status_releasing)
b.itemCompactTitle.text = media.userPreferredName
b.itemCompactScore.text =
((if (media.userScore == 0) (media.meanScore
diff --git a/app/src/main/java/ani/dantotsu/media/MediaDetailsActivity.kt b/app/src/main/java/ani/dantotsu/media/MediaDetailsActivity.kt
index 9a528b80..38ded425 100644
--- a/app/src/main/java/ani/dantotsu/media/MediaDetailsActivity.kt
+++ b/app/src/main/java/ani/dantotsu/media/MediaDetailsActivity.kt
@@ -2,9 +2,9 @@ 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
import android.os.Bundle
import android.text.SpannableStringBuilder
import android.util.TypedValue
@@ -12,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
@@ -22,8 +20,10 @@ import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import androidx.core.text.bold
import androidx.core.text.color
+import androidx.core.view.isVisible
import androidx.core.view.marginBottom
import androidx.core.view.updateLayoutParams
+import androidx.core.view.updateMargins
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
@@ -62,6 +62,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
+import nl.joery.animatedbottombar.AnimatedBottomBar
import kotlin.math.abs
@@ -70,12 +71,12 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
lateinit var binding: ActivityMediaBinding
private val scope = lifecycleScope
private val model: MediaDetailsViewModel by viewModels()
- lateinit var tabLayout: TripleNavAdapter
var selected = 0
+ lateinit var navBar: AnimatedBottomBar
var anime = true
private var adult = false
- @SuppressLint("SetTextI18n", "ClickableViewAccessibility")
+ @SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
var media: Media = intent.getSerialized("media") ?: mediaSingleton ?: emptyMedia()
@@ -83,8 +84,7 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
if (id != -1) {
runBlocking {
withContext(Dispatchers.IO) {
- media =
- Anilist.query.getMedia(id, false) ?: emptyMedia()
+ media = Anilist.query.getMedia(id, false) ?: emptyMedia()
}
}
}
@@ -100,26 +100,34 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
binding = ActivityMediaBinding.inflate(layoutInflater)
setContentView(binding.root)
screenWidth = resources.displayMetrics.widthPixels.toFloat()
+ navBar = binding.mediaBottomBar
- val isVertical = resources.configuration.orientation
- //Ui init
+ // Ui init
initActivity(this)
- binding.mediaViewPager.updateLayoutParams { bottomMargin += navBarHeight }
+ binding.mediaViewPager.updateLayoutParams { bottomMargin = navBarHeight }
val oldMargin = binding.mediaViewPager.marginBottom
AndroidBug5497Workaround.assistActivity(this) {
if (it) {
binding.mediaViewPager.updateLayoutParams {
bottomMargin = 0
}
- binding.mediaTabContainer.visibility = View.GONE
+ navBar.visibility = View.GONE
} else {
binding.mediaViewPager.updateLayoutParams {
bottomMargin = oldMargin
}
- binding.mediaTabContainer.visibility = View.VISIBLE
+ navBar.visibility = View.VISIBLE
}
}
+ val navBarRightMargin = if (resources.configuration.orientation ==
+ Configuration.ORIENTATION_LANDSCAPE) navBarHeight else 0
+ val navBarBottomMargin = if (resources.configuration.orientation ==
+ Configuration.ORIENTATION_LANDSCAPE) 0 else navBarHeight
+ navBar.updateLayoutParams {
+ rightMargin = navBarRightMargin
+ bottomMargin = navBarBottomMargin
+ }
binding.mediaBanner.updateLayoutParams { height += statusBarHeight }
binding.mediaBannerNoKen.updateLayoutParams { height += statusBarHeight }
binding.mediaClose.updateLayoutParams { topMargin += statusBarHeight }
@@ -147,7 +155,6 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
val banner =
if (bannerAnimations) binding.mediaBanner else binding.mediaBannerNoKen
val viewPager = binding.mediaViewPager
- //tabLayout = binding.mediaTab as AnimatedBottomBar
viewPager.isUserInputEnabled = false
viewPager.setPageTransformer(ZoomOutPageTransformer())
@@ -157,9 +164,10 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
binding.mediaCoverImage.loadImage(media.cover)
binding.mediaCoverImage.setOnLongClickListener {
+ val coverTitle = "${media.userPreferredName}[Cover]"
ImageViewDialog.newInstance(
this,
- media.userPreferredName + "[Cover]",
+ coverTitle,
media.cover
)
}
@@ -176,9 +184,10 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
}
override fun onLongClick(event: MotionEvent) {
+ val bannerTitle = "${media.userPreferredName}[Banner]"
ImageViewDialog.newInstance(
this@MediaDetailsActivity,
- media.userPreferredName + "[Banner]",
+ bannerTitle,
media.banner ?: media.cover
)
banner.performClick()
@@ -186,7 +195,8 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
})
banner.setOnTouchListener { _, motionEvent -> gestureDetector.onTouchEvent(motionEvent);true }
if (PrefManager.getVal(PrefName.Incognito)) {
- binding.mediaTitle.text = " ${media.userPreferredName}"
+ val mediaTitle = " ${media.userPreferredName}"
+ binding.mediaTitle.text = mediaTitle
binding.incognito.visibility = View.VISIBLE
} else {
binding.mediaTitle.text = media.userPreferredName
@@ -246,13 +256,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()
@@ -342,14 +352,6 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
progress()
}
}
- tabLayout = TripleNavAdapter(
- binding.mediaTab1,
- binding.mediaTab2,
- binding.mediaTab3,
- media.anime != null,
- media.format ?: "",
- isVertical == 1
- )
adult = media.isAdult
if (media.anime != null) {
viewPager.adapter =
@@ -365,22 +367,36 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
anime = false
}
-
selected = media.selected!!.window
binding.mediaTitle.translationX = -screenWidth
- tabLayout.selectionListener = { selected, newId ->
- binding.commentInputLayout.visibility = if (selected == 2) View.VISIBLE else View.GONE
- this.selected = selected
- selectFromID(newId)
- viewPager.setCurrentItem(selected, false)
- val sel = model.loadSelected(media, isDownload)
- sel.window = selected
- model.saveSelected(media.id, sel)
+ val infoTab = navBar.createTab(R.drawable.ic_round_info_24, R.string.info, R.id.info)
+ val watchTab = if (anime) {
+ navBar.createTab(R.drawable.ic_round_movie_filter_24, R.string.watch, R.id.watch)
+ } else if (media.format == "NOVEL") {
+ navBar.createTab(R.drawable.ic_round_book_24, R.string.read, R.id.read)
+ } else {
+ navBar.createTab(R.drawable.ic_round_import_contacts_24, R.string.read, R.id.read)
}
- tabLayout.selectTab(selected)
- selectFromID(tabLayout.selected)
- viewPager.setCurrentItem(selected, false)
+ val commentTab = navBar.createTab(R.drawable.ic_round_comment_24, R.string.comments, R.id.comment)
+ navBar.addTab(infoTab)
+ navBar.addTab(watchTab)
+ navBar.addTab(commentTab)
+ navBar.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener {
+ override fun onTabSelected(
+ lastIndex: Int,
+ lastTab: AnimatedBottomBar.Tab?,
+ newIndex: Int,
+ newTab: AnimatedBottomBar.Tab
+ ) {
+ selected = newIndex
+ binding.commentInputLayout.isVisible = selected == 2
+ viewPager.setCurrentItem(selected, true)
+ val sel = model.loadSelected(media, isDownload)
+ sel.window = selected
+ model.saveSelected(media.id, sel)
+ }
+ })
if (model.continueMedia == null && media.cameFromContinue) {
model.continueMedia = PrefManager.getVal(PrefName.ContinueMedia)
@@ -390,6 +406,9 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
if (frag != null) {
selected = 2
}
+ navBar.selectTabAt(selected)
+ binding.commentInputLayout.isVisible = selected == 2
+ viewPager.setCurrentItem(selected, false)
val live = Refresh.activity.getOrPut(this.hashCode()) { MutableLiveData(true) }
live.observe(this) {
@@ -402,40 +421,19 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
}
}
- private fun selectFromID(id: Int) {
- when (id) {
- R.id.info -> {
- selected = 0
- }
-
- R.id.watch, R.id.read -> {
- selected = 1
- }
-
- R.id.comment -> {
- selected = 2
- }
- }
- }
-
- private fun idFromSelect(): Int {
- if (anime) when (selected) {
- 0 -> return R.id.info
- 1 -> return R.id.watch
- 2 -> return R.id.comment
- }
- else when (selected) {
- 0 -> return R.id.info
- 1 -> return R.id.read
- 2 -> return R.id.comment
- }
- return R.id.info
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ val rightMargin = if (resources.configuration.orientation ==
+ Configuration.ORIENTATION_LANDSCAPE) navBarHeight else 0
+ val bottomMargin = if (resources.configuration.orientation ==
+ Configuration.ORIENTATION_LANDSCAPE) 0 else navBarHeight
+ val params : ViewGroup.MarginLayoutParams =
+ navBar.layoutParams as ViewGroup.MarginLayoutParams
+ params.updateMargins(right = rightMargin, bottom = bottomMargin)
}
override fun onResume() {
- if (this::tabLayout.isInitialized) {
- tabLayout.selectTab(selected)
- }
+ navBar.selectTabAt(selected)
super.onResume()
}
@@ -443,7 +441,7 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
ANIME, MANGA, NOVEL
}
- //ViewPager
+ // ViewPager
private class ViewPagerAdapter(
fragmentManager: FragmentManager,
lifecycle: Lifecycle,
@@ -602,4 +600,4 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
companion object {
var mediaSingleton: Media? = null
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/ani/dantotsu/media/MediaDetailsViewModel.kt b/app/src/main/java/ani/dantotsu/media/MediaDetailsViewModel.kt
index 650e722d..b9d005e3 100644
--- a/app/src/main/java/ani/dantotsu/media/MediaDetailsViewModel.kt
+++ b/app/src/main/java/ani/dantotsu/media/MediaDetailsViewModel.kt
@@ -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)
}
}
}
diff --git a/app/src/main/java/ani/dantotsu/media/MediaInfoFragment.kt b/app/src/main/java/ani/dantotsu/media/MediaInfoFragment.kt
index 1cec1eb6..ecd0e537 100644
--- a/app/src/main/java/ani/dantotsu/media/MediaInfoFragment.kt
+++ b/app/src/main/java/ani/dantotsu/media/MediaInfoFragment.kt
@@ -16,6 +16,8 @@ import android.widget.TextView
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.core.text.HtmlCompat
+import androidx.core.view.isGone
+import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
@@ -37,7 +39,7 @@ import java.io.Serializable
import java.net.URLEncoder
-@SuppressLint("SetTextI18n")
+
class MediaInfoFragment : Fragment() {
private var _binding: FragmentMediaInfoBinding? = null
private val binding get() = _binding!!
@@ -46,6 +48,8 @@ class MediaInfoFragment : Fragment() {
private var type = "ANIME"
private val genreModel: GenresViewModel by activityViewModels()
+ private val tripleTab = "\t\t\t"
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -63,8 +67,8 @@ class MediaInfoFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val model: MediaDetailsViewModel by activityViewModels()
val offline: Boolean = PrefManager.getVal(PrefName.OfflineMode)
- binding.mediaInfoProgressBar.visibility = if (!loaded) View.VISIBLE else View.GONE
- binding.mediaInfoContainer.visibility = if (loaded) View.VISIBLE else View.GONE
+ binding.mediaInfoProgressBar.isGone = loaded
+ binding.mediaInfoContainer.isVisible = loaded
binding.mediaInfoContainer.updateLayoutParams { bottomMargin += 128f.px + navBarHeight }
model.scrolledToTop.observe(viewLifecycleOwner) {
@@ -78,14 +82,16 @@ class MediaInfoFragment : Fragment() {
binding.mediaInfoProgressBar.visibility = View.GONE
binding.mediaInfoContainer.visibility = View.VISIBLE
- binding.mediaInfoName.text = "\t\t\t" + (media.name ?: media.nameRomaji)
+ val infoName = tripleTab + (media.name ?: media.nameRomaji)
+ binding.mediaInfoName.text = infoName
binding.mediaInfoName.setOnLongClickListener {
copyToClipboard(media.name ?: media.nameRomaji)
true
}
if (media.name != null) binding.mediaInfoNameRomajiContainer.visibility =
View.VISIBLE
- binding.mediaInfoNameRomaji.text = "\t\t\t" + media.nameRomaji
+ val infoNameRomanji = tripleTab + media.nameRomaji
+ binding.mediaInfoNameRomaji.text = infoNameRomanji
binding.mediaInfoNameRomaji.setOnLongClickListener {
copyToClipboard(media.nameRomaji)
true
@@ -127,8 +133,9 @@ class MediaInfoFragment : Fragment() {
}
binding.mediaInfoDurationContainer.visibility = View.VISIBLE
binding.mediaInfoSeasonContainer.visibility = View.VISIBLE
- binding.mediaInfoSeason.text =
- (media.anime.season ?: "??") + " " + (media.anime.seasonYear ?: "??")
+ val seasonInfo = "${(media.anime.season ?: "??")} ${(media.anime.seasonYear ?: "??")}"
+ binding.mediaInfoSeason.text = seasonInfo
+
if (media.anime.mainStudio != null) {
binding.mediaInfoStudioContainer.visibility = View.VISIBLE
binding.mediaInfoStudio.text = media.anime.mainStudio!!.name
@@ -162,9 +169,12 @@ class MediaInfoFragment : Fragment() {
}
}
binding.mediaInfoTotalTitle.setText(R.string.total_eps)
- binding.mediaInfoTotal.text =
- if (media.anime.nextAiringEpisode != null) (media.anime.nextAiringEpisode.toString() + " | " + (media.anime.totalEpisodes
- ?: "~").toString()) else (media.anime.totalEpisodes ?: "~").toString()
+ val infoTotal = if (media.anime.nextAiringEpisode != null)
+ "${media.anime.nextAiringEpisode} | ${media.anime.totalEpisodes ?: "~"}"
+ else
+ (media.anime.totalEpisodes ?: "~").toString()
+ binding.mediaInfoTotal.text = infoTotal
+
} else if (media.manga != null) {
type = "MANGA"
binding.mediaInfoTotalTitle.setText(R.string.total_chaps)
@@ -191,8 +201,9 @@ class MediaInfoFragment : Fragment() {
(media.description ?: "null").replace("\\n", "
").replace("\\\"", "\""),
HtmlCompat.FROM_HTML_MODE_LEGACY
)
- binding.mediaInfoDescription.text =
- "\t\t\t" + if (desc.toString() != "null") desc else getString(R.string.no_description_available)
+ val infoDesc = tripleTab + if (desc.toString() != "null") desc else getString(R.string.no_description_available)
+ binding.mediaInfoDescription.text = infoDesc
+
binding.mediaInfoDescription.setOnClickListener {
if (binding.mediaInfoDescription.maxLines == 5) {
ObjectAnimator.ofInt(binding.mediaInfoDescription, "maxLines", 100)
@@ -550,7 +561,7 @@ class MediaInfoFragment : Fragment() {
}
override fun onResume() {
- binding.mediaInfoProgressBar.visibility = if (!loaded) View.VISIBLE else View.GONE
+ binding.mediaInfoProgressBar.isGone = loaded
super.onResume()
}
diff --git a/app/src/main/java/ani/dantotsu/media/MediaListDialogFragment.kt b/app/src/main/java/ani/dantotsu/media/MediaListDialogFragment.kt
index 0430709b..e8c15685 100644
--- a/app/src/main/java/ani/dantotsu/media/MediaListDialogFragment.kt
+++ b/app/src/main/java/ani/dantotsu/media/MediaListDialogFragment.kt
@@ -36,7 +36,6 @@ class MediaListDialogFragment : BottomSheetDialogFragment() {
return binding.root
}
- @SuppressLint("SetTextI18n")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.mediaListContainer.updateLayoutParams { bottomMargin += navBarHeight }
var media: Media?
@@ -168,9 +167,10 @@ class MediaListDialogFragment : BottomSheetDialogFragment() {
val init =
if (binding.mediaListProgress.text.toString() != "") binding.mediaListProgress.text.toString()
.toInt() else 0
- if (init < (total
- ?: 5000)
- ) binding.mediaListProgress.setText((init + 1).toString())
+ if (init < (total ?: 5000)) {
+ val progressText = "${init + 1}"
+ binding.mediaListProgress.setText(progressText)
+ }
if (init + 1 == (total ?: 5000)) {
binding.mediaListStatus.setText(statusStrings[2], false)
onComplete()
diff --git a/app/src/main/java/ani/dantotsu/media/MediaListDialogSmallFragment.kt b/app/src/main/java/ani/dantotsu/media/MediaListDialogSmallFragment.kt
index 982eca8e..8848c125 100644
--- a/app/src/main/java/ani/dantotsu/media/MediaListDialogSmallFragment.kt
+++ b/app/src/main/java/ani/dantotsu/media/MediaListDialogSmallFragment.kt
@@ -54,7 +54,6 @@ class MediaListDialogSmallFragment : BottomSheetDialogFragment() {
}
- @SuppressLint("SetTextI18n")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.mediaListContainer.updateLayoutParams { bottomMargin += navBarHeight }
val scope = viewLifecycleOwner.lifecycleScope
@@ -68,7 +67,7 @@ class MediaListDialogSmallFragment : BottomSheetDialogFragment() {
MAL.query.deleteList(media.anime != null, media.idMAL)
} catch (e: Exception) {
withContext(Dispatchers.Main) {
- snackString("Failed to delete because of... ${e.message}")
+ snackString(getString(R.string.delete_fail_reason, e.message))
}
return@withContext
}
@@ -154,7 +153,10 @@ class MediaListDialogSmallFragment : BottomSheetDialogFragment() {
val init =
if (binding.mediaListProgress.text.toString() != "") binding.mediaListProgress.text.toString()
.toInt() else 0
- if (init < (total ?: 5000)) binding.mediaListProgress.setText((init + 1).toString())
+ if (init < (total ?: 5000)) {
+ val progressText = "${init + 1}"
+ binding.mediaListProgress.setText(progressText)
+ }
if (init + 1 == (total ?: 5000)) {
binding.mediaListStatus.setText(statusStrings[2], false)
}
diff --git a/app/src/main/java/ani/dantotsu/media/MediaType.kt b/app/src/main/java/ani/dantotsu/media/MediaType.kt
new file mode 100644
index 00000000..6762d98e
--- /dev/null
+++ b/app/src/main/java/ani/dantotsu/media/MediaType.kt
@@ -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 }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/media/ProgressAdapter.kt b/app/src/main/java/ani/dantotsu/media/ProgressAdapter.kt
index 081d47fc..eb11c29f 100644
--- a/app/src/main/java/ani/dantotsu/media/ProgressAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/media/ProgressAdapter.kt
@@ -27,7 +27,7 @@ class ProgressAdapter(private val horizontal: Boolean = true, searched: Boolean)
return ProgressViewHolder(binding)
}
- @SuppressLint("SetTextI18n", "ClickableViewAccessibility")
+ @SuppressLint("ClickableViewAccessibility")
override fun onBindViewHolder(holder: ProgressViewHolder, position: Int) {
val progressBar = holder.binding.root
bar = progressBar
diff --git a/app/src/main/java/ani/dantotsu/media/SearchActivity.kt b/app/src/main/java/ani/dantotsu/media/SearchActivity.kt
index 33403915..e1915f22 100644
--- a/app/src/main/java/ani/dantotsu/media/SearchActivity.kt
+++ b/app/src/main/java/ani/dantotsu/media/SearchActivity.kt
@@ -6,6 +6,7 @@ import android.os.Parcelable
import android.view.View
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.isVisible
import androidx.core.view.updatePaddingRelative
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ConcatAdapter
@@ -137,7 +138,7 @@ class SearchActivity : AppCompatActivity() {
model.searchResults.results.addAll(it.results)
mediaAdaptor.notifyItemRangeInserted(prev, it.results.size)
- progressAdapter.bar?.visibility = if (it.hasNextPage) View.VISIBLE else View.GONE
+ progressAdapter.bar?.isVisible = it.hasNextPage
}
}
diff --git a/app/src/main/java/ani/dantotsu/media/SourceAdapter.kt b/app/src/main/java/ani/dantotsu/media/SourceAdapter.kt
index c1dd18b2..e56adde6 100644
--- a/app/src/main/java/ani/dantotsu/media/SourceAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/media/SourceAdapter.kt
@@ -1,6 +1,5 @@
package ani.dantotsu.media
-import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
@@ -22,7 +21,6 @@ abstract class SourceAdapter(
return SourceViewHolder(binding)
}
- @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: SourceViewHolder, position: Int) {
val binding = holder.binding
val character = sources[position]
diff --git a/app/src/main/java/ani/dantotsu/media/SourceSearchDialogFragment.kt b/app/src/main/java/ani/dantotsu/media/SourceSearchDialogFragment.kt
index 3925bcce..06b784e8 100644
--- a/app/src/main/java/ani/dantotsu/media/SourceSearchDialogFragment.kt
+++ b/app/src/main/java/ani/dantotsu/media/SourceSearchDialogFragment.kt
@@ -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!!]
diff --git a/app/src/main/java/ani/dantotsu/media/StudioActivity.kt b/app/src/main/java/ani/dantotsu/media/StudioActivity.kt
index ac28cd5f..a90caeb4 100644
--- a/app/src/main/java/ani/dantotsu/media/StudioActivity.kt
+++ b/app/src/main/java/ani/dantotsu/media/StudioActivity.kt
@@ -6,6 +6,7 @@ import android.view.ViewGroup
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
+import androidx.core.view.isGone
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.lifecycle.MutableLiveData
@@ -114,7 +115,7 @@ class StudioActivity : AppCompatActivity() {
}
override fun onResume() {
- binding.studioProgressBar.visibility = if (!loaded) View.VISIBLE else View.GONE
+ binding.studioProgressBar.isGone = loaded
super.onResume()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/media/SubtitleDownloader.kt b/app/src/main/java/ani/dantotsu/media/SubtitleDownloader.kt
index e5ebd81b..6672f37d 100644
--- a/app/src/main/java/ani/dantotsu/media/SubtitleDownloader.kt
+++ b/app/src/main/java/ani/dantotsu/media/SubtitleDownloader.kt
@@ -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()
@@ -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()
diff --git a/app/src/main/java/ani/dantotsu/media/TripleNavAdapter.kt b/app/src/main/java/ani/dantotsu/media/TripleNavAdapter.kt
deleted file mode 100644
index b76a0dff..00000000
--- a/app/src/main/java/ani/dantotsu/media/TripleNavAdapter.kt
+++ /dev/null
@@ -1,136 +0,0 @@
-package ani.dantotsu.media
-
-import android.graphics.Color
-import android.view.ViewGroup
-import androidx.core.view.updateLayoutParams
-import ani.dantotsu.R
-import ani.dantotsu.navBarHeight
-import nl.joery.animatedbottombar.AnimatedBottomBar
-
-class TripleNavAdapter(
- private val nav1: AnimatedBottomBar,
- private val nav2: AnimatedBottomBar,
- private val nav3: AnimatedBottomBar,
- anime: Boolean,
- format: String,
- private val isScreenVertical: Boolean = false
-) {
- var selected: Int = 0
- var selectionListener: ((Int, Int) -> Unit)? = null
- init {
- nav1.tabs.clear()
- nav2.tabs.clear()
- nav3.tabs.clear()
- val infoTab = nav1.createTab(R.drawable.ic_round_info_24, R.string.info, R.id.info)
- val watchTab = if (anime) {
- nav2.createTab(R.drawable.ic_round_movie_filter_24, R.string.watch, R.id.watch)
- } else if (format == "NOVEL") {
- nav2.createTab(R.drawable.ic_round_book_24, R.string.read, R.id.read)
- } else {
- nav2.createTab(R.drawable.ic_round_import_contacts_24, R.string.read, R.id.read)
- }
- val commentTab = nav3.createTab(R.drawable.ic_round_comment_24, R.string.comments, R.id.comment)
- nav1.addTab(infoTab)
- nav1.visibility = ViewGroup.VISIBLE
- if (isScreenVertical) {
- nav2.visibility = ViewGroup.GONE
- nav3.visibility = ViewGroup.GONE
- nav1.addTab(watchTab)
- nav1.addTab(commentTab)
- nav1.updateLayoutParams {
- bottomMargin = navBarHeight
- }
- nav2.updateLayoutParams {
- bottomMargin = navBarHeight
- }
- nav3.updateLayoutParams {
- bottomMargin = navBarHeight
- }
- } else {
- nav1.indicatorColor = Color.TRANSPARENT
- nav2.indicatorColor = Color.TRANSPARENT
- nav3.indicatorColor = Color.TRANSPARENT
- nav2.visibility = ViewGroup.VISIBLE
- nav3.visibility = ViewGroup.VISIBLE
- nav2.addTab(watchTab)
- nav3.addTab(commentTab)
- nav2.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener {
- override fun onTabSelected(
- lastIndex: Int,
- lastTab: AnimatedBottomBar.Tab?,
- newIndex: Int,
- newTab: AnimatedBottomBar.Tab
- ) {
- selected = 1
- deselectOthers(selected)
- selectionListener?.invoke(selected, newTab.id)
- }
- })
- nav3.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener {
- override fun onTabSelected(
- lastIndex: Int,
- lastTab: AnimatedBottomBar.Tab?,
- newIndex: Int,
- newTab: AnimatedBottomBar.Tab
- ) {
- selected = 2
- deselectOthers(selected)
- selectionListener?.invoke(selected, newTab.id)
- }
- })
- }
- nav1.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener {
- override fun onTabSelected(
- lastIndex: Int,
- lastTab: AnimatedBottomBar.Tab?,
- newIndex: Int,
- newTab: AnimatedBottomBar.Tab
- ) {
- if (!isScreenVertical) {
- selected = 0
- deselectOthers(selected)
- } else selected = newIndex
- selectionListener?.invoke(selected, newTab.id)
- }
- })
- }
-
- private fun deselectOthers(selected: Int) {
- if (selected == 0) {
- nav2.clearSelection()
- nav3.clearSelection()
- }
- if (selected == 1) {
- nav1.clearSelection()
- nav3.clearSelection()
- }
- if (selected == 2) {
- nav1.clearSelection()
- nav2.clearSelection()
- }
- }
-
- fun selectTab(tab: Int) {
- selected = tab
- if (!isScreenVertical) {
- when (tab) {
- 0 -> nav1.selectTabAt(0)
- 1 -> nav2.selectTabAt(0)
- 2 -> nav3.selectTabAt(0)
- }
- deselectOthers(selected)
- } else {
- nav1.selectTabAt(selected)
- }
- }
-
- fun setVisibility(visibility: Int) {
- if (isScreenVertical) {
- nav1.visibility = visibility
- return
- }
- nav1.visibility = visibility
- nav2.visibility = visibility
- nav3.visibility = visibility
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/media/anime/AnimeNameAdapter.kt b/app/src/main/java/ani/dantotsu/media/anime/AnimeNameAdapter.kt
index ad8c378e..16142902 100644
--- a/app/src/main/java/ani/dantotsu/media/anime/AnimeNameAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/media/anime/AnimeNameAdapter.kt
@@ -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 =
"(?
mr.value.replaceFirst(mr.groupValues[1], "")
diff --git a/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchAdapter.kt b/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchAdapter.kt
index 4b53fe42..3b69477f 100644
--- a/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchAdapter.kt
@@ -13,6 +13,8 @@ import android.widget.LinearLayout
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.startActivity
+import androidx.core.view.isGone
+import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import ani.dantotsu.*
@@ -54,7 +56,6 @@ class AnimeWatchAdapter(
private var nestedDialog: AlertDialog? = null
- @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val binding = holder.binding
_binding = binding
@@ -97,15 +98,12 @@ class AnimeWatchAdapter(
null
)
}
- val offline = if (!isOnline(binding.root.context) || PrefManager.getVal(
- PrefName.OfflineMode
- )
- ) View.GONE else View.VISIBLE
+ val offline = !isOnline(binding.root.context) || PrefManager.getVal(PrefName.OfflineMode)
- binding.animeSourceNameContainer.visibility = offline
- binding.animeSourceSettings.visibility = offline
- binding.animeSourceSearch.visibility = offline
- binding.animeSourceTitle.visibility = offline
+ binding.animeSourceNameContainer.isGone = offline
+ binding.animeSourceSettings.isGone = offline
+ binding.animeSourceSearch.isGone = offline
+ binding.animeSourceTitle.isGone = offline
//Source Selection
var source =
@@ -117,8 +115,7 @@ class AnimeWatchAdapter(
this.selectDub = media.selected!!.preferDub
binding.animeSourceTitle.text = showUserText
showUserTextListener = { MainScope().launch { binding.animeSourceTitle.text = it } }
- binding.animeSourceDubbedCont.visibility =
- if (isDubAvailableSeparately()) View.VISIBLE else View.GONE
+ binding.animeSourceDubbedCont.isVisible = isDubAvailableSeparately()
}
}
@@ -137,8 +134,7 @@ class AnimeWatchAdapter(
changing = true
binding.animeSourceDubbed.isChecked = selectDub
changing = false
- binding.animeSourceDubbedCont.visibility =
- if (isDubAvailableSeparately()) View.VISIBLE else View.GONE
+ binding.animeSourceDubbedCont.isVisible = isDubAvailableSeparately()
source = i
setLanguageList(0, i)
}
@@ -158,8 +154,7 @@ class AnimeWatchAdapter(
changing = true
binding.animeSourceDubbed.isChecked = selectDub
changing = false
- binding.animeSourceDubbedCont.visibility =
- if (isDubAvailableSeparately()) View.VISIBLE else View.GONE
+ binding.animeSourceDubbedCont.isVisible = isDubAvailableSeparately()
setLanguageList(i, source)
}
subscribeButton(false)
@@ -223,9 +218,9 @@ class AnimeWatchAdapter(
else -> dialogBinding.animeSourceList
}
when (style) {
- 0 -> dialogBinding.layoutText.text = "List"
- 1 -> dialogBinding.layoutText.text = "Grid"
- 2 -> dialogBinding.layoutText.text = "Compact"
+ 0 -> dialogBinding.layoutText.setText(R.string.list)
+ 1 -> dialogBinding.layoutText.setText(R.string.grid)
+ 2 -> dialogBinding.layoutText.setText(R.string.compact)
else -> dialogBinding.animeSourceList
}
selected.alpha = 1f
@@ -237,24 +232,24 @@ class AnimeWatchAdapter(
dialogBinding.animeSourceList.setOnClickListener {
selected(it as ImageButton)
style = 0
- dialogBinding.layoutText.text = "List"
+ dialogBinding.layoutText.setText(R.string.list)
run = true
}
dialogBinding.animeSourceGrid.setOnClickListener {
selected(it as ImageButton)
style = 1
- dialogBinding.layoutText.text = "Grid"
+ dialogBinding.layoutText.setText(R.string.grid)
run = true
}
dialogBinding.animeSourceCompact.setOnClickListener {
selected(it as ImageButton)
style = 2
- dialogBinding.layoutText.text = "Compact"
+ dialogBinding.layoutText.setText(R.string.compact)
run = true
}
dialogBinding.animeWebviewContainer.setOnClickListener {
if (!WebViewUtil.supportsWebView(fragment.requireContext())) {
- toast("WebView not installed")
+ toast(R.string.webview_not_installed)
}
//start CookieCatcher activity
if (watchSources.names.isNotEmpty() && source in 0 until watchSources.names.size) {
@@ -307,7 +302,6 @@ class AnimeWatchAdapter(
}
//Chips
- @SuppressLint("SetTextI18n")
fun updateChips(limit: Int, names: Array, arr: Array, selected: Int = 0) {
val binding = _binding
if (binding != null) {
@@ -329,7 +323,8 @@ class AnimeWatchAdapter(
0
)
}
- chip.text = "${names[limit * (position)]} - ${names[last - 1]}"
+ val chipText = "${names[limit * (position)]} - ${names[last - 1]}"
+ chip.text = chipText
chip.setTextColor(
ContextCompat.getColorStateList(
fragment.requireContext(),
@@ -363,7 +358,6 @@ class AnimeWatchAdapter(
_binding?.animeSourceChipGroup?.removeAllViews()
}
- @SuppressLint("SetTextI18n")
fun handleEpisodes() {
val binding = _binding
if (binding != null) {
@@ -371,9 +365,9 @@ class AnimeWatchAdapter(
val episodes = media.anime.episodes!!.keys.toTypedArray()
val anilistEp = (media.userProgress ?: 0).plus(1)
- val appEp =
- PrefManager.getCustomVal("${media.id}_current_ep", "")?.toIntOrNull()
- ?: 1
+ val appEp = PrefManager.getCustomVal(
+ "${media.id}_current_ep", ""
+ )?.toIntOrNull() ?: 1
var continueEp = (if (anilistEp > appEp) anilistEp else appEp).toString()
if (episodes.contains(continueEp)) {
@@ -409,15 +403,19 @@ class AnimeWatchAdapter(
ep.thumb ?: FileUrl[media.banner ?: media.cover], 0
)
if (ep.filler) binding.itemEpisodeFillerView.visibility = View.VISIBLE
+
binding.animeSourceContinueText.text =
- currActivity()!!.getString(R.string.continue_episode) + "${ep.number}${if (ep.filler) " - Filler" else ""}${"\n$cleanedTitle"}"
+ currActivity()!!.getString(R.string.continue_episode, ep.number, if (ep.filler)
+ currActivity()!!.getString(R.string.filler_tag)
+ else
+ "", cleanedTitle)
binding.animeSourceContinue.setOnClickListener {
fragment.onEpisodeClick(continueEp)
}
if (fragment.continueEp) {
- if ((binding.itemEpisodeProgress.layoutParams as LinearLayout.LayoutParams).weight < PrefManager.getVal(
- PrefName.WatchPercentage
- )
+ if (
+ (binding.itemEpisodeProgress.layoutParams as LinearLayout.LayoutParams)
+ .weight < PrefManager.getVal(PrefName.WatchPercentage)
) {
binding.animeSourceContinue.performClick()
fragment.continueEp = false
@@ -428,13 +426,10 @@ class AnimeWatchAdapter(
}
binding.animeSourceProgressBar.visibility = View.GONE
- if (media.anime.episodes!!.isNotEmpty()) {
- binding.animeSourceNotFound.visibility = View.GONE
- binding.faqbutton.visibility = View.GONE}
- else {
- binding.animeSourceNotFound.visibility = View.VISIBLE
- binding.faqbutton.visibility = View.VISIBLE
- }
+
+ val sourceFound = media.anime.episodes!!.isNotEmpty()
+ binding.animeSourceNotFound.isGone = sourceFound
+ binding.faqbutton.isGone = sourceFound
} else {
binding.animeSourceContinue.visibility = View.GONE
binding.animeSourceNotFound.visibility = View.GONE
diff --git a/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchFragment.kt b/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchFragment.kt
index 50eef688..28d10c6b 100644
--- a/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchFragment.kt
+++ b/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchFragment.kt
@@ -17,6 +17,8 @@ import androidx.annotation.OptIn
import androidx.cardview.widget.CardView
import androidx.core.content.ContextCompat
import androidx.core.math.MathUtils
+import androidx.core.view.isGone
+import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
@@ -27,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
@@ -340,16 +347,12 @@ class AnimeWatchFragment : Fragment() {
val changeUIVisibility: (Boolean) -> Unit = { show ->
val activity = activity
if (activity is MediaDetailsActivity && isAdded) {
- val visibility = if (show) View.VISIBLE else View.GONE
- activity.findViewById(R.id.mediaAppBar).visibility = visibility
- activity.findViewById(R.id.mediaViewPager).visibility = visibility
- activity.findViewById(R.id.mediaCover).visibility = visibility
- activity.findViewById(R.id.mediaClose).visibility = visibility
-
- activity.tabLayout.setVisibility(visibility)
-
- activity.findViewById(R.id.fragmentExtensionsContainer).visibility =
- if (show) View.GONE else View.VISIBLE
+ activity.findViewById(R.id.mediaAppBar).isVisible = show
+ activity.findViewById(R.id.mediaViewPager).isVisible = show
+ activity.findViewById(R.id.mediaCover).isVisible = show
+ activity.findViewById(R.id.mediaClose).isVisible = show
+ activity.navBar.isVisible = show
+ activity.findViewById(R.id.fragmentExtensionsContainer).isGone = show
}
}
var itemSelected = false
@@ -435,7 +438,7 @@ class AnimeWatchFragment : Fragment() {
DownloadedType(
media.mainName(),
i,
- DownloadedType.Type.ANIME
+ MediaType.ANIME
)
)
episodeAdapter.purgeDownload(i)
@@ -447,7 +450,7 @@ class AnimeWatchFragment : Fragment() {
DownloadedType(
media.mainName(),
i,
- DownloadedType.Type.ANIME
+ MediaType.ANIME
)
)
val taskName = AnimeDownloaderService.AnimeDownloadTask.getTaskName(media.mainName(), i)
diff --git a/app/src/main/java/ani/dantotsu/media/anime/EpisodeAdapters.kt b/app/src/main/java/ani/dantotsu/media/anime/EpisodeAdapters.kt
index 7a3d8aec..3f06bf4d 100644
--- a/app/src/main/java/ani/dantotsu/media/anime/EpisodeAdapters.kt
+++ b/app/src/main/java/ani/dantotsu/media/anime/EpisodeAdapters.kt
@@ -8,18 +8,21 @@ import android.view.ViewGroup
import android.view.animation.LinearInterpolator
import android.widget.LinearLayout
import androidx.annotation.OptIn
+import androidx.core.view.isVisible
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
@@ -97,7 +100,6 @@ class EpisodeAdapter(
return type
}
- @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val ep = arr[position]
val title = if (!ep.title.isNullOrEmpty() && ep.title != "null") {
@@ -125,8 +127,7 @@ class EpisodeAdapter(
binding.itemEpisodeFiller.visibility = View.GONE
binding.itemEpisodeFillerView.visibility = View.GONE
}
- binding.itemEpisodeDesc.visibility =
- if (ep.desc != null && ep.desc?.trim(' ') != "") View.VISIBLE else View.GONE
+ binding.itemEpisodeDesc.isVisible = !ep.desc.isNullOrBlank()
binding.itemEpisodeDesc.text = ep.desc ?: ""
holder.bind(ep.number, ep.downloadProgress, ep.desc)
@@ -203,8 +204,7 @@ class EpisodeAdapter(
val binding = holder.binding
setAnimation(fragment.requireContext(), holder.binding.root)
binding.itemEpisodeNumber.text = ep.number
- binding.itemEpisodeFillerView.visibility =
- if (ep.filler) View.VISIBLE else View.GONE
+ binding.itemEpisodeFillerView.isVisible = ep.filler
if (media.userProgress != null) {
if ((ep.number.toFloatOrNull() ?: 9999f) <= media.userProgress!!.toFloat())
binding.itemEpisodeViewedCover.visibility = View.VISIBLE
@@ -429,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)
}
diff --git a/app/src/main/java/ani/dantotsu/media/anime/ExoplayerView.kt b/app/src/main/java/ani/dantotsu/media/anime/ExoplayerView.kt
index 7ae06a1a..ea95e077 100644
--- a/app/src/main/java/ani/dantotsu/media/anime/ExoplayerView.kt
+++ b/app/src/main/java/ani/dantotsu/media/anime/ExoplayerView.kt
@@ -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,14 +151,17 @@ 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
@UnstableApi
-@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
+@SuppressLint("ClickableViewAccessibility")
class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityListener {
private val resumeWindow = "resumeWindow"
@@ -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
}
}
}
@@ -703,11 +757,13 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
fun seek(forward: Boolean, event: MotionEvent? = null) {
val seekTime = PrefManager.getVal(PrefName.SeekTime)
val (card, text) = if (forward) {
- forwardText.text = "+${seekTime * ++seekTimesF}"
+ val text = "+${seekTime * ++seekTimesF}"
+ forwardText.text = text
handler.post { exoPlayer.seekTo(exoPlayer.currentPosition + seekTime * 1000) }
fastForwardCard to forwardText
} else {
- rewindText.text = "-${seekTime * ++seekTimesR}"
+ val text = "-${seekTime * ++seekTimesR}"
+ rewindText.text = text
handler.post { exoPlayer.seekTo(exoPlayer.currentPosition - seekTime * 1000) }
fastRewindCard to rewindText
}
@@ -941,7 +997,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
episodeArr = episodes.keys.toList()
currentEpisodeIndex = episodeArr.indexOf(media.anime!!.selectedEpisode!!)
- episodeTitleArr = arrayListOf()
+ episodeTitleArr = arrayListOf()
episodes.forEach {
val episode = it.value
val cleanedTitle = AnimeNameAdapter.removeEpisodeNumberCompletely(episode.title ?: "")
@@ -1052,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)
)
)
)
@@ -1264,6 +1320,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
media.anime!!.selectedEpisode!!
)
+ @Suppress("UNCHECKED_CAST")
val list = (PrefManager.getNullableCustomVal("continueAnimeList", listOf(), List::class.java) as List).toMutableList()
if (list.contains(media.id)) list.remove(media.id)
list.add(media.id)
@@ -1293,7 +1350,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
}
//Subtitles
- exoSubtitle.visibility = if (ext.subtitles.isNotEmpty()) View.VISIBLE else View.GONE
+ exoSubtitle.isVisible = ext.subtitles.isNotEmpty()
exoSubtitle.setOnClickListener {
subClick()
}
@@ -1301,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)
@@ -1358,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) {
@@ -1659,7 +1714,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
aspectRatio = Rational(width, height)
- videoInfo.text = "Quality: ${height}p"
+ videoInfo.text = getString(R.string.video_quality, height)
if (exoPlayer.duration < playbackPosition)
exoPlayer.seekTo(0)
@@ -1735,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)) {
diff --git a/app/src/main/java/ani/dantotsu/media/anime/SelectorDialogFragment.kt b/app/src/main/java/ani/dantotsu/media/anime/SelectorDialogFragment.kt
index f83b22ad..22a7e097 100644
--- a/app/src/main/java/ani/dantotsu/media/anime/SelectorDialogFragment.kt
+++ b/app/src/main/java/ani/dantotsu/media/anime/SelectorDialogFragment.kt
@@ -12,6 +12,7 @@ import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
@@ -302,7 +303,6 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
)
}
- @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: UrlViewHolder, position: Int) {
val binding = holder.binding
val video = extractor.videos[position]
@@ -401,12 +401,12 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
dismiss()
}
if (video.format == VideoType.CONTAINER) {
- binding.urlSize.visibility = if (video.size != null) View.VISIBLE else View.GONE
- binding.urlSize.text =
- // if video size is null or 0, show "Unknown Size" else show the size in MB
- (if (video.extraNote != null) " : " else "") + (if (video.size == 0.0) "Unknown Size" else (DecimalFormat(
- "#.##"
- ).format(video.size ?: 0).toString() + " MB"))
+ binding.urlSize.isVisible = video.size != null
+ // if video size is null or 0, show "Unknown Size" else show the size in MB
+ val sizeText = getString(R.string.mb_size, "${if (video.extraNote != null) " : " else ""}${
+ if (video.size == 0.0) getString(R.string.size_unknown) else DecimalFormat("#.##").format(video.size ?: 0)
+ }")
+ binding.urlSize.text = sizeText
}
binding.urlNote.visibility = View.VISIBLE
binding.urlNote.text = video.format.name
diff --git a/app/src/main/java/ani/dantotsu/media/comments/CommentItem.kt b/app/src/main/java/ani/dantotsu/media/comments/CommentItem.kt
index b78d4dce..d5b887bd 100644
--- a/app/src/main/java/ani/dantotsu/media/comments/CommentItem.kt
+++ b/app/src/main/java/ani/dantotsu/media/comments/CommentItem.kt
@@ -11,6 +11,7 @@ import ani.dantotsu.connections.comments.Comment
import ani.dantotsu.connections.comments.CommentsAPI
import ani.dantotsu.copyToClipboard
import ani.dantotsu.databinding.ItemCommentsBinding
+import ani.dantotsu.getAppString
import ani.dantotsu.loadImage
import ani.dantotsu.others.ImageViewDialog
import ani.dantotsu.profile.ProfileActivity
@@ -28,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
@@ -52,7 +54,6 @@ class CommentItem(val comment: Comment,
adapter.add(repliesSection)
}
- @SuppressLint("SetTextI18n")
override fun bind(viewBinding: ItemCommentsBinding, position: Int) {
binding = viewBinding
setAnimation(binding.root.context, binding.root)
@@ -76,8 +77,15 @@ class CommentItem(val comment: Comment,
if ((comment.replyCount ?: 0) > 0) {
viewBinding.commentTotalReplies.visibility = View.VISIBLE
viewBinding.commentRepliesDivider.visibility = View.VISIBLE
- viewBinding.commentTotalReplies.text = if(repliesVisible) "Hide Replies" else
- "View ${comment.replyCount} repl${if (comment.replyCount == 1) "y" else "ies"}"
+ viewBinding.commentTotalReplies.context.run {
+ viewBinding.commentTotalReplies.text = if (repliesVisible)
+ getString(R.string.hide_replies)
+ else
+ if (comment.replyCount == 1)
+ getString(R.string.view_reply)
+ else
+ getString(R.string.view_replies_count, comment.replyCount)
+ }
} else {
viewBinding.commentTotalReplies.visibility = View.GONE
viewBinding.commentRepliesDivider.visibility = View.GONE
@@ -87,10 +95,15 @@ class CommentItem(val comment: Comment,
if (repliesVisible) {
repliesSection.clear()
removeSubCommentIds()
- viewBinding.commentTotalReplies.text = "View ${comment.replyCount} repl${if (comment.replyCount == 1) "y" else "ies"}"
+ viewBinding.commentTotalReplies.context.run {
+ viewBinding.commentTotalReplies.text = if (comment.replyCount == 1)
+ getString(R.string.view_reply)
+ else
+ getString(R.string.view_replies_count, comment.replyCount)
+ }
repliesVisible = false
} else {
- viewBinding.commentTotalReplies.text = "Hide Replies"
+ viewBinding.commentTotalReplies.setText(R.string.hide_replies)
repliesSection.clear()
commentsFragment.viewReplyCallback(this)
repliesVisible = true
@@ -128,35 +141,37 @@ class CommentItem(val comment: Comment,
viewBinding.modBadge.visibility = if (comment.isMod == true) View.VISIBLE else View.GONE
viewBinding.adminBadge.visibility = if (comment.isAdmin == true) View.VISIBLE else View.GONE
viewBinding.commentDelete.setOnClickListener {
- dialogBuilder("Delete Comment", "Are you sure you want to delete this comment?") {
- val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
- scope.launch {
+ dialogBuilder(getAppString(R.string.delete_comment), getAppString(R.string.delete_comment_confirm)) {
+ CoroutineScope(Dispatchers.Main + SupervisorJob()).launch {
val success = CommentsAPI.deleteComment(comment.commentId)
if (success) {
- snackString("Comment Deleted")
+ snackString(R.string.comment_deleted)
parentSection.remove(this@CommentItem)
}
}
}
}
viewBinding.commentBanUser.setOnClickListener {
- dialogBuilder("Ban User", "Are you sure you want to ban this user?") {
- val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
- scope.launch {
+ dialogBuilder(getAppString(R.string.ban_user), getAppString(R.string.ban_user_confirm)) {
+ CoroutineScope(Dispatchers.Main + SupervisorJob()).launch {
val success = CommentsAPI.banUser(comment.userId)
if (success) {
- snackString("User Banned")
+ snackString(R.string.user_banned)
}
}
}
}
viewBinding.commentReport.setOnClickListener {
- dialogBuilder("Report Comment", "Only report comments that violate the rules. Are you sure you want to report this comment?") {
- val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
- scope.launch {
- val success = CommentsAPI.reportComment(comment.commentId, comment.username, commentsFragment.mediaName, comment.userId)
+ dialogBuilder(getAppString(R.string.report_comment), getAppString(R.string.report_comment_confirm)) {
+ CoroutineScope(Dispatchers.Main + SupervisorJob()).launch {
+ val success = CommentsAPI.reportComment(
+ comment.commentId,
+ comment.username,
+ commentsFragment.mediaName,
+ comment.userId
+ )
if (success) {
- snackString("Comment Reported")
+ snackString(R.string.comment_reported)
}
}
}
@@ -210,7 +225,8 @@ class CommentItem(val comment: Comment,
}
comment.profilePictureUrl?.let { viewBinding.commentUserAvatar.loadImage(it) }
viewBinding.commentUserName.text = comment.username
- viewBinding.commentUserLevel.text = "[${levelColor.second}]"
+ val userColor = "[${levelColor.second}]"
+ viewBinding.commentUserLevel.text = userColor
viewBinding.commentUserLevel.setTextColor(levelColor.first)
viewBinding.commentUserTime.text = formatTimestamp(comment.timestamp)
}
@@ -243,6 +259,7 @@ class CommentItem(val comment: Comment,
private fun removeSubCommentIds(){
subCommentIds.forEach { id ->
+ @Suppress("UNCHECKED_CAST")
val parentComments = parentSection.groups as? List ?: emptyList()
val commentToRemove = parentComments.find { it.comment.commentId == id }
commentToRemove?.let {
@@ -272,9 +289,10 @@ 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()
@@ -297,8 +315,9 @@ 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
diff --git a/app/src/main/java/ani/dantotsu/media/comments/CommentsFragment.kt b/app/src/main/java/ani/dantotsu/media/comments/CommentsFragment.kt
index 5e699799..0ec2d3bf 100644
--- a/app/src/main/java/ani/dantotsu/media/comments/CommentsFragment.kt
+++ b/app/src/main/java/ani/dantotsu/media/comments/CommentsFragment.kt
@@ -523,11 +523,10 @@ class CommentsFragment : Fragment() {
}
- @SuppressLint("SetTextI18n")
fun replyTo(comment: CommentItem, username: String) {
if (comment.isReplying) {
activity.binding.commentReplyToContainer.visibility = View.VISIBLE
- activity.binding.commentReplyTo.text = "Replying to $username"
+ activity.binding.commentReplyTo.text = getString(R.string.replying_to, username)
activity.binding.commentReplyToCancel.setOnClickListener {
comment.replying(false)
replyCallback(comment)
diff --git a/app/src/main/java/ani/dantotsu/media/manga/MangaCache.kt b/app/src/main/java/ani/dantotsu/media/manga/MangaCache.kt
index ebf1c57f..359c64a5 100644
--- a/app/src/main/java/ani/dantotsu/media/manga/MangaCache.kt
+++ b/app/src/main/java/ani/dantotsu/media/manga/MangaCache.kt
@@ -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,15 +24,13 @@ data class ImageData(
) {
suspend fun fetchAndProcessImage(
page: Page,
- httpSource: HttpSource,
- context: Context
+ httpSource: HttpSource
): Bitmap? {
return withContext(Dispatchers.IO) {
try {
// Fetch the image
val response = httpSource.getImage(page)
- Logger.log("Response: ${response.code}")
- Logger.log("Response: ${response.message}")
+ Logger.log("Response: ${response.code} - ${response.message}")
// Convert the Response to an InputStream
val inputStream = response.body.byteStream()
diff --git a/app/src/main/java/ani/dantotsu/media/manga/MangaChapterAdapter.kt b/app/src/main/java/ani/dantotsu/media/manga/MangaChapterAdapter.kt
index d19aa011..67d9a696 100644
--- a/app/src/main/java/ani/dantotsu/media/manga/MangaChapterAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/media/manga/MangaChapterAdapter.kt
@@ -262,7 +262,6 @@ class MangaChapterAdapter(
}
}
- @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is ChapterCompactViewHolder -> {
diff --git a/app/src/main/java/ani/dantotsu/media/manga/MangaNameAdapter.kt b/app/src/main/java/ani/dantotsu/media/manga/MangaNameAdapter.kt
index ae755faa..d265b69a 100644
--- a/app/src/main/java/ani/dantotsu/media/manga/MangaNameAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/media/manga/MangaNameAdapter.kt
@@ -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 = "(?= mangaReadSources.names.size) 0 else it }
@@ -188,8 +187,8 @@ class MangaReadAdapter(
else -> dialogBinding.animeSourceList
}
when (style) {
- 0 -> dialogBinding.layoutText.text = "List"
- 1 -> dialogBinding.layoutText.text = "Compact"
+ 0 -> dialogBinding.layoutText.setText(R.string.list)
+ 1 -> dialogBinding.layoutText.setText(R.string.compact)
else -> dialogBinding.animeSourceList
}
selected.alpha = 1f
@@ -201,18 +200,18 @@ class MangaReadAdapter(
dialogBinding.animeSourceList.setOnClickListener {
selected(it as ImageButton)
style = 0
- dialogBinding.layoutText.text = "List"
+ dialogBinding.layoutText.setText(R.string.list)
run = true
}
dialogBinding.animeSourceCompact.setOnClickListener {
selected(it as ImageButton)
style = 1
- dialogBinding.layoutText.text = "Compact"
+ dialogBinding.layoutText.setText(R.string.compact)
run = true
}
dialogBinding.animeWebviewContainer.setOnClickListener {
if (!WebViewUtil.supportsWebView(fragment.requireContext())) {
- toast("WebView not installed")
+ toast(R.string.webview_not_installed)
}
//start CookieCatcher activity
if (mangaReadSources.names.isNotEmpty() && source in 0 until mangaReadSources.names.size) {
@@ -249,8 +248,7 @@ class MangaReadAdapter(
}
//Scanlator
- dialogBinding.animeScanlatorContainer.visibility =
- if (options.count() > 1) View.VISIBLE else View.GONE
+ dialogBinding.animeScanlatorContainer.isVisible = options.count() > 1
dialogBinding.scanlatorNo.text = "${options.count()}"
dialogBinding.animeScanlatorTop.setOnClickListener {
val dialogView2 = LayoutInflater.from(currContext()).inflate(R.layout.custom_dialog_layout, null)
@@ -359,7 +357,6 @@ class MangaReadAdapter(
}
//Chips
- @SuppressLint("SetTextI18n")
fun updateChips(limit: Int, names: Array, arr: Array, selected: Int = 0) {
val binding = _binding
if (binding != null) {
@@ -395,7 +392,8 @@ class MangaReadAdapter(
names[last - 1]
}
//chip.text = "${names[limit * (position)]} - ${names[last - 1]}"
- chip.text = "$startChapterString - $endChapterString"
+ val chipText = "$startChapterString - $endChapterString"
+ chip.text = chipText
chip.setTextColor(
ContextCompat.getColorStateList(
fragment.requireContext(),
@@ -429,7 +427,6 @@ class MangaReadAdapter(
_binding?.animeSourceChipGroup?.removeAllViews()
}
- @SuppressLint("SetTextI18n")
fun handleChapters() {
val binding = _binding
@@ -466,7 +463,7 @@ class MangaReadAdapter(
val ep = media.manga.chapters!![continueEp]!!
binding.itemEpisodeImage.loadImage(media.banner ?: media.cover)
binding.animeSourceContinueText.text =
- currActivity()!!.getString(R.string.continue_chapter) + "${ep.number}${if (!ep.title.isNullOrEmpty()) "\n${ep.title}" else ""}"
+ currActivity()!!.getString(R.string.continue_chapter, ep.number, if (!ep.title.isNullOrEmpty()) ep.title else "")
binding.animeSourceContinue.setOnClickListener {
fragment.onMangaChapterClick(continueEp)
}
@@ -481,13 +478,9 @@ class MangaReadAdapter(
binding.animeSourceContinue.visibility = View.GONE
}
binding.animeSourceProgressBar.visibility = View.GONE
- if (media.manga.chapters!!.isNotEmpty()) {
- binding.animeSourceNotFound.visibility = View.GONE
- binding.faqbutton.visibility = View.GONE
- } else {
- binding.animeSourceNotFound.visibility = View.VISIBLE
- binding.faqbutton.visibility = View.VISIBLE
- }
+ val sourceFound = media.manga.chapters!!.isNotEmpty()
+ binding.animeSourceNotFound.isGone = sourceFound
+ binding.faqbutton.isGone = sourceFound
} else {
binding.animeSourceContinue.visibility = View.GONE
binding.animeSourceNotFound.visibility = View.GONE
@@ -519,8 +512,7 @@ class MangaReadAdapter(
parser.extension.sources.map { LanguageMapper.mapLanguageCodeToName(it.lang) }
)
val items = adapter.count
- binding?.animeSourceLanguageContainer?.visibility =
- if (items > 1) View.VISIBLE else View.GONE
+ binding?.animeSourceLanguageContainer?.isVisible = items > 1
binding?.animeSourceLanguage?.setAdapter(adapter)
diff --git a/app/src/main/java/ani/dantotsu/media/manga/MangaReadFragment.kt b/app/src/main/java/ani/dantotsu/media/manga/MangaReadFragment.kt
index 621e07fb..8d11693c 100644
--- a/app/src/main/java/ani/dantotsu/media/manga/MangaReadFragment.kt
+++ b/app/src/main/java/ani/dantotsu/media/manga/MangaReadFragment.kt
@@ -20,6 +20,8 @@ import androidx.cardview.widget.CardView
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.math.MathUtils.clamp
+import androidx.core.view.isGone
+import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
@@ -28,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
@@ -354,14 +360,12 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
val changeUIVisibility: (Boolean) -> Unit = { show ->
val activity = activity
if (activity is MediaDetailsActivity && isAdded) {
- val visibility = if (show) View.VISIBLE else View.GONE
- activity.findViewById(R.id.mediaAppBar).visibility = visibility
- activity.findViewById(R.id.mediaViewPager).visibility = visibility
- activity.findViewById(R.id.mediaCover).visibility = visibility
- activity.findViewById(R.id.mediaClose).visibility = visibility
- activity.tabLayout.setVisibility(visibility)
- activity.findViewById(R.id.fragmentExtensionsContainer).visibility =
- if (show) View.GONE else View.VISIBLE
+ activity.findViewById(R.id.mediaAppBar).isVisible = show
+ activity.findViewById(R.id.mediaViewPager).isVisible = show
+ activity.findViewById(R.id.mediaCover).isVisible = show
+ activity.findViewById(R.id.mediaClose).isVisible = show
+ activity.navBar.isVisible = show
+ activity.findViewById(R.id.fragmentExtensionsContainer).isGone = show
}
}
var itemSelected = false
@@ -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)
diff --git a/app/src/main/java/ani/dantotsu/media/manga/mangareader/BaseImageAdapter.kt b/app/src/main/java/ani/dantotsu/media/manga/mangareader/BaseImageAdapter.kt
index c313d71d..6db754dc 100644
--- a/app/src/main/java/ani/dantotsu/media/manga/mangareader/BaseImageAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/media/manga/mangareader/BaseImageAdapter.kt
@@ -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
): 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)
diff --git a/app/src/main/java/ani/dantotsu/media/manga/mangareader/MangaReaderActivity.kt b/app/src/main/java/ani/dantotsu/media/manga/mangareader/MangaReaderActivity.kt
index 157c6146..747bb8dd 100644
--- a/app/src/main/java/ani/dantotsu/media/manga/mangareader/MangaReaderActivity.kt
+++ b/app/src/main/java/ani/dantotsu/media/manga/mangareader/MangaReaderActivity.kt
@@ -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
@@ -20,13 +31,16 @@ import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.math.MathUtils.clamp
import androidx.core.view.GestureDetectorCompat
+import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
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
@@ -34,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
@@ -45,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
@@ -65,11 +95,11 @@ 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
-@SuppressLint("SetTextI18n")
class MangaReaderActivity : AppCompatActivity() {
private val mangaCache = Injekt.get()
@@ -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(PrefName.ShowSystemBars))
+ if (PrefManager.getVal(PrefName.ShowSystemBars))
showSystemBarsRetractView()
else
hideSystemBarsExtendView()
@@ -223,8 +252,7 @@ class MangaReaderActivity : AppCompatActivity() {
chapter = chapters[media.manga!!.selectedChapter] ?: return
model.mangaReadSources = if (media.isAdult) HMangaSources else MangaSources
- binding.mangaReaderSource.visibility =
- if (PrefManager.getVal(PrefName.ShowSource)) View.VISIBLE else View.GONE
+ binding.mangaReaderSource.isVisible = PrefManager.getVal(PrefName.ShowSource)
if (model.mangaReadSources!!.names.isEmpty()) {
//try to reload sources
try {
@@ -369,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)
)
)
)
@@ -741,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
@@ -756,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.. 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
@@ -783,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) {
@@ -961,7 +989,7 @@ class MangaReaderActivity : AppCompatActivity() {
if (!incognito && PrefManager.getCustomVal(
"${media.id}_save_progress",
true
- ) && if (media.isAdult) PrefManager.getVal(PrefName.UpdateForHReader) else true
+ ) && if (media.isAdult) PrefManager.getVal(PrefName.UpdateForHReader) else true
)
updateProgress(
media,
diff --git a/app/src/main/java/ani/dantotsu/media/novel/NovelReadFragment.kt b/app/src/main/java/ani/dantotsu/media/novel/NovelReadFragment.kt
index 859dfdac..867912a7 100644
--- a/app/src/main/java/ani/dantotsu/media/novel/NovelReadFragment.kt
+++ b/app/src/main/java/ani/dantotsu/media/novel/NovelReadFragment.kt
@@ -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
)
)
}
diff --git a/app/src/main/java/ani/dantotsu/media/novel/NovelResponseAdapter.kt b/app/src/main/java/ani/dantotsu/media/novel/NovelResponseAdapter.kt
index 8da7c35b..e523ff29 100644
--- a/app/src/main/java/ani/dantotsu/media/novel/NovelResponseAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/media/novel/NovelResponseAdapter.kt
@@ -6,6 +6,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import ani.dantotsu.R
import ani.dantotsu.databinding.ItemNovelResponseBinding
@@ -71,8 +72,7 @@ class NovelResponseAdapter(
}
binding.itemEpisodeDesc2.text = novel.extra?.get("1") ?: ""
val desc = novel.extra?.get("2")
- binding.itemEpisodeDesc.visibility =
- if (desc != null && desc.trim(' ') != "") View.VISIBLE else View.GONE
+ binding.itemEpisodeDesc.isVisible = !desc.isNullOrBlank()
binding.itemEpisodeDesc.text = desc ?: ""
binding.root.setOnClickListener {
diff --git a/app/src/main/java/ani/dantotsu/media/novel/UrlAdapter.kt b/app/src/main/java/ani/dantotsu/media/novel/UrlAdapter.kt
index 96e9bcf8..dabd635c 100644
--- a/app/src/main/java/ani/dantotsu/media/novel/UrlAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/media/novel/UrlAdapter.kt
@@ -31,7 +31,6 @@ class UrlAdapter(
)
}
- @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: UrlViewHolder, position: Int) {
val binding = holder.binding
val url = urls[position]
diff --git a/app/src/main/java/ani/dantotsu/media/user/ListActivity.kt b/app/src/main/java/ani/dantotsu/media/user/ListActivity.kt
index 7ce2f136..81a80cfa 100644
--- a/app/src/main/java/ani/dantotsu/media/user/ListActivity.kt
+++ b/app/src/main/java/ani/dantotsu/media/user/ListActivity.kt
@@ -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
@@ -33,7 +32,6 @@ class ListActivity : AppCompatActivity() {
private val scope = lifecycleScope
private var selectedTabIdx = 0
- @SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -72,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 {
topMargin = statusBarHeight
}
@@ -83,8 +78,8 @@ class ListActivity : AppCompatActivity() {
setContentView(binding.root)
val anime = intent.getBooleanExtra("anime", true)
- binding.listTitle.text =
- intent.getStringExtra("username") + "'s " + (if (anime) "Anime" else "Manga") + " List"
+ binding.listTitle.text = getString(R.string.user_list, intent.getStringExtra("username"),
+ if (anime) getString(R.string.anime) else getString(R.string.manga))
binding.listTabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
this@ListActivity.selectedTabIdx = tab?.position ?: 0
diff --git a/app/src/main/java/ani/dantotsu/others/AndroidBug5497Workaround.kt b/app/src/main/java/ani/dantotsu/others/AndroidBug5497Workaround.kt
index 46e8a297..b25d10e2 100644
--- a/app/src/main/java/ani/dantotsu/others/AndroidBug5497Workaround.kt
+++ b/app/src/main/java/ani/dantotsu/others/AndroidBug5497Workaround.kt
@@ -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
@@ -42,9 +42,15 @@ class AndroidBug5497Workaround private constructor(activity: Activity, private v
return r.bottom
}
+ /**
+ * Fixes windowSoftInputMode adjustResize when used with setDecorFitsSystemWindows(false)
+ *
+ * @see adjustResize breaks when activity is fullscreen
+ */
companion object {
- // For more information, see https://issuetracker.google.com/issues/36911528
- // To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
+ /**
+ * Called on an Activity after the content view has been set.
+ */
fun assistActivity(activity: Activity, callback: (Boolean) -> Unit) {
AndroidBug5497Workaround(activity, callback)
}
diff --git a/app/src/main/java/ani/dantotsu/others/ImageViewDialog.kt b/app/src/main/java/ani/dantotsu/others/ImageViewDialog.kt
index e11715c7..346bd592 100644
--- a/app/src/main/java/ani/dantotsu/others/ImageViewDialog.kt
+++ b/app/src/main/java/ani/dantotsu/others/ImageViewDialog.kt
@@ -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 =
diff --git a/app/src/main/java/ani/dantotsu/others/OutlineTextView.kt b/app/src/main/java/ani/dantotsu/others/OutlineTextView.kt
index e2c17cc0..7a0cf925 100644
--- a/app/src/main/java/ani/dantotsu/others/OutlineTextView.kt
+++ b/app/src/main/java/ani/dantotsu/others/OutlineTextView.kt
@@ -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()
diff --git a/app/src/main/java/ani/dantotsu/others/webview/CookieCatcher.kt b/app/src/main/java/ani/dantotsu/others/webview/CookieCatcher.kt
index 73ae553a..e9e171f8 100644
--- a/app/src/main/java/ani/dantotsu/others/webview/CookieCatcher.kt
+++ b/app/src/main/java/ani/dantotsu/others/webview/CookieCatcher.kt
@@ -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 = intent.getSerializableExtra("headers") as? Map ?: emptyMap()
+ val url = intent.getStringExtra("url") ?: getString(R.string.cursed_yt)
+ val headers: Map = intent.getSerializableExtraCompat("headers") as? Map ?: emptyMap()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val process = Application.getProcessName()
diff --git a/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt b/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt
index 5ef0adf1..fc271de6 100644
--- a/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt
@@ -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 = listOf()
+ val imageDataList: MutableList = 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)
}
diff --git a/app/src/main/java/ani/dantotsu/parsers/OfflineAnimeParser.kt b/app/src/main/java/ani/dantotsu/parsers/OfflineAnimeParser.kt
index 1c9c3b6c..57098894 100644
--- a/app/src/main/java/ani/dantotsu/parsers/OfflineAnimeParser.kt
+++ b/app/src/main/java/ani/dantotsu/parsers/OfflineAnimeParser.kt
@@ -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)
)
)
}
diff --git a/app/src/main/java/ani/dantotsu/parsers/novel/NovelExtensionInstallReceiver.kt b/app/src/main/java/ani/dantotsu/parsers/novel/NovelExtensionFileObserver.kt
similarity index 98%
rename from app/src/main/java/ani/dantotsu/parsers/novel/NovelExtensionInstallReceiver.kt
rename to app/src/main/java/ani/dantotsu/parsers/novel/NovelExtensionFileObserver.kt
index 056118a5..b69cea44 100644
--- a/app/src/main/java/ani/dantotsu/parsers/novel/NovelExtensionInstallReceiver.kt
+++ b/app/src/main/java/ani/dantotsu/parsers/novel/NovelExtensionFileObserver.kt
@@ -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
diff --git a/app/src/main/java/ani/dantotsu/parsers/novel/NovelExtensionInstaller.kt b/app/src/main/java/ani/dantotsu/parsers/novel/NovelExtensionInstaller.kt
index 14d7b75e..818713c2 100644
--- a/app/src/main/java/ani/dantotsu/parsers/novel/NovelExtensionInstaller.kt
+++ b/app/src/main/java/ani/dantotsu/parsers/novel/NovelExtensionInstaller.kt
@@ -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 = Observable.defer {
val pkgName = extension.pkgName
val oldDownload = activeDownloads[pkgName]
diff --git a/app/src/main/java/ani/dantotsu/parsers/novel/NovelExtensionLoader.kt b/app/src/main/java/ani/dantotsu/parsers/novel/NovelExtensionLoader.kt
index 78535115..d4c94da5 100644
--- a/app/src/main/java/ani/dantotsu/parsers/novel/NovelExtensionLoader.kt
+++ b/app/src/main/java/ani/dantotsu/parsers/novel/NovelExtensionLoader.kt
@@ -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) {
diff --git a/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt b/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt
index 78867e37..5dac823a 100644
--- a/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt
+++ b/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt
@@ -3,6 +3,7 @@ package ani.dantotsu.profile
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.Intent
+import android.content.res.Configuration
import android.os.Bundle
import android.util.TypedValue
import android.view.View
@@ -11,6 +12,7 @@ import android.widget.PopupMenu
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.updateLayoutParams
+import androidx.core.view.updateMargins
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
@@ -47,7 +49,6 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
private var selected: Int = 0
private lateinit var navBar: AnimatedBottomBar
- @SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ThemeManager(this).applyTheme()
@@ -56,8 +57,14 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
setContentView(binding.root)
screenWidth = resources.displayMetrics.widthPixels.toFloat()
navBar = binding.profileNavBar
- navBar.updateLayoutParams { bottomMargin = navBarHeight }
-
+ val navBarRightMargin = if (resources.configuration.orientation ==
+ Configuration.ORIENTATION_LANDSCAPE) navBarHeight else 0
+ val navBarBottomMargin = if (resources.configuration.orientation ==
+ Configuration.ORIENTATION_LANDSCAPE) 0 else navBarHeight
+ navBar.updateLayoutParams {
+ rightMargin = navBarRightMargin
+ bottomMargin = navBarBottomMargin
+ }
val feedTab = navBar.createTab(R.drawable.ic_round_filter_24, "Feed")
val profileTab = navBar.createTab(R.drawable.ic_round_person_24, "Profile")
val statsTab = navBar.createTab(R.drawable.ic_stats_24, "Stats")
@@ -105,20 +112,30 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
val userLevel = intent.getStringExtra("userLVL") ?: ""
binding.followButton.visibility =
if (user.id == Anilist.userid || Anilist.userid == null) View.GONE else View.VISIBLE
- binding.followButton.text =
- if (user.isFollowing) "Unfollow" else if (user.isFollower) "Follows you" else "Follow"
- if (user.isFollowing && user.isFollower) binding.followButton.text = "Mutual"
+ binding.followButton.text = getString(
+ when {
+ user.isFollowing -> R.string.unfollow
+ user.isFollower -> R.string.follows_you
+ else -> R.string.follow
+ }
+ )
+ if (user.isFollowing && user.isFollower) binding.followButton.text = getString(R.string.mutual)
binding.followButton.setOnClickListener {
lifecycleScope.launch(Dispatchers.IO) {
val res = Anilist.query.toggleFollow(user.id)
if (res?.data?.toggleFollow != null) {
withContext(Dispatchers.Main) {
- snackString("Success")
+ snackString(R.string.success)
user.isFollowing = res.data.toggleFollow.isFollowing
- binding.followButton.text =
- if (user.isFollowing) "Unfollow" else if (user.isFollower) "Follows you" else "Follow"
- if (user.isFollowing && user.isFollower) binding.followButton.text =
- "Mutual"
+ binding.followButton.text = getString(
+ when {
+ user.isFollowing -> R.string.unfollow
+ user.isFollower -> R.string.follows_you
+ else -> R.string.follow
+ }
+ )
+ if (user.isFollowing && user.isFollower)
+ binding.followButton.text = getString(R.string.mutual)
}
}
}
@@ -172,7 +189,8 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
)
}
- binding.profileUserName.text = "${user.name} $userLevel"
+ val userLevelText = "${user.name} $userLevel"
+ binding.profileUserName.text = userLevelText
if (!(PrefManager.getVal(PrefName.BannerAnimations) as Boolean)) binding.profileBannerImage.pause()
blurImage(binding.profileBannerImage, user.bannerImage ?: user.avatar?.medium)
binding.profileBannerImage.updateLayoutParams { height += statusBarHeight }
@@ -196,7 +214,7 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
ContextCompat.startActivity(
this@ProfileActivity,
Intent(this@ProfileActivity, FollowActivity::class.java)
- .putExtra("title", "Followers")
+ .putExtra("title", getString(R.string.followers))
.putExtra("userId", user.id),
null
)
@@ -279,6 +297,17 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
}
}
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ val rightMargin = if (resources.configuration.orientation ==
+ Configuration.ORIENTATION_LANDSCAPE) navBarHeight else 0
+ val bottomMargin = if (resources.configuration.orientation ==
+ Configuration.ORIENTATION_LANDSCAPE) 0 else navBarHeight
+ val params : ViewGroup.MarginLayoutParams =
+ navBar.layoutParams as ViewGroup.MarginLayoutParams
+ params.updateMargins(right = rightMargin, bottom = bottomMargin)
+ }
+
override fun onResume() {
if (this::navBar.isInitialized) {
navBar.selectTabAt(selected)
@@ -301,4 +330,4 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
else -> ProfileFragment.newInstance(user)
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt
index e361199d..d008f966 100644
--- a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt
+++ b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt
@@ -11,6 +11,7 @@ import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.LiveData
@@ -33,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
@@ -57,7 +59,7 @@ class ProfileFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
activity = requireActivity() as ProfileActivity
- user = arguments?.getSerializable("user") as Query.UserProfile
+ user = arguments?.getSerializableCompat("user") as Query.UserProfile
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
model.setData(user.id)
}
@@ -101,8 +103,7 @@ class ProfileFragment : Fragment() {
}
}
- binding.userInfoContainer.visibility =
- if (user.about != null) View.VISIBLE else View.GONE
+ binding.userInfoContainer.isVisible = user.about != null
binding.statsEpisodesWatched.text = user.statistics.anime.episodesWatched.toString()
diff --git a/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt b/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt
index b90cba33..2f01cac6 100644
--- a/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt
+++ b/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt
@@ -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("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,
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt b/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt
index c55e6a82..0f9ed865 100644
--- a/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt
+++ b/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt
@@ -3,6 +3,7 @@ package ani.dantotsu.profile.activity
import android.annotation.SuppressLint
import android.view.View
import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.LinearLayoutManager
import ani.dantotsu.R
@@ -38,7 +39,6 @@ class ActivityItem(
private lateinit var binding: ItemActivityBinding
private lateinit var repliesAdapter: GroupieAdapter
- @SuppressLint("SetTextI18n")
override fun bind(viewBinding: ItemActivityBinding, position: Int) {
binding = viewBinding
setAnimation(binding.root.context, binding.root)
@@ -58,8 +58,7 @@ class ActivityItem(
val likeColor = ContextCompat.getColor(binding.root.context, R.color.yt_red)
val notLikeColor = ContextCompat.getColor(binding.root.context, R.color.bg_opp)
binding.activityLike.setColorFilter(if (activity.isLiked == true) likeColor else notLikeColor)
- binding.commentRepliesContainer.visibility =
- if (activity.replyCount > 0) View.VISIBLE else View.GONE
+ binding.commentRepliesContainer.isVisible = activity.replyCount > 0
binding.commentRepliesContainer.setOnClickListener {
when (binding.activityReplies.visibility) {
View.GONE -> {
@@ -73,13 +72,13 @@ class ActivityItem(
} ?: emptyList()
repliesAdapter.addAll(replyItems)
binding.activityReplies.visibility = View.VISIBLE
- binding.commentTotalReplies.text = "Hide replies"
+ binding.commentTotalReplies.setText(R.string.hide_replies)
}
else -> {
repliesAdapter.clear()
binding.activityReplies.visibility = View.GONE
- binding.commentTotalReplies.text = "View replies"
+ binding.commentTotalReplies.setText(R.string.view_replies)
}
}
@@ -127,7 +126,9 @@ class ActivityItem(
binding.activityContent.visibility = View.GONE
binding.activityBannerContainer.visibility = View.VISIBLE
binding.activityMediaName.text = activity.media?.title?.userPreferred
- binding.activityText.text = "${activity.user!!.name} ${activity.status} ${activity.progress ?: activity.media?.title?.userPreferred}"
+ val activityText = "${activity.user!!.name} ${activity.status} ${activity.progress
+ ?: activity.media?.title?.userPreferred}"
+ binding.activityText.text = activityText
binding.activityCover.loadImage(cover)
blurImage(binding.activityBannerImage, banner ?: cover)
binding.activityAvatarContainer.setOnClickListener {
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt b/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt
index 98f0492b..0b35f047 100644
--- a/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt
+++ b/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt
@@ -1,9 +1,11 @@
package ani.dantotsu.profile.activity
+import android.content.res.Configuration
import android.os.Bundle
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.updateLayoutParams
+import androidx.core.view.updateMargins
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
@@ -28,14 +30,16 @@ class FeedActivity : AppCompatActivity() {
binding = ActivityFeedBinding.inflate(layoutInflater)
setContentView(binding.root)
navBar = binding.feedNavBar
- navBar.updateLayoutParams { bottomMargin += navBarHeight }
+ val navBarMargin = if (resources.configuration.orientation ==
+ Configuration.ORIENTATION_LANDSCAPE) 0 else navBarHeight
+ navBar.updateLayoutParams { bottomMargin = navBarMargin }
val personalTab = navBar.createTab(R.drawable.ic_round_person_24, "Following")
val globalTab = navBar.createTab(R.drawable.ic_globe_24, "Global")
navBar.addTab(personalTab)
navBar.addTab(globalTab)
binding.listTitle.text = getString(R.string.activities)
binding.feedViewPager.updateLayoutParams {
- bottomMargin += navBarHeight
+ bottomMargin = navBarMargin
topMargin += statusBarHeight
}
binding.listToolbar.updateLayoutParams { topMargin += statusBarHeight }
@@ -57,10 +61,20 @@ class FeedActivity : AppCompatActivity() {
}
})
binding.listBack.setOnClickListener {
- onBackPressed()
+ onBackPressedDispatcher.onBackPressed()
}
}
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ val margin = if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) 0 else navBarHeight
+ val params : ViewGroup.MarginLayoutParams =
+ binding.feedViewPager.layoutParams as ViewGroup.MarginLayoutParams
+ val paramsNav : ViewGroup.MarginLayoutParams = navBar.layoutParams as ViewGroup.MarginLayoutParams
+ params.updateMargins(bottom = margin)
+ paramsNav.updateMargins(bottom = margin)
+ }
+
override fun onResume() {
super.onResume()
navBar.selectTabAt(selected)
@@ -80,4 +94,4 @@ class FeedActivity : AppCompatActivity() {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/NotificationActivity.kt b/app/src/main/java/ani/dantotsu/profile/activity/NotificationActivity.kt
index 9b68f377..a8214004 100644
--- a/app/src/main/java/ani/dantotsu/profile/activity/NotificationActivity.kt
+++ b/app/src/main/java/ani/dantotsu/profile/activity/NotificationActivity.kt
@@ -11,6 +11,7 @@ import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
+import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.api.Notification
import ani.dantotsu.databinding.ActivityFollowBinding
@@ -37,14 +38,14 @@ class NotificationActivity : AppCompatActivity() {
private var currentPage: Int = 1
private var hasNextPage: Boolean = true
- @SuppressLint("SetTextI18n", "ClickableViewAccessibility")
+ @SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ThemeManager(this).applyTheme()
initActivity(this)
binding = ActivityFollowBinding.inflate(layoutInflater)
setContentView(binding.root)
- binding.listTitle.text = "Notifications"
+ binding.listTitle.text = getString(R.string.notifications)
binding.listToolbar.updateLayoutParams {
topMargin = statusBarHeight
}
@@ -57,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)
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/NotificationItem.kt b/app/src/main/java/ani/dantotsu/profile/activity/NotificationItem.kt
index bf56db20..0276e3f7 100644
--- a/app/src/main/java/ani/dantotsu/profile/activity/NotificationItem.kt
+++ b/app/src/main/java/ani/dantotsu/profile/activity/NotificationItem.kt
@@ -12,6 +12,7 @@ import ani.dantotsu.databinding.ItemNotificationBinding
import ani.dantotsu.loadImage
import ani.dantotsu.profile.activity.NotificationActivity.Companion.NotificationClickType
import ani.dantotsu.setAnimation
+import ani.dantotsu.toPx
import com.xwray.groupie.viewbinding.BindableItem
class NotificationItem(
@@ -40,23 +41,11 @@ class NotificationItem(
?: notification.media?.coverImage?.large
blurImage(binding.notificationBannerImage, cover)
- val defaultHeight = TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP,
- 153f,
- binding.root.context.resources.displayMetrics
- ).toInt()
+ val defaultHeight = 153.toPx
- val userHeight = TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP,
- 90f,
- binding.root.context.resources.displayMetrics
- ).toInt()
+ val userHeight = 90.toPx
- val textMarginStart = TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP,
- 125f,
- binding.root.context.resources.displayMetrics
- ).toInt()
+ val textMarginStart = 125.toPx
if (user) {
binding.notificationCover.visibility = View.GONE
diff --git a/app/src/main/java/ani/dantotsu/settings/ExtensionsActivity.kt b/app/src/main/java/ani/dantotsu/settings/ExtensionsActivity.kt
index a97a644d..6c10242d 100644
--- a/app/src/main/java/ani/dantotsu/settings/ExtensionsActivity.kt
+++ b/app/src/main/java/ani/dantotsu/settings/ExtensionsActivity.kt
@@ -29,7 +29,6 @@ import com.google.android.material.tabs.TabLayoutMediator
class ExtensionsActivity : AppCompatActivity() {
lateinit var binding: ActivityExtensionsBinding
- @SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/ani/dantotsu/settings/InstalledAnimeExtensionsFragment.kt b/app/src/main/java/ani/dantotsu/settings/InstalledAnimeExtensionsFragment.kt
index f7108bc7..0149b8ba 100644
--- a/app/src/main/java/ani/dantotsu/settings/InstalledAnimeExtensionsFragment.kt
+++ b/app/src/main/java/ani/dantotsu/settings/InstalledAnimeExtensionsFragment.kt
@@ -14,6 +14,8 @@ import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.core.app.NotificationCompat
+import androidx.core.view.isGone
+import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DiffUtil
@@ -59,15 +61,13 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
val name = pkg.name
val changeUIVisibility: (Boolean) -> Unit = { show ->
val activity = requireActivity() as ExtensionsActivity
- val visibility = if (show) View.VISIBLE else View.GONE
- activity.findViewById(R.id.viewPager).visibility = visibility
- activity.findViewById(R.id.tabLayout).visibility = visibility
- activity.findViewById(R.id.searchView).visibility = visibility
- activity.findViewById(R.id.languageselect).visibility = visibility
+ activity.findViewById(R.id.viewPager).isVisible = show
+ activity.findViewById(R.id.tabLayout).isVisible = show
+ activity.findViewById(R.id.searchView).isVisible = show
+ activity.findViewById(R.id.languageselect).isVisible = show
activity.findViewById(R.id.extensions).text =
if (show) getString(R.string.extensions) else name
- activity.findViewById(R.id.fragmentExtensionsContainer).visibility =
- if (show) View.GONE else View.VISIBLE
+ activity.findViewById(R.id.fragmentExtensionsContainer).isGone = show
}
var itemSelected = false
val allSettings = pkg.sources.filterIsInstance()
@@ -294,13 +294,13 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
return ViewHolder(view)
}
- @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val extension = getItem(position)
val nsfw = if (extension.isNsfw) "(18+)" else ""
val lang = LanguageMapper.mapLanguageCodeToName(extension.lang)
holder.extensionNameTextView.text = extension.name
- holder.extensionVersionTextView.text = "$lang ${extension.versionName} $nsfw"
+ val versionText = "$lang ${extension.versionName} $nsfw"
+ holder.extensionVersionTextView.text = versionText
if (!skipIcons) {
holder.extensionIconImageView.setImageDrawable(extension.icon)
}
diff --git a/app/src/main/java/ani/dantotsu/settings/InstalledMangaExtensionsFragment.kt b/app/src/main/java/ani/dantotsu/settings/InstalledMangaExtensionsFragment.kt
index 2da2a777..12ee40be 100644
--- a/app/src/main/java/ani/dantotsu/settings/InstalledMangaExtensionsFragment.kt
+++ b/app/src/main/java/ani/dantotsu/settings/InstalledMangaExtensionsFragment.kt
@@ -15,6 +15,8 @@ import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.core.app.NotificationCompat
+import androidx.core.view.isGone
+import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DiffUtil
@@ -57,15 +59,13 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
val name = pkg.name
val changeUIVisibility: (Boolean) -> Unit = { show ->
val activity = requireActivity() as ExtensionsActivity
- val visibility = if (show) View.VISIBLE else View.GONE
- activity.findViewById(R.id.viewPager).visibility = visibility
- activity.findViewById(R.id.tabLayout).visibility = visibility
- activity.findViewById(R.id.searchView).visibility = visibility
- activity.findViewById(R.id.languageselect).visibility = visibility
+ activity.findViewById(R.id.viewPager).isVisible = show
+ activity.findViewById(R.id.tabLayout).isVisible = show
+ activity.findViewById(R.id.searchView).isVisible = show
+ activity.findViewById(R.id.languageselect).isVisible = show
activity.findViewById(R.id.extensions).text =
if (show) getString(R.string.extensions) else name
- activity.findViewById(R.id.fragmentExtensionsContainer).visibility =
- if (show) View.GONE else View.VISIBLE
+ activity.findViewById(R.id.fragmentExtensionsContainer).isGone = show
}
var itemSelected = false
val allSettings = pkg.sources.filterIsInstance()
@@ -290,13 +290,14 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
MangaSources.performReorderMangaSources()
}
- @SuppressLint("SetTextI18n", "ClickableViewAccessibility")
+ @SuppressLint("ClickableViewAccessibility")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val extension = getItem(position) // Use getItem() from ListAdapter
val nsfw = if (extension.isNsfw) "(18+)" else ""
val lang = LanguageMapper.mapLanguageCodeToName(extension.lang)
holder.extensionNameTextView.text = extension.name
- holder.extensionVersionTextView.text = "$lang ${extension.versionName} $nsfw"
+ val versionText = "$lang ${extension.versionName} $nsfw"
+ holder.extensionVersionTextView.text = versionText
if (!skipIcons) {
holder.extensionIconImageView.setImageDrawable(extension.icon)
}
diff --git a/app/src/main/java/ani/dantotsu/settings/InstalledNovelExtensionsFragment.kt b/app/src/main/java/ani/dantotsu/settings/InstalledNovelExtensionsFragment.kt
index 5c46a5c9..05314985 100644
--- a/app/src/main/java/ani/dantotsu/settings/InstalledNovelExtensionsFragment.kt
+++ b/app/src/main/java/ani/dantotsu/settings/InstalledNovelExtensionsFragment.kt
@@ -221,13 +221,13 @@ class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler {
return ViewHolder(view)
}
- @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val extension = getItem(position) // Use getItem() from ListAdapter
val nsfw = ""
val lang = LanguageMapper.mapLanguageCodeToName("all")
holder.extensionNameTextView.text = extension.name
- holder.extensionVersionTextView.text = "$lang ${extension.versionName} $nsfw"
+ val versionText = "$lang ${extension.versionName} $nsfw"
+ holder.extensionVersionTextView.text = versionText
if (!skipIcons) {
holder.extensionIconImageView.setImageDrawable(extension.icon)
}
diff --git a/app/src/main/java/ani/dantotsu/settings/PlayerSettingsActivity.kt b/app/src/main/java/ani/dantotsu/settings/PlayerSettingsActivity.kt
index 5faccc17..0a7b7d9e 100644
--- a/app/src/main/java/ani/dantotsu/settings/PlayerSettingsActivity.kt
+++ b/app/src/main/java/ani/dantotsu/settings/PlayerSettingsActivity.kt
@@ -127,6 +127,7 @@ class PlayerSettingsActivity : AppCompatActivity() {
binding.playerSettingsTimeStamps.isChecked = PrefManager.getVal(PrefName.TimeStampsEnabled)
binding.playerSettingsTimeStamps.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.TimeStampsEnabled, isChecked)
+ binding.playerSettingsAutoSkipOpEd.isEnabled = isChecked
}
binding.playerSettingsTimeStampsAutoHide.isChecked = PrefManager.getVal(PrefName.AutoHideTimeStamps)
@@ -148,6 +149,7 @@ class PlayerSettingsActivity : AppCompatActivity() {
// Auto
binding.playerSettingsAutoSkipOpEd.isChecked = PrefManager.getVal(PrefName.AutoSkipOPED)
+ binding.playerSettingsAutoSkipOpEd.isEnabled = binding.playerSettingsTimeStamps.isChecked
binding.playerSettingsAutoSkipOpEd.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.AutoSkipOPED, isChecked)
}
@@ -172,7 +174,7 @@ class PlayerSettingsActivity : AppCompatActivity() {
binding.playerSettingsAskChapterZero.isChecked =
PrefManager.getVal(PrefName.ChapterZeroPlayer)
binding.playerSettingsAskChapterZero.isEnabled =
- !PrefManager.getVal(PrefName.AskIndividualPlayer)
+ !binding.playerSettingsAskUpdateProgress.isChecked
binding.playerSettingsAskChapterZero.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.ChapterZeroPlayer, isChecked)
}
@@ -411,7 +413,7 @@ class PlayerSettingsActivity : AppCompatActivity() {
"Magenta"
)
val subBackgroundDialog = AlertDialog.Builder(this, R.style.MyPopup)
- .setTitle(getString(R.string.outline_sub_color))
+ .setTitle(getString(R.string.sub_background_color_select))
binding.videoSubColorBackground.setOnClickListener {
val dialog = subBackgroundDialog.setSingleChoiceItems(
colorsSubBackground,
@@ -438,7 +440,7 @@ class PlayerSettingsActivity : AppCompatActivity() {
"Magenta"
)
val subWindowDialog = AlertDialog.Builder(this, R.style.MyPopup)
- .setTitle(getString(R.string.outline_sub_color))
+ .setTitle(getString(R.string.sub_window_color_select))
binding.videoSubColorWindow.setOnClickListener {
val dialog = subWindowDialog.setSingleChoiceItems(
colorsSubWindow,
diff --git a/app/src/main/java/ani/dantotsu/settings/SettingsActivity.kt b/app/src/main/java/ani/dantotsu/settings/SettingsActivity.kt
index 4394156c..12b0701d 100644
--- a/app/src/main/java/ani/dantotsu/settings/SettingsActivity.kt
+++ b/app/src/main/java/ani/dantotsu/settings/SettingsActivity.kt
@@ -21,7 +21,6 @@ import android.view.animation.AnimationUtils
import android.view.inputmethod.EditorInfo
import android.widget.ArrayAdapter
import android.widget.TextView
-import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.OptIn
@@ -41,20 +40,28 @@ import ani.dantotsu.connections.discord.Discord
import ani.dantotsu.connections.mal.MAL
import ani.dantotsu.copyToClipboard
import ani.dantotsu.currContext
+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
+import ani.dantotsu.databinding.ActivitySettingsNotificationsBinding
+import ani.dantotsu.databinding.ActivitySettingsThemeBinding
import ani.dantotsu.download.DownloadsManager
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.comment.CommentNotificationWorker
import ani.dantotsu.notifications.anilist.AnilistNotificationWorker
+import ani.dantotsu.notifications.comment.CommentNotificationWorker
import ani.dantotsu.notifications.subscription.SubscriptionNotificationWorker.Companion.checkIntervals
import ani.dantotsu.openLinkInBrowser
+import ani.dantotsu.openLinkInYouTube
import ani.dantotsu.openSettings
import ani.dantotsu.others.AppUpdater
import ani.dantotsu.others.CustomBottomDialog
@@ -71,6 +78,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
@@ -92,11 +100,18 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
override fun handleOnBackPressed() = startMainActivity(this@SettingsActivity)
}
lateinit var binding: ActivitySettingsBinding
+ private lateinit var bindingAccounts: ActivitySettingsAccountsBinding
+ private lateinit var bindingTheme: ActivitySettingsThemeBinding
+ private lateinit var bindingExtensions: ActivitySettingsExtensionsBinding
+ private lateinit var bindingCommon: ActivitySettingsCommonBinding
+ private lateinit var bindingAnime: ActivitySettingsAnimeBinding
+ private lateinit var bindingManga: ActivitySettingsMangaBinding
+ private lateinit var bindingNotifications: ActivitySettingsNotificationsBinding
+ private lateinit var bindingAbout: ActivitySettingsAboutBinding
private val extensionInstaller = Injekt.get().extensionInstaller()
private var cursedCounter = 0
@OptIn(UnstableApi::class)
- @SuppressLint("SetTextI18n", "Recycle")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ThemeManager(this).applyTheme()
@@ -125,13 +140,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")) {
@@ -139,11 +154,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))
}
}
}
@@ -166,253 +181,420 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
onBackPressedDispatcher.onBackPressed()
}
- binding.settingsUseMaterialYou.isChecked = PrefManager.getVal(PrefName.UseMaterialYou)
- binding.settingsUseMaterialYou.setOnCheckedChangeListener { _, isChecked ->
- PrefManager.setVal(PrefName.UseMaterialYou, isChecked)
- if (isChecked) binding.settingsUseCustomTheme.isChecked = false
- restartApp()
- }
-
- binding.settingsUseCustomTheme.isChecked = PrefManager.getVal(PrefName.UseCustomTheme)
- binding.settingsUseCustomTheme.setOnCheckedChangeListener { _, isChecked ->
- PrefManager.setVal(PrefName.UseCustomTheme, isChecked)
- if (isChecked) {
- binding.settingsUseMaterialYou.isChecked = false
+ bindingAccounts = ActivitySettingsAccountsBinding.bind(binding.root).apply {
+ settingsAccountHelp.setOnClickListener {
+ val title = getString(R.string.account_help)
+ val full = getString(R.string.full_account_help)
+ CustomBottomDialog.newInstance().apply {
+ setTitleText(title)
+ addView(
+ TextView(it.context).apply {
+ val markWon = Markwon.builder(it.context)
+ .usePlugin(SoftBreakAddsNewLinePlugin.create()).build()
+ markWon.setMarkdown(this, full)
+ }
+ )
+ }.show(supportFragmentManager, "dialog")
}
- restartApp()
- }
+ fun reload() {
+ if (Anilist.token != null) {
+ settingsAnilistLogin.setText(R.string.logout)
+ settingsAnilistLogin.setOnClickListener {
+ Anilist.removeSavedToken()
+ restartMainActivity.isEnabled = true
+ reload()
+ }
+ settingsAnilistUsername.visibility = View.VISIBLE
+ settingsAnilistUsername.text = Anilist.username
+ settingsAnilistAvatar.loadImage(Anilist.avatar)
- binding.settingsUseSourceTheme.isChecked = PrefManager.getVal(PrefName.UseSourceTheme)
- binding.settingsUseSourceTheme.setOnCheckedChangeListener { _, isChecked ->
- PrefManager.setVal(PrefName.UseSourceTheme, isChecked)
- restartApp()
- }
+ settingsMALLoginRequired.visibility = View.GONE
+ settingsMALLogin.visibility = View.VISIBLE
+ settingsMALUsername.visibility = View.VISIBLE
- binding.settingsUseOLED.isChecked = PrefManager.getVal(PrefName.UseOLED)
- binding.settingsUseOLED.setOnCheckedChangeListener { _, isChecked ->
- PrefManager.setVal(PrefName.UseOLED, isChecked)
- restartApp()
- }
+ if (MAL.token != null) {
+ settingsMALLogin.setText(R.string.logout)
+ settingsMALLogin.setOnClickListener {
+ MAL.removeSavedToken()
+ restartMainActivity.isEnabled = true
+ reload()
+ }
+ settingsMALUsername.visibility = View.VISIBLE
+ settingsMALUsername.text = MAL.username
+ settingsMALAvatar.loadImage(MAL.avatar)
+ } else {
+ settingsMALAvatar.setImageResource(R.drawable.ic_round_person_24)
+ settingsMALUsername.visibility = View.GONE
+ settingsMALLogin.setText(R.string.login)
+ settingsMALLogin.setOnClickListener {
+ MAL.loginIntent(this@SettingsActivity)
+ }
+ }
+ } else {
+ settingsAnilistAvatar.setImageResource(R.drawable.ic_round_person_24)
+ settingsAnilistUsername.visibility = View.GONE
+ settingsAnilistLogin.setText(R.string.login)
+ settingsAnilistLogin.setOnClickListener {
+ Anilist.loginIntent(this@SettingsActivity)
+ }
+ settingsMALLoginRequired.visibility = View.VISIBLE
+ settingsMALLogin.visibility = View.GONE
+ settingsMALUsername.visibility = View.GONE
+ }
- val themeString: String = PrefManager.getVal(PrefName.Theme)
- binding.themeSwitcher.setText(
- themeString.substring(0, 1) + themeString.substring(1).lowercase()
- )
+ if (Discord.token != null) {
+ val id = PrefManager.getVal(PrefName.DiscordId, null as String?)
+ val avatar = PrefManager.getVal(PrefName.DiscordAvatar, null as String?)
+ val username = PrefManager.getVal(PrefName.DiscordUserName, null as String?)
+ if (id != null && avatar != null) {
+ settingsDiscordAvatar.loadImage("https://cdn.discordapp.com/avatars/$id/$avatar.png")
+ }
+ settingsDiscordUsername.visibility = View.VISIBLE
+ settingsDiscordUsername.text =
+ username ?: Discord.token?.replace(Regex("."), "*")
+ settingsDiscordLogin.setText(R.string.logout)
+ settingsDiscordLogin.setOnClickListener {
+ Discord.removeSavedToken(this@SettingsActivity)
+ restartMainActivity.isEnabled = true
+ reload()
+ }
- binding.themeSwitcher.setAdapter(
- ArrayAdapter(
- this,
- R.layout.item_dropdown,
- ThemeManager.Companion.Theme.entries
- .map { it.theme.substring(0, 1) + it.theme.substring(1).lowercase() })
- )
+ imageSwitcher.visibility = View.VISIBLE
+ var initialStatus = when (PrefManager.getVal(PrefName.DiscordStatus)) {
+ "online" -> R.drawable.discord_status_online
+ "idle" -> R.drawable.discord_status_idle
+ "dnd" -> R.drawable.discord_status_dnd
+ else -> R.drawable.discord_status_online
+ }
+ imageSwitcher.setImageResource(initialStatus)
- binding.themeSwitcher.setOnItemClickListener { _, _, i, _ ->
- PrefManager.setVal(PrefName.Theme, ThemeManager.Companion.Theme.entries[i].theme)
- //ActivityHelper.shouldRefreshMainActivity = true
- binding.themeSwitcher.clearFocus()
- restartApp()
+ val zoomInAnimation =
+ AnimationUtils.loadAnimation(this@SettingsActivity, R.anim.bounce_zoom)
+ imageSwitcher.setOnClickListener {
+ var status = "online"
+ initialStatus = when (initialStatus) {
+ R.drawable.discord_status_online -> {
+ status = "idle"
+ R.drawable.discord_status_idle
+ }
- }
+ R.drawable.discord_status_idle -> {
+ status = "dnd"
+ R.drawable.discord_status_dnd
+ }
+ R.drawable.discord_status_dnd -> {
+ status = "online"
+ R.drawable.discord_status_online
+ }
- binding.customTheme.setOnClickListener {
- val originalColor: Int = PrefManager.getVal(PrefName.CustomThemeInt)
+ else -> R.drawable.discord_status_online
+ }
- class CustomColorDialog : SimpleColorDialog() { //idk where to put it
- override fun onPositiveButtonClick() {
- restartApp()
- super.onPositiveButtonClick()
+ PrefManager.setVal(PrefName.DiscordStatus, status)
+ imageSwitcher.setImageResource(initialStatus)
+ imageSwitcher.startAnimation(zoomInAnimation)
+ }
+ } else {
+ imageSwitcher.visibility = View.GONE
+ settingsDiscordAvatar.setImageResource(R.drawable.ic_round_person_24)
+ settingsDiscordUsername.visibility = View.GONE
+ settingsDiscordLogin.setText(R.string.login)
+ settingsDiscordLogin.setOnClickListener {
+ Discord.warning(this@SettingsActivity)
+ .show(supportFragmentManager, "dialog")
+ }
}
}
-
- val tag = "colorPicker"
- CustomColorDialog().title("Custom Theme")
- .colorPreset(originalColor)
- .colors(this, SimpleColorDialog.MATERIAL_COLOR_PALLET)
- .allowCustom(true)
- .showOutline(0x46000000)
- .gridNumColumn(5)
- .choiceMode(SimpleColorDialog.SINGLE_CHOICE)
- .neg()
- .show(this, tag)
+ reload()
}
- binding.settingsPlayer.setOnClickListener {
- startActivity(Intent(this, PlayerSettingsActivity::class.java))
+ bindingTheme = ActivitySettingsThemeBinding.bind(binding.root).apply {
+ settingsUseMaterialYou.isChecked =
+ PrefManager.getVal(PrefName.UseMaterialYou)
+ settingsUseMaterialYou.setOnCheckedChangeListener { _, isChecked ->
+ PrefManager.setVal(PrefName.UseMaterialYou, isChecked)
+ if (isChecked) settingsUseCustomTheme.isChecked = false
+ restartApp()
+ }
+
+ settingsUseCustomTheme.isChecked =
+ PrefManager.getVal(PrefName.UseCustomTheme)
+ settingsUseCustomTheme.setOnCheckedChangeListener { _, isChecked ->
+ PrefManager.setVal(PrefName.UseCustomTheme, isChecked)
+ if (isChecked) {
+ settingsUseMaterialYou.isChecked = false
+ }
+
+ restartApp()
+ }
+
+ settingsUseSourceTheme.isChecked =
+ PrefManager.getVal(PrefName.UseSourceTheme)
+ settingsUseSourceTheme.setOnCheckedChangeListener { _, isChecked ->
+ PrefManager.setVal(PrefName.UseSourceTheme, isChecked)
+ restartApp()
+ }
+
+ settingsUseOLED.isChecked = PrefManager.getVal(PrefName.UseOLED)
+ settingsUseOLED.setOnCheckedChangeListener { _, isChecked ->
+ PrefManager.setVal(PrefName.UseOLED, isChecked)
+ restartApp()
+ }
+
+ val themeString: String = PrefManager.getVal(PrefName.Theme)
+ val themeText = themeString.substring(0, 1) + themeString.substring(1).lowercase()
+ themeSwitcher.setText(themeText)
+
+ themeSwitcher.setAdapter(
+ ArrayAdapter(
+ this@SettingsActivity,
+ R.layout.item_dropdown,
+ ThemeManager.Companion.Theme.entries
+ .map { it.theme.substring(0, 1) + it.theme.substring(1).lowercase() })
+ )
+
+ themeSwitcher.setOnItemClickListener { _, _, i, _ ->
+ PrefManager.setVal(PrefName.Theme, ThemeManager.Companion.Theme.entries[i].theme)
+ //ActivityHelper.shouldRefreshMainActivity = true
+ themeSwitcher.clearFocus()
+ restartApp()
+
+ }
+
+
+ customTheme.setOnClickListener {
+ val originalColor: Int = PrefManager.getVal(PrefName.CustomThemeInt)
+
+ class CustomColorDialog : SimpleColorDialog() { //idk where to put it
+ override fun onPositiveButtonClick() {
+ restartApp()
+ super.onPositiveButtonClick()
+ }
+ }
+
+ val tag = "colorPicker"
+ CustomColorDialog().title(R.string.custom_theme)
+ .colorPreset(originalColor)
+ .colors(this@SettingsActivity, SimpleColorDialog.MATERIAL_COLOR_PALLET)
+ .allowCustom(true)
+ .showOutline(0x46000000)
+ .gridNumColumn(5)
+ .choiceMode(SimpleColorDialog.SINGLE_CHOICE)
+ .neg()
+ .show(this@SettingsActivity, tag)
+ }
+
+ var previous: View = when (PrefManager.getVal(PrefName.DarkMode)) {
+ 0 -> settingsUiAuto
+ 1 -> settingsUiLight
+ 2 -> settingsUiDark
+ else -> settingsUiAuto
+ }
+ previous.alpha = 1f
+ fun uiTheme(mode: Int, current: View) {
+ previous.alpha = 0.33f
+ previous = current
+ current.alpha = 1f
+ PrefManager.setVal(PrefName.DarkMode, mode)
+ Refresh.all()
+ finish()
+ startActivity(Intent(this@SettingsActivity, SettingsActivity::class.java))
+ initActivity(this@SettingsActivity)
+ }
+
+ settingsUiAuto.setOnClickListener {
+ uiTheme(0, it)
+ }
+
+ settingsUiLight.setOnClickListener {
+ settingsUseOLED.isChecked = false
+ uiTheme(1, it)
+ }
+
+ settingsUiDark.setOnClickListener {
+ uiTheme(2, it)
+ }
}
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)
- binding.settingsDownloadManager.setOnClickListener {
- val dialog = downloadManagerDialog.setSingleChoiceItems(
- managers,
- downloadManager
- ) { dialog, count ->
- downloadManager = count
- PrefManager.setVal(PrefName.DownloadManager, downloadManager)
- dialog.dismiss()
- }.show()
- dialog.window?.setDimAmount(0.8f)
- }
- binding.importExportSettings.setOnClickListener {
- downloadsPermission(this)
- val selectedArray = mutableListOf(false)
- 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")
- .setMultiChoiceItems(
- filteredLocations.map { it.name }.toTypedArray(),
- selectedArray.toBooleanArray()
- ) { _, which, isChecked ->
- selectedArray[which] = isChecked
- }
- .setPositiveButton("Import...") { dialog, _ ->
- openDocumentLauncher.launch(arrayOf("*/*"))
- dialog.dismiss()
- }
- .setNegativeButton("Export...") { dialog, _ ->
- if (!selectedArray.contains(true)) {
- toast("No location selected")
- return@setNegativeButton
- }
- dialog.dismiss()
- val selected =
- filteredLocations.filterIndexed { index, _ -> selectedArray[index] }
- if (selected.contains(Location.Protected)) {
- passwordAlertDialog(true) { password ->
- if (password != null) {
- savePrefsToDownloads(
- "DantotsuSettings",
- PrefManager.exportAllPrefs(selected),
- this@SettingsActivity,
- password
- )
- } else {
- toast("Password cannot be empty")
- }
- }
- } else {
- savePrefsToDownloads(
- "DantotsuSettings",
- PrefManager.exportAllPrefs(selected),
+ bindingAnime = ActivitySettingsAnimeBinding.bind(binding.root).apply {
+ settingsPlayer.setOnClickListener {
+ startActivity(Intent(this@SettingsActivity, PlayerSettingsActivity::class.java))
+ }
+
+ purgeAnimeDownloads.setOnClickListener {
+ val dialog = AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
+ .setTitle(R.string.purge_anime_downloads)
+ .setMessage(getString(R.string.purge_confirm, getString(R.string.anime)))
+ .setPositiveButton(R.string.yes) { dialog, _ ->
+ val downloadsManager = Injekt.get()
+ downloadsManager.purgeDownloads(MediaType.ANIME)
+ DownloadService.sendRemoveAllDownloads(
this@SettingsActivity,
- null
+ ExoplayerDownloadService::class.java,
+ false
)
+ dialog.dismiss()
}
- }
- .setNeutralButton("Cancel") { dialog, _ ->
- dialog.dismiss()
- }
- .create()
- dialog.window?.setDimAmount(0.8f)
- dialog.show()
- }
+ .setNegativeButton(R.string.no) { dialog, _ ->
+ dialog.dismiss()
+ }
+ .create()
+ dialog.window?.setDimAmount(0.8f)
+ dialog.show()
+ }
- binding.purgeAnimeDownloads.setOnClickListener {
- val dialog = AlertDialog.Builder(this, R.style.MyPopup)
- .setTitle("Purge Anime Downloads")
- .setMessage("Are you sure you want to purge all anime downloads?")
- .setPositiveButton("Yes") { dialog, _ ->
- val downloadsManager = Injekt.get()
- downloadsManager.purgeDownloads(DownloadedType.Type.ANIME)
- DownloadService.sendRemoveAllDownloads(
- this,
- ExoplayerDownloadService::class.java,
- false
- )
- dialog.dismiss()
- }
- .setNegativeButton("No") { dialog, _ ->
- dialog.dismiss()
- }
- .create()
- dialog.window?.setDimAmount(0.8f)
- dialog.show()
- }
+ settingsPreferDub.isChecked = PrefManager.getVal(PrefName.SettingsPreferDub)
+ settingsPreferDub.setOnCheckedChangeListener { _, isChecked ->
+ PrefManager.setVal(PrefName.SettingsPreferDub, isChecked)
+ }
- binding.purgeMangaDownloads.setOnClickListener {
- val dialog = AlertDialog.Builder(this, R.style.MyPopup)
- .setTitle("Purge Manga Downloads")
- .setMessage("Are you sure you want to purge all manga downloads?")
- .setPositiveButton("Yes") { dialog, _ ->
- val downloadsManager = Injekt.get()
- downloadsManager.purgeDownloads(DownloadedType.Type.MANGA)
- dialog.dismiss()
- }
- .setNegativeButton("No") { dialog, _ ->
- dialog.dismiss()
- }
- .create()
- dialog.window?.setDimAmount(0.8f)
- dialog.show()
- }
- binding.purgeNovelDownloads.setOnClickListener {
- val dialog = AlertDialog.Builder(this, R.style.MyPopup)
- .setTitle("Purge Novel Downloads")
- .setMessage("Are you sure you want to purge all novel downloads?")
- .setPositiveButton("Yes") { dialog, _ ->
- val downloadsManager = Injekt.get()
- downloadsManager.purgeDownloads(DownloadedType.Type.NOVEL)
- dialog.dismiss()
- }
- .setNegativeButton("No") { dialog, _ ->
- dialog.dismiss()
- }
- .create()
- dialog.window?.setDimAmount(0.8f)
- dialog.show()
- }
+ settingsShowYt.isChecked = PrefManager.getVal(PrefName.ShowYtButton)
+ settingsShowYt.setOnCheckedChangeListener { _, isChecked ->
+ PrefManager.setVal(PrefName.ShowYtButton, isChecked)
+ }
- binding.settingsForceLegacyInstall.isChecked =
- extensionInstaller.get() == BasePreferences.ExtensionInstaller.LEGACY
- binding.settingsForceLegacyInstall.setOnCheckedChangeListener { _, isChecked ->
- if (isChecked) {
- extensionInstaller.set(BasePreferences.ExtensionInstaller.LEGACY)
- } else {
- extensionInstaller.set(BasePreferences.ExtensionInstaller.PACKAGEINSTALLER)
+ var previousEp: View = when (PrefManager.getVal(PrefName.AnimeDefaultView)) {
+ 0 -> settingsEpList
+ 1 -> settingsEpGrid
+ 2 -> settingsEpCompact
+ else -> settingsEpList
+ }
+ previousEp.alpha = 1f
+ fun uiEp(mode: Int, current: View) {
+ previousEp.alpha = 0.33f
+ previousEp = current
+ current.alpha = 1f
+ PrefManager.setVal(PrefName.AnimeDefaultView, mode)
+ }
+
+ settingsEpList.setOnClickListener {
+ uiEp(0, it)
+ }
+
+ settingsEpGrid.setOnClickListener {
+ uiEp(1, it)
+ }
+
+ settingsEpCompact.setOnClickListener {
+ uiEp(2, it)
}
}
- binding.skipExtensionIcons.isChecked = PrefManager.getVal(PrefName.SkipExtensionIcons)
- binding.skipExtensionIcons.setOnCheckedChangeListener { _, isChecked ->
- PrefManager.getVal(PrefName.SkipExtensionIcons, isChecked)
- }
- binding.NSFWExtension.isChecked = PrefManager.getVal(PrefName.NSFWExtension)
- binding.NSFWExtension.setOnCheckedChangeListener { _, isChecked ->
- PrefManager.setVal(PrefName.NSFWExtension, isChecked)
+ bindingManga = ActivitySettingsMangaBinding.bind(binding.root).apply {
+ purgeMangaDownloads.setOnClickListener {
+ val dialog = AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
+ .setTitle(R.string.purge_manga_downloads)
+ .setMessage(getString(R.string.purge_confirm, getString(R.string.manga)))
+ .setPositiveButton(R.string.yes) { dialog, _ ->
+ val downloadsManager = Injekt.get()
+ downloadsManager.purgeDownloads(MediaType.MANGA)
+ dialog.dismiss()
+ }
+ .setNegativeButton(R.string.no) { dialog, _ ->
+ dialog.dismiss()
+ }
+ .create()
+ dialog.window?.setDimAmount(0.8f)
+ dialog.show()
+ }
+ purgeNovelDownloads.setOnClickListener {
+ val dialog = AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
+ .setTitle(R.string.purge_novel_downloads)
+ .setMessage(getString(R.string.purge_confirm, getString(R.string.novels)))
+ .setPositiveButton(R.string.yes) { dialog, _ ->
+ val downloadsManager = Injekt.get()
+ downloadsManager.purgeDownloads(MediaType.NOVEL)
+ dialog.dismiss()
+ }
+ .setNegativeButton(R.string.no) { dialog, _ ->
+ dialog.dismiss()
+ }
+ .create()
+ dialog.window?.setDimAmount(0.8f)
+ dialog.show()
+ }
+
+ settingsReader.setOnClickListener {
+ startActivity(Intent(this@SettingsActivity, ReaderSettingsActivity::class.java))
+ }
+
+ var previousChp: View = when (PrefManager.getVal(PrefName.MangaDefaultView)) {
+ 0 -> settingsChpList
+ 1 -> settingsChpCompact
+ else -> settingsChpList
+ }
+ previousChp.alpha = 1f
+ fun uiChp(mode: Int, current: View) {
+ previousChp.alpha = 0.33f
+ previousChp = current
+ current.alpha = 1f
+ PrefManager.setVal(PrefName.MangaDefaultView, mode)
+ }
+
+ settingsChpList.setOnClickListener {
+ uiChp(0, it)
+ }
+
+ settingsChpCompact.setOnClickListener {
+ uiChp(1, it)
+ }
}
- binding.userAgent.setOnClickListener {
- val dialogView = layoutInflater.inflate(R.layout.dialog_user_agent, null)
- val editText = dialogView.findViewById(R.id.userAgentTextBox)
- editText.setText(PrefManager.getVal(PrefName.DefaultUserAgent))
- val alertDialog = AlertDialog.Builder(this, R.style.MyPopup)
- .setTitle("User Agent")
- .setView(dialogView)
- .setPositiveButton("OK") { dialog, _ ->
- PrefManager.setVal(PrefName.DefaultUserAgent, editText.text.toString())
- dialog.dismiss()
+ bindingExtensions = ActivitySettingsExtensionsBinding.bind(binding.root).apply {
+ settingsForceLegacyInstall.isChecked =
+ extensionInstaller.get() == BasePreferences.ExtensionInstaller.LEGACY
+ settingsForceLegacyInstall.setOnCheckedChangeListener { _, isChecked ->
+ if (isChecked) {
+ extensionInstaller.set(BasePreferences.ExtensionInstaller.LEGACY)
+ } else {
+ extensionInstaller.set(BasePreferences.ExtensionInstaller.PACKAGEINSTALLER)
}
- .setNeutralButton("Reset") { dialog, _ ->
- PrefManager.removeVal(PrefName.DefaultUserAgent)
- editText.setText("")
- dialog.dismiss()
- }
- .setNegativeButton("Cancel") { dialog, _ ->
- dialog.dismiss()
- }
- .create()
+ }
- alertDialog.show()
- alertDialog.window?.setDimAmount(0.8f)
+ skipExtensionIcons.isChecked =
+ PrefManager.getVal(PrefName.SkipExtensionIcons)
+ skipExtensionIcons.setOnCheckedChangeListener { _, isChecked ->
+ PrefManager.getVal(PrefName.SkipExtensionIcons, isChecked)
+ }
+ NSFWExtension.isChecked = PrefManager.getVal(PrefName.NSFWExtension)
+ NSFWExtension.setOnCheckedChangeListener { _, isChecked ->
+ PrefManager.setVal(PrefName.NSFWExtension, isChecked)
+
+ }
+
+ userAgent.setOnClickListener {
+ val dialogView = layoutInflater.inflate(R.layout.dialog_user_agent, null)
+ val editText = dialogView.findViewById(R.id.userAgentTextBox)
+ editText.setText(PrefManager.getVal(PrefName.DefaultUserAgent))
+ val alertDialog = AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
+ .setTitle(R.string.user_agent)
+ .setView(dialogView)
+ .setPositiveButton(getString(R.string.ok)) { dialog, _ ->
+ PrefManager.setVal(PrefName.DefaultUserAgent, editText.text.toString())
+ dialog.dismiss()
+ }
+ .setNeutralButton(getString(R.string.reset)) { dialog, _ ->
+ PrefManager.removeVal(PrefName.DefaultUserAgent)
+ editText.setText("")
+ dialog.dismiss()
+ }
+ .setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
+ dialog.dismiss()
+ }
+ .create()
+
+ alertDialog.show()
+ alertDialog.window?.setDimAmount(0.8f)
+ }
}
@@ -432,162 +614,373 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
"Shecan",
"Libre"
)
- binding.settingsExtensionDns.setText(exDns[PrefManager.getVal(PrefName.DohProvider)])
- binding.settingsExtensionDns.setAdapter(ArrayAdapter(this, R.layout.item_dropdown, exDns))
- binding.settingsExtensionDns.setOnItemClickListener { _, _, i, _ ->
- PrefManager.setVal(PrefName.DohProvider, i)
- binding.settingsExtensionDns.clearFocus()
- Toast.makeText(this, "Restart app to apply changes", Toast.LENGTH_LONG).show()
+
+ bindingCommon = ActivitySettingsCommonBinding.bind(binding.root).apply {
+ settingsDownloadManager.setOnClickListener {
+ val dialog = downloadManagerDialog.setSingleChoiceItems(
+ managers,
+ downloadManager
+ ) { dialog, count ->
+ downloadManager = count
+ PrefManager.setVal(PrefName.DownloadManager, downloadManager)
+ dialog.dismiss()
+ }.show()
+ dialog.window?.setDimAmount(0.8f)
+ }
+
+ importExportSettings.setOnClickListener {
+ downloadsPermission(this@SettingsActivity)
+ val selectedArray = mutableListOf(false)
+ val filteredLocations = Location.entries.filter { it.exportable }
+ selectedArray.addAll(List(filteredLocations.size - 1) { false })
+ val dialog = AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
+ .setTitle(R.string.import_export_settings)
+ .setMultiChoiceItems(
+ filteredLocations.map { it.name }.toTypedArray(),
+ selectedArray.toBooleanArray()
+ ) { _, which, isChecked ->
+ selectedArray[which] = isChecked
+ }
+ .setPositiveButton(R.string.button_import) { dialog, _ ->
+ openDocumentLauncher.launch(arrayOf("*/*"))
+ dialog.dismiss()
+ }
+ .setNegativeButton(R.string.button_export) { dialog, _ ->
+ if (!selectedArray.contains(true)) {
+ toast(R.string.no_location_selected)
+ return@setNegativeButton
+ }
+ dialog.dismiss()
+ val selected =
+ filteredLocations.filterIndexed { index, _ -> selectedArray[index] }
+ if (selected.contains(Location.Protected)) {
+ passwordAlertDialog(true) { password ->
+ if (password != null) {
+ savePrefsToDownloads(
+ "DantotsuSettings",
+ PrefManager.exportAllPrefs(selected),
+ this@SettingsActivity,
+ password
+ )
+ } else {
+ toast(R.string.password_cannot_be_empty)
+ }
+ }
+ } else {
+ savePrefsToDownloads(
+ "DantotsuSettings",
+ PrefManager.exportAllPrefs(selected),
+ this@SettingsActivity,
+ null
+ )
+ }
+ }
+ .setNeutralButton(R.string.cancel) { dialog, _ ->
+ dialog.dismiss()
+ }
+ .create()
+ dialog.window?.setDimAmount(0.8f)
+ dialog.show()
+ }
+
+ settingsExtensionDns.setText(exDns[PrefManager.getVal(PrefName.DohProvider)])
+ settingsExtensionDns.setAdapter(ArrayAdapter(this@SettingsActivity, R.layout.item_dropdown, exDns))
+ settingsExtensionDns.setOnItemClickListener { _, _, i, _ ->
+ PrefManager.setVal(PrefName.DohProvider, i)
+ settingsExtensionDns.clearFocus()
+ restartApp()
+ }
+
+ settingsDownloadInSd.isChecked = PrefManager.getVal(PrefName.SdDl)
+ settingsDownloadInSd.setOnCheckedChangeListener { _, isChecked ->
+ if (isChecked) {
+ val arrayOfFiles = ContextCompat.getExternalFilesDirs(this@SettingsActivity, null)
+ if (arrayOfFiles.size > 1 && arrayOfFiles[1] != null) {
+ PrefManager.setVal(PrefName.SdDl, true)
+ } else {
+ settingsDownloadInSd.isChecked = false
+ PrefManager.setVal(PrefName.SdDl, true)
+ snackString(getString(R.string.noSdFound))
+ }
+ } else PrefManager.setVal(PrefName.SdDl, true)
+ }
+
+ settingsContinueMedia.isChecked = PrefManager.getVal(PrefName.ContinueMedia)
+ settingsContinueMedia.setOnCheckedChangeListener { _, isChecked ->
+ PrefManager.setVal(PrefName.ContinueMedia, isChecked)
+ }
+
+ settingsRecentlyListOnly.isChecked = PrefManager.getVal(PrefName.RecentlyListOnly)
+ settingsRecentlyListOnly.setOnCheckedChangeListener { _, isChecked ->
+ PrefManager.setVal(PrefName.RecentlyListOnly, isChecked)
+ }
+
+ var previousStart: View = when (PrefManager.getVal(PrefName.DefaultStartUpTab)) {
+ 0 -> uiSettingsAnime
+ 1 -> uiSettingsHome
+ 2 -> uiSettingsManga
+ else -> uiSettingsHome
+ }
+ previousStart.alpha = 1f
+ fun uiDefault(mode: Int, current: View) {
+ previousStart.alpha = 0.33f
+ previousStart = current
+ current.alpha = 1f
+ PrefManager.setVal(PrefName.DefaultStartUpTab, mode)
+ initActivity(this@SettingsActivity)
+ }
+
+ uiSettingsAnime.setOnClickListener {
+ uiDefault(0, it)
+ }
+
+ uiSettingsHome.setOnClickListener {
+ uiDefault(1, it)
+ }
+
+ uiSettingsManga.setOnClickListener {
+ uiDefault(2, it)
+ }
+
+ settingsUi.setOnClickListener {
+ startActivity(Intent(this@SettingsActivity, UserInterfaceSettingsActivity::class.java))
+ }
}
- binding.settingsDownloadInSd.isChecked = PrefManager.getVal(PrefName.SdDl)
- binding.settingsDownloadInSd.setOnCheckedChangeListener { _, isChecked ->
- if (isChecked) {
- val arrayOfFiles = ContextCompat.getExternalFilesDirs(this, null)
- if (arrayOfFiles.size > 1 && arrayOfFiles[1] != null) {
- PrefManager.setVal(PrefName.SdDl, true)
+ bindingNotifications = ActivitySettingsNotificationsBinding.bind(binding.root).apply {
+ var curTime = PrefManager.getVal(PrefName.SubscriptionNotificationInterval)
+ val timeNames = checkIntervals.map {
+ val mins = it % 60
+ val hours = it / 60
+ if (it > 0) "${if (hours > 0) "$hours hrs " else ""}${if (mins > 0) "$mins mins" else ""}"
+ else getString(R.string.do_not_update)
+ }.toTypedArray()
+
+ settingsSubscriptionsTime.text =
+ getString(R.string.subscriptions_checking_time_s, timeNames[curTime])
+ val speedDialog = AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
+ .setTitle(R.string.subscriptions_checking_time)
+ settingsSubscriptionsTime.setOnClickListener {
+ val dialog = speedDialog.setSingleChoiceItems(timeNames, curTime) { dialog, i ->
+ curTime = i
+ settingsSubscriptionsTime.text =
+ getString(R.string.subscriptions_checking_time_s, timeNames[i])
+ PrefManager.setVal(PrefName.SubscriptionNotificationInterval, curTime)
+ dialog.dismiss()
+ TaskScheduler.create(this@SettingsActivity,
+ PrefManager.getVal(PrefName.UseAlarmManager)
+ ).scheduleAllTasks(this@SettingsActivity)
+ }.show()
+ dialog.window?.setDimAmount(0.8f)
+ }
+
+ settingsSubscriptionsTime.setOnLongClickListener {
+ TaskScheduler.create(this@SettingsActivity,
+ PrefManager.getVal(PrefName.UseAlarmManager)
+ ).scheduleAllTasks(this@SettingsActivity)
+ true
+ }
+
+ val aTimeNames = AnilistNotificationWorker.checkIntervals.map { it.toInt() }
+ val aItems = aTimeNames.map {
+ val mins = it % 60
+ val hours = it / 60
+ if (it > 0) "${if (hours > 0) "$hours hrs " else ""}${if (mins > 0) "$mins mins" else ""}"
+ else getString(R.string.do_not_update)
+ }
+ settingsAnilistSubscriptionsTime.text =
+ getString(R.string.anilist_notifications_checking_time, aItems[PrefManager.getVal(PrefName.AnilistNotificationInterval)])
+ settingsAnilistSubscriptionsTime.setOnClickListener {
+
+ val selected = PrefManager.getVal(PrefName.AnilistNotificationInterval)
+ val dialog = AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
+ .setTitle(R.string.subscriptions_checking_time)
+ .setSingleChoiceItems(aItems.toTypedArray(), selected) { dialog, i ->
+ PrefManager.setVal(PrefName.AnilistNotificationInterval, i)
+ settingsAnilistSubscriptionsTime.text =
+ getString(R.string.anilist_notifications_checking_time, aItems[i])
+ dialog.dismiss()
+ TaskScheduler.create(this@SettingsActivity,
+ PrefManager.getVal(PrefName.UseAlarmManager)
+ ).scheduleAllTasks(this@SettingsActivity)
+ }
+ .create()
+ dialog.window?.setDimAmount(0.8f)
+ dialog.show()
+ }
+
+ settingsAnilistNotifications.setOnClickListener {
+ val types = NotificationType.entries.map { it.name }
+ val filteredTypes = PrefManager.getVal>(PrefName.AnilistFilteredTypes).toMutableSet()
+ val selected = types.map { filteredTypes.contains(it) }.toBooleanArray()
+ val dialog = AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
+ .setTitle(R.string.anilist_notification_filters)
+ .setMultiChoiceItems(types.toTypedArray(), selected) { _, which, isChecked ->
+ val type = types[which]
+ if (isChecked) {
+ filteredTypes.add(type)
+ } else {
+ filteredTypes.remove(type)
+ }
+ PrefManager.setVal(PrefName.AnilistFilteredTypes, filteredTypes)
+ }
+ .create()
+ dialog.window?.setDimAmount(0.8f)
+ dialog.show()
+ }
+
+ val cTimeNames = CommentNotificationWorker.checkIntervals.map { it.toInt() }
+ val cItems = cTimeNames.map {
+ val mins = it % 60
+ val hours = it / 60
+ if (it > 0) "${if (hours > 0) "$hours hrs " else ""}${if (mins > 0) "$mins mins" else ""}"
+ else getString(R.string.do_not_update)
+ }
+
+ settingsCommentSubscriptionsTime.text =
+ getString(R.string.comment_notification_checking_time, cItems[PrefManager.getVal(PrefName.CommentNotificationInterval)])
+ settingsCommentSubscriptionsTime.setOnClickListener {
+ val selected = PrefManager.getVal(PrefName.CommentNotificationInterval)
+ val dialog = AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
+ .setTitle(R.string.subscriptions_checking_time)
+ .setSingleChoiceItems(cItems.toTypedArray(), selected) { dialog, i ->
+ PrefManager.setVal(PrefName.CommentNotificationInterval, i)
+ settingsCommentSubscriptionsTime.text =
+ getString(R.string.comment_notification_checking_time, cItems[i])
+ dialog.dismiss()
+ TaskScheduler.create(this@SettingsActivity,
+ PrefManager.getVal(PrefName.UseAlarmManager)
+ ).scheduleAllTasks(this@SettingsActivity)
+ }
+ .create()
+ dialog.window?.setDimAmount(0.8f)
+ dialog.show()
+ }
+
+ settingsNotificationsCheckingSubscriptions.isChecked =
+ PrefManager.getVal(PrefName.SubscriptionCheckingNotifications)
+ settingsNotificationsCheckingSubscriptions.setOnCheckedChangeListener { _, isChecked ->
+ PrefManager.setVal(PrefName.SubscriptionCheckingNotifications, isChecked)
+ }
+
+ settingsNotificationsCheckingSubscriptions.setOnLongClickListener {
+ openSettings(this@SettingsActivity, null)
+ }
+
+ settingsNotificationsUseAlarmManager.isChecked =
+ PrefManager.getVal(PrefName.UseAlarmManager)
+
+ settingsNotificationsUseAlarmManager.setOnCheckedChangeListener { _, isChecked ->
+ if (isChecked) {
+ val alertDialog = AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
+ .setTitle(R.string.use_alarm_manager)
+ .setMessage(R.string.use_alarm_manager_confirm)
+ .setPositiveButton(R.string.use) { dialog, _ ->
+ PrefManager.setVal(PrefName.UseAlarmManager, true)
+ if (SDK_INT >= Build.VERSION_CODES.S) {
+ if (!(getSystemService(Context.ALARM_SERVICE) as AlarmManager).canScheduleExactAlarms()) {
+ val intent = Intent("android.settings.REQUEST_SCHEDULE_EXACT_ALARM")
+ startActivity(intent)
+ settingsNotificationsCheckingSubscriptions.isChecked = true
+ }
+ }
+ dialog.dismiss()
+ }
+ .setNegativeButton(R.string.cancel) { dialog, _ ->
+ settingsNotificationsCheckingSubscriptions.isChecked = false
+ PrefManager.setVal(PrefName.UseAlarmManager, false)
+ dialog.dismiss()
+ }
+ .create()
+ alertDialog.window?.setDimAmount(0.8f)
+ alertDialog.show()
} else {
- binding.settingsDownloadInSd.isChecked = false
- PrefManager.setVal(PrefName.SdDl, true)
- snackString(getString(R.string.noSdFound))
+ PrefManager.setVal(PrefName.UseAlarmManager, false)
+ TaskScheduler.create(this@SettingsActivity, true).cancelAllTasks()
+ TaskScheduler.create(this@SettingsActivity, false).scheduleAllTasks(this@SettingsActivity)
}
- } else PrefManager.setVal(PrefName.SdDl, true)
+ }
}
- binding.settingsContinueMedia.isChecked = PrefManager.getVal(PrefName.ContinueMedia)
- binding.settingsContinueMedia.setOnCheckedChangeListener { _, isChecked ->
- PrefManager.setVal(PrefName.ContinueMedia, isChecked)
- }
+ bindingAbout = ActivitySettingsAboutBinding.bind(binding.root).apply {
+ settingsDev.setOnClickListener {
+ DevelopersDialogFragment().show(supportFragmentManager, "dialog")
+ }
+ settingsForks.setOnClickListener {
+ ForksDialogFragment().show(supportFragmentManager, "dialog")
+ }
+ settingsDisclaimer.setOnClickListener {
+ val title = getString(R.string.disclaimer)
+ val text = TextView(this@SettingsActivity)
+ text.setText(R.string.full_disclaimer)
- binding.settingsRecentlyListOnly.isChecked = PrefManager.getVal(PrefName.RecentlyListOnly)
- binding.settingsRecentlyListOnly.setOnCheckedChangeListener { _, isChecked ->
- PrefManager.setVal(PrefName.RecentlyListOnly, isChecked)
- }
- binding.settingsPreferDub.isChecked = PrefManager.getVal(PrefName.SettingsPreferDub)
- binding.settingsPreferDub.setOnCheckedChangeListener { _, isChecked ->
- PrefManager.setVal(PrefName.SettingsPreferDub, isChecked)
- }
+ CustomBottomDialog.newInstance().apply {
+ setTitleText(title)
+ addView(text)
+ setNegativeButton(currContext()!!.getString(R.string.close)) {
+ dismiss()
+ }
+ show(supportFragmentManager, "dialog")
+ }
+ }
- binding.settingsReader.setOnClickListener {
- startActivity(Intent(this, ReaderSettingsActivity::class.java))
- }
+ settingsFAQ.setOnClickListener {
+ startActivity(Intent(this@SettingsActivity, FAQActivity::class.java))
+ }
- var previous: View = when (PrefManager.getVal(PrefName.DarkMode)) {
- 0 -> binding.settingsUiAuto
- 1 -> binding.settingsUiLight
- 2 -> binding.settingsUiDark
- else -> binding.settingsUiAuto
- }
- previous.alpha = 1f
- fun uiTheme(mode: Int, current: View) {
- previous.alpha = 0.33f
- previous = current
- current.alpha = 1f
- PrefManager.setVal(PrefName.DarkMode, mode)
- Refresh.all()
- finish()
- startActivity(Intent(this, SettingsActivity::class.java))
- initActivity(this)
- }
+ if (!BuildConfig.FLAVOR.contains("fdroid")) {
+ binding.settingsLogo.setOnLongClickListener {
+ lifecycleScope.launch(Dispatchers.IO) {
+ AppUpdater.check(this@SettingsActivity, true)
+ }
+ true
+ }
- binding.settingsUiAuto.setOnClickListener {
- uiTheme(0, it)
- }
+ settingsCheckUpdate.isChecked = PrefManager.getVal(PrefName.CheckUpdate)
+ settingsCheckUpdate.setOnCheckedChangeListener { _, isChecked ->
+ PrefManager.setVal(PrefName.CheckUpdate, isChecked)
+ if (!isChecked) {
+ snackString(getString(R.string.long_click_to_check_update))
+ }
+ }
- binding.settingsUiLight.setOnClickListener {
- binding.settingsUseOLED.isChecked = false
- uiTheme(1, it)
- }
+ settingsCheckUpdate.setOnLongClickListener {
+ lifecycleScope.launch(Dispatchers.IO) {
+ AppUpdater.check(this@SettingsActivity, true)
+ }
+ true
+ }
- binding.settingsUiDark.setOnClickListener {
- uiTheme(2, it)
- }
+ settingsShareUsername.isChecked = PrefManager.getVal(PrefName.SharedUserID)
+ settingsShareUsername.setOnCheckedChangeListener { _, isChecked ->
+ PrefManager.setVal(PrefName.SharedUserID, isChecked)
+ }
- var previousStart: View = when (PrefManager.getVal(PrefName.DefaultStartUpTab)) {
- 0 -> binding.uiSettingsAnime
- 1 -> binding.uiSettingsHome
- 2 -> binding.uiSettingsManga
- else -> binding.uiSettingsHome
- }
- previousStart.alpha = 1f
- fun uiDefault(mode: Int, current: View) {
- previousStart.alpha = 0.33f
- previousStart = current
- current.alpha = 1f
- PrefManager.setVal(PrefName.DefaultStartUpTab, mode)
- initActivity(this)
- }
+ } else {
+ settingsCheckUpdate.visibility = View.GONE
+ settingsShareUsername.visibility = View.GONE
+ settingsCheckUpdate.isEnabled = false
+ settingsShareUsername.isEnabled = false
+ settingsCheckUpdate.isChecked = false
+ settingsShareUsername.isChecked = false
+ }
+ settingsLogToFile.isChecked = PrefManager.getVal(PrefName.LogToFile)
+ settingsLogToFile.setOnCheckedChangeListener { _, isChecked ->
+ PrefManager.setVal(PrefName.LogToFile, isChecked)
+ restartApp()
+ }
- binding.uiSettingsAnime.setOnClickListener {
- uiDefault(0, it)
- }
-
- binding.uiSettingsHome.setOnClickListener {
- uiDefault(1, it)
- }
-
- binding.uiSettingsManga.setOnClickListener {
- uiDefault(2, it)
- }
-
- binding.settingsShowYt.isChecked = PrefManager.getVal(PrefName.ShowYtButton)
- binding.settingsShowYt.setOnCheckedChangeListener { _, isChecked ->
- PrefManager.setVal(PrefName.ShowYtButton, isChecked)
- }
-
- var previousEp: View = when (PrefManager.getVal(PrefName.AnimeDefaultView)) {
- 0 -> binding.settingsEpList
- 1 -> binding.settingsEpGrid
- 2 -> binding.settingsEpCompact
- else -> binding.settingsEpList
- }
- previousEp.alpha = 1f
- fun uiEp(mode: Int, current: View) {
- previousEp.alpha = 0.33f
- previousEp = current
- current.alpha = 1f
- PrefManager.setVal(PrefName.AnimeDefaultView, mode)
- }
-
- binding.settingsEpList.setOnClickListener {
- uiEp(0, it)
- }
-
- binding.settingsEpGrid.setOnClickListener {
- uiEp(1, it)
- }
-
- binding.settingsEpCompact.setOnClickListener {
- uiEp(2, it)
- }
-
- var previousChp: View = when (PrefManager.getVal(PrefName.MangaDefaultView)) {
- 0 -> binding.settingsChpList
- 1 -> binding.settingsChpCompact
- else -> binding.settingsChpList
- }
- previousChp.alpha = 1f
- fun uiChp(mode: Int, current: View) {
- previousChp.alpha = 0.33f
- previousChp = current
- current.alpha = 1f
- PrefManager.setVal(PrefName.MangaDefaultView, mode)
- }
-
- binding.settingsChpList.setOnClickListener {
- uiChp(0, it)
- }
-
- binding.settingsChpCompact.setOnClickListener {
- uiChp(1, it)
+ settingsShareLog.setOnClickListener {
+ Logger.shareLog(this@SettingsActivity)
+ }
}
binding.settingBuyMeCoffee.setOnClickListener {
lifecycleScope.launch {
it.pop()
}
- openLinkInBrowser("https://www.buymeacoffee.com/rebelonion")
+ openLinkInBrowser(getString(R.string.coffee))
}
lifecycleScope.launch {
binding.settingBuyMeCoffee.pop()
@@ -602,13 +995,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
binding.loginTelegram.setOnClickListener {
openLinkInBrowser(getString(R.string.telegram))
}
- binding.settingsUi.setOnClickListener {
- startActivity(Intent(this, UserInterfaceSettingsActivity::class.java))
- }
- binding.settingsFAQ.setOnClickListener {
- startActivity(Intent(this, FAQActivity::class.java))
- }
(binding.settingsLogo.drawable as Animatable).start()
val array = resources.getStringArray(R.array.tips)
@@ -617,9 +1004,8 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
cursedCounter++
(binding.settingsLogo.drawable as Animatable).start()
if (cursedCounter % 7 == 0) {
- Toast.makeText(this, "youwu have been cuwsed :pwayge:", Toast.LENGTH_LONG).show()
- val url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
- openLinkInBrowser(url)
+ toast(R.string.you_cursed)
+ openLinkInYouTube(getString(R.string.cursed_yt))
//PrefManager.setVal(PrefName.ImageUrl, !PrefManager.getVal(PrefName.ImageUrl, false))
} else {
snackString(array[(Math.random() * array.size).toInt()], this)
@@ -627,364 +1013,22 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
}
- binding.settingsDev.setOnClickListener {
- DevelopersDialogFragment().show(supportFragmentManager, "dialog")
- }
- binding.settingsForks.setOnClickListener {
- ForksDialogFragment().show(supportFragmentManager, "dialog")
- }
- binding.settingsDisclaimer.setOnClickListener {
- val title = getString(R.string.disclaimer)
- val text = TextView(this)
- text.setText(R.string.full_disclaimer)
-
- CustomBottomDialog.newInstance().apply {
- setTitleText(title)
- addView(text)
- setNegativeButton(currContext()!!.getString(R.string.close)) {
- dismiss()
- }
- show(supportFragmentManager, "dialog")
- }
- }
-
- var curTime = PrefManager.getVal(PrefName.SubscriptionNotificationInterval)
- val timeNames = checkIntervals.map {
- val mins = it % 60
- val hours = it / 60
- if (it > 0) "${if (hours > 0) "$hours hrs " else ""}${if (mins > 0) "$mins mins" else ""}"
- else getString(R.string.do_not_update)
- }.toTypedArray()
- binding.settingsSubscriptionsTime.text =
- getString(R.string.subscriptions_checking_time_s, timeNames[curTime])
- val speedDialog = AlertDialog.Builder(this, R.style.MyPopup)
- .setTitle(R.string.subscriptions_checking_time)
- binding.settingsSubscriptionsTime.setOnClickListener {
- val dialog = speedDialog.setSingleChoiceItems(timeNames, curTime) { dialog, i ->
- curTime = i
- binding.settingsSubscriptionsTime.text =
- getString(R.string.subscriptions_checking_time_s, timeNames[i])
- PrefManager.setVal(PrefName.SubscriptionNotificationInterval, curTime)
- dialog.dismiss()
- TaskScheduler.create(this,
- PrefManager.getVal(PrefName.UseAlarmManager)
- ).scheduleAllTasks(this)
- }.show()
- dialog.window?.setDimAmount(0.8f)
- }
-
- binding.settingsSubscriptionsTime.setOnLongClickListener {
- TaskScheduler.create(this,
- PrefManager.getVal(PrefName.UseAlarmManager)
- ).scheduleAllTasks(this)
- true
- }
-
- val aTimeNames = AnilistNotificationWorker.checkIntervals.map { it.toInt() }
- val aItems = aTimeNames.map {
- val mins = it % 60
- val hours = it / 60
- if (it > 0) "${if (hours > 0) "$hours hrs " else ""}${if (mins > 0) "$mins mins" else ""}"
- else getString(R.string.do_not_update)
- }
- binding.settingsAnilistSubscriptionsTime.text =
- getString(R.string.anilist_notifications_checking_time, aItems[PrefManager.getVal(PrefName.AnilistNotificationInterval)])
- binding.settingsAnilistSubscriptionsTime.setOnClickListener {
-
- val selected = PrefManager.getVal(PrefName.AnilistNotificationInterval)
- val dialog = AlertDialog.Builder(this, R.style.MyPopup)
- .setTitle(R.string.subscriptions_checking_time)
- .setSingleChoiceItems(aItems.toTypedArray(), selected) { dialog, i ->
- PrefManager.setVal(PrefName.AnilistNotificationInterval, i)
- binding.settingsAnilistSubscriptionsTime.text =
- getString(R.string.anilist_notifications_checking_time, aItems[i])
- dialog.dismiss()
- TaskScheduler.create(this,
- PrefManager.getVal(PrefName.UseAlarmManager)
- ).scheduleAllTasks(this)
- }
- .create()
- dialog.window?.setDimAmount(0.8f)
- dialog.show()
- }
-
- binding.settingsAnilistNotifications.setOnClickListener {
- val types = NotificationType.entries.map { it.name }
- val filteredTypes = PrefManager.getVal>(PrefName.AnilistFilteredTypes).toMutableSet()
- val selected = types.map { filteredTypes.contains(it) }.toBooleanArray()
- val dialog = AlertDialog.Builder(this, R.style.MyPopup)
- .setTitle(R.string.anilist_notification_filters)
- .setMultiChoiceItems(types.toTypedArray(), selected) { _, which, isChecked ->
- val type = types[which]
- if (isChecked) {
- filteredTypes.add(type)
- } else {
- filteredTypes.remove(type)
- }
- PrefManager.setVal(PrefName.AnilistFilteredTypes, filteredTypes)
- }
- .create()
- dialog.window?.setDimAmount(0.8f)
- dialog.show()
- }
-
- val cTimeNames = CommentNotificationWorker.checkIntervals.map { it.toInt() }
- val cItems = cTimeNames.map {
- val mins = it % 60
- val hours = it / 60
- if (it > 0) "${if (hours > 0) "$hours hrs " else ""}${if (mins > 0) "$mins mins" else ""}"
- else getString(R.string.do_not_update)
- }
- binding.settingsCommentSubscriptionsTime.text =
- getString(R.string.comment_notification_checking_time, cItems[PrefManager.getVal(PrefName.CommentNotificationInterval)])
- binding.settingsCommentSubscriptionsTime.setOnClickListener {
- val selected = PrefManager.getVal(PrefName.CommentNotificationInterval)
- val dialog = AlertDialog.Builder(this, R.style.MyPopup)
- .setTitle(R.string.subscriptions_checking_time)
- .setSingleChoiceItems(cItems.toTypedArray(), selected) { dialog, i ->
- PrefManager.setVal(PrefName.CommentNotificationInterval, i)
- binding.settingsCommentSubscriptionsTime.text =
- getString(R.string.comment_notification_checking_time, cItems[i])
- dialog.dismiss()
- TaskScheduler.create(this,
- PrefManager.getVal(PrefName.UseAlarmManager)
- ).scheduleAllTasks(this)
- }
- .create()
- dialog.window?.setDimAmount(0.8f)
- dialog.show()
- }
-
- binding.settingsNotificationsCheckingSubscriptions.isChecked =
- PrefManager.getVal(PrefName.SubscriptionCheckingNotifications)
- binding.settingsNotificationsCheckingSubscriptions.setOnCheckedChangeListener { _, isChecked ->
- PrefManager.setVal(PrefName.SubscriptionCheckingNotifications, isChecked)
- }
-
- binding.settingsNotificationsCheckingSubscriptions.setOnLongClickListener {
- openSettings(this, null)
- }
-
- binding.settingsNotificationsUseAlarmManager.isChecked =
- PrefManager.getVal(PrefName.UseAlarmManager)
-
- binding.settingsNotificationsUseAlarmManager.setOnCheckedChangeListener { _, isChecked ->
- if (isChecked) {
- val alertDialog = AlertDialog.Builder(this, R.style.MyPopup)
- .setTitle("Use Alarm Manager")
- .setMessage("Using Alarm Manger can help fight against battery optimization, but may consume more battery. It also requires the Alarm Manager permission.")
- .setPositiveButton("Use") { dialog, _ ->
- PrefManager.setVal(PrefName.UseAlarmManager, true)
- if (SDK_INT >= Build.VERSION_CODES.S) {
- if (!(getSystemService(Context.ALARM_SERVICE) as AlarmManager).canScheduleExactAlarms()) {
- val intent = Intent("android.settings.REQUEST_SCHEDULE_EXACT_ALARM")
- startActivity(intent)
- binding.settingsNotificationsCheckingSubscriptions.isChecked = true
- }
- }
- dialog.dismiss()
- }
- .setNegativeButton("Cancel") { dialog, _ ->
- binding.settingsNotificationsCheckingSubscriptions.isChecked = false
- PrefManager.setVal(PrefName.UseAlarmManager, false)
- dialog.dismiss()
- }
- .create()
- alertDialog.window?.setDimAmount(0.8f)
- alertDialog.show()
- } else {
- PrefManager.setVal(PrefName.UseAlarmManager, false)
- TaskScheduler.create(this, true).cancelAllTasks()
- TaskScheduler.create(this, false).scheduleAllTasks(this)
- }
- }
-
- if (!BuildConfig.FLAVOR.contains("fdroid")) {
- binding.settingsLogo.setOnLongClickListener {
- lifecycleScope.launch(Dispatchers.IO) {
- AppUpdater.check(this@SettingsActivity, true)
- }
- true
- }
-
- binding.settingsCheckUpdate.isChecked = PrefManager.getVal(PrefName.CheckUpdate)
- binding.settingsCheckUpdate.setOnCheckedChangeListener { _, isChecked ->
- PrefManager.setVal(PrefName.CheckUpdate, isChecked)
- if (!isChecked) {
- snackString(getString(R.string.long_click_to_check_update))
- }
- }
-
- binding.settingsCheckUpdate.setOnLongClickListener {
- lifecycleScope.launch(Dispatchers.IO) {
- AppUpdater.check(this@SettingsActivity, true)
- }
- true
- }
-
- binding.settingsShareUsername.isChecked = PrefManager.getVal(PrefName.SharedUserID)
- binding.settingsShareUsername.setOnCheckedChangeListener { _, isChecked ->
- PrefManager.setVal(PrefName.SharedUserID, isChecked)
- }
-
- } else {
- binding.settingsCheckUpdate.visibility = View.GONE
- binding.settingsShareUsername.visibility = View.GONE
- binding.settingsCheckUpdate.isEnabled = false
- binding.settingsShareUsername.isEnabled = false
- binding.settingsCheckUpdate.isChecked = false
- binding.settingsShareUsername.isChecked = false
- }
-
- binding.settingsLogToFile.isChecked = PrefManager.getVal(PrefName.LogToFile)
- binding.settingsLogToFile.setOnCheckedChangeListener { _, isChecked ->
- PrefManager.setVal(PrefName.LogToFile, isChecked)
- restartApp()
- }
-
- binding.settingsShareLog.setOnClickListener {
- Logger.shareLog(this)
- }
-
- binding.settingsAccountHelp.setOnClickListener {
- val title = getString(R.string.account_help)
- val full = getString(R.string.full_account_help)
- CustomBottomDialog.newInstance().apply {
- setTitleText(title)
- addView(
- TextView(it.context).apply {
- val markWon = Markwon.builder(it.context)
- .usePlugin(SoftBreakAddsNewLinePlugin.create()).build()
- markWon.setMarkdown(this, full)
- }
- )
- }.show(supportFragmentManager, "dialog")
- }
-
- fun reload() {
- if (Anilist.token != null) {
- binding.settingsAnilistLogin.setText(R.string.logout)
- binding.settingsAnilistLogin.setOnClickListener {
- Anilist.removeSavedToken()
- restartMainActivity.isEnabled = true
- reload()
- }
- binding.settingsAnilistUsername.visibility = View.VISIBLE
- binding.settingsAnilistUsername.text = Anilist.username
- binding.settingsAnilistAvatar.loadImage(Anilist.avatar)
-
- binding.settingsMALLoginRequired.visibility = View.GONE
- binding.settingsMALLogin.visibility = View.VISIBLE
- binding.settingsMALUsername.visibility = View.VISIBLE
-
- if (MAL.token != null) {
- binding.settingsMALLogin.setText(R.string.logout)
- binding.settingsMALLogin.setOnClickListener {
- MAL.removeSavedToken(it.context)
- restartMainActivity.isEnabled = true
- reload()
- }
- binding.settingsMALUsername.visibility = View.VISIBLE
- binding.settingsMALUsername.text = MAL.username
- binding.settingsMALAvatar.loadImage(MAL.avatar)
- } else {
- binding.settingsMALAvatar.setImageResource(R.drawable.ic_round_person_24)
- binding.settingsMALUsername.visibility = View.GONE
- binding.settingsMALLogin.setText(R.string.login)
- binding.settingsMALLogin.setOnClickListener {
- MAL.loginIntent(this)
- }
- }
- } else {
- binding.settingsAnilistAvatar.setImageResource(R.drawable.ic_round_person_24)
- binding.settingsAnilistUsername.visibility = View.GONE
- binding.settingsAnilistLogin.setText(R.string.login)
- binding.settingsAnilistLogin.setOnClickListener {
- Anilist.loginIntent(this)
- }
- binding.settingsMALLoginRequired.visibility = View.VISIBLE
- binding.settingsMALLogin.visibility = View.GONE
- binding.settingsMALUsername.visibility = View.GONE
- }
-
- if (Discord.token != null) {
- val id = PrefManager.getVal(PrefName.DiscordId, null as String?)
- val avatar = PrefManager.getVal(PrefName.DiscordAvatar, null as String?)
- val username = PrefManager.getVal(PrefName.DiscordUserName, null as String?)
- if (id != null && avatar != null) {
- binding.settingsDiscordAvatar.loadImage("https://cdn.discordapp.com/avatars/$id/$avatar.png")
- }
- binding.settingsDiscordUsername.visibility = View.VISIBLE
- binding.settingsDiscordUsername.text =
- username ?: Discord.token?.replace(Regex("."), "*")
- binding.settingsDiscordLogin.setText(R.string.logout)
- binding.settingsDiscordLogin.setOnClickListener {
- Discord.removeSavedToken(this)
- restartMainActivity.isEnabled = true
- reload()
- }
-
- binding.imageSwitcher.visibility = View.VISIBLE
- var initialStatus = when (PrefManager.getVal(PrefName.DiscordStatus)) {
- "online" -> R.drawable.discord_status_online
- "idle" -> R.drawable.discord_status_idle
- "dnd" -> R.drawable.discord_status_dnd
- else -> R.drawable.discord_status_online
- }
- binding.imageSwitcher.setImageResource(initialStatus)
-
- val zoomInAnimation = AnimationUtils.loadAnimation(this, R.anim.bounce_zoom)
- binding.imageSwitcher.setOnClickListener {
- var status = "online"
- initialStatus = when (initialStatus) {
- R.drawable.discord_status_online -> {
- status = "idle"
- R.drawable.discord_status_idle
- }
- R.drawable.discord_status_idle -> {
- status = "dnd"
- R.drawable.discord_status_dnd
- }
- R.drawable.discord_status_dnd -> {
- status = "online"
- R.drawable.discord_status_online
- }
- else -> R.drawable.discord_status_online
- }
-
- PrefManager.setVal(PrefName.DiscordStatus, status)
- binding.imageSwitcher.setImageResource(initialStatus)
- binding.imageSwitcher.startAnimation(zoomInAnimation)
- }
- } else {
- binding.imageSwitcher.visibility = View.GONE
- binding.settingsDiscordAvatar.setImageResource(R.drawable.ic_round_person_24)
- binding.settingsDiscordUsername.visibility = View.GONE
- binding.settingsDiscordLogin.setText(R.string.login)
- binding.settingsDiscordLogin.setOnClickListener {
- Discord.warning(this).show(supportFragmentManager, "dialog")
- }
- }
- }
- reload()
-
lifecycleScope.launch(Dispatchers.IO) {
delay(2000)
runOnUiThread {
if (Random.nextInt(0, 100) > 69) {
CustomBottomDialog.newInstance().apply {
- title = "Enjoying the App?"
+ title = getString(R.string.enjoying_app)
addView(TextView(this@SettingsActivity).apply {
- text =
- "Consider donating!"
+ text = context.getString(R.string.consider_donating)
})
- setNegativeButton("no moners :(") {
- snackString("That's alright, you'll be a rich man soon :prayge:")
+ setNegativeButton(getString(R.string.no_moners)) {
+ snackString(R.string.you_be_rich)
dismiss()
}
- setPositiveButton("denote :)") {
+ setPositiveButton(getString(R.string.donate)) {
binding.settingBuyMeCoffee.performClick()
dismiss()
}
@@ -1017,7 +1061,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
context.packageName
)!!.component
)
- setAction("Do it!") {
+ setAction(getString(R.string.do_it)) {
context.startActivity(mainIntent)
Runtime.getRuntime().exit(0)
}
@@ -1031,14 +1075,14 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
// Inflate the dialog layout
val dialogView = LayoutInflater.from(this).inflate(R.layout.dialog_user_agent, null)
val box = dialogView.findViewById(R.id.userAgentTextBox)
- box?.hint = "Password"
+ box?.hint = getString(R.string.password)
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, _ ->
+ .setPositiveButton(R.string.ok, null)
+ .setNegativeButton(R.string.cancel) { dialog, _ ->
password.fill('0')
dialog.dismiss()
callback(null)
@@ -1051,7 +1095,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, _ ->
@@ -1065,7 +1109,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
val subtitleTextView = dialogView.findViewById(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)
diff --git a/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt b/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt
index 89a65b17..535b7273 100644
--- a/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt
+++ b/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt
@@ -9,9 +9,9 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
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
@@ -24,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
@@ -41,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(
@@ -94,7 +96,7 @@ class SettingsDialogFragment : BottomSheetDialogFragment() {
Anilist.loginIntent(requireActivity())
}
}
- binding.settingsNotificationCount.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE
+ binding.settingsNotificationCount.isVisible = Anilist.unreadNotificationCount > 0
binding.settingsNotificationCount.text = Anilist.unreadNotificationCount.toString()
binding.settingsUserAvatar.setOnClickListener{
ContextCompat.startActivity(
diff --git a/app/src/main/java/ani/dantotsu/settings/paging/AnimePagingSource.kt b/app/src/main/java/ani/dantotsu/settings/paging/AnimePagingSource.kt
index 53fe43cb..1d7d5f92 100644
--- a/app/src/main/java/ani/dantotsu/settings/paging/AnimePagingSource.kt
+++ b/app/src/main/java/ani/dantotsu/settings/paging/AnimePagingSource.kt
@@ -202,12 +202,12 @@ class AnimeExtensionAdapter(private val clickListener: OnAnimeInstallClickListen
val extensionIconImageView: ImageView = binding.extensionIconImageView
- @SuppressLint("SetTextI18n")
fun bind(extension: AnimeExtension.Available) {
val nsfw = if (extension.isNsfw) "(18+)" else ""
val lang = LanguageMapper.mapLanguageCodeToName(extension.lang)
binding.extensionNameTextView.text = extension.name
- binding.extensionVersionTextView.text = "$lang ${extension.versionName} $nsfw"
+ val versionText = "$lang ${extension.versionName} $nsfw"
+ binding.extensionVersionTextView.text = versionText
}
fun clear() {
diff --git a/app/src/main/java/ani/dantotsu/settings/paging/MangaPagingSource.kt b/app/src/main/java/ani/dantotsu/settings/paging/MangaPagingSource.kt
index 140eb549..1227d667 100644
--- a/app/src/main/java/ani/dantotsu/settings/paging/MangaPagingSource.kt
+++ b/app/src/main/java/ani/dantotsu/settings/paging/MangaPagingSource.kt
@@ -199,12 +199,12 @@ class MangaExtensionAdapter(private val clickListener: OnMangaInstallClickListen
val extensionIconImageView: ImageView = binding.extensionIconImageView
- @SuppressLint("SetTextI18n")
fun bind(extension: MangaExtension.Available) {
val nsfw = if (extension.isNsfw) "(18+)" else ""
val lang = LanguageMapper.mapLanguageCodeToName(extension.lang)
binding.extensionNameTextView.text = extension.name
- binding.extensionVersionTextView.text = "$lang ${extension.versionName} $nsfw"
+ val versionText = "$lang ${extension.versionName} $nsfw"
+ binding.extensionVersionTextView.text = versionText
}
fun clear() {
diff --git a/app/src/main/java/ani/dantotsu/settings/paging/NovelPagingSource.kt b/app/src/main/java/ani/dantotsu/settings/paging/NovelPagingSource.kt
index 46379b76..fa2bf1ae 100644
--- a/app/src/main/java/ani/dantotsu/settings/paging/NovelPagingSource.kt
+++ b/app/src/main/java/ani/dantotsu/settings/paging/NovelPagingSource.kt
@@ -41,13 +41,14 @@ import kotlinx.coroutines.withContext
class NovelExtensionsViewModelFactory(
private val novelExtensionManager: NovelExtensionManager
) : ViewModelProvider.Factory {
+ @Suppress("UNCHECKED_CAST")
override fun create(modelClass: Class): 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)
diff --git a/app/src/main/java/ani/dantotsu/util/AniMarkdown.kt b/app/src/main/java/ani/dantotsu/util/AniMarkdown.kt
index 6bac3fcc..54cd0dff 100644
--- a/app/src/main/java/ani/dantotsu/util/AniMarkdown.kt
+++ b/app/src/main/java/ani/dantotsu/util/AniMarkdown.kt
@@ -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(), "
$1
")
.replace("(?s)__(.*?)__".toRegex(), "
$1
")
- .replace("(?s)[\\s]+_([^_]+)_[\\s]+".toRegex(), "$1")
+ .replace("(?s)\\s+_([^_]+)_\\s+".toRegex(), "$1")
}
fun getBasicAniHTML(html: String): String {
diff --git a/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringRemoteViewsFactory.kt b/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringRemoteViewsFactory.kt
index 75f35588..8cf8029a 100644
--- a/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringRemoteViewsFactory.kt
+++ b/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringRemoteViewsFactory.kt
@@ -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()
diff --git a/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringRemoteViewsService.kt b/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringRemoteViewsService.kt
index a0ff2efc..4d042b33 100644
--- a/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringRemoteViewsService.kt
+++ b/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringRemoteViewsService.kt
@@ -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)
}
}
diff --git a/app/src/main/java/eu/kanade/domain/base/ExtensionInstallerPreference.kt b/app/src/main/java/eu/kanade/domain/base/ExtensionInstallerPreference.kt
index e9a5c3a7..a52789f5 100644
--- a/app/src/main/java/eu/kanade/domain/base/ExtensionInstallerPreference.kt
+++ b/app/src/main/java/eu/kanade/domain/base/ExtensionInstallerPreference.kt
@@ -20,7 +20,7 @@ class ExtensionInstallerPreference(
val entries
- get() = ExtensionInstaller.values().run {
+ get() = ExtensionInstaller.entries.toTypedArray().run {
if (context.hasMiuiPackageInstaller) {
filter { it != ExtensionInstaller.PACKAGEINSTALLER }
} else {
diff --git a/app/src/main/java/eu/kanade/tachiyomi/animesource/AnimeSource.kt b/app/src/main/java/eu/kanade/tachiyomi/animesource/AnimeSource.kt
index 53da5305..171b07b2 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/animesource/AnimeSource.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/animesource/AnimeSource.kt
@@ -58,8 +58,7 @@ interface AnimeSource {
*/
@Suppress("DEPRECATION")
suspend fun getVideoList(episode: SEpisode): List
diff --git a/app/src/main/res/layout/dialog_edittext.xml b/app/src/main/res/layout/dialog_edittext.xml
index 86970870..bfd55e12 100644
--- a/app/src/main/res/layout/dialog_edittext.xml
+++ b/app/src/main/res/layout/dialog_edittext.xml
@@ -1,5 +1,6 @@
+ android:autofillHints="e.g. 1"
+ tools:ignore="LabelFor" />
diff --git a/app/src/main/res/layout/dialog_layout.xml b/app/src/main/res/layout/dialog_layout.xml
index 0aa95217..4eae05d3 100644
--- a/app/src/main/res/layout/dialog_layout.xml
+++ b/app/src/main/res/layout/dialog_layout.xml
@@ -120,7 +120,7 @@
android:layout_height="wrap_content"
android:alpha="0.58"
android:fontFamily="@font/poppins_bold"
- android:text="Sort" />
+ android:text="@string/sort" />
+ android:text="@string/download" />
+ android:text="@string/scanlator" />
+ android:text="@string/set_cookies" />
diff --git a/app/src/main/res/layout/dialog_user_agent.xml b/app/src/main/res/layout/dialog_user_agent.xml
index 61cb3e95..fa9ac0c1 100644
--- a/app/src/main/res/layout/dialog_user_agent.xml
+++ b/app/src/main/res/layout/dialog_user_agent.xml
@@ -11,7 +11,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins"
- android:text="Exporting credentials requires a password for encryption."
+ android:text="@string/exporting_requires_encryption"
android:textSize="18sp"
android:visibility="gone" />
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index 31cea274..c3caeff4 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -49,7 +49,8 @@
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="horizontal"
- android:padding="32dp">
+ android:padding="32dp"
+ android:baselineAligned="false">
+ android:text="@string/anime_queue" />
+ android:text="@string/manga_queue" />
diff --git a/app/src/main/res/layout/item_anime_page.xml b/app/src/main/res/layout/item_anime_page.xml
index 52b064dc..2cc202a0 100644
--- a/app/src/main/res/layout/item_anime_page.xml
+++ b/app/src/main/res/layout/item_anime_page.xml
@@ -9,104 +9,7 @@
android:layout_marginEnd="-16dp"
android:orientation="vertical">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ android:layout_height="match_parent"
+ android:baselineAligned="false">
+ tools:text="Dubbed"
+ tools:ignore="RtlSymmetry" />
@@ -356,7 +358,7 @@
android:text="@string/source_not_found"
android:textAlignment="center"
android:textSize="16sp"
- android:visibility="gone"/>
+ android:visibility="gone"/>
Show notification for Checking Subscriptions
- Use Alarm Manager for reliable Notifications
+ Use Alarm Manager
+ Use Alarm Manager for reliable Notifications
+ Using Alarm Manger can help fight against battery optimization, but may consume more battery. It also requires the Alarm Manager permission.
+ Use
Notification for Checking Subscriptions
Subscriptions Update Frequency : %1$s
Subscriptions Update Frequency
Amount of time for Dantotsu to periodically check for new Episodes/Chapters\n(Less time will cause more battery consumption)
Don\'t Update
Loading Next Chapter
- Grid
Sort by Release Date
Crop Borders
NOTE
@@ -404,7 +418,7 @@
You Long Click the button to check for App Update
Saved to:\n%s
Setting progress to %1$d
- Please Login into anilist account!
+ Please Login into AniList account!
Congrats Vro
Please Reload.
Copied "%1$s"
@@ -418,7 +432,7 @@
You can long click List Editor button to Reset Auto Update
Autoplay cancelled, no Interaction for more than 1 Hour.
Couldn\'t auto select the server, Please try again!
- No streams available for content. Try another source.
+ No streams available! Try another source.
Logging in MAL
Getting User Data
No next Episode Found!
@@ -490,19 +504,21 @@
Read on Dantotsu
Watch on Dantotsu
View Profile in Dantotsu
- "Continue : Episode "
- "Continue : "
+ Continue : Episode %1$s%2$s\n%3$s
+ - Filler
+ Continue : %1$s\n%2$s
"Episode "
"Episode %1$s"
"Chapter "
"Chapter %1$s"
- just got released!
Checking Subscriptions
+ %1$s\'s %2$s List
Speed
Auto Update progress for %1$s?
Continue from %1$s?
- Update progress on anilist?
+ Update progress on AniList?
Incognito mode will still ignore progress.
"Don\'t ask again for %1$s"
Default Speed
@@ -515,6 +531,8 @@
Yes
No
+ OK
+ Reset
Close
No Chapter
Turn on 18+ Content from your Anilist Settings
@@ -657,7 +675,7 @@
This is an app widget description
Airing Image
animeDownloads
- Delete all anime downloads
+ Delete all Anime downloads
Delete all Manga Downloads
Delete all Novel Downloads
Requires Android 12+
@@ -681,6 +699,7 @@
User has no favorite Manga
Favourite Characters
Favorite Staff
+
Stats
Days watched
Total Anime
@@ -690,7 +709,33 @@
Manga Mean Score
About me
Follow
-
+ Following
+ Unfollow
+ Follows you
+ Mutual
+ Success
+
+ Currently Airing
+ No shows to display
+ Extension Name
+ version
+ Enter your password to decrypt the file
+ Show Rotate Button
+ Default Manga Settings
+ Use Dark Theme
+ Use OLED Theme
+ Scanlators
+ Exporting credentials requires a password for encryption.
+ Manga Queue (WIP)
+ Anime Queue (WIP)
+ No offline manga found
+ Sort
+ Download
+ Scanlator
+ Set Cookies
+ Open Website
+
+
Lorem ipsum dolor sit amet. Est consectetur sint qui internos optio nam Quis excepturi qui voluptatem animi. Qui labore quasi vel suscipit deleniti et doloremque omnis in velit suscipit et quasi eaque. Et doloribus recusandae id laudantium Quis qui natus velit in voluptatem voluptatem!
@@ -710,4 +755,55 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
Anilist notifications update frequency : %1$s
Comment notifications update frequency : %1$s
Activities
+
+ Incorrect password
+ Password cannot be empty
+ Unknown file type
+ Error importing settings
+ Download Manager
+ Enter Password
+
+ youwu have been cuwsed :pwayge:
+ https://www.youtube.com/watch?v=dQw4w9WgXcQ
+ Are you sure you want to purge all %1$s downloads?
+
+ Failed to delete because of… %1$s
+
+ Hide replies
+ View reply
+ View replies
+ View %1$d replies
+ Replying to %1$s
+
+ Delete Comment
+ Are you sure you want to delete this comment?
+ Comment Deleted
+
+ Ban User
+ Are you sure you want to ban this user?
+ User Banned
+
+ Report Comment
+ Only report comments that violate the rules. Are you sure you want to report this comment?
+ Comment Reported
+
+ List
+ Grid
+ Compact
+
+ WebView not installed
+
+ Quality: %1$dp
+ Unknown Size
+ %1$s MB
+ Import…
+ Export…
+ No location selected
+ Enjoying the App?
+ Consider donating!
+ no moners :(
+ That\'s alright, you\'ll be a rich man soon :prayge:
+ donate :)
+ Do it!
+ Password
diff --git a/app/src/main/res/xml-v31/currently_airing_widget_info.xml b/app/src/main/res/xml-v31/currently_airing_widget_info.xml
new file mode 100644
index 00000000..30d7c6f0
--- /dev/null
+++ b/app/src/main/res/xml-v31/currently_airing_widget_info.xml
@@ -0,0 +1,14 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/currently_airing_widget_info.xml b/app/src/main/res/xml/currently_airing_widget_info.xml
index 30d7c6f0..ac32ee7a 100644
--- a/app/src/main/res/xml/currently_airing_widget_info.xml
+++ b/app/src/main/res/xml/currently_airing_widget_info.xml
@@ -6,9 +6,6 @@
android:minWidth="160dp"
android:minHeight="160dp"
android:previewImage="@drawable/example_appwidget_preview"
- android:previewLayout="@layout/currently_airing_widget"
android:resizeMode="horizontal|vertical"
- android:targetCellWidth="1"
- android:targetCellHeight="1"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen">
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 147bafe3..8f7bd6c8 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,4 +1,4 @@
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
buildscript {
repositories {
@@ -26,8 +26,9 @@ tasks.register('clean', Delete) {
delete getLayout().getBuildDirectory()
}
-tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
- kotlinOptions {
- freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
+
+tasks.withType(KotlinJvmCompile).configureEach {
+ compilerOptions {
+ freeCompilerArgs.add("-opt-in=kotlin.RequiresOptIn")
}
}
diff --git a/lint.xml b/lint.xml
index 652f2203..bc62ec86 100644
--- a/lint.xml
+++ b/lint.xml
@@ -2,4 +2,6 @@
+
+
\ No newline at end of file