mirror of
https://github.com/rebelonion/Dantotsu.git
synced 2026-01-18 09:53:56 +00:00
Merge branch 'dev' into Dunno
This commit is contained in:
7
.github/workflows/beta.yml
vendored
7
.github/workflows/beta.yml
vendored
@@ -3,7 +3,10 @@ name: Build APK and Notify Discord
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- Dunno
|
||||
- dev
|
||||
paths-ignore:
|
||||
- '**/README.md'
|
||||
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -50,7 +53,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
contentbody=$( jq -Rsa . <<< "${{ github.event.head_commit.message }}" )
|
||||
curl -F "payload_json={\"content\":\" everyone **${{ env.VERSION }}**\n\n${contentbody:1:-1}\"}" -F "dantotsu_debug=@app/build/outputs/apk/debug/app-debug.apk" ${{ secrets.DISCORD_WEBHOOK }}
|
||||
curl -F "payload_json={\"content\":\" Debug-Build **${{ env.VERSION }}**\n\n${contentbody:1:-1}\"}" -F "dantotsu_debug=@app/build/outputs/apk/debug/app-debug.apk" ${{ secrets.DISCORD_WEBHOOK }}
|
||||
|
||||
- name: Delete Old Pre-Releases
|
||||
id: delete-pre-releases
|
||||
|
||||
@@ -21,7 +21,7 @@ android {
|
||||
minSdk 23
|
||||
targetSdk 34
|
||||
versionCode ((System.currentTimeMillis() / 60000).toInteger())
|
||||
versionName "2.0.0-beta00-i"
|
||||
versionName "2.0.0-beta00-iv2"
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
|
||||
@@ -90,6 +90,9 @@ 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
|
||||
implementation "androidx.media3:media3-cast:$exo_version"
|
||||
implementation "androidx.mediarouter:mediarouter:1.6.0"
|
||||
|
||||
// UI
|
||||
implementation 'com.google.android.material:material:1.10.0'
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
android:required="false" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
|
||||
tools:ignore="LeanbackUsesWifi" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
@@ -45,7 +47,7 @@
|
||||
<application
|
||||
android:name=".App"
|
||||
android:allowBackup="true"
|
||||
android:banner="@drawable/ic_banner_foreground"
|
||||
android:banner="@mipmap/ic_banner_foreground"
|
||||
android:icon="${icon_placeholder}"
|
||||
android:label="@string/app_name"
|
||||
android:largeHeap="true"
|
||||
@@ -271,9 +273,10 @@
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS"
|
||||
android:exported="true" />
|
||||
<service
|
||||
android:name=".download.video.MyDownloadService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
android:name=".download.video.ExoplayerDownloadService"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="dataSync">
|
||||
<intent-filter>
|
||||
<action android:name="androidx.media3.exoplayer.downloadService.action.RESTART" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
@@ -295,10 +298,16 @@
|
||||
android:name=".download.novel.NovelDownloaderService"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="dataSync" />
|
||||
<service android:name=".download.anime.AnimeDownloaderService"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="dataSync" />
|
||||
<service
|
||||
android:name=".connections.discord.DiscordService"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="dataSync" />
|
||||
|
||||
<meta-data android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
|
||||
android:value="androidx.media3.cast.DefaultCastOptionsProvider"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -53,6 +53,7 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.google.android.material.internal.ViewUtils
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import kotlinx.coroutines.*
|
||||
import nl.joery.animatedbottombar.AnimatedBottomBar
|
||||
import java.io.*
|
||||
@@ -673,7 +674,7 @@ fun copyToClipboard(string: String, toast: Boolean = true) {
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun countDown(media: Media, view: ViewGroup) {
|
||||
if (media.anime?.nextAiringEpisode != null && media.anime.nextAiringEpisodeTime != null && (media.anime.nextAiringEpisodeTime!! - System.currentTimeMillis() / 1000) <= 86400 * 7.toLong()) {
|
||||
if (media.anime?.nextAiringEpisode != null && media.anime.nextAiringEpisodeTime != null && (media.anime.nextAiringEpisodeTime!! - System.currentTimeMillis() / 1000) <= 86400 * 28.toLong()) {
|
||||
val v = ItemCountDownBinding.inflate(LayoutInflater.from(view.context), view, false)
|
||||
view.addView(v.root, 0)
|
||||
v.mediaCountdownText.text =
|
||||
@@ -783,35 +784,40 @@ fun toast(string: String?) {
|
||||
}
|
||||
|
||||
fun snackString(s: String?, activity: Activity? = null, clipboard: String? = null) {
|
||||
if (s != null) {
|
||||
(activity ?: currActivity())?.apply {
|
||||
runOnUiThread {
|
||||
val snackBar = Snackbar.make(
|
||||
window.decorView.findViewById(android.R.id.content),
|
||||
s,
|
||||
Snackbar.LENGTH_SHORT
|
||||
)
|
||||
snackBar.view.apply {
|
||||
updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
gravity = (Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM)
|
||||
width = WRAP_CONTENT
|
||||
}
|
||||
translationY = -(navBarHeight.dp + 32f)
|
||||
translationZ = 32f
|
||||
updatePadding(16f.px, right = 16f.px)
|
||||
setOnClickListener {
|
||||
snackBar.dismiss()
|
||||
}
|
||||
setOnLongClickListener {
|
||||
copyToClipboard(clipboard ?: s, false)
|
||||
toast(getString(R.string.copied_to_clipboard))
|
||||
true
|
||||
try { //I have no idea why this sometimes crashes for some people...
|
||||
if (s != null) {
|
||||
(activity ?: currActivity())?.apply {
|
||||
runOnUiThread {
|
||||
val snackBar = Snackbar.make(
|
||||
window.decorView.findViewById(android.R.id.content),
|
||||
s,
|
||||
Snackbar.LENGTH_SHORT
|
||||
)
|
||||
snackBar.view.apply {
|
||||
updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
gravity = (Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM)
|
||||
width = WRAP_CONTENT
|
||||
}
|
||||
translationY = -(navBarHeight.dp + 32f)
|
||||
translationZ = 32f
|
||||
updatePadding(16f.px, right = 16f.px)
|
||||
setOnClickListener {
|
||||
snackBar.dismiss()
|
||||
}
|
||||
setOnLongClickListener {
|
||||
copyToClipboard(clipboard ?: s, false)
|
||||
toast(getString(R.string.copied_to_clipboard))
|
||||
true
|
||||
}
|
||||
}
|
||||
snackBar.show()
|
||||
}
|
||||
snackBar.show()
|
||||
}
|
||||
logger(s)
|
||||
}
|
||||
logger(s)
|
||||
} catch (e: Exception) {
|
||||
logger(e.stackTraceToString())
|
||||
FirebaseCrashlytics.getInstance().recordException(e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,12 +11,14 @@ import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AnticipateInterpolator
|
||||
import android.widget.TextView
|
||||
import androidx.activity.addCallback
|
||||
import androidx.activity.viewModels
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.animation.doOnEnd
|
||||
import androidx.core.content.ContextCompat
|
||||
@@ -26,11 +28,14 @@ import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.exoplayer.offline.Download
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.connections.anilist.AnilistHomeViewModel
|
||||
import ani.dantotsu.databinding.ActivityMainBinding
|
||||
import ani.dantotsu.databinding.SplashScreenBinding
|
||||
import ani.dantotsu.download.video.Helper
|
||||
import ani.dantotsu.home.AnimeFragment
|
||||
import ani.dantotsu.home.HomeFragment
|
||||
import ani.dantotsu.home.LoginFragment
|
||||
@@ -45,6 +50,7 @@ import ani.dantotsu.themes.ThemeManager
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.SoftBreakAddsNewLinePlugin
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -60,7 +66,7 @@ class MainActivity : AppCompatActivity() {
|
||||
private var uiSettings = UserInterfaceSettings()
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@OptIn(UnstableApi::class) override fun onCreate(savedInstanceState: Bundle?) {
|
||||
ThemeManager(this).applyTheme()
|
||||
LangSet.setLocale(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -73,16 +79,10 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
val backgroundDrawable = _bottomBar.background as GradientDrawable
|
||||
val currentColor = backgroundDrawable.color?.defaultColor ?: 0
|
||||
val semiTransparentColor = (currentColor and 0x00FFFFFF) or 0xE8000000.toInt()
|
||||
val semiTransparentColor = (currentColor and 0x00FFFFFF) or 0xF0000000.toInt()
|
||||
backgroundDrawable.setColor(semiTransparentColor)
|
||||
_bottomBar.background = backgroundDrawable
|
||||
}
|
||||
val colorOverflow = this.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
|
||||
.getBoolean("colorOverflow", false)
|
||||
if (!colorOverflow) {
|
||||
_bottomBar.background = ContextCompat.getDrawable(this, R.drawable.bottom_nav_gray)
|
||||
|
||||
}
|
||||
|
||||
|
||||
var doubleBackToExitPressedOnce = false
|
||||
@@ -242,6 +242,25 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
val index = Helper.downloadManager(this@MainActivity).downloadIndex
|
||||
val downloadCursor = index.getDownloads()
|
||||
while (downloadCursor.moveToNext()) {
|
||||
val download = downloadCursor.download
|
||||
Log.e("Downloader", download.request.uri.toString())
|
||||
Log.e("Downloader", download.request.id.toString())
|
||||
Log.e("Downloader", download.request.mimeType.toString())
|
||||
Log.e("Downloader", download.request.data.size.toString())
|
||||
Log.e("Downloader", download.bytesDownloaded.toString())
|
||||
Log.e("Downloader", download.state.toString())
|
||||
Log.e("Downloader", download.failureReason.toString())
|
||||
|
||||
if (download.state == Download.STATE_FAILED) { //simple cleanup
|
||||
Helper.downloadManager(this@MainActivity).removeDownload(download.request.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,11 @@ package ani.dantotsu.aniyomi.anime.custom
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.database.StandaloneDatabaseProvider
|
||||
import androidx.media3.datasource.cache.SimpleCache
|
||||
import ani.dantotsu.download.DownloadsManager
|
||||
import ani.dantotsu.media.manga.MangaCache
|
||||
import ani.dantotsu.parsers.novel.NovelExtensionManager
|
||||
@@ -27,7 +31,7 @@ import uy.kohesive.injekt.api.addSingletonFactory
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class AppModule(val app: Application) : InjektModule {
|
||||
override fun InjektRegistrar.registerInjectables() {
|
||||
@OptIn(UnstableApi::class) override fun InjektRegistrar.registerInjectables() {
|
||||
addSingleton(app)
|
||||
|
||||
addSingletonFactory { DownloadsManager(app) }
|
||||
@@ -51,6 +55,8 @@ class AppModule(val app: Application) : InjektModule {
|
||||
}
|
||||
}
|
||||
|
||||
addSingletonFactory { StandaloneDatabaseProvider(app) }
|
||||
|
||||
addSingletonFactory { MangaCache() }
|
||||
|
||||
ContextCompat.getMainExecutor(app).execute {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ani.dantotsu.connections.anilist
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.checkGenreTime
|
||||
import ani.dantotsu.checkId
|
||||
@@ -410,8 +411,9 @@ class AnilistQueries {
|
||||
sorted["Favourites"]?.sortWith(compareBy { it.userFavOrder })
|
||||
|
||||
sorted["All"] = all
|
||||
|
||||
val sort = sortOrder ?: options?.rowOrder
|
||||
val listsort = currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
|
||||
?.getString("sort_order", "score")
|
||||
val sort = listsort ?: sortOrder ?: options?.rowOrder
|
||||
for (i in sorted.keys) {
|
||||
when (sort) {
|
||||
"score" -> sorted[i]?.sortWith { b, a ->
|
||||
|
||||
@@ -15,43 +15,43 @@ class DownloadsManager(private val context: Context) {
|
||||
private val gson = Gson()
|
||||
private val downloadsList = loadDownloads().toMutableList()
|
||||
|
||||
val mangaDownloads: List<Download>
|
||||
get() = downloadsList.filter { it.type == Download.Type.MANGA }
|
||||
val animeDownloads: List<Download>
|
||||
get() = downloadsList.filter { it.type == Download.Type.ANIME }
|
||||
val novelDownloads: List<Download>
|
||||
get() = downloadsList.filter { it.type == Download.Type.NOVEL }
|
||||
val mangaDownloadedTypes: List<DownloadedType>
|
||||
get() = downloadsList.filter { it.type == DownloadedType.Type.MANGA }
|
||||
val animeDownloadedTypes: List<DownloadedType>
|
||||
get() = downloadsList.filter { it.type == DownloadedType.Type.ANIME }
|
||||
val novelDownloadedTypes: List<DownloadedType>
|
||||
get() = downloadsList.filter { it.type == DownloadedType.Type.NOVEL }
|
||||
|
||||
private fun saveDownloads() {
|
||||
val jsonString = gson.toJson(downloadsList)
|
||||
prefs.edit().putString("downloads_key", jsonString).apply()
|
||||
}
|
||||
|
||||
private fun loadDownloads(): List<Download> {
|
||||
private fun loadDownloads(): List<DownloadedType> {
|
||||
val jsonString = prefs.getString("downloads_key", null)
|
||||
return if (jsonString != null) {
|
||||
val type = object : TypeToken<List<Download>>() {}.type
|
||||
val type = object : TypeToken<List<DownloadedType>>() {}.type
|
||||
gson.fromJson(jsonString, type)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
fun addDownload(download: Download) {
|
||||
downloadsList.add(download)
|
||||
fun addDownload(downloadedType: DownloadedType) {
|
||||
downloadsList.add(downloadedType)
|
||||
saveDownloads()
|
||||
}
|
||||
|
||||
fun removeDownload(download: Download) {
|
||||
downloadsList.remove(download)
|
||||
removeDirectory(download)
|
||||
fun removeDownload(downloadedType: DownloadedType) {
|
||||
downloadsList.remove(downloadedType)
|
||||
removeDirectory(downloadedType)
|
||||
saveDownloads()
|
||||
}
|
||||
|
||||
fun removeMedia(title: String, type: Download.Type) {
|
||||
val subDirectory = if (type == Download.Type.MANGA) {
|
||||
fun removeMedia(title: String, type: DownloadedType.Type) {
|
||||
val subDirectory = if (type == DownloadedType.Type.MANGA) {
|
||||
"Manga"
|
||||
} else if (type == Download.Type.ANIME) {
|
||||
} else if (type == DownloadedType.Type.ANIME) {
|
||||
"Anime"
|
||||
} else {
|
||||
"Novel"
|
||||
@@ -76,16 +76,16 @@ class DownloadsManager(private val context: Context) {
|
||||
}
|
||||
|
||||
private fun cleanDownloads() {
|
||||
cleanDownload(Download.Type.MANGA)
|
||||
cleanDownload(Download.Type.ANIME)
|
||||
cleanDownload(Download.Type.NOVEL)
|
||||
cleanDownload(DownloadedType.Type.MANGA)
|
||||
cleanDownload(DownloadedType.Type.ANIME)
|
||||
cleanDownload(DownloadedType.Type.NOVEL)
|
||||
}
|
||||
|
||||
private fun cleanDownload(type: Download.Type) {
|
||||
private fun cleanDownload(type: DownloadedType.Type) {
|
||||
// remove all folders that are not in the downloads list
|
||||
val subDirectory = if (type == Download.Type.MANGA) {
|
||||
val subDirectory = if (type == DownloadedType.Type.MANGA) {
|
||||
"Manga"
|
||||
} else if (type == Download.Type.ANIME) {
|
||||
} else if (type == DownloadedType.Type.ANIME) {
|
||||
"Anime"
|
||||
} else {
|
||||
"Novel"
|
||||
@@ -94,18 +94,18 @@ class DownloadsManager(private val context: Context) {
|
||||
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
||||
"Dantotsu/$subDirectory"
|
||||
)
|
||||
val downloadsSubList = if (type == Download.Type.MANGA) {
|
||||
mangaDownloads
|
||||
} else if (type == Download.Type.ANIME) {
|
||||
animeDownloads
|
||||
val downloadsSubLists = if (type == DownloadedType.Type.MANGA) {
|
||||
mangaDownloadedTypes
|
||||
} else if (type == DownloadedType.Type.ANIME) {
|
||||
animeDownloadedTypes
|
||||
} else {
|
||||
novelDownloads
|
||||
novelDownloadedTypes
|
||||
}
|
||||
if (directory.exists()) {
|
||||
val files = directory.listFiles()
|
||||
if (files != null) {
|
||||
for (file in files) {
|
||||
if (!downloadsSubList.any { it.title == file.name }) {
|
||||
if (!downloadsSubLists.any { it.title == file.name }) {
|
||||
val deleted = file.deleteRecursively()
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,7 @@ class DownloadsManager(private val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
fun saveDownloadsListToJSONFileInDownloadsFolder(downloadsList: List<Download>) //for debugging
|
||||
fun saveDownloadsListToJSONFileInDownloadsFolder(downloadsList: List<DownloadedType>) //for debugging
|
||||
{
|
||||
val jsonString = gson.toJson(downloadsList)
|
||||
val file = File(
|
||||
@@ -138,25 +138,33 @@ class DownloadsManager(private val context: Context) {
|
||||
file.writeText(jsonString)
|
||||
}
|
||||
|
||||
fun queryDownload(download: Download): Boolean {
|
||||
return downloadsList.contains(download)
|
||||
fun queryDownload(downloadedType: DownloadedType): Boolean {
|
||||
return downloadsList.contains(downloadedType)
|
||||
}
|
||||
|
||||
private fun removeDirectory(download: Download) {
|
||||
val directory = if (download.type == Download.Type.MANGA) {
|
||||
fun queryDownload(title: String, chapter: String, type: DownloadedType.Type? = null): Boolean {
|
||||
return if (type == null) {
|
||||
downloadsList.any { it.title == title && it.chapter == chapter }
|
||||
} else {
|
||||
downloadsList.any { it.title == title && it.chapter == chapter && it.type == type }
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeDirectory(downloadedType: DownloadedType) {
|
||||
val directory = if (downloadedType.type == DownloadedType.Type.MANGA) {
|
||||
File(
|
||||
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
||||
"Dantotsu/Manga/${download.title}/${download.chapter}"
|
||||
"Dantotsu/Manga/${downloadedType.title}/${downloadedType.chapter}"
|
||||
)
|
||||
} else if (download.type == Download.Type.ANIME) {
|
||||
} else if (downloadedType.type == DownloadedType.Type.ANIME) {
|
||||
File(
|
||||
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
||||
"Dantotsu/Anime/${download.title}/${download.chapter}"
|
||||
"Dantotsu/Anime/${downloadedType.title}/${downloadedType.chapter}"
|
||||
)
|
||||
} else {
|
||||
File(
|
||||
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
||||
"Dantotsu/Novel/${download.title}/${download.chapter}"
|
||||
"Dantotsu/Novel/${downloadedType.title}/${downloadedType.chapter}"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -173,26 +181,26 @@ class DownloadsManager(private val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
fun exportDownloads(download: Download) { //copies to the downloads folder available to the user
|
||||
val directory = if (download.type == Download.Type.MANGA) {
|
||||
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/${download.title}/${download.chapter}"
|
||||
"Dantotsu/Manga/${downloadedType.title}/${downloadedType.chapter}"
|
||||
)
|
||||
} else if (download.type == Download.Type.ANIME) {
|
||||
} else if (downloadedType.type == DownloadedType.Type.ANIME) {
|
||||
File(
|
||||
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
||||
"Dantotsu/Anime/${download.title}/${download.chapter}"
|
||||
"Dantotsu/Anime/${downloadedType.title}/${downloadedType.chapter}"
|
||||
)
|
||||
} else {
|
||||
File(
|
||||
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
||||
"Dantotsu/Novel/${download.title}/${download.chapter}"
|
||||
"Dantotsu/Novel/${downloadedType.title}/${downloadedType.chapter}"
|
||||
)
|
||||
}
|
||||
val destination = File(
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
|
||||
"Dantotsu/${download.title}/${download.chapter}"
|
||||
"Dantotsu/${downloadedType.title}/${downloadedType.chapter}"
|
||||
)
|
||||
if (directory.exists()) {
|
||||
val copied = directory.copyRecursively(destination, true)
|
||||
@@ -206,10 +214,10 @@ class DownloadsManager(private val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
fun purgeDownloads(type: Download.Type) {
|
||||
val directory = if (type == Download.Type.MANGA) {
|
||||
fun purgeDownloads(type: DownloadedType.Type) {
|
||||
val directory = if (type == DownloadedType.Type.MANGA) {
|
||||
File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "Dantotsu/Manga")
|
||||
} else if (type == Download.Type.ANIME) {
|
||||
} else if (type == DownloadedType.Type.ANIME) {
|
||||
File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "Dantotsu/Anime")
|
||||
} else {
|
||||
File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "Dantotsu/Novel")
|
||||
@@ -237,7 +245,7 @@ class DownloadsManager(private val context: Context) {
|
||||
|
||||
}
|
||||
|
||||
data class Download(val title: String, val chapter: String, val type: Type) : Serializable {
|
||||
data class DownloadedType(val title: String, val chapter: String, val type: Type) : Serializable {
|
||||
enum class Type {
|
||||
MANGA,
|
||||
ANIME,
|
||||
|
||||
@@ -0,0 +1,455 @@
|
||||
package ani.dantotsu.download.anime
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Service
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ServiceInfo
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.os.IBinder
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.exoplayer.offline.Download
|
||||
import androidx.media3.exoplayer.offline.DownloadManager
|
||||
import androidx.media3.exoplayer.offline.DownloadService
|
||||
import ani.dantotsu.FileUrl
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.currActivity
|
||||
import ani.dantotsu.download.DownloadedType
|
||||
import ani.dantotsu.download.DownloadsManager
|
||||
import ani.dantotsu.download.video.Helper
|
||||
import ani.dantotsu.download.video.ExoplayerDownloadService
|
||||
import ani.dantotsu.logger
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.media.anime.AnimeWatchFragment
|
||||
import ani.dantotsu.parsers.Subtitle
|
||||
import ani.dantotsu.parsers.Video
|
||||
import ani.dantotsu.snackString
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.InstanceCreator
|
||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||
import eu.kanade.tachiyomi.animesource.model.SAnimeImpl
|
||||
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
||||
import eu.kanade.tachiyomi.animesource.model.SEpisodeImpl
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SChapterImpl
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.util.Queue
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
|
||||
class AnimeDownloaderService : Service() {
|
||||
|
||||
private lateinit var notificationManager: NotificationManagerCompat
|
||||
private lateinit var builder: NotificationCompat.Builder
|
||||
private val downloadsManager: DownloadsManager = Injekt.get<DownloadsManager>()
|
||||
|
||||
private val downloadJobs = mutableMapOf<String, Job>()
|
||||
private val mutex = Mutex()
|
||||
private var isCurrentlyProcessing = false
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
// This is only required for bound services.
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
notificationManager = NotificationManagerCompat.from(this)
|
||||
builder = NotificationCompat.Builder(this, Notifications.CHANNEL_DOWNLOADER_PROGRESS).apply {
|
||||
setContentTitle("Anime Download Progress")
|
||||
setSmallIcon(R.drawable.ic_round_download_24)
|
||||
priority = NotificationCompat.PRIORITY_DEFAULT
|
||||
setOnlyAlertOnce(true)
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
startForeground(
|
||||
NOTIFICATION_ID,
|
||||
builder.build(),
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
|
||||
)
|
||||
} else {
|
||||
startForeground(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
ContextCompat.registerReceiver(
|
||||
this,
|
||||
cancelReceiver,
|
||||
IntentFilter(ACTION_CANCEL_DOWNLOAD),
|
||||
ContextCompat.RECEIVER_EXPORTED
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
AnimeServiceDataSingleton.downloadQueue.clear()
|
||||
downloadJobs.clear()
|
||||
AnimeServiceDataSingleton.isServiceRunning = false
|
||||
unregisterReceiver(cancelReceiver)
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
snackString("Download started")
|
||||
val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
||||
serviceScope.launch {
|
||||
mutex.withLock {
|
||||
if (!isCurrentlyProcessing) {
|
||||
isCurrentlyProcessing = true
|
||||
processQueue()
|
||||
isCurrentlyProcessing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
private fun processQueue() {
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
while (AnimeServiceDataSingleton.downloadQueue.isNotEmpty()) {
|
||||
val task = AnimeServiceDataSingleton.downloadQueue.poll()
|
||||
if (task != null) {
|
||||
val job = launch { download(task) }
|
||||
mutex.withLock {
|
||||
downloadJobs[task.getTaskName()] = job
|
||||
}
|
||||
job.join() // Wait for the job to complete before continuing to the next task
|
||||
mutex.withLock {
|
||||
downloadJobs.remove(task.getTaskName())
|
||||
}
|
||||
updateNotification() // Update the notification after each task is completed
|
||||
}
|
||||
if (AnimeServiceDataSingleton.downloadQueue.isEmpty()) {
|
||||
withContext(Dispatchers.Main) {
|
||||
stopSelf() // Stop the service when the queue is empty
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@UnstableApi
|
||||
fun cancelDownload(taskName: String) {
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
mutex.withLock {
|
||||
val url = AnimeServiceDataSingleton.downloadQueue.find { it.getTaskName() == taskName }?.video?.file?.url ?: ""
|
||||
DownloadService.sendRemoveDownload(
|
||||
this@AnimeDownloaderService,
|
||||
ExoplayerDownloadService::class.java,
|
||||
url,
|
||||
false
|
||||
)
|
||||
downloadJobs[taskName]?.cancel()
|
||||
downloadJobs.remove(taskName)
|
||||
AnimeServiceDataSingleton.downloadQueue.removeAll { it.getTaskName() == taskName }
|
||||
updateNotification() // Update the notification after cancellation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateNotification() {
|
||||
// Update the notification to reflect the current state of the queue
|
||||
val pendingDownloads = AnimeServiceDataSingleton.downloadQueue.size
|
||||
val text = if (pendingDownloads > 0) {
|
||||
"Pending downloads: $pendingDownloads"
|
||||
} else {
|
||||
"All downloads completed"
|
||||
}
|
||||
builder.setContentText(text)
|
||||
if (ActivityCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.POST_NOTIFICATIONS
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
return
|
||||
}
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
|
||||
@androidx.annotation.OptIn(UnstableApi::class) suspend fun download(task: DownloadTask) {
|
||||
try {
|
||||
val downloadManager = Helper.downloadManager(this@AnimeDownloaderService)
|
||||
withContext(Dispatchers.Main) {
|
||||
val notifi = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
ContextCompat.checkSelfPermission(
|
||||
this@AnimeDownloaderService,
|
||||
Manifest.permission.POST_NOTIFICATIONS
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
true
|
||||
}
|
||||
|
||||
builder.setContentText("Downloading ${task.title} - ${task.episode}")
|
||||
if (notifi) {
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
|
||||
broadcastDownloadStarted(task.getTaskName())
|
||||
|
||||
currActivity()?.let {
|
||||
Helper.downloadVideo(
|
||||
it,
|
||||
task.video,
|
||||
task.subtitle)
|
||||
}
|
||||
|
||||
saveMediaInfo(task)
|
||||
val downloadStarted = hasDownloadStarted(downloadManager, task, 30000) // 30 seconds timeout
|
||||
|
||||
if (!downloadStarted) {
|
||||
logger("Download failed to start")
|
||||
builder.setContentText("${task.title} - ${task.episode} Download failed to start")
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
snackString("${task.title} - ${task.episode} Download failed to start")
|
||||
broadcastDownloadFailed(task.getTaskName())
|
||||
return@withContext
|
||||
}
|
||||
|
||||
|
||||
// periodically check if the download is complete
|
||||
while (downloadManager.downloadIndex.getDownload(task.video.file.url) != null) {
|
||||
val download = downloadManager.downloadIndex.getDownload(task.video.file.url)
|
||||
if (download != null) {
|
||||
if (download.state == androidx.media3.exoplayer.offline.Download.STATE_FAILED) {
|
||||
logger("Download failed")
|
||||
builder.setContentText("${task.title} - ${task.episode} Download failed")
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
snackString("${task.title} - ${task.episode} Download failed")
|
||||
logger("Download failed: ${download.failureReason}")
|
||||
FirebaseCrashlytics.getInstance().recordException(Exception("Anime Download failed:" +
|
||||
" ${download.failureReason}" +
|
||||
" url: ${task.video.file.url}" +
|
||||
" title: ${task.title}" +
|
||||
" episode: ${task.episode}"))
|
||||
broadcastDownloadFailed(task.getTaskName())
|
||||
break
|
||||
}
|
||||
if (download.state == androidx.media3.exoplayer.offline.Download.STATE_COMPLETED) {
|
||||
logger("Download completed")
|
||||
builder.setContentText("${task.title} - ${task.episode} Download completed")
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
snackString("${task.title} - ${task.episode} Download completed")
|
||||
getSharedPreferences(getString(R.string.anime_downloads), Context.MODE_PRIVATE).edit().putString(
|
||||
task.getTaskName(),
|
||||
task.video.file.url
|
||||
).apply()
|
||||
downloadsManager.addDownload(
|
||||
DownloadedType(
|
||||
task.title,
|
||||
task.episode,
|
||||
DownloadedType.Type.ANIME,
|
||||
)
|
||||
)
|
||||
broadcastDownloadFinished(task.getTaskName())
|
||||
break
|
||||
}
|
||||
if (download.state == androidx.media3.exoplayer.offline.Download.STATE_STOPPED) {
|
||||
logger("Download stopped")
|
||||
builder.setContentText("${task.title} - ${task.episode} Download stopped")
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
snackString("${task.title} - ${task.episode} Download stopped")
|
||||
break
|
||||
}
|
||||
broadcastDownloadProgress(task.getTaskName(), download.percentDownloaded.toInt())
|
||||
if (notifi) {
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
}
|
||||
kotlinx.coroutines.delay(2000)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger("Exception while downloading file: ${e.message}")
|
||||
snackString("Exception while downloading file: ${e.message}")
|
||||
FirebaseCrashlytics.getInstance().recordException(e)
|
||||
broadcastDownloadFailed(task.getTaskName())
|
||||
}
|
||||
}
|
||||
|
||||
@androidx.annotation.OptIn(UnstableApi::class) suspend fun hasDownloadStarted(downloadManager: DownloadManager, task: DownloadTask, timeout: Long): Boolean {
|
||||
val startTime = System.currentTimeMillis()
|
||||
while (System.currentTimeMillis() - startTime < timeout) {
|
||||
val download = downloadManager.downloadIndex.getDownload(task.video.file.url)
|
||||
if (download != null) {
|
||||
return true
|
||||
}
|
||||
// Delay between each poll
|
||||
kotlinx.coroutines.delay(500)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
private fun saveMediaInfo(task: DownloadTask) {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
val directory = File(
|
||||
getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
||||
"${DownloadsManager.animeLocation}/${task.title}"
|
||||
)
|
||||
val episodeDirectory = File(directory, task.episode)
|
||||
if (!directory.exists()) directory.mkdirs()
|
||||
if (!episodeDirectory.exists()) episodeDirectory.mkdirs()
|
||||
|
||||
val file = File(directory, "media.json")
|
||||
val gson = GsonBuilder()
|
||||
.registerTypeAdapter(SChapter::class.java, InstanceCreator<SChapter> {
|
||||
SChapterImpl() // Provide an instance of SChapterImpl
|
||||
})
|
||||
.registerTypeAdapter(SAnime::class.java, InstanceCreator<SAnime> {
|
||||
SAnimeImpl() // Provide an instance of SAnimeImpl
|
||||
})
|
||||
.registerTypeAdapter(SEpisode::class.java, InstanceCreator<SEpisode> {
|
||||
SEpisodeImpl() // Provide an instance of SEpisodeImpl
|
||||
})
|
||||
.create()
|
||||
val mediaJson = gson.toJson(task.sourceMedia)
|
||||
val media = gson.fromJson(mediaJson, Media::class.java)
|
||||
if (media != null) {
|
||||
media.cover = media.cover?.let { downloadImage(it, directory, "cover.jpg") }
|
||||
media.banner = media.banner?.let { downloadImage(it, directory, "banner.jpg") }
|
||||
if (task.episodeImage != null) {
|
||||
media.anime?.episodes?.get(task.episode)?.let { episode ->
|
||||
episode.thumb = downloadImage(task.episodeImage, episodeDirectory, "episodeImage.jpg")?.let {
|
||||
FileUrl(
|
||||
it
|
||||
)
|
||||
}
|
||||
}
|
||||
downloadImage(task.episodeImage, episodeDirectory, "episodeImage.jpg")
|
||||
}
|
||||
|
||||
val jsonString = gson.toJson(media)
|
||||
withContext(Dispatchers.Main) {
|
||||
file.writeText(jsonString)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private suspend fun downloadImage(url: String, directory: File, name: String): String? =
|
||||
withContext(Dispatchers.IO) {
|
||||
var connection: HttpURLConnection? = null
|
||||
println("Downloading url $url")
|
||||
try {
|
||||
connection = URL(url).openConnection() as HttpURLConnection
|
||||
connection.connect()
|
||||
if (connection.responseCode != HttpURLConnection.HTTP_OK) {
|
||||
throw Exception("Server returned HTTP ${connection.responseCode} ${connection.responseMessage}")
|
||||
}
|
||||
|
||||
val file = File(directory, name)
|
||||
FileOutputStream(file).use { output ->
|
||||
connection.inputStream.use { input ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
}
|
||||
return@withContext file.absolutePath
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(
|
||||
this@AnimeDownloaderService,
|
||||
"Exception while saving ${name}: ${e.message}",
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
null
|
||||
} finally {
|
||||
connection?.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
private fun broadcastDownloadStarted(chapterNumber: String) {
|
||||
val intent = Intent(AnimeWatchFragment.ACTION_DOWNLOAD_STARTED).apply {
|
||||
putExtra(AnimeWatchFragment.EXTRA_EPISODE_NUMBER, chapterNumber)
|
||||
}
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
|
||||
private fun broadcastDownloadFinished(chapterNumber: String) {
|
||||
val intent = Intent(AnimeWatchFragment.ACTION_DOWNLOAD_FINISHED).apply {
|
||||
putExtra(AnimeWatchFragment.EXTRA_EPISODE_NUMBER, chapterNumber)
|
||||
}
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
|
||||
private fun broadcastDownloadFailed(chapterNumber: String) {
|
||||
val intent = Intent(AnimeWatchFragment.ACTION_DOWNLOAD_FAILED).apply {
|
||||
putExtra(AnimeWatchFragment.EXTRA_EPISODE_NUMBER, chapterNumber)
|
||||
}
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
|
||||
private fun broadcastDownloadProgress(chapterNumber: String, progress: Int) {
|
||||
val intent = Intent(AnimeWatchFragment.ACTION_DOWNLOAD_PROGRESS).apply {
|
||||
putExtra(AnimeWatchFragment.EXTRA_EPISODE_NUMBER, chapterNumber)
|
||||
putExtra("progress", progress)
|
||||
}
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
|
||||
private val cancelReceiver = object : BroadcastReceiver() {
|
||||
@androidx.annotation.OptIn(UnstableApi::class) override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action == ACTION_CANCEL_DOWNLOAD) {
|
||||
val taskName = intent.getStringExtra(EXTRA_TASK_NAME)
|
||||
taskName?.let {
|
||||
cancelDownload(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class DownloadTask(
|
||||
val title: String,
|
||||
val episode: String,
|
||||
val video: Video,
|
||||
val subtitle: Subtitle? = null,
|
||||
val sourceMedia: Media? = null,
|
||||
val episodeImage: String? = null,
|
||||
val retries: Int = 2,
|
||||
val simultaneousDownloads: Int = 2,
|
||||
) {
|
||||
fun getTaskName(): String {
|
||||
return "$title - $episode"
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val NOTIFICATION_ID = 1103
|
||||
const val ACTION_CANCEL_DOWNLOAD = "action_cancel_download"
|
||||
const val EXTRA_TASK_NAME = "extra_task_name"
|
||||
}
|
||||
}
|
||||
|
||||
object AnimeServiceDataSingleton {
|
||||
var video: Video? = null
|
||||
var sourceMedia: Media? = null
|
||||
var downloadQueue: Queue<AnimeDownloaderService.DownloadTask> = ConcurrentLinkedQueue()
|
||||
|
||||
@Volatile
|
||||
var isServiceRunning: Boolean = false
|
||||
}
|
||||
@@ -18,7 +18,7 @@ import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.download.Download
|
||||
import ani.dantotsu.download.DownloadedType
|
||||
import ani.dantotsu.download.DownloadsManager
|
||||
import ani.dantotsu.logger
|
||||
import ani.dantotsu.media.Media
|
||||
@@ -246,10 +246,10 @@ class MangaDownloaderService : Service() {
|
||||
|
||||
saveMediaInfo(task)
|
||||
downloadsManager.addDownload(
|
||||
Download(
|
||||
DownloadedType(
|
||||
task.title,
|
||||
task.chapter,
|
||||
Download.Type.MANGA
|
||||
DownloadedType.Type.MANGA
|
||||
)
|
||||
)
|
||||
broadcastDownloadFinished(task.chapter)
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package ani.dantotsu.download.manga
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.BaseAdapter
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.cardview.widget.CardView
|
||||
import ani.dantotsu.R
|
||||
@@ -19,6 +21,7 @@ class OfflineMangaAdapter(
|
||||
private val inflater: LayoutInflater =
|
||||
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
private var originalItems: List<OfflineMangaModel> = items
|
||||
private var style = context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getInt("offline_view", 0)
|
||||
|
||||
override fun getCount(): Int {
|
||||
return items.size
|
||||
@@ -32,10 +35,13 @@ class OfflineMangaAdapter(
|
||||
return position.toLong()
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
|
||||
var view = convertView
|
||||
if (view == null) {
|
||||
view = inflater.inflate(R.layout.item_media_compact, parent, false)
|
||||
|
||||
val view: View = convertView ?: when(style) {
|
||||
0 -> inflater.inflate(R.layout.item_media_large, parent, false) // large view
|
||||
1 -> inflater.inflate(R.layout.item_media_compact, parent, false) // compact view
|
||||
else -> inflater.inflate(R.layout.item_media_compact, parent, false) // compact view
|
||||
}
|
||||
|
||||
val item = getItem(position) as OfflineMangaModel
|
||||
@@ -44,11 +50,31 @@ class OfflineMangaAdapter(
|
||||
val itemScore = view.findViewById<TextView>(R.id.itemCompactScore)
|
||||
val itemScoreBG = view.findViewById<View>(R.id.itemCompactScoreBG)
|
||||
val ongoing = view.findViewById<CardView>(R.id.itemCompactOngoing)
|
||||
val totalchapter = view.findViewById<TextView>(R.id.itemCompactTotal)
|
||||
val type = view.findViewById<TextView>(R.id.itemCompactRelation)
|
||||
val typeView = view.findViewById<LinearLayout>(R.id.itemCompactType)
|
||||
|
||||
if (style == 0){
|
||||
val bannerView = view.findViewById<ImageView>(R.id.itemCompactBanner) // for large view
|
||||
val chapters = view.findViewById<TextView>(R.id.itemTotal)
|
||||
chapters.text = " Chapters"
|
||||
bannerView.setImageURI(item.banner)
|
||||
totalchapter.text = item.totalchapter
|
||||
}
|
||||
|
||||
else if (style == 1){
|
||||
val readchapter = view.findViewById<TextView>(R.id.itemCompactUserProgress) // for compact view
|
||||
readchapter.text = item.readchapter
|
||||
totalchapter.text = " | " + item.totalchapter
|
||||
}
|
||||
|
||||
// Bind item data to the views
|
||||
// For example:
|
||||
type.text = item.type
|
||||
typeView.visibility = View.VISIBLE
|
||||
imageView.setImageURI(item.image)
|
||||
titleTextView.text = item.title
|
||||
itemScore.text = item.score
|
||||
|
||||
if (item.isOngoing) {
|
||||
ongoing.visibility = View.VISIBLE
|
||||
} else {
|
||||
@@ -74,4 +100,9 @@ class OfflineMangaAdapter(
|
||||
this.originalItems = items
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun notifyNewGrid(){
|
||||
style = context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getInt("offline_view", 0)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
@@ -13,16 +13,22 @@ import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AlphaAnimation
|
||||
import android.view.animation.LayoutAnimationController
|
||||
import android.view.animation.OvershootInterpolator
|
||||
import android.widget.AbsListView
|
||||
import android.widget.AutoCompleteTextView
|
||||
import android.widget.GridView
|
||||
import android.widget.ImageView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.cardview.widget.CardView
|
||||
import androidx.fragment.app.Fragment
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.currActivity
|
||||
import ani.dantotsu.currContext
|
||||
import ani.dantotsu.download.Download
|
||||
import ani.dantotsu.download.DownloadedType
|
||||
import ani.dantotsu.download.DownloadsManager
|
||||
import ani.dantotsu.initActivity
|
||||
import ani.dantotsu.logger
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.media.MediaDetailsActivity
|
||||
@@ -45,6 +51,7 @@ import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
||||
|
||||
private val downloadManager = Injekt.get<DownloadsManager>()
|
||||
private var downloads: List<OfflineMangaModel> = listOf()
|
||||
private lateinit var gridView: GridView
|
||||
@@ -91,24 +98,75 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int, ) {
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
onSearchQuery(s.toString())
|
||||
}
|
||||
})
|
||||
var style = context?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
|
||||
?.getInt("offline_view", 0)
|
||||
val layoutList = view.findViewById<ImageView>(R.id.downloadedList)
|
||||
val layoutcompact = view.findViewById<ImageView>(R.id.downloadedGrid)
|
||||
var selected = when (style) {
|
||||
0 -> layoutList
|
||||
1 -> layoutcompact
|
||||
else -> layoutList
|
||||
}
|
||||
selected.alpha = 1f
|
||||
|
||||
gridView = view.findViewById(R.id.gridView)
|
||||
fun selected(it: ImageView) {
|
||||
selected.alpha = 0.33f
|
||||
selected = it
|
||||
selected.alpha = 1f
|
||||
}
|
||||
|
||||
layoutList.setOnClickListener {
|
||||
selected(it as ImageView)
|
||||
style = 0
|
||||
context?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)?.edit()
|
||||
?.putInt("offline_view", style!!)?.apply()
|
||||
gridView.visibility = View.GONE
|
||||
gridView = view.findViewById(R.id.gridView)
|
||||
gridView.adapter = adapter
|
||||
gridView.scheduleLayoutAnimation()
|
||||
gridView.visibility = View.VISIBLE
|
||||
adapter.notifyNewGrid()
|
||||
|
||||
}
|
||||
|
||||
layoutcompact.setOnClickListener {
|
||||
selected(it as ImageView)
|
||||
style = 1
|
||||
context?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)?.edit()
|
||||
?.putInt("offline_view", style!!)?.apply()
|
||||
gridView.visibility = View.GONE
|
||||
gridView = view.findViewById(R.id.gridView1)
|
||||
gridView.adapter = adapter
|
||||
gridView.scheduleLayoutAnimation()
|
||||
gridView.visibility = View.VISIBLE
|
||||
adapter.notifyNewGrid()
|
||||
}
|
||||
|
||||
gridView = if(style == 0) view.findViewById(R.id.gridView) else view.findViewById(R.id.gridView1)
|
||||
gridView.visibility = View.VISIBLE
|
||||
getDownloads()
|
||||
|
||||
val fadeIn = AlphaAnimation(0f, 1f)
|
||||
fadeIn.duration = 200 // animations pog
|
||||
val animation = LayoutAnimationController(fadeIn)
|
||||
|
||||
gridView.layoutAnimation = animation
|
||||
adapter = OfflineMangaAdapter(requireContext(), downloads, this)
|
||||
gridView.adapter = adapter
|
||||
gridView.scheduleLayoutAnimation()
|
||||
gridView.setOnItemClickListener { parent, view, position, id ->
|
||||
// Get the OfflineMangaModel that was clicked
|
||||
val item = adapter.getItem(position) as OfflineMangaModel
|
||||
val media =
|
||||
downloadManager.mangaDownloads.firstOrNull { it.title == item.title }
|
||||
?: downloadManager.novelDownloads.firstOrNull { it.title == item.title }
|
||||
downloadManager.mangaDownloadedTypes.firstOrNull { it.title == item.title }
|
||||
?: downloadManager.novelDownloadedTypes.firstOrNull { it.title == item.title }
|
||||
media?.let {
|
||||
startActivity(
|
||||
Intent(requireContext(), MediaDetailsActivity::class.java)
|
||||
@@ -123,10 +181,10 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
||||
gridView.setOnItemLongClickListener { parent, view, position, id ->
|
||||
// Get the OfflineMangaModel that was clicked
|
||||
val item = adapter.getItem(position) as OfflineMangaModel
|
||||
val type: Download.Type = if (downloadManager.mangaDownloads.any { it.title == item.title }) {
|
||||
Download.Type.MANGA
|
||||
val type: DownloadedType.Type = if (downloadManager.mangaDownloadedTypes.any { it.title == item.title }) {
|
||||
DownloadedType.Type.MANGA
|
||||
} else {
|
||||
Download.Type.NOVEL
|
||||
DownloadedType.Type.NOVEL
|
||||
}
|
||||
// Alert dialog to confirm deletion
|
||||
val builder = androidx.appcompat.app.AlertDialog.Builder(requireContext(), R.style.MyPopup)
|
||||
@@ -154,6 +212,7 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
initActivity(requireActivity())
|
||||
var height = statusBarHeight
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
val displayCutout = activity?.window?.decorView?.rootWindowInsets?.displayCutout
|
||||
@@ -187,9 +246,25 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
||||
}
|
||||
|
||||
scrollTop.setOnClickListener {
|
||||
//TODO: scroll to top
|
||||
gridView.smoothScrollToPosition(0)
|
||||
}
|
||||
|
||||
// Assuming 'scrollTop' is a view that you want to hide/show
|
||||
scrollTop.visibility = View.GONE
|
||||
|
||||
gridView.setOnScrollListener(object : AbsListView.OnScrollListener {
|
||||
override fun onScrollStateChanged(view: AbsListView, scrollState: Int) {
|
||||
// Implement behavior for different scroll states if needed
|
||||
}
|
||||
|
||||
override fun onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int, totalItemCount: Int) {
|
||||
val first = view.getChildAt(0)
|
||||
val visibility = first != null && first.top < -height
|
||||
scrollTop.visibility = if (visibility) View.VISIBLE else View.GONE
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
@@ -215,19 +290,19 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
||||
|
||||
private fun getDownloads() {
|
||||
downloads = listOf()
|
||||
val mangaTitles = downloadManager.mangaDownloads.map { it.title }.distinct()
|
||||
val mangaTitles = downloadManager.mangaDownloadedTypes.map { it.title }.distinct()
|
||||
val newMangaDownloads = mutableListOf<OfflineMangaModel>()
|
||||
for (title in mangaTitles) {
|
||||
val _downloads = downloadManager.mangaDownloads.filter { it.title == title }
|
||||
val _downloads = downloadManager.mangaDownloadedTypes.filter { it.title == title }
|
||||
val download = _downloads.first()
|
||||
val offlineMangaModel = loadOfflineMangaModel(download)
|
||||
newMangaDownloads += offlineMangaModel
|
||||
}
|
||||
downloads = newMangaDownloads
|
||||
val novelTitles = downloadManager.novelDownloads.map { it.title }.distinct()
|
||||
val novelTitles = downloadManager.novelDownloadedTypes.map { it.title }.distinct()
|
||||
val newNovelDownloads = mutableListOf<OfflineMangaModel>()
|
||||
for (title in novelTitles) {
|
||||
val _downloads = downloadManager.novelDownloads.filter { it.title == title }
|
||||
val _downloads = downloadManager.novelDownloadedTypes.filter { it.title == title }
|
||||
val download = _downloads.first()
|
||||
val offlineMangaModel = loadOfflineMangaModel(download)
|
||||
newNovelDownloads += offlineMangaModel
|
||||
@@ -236,17 +311,17 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
||||
|
||||
}
|
||||
|
||||
private fun getMedia(download: Download): Media? {
|
||||
val type = if (download.type == Download.Type.MANGA) {
|
||||
private fun getMedia(downloadedType: DownloadedType): Media? {
|
||||
val type = if (downloadedType.type == DownloadedType.Type.MANGA) {
|
||||
"Manga"
|
||||
} else if (download.type == Download.Type.ANIME) {
|
||||
} else if (downloadedType.type == DownloadedType.Type.ANIME) {
|
||||
"Anime"
|
||||
} else {
|
||||
"Novel"
|
||||
}
|
||||
val directory = File(
|
||||
currContext()?.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
||||
"Dantotsu/$type/${download.title}"
|
||||
"Dantotsu/$type/${downloadedType.title}"
|
||||
)
|
||||
//load media.json and convert to media class with gson
|
||||
return try {
|
||||
@@ -266,40 +341,45 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadOfflineMangaModel(download: Download): OfflineMangaModel {
|
||||
val type = if (download.type == Download.Type.MANGA) {
|
||||
private fun loadOfflineMangaModel(downloadedType: DownloadedType): OfflineMangaModel {
|
||||
val type = if (downloadedType.type == DownloadedType.Type.MANGA) {
|
||||
"Manga"
|
||||
} else if (download.type == Download.Type.ANIME) {
|
||||
} else if (downloadedType.type == DownloadedType.Type.ANIME) {
|
||||
"Anime"
|
||||
} else {
|
||||
"Novel"
|
||||
}
|
||||
val directory = File(
|
||||
currContext()?.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
||||
"Dantotsu/$type/${download.title}"
|
||||
"Dantotsu/$type/${downloadedType.title}"
|
||||
)
|
||||
//load media.json and convert to media class with gson
|
||||
try {
|
||||
val media = File(directory, "media.json")
|
||||
val mediaJson = media.readText()
|
||||
val mediaModel = getMedia(download)!!
|
||||
val mediaModel = getMedia(downloadedType)!!
|
||||
val cover = File(directory, "cover.jpg")
|
||||
val coverUri: Uri? = if (cover.exists()) {
|
||||
Uri.fromFile(cover)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else null
|
||||
val banner = File(directory, "banner.jpg")
|
||||
val bannerUri: Uri? = if (banner.exists()) {
|
||||
Uri.fromFile(banner)
|
||||
} else null
|
||||
val title = mediaModel.nameMAL ?: mediaModel.nameRomaji
|
||||
val score = ((if (mediaModel.userScore == 0) (mediaModel.meanScore
|
||||
?: 0) else mediaModel.userScore) / 10.0).toString()
|
||||
val isOngoing = false
|
||||
val isOngoing = mediaModel.status == currActivity()!!.getString(R.string.status_releasing)
|
||||
val isUserScored = mediaModel.userScore != 0
|
||||
return OfflineMangaModel(title, score, isOngoing, isUserScored, coverUri)
|
||||
val readchapter = (mediaModel.userProgress ?: "~").toString()
|
||||
val totalchapter = "${mediaModel.manga?.totalChapters ?: "??"}"
|
||||
val chapters = " Chapters"
|
||||
return OfflineMangaModel(title, score, totalchapter, readchapter, type, chapters, isOngoing, isUserScored, coverUri , bannerUri )
|
||||
} catch (e: Exception) {
|
||||
logger("Error loading media.json: ${e.message}")
|
||||
logger(e.printStackTrace())
|
||||
FirebaseCrashlytics.getInstance().recordException(e)
|
||||
return OfflineMangaModel("unknown", "0", false, false, null)
|
||||
return OfflineMangaModel("unknown", "0", "??", "??","movie" ,"hmm", false, false, null , null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,12 @@ import android.net.Uri
|
||||
data class OfflineMangaModel(
|
||||
val title: String,
|
||||
val score: String,
|
||||
val totalchapter: String,
|
||||
val readchapter : String,
|
||||
val type: String,
|
||||
val chapters: String,
|
||||
val isOngoing: Boolean,
|
||||
val isUserScored: Boolean,
|
||||
val image: Uri?
|
||||
val image: Uri?,
|
||||
val banner: Uri?
|
||||
)
|
||||
@@ -17,7 +17,7 @@ import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.download.Download
|
||||
import ani.dantotsu.download.DownloadedType
|
||||
import ani.dantotsu.download.DownloadsManager
|
||||
import ani.dantotsu.logger
|
||||
import ani.dantotsu.media.Media
|
||||
@@ -330,10 +330,10 @@ class NovelDownloaderService : Service() {
|
||||
|
||||
saveMediaInfo(task)
|
||||
downloadsManager.addDownload(
|
||||
Download(
|
||||
DownloadedType(
|
||||
task.title,
|
||||
task.chapter,
|
||||
Download.Type.NOVEL
|
||||
DownloadedType.Type.NOVEL
|
||||
)
|
||||
)
|
||||
broadcastDownloadFinished(task.originalLink)
|
||||
|
||||
@@ -11,7 +11,7 @@ import androidx.media3.exoplayer.scheduler.Scheduler
|
||||
import ani.dantotsu.R
|
||||
|
||||
@UnstableApi
|
||||
class MyDownloadService : DownloadService(1, 1, "download_service", R.string.downloads, 0) {
|
||||
class ExoplayerDownloadService : DownloadService(1, 2000, "download_service", R.string.downloads, 0) {
|
||||
companion object {
|
||||
private const val JOB_ID = 1
|
||||
private const val FOREGROUND_NOTIFICATION_ID = 1
|
||||
@@ -1,8 +1,19 @@
|
||||
package ani.dantotsu.download.video
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
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
|
||||
import androidx.core.content.ContextCompat.getString
|
||||
import androidx.media3.common.C
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.MimeTypes
|
||||
@@ -15,6 +26,7 @@ import androidx.media3.datasource.cache.NoOpCacheEvictor
|
||||
import androidx.media3.datasource.cache.SimpleCache
|
||||
import androidx.media3.datasource.okhttp.OkHttpDataSource
|
||||
import androidx.media3.exoplayer.DefaultRenderersFactory
|
||||
import androidx.media3.exoplayer.offline.Download
|
||||
import androidx.media3.exoplayer.offline.DownloadHelper
|
||||
import androidx.media3.exoplayer.offline.DownloadManager
|
||||
import androidx.media3.exoplayer.offline.DownloadService
|
||||
@@ -22,7 +34,12 @@ import androidx.media3.exoplayer.scheduler.Requirements
|
||||
import androidx.media3.ui.TrackSelectionDialogBuilder
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.defaultHeaders
|
||||
import ani.dantotsu.download.DownloadedType
|
||||
import ani.dantotsu.download.DownloadsManager
|
||||
import ani.dantotsu.download.anime.AnimeDownloaderService
|
||||
import ani.dantotsu.download.anime.AnimeServiceDataSingleton
|
||||
import ani.dantotsu.logError
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.okHttpClient
|
||||
import ani.dantotsu.parsers.Subtitle
|
||||
import ani.dantotsu.parsers.SubtitleType
|
||||
@@ -37,6 +54,8 @@ import java.util.concurrent.*
|
||||
|
||||
object Helper {
|
||||
|
||||
private var simpleCache: SimpleCache? = null
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
fun downloadVideo(context: Context, video: Video, subtitle: Subtitle?) {
|
||||
val dataSourceFactory = DataSource.Factory {
|
||||
@@ -82,18 +101,18 @@ object Helper {
|
||||
)
|
||||
downloadHelper.prepare(object : DownloadHelper.Callback {
|
||||
override fun onPrepared(helper: DownloadHelper) {
|
||||
TrackSelectionDialogBuilder(
|
||||
context, "Select thingy", helper.getTracks(0).groups
|
||||
/*TrackSelectionDialogBuilder( TODO: use this for subtitles
|
||||
context, "Select Source", helper.getTracks(0).groups
|
||||
) { _, overrides ->
|
||||
val params = TrackSelectionParameters.Builder(context)
|
||||
overrides.forEach {
|
||||
params.addOverride(it.value)
|
||||
}
|
||||
helper.addTrackSelection(0, params.build())
|
||||
MyDownloadService
|
||||
ExoplayerDownloadService
|
||||
DownloadService.sendAddDownload(
|
||||
context,
|
||||
MyDownloadService::class.java,
|
||||
ExoplayerDownloadService::class.java,
|
||||
helper.getDownloadRequest(null),
|
||||
false
|
||||
)
|
||||
@@ -103,6 +122,14 @@ object Helper {
|
||||
if (it.frameRate > 0f) it.height.toString() + "p" else it.height.toString() + "p (fps : N/A)"
|
||||
}
|
||||
build().show()
|
||||
}*/
|
||||
helper.getDownloadRequest(null).let {
|
||||
DownloadService.sendAddDownload(
|
||||
context,
|
||||
ExoplayerDownloadService::class.java,
|
||||
it,
|
||||
false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,13 +141,13 @@ object Helper {
|
||||
|
||||
|
||||
private var download: DownloadManager? = null
|
||||
private const val DOWNLOAD_CONTENT_DIRECTORY = "downloads"
|
||||
private const val DOWNLOAD_CONTENT_DIRECTORY = "Anime_Downloads"
|
||||
|
||||
@Synchronized
|
||||
@UnstableApi
|
||||
fun downloadManager(context: Context): DownloadManager {
|
||||
return download ?: let {
|
||||
val database = StandaloneDatabaseProvider(context)
|
||||
val database = Injekt.get<StandaloneDatabaseProvider>()
|
||||
val downloadDirectory = File(getDownloadDirectory(context), DOWNLOAD_CONTENT_DIRECTORY)
|
||||
val dataSourceFactory = DataSource.Factory {
|
||||
//val dataSource: HttpDataSource = OkHttpDataSource.Factory(okHttpClient).createDataSource()
|
||||
@@ -133,17 +160,42 @@ object Helper {
|
||||
}
|
||||
dataSource
|
||||
}
|
||||
DownloadManager(
|
||||
val threadPoolSize = Runtime.getRuntime().availableProcessors()
|
||||
val executorService = Executors.newFixedThreadPool(threadPoolSize)
|
||||
val downloadManager = DownloadManager(
|
||||
context,
|
||||
database,
|
||||
SimpleCache(downloadDirectory, NoOpCacheEvictor(), database),
|
||||
getSimpleCache(context),
|
||||
dataSourceFactory,
|
||||
Executor(Runnable::run)
|
||||
executorService
|
||||
).apply {
|
||||
requirements =
|
||||
Requirements(Requirements.NETWORK or Requirements.DEVICE_STORAGE_NOT_LOW)
|
||||
maxParallelDownloads = 3
|
||||
}
|
||||
downloadManager.addListener( //for testing
|
||||
object : DownloadManager.Listener {
|
||||
override fun onDownloadChanged(
|
||||
downloadManager: DownloadManager,
|
||||
download: Download,
|
||||
finalException: Exception?
|
||||
) {
|
||||
if (download.state == Download.STATE_COMPLETED) {
|
||||
Log.e("Downloader", "Download Completed")
|
||||
} else if (download.state == Download.STATE_FAILED) {
|
||||
Log.e("Downloader", "Download Failed")
|
||||
} else if (download.state == Download.STATE_STOPPED) {
|
||||
Log.e("Downloader", "Download Stopped")
|
||||
} else if (download.state == Download.STATE_QUEUED) {
|
||||
Log.e("Downloader", "Download Queued")
|
||||
} else if (download.state == Download.STATE_DOWNLOADING) {
|
||||
Log.e("Downloader", "Download Downloading")
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
downloadManager
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,4 +211,108 @@ object Helper {
|
||||
}
|
||||
return downloadDirectory!!
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
fun startAnimeDownloadService(
|
||||
context: Context,
|
||||
title: String,
|
||||
episode: String,
|
||||
video: Video,
|
||||
subtitle: Subtitle? = null,
|
||||
sourceMedia: Media? = null,
|
||||
episodeImage: String? = null
|
||||
) {
|
||||
if (!isNotificationPermissionGranted(context)) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
ActivityCompat.requestPermissions(
|
||||
context as Activity,
|
||||
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
|
||||
1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val downloadTask = AnimeDownloaderService.DownloadTask(
|
||||
title,
|
||||
episode,
|
||||
video,
|
||||
subtitle,
|
||||
sourceMedia,
|
||||
episodeImage
|
||||
)
|
||||
|
||||
val downloadsManger = Injekt.get<DownloadsManager>()
|
||||
val downloadCheck = downloadsManger
|
||||
.queryDownload(title, episode, DownloadedType.Type.ANIME)
|
||||
|
||||
if (downloadCheck) {
|
||||
AlertDialog.Builder(context , R.style.MyPopup)
|
||||
.setTitle("Download Exists")
|
||||
.setMessage("A download for this episode already exists. Do you want to overwrite it?")
|
||||
.setPositiveButton("Yes") { _, _ ->
|
||||
DownloadService.sendRemoveDownload(
|
||||
context,
|
||||
ExoplayerDownloadService::class.java,
|
||||
context.getSharedPreferences(
|
||||
getString(context, R.string.anime_downloads),
|
||||
Context.MODE_PRIVATE
|
||||
).getString(
|
||||
downloadTask.getTaskName(),
|
||||
""
|
||||
) ?: "",
|
||||
false
|
||||
)
|
||||
context.getSharedPreferences(
|
||||
getString(context, R.string.anime_downloads),
|
||||
Context.MODE_PRIVATE
|
||||
).edit()
|
||||
.remove(downloadTask.getTaskName())
|
||||
.apply()
|
||||
downloadsManger.removeDownload(
|
||||
DownloadedType(
|
||||
title,
|
||||
episode,
|
||||
DownloadedType.Type.ANIME
|
||||
)
|
||||
)
|
||||
AnimeServiceDataSingleton.downloadQueue.offer(downloadTask)
|
||||
if (!AnimeServiceDataSingleton.isServiceRunning) {
|
||||
val intent = Intent(context, AnimeDownloaderService::class.java)
|
||||
ContextCompat.startForegroundService(context, intent)
|
||||
AnimeServiceDataSingleton.isServiceRunning = true
|
||||
}
|
||||
}
|
||||
.setNegativeButton("No") { _, _ -> }
|
||||
.show()
|
||||
} else {
|
||||
AnimeServiceDataSingleton.downloadQueue.offer(downloadTask)
|
||||
if (!AnimeServiceDataSingleton.isServiceRunning) {
|
||||
val intent = Intent(context, AnimeDownloaderService::class.java)
|
||||
ContextCompat.startForegroundService(context, intent)
|
||||
AnimeServiceDataSingleton.isServiceRunning = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
fun getSimpleCache(context: Context): SimpleCache {
|
||||
return if (simpleCache == null) {
|
||||
val downloadDirectory = File(getDownloadDirectory(context), DOWNLOAD_CONTENT_DIRECTORY)
|
||||
val database = Injekt.get<StandaloneDatabaseProvider>()
|
||||
simpleCache = SimpleCache(downloadDirectory, NoOpCacheEvictor(), database)
|
||||
simpleCache!!
|
||||
} else {
|
||||
simpleCache!!
|
||||
}
|
||||
}
|
||||
|
||||
private fun isNotificationPermissionGranted(context: Context): Boolean {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
return ActivityCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.POST_NOTIFICATIONS
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package ani.dantotsu.home
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@@ -26,6 +27,7 @@ import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.connections.anilist.AnilistAnimeViewModel
|
||||
import ani.dantotsu.connections.anilist.SearchResults
|
||||
import ani.dantotsu.connections.anilist.getUserId
|
||||
import ani.dantotsu.currContext
|
||||
import ani.dantotsu.databinding.FragmentAnimeBinding
|
||||
import ani.dantotsu.loadData
|
||||
import ani.dantotsu.media.MediaAdaptor
|
||||
@@ -47,16 +49,17 @@ import kotlin.math.min
|
||||
class AnimeFragment : Fragment() {
|
||||
private var _binding: FragmentAnimeBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
private lateinit var animePageAdapter: AnimePageAdapter
|
||||
|
||||
private var uiSettings: UserInterfaceSettings =
|
||||
loadData("ui_settings") ?: UserInterfaceSettings()
|
||||
loadData("ui_settings") ?: UserInterfaceSettings()
|
||||
|
||||
val model: AnilistAnimeViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentAnimeBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
@@ -78,11 +81,11 @@ class AnimeFragment : Fragment() {
|
||||
if (displayCutout != null) {
|
||||
if (displayCutout.boundingRects.size > 0) {
|
||||
height = max(
|
||||
statusBarHeight,
|
||||
min(
|
||||
displayCutout.boundingRects[0].width(),
|
||||
displayCutout.boundingRects[0].height()
|
||||
)
|
||||
statusBarHeight,
|
||||
min(
|
||||
displayCutout.boundingRects[0].width(),
|
||||
displayCutout.boundingRects[0].height()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -95,18 +98,18 @@ class AnimeFragment : Fragment() {
|
||||
|
||||
binding.animePageRecyclerView.updatePaddingRelative(bottom = navBarHeight + 160f.px)
|
||||
|
||||
val animePageAdapter = AnimePageAdapter()
|
||||
animePageAdapter = AnimePageAdapter()
|
||||
|
||||
var loading = true
|
||||
if (model.notSet) {
|
||||
model.notSet = false
|
||||
model.searchResults = SearchResults(
|
||||
"ANIME",
|
||||
isAdult = false,
|
||||
onList = false,
|
||||
results = mutableListOf(),
|
||||
hasNextPage = true,
|
||||
sort = Anilist.sortBy[1]
|
||||
"ANIME",
|
||||
isAdult = false,
|
||||
onList = false,
|
||||
results = mutableListOf(),
|
||||
hasNextPage = true,
|
||||
sort = Anilist.sortBy[1]
|
||||
)
|
||||
}
|
||||
val popularAdaptor = MediaAdaptor(1, model.searchResults.results, requireActivity())
|
||||
@@ -174,7 +177,7 @@ class AnimeFragment : Fragment() {
|
||||
}
|
||||
|
||||
binding.animePageRecyclerView.addOnScrollListener(object :
|
||||
RecyclerView.OnScrollListener() {
|
||||
RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(v: RecyclerView, dx: Int, dy: Int) {
|
||||
if (!v.canScrollVertically(1)) {
|
||||
if (model.searchResults.hasNextPage && model.searchResults.results.isNotEmpty() && !loading) {
|
||||
@@ -214,19 +217,19 @@ class AnimeFragment : Fragment() {
|
||||
model.getTrending().observe(viewLifecycleOwner) {
|
||||
if (it != null) {
|
||||
animePageAdapter.updateTrending(
|
||||
MediaAdaptor(
|
||||
if (uiSettings.smallView) 3 else 2,
|
||||
it,
|
||||
requireActivity(),
|
||||
viewPager = animePageAdapter.trendingViewPager
|
||||
)
|
||||
MediaAdaptor(
|
||||
if (uiSettings.smallView) 3 else 2,
|
||||
it,
|
||||
requireActivity(),
|
||||
viewPager = animePageAdapter.trendingViewPager
|
||||
)
|
||||
)
|
||||
animePageAdapter.updateAvatar()
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.animePageScrollTop.translationY =
|
||||
-(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat()
|
||||
-(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,13 +247,13 @@ class AnimeFragment : Fragment() {
|
||||
animePageAdapter.onSeasonLongClick = { i ->
|
||||
val (season, year) = Anilist.currentSeasons[i]
|
||||
ContextCompat.startActivity(
|
||||
requireContext(),
|
||||
Intent(requireContext(), SearchActivity::class.java)
|
||||
.putExtra("type", "ANIME")
|
||||
.putExtra("season", season)
|
||||
.putExtra("seasonYear", year.toString())
|
||||
.putExtra("search", true),
|
||||
null
|
||||
requireContext(),
|
||||
Intent(requireContext(), SearchActivity::class.java)
|
||||
.putExtra("type", "ANIME")
|
||||
.putExtra("season", season)
|
||||
.putExtra("seasonYear", year.toString())
|
||||
.putExtra("search", true),
|
||||
null
|
||||
)
|
||||
true
|
||||
}
|
||||
@@ -277,6 +280,12 @@ class AnimeFragment : Fragment() {
|
||||
|
||||
override fun onResume() {
|
||||
if (!model.loaded) Refresh.activity[this.hashCode()]!!.postValue(true)
|
||||
if (animePageAdapter.trendingViewPager != null) {
|
||||
animePageAdapter.setIncognito()
|
||||
binding.root.requestApplyInsets()
|
||||
binding.root.requestLayout()
|
||||
}
|
||||
|
||||
super.onResume()
|
||||
}
|
||||
}
|
||||
@@ -75,12 +75,6 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
|
||||
textInputLayout.boxBackgroundColor = (color and 0x00FFFFFF) or 0x28000000.toInt()
|
||||
materialCardView.setCardBackgroundColor((color and 0x00FFFFFF) or 0x28000000.toInt())
|
||||
}
|
||||
val incognito = currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
|
||||
?.getBoolean("incognito", false) ?: false
|
||||
if(incognito) {
|
||||
binding.incognitoTextView.visibility = View.VISIBLE
|
||||
binding.incognitoView.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
binding.animeTitleContainer.updatePadding(top = statusBarHeight)
|
||||
|
||||
@@ -155,6 +149,19 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
|
||||
trendingViewPager!!.updateLayoutParams { height += statusBarHeight }
|
||||
}
|
||||
|
||||
fun setIncognito() {
|
||||
val incognito = currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
|
||||
?.getBoolean("incognito", false) ?: false
|
||||
if(incognito) {
|
||||
binding.incognitoTextView.visibility = View.VISIBLE
|
||||
if (!uiSettings.immersiveMode) {
|
||||
binding.root.fitsSystemWindows = true
|
||||
}
|
||||
} else {
|
||||
binding.incognitoTextView.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
fun updateTrending(adaptor: MediaAdaptor) {
|
||||
binding.animeTrendingProgressBar.visibility = View.GONE
|
||||
binding.animeTrendingViewPager.adapter = adaptor
|
||||
|
||||
@@ -10,6 +10,7 @@ import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.view.animation.LayoutAnimationController
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
@@ -115,12 +116,6 @@ class HomeFragment : Fragment() {
|
||||
snackString(currContext()?.getString(R.string.please_reload))
|
||||
}
|
||||
}
|
||||
val incognito = currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
|
||||
?.getBoolean("incognito", false) ?: false
|
||||
if(incognito) {
|
||||
binding.incognitoTextView.visibility = View.VISIBLE
|
||||
binding.incognitoView.visibility = View.VISIBLE
|
||||
}
|
||||
binding.homeUserAvatarContainer.setSafeOnClickListener {
|
||||
val dialogFragment =
|
||||
SettingsDialogFragment.newInstance(SettingsDialogFragment.Companion.PageType.HOME)
|
||||
@@ -369,6 +364,23 @@ class HomeFragment : Fragment() {
|
||||
|
||||
override fun onResume() {
|
||||
if (!model.loaded) Refresh.activity[1]!!.postValue(true)
|
||||
val incognito = currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
|
||||
?.getBoolean("incognito", false) ?: false
|
||||
if(incognito) {
|
||||
val uiSettings = loadData<UserInterfaceSettings>("ui_settings") ?: UserInterfaceSettings()
|
||||
binding.incognitoTextView.visibility = View.VISIBLE
|
||||
if (!uiSettings.immersiveMode) {
|
||||
binding.root.fitsSystemWindows = true
|
||||
//holy deprecation
|
||||
binding.root.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
binding.root.requestApplyInsets()
|
||||
binding.root.requestLayout()
|
||||
}
|
||||
} else {
|
||||
binding.incognitoTextView.visibility = View.GONE
|
||||
}
|
||||
super.onResume()
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package ani.dantotsu.home
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
@@ -24,6 +25,7 @@ import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.connections.anilist.AnilistMangaViewModel
|
||||
import ani.dantotsu.connections.anilist.SearchResults
|
||||
import ani.dantotsu.connections.anilist.getUserId
|
||||
import ani.dantotsu.currContext
|
||||
import ani.dantotsu.databinding.FragmentMangaBinding
|
||||
import ani.dantotsu.loadData
|
||||
import ani.dantotsu.media.MediaAdaptor
|
||||
@@ -43,16 +45,17 @@ import kotlin.math.min
|
||||
class MangaFragment : Fragment() {
|
||||
private var _binding: FragmentMangaBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
private lateinit var mangaPageAdapter: MangaPageAdapter
|
||||
|
||||
private var uiSettings: UserInterfaceSettings =
|
||||
loadData("ui_settings") ?: UserInterfaceSettings()
|
||||
loadData("ui_settings") ?: UserInterfaceSettings()
|
||||
|
||||
val model: AnilistMangaViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentMangaBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
@@ -73,11 +76,11 @@ class MangaFragment : Fragment() {
|
||||
if (displayCutout != null) {
|
||||
if (displayCutout.boundingRects.size > 0) {
|
||||
height = max(
|
||||
statusBarHeight,
|
||||
min(
|
||||
displayCutout.boundingRects[0].width(),
|
||||
displayCutout.boundingRects[0].height()
|
||||
)
|
||||
statusBarHeight,
|
||||
min(
|
||||
displayCutout.boundingRects[0].width(),
|
||||
displayCutout.boundingRects[0].height()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -90,23 +93,23 @@ class MangaFragment : Fragment() {
|
||||
|
||||
binding.mangaPageRecyclerView.updatePaddingRelative(bottom = navBarHeight + 160f.px)
|
||||
|
||||
val mangaPageAdapter = MangaPageAdapter()
|
||||
mangaPageAdapter = MangaPageAdapter()
|
||||
var loading = true
|
||||
if (model.notSet) {
|
||||
model.notSet = false
|
||||
model.searchResults = SearchResults(
|
||||
"MANGA",
|
||||
isAdult = false,
|
||||
onList = false,
|
||||
results = arrayListOf(),
|
||||
hasNextPage = true,
|
||||
sort = Anilist.sortBy[1]
|
||||
"MANGA",
|
||||
isAdult = false,
|
||||
onList = false,
|
||||
results = arrayListOf(),
|
||||
hasNextPage = true,
|
||||
sort = Anilist.sortBy[1]
|
||||
)
|
||||
}
|
||||
val popularAdaptor = MediaAdaptor(1, model.searchResults.results, requireActivity())
|
||||
val progressAdaptor = ProgressAdapter(searched = model.searched)
|
||||
binding.mangaPageRecyclerView.adapter =
|
||||
ConcatAdapter(mangaPageAdapter, popularAdaptor, progressAdaptor)
|
||||
ConcatAdapter(mangaPageAdapter, popularAdaptor, progressAdaptor)
|
||||
val layout = LinearLayoutManager(requireContext())
|
||||
binding.mangaPageRecyclerView.layoutManager = layout
|
||||
|
||||
@@ -132,7 +135,7 @@ class MangaFragment : Fragment() {
|
||||
}
|
||||
|
||||
binding.mangaPageRecyclerView.addOnScrollListener(object :
|
||||
RecyclerView.OnScrollListener() {
|
||||
RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(v: RecyclerView, dx: Int, dy: Int) {
|
||||
if (!v.canScrollVertically(1)) {
|
||||
if (model.searchResults.hasNextPage && model.searchResults.results.isNotEmpty() && !loading) {
|
||||
@@ -172,19 +175,19 @@ class MangaFragment : Fragment() {
|
||||
model.getTrending().observe(viewLifecycleOwner) {
|
||||
if (it != null) {
|
||||
mangaPageAdapter.updateTrending(
|
||||
MediaAdaptor(
|
||||
if (uiSettings.smallView) 3 else 2,
|
||||
it,
|
||||
requireActivity(),
|
||||
viewPager = mangaPageAdapter.trendingViewPager
|
||||
)
|
||||
MediaAdaptor(
|
||||
if (uiSettings.smallView) 3 else 2,
|
||||
it,
|
||||
requireActivity(),
|
||||
viewPager = mangaPageAdapter.trendingViewPager
|
||||
)
|
||||
)
|
||||
mangaPageAdapter.updateAvatar()
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.mangaPageScrollTop.translationY =
|
||||
-(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat()
|
||||
-(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat()
|
||||
|
||||
}
|
||||
}
|
||||
@@ -251,6 +254,12 @@ class MangaFragment : Fragment() {
|
||||
|
||||
override fun onResume() {
|
||||
if (!model.loaded) Refresh.activity[this.hashCode()]!!.postValue(true)
|
||||
//make sure mangaPageAdapter is initialized
|
||||
if (mangaPageAdapter.trendingViewPager != null) {
|
||||
mangaPageAdapter.setIncognito()
|
||||
binding.root.requestApplyInsets()
|
||||
binding.root.requestLayout()
|
||||
}
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
|
||||
@@ -75,13 +75,6 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
|
||||
materialCardView.setCardBackgroundColor((color and 0x00FFFFFF) or 0x28000000.toInt())
|
||||
}
|
||||
|
||||
val incognito = currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
|
||||
?.getBoolean("incognito", false) ?: false
|
||||
if(incognito) {
|
||||
binding.incognitoTextView.visibility = View.VISIBLE
|
||||
binding.incognitoView.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
binding.mangaTitleContainer.updatePadding(top = statusBarHeight)
|
||||
|
||||
if (uiSettings.smallView) binding.mangaTrendingContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
@@ -148,6 +141,19 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
|
||||
trendingViewPager!!.updateLayoutParams { height += statusBarHeight }
|
||||
}
|
||||
|
||||
fun setIncognito() {
|
||||
val incognito = currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
|
||||
?.getBoolean("incognito", false) ?: false
|
||||
if(incognito) {
|
||||
binding.incognitoTextView.visibility = View.VISIBLE
|
||||
if (!uiSettings.immersiveMode) {
|
||||
binding.root.fitsSystemWindows = true
|
||||
}
|
||||
} else {
|
||||
binding.incognitoTextView.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
fun updateTrending(adaptor: MediaAdaptor) {
|
||||
binding.mangaTrendingProgressBar.visibility = View.GONE
|
||||
binding.mangaTrendingViewPager.adapter = adaptor
|
||||
|
||||
@@ -136,7 +136,7 @@ class MediaAdaptor(
|
||||
val media = mediaList?.get(position)
|
||||
if (media != null) {
|
||||
b.itemCompactImage.loadImage(media.cover)
|
||||
b.itemCompactBanner.loadImage(media.banner ?: media.cover, 400)
|
||||
b.itemCompactBanner.loadImage(media.banner ?: media.cover)
|
||||
b.itemCompactOngoing.visibility =
|
||||
if (media.status == currActivity()!!.getString(R.string.status_releasing)) View.VISIBLE else View.GONE
|
||||
b.itemCompactTitle.text = media.userPreferredName
|
||||
|
||||
@@ -78,7 +78,7 @@ class SearchActivity : AppCompatActivity() {
|
||||
mediaAdaptor = MediaAdaptor(style, model.searchResults.results, this, matchParent = true)
|
||||
val headerAdaptor = SearchAdapter(this)
|
||||
|
||||
val gridSize = (screenWidth / 124f).toInt()
|
||||
val gridSize = (screenWidth / 120f).toInt()
|
||||
val gridLayoutManager = GridLayoutManager(this, gridSize)
|
||||
gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
|
||||
override fun getSpanSize(position: Int): Int {
|
||||
|
||||
@@ -16,5 +16,17 @@ class AnimeNameAdapter {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun findEpisodeNumber(text: String): Float? {
|
||||
val episodeRegex = "(episode|ep|e)[\\s:.\\-]*([\\d]+\\.?[\\d]*)"
|
||||
val episodePattern: Pattern = Pattern.compile(episodeRegex, Pattern.CASE_INSENSITIVE)
|
||||
val episodeMatcher: Matcher = episodePattern.matcher(text)
|
||||
|
||||
return if (episodeMatcher.find()) {
|
||||
episodeMatcher.group(2)?.toFloat()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,28 @@
|
||||
package ani.dantotsu.media.anime
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.ImageButton
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.*
|
||||
import ani.dantotsu.databinding.ItemAnimeWatchBinding
|
||||
import ani.dantotsu.databinding.ItemChipBinding
|
||||
import ani.dantotsu.databinding.DialogLayoutBinding
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.media.MediaDetailsActivity
|
||||
import ani.dantotsu.media.SourceSearchDialogFragment
|
||||
import ani.dantotsu.others.LanguageMapper
|
||||
import ani.dantotsu.parsers.AnimeSources
|
||||
import ani.dantotsu.parsers.DynamicAnimeParser
|
||||
import ani.dantotsu.parsers.WatchSources
|
||||
@@ -27,6 +32,7 @@ import com.google.android.material.chip.Chip
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
class AnimeWatchAdapter(
|
||||
private val media: Media,
|
||||
private val fragment: AnimeWatchFragment,
|
||||
@@ -40,6 +46,8 @@ class AnimeWatchAdapter(
|
||||
val bind = ItemAnimeWatchBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return ViewHolder(bind)
|
||||
}
|
||||
private var nestedDialog: AlertDialog? = null
|
||||
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
@@ -147,8 +155,9 @@ class AnimeWatchAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
//Icons
|
||||
|
||||
//Subscription
|
||||
//subscribe
|
||||
subscribe = MediaDetailsActivity.PopImageButton(
|
||||
fragment.lifecycleScope,
|
||||
binding.animeSourceSubscribe,
|
||||
@@ -167,44 +176,76 @@ class AnimeWatchAdapter(
|
||||
openSettings(fragment.requireContext(), getChannelId(true, media.id))
|
||||
}
|
||||
|
||||
//Icons
|
||||
var reversed = media.selected!!.recyclerReversed
|
||||
var style = media.selected!!.recyclerStyle ?: fragment.uiSettings.animeDefaultView
|
||||
binding.animeSourceTop.rotation = if (reversed) -90f else 90f
|
||||
binding.animeSourceTop.setOnClickListener {
|
||||
reversed = !reversed
|
||||
binding.animeSourceTop.rotation = if (reversed) -90f else 90f
|
||||
fragment.onIconPressed(style, reversed)
|
||||
}
|
||||
var selected = when (style) {
|
||||
0 -> binding.animeSourceList
|
||||
1 -> binding.animeSourceGrid
|
||||
2 -> binding.animeSourceCompact
|
||||
else -> binding.animeSourceList
|
||||
}
|
||||
selected.alpha = 1f
|
||||
fun selected(it: ImageView) {
|
||||
selected.alpha = 0.33f
|
||||
selected = it
|
||||
//Nested Button
|
||||
binding.animeNestedButton.setOnClickListener {
|
||||
val dialogView =
|
||||
LayoutInflater.from(fragment.requireContext()).inflate(R.layout.dialog_layout, null)
|
||||
val dialogBinding = DialogLayoutBinding.bind(dialogView)
|
||||
|
||||
var run = false
|
||||
var reversed = media.selected!!.recyclerReversed
|
||||
var style = media.selected!!.recyclerStyle ?: fragment.uiSettings.animeDefaultView
|
||||
dialogBinding.animeSourceTop.rotation = if (reversed) -90f else 90f
|
||||
dialogBinding.sortText.text = if (reversed) "Down to Up" else "Up to Down"
|
||||
dialogBinding.animeSourceTop.setOnClickListener {
|
||||
reversed = !reversed
|
||||
dialogBinding.animeSourceTop.rotation = if (reversed) -90f else 90f
|
||||
dialogBinding.sortText.text = if (reversed) "Down to Up" else "Up to Down"
|
||||
run = true
|
||||
}
|
||||
//Grids
|
||||
var selected = when (style) {
|
||||
0 -> dialogBinding.animeSourceList
|
||||
1 -> dialogBinding.animeSourceGrid
|
||||
2 -> dialogBinding.animeSourceCompact
|
||||
else -> dialogBinding.animeSourceList
|
||||
}
|
||||
when (style) {
|
||||
0 -> dialogBinding.layoutText.text = "List"
|
||||
1 -> dialogBinding.layoutText.text = "Grid"
|
||||
2 -> dialogBinding.layoutText.text = "Compact"
|
||||
else -> dialogBinding.animeSourceList
|
||||
}
|
||||
selected.alpha = 1f
|
||||
fun selected(it: ImageButton) {
|
||||
selected.alpha = 0.33f
|
||||
selected = it
|
||||
selected.alpha = 1f
|
||||
}
|
||||
dialogBinding.animeSourceList.setOnClickListener {
|
||||
selected(it as ImageButton)
|
||||
style = 0
|
||||
dialogBinding.layoutText.text = "List"
|
||||
run = true
|
||||
}
|
||||
dialogBinding.animeSourceGrid.setOnClickListener {
|
||||
selected(it as ImageButton)
|
||||
style = 1
|
||||
dialogBinding.layoutText.text = "Grid"
|
||||
run = true
|
||||
}
|
||||
dialogBinding.animeSourceCompact.setOnClickListener {
|
||||
selected(it as ImageButton)
|
||||
style = 2
|
||||
dialogBinding.layoutText.text = "Compact"
|
||||
run = true
|
||||
}
|
||||
|
||||
//hidden
|
||||
dialogBinding.animeScanlatorContainer.visibility = View.GONE
|
||||
dialogBinding.animeDownloadContainer.visibility = View.GONE
|
||||
|
||||
nestedDialog = AlertDialog.Builder(fragment.requireContext() , R.style.MyPopup)
|
||||
.setTitle("Options")
|
||||
.setView(dialogView)
|
||||
.setPositiveButton("OK") { _, _ ->
|
||||
if (run) fragment.onIconPressed(style, reversed)
|
||||
}
|
||||
.setNegativeButton("Cancel") { _, _ ->
|
||||
}
|
||||
.create()
|
||||
nestedDialog?.show()
|
||||
}
|
||||
binding.animeSourceList.setOnClickListener {
|
||||
selected(it as ImageView)
|
||||
style = 0
|
||||
fragment.onIconPressed(style, reversed)
|
||||
}
|
||||
binding.animeSourceGrid.setOnClickListener {
|
||||
selected(it as ImageView)
|
||||
style = 1
|
||||
fragment.onIconPressed(style, reversed)
|
||||
}
|
||||
binding.animeSourceCompact.setOnClickListener {
|
||||
selected(it as ImageView)
|
||||
style = 2
|
||||
fragment.onIconPressed(style, reversed)
|
||||
}
|
||||
binding.animeScanlatorTop.visibility = View.GONE
|
||||
binding.animeDownloadTop.visibility = View.GONE
|
||||
//Episode Handling
|
||||
handleEpisodes()
|
||||
}
|
||||
@@ -351,12 +392,15 @@ class AnimeWatchAdapter(
|
||||
parser.extension.sources.firstOrNull()?.lang ?: "Unknown"
|
||||
)
|
||||
}
|
||||
binding?.animeSourceLanguage?.setAdapter(
|
||||
ArrayAdapter(
|
||||
fragment.requireContext(),
|
||||
R.layout.item_dropdown,
|
||||
parser.extension.sources.map { it.lang })
|
||||
val adapter = ArrayAdapter(
|
||||
fragment.requireContext(),
|
||||
R.layout.item_dropdown,
|
||||
parser.extension.sources.sortedBy { it.lang }.map { LanguageMapper.mapLanguageCodeToName(it.lang) }
|
||||
)
|
||||
val items = adapter.count
|
||||
if (items > 1) binding?.animeSourceLanguageContainer?.visibility = View.VISIBLE else binding?.animeSourceLanguageContainer?.visibility = View.GONE
|
||||
|
||||
binding?.animeSourceLanguage?.setAdapter(adapter)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import ani.dantotsu.databinding.FragmentAnimeWatchBinding
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.media.MediaDetailsActivity
|
||||
import ani.dantotsu.media.MediaDetailsViewModel
|
||||
import ani.dantotsu.others.LanguageMapper
|
||||
import ani.dantotsu.parsers.AnimeParser
|
||||
import ani.dantotsu.parsers.AnimeSources
|
||||
import ani.dantotsu.parsers.HAnimeSources
|
||||
@@ -314,19 +315,19 @@ class AnimeWatchFragment : Fragment() {
|
||||
if (show) View.GONE else View.VISIBLE
|
||||
}
|
||||
}
|
||||
var itemSelected = false
|
||||
val allSettings = pkg.sources.filterIsInstance<ConfigurableAnimeSource>()
|
||||
if (allSettings.isNotEmpty()) {
|
||||
var selectedSetting = allSettings[0]
|
||||
if (allSettings.size > 1) {
|
||||
val names = allSettings.map { it.lang }.toTypedArray()
|
||||
val names = allSettings.sortedBy { it.lang }.map { LanguageMapper.mapLanguageCodeToName(it.lang) }.toTypedArray()
|
||||
var selectedIndex = 0
|
||||
val dialog = AlertDialog.Builder(requireContext())
|
||||
val dialog = AlertDialog.Builder(requireContext() , R.style.MyPopup)
|
||||
.setTitle("Select a Source")
|
||||
.setSingleChoiceItems(names, selectedIndex) { _, which ->
|
||||
.setSingleChoiceItems(names, selectedIndex) { dialog, which ->
|
||||
selectedIndex = which
|
||||
}
|
||||
.setPositiveButton("OK") { dialog, _ ->
|
||||
selectedSetting = allSettings[selectedIndex]
|
||||
itemSelected = true
|
||||
dialog.dismiss()
|
||||
|
||||
// Move the fragment transaction here
|
||||
@@ -343,10 +344,10 @@ class AnimeWatchFragment : Fragment() {
|
||||
.commit()
|
||||
}
|
||||
}
|
||||
.setNegativeButton("Cancel") { dialog, _ ->
|
||||
dialog.cancel()
|
||||
changeUIVisibility(true)
|
||||
return@setNegativeButton
|
||||
.setOnDismissListener {
|
||||
if (!itemSelected) {
|
||||
changeUIVisibility(true)
|
||||
}
|
||||
}
|
||||
.show()
|
||||
dialog.window?.setDimAmount(0.8f)
|
||||
@@ -424,4 +425,12 @@ class AnimeWatchFragment : Fragment() {
|
||||
state = binding.animeSourceRecycler.layoutManager?.onSaveInstanceState()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ACTION_DOWNLOAD_STARTED = "ani.dantotsu.ACTION_DOWNLOAD_STARTED"
|
||||
const val ACTION_DOWNLOAD_FINISHED = "ani.dantotsu.ACTION_DOWNLOAD_FINISHED"
|
||||
const val ACTION_DOWNLOAD_FAILED = "ani.dantotsu.ACTION_DOWNLOAD_FAILED"
|
||||
const val ACTION_DOWNLOAD_PROGRESS = "ani.dantotsu.ACTION_DOWNLOAD_PROGRESS"
|
||||
const val EXTRA_EPISODE_NUMBER = "extra_episode_number"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package ani.dantotsu.media.anime
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import androidx.mediarouter.app.MediaRouteActionProvider
|
||||
import androidx.mediarouter.app.MediaRouteChooserDialog
|
||||
import androidx.mediarouter.app.MediaRouteChooserDialogFragment
|
||||
import androidx.mediarouter.app.MediaRouteControllerDialog
|
||||
import androidx.mediarouter.app.MediaRouteControllerDialogFragment
|
||||
import androidx.mediarouter.app.MediaRouteDialogFactory
|
||||
import ani.dantotsu.R
|
||||
|
||||
class CustomCastProvider(context: Context) : MediaRouteActionProvider(context) {
|
||||
init {
|
||||
dialogFactory = CustomCastThemeFactory()
|
||||
}
|
||||
}
|
||||
|
||||
class CustomCastThemeFactory : MediaRouteDialogFactory() {
|
||||
override fun onCreateChooserDialogFragment(): MediaRouteChooserDialogFragment {
|
||||
return CustomMediaRouterChooserDialogFragment()
|
||||
}
|
||||
|
||||
override fun onCreateControllerDialogFragment(): MediaRouteControllerDialogFragment {
|
||||
return CustomMediaRouteControllerDialogFragment()
|
||||
}
|
||||
}
|
||||
|
||||
class CustomMediaRouterChooserDialogFragment: MediaRouteChooserDialogFragment() {
|
||||
override fun onCreateChooserDialog(
|
||||
context: Context,
|
||||
savedInstanceState: Bundle?
|
||||
): MediaRouteChooserDialog =
|
||||
MediaRouteChooserDialog(context, R.style.MyPopup)
|
||||
}
|
||||
|
||||
class CustomMediaRouteControllerDialogFragment: MediaRouteControllerDialogFragment() {
|
||||
override fun onCreateControllerDialog(
|
||||
context: Context,
|
||||
savedInstanceState: Bundle?
|
||||
): MediaRouteControllerDialog =
|
||||
MediaRouteControllerDialog(context, R.style.MyPopup)
|
||||
}
|
||||
@@ -14,7 +14,7 @@ data class Episode(
|
||||
var selectedExtractor: String? = null,
|
||||
var selectedVideo: Int = 0,
|
||||
var selectedSubtitle: Int? = -1,
|
||||
var extractors: MutableList<VideoExtractor>? = null,
|
||||
@Transient var extractors: MutableList<VideoExtractor>? = null,
|
||||
@Transient var extractorCallback: ((VideoExtractor) -> Unit)? = null,
|
||||
var allStreams: Boolean = false,
|
||||
var watched: Long? = null,
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.AlertDialog
|
||||
import android.app.Dialog
|
||||
import android.app.DownloadManager
|
||||
import android.app.PictureInPictureParams
|
||||
import android.app.PictureInPictureUiState
|
||||
import android.content.ActivityNotFoundException
|
||||
@@ -14,7 +15,6 @@ import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.hardware.Sensor
|
||||
import android.hardware.SensorManager
|
||||
import android.media.AudioManager
|
||||
import android.media.AudioManager.*
|
||||
@@ -96,11 +96,17 @@ import java.util.concurrent.*
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
import androidx.media3.cast.SessionAvailabilityListener
|
||||
import androidx.media3.cast.CastPlayer
|
||||
import androidx.media3.exoplayer.offline.Download
|
||||
import androidx.mediarouter.app.MediaRouteButton
|
||||
import ani.dantotsu.download.video.Helper
|
||||
import com.google.android.gms.cast.framework.CastButtonFactory
|
||||
import com.google.android.gms.cast.framework.CastContext
|
||||
|
||||
@UnstableApi
|
||||
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
|
||||
class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityListener {
|
||||
|
||||
private val resumeWindow = "resumeWindow"
|
||||
private val resumePosition = "resumePosition"
|
||||
@@ -108,6 +114,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
private val playerOnPlay = "playerOnPlay"
|
||||
|
||||
private lateinit var exoPlayer: ExoPlayer
|
||||
private lateinit var castPlayer: CastPlayer
|
||||
private lateinit var castContext: CastContext
|
||||
private lateinit var trackSelector: DefaultTrackSelector
|
||||
private lateinit var cacheFactory: CacheDataSource.Factory
|
||||
private lateinit var playbackParameters: PlaybackParameters
|
||||
@@ -145,6 +153,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
|
||||
private var orientationListener: OrientationEventListener? = null
|
||||
|
||||
private var downloadId: String? = null
|
||||
|
||||
companion object {
|
||||
var initialized = false
|
||||
lateinit var media: Media
|
||||
@@ -328,6 +338,11 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
setContentView(binding.root)
|
||||
|
||||
//Initialize
|
||||
|
||||
castContext = CastContext.getSharedInstance(this)
|
||||
castPlayer = CastPlayer(castContext)
|
||||
castPlayer.setSessionAvailabilityListener(this)
|
||||
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
hideSystemBars()
|
||||
|
||||
@@ -387,7 +402,6 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
orientationListener =
|
||||
object : OrientationEventListener(this, SensorManager.SENSOR_DELAY_UI) {
|
||||
override fun onOrientationChanged(orientation: Int) {
|
||||
println(orientation)
|
||||
if (orientation in 45..135) {
|
||||
if (rotation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE) exoRotate.visibility =
|
||||
View.VISIBLE
|
||||
@@ -466,12 +480,18 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
if (isInitialized) {
|
||||
isPlayerPlaying = exoPlayer.isPlaying
|
||||
(exoPlay.drawable as Animatable?)?.start()
|
||||
if (isPlayerPlaying) {
|
||||
if (isPlayerPlaying || castPlayer.isPlaying) {
|
||||
Glide.with(this).load(R.drawable.anim_play_to_pause).into(exoPlay)
|
||||
exoPlayer.pause()
|
||||
castPlayer.pause()
|
||||
} else {
|
||||
Glide.with(this).load(R.drawable.anim_pause_to_play).into(exoPlay)
|
||||
exoPlayer.play()
|
||||
if (!castPlayer.isPlaying && castPlayer.currentMediaItem != null) {
|
||||
Glide.with(this).load(R.drawable.anim_pause_to_play).into(exoPlay)
|
||||
castPlayer.play()
|
||||
} else if (!isPlayerPlaying) {
|
||||
Glide.with(this).load(R.drawable.anim_pause_to_play).into(exoPlay)
|
||||
exoPlayer.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1074,11 +1094,10 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
|
||||
//Cast
|
||||
if (settings.cast) {
|
||||
playerView.findViewById<ImageButton>(R.id.exo_cast).apply {
|
||||
playerView.findViewById<MediaRouteButton>(R.id.exo_cast).apply {
|
||||
visibility = View.VISIBLE
|
||||
setSafeOnClickListener {
|
||||
cast()
|
||||
}
|
||||
CastButtonFactory.setUpMediaRouteButton(context, this)
|
||||
dialogFactory = CustomCastThemeFactory()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1101,7 +1120,21 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
if (settings.cursedSpeeds)
|
||||
arrayOf(1f, 1.25f, 1.5f, 1.75f, 2f, 2.5f, 3f, 4f, 5f, 10f, 25f, 50f)
|
||||
else
|
||||
arrayOf(0.25f, 0.33f, 0.5f, 0.66f, 0.75f, 1f, 1.15f, 1.25f, 1.33f, 1.5f, 1.66f, 1.75f, 2f)
|
||||
arrayOf(
|
||||
0.25f,
|
||||
0.33f,
|
||||
0.5f,
|
||||
0.66f,
|
||||
0.75f,
|
||||
1f,
|
||||
1.15f,
|
||||
1.25f,
|
||||
1.33f,
|
||||
1.5f,
|
||||
1.66f,
|
||||
1.75f,
|
||||
2f
|
||||
)
|
||||
|
||||
val speedsName = speeds.map { "${it}x" }.toTypedArray()
|
||||
var curSpeed = loadData("${media.id}_speed", this) ?: settings.defaultSpeed
|
||||
@@ -1278,7 +1311,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
if (video?.format == VideoType.CONTAINER || (loadData<Int>("settings_download_manager")
|
||||
?: 0) != 0
|
||||
) {
|
||||
but.visibility = View.VISIBLE
|
||||
//but.visibility = View.VISIBLE TODO: not sure if this is needed
|
||||
but.setOnClickListener {
|
||||
download(this, episode, animeTitle.text.toString())
|
||||
}
|
||||
@@ -1303,8 +1336,9 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
dataSource
|
||||
}
|
||||
cacheFactory = CacheDataSource.Factory().apply {
|
||||
setCache(simpleCache)
|
||||
setCache(Helper.getSimpleCache(this@ExoplayerView))
|
||||
setUpstreamDataSourceFactory(dataSourceFactory)
|
||||
setCacheWriteDataSinkFactory(null)
|
||||
}
|
||||
|
||||
val mimeType = when (video?.format) {
|
||||
@@ -1313,15 +1347,33 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
else -> MimeTypes.APPLICATION_MP4
|
||||
}
|
||||
|
||||
val builder = MediaItem.Builder().setUri(video!!.file.url).setMimeType(mimeType)
|
||||
logger("url: ${video!!.file.url}")
|
||||
logger("mimeType: $mimeType")
|
||||
val downloadedMediaItem = if (ext.server.offline) {
|
||||
val key = ext.server.name
|
||||
downloadId = getSharedPreferences(getString(R.string.anime_downloads), MODE_PRIVATE)
|
||||
.getString(key, null)
|
||||
if (downloadId != null) {
|
||||
Helper.downloadManager(this)
|
||||
.downloadIndex.getDownload(downloadId!!)?.request?.toMediaItem()
|
||||
} else {
|
||||
snackString("Download not found")
|
||||
null
|
||||
}
|
||||
} else null
|
||||
|
||||
if (sub != null) {
|
||||
val listofnotnullsubs = immutableListOf(sub).filterNotNull()
|
||||
builder.setSubtitleConfigurations(listofnotnullsubs)
|
||||
mediaItem = if (downloadedMediaItem == null) {
|
||||
val builder = MediaItem.Builder().setUri(video!!.file.url).setMimeType(mimeType)
|
||||
logger("url: ${video!!.file.url}")
|
||||
logger("mimeType: $mimeType")
|
||||
|
||||
if (sub != null) {
|
||||
val listofnotnullsubs = immutableListOf(sub).filterNotNull()
|
||||
builder.setSubtitleConfigurations(listofnotnullsubs)
|
||||
}
|
||||
builder.build()
|
||||
} else {
|
||||
downloadedMediaItem
|
||||
}
|
||||
mediaItem = builder.build()
|
||||
|
||||
|
||||
//Source
|
||||
exoSource.setOnClickListener {
|
||||
@@ -1443,7 +1495,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
exoPlayer.release()
|
||||
VideoCache.release()
|
||||
mediaSession?.release()
|
||||
if(DiscordServiceRunningSingleton.running) {
|
||||
if (DiscordServiceRunningSingleton.running) {
|
||||
val stopIntent = Intent(this, DiscordService::class.java)
|
||||
DiscordServiceRunningSingleton.running = false
|
||||
stopService(stopIntent)
|
||||
@@ -1483,7 +1535,9 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
super.onPause()
|
||||
orientationListener?.disable()
|
||||
if (isInitialized) {
|
||||
playerView.player?.pause()
|
||||
if (!castPlayer.isPlaying) {
|
||||
playerView.player?.pause()
|
||||
}
|
||||
saveData(
|
||||
"${media.id}_${media.anime!!.selectedEpisode}",
|
||||
exoPlayer.currentPosition,
|
||||
@@ -1504,7 +1558,9 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
playerView.player?.pause()
|
||||
if (!castPlayer.isPlaying) {
|
||||
playerView.player?.pause()
|
||||
}
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
@@ -1576,7 +1632,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
if (isInitialized) {
|
||||
if (exoPlayer.currentPosition.toFloat() / exoPlayer.duration > settings.watchPercentage) {
|
||||
preloading = true
|
||||
nextEpisode(false) { i ->
|
||||
nextEpisode(false) { i -> //TODO: make sure this works for offline episodes
|
||||
val ep = episodes[episodeArr[currentEpisodeIndex + i]] ?: return@nextEpisode
|
||||
val selected = media.selected ?: return@nextEpisode
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
@@ -1797,7 +1853,6 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
|
||||
// Enter PiP Mode
|
||||
@Suppress("DEPRECATION")
|
||||
@RequiresApi(Build.VERSION_CODES.N)
|
||||
private fun enterPipMode() {
|
||||
wasPlaying = isPlayerPlaying
|
||||
if (!pipEnabled) return
|
||||
@@ -1870,6 +1925,47 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun startCastPlayer() {
|
||||
castPlayer.setMediaItem(mediaItem)
|
||||
castPlayer.prepare()
|
||||
playerView.player = castPlayer
|
||||
exoPlayer.stop()
|
||||
castPlayer.addListener(object : Player.Listener {
|
||||
//if the player is paused changed, we want to update the UI
|
||||
override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) {
|
||||
super.onPlayWhenReadyChanged(playWhenReady, reason)
|
||||
if (playWhenReady) {
|
||||
(exoPlay.drawable as Animatable?)?.start()
|
||||
Glide.with(this@ExoplayerView)
|
||||
.load(R.drawable.anim_play_to_pause)
|
||||
.into(exoPlay)
|
||||
} else {
|
||||
(exoPlay.drawable as Animatable?)?.start()
|
||||
Glide.with(this@ExoplayerView)
|
||||
.load(R.drawable.anim_pause_to_play)
|
||||
.into(exoPlay)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun startExoPlayer() {
|
||||
exoPlayer.setMediaItem(mediaItem)
|
||||
exoPlayer.prepare()
|
||||
playerView.player = exoPlayer
|
||||
castPlayer.stop()
|
||||
}
|
||||
|
||||
override fun onCastSessionAvailable() {
|
||||
startCastPlayer()
|
||||
}
|
||||
|
||||
override fun onCastSessionUnavailable() {
|
||||
startExoPlayer()
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
class ExtendedTimeBar(
|
||||
context: Context,
|
||||
|
||||
@@ -20,6 +20,7 @@ import ani.dantotsu.*
|
||||
import ani.dantotsu.databinding.BottomSheetSelectorBinding
|
||||
import ani.dantotsu.databinding.ItemStreamBinding
|
||||
import ani.dantotsu.databinding.ItemUrlBinding
|
||||
import ani.dantotsu.download.video.Helper
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.media.MediaDetailsViewModel
|
||||
import ani.dantotsu.others.Download.download
|
||||
@@ -214,7 +215,8 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
|
||||
|
||||
override fun onBindViewHolder(holder: StreamViewHolder, position: Int) {
|
||||
val extractor = links[position]
|
||||
holder.binding.streamName.text = extractor.server.name
|
||||
holder.binding.streamName.text = ""//extractor.server.name
|
||||
holder.binding.streamName.visibility = View.GONE
|
||||
|
||||
holder.binding.streamRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||
holder.binding.streamRecyclerView.adapter = VideoAdapter(extractor)
|
||||
@@ -256,10 +258,10 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
|
||||
override fun onBindViewHolder(holder: UrlViewHolder, position: Int) {
|
||||
val binding = holder.binding
|
||||
val video = extractor.videos[position]
|
||||
binding.urlQuality.text =
|
||||
if (video.quality != null) "${video.quality}p" else "Default Quality"
|
||||
binding.urlNote.text = video.extraNote ?: ""
|
||||
binding.urlNote.visibility = if (video.extraNote != null) View.VISIBLE else View.GONE
|
||||
//binding.urlQuality.text =
|
||||
// if (video.quality != null) "${video.quality}p" else "Default Quality"
|
||||
//binding.urlNote.text = video.extraNote ?: ""
|
||||
//binding.urlNote.visibility = if (video.extraNote != null) View.VISIBLE else View.GONE
|
||||
binding.urlDownload.visibility = View.VISIBLE
|
||||
binding.urlDownload.setSafeOnClickListener {
|
||||
media!!.anime!!.episodes!![media!!.anime!!.selectedEpisode!!]!!.selectedExtractor =
|
||||
@@ -267,11 +269,24 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
|
||||
media!!.anime!!.episodes!![media!!.anime!!.selectedEpisode!!]!!.selectedVideo =
|
||||
position
|
||||
binding.urlDownload.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||
download(
|
||||
requireActivity(),
|
||||
media!!.anime!!.episodes!![media!!.anime!!.selectedEpisode!!]!!,
|
||||
media!!.userPreferredName
|
||||
)
|
||||
//download(
|
||||
// requireActivity(),
|
||||
// media!!.anime!!.episodes!![media!!.anime!!.selectedEpisode!!]!!,
|
||||
// media!!.userPreferredName
|
||||
//)
|
||||
val episode = media!!.anime!!.episodes!![media!!.anime!!.selectedEpisode!!]!!
|
||||
val video = if (extractor.videos.size > episode.selectedVideo) extractor.videos[episode.selectedVideo] else null
|
||||
if (video != null) {
|
||||
Helper.startAnimeDownloadService(
|
||||
requireActivity(),
|
||||
media!!.userPreferredName,
|
||||
episode.number,
|
||||
video,
|
||||
null,
|
||||
media,
|
||||
episode.thumb?.url?: media!!.banner?: media!!.cover
|
||||
)
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
if (video.format == VideoType.CONTAINER) {
|
||||
@@ -282,11 +297,13 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
|
||||
"#.##"
|
||||
).format(video.size ?: 0).toString() + " MB"))
|
||||
} else {
|
||||
binding.urlQuality.text = "Multi Quality"
|
||||
if ((loadData<Int>("settings_download_manager") ?: 0) == 0) {
|
||||
binding.urlDownload.visibility = View.GONE
|
||||
////binding.urlDownload.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
binding.urlNote.visibility = View.VISIBLE
|
||||
binding.urlNote.text = video.format.name
|
||||
binding.urlQuality.text = extractor.server.name
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = extractor.videos.size
|
||||
|
||||
@@ -2,12 +2,14 @@ package ani.dantotsu.media.manga
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.CheckBox
|
||||
import android.widget.ImageButton
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.NumberPicker
|
||||
@@ -15,12 +17,14 @@ import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.*
|
||||
import ani.dantotsu.databinding.DialogLayoutBinding
|
||||
import ani.dantotsu.databinding.ItemAnimeWatchBinding
|
||||
import ani.dantotsu.databinding.ItemChipBinding
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.media.MediaDetailsActivity
|
||||
import ani.dantotsu.media.SourceSearchDialogFragment
|
||||
import ani.dantotsu.media.anime.handleProgress
|
||||
import ani.dantotsu.others.LanguageMapper
|
||||
import ani.dantotsu.parsers.DynamicMangaParser
|
||||
import ani.dantotsu.parsers.MangaReadSources
|
||||
import ani.dantotsu.parsers.MangaSources
|
||||
@@ -30,6 +34,7 @@ import com.google.android.material.chip.Chip
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
class MangaReadAdapter(
|
||||
private val media: Media,
|
||||
private val fragment: MangaReadFragment,
|
||||
@@ -46,7 +51,7 @@ class MangaReadAdapter(
|
||||
val bind = ItemAnimeWatchBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return ViewHolder(bind)
|
||||
}
|
||||
|
||||
private var nestedDialog: AlertDialog? = null
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val binding = holder.binding
|
||||
@@ -117,7 +122,7 @@ class MangaReadAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
//Subscription
|
||||
//Grids
|
||||
subscribe = MediaDetailsActivity.PopImageButton(
|
||||
fragment.lifecycleScope,
|
||||
binding.animeSourceSubscribe,
|
||||
@@ -136,98 +141,130 @@ class MangaReadAdapter(
|
||||
openSettings(fragment.requireContext(), getChannelId(true, media.id))
|
||||
}
|
||||
|
||||
//Icons
|
||||
binding.animeSourceGrid.visibility = View.GONE
|
||||
var reversed = media.selected!!.recyclerReversed
|
||||
var style = media.selected!!.recyclerStyle ?: fragment.uiSettings.mangaDefaultView
|
||||
binding.animeSourceTop.rotation = if (reversed) -90f else 90f
|
||||
binding.animeSourceTop.setOnClickListener {
|
||||
reversed = !reversed
|
||||
binding.animeSourceTop.rotation = if (reversed) -90f else 90f
|
||||
fragment.onIconPressed(style, reversed)
|
||||
}
|
||||
binding.animeNestedButton.setOnClickListener {
|
||||
|
||||
binding.animeScanlatorTop.setOnClickListener {
|
||||
val dialogView =
|
||||
LayoutInflater.from(currContext()).inflate(R.layout.custom_dialog_layout, null)
|
||||
val checkboxContainer = dialogView.findViewById<LinearLayout>(R.id.checkboxContainer)
|
||||
LayoutInflater.from(fragment.requireContext()).inflate(R.layout.dialog_layout, null)
|
||||
val dialogBinding = DialogLayoutBinding.bind(dialogView)
|
||||
|
||||
// Dynamically add checkboxes
|
||||
|
||||
options.forEach { option ->
|
||||
val checkBox = CheckBox(currContext()).apply {
|
||||
text = option
|
||||
}
|
||||
//set checked if it's already selected
|
||||
if (media.selected!!.scanlators != null) {
|
||||
checkBox.isChecked = media.selected!!.scanlators?.contains(option) != true
|
||||
scanlatorSelectionListener?.onScanlatorsSelected()
|
||||
} else {
|
||||
checkBox.isChecked = true
|
||||
}
|
||||
checkboxContainer.addView(checkBox)
|
||||
var run = false
|
||||
var reversed = media.selected!!.recyclerReversed
|
||||
var style = media.selected!!.recyclerStyle ?: fragment.uiSettings.animeDefaultView
|
||||
dialogBinding.animeSourceTop.rotation = if (reversed) -90f else 90f
|
||||
dialogBinding.sortText.text = if (reversed) "Down to Up" else "Up to Down"
|
||||
dialogBinding.animeSourceTop.setOnClickListener {
|
||||
reversed = !reversed
|
||||
dialogBinding.animeSourceTop.rotation = if (reversed) -90f else 90f
|
||||
dialogBinding.sortText.text = if (reversed) "Down to Up" else "Up to Down"
|
||||
run = true
|
||||
}
|
||||
|
||||
// Create AlertDialog
|
||||
val dialog = AlertDialog.Builder(currContext(), R.style.MyPopup)
|
||||
.setView(dialogView)
|
||||
.setPositiveButton("OK") { dialog, which ->
|
||||
//add unchecked to hidden
|
||||
hiddenScanlators.clear()
|
||||
for (i in 0 until checkboxContainer.childCount) {
|
||||
val checkBox = checkboxContainer.getChildAt(i) as CheckBox
|
||||
if (!checkBox.isChecked) {
|
||||
hiddenScanlators.add(checkBox.text.toString())
|
||||
}
|
||||
}
|
||||
fragment.onScanlatorChange(hiddenScanlators)
|
||||
scanlatorSelectionListener?.onScanlatorsSelected()
|
||||
}
|
||||
.setNegativeButton("Cancel", null)
|
||||
.show()
|
||||
dialog.window?.setDimAmount(0.8f)
|
||||
}
|
||||
|
||||
binding.animeDownloadTop.setOnClickListener {
|
||||
//Alert dialog asking for the number of chapters to download
|
||||
val alertDialog = AlertDialog.Builder(currContext(), R.style.MyPopup)
|
||||
alertDialog.setTitle("Multi Chapter Downloader")
|
||||
alertDialog.setMessage("Enter the number of chapters to download")
|
||||
val input = NumberPicker(currContext())
|
||||
input.minValue = 1
|
||||
input.maxValue = 20
|
||||
input.value = 1
|
||||
alertDialog.setView(input)
|
||||
alertDialog.setPositiveButton("OK") { dialog, which ->
|
||||
fragment.multiDownload(input.value)
|
||||
//Grids
|
||||
dialogBinding.animeSourceGrid.visibility = View.GONE
|
||||
var selected = when (style) {
|
||||
0 -> dialogBinding.animeSourceList
|
||||
1 -> dialogBinding.animeSourceCompact
|
||||
else -> dialogBinding.animeSourceList
|
||||
}
|
||||
when (style) {
|
||||
0 -> dialogBinding.layoutText.text = "List"
|
||||
1 -> dialogBinding.layoutText.text = "Compact"
|
||||
else -> dialogBinding.animeSourceList
|
||||
}
|
||||
alertDialog.setNegativeButton("Cancel") { dialog, _ -> dialog.cancel() }
|
||||
val dialog = alertDialog.show()
|
||||
dialog.window?.setDimAmount(0.8f)
|
||||
}
|
||||
|
||||
var selected = when (style) {
|
||||
0 -> binding.animeSourceList
|
||||
1 -> binding.animeSourceCompact
|
||||
else -> binding.animeSourceList
|
||||
}
|
||||
selected.alpha = 1f
|
||||
fun selected(it: ImageView) {
|
||||
selected.alpha = 0.33f
|
||||
selected = it
|
||||
selected.alpha = 1f
|
||||
}
|
||||
binding.animeSourceList.setOnClickListener {
|
||||
selected(it as ImageView)
|
||||
style = 0
|
||||
fragment.onIconPressed(style, reversed)
|
||||
}
|
||||
binding.animeSourceCompact.setOnClickListener {
|
||||
selected(it as ImageView)
|
||||
style = 1
|
||||
fragment.onIconPressed(style, reversed)
|
||||
}
|
||||
fun selected(it: ImageButton) {
|
||||
selected.alpha = 0.33f
|
||||
selected = it
|
||||
selected.alpha = 1f
|
||||
}
|
||||
dialogBinding.animeSourceList.setOnClickListener {
|
||||
selected(it as ImageButton)
|
||||
style = 0
|
||||
dialogBinding.layoutText.text = "List"
|
||||
run = true
|
||||
}
|
||||
dialogBinding.animeSourceCompact.setOnClickListener {
|
||||
selected(it as ImageButton)
|
||||
style = 1
|
||||
dialogBinding.layoutText.text = "Compact"
|
||||
run = true
|
||||
}
|
||||
|
||||
//Multi download
|
||||
dialogBinding.downloadNo.text = "0"
|
||||
dialogBinding.animeDownloadTop.setOnClickListener {
|
||||
//Alert dialog asking for the number of chapters to download
|
||||
val alertDialog = AlertDialog.Builder(currContext(), R.style.MyPopup)
|
||||
alertDialog.setTitle("Multi Chapter Downloader")
|
||||
alertDialog.setMessage("Enter the number of chapters to download")
|
||||
val input = NumberPicker(currContext())
|
||||
input.minValue = 1
|
||||
input.maxValue = 20
|
||||
input.value = 1
|
||||
alertDialog.setView(input)
|
||||
alertDialog.setPositiveButton("OK") { dialog, which ->
|
||||
dialogBinding.downloadNo.text = "${input.value}"
|
||||
}
|
||||
alertDialog.setNegativeButton("Cancel") { dialog, _ -> dialog.cancel() }
|
||||
val dialog = alertDialog.show()
|
||||
dialog.window?.setDimAmount(0.8f)
|
||||
}
|
||||
|
||||
//Scanlator
|
||||
dialogBinding.animeScanlatorTop.setOnClickListener {
|
||||
val dialogView2 =
|
||||
LayoutInflater.from(currContext()).inflate(R.layout.custom_dialog_layout, null)
|
||||
val checkboxContainer = dialogView2.findViewById<LinearLayout>(R.id.checkboxContainer)
|
||||
|
||||
// Dynamically add checkboxes
|
||||
options.forEach { option ->
|
||||
val checkBox = CheckBox(currContext()).apply {
|
||||
text = option
|
||||
}
|
||||
//set checked if it's already selected
|
||||
if (media.selected!!.scanlators != null) {
|
||||
checkBox.isChecked = media.selected!!.scanlators?.contains(option) != true
|
||||
scanlatorSelectionListener?.onScanlatorsSelected()
|
||||
} else {
|
||||
checkBox.isChecked = true
|
||||
}
|
||||
checkboxContainer.addView(checkBox)
|
||||
}
|
||||
|
||||
// Create AlertDialog
|
||||
val dialog = AlertDialog.Builder(currContext(), R.style.MyPopup)
|
||||
.setView(dialogView2)
|
||||
.setPositiveButton("OK") { dialog, which ->
|
||||
//add unchecked to hidden
|
||||
hiddenScanlators.clear()
|
||||
for (i in 0 until checkboxContainer.childCount) {
|
||||
val checkBox = checkboxContainer.getChildAt(i) as CheckBox
|
||||
if (!checkBox.isChecked) {
|
||||
hiddenScanlators.add(checkBox.text.toString())
|
||||
}
|
||||
}
|
||||
fragment.onScanlatorChange(hiddenScanlators)
|
||||
scanlatorSelectionListener?.onScanlatorsSelected()
|
||||
}
|
||||
.setNegativeButton("Cancel", null)
|
||||
.show()
|
||||
dialog.window?.setDimAmount(0.8f)
|
||||
}
|
||||
|
||||
nestedDialog = AlertDialog.Builder(fragment.requireContext() , R.style.MyPopup)
|
||||
.setTitle("Options")
|
||||
.setView(dialogView)
|
||||
.setPositiveButton("OK") { _, _ ->
|
||||
if(run) fragment.onIconPressed(style, reversed)
|
||||
if (dialogBinding.downloadNo.text != "0"){
|
||||
fragment.multiDownload(dialogBinding.downloadNo.text.toString().toInt())
|
||||
}
|
||||
}
|
||||
.setNegativeButton("Cancel") { _, _ ->
|
||||
}
|
||||
.create()
|
||||
nestedDialog?.show()
|
||||
}
|
||||
//Chapter Handling
|
||||
handleChapters()
|
||||
}
|
||||
@@ -385,12 +422,15 @@ class MangaReadAdapter(
|
||||
parser.extension.sources.firstOrNull()?.lang ?: "Unknown"
|
||||
)
|
||||
}
|
||||
binding?.animeSourceLanguage?.setAdapter(
|
||||
ArrayAdapter(
|
||||
fragment.requireContext(),
|
||||
R.layout.item_dropdown,
|
||||
parser.extension.sources.map { it.lang })
|
||||
val adapter = ArrayAdapter(
|
||||
fragment.requireContext(),
|
||||
R.layout.item_dropdown,
|
||||
parser.extension.sources.sortedBy { it.lang }.map { LanguageMapper.mapLanguageCodeToName(it.lang) }
|
||||
)
|
||||
val items = adapter.count
|
||||
if (items > 1) binding?.animeSourceLanguageContainer?.visibility = View.VISIBLE else binding?.animeSourceLanguageContainer?.visibility = View.GONE
|
||||
|
||||
binding?.animeSourceLanguage?.setAdapter(adapter)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import ani.dantotsu.*
|
||||
import ani.dantotsu.databinding.FragmentAnimeWatchBinding
|
||||
import ani.dantotsu.download.Download
|
||||
import ani.dantotsu.download.DownloadedType
|
||||
import ani.dantotsu.download.DownloadsManager
|
||||
import ani.dantotsu.download.manga.MangaDownloaderService
|
||||
import ani.dantotsu.download.manga.MangaServiceDataSingleton
|
||||
@@ -37,6 +37,7 @@ import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.media.MediaDetailsActivity
|
||||
import ani.dantotsu.media.MediaDetailsViewModel
|
||||
import ani.dantotsu.media.manga.mangareader.ChapterLoaderDialog
|
||||
import ani.dantotsu.others.LanguageMapper
|
||||
import ani.dantotsu.parsers.DynamicMangaParser
|
||||
import ani.dantotsu.parsers.HMangaSources
|
||||
import ani.dantotsu.parsers.MangaParser
|
||||
@@ -166,7 +167,7 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
|
||||
chapterAdapter =
|
||||
MangaChapterAdapter(style ?: uiSettings.mangaDefaultView, media, this)
|
||||
|
||||
for (download in downloadManager.mangaDownloads) {
|
||||
for (download in downloadManager.mangaDownloadedTypes) {
|
||||
chapterAdapter.stopDownload(download.chapter)
|
||||
}
|
||||
|
||||
@@ -196,26 +197,28 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
|
||||
override fun onScanlatorsSelected() {
|
||||
updateChapters()
|
||||
}
|
||||
|
||||
fun multiDownload(n: Int) {
|
||||
//get last viewed chapter
|
||||
val selected = media.userProgress
|
||||
val chapters = media.manga?.chapters?.values?.toList()
|
||||
//filter by selected language
|
||||
val progressChapterIndex = chapters?.indexOfFirst { MangaNameAdapter.findChapterNumber(it.number)?.toInt() == selected }?:0
|
||||
if (progressChapterIndex < 0 || n < 1) return
|
||||
val chaptersToDownload = chapters?.subList(
|
||||
progressChapterIndex + 1,
|
||||
progressChapterIndex + n + 1
|
||||
)
|
||||
if (chaptersToDownload != null) {
|
||||
for (chapter in chaptersToDownload) {
|
||||
onMangaChapterDownloadClick(chapter.title!!)
|
||||
}
|
||||
}
|
||||
val progressChapterIndex = (chapters?.indexOfFirst { MangaNameAdapter.findChapterNumber(it.number)?.toInt() == selected } ?: 0) + 1
|
||||
|
||||
if (progressChapterIndex < 0 || n < 1 || chapters == null) return
|
||||
|
||||
// Calculate the end index
|
||||
val endIndex = minOf(progressChapterIndex + n, chapters.size)
|
||||
|
||||
//make sure there are enough chapters
|
||||
val chaptersToDownload = chapters.subList(progressChapterIndex, endIndex)
|
||||
|
||||
|
||||
for (chapter in chaptersToDownload) {
|
||||
onMangaChapterDownloadClick(chapter.title!!)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun updateChapters() {
|
||||
val loadedChapters = model.getMangaChapters().value
|
||||
if (loadedChapters != null) {
|
||||
@@ -355,19 +358,19 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
|
||||
if (show) View.GONE else View.VISIBLE
|
||||
}
|
||||
}
|
||||
var itemSelected = false
|
||||
val allSettings = pkg.sources.filterIsInstance<ConfigurableSource>()
|
||||
if (allSettings.isNotEmpty()) {
|
||||
var selectedSetting = allSettings[0]
|
||||
if (allSettings.size > 1) {
|
||||
val names = allSettings.map { it.lang }.toTypedArray()
|
||||
val names = allSettings.sortedBy { it.lang }.map { LanguageMapper.mapLanguageCodeToName(it.lang) }.toTypedArray()
|
||||
var selectedIndex = 0
|
||||
val dialog = AlertDialog.Builder(requireContext())
|
||||
val dialog = AlertDialog.Builder(requireContext(), R.style.MyPopup)
|
||||
.setTitle("Select a Source")
|
||||
.setSingleChoiceItems(names, selectedIndex) { _, which ->
|
||||
.setSingleChoiceItems(names, selectedIndex) { dialog, which ->
|
||||
selectedIndex = which
|
||||
}
|
||||
.setPositiveButton("OK") { dialog, _ ->
|
||||
selectedSetting = allSettings[selectedIndex]
|
||||
itemSelected = true
|
||||
dialog.dismiss()
|
||||
|
||||
// Move the fragment transaction here
|
||||
@@ -382,10 +385,10 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
|
||||
.addToBackStack(null)
|
||||
.commit()
|
||||
}
|
||||
.setNegativeButton("Cancel") { dialog, _ ->
|
||||
dialog.cancel()
|
||||
changeUIVisibility(true)
|
||||
return@setNegativeButton
|
||||
.setOnDismissListener {
|
||||
if (!itemSelected) {
|
||||
changeUIVisibility(true)
|
||||
}
|
||||
}
|
||||
.show()
|
||||
dialog.window?.setDimAmount(0.8f)
|
||||
@@ -481,10 +484,10 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
|
||||
|
||||
fun onMangaChapterRemoveDownloadClick(i: String) {
|
||||
downloadManager.removeDownload(
|
||||
Download(
|
||||
DownloadedType(
|
||||
media.nameMAL ?: media.nameRomaji,
|
||||
i,
|
||||
Download.Type.MANGA
|
||||
DownloadedType.Type.MANGA
|
||||
)
|
||||
)
|
||||
chapterAdapter.deleteDownload(i)
|
||||
@@ -499,10 +502,10 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
|
||||
|
||||
// Remove the download from the manager and update the UI
|
||||
downloadManager.removeDownload(
|
||||
Download(
|
||||
DownloadedType(
|
||||
media.nameMAL ?: media.nameRomaji,
|
||||
i,
|
||||
Download.Type.MANGA
|
||||
DownloadedType.Type.MANGA
|
||||
)
|
||||
)
|
||||
chapterAdapter.purgeDownload(i)
|
||||
|
||||
@@ -89,7 +89,7 @@ abstract class BaseImageAdapter(
|
||||
}
|
||||
} else {
|
||||
val detector = GestureDetectorCompat(view.context, object : GesturesListener() {
|
||||
override fun onSingleClick(event: MotionEvent) = activity.handleController()
|
||||
override fun onSingleClick(event: MotionEvent) = activity.handleController(event = event)
|
||||
})
|
||||
view.findViewById<View>(R.id.imgProgCover).apply {
|
||||
setOnTouchListener { _, event ->
|
||||
@@ -112,6 +112,9 @@ abstract class BaseImageAdapter(
|
||||
activity.lifecycleScope.launch { loadImage(holder.bindingAdapterPosition, view) }
|
||||
}
|
||||
|
||||
abstract fun isZoomed(): Boolean
|
||||
abstract fun setZoom(zoom: Float)
|
||||
|
||||
abstract suspend fun loadImage(position: Int, parent: View): Boolean
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -91,4 +91,14 @@ open class ImageAdapter(
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = images.size
|
||||
|
||||
override fun isZoomed(): Boolean {
|
||||
val imageView = activity.findViewById<SubsamplingScaleImageView>(R.id.imgProgImageNoGestures)
|
||||
return imageView.scale > imageView.minScale
|
||||
}
|
||||
|
||||
override fun setZoom(zoom: Float) {
|
||||
val imageView = activity.findViewById<SubsamplingScaleImageView>(R.id.imgProgImageNoGestures)
|
||||
imageView.setScaleAndCenter(zoom, imageView.center)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@@ -702,8 +703,60 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||
goneTimer.schedule(timerTask, controllerDuration)
|
||||
}
|
||||
|
||||
fun handleController(shouldShow: Boolean? = null) {
|
||||
enum class pressPos {
|
||||
LEFT, RIGHT, CENTER
|
||||
}
|
||||
|
||||
fun handleController(shouldShow: Boolean? = null, event: MotionEvent? = null) {
|
||||
var pressLocation = pressPos.CENTER
|
||||
if (!sliding) {
|
||||
if (event != null && settings.default.layout == PAGED) {
|
||||
if (event.action != MotionEvent.ACTION_UP) return
|
||||
val x = event.rawX.toInt()
|
||||
val y = event.rawY.toInt()
|
||||
val screenWidth = Resources.getSystem().displayMetrics.widthPixels
|
||||
//if in the 1st 1/5th of the screen width, left and lower than 1/5th of the screen height, left
|
||||
if (screenWidth / 5 in (x + 1)..<y) {
|
||||
pressLocation = if (settings.default.direction == RIGHT_TO_LEFT) {
|
||||
pressPos.RIGHT
|
||||
} else {
|
||||
pressPos.LEFT
|
||||
}
|
||||
}
|
||||
//if in the last 1/5th of the screen width, right and lower than 1/5th of the screen height, right
|
||||
else if (x > screenWidth - screenWidth / 5 && y > screenWidth / 5) {
|
||||
pressLocation = if (settings.default.direction == RIGHT_TO_LEFT) {
|
||||
pressPos.LEFT
|
||||
} else {
|
||||
pressPos.RIGHT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if pressLocation is left or right go to previous or next page (paged mode only)
|
||||
if (pressLocation == pressPos.LEFT) {
|
||||
|
||||
if (binding.mangaReaderPager.currentItem > 0) {
|
||||
//if the current images zoomed in, go back to normal before going to previous page
|
||||
if (imageAdapter?.isZoomed() == true) {
|
||||
imageAdapter?.setZoom(1f)
|
||||
}
|
||||
binding.mangaReaderPager.currentItem -= 1
|
||||
return
|
||||
}
|
||||
|
||||
} 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) {
|
||||
imageAdapter?.setZoom(1f)
|
||||
}
|
||||
//if right to left, go to previous page
|
||||
binding.mangaReaderPager.currentItem += 1
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (!settings.showSystemBars) {
|
||||
hideBars()
|
||||
checkNotch()
|
||||
@@ -796,7 +849,7 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||
|
||||
private fun progress(runnable: Runnable) {
|
||||
if (maxChapterPage - currentChapterPage <= 1 && Anilist.userid != null) {
|
||||
if (showProgressDialog) {
|
||||
if (showProgressDialog) {
|
||||
|
||||
val dialogView = layoutInflater.inflate(R.layout.item_custom_dialog, null)
|
||||
val checkbox = dialogView.findViewById<CheckBox>(R.id.dialog_checkbox)
|
||||
@@ -805,8 +858,9 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||
saveData("${media.id}_progressDialog", isChecked)
|
||||
showProgressDialog = !isChecked
|
||||
}
|
||||
val incognito = currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
|
||||
?.getBoolean("incognito", false) ?: false
|
||||
val incognito =
|
||||
currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
|
||||
?.getBoolean("incognito", false) ?: false
|
||||
AlertDialog.Builder(this, R.style.MyPopup)
|
||||
.setTitle(getString(R.string.title_update_progress))
|
||||
.apply {
|
||||
@@ -818,7 +872,7 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(getString(R.string.yes)) { dialog, _ ->
|
||||
saveData("${media.id}_save_progress", true)
|
||||
updateProgress(
|
||||
updateProgress(
|
||||
media,
|
||||
MangaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!)
|
||||
.toString()
|
||||
|
||||
@@ -22,7 +22,7 @@ import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ConcatAdapter
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import ani.dantotsu.databinding.FragmentAnimeWatchBinding
|
||||
import ani.dantotsu.download.Download
|
||||
import ani.dantotsu.download.DownloadedType
|
||||
import ani.dantotsu.download.DownloadsManager
|
||||
import ani.dantotsu.download.novel.NovelDownloaderService
|
||||
import ani.dantotsu.download.novel.NovelServiceDataSingleton
|
||||
@@ -92,10 +92,10 @@ class NovelReadFragment : Fragment(),
|
||||
override fun downloadedCheckWithStart(novel: ShowResponse): Boolean {
|
||||
val downloadsManager = Injekt.get<DownloadsManager>()
|
||||
if (downloadsManager.queryDownload(
|
||||
Download(
|
||||
DownloadedType(
|
||||
media.nameMAL ?: media.nameRomaji,
|
||||
novel.name,
|
||||
Download.Type.NOVEL
|
||||
DownloadedType.Type.NOVEL
|
||||
)
|
||||
)
|
||||
) {
|
||||
@@ -124,10 +124,10 @@ class NovelReadFragment : Fragment(),
|
||||
override fun downloadedCheck(novel: ShowResponse): Boolean {
|
||||
val downloadsManager = Injekt.get<DownloadsManager>()
|
||||
return downloadsManager.queryDownload(
|
||||
Download(
|
||||
DownloadedType(
|
||||
media.nameMAL ?: media.nameRomaji,
|
||||
novel.name,
|
||||
Download.Type.NOVEL
|
||||
DownloadedType.Type.NOVEL
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -135,10 +135,10 @@ class NovelReadFragment : Fragment(),
|
||||
override fun deleteDownload(novel: ShowResponse) {
|
||||
val downloadsManager = Injekt.get<DownloadsManager>()
|
||||
downloadsManager.removeDownload(
|
||||
Download(
|
||||
DownloadedType(
|
||||
media.nameMAL ?: media.nameRomaji,
|
||||
novel.name,
|
||||
Download.Type.NOVEL
|
||||
DownloadedType.Type.NOVEL
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ import ani.dantotsu.saveData
|
||||
import ani.dantotsu.setSafeOnClickListener
|
||||
import ani.dantotsu.settings.CurrentNovelReaderSettings
|
||||
import ani.dantotsu.settings.CurrentReaderSettings
|
||||
import ani.dantotsu.settings.NovelReaderSettings
|
||||
import ani.dantotsu.settings.ReaderSettings
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.snackString
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
@@ -62,7 +62,7 @@ class NovelReaderActivity : AppCompatActivity(), EbookReaderEventListener {
|
||||
private lateinit var binding: ActivityNovelReaderBinding
|
||||
private val scope = lifecycleScope
|
||||
|
||||
lateinit var settings: NovelReaderSettings
|
||||
lateinit var settings: ReaderSettings
|
||||
private lateinit var uiSettings: UserInterfaceSettings
|
||||
|
||||
private var notchHeight: Int? = null
|
||||
@@ -159,9 +159,8 @@ class NovelReaderActivity : AppCompatActivity(), EbookReaderEventListener {
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityNovelReaderBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
settings = loadData("novel_reader_settings", this)
|
||||
?: NovelReaderSettings().apply { saveData("novel_reader_settings", this) }
|
||||
settings = loadData("reader_settings", this)
|
||||
?: ReaderSettings().apply { saveData("reader_settings", this) }
|
||||
uiSettings = loadData("ui_settings", this)
|
||||
?: UserInterfaceSettings().also { saveData("ui_settings", it) }
|
||||
|
||||
@@ -271,7 +270,7 @@ class NovelReaderActivity : AppCompatActivity(), EbookReaderEventListener {
|
||||
binding.bookReader.getAppearance {
|
||||
currentTheme = it
|
||||
themes.add(0, it)
|
||||
settings.default = loadData("${sanitizedBookId}_current_settings") ?: settings.default
|
||||
settings.defaultLN = loadData("${sanitizedBookId}_current_settings") ?: settings.defaultLN
|
||||
applySettings()
|
||||
}
|
||||
|
||||
@@ -323,7 +322,7 @@ class NovelReaderActivity : AppCompatActivity(), EbookReaderEventListener {
|
||||
return when (event.keyCode) {
|
||||
KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_PAGE_UP -> {
|
||||
if (event.keyCode == KeyEvent.KEYCODE_VOLUME_UP)
|
||||
if (!settings.default.volumeButtons)
|
||||
if (!settings.defaultLN.volumeButtons)
|
||||
return false
|
||||
if (event.action == KeyEvent.ACTION_DOWN) {
|
||||
onVolumeUp?.invoke()
|
||||
@@ -333,7 +332,7 @@ class NovelReaderActivity : AppCompatActivity(), EbookReaderEventListener {
|
||||
|
||||
KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_PAGE_DOWN -> {
|
||||
if (event.keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)
|
||||
if (!settings.default.volumeButtons)
|
||||
if (!settings.defaultLN.volumeButtons)
|
||||
return false
|
||||
if (event.action == KeyEvent.ACTION_DOWN) {
|
||||
onVolumeDown?.invoke()
|
||||
@@ -349,13 +348,18 @@ class NovelReaderActivity : AppCompatActivity(), EbookReaderEventListener {
|
||||
|
||||
|
||||
fun applySettings() {
|
||||
saveData("${sanitizedBookId}_current_settings", settings.default)
|
||||
saveData("${sanitizedBookId}_current_settings", settings.defaultLN)
|
||||
hideBars()
|
||||
|
||||
if(settings.defaultLN.useOledTheme) {
|
||||
themes.forEach { theme ->
|
||||
theme.darkBg = Color.parseColor("#000000")
|
||||
}
|
||||
}
|
||||
currentTheme =
|
||||
themes.first { it.name.equals(settings.default.currentThemeName, ignoreCase = true) }
|
||||
themes.first { it.name.equals(settings.defaultLN.currentThemeName, ignoreCase = true) }
|
||||
|
||||
when (settings.default.layout) {
|
||||
when (settings.defaultLN.layout) {
|
||||
CurrentNovelReaderSettings.Layouts.PAGED -> {
|
||||
currentTheme?.flow = ReaderFlow.PAGINATED
|
||||
}
|
||||
@@ -366,22 +370,22 @@ class NovelReaderActivity : AppCompatActivity(), EbookReaderEventListener {
|
||||
}
|
||||
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER
|
||||
when (settings.default.dualPageMode) {
|
||||
when (settings.defaultLN.dualPageMode) {
|
||||
CurrentReaderSettings.DualPageModes.No -> currentTheme?.maxColumnCount = 1
|
||||
CurrentReaderSettings.DualPageModes.Automatic -> currentTheme?.maxColumnCount = 2
|
||||
CurrentReaderSettings.DualPageModes.Force -> requestedOrientation =
|
||||
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||
}
|
||||
|
||||
currentTheme?.lineHeight = settings.default.lineHeight
|
||||
currentTheme?.gap = settings.default.margin
|
||||
currentTheme?.maxInlineSize = settings.default.maxInlineSize
|
||||
currentTheme?.maxBlockSize = settings.default.maxBlockSize
|
||||
currentTheme?.useDark = settings.default.useDarkTheme
|
||||
currentTheme?.lineHeight = settings.defaultLN.lineHeight
|
||||
currentTheme?.gap = settings.defaultLN.margin
|
||||
currentTheme?.maxInlineSize = settings.defaultLN.maxInlineSize
|
||||
currentTheme?.maxBlockSize = settings.defaultLN.maxBlockSize
|
||||
currentTheme?.useDark = settings.defaultLN.useDarkTheme
|
||||
|
||||
currentTheme?.let { binding.bookReader.setAppearance(it) }
|
||||
|
||||
if (settings.default.keepScreenOn) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
if (settings.defaultLN.keepScreenOn) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
else window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,7 @@ class NovelReaderSettingsDialogFragment : BottomSheetDialogFragment() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val activity = requireActivity() as NovelReaderActivity
|
||||
val settings = activity.settings.default
|
||||
|
||||
val settings = activity.settings.defaultLN
|
||||
val themeLabels = activity.themes.map { it.name }
|
||||
binding.themeSelect.adapter =
|
||||
NoPaddingArrayAdapter(activity, R.layout.item_dropdown, themeLabels)
|
||||
@@ -49,7 +48,11 @@ class NovelReaderSettingsDialogFragment : BottomSheetDialogFragment() {
|
||||
|
||||
override fun onNothingSelected(parent: AdapterView<*>?) {}
|
||||
}
|
||||
|
||||
binding.useOledTheme.isChecked = settings.useOledTheme
|
||||
binding.useOledTheme.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.useOledTheme = isChecked
|
||||
activity.applySettings()
|
||||
}
|
||||
val layoutList = listOf(
|
||||
binding.paged,
|
||||
binding.continuous
|
||||
@@ -173,6 +176,20 @@ class NovelReaderSettingsDialogFragment : BottomSheetDialogFragment() {
|
||||
binding.maxBlockSize.setText(value.toString())
|
||||
activity.applySettings()
|
||||
}
|
||||
|
||||
}
|
||||
binding.incrementMaxBlockSize.setOnClickListener {
|
||||
val value = binding.maxBlockSize.text.toString().toIntOrNull() ?: 720
|
||||
settings.maxBlockSize = value + 10
|
||||
binding.maxBlockSize.setText(settings.maxBlockSize.toString())
|
||||
activity.applySettings()
|
||||
}
|
||||
|
||||
binding.decrementMaxBlockSize.setOnClickListener {
|
||||
val value = binding.maxBlockSize.text.toString().toIntOrNull() ?: 720
|
||||
settings.maxBlockSize = value - 10
|
||||
binding.maxBlockSize.setText(settings.maxBlockSize.toString())
|
||||
activity.applySettings()
|
||||
}
|
||||
|
||||
binding.useDarkTheme.isChecked = settings.useDarkTheme
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ani.dantotsu.media.user
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
@@ -14,9 +15,11 @@ import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.Refresh
|
||||
import ani.dantotsu.currContext
|
||||
import ani.dantotsu.databinding.ActivityListBinding
|
||||
import ani.dantotsu.loadData
|
||||
import ani.dantotsu.others.LangSet
|
||||
import ani.dantotsu.saveData
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
@@ -62,7 +65,7 @@ class ListActivity : AppCompatActivity() {
|
||||
binding.listTabLayout.setTabTextColors(secondaryTextColor, primaryTextColor)
|
||||
binding.listTabLayout.setSelectedTabIndicatorColor(primaryTextColor)
|
||||
val uiSettings = loadData<UserInterfaceSettings>("ui_settings") ?: UserInterfaceSettings()
|
||||
if (!uiSettings.immersiveModeList) {
|
||||
if (!uiSettings.immersiveMode) {
|
||||
this.window.statusBarColor =
|
||||
ContextCompat.getColor(this, R.color.nav_bg_inv)
|
||||
binding.root.fitsSystemWindows = true
|
||||
@@ -78,8 +81,7 @@ 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 = (if (anime) "Anime" else "Manga") + " List"
|
||||
|
||||
binding.listTabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab?) {
|
||||
@@ -145,7 +147,8 @@ class ListActivity : AppCompatActivity() {
|
||||
R.id.release -> "release"
|
||||
else -> null
|
||||
}
|
||||
|
||||
currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)?.edit()
|
||||
?.putString("sort_order", sort)?.apply()
|
||||
binding.listProgressBar.visibility = View.VISIBLE
|
||||
binding.listViewPager.adapter = null
|
||||
scope.launch {
|
||||
|
||||
@@ -46,7 +46,7 @@ class ListFragment : Fragment() {
|
||||
binding.listRecyclerView.layoutManager =
|
||||
GridLayoutManager(
|
||||
requireContext(),
|
||||
if (grid!!) (screenWidth / 124f).toInt() else 1
|
||||
if (grid!!) (screenWidth / 120f).toInt() else 1
|
||||
)
|
||||
binding.listRecyclerView.adapter = adapter
|
||||
}
|
||||
|
||||
@@ -6,25 +6,116 @@ class LanguageMapper {
|
||||
fun mapLanguageCodeToName(code: String): String {
|
||||
return when (code) {
|
||||
"all" -> "Multi"
|
||||
"af" -> "Afrikaans"
|
||||
"am" -> "Amharic"
|
||||
"ar" -> "Arabic"
|
||||
"as" -> "Assamese"
|
||||
"az" -> "Azerbaijani"
|
||||
"be" -> "Belarusian"
|
||||
"bg" -> "Bulgarian"
|
||||
"bn" -> "Bengali"
|
||||
"bs" -> "Bosnian"
|
||||
"ca" -> "Catalan"
|
||||
"ceb" -> "Cebuano"
|
||||
"cs" -> "Czech"
|
||||
"da" -> "Danish"
|
||||
"de" -> "German"
|
||||
"el" -> "Greek"
|
||||
"en" -> "English"
|
||||
"en-Us" -> "English (United States)"
|
||||
"eo" -> "Esperanto"
|
||||
"es" -> "Spanish"
|
||||
"es-419" -> "Spanish (Latin America)"
|
||||
"et" -> "Estonian"
|
||||
"eu" -> "Basque"
|
||||
"fa" -> "Persian"
|
||||
"fi" -> "Finnish"
|
||||
"fil" -> "Filipino"
|
||||
"fo" -> "Faroese"
|
||||
"fr" -> "French"
|
||||
"ga" -> "Irish"
|
||||
"gn" -> "Guarani"
|
||||
"gu" -> "Gujarati"
|
||||
"ha" -> "Hausa"
|
||||
"he" -> "Hebrew"
|
||||
"hi" -> "Hindi"
|
||||
"hr" -> "Croatian"
|
||||
"ht" -> "Haitian Creole"
|
||||
"hu" -> "Hungarian"
|
||||
"hy" -> "Armenian"
|
||||
"id" -> "Indonesian"
|
||||
"ig" -> "Igbo"
|
||||
"is" -> "Icelandic"
|
||||
"it" -> "Italian"
|
||||
"ja" -> "Japanese"
|
||||
"jv" -> "Javanese"
|
||||
"ka" -> "Georgian"
|
||||
"kk" -> "Kazakh"
|
||||
"km" -> "Khmer"
|
||||
"kn" -> "Kannada"
|
||||
"ko" -> "Korean"
|
||||
"ku" -> "Kurdish"
|
||||
"ky" -> "Kyrgyz"
|
||||
"la" -> "Latin"
|
||||
"lb" -> "Luxembourgish"
|
||||
"lo" -> "Lao"
|
||||
"lt" -> "Lithuanian"
|
||||
"lv" -> "Latvian"
|
||||
"mg" -> "Malagasy"
|
||||
"mi" -> "Maori"
|
||||
"mk" -> "Macedonian"
|
||||
"ml" -> "Malayalam"
|
||||
"mn" -> "Mongolian"
|
||||
"mo" -> "Moldovan"
|
||||
"mr" -> "Marathi"
|
||||
"ms" -> "Malay"
|
||||
"mt" -> "Maltese"
|
||||
"my" -> "Burmese"
|
||||
"ne" -> "Nepali"
|
||||
"nl" -> "Dutch"
|
||||
"no" -> "Norwegian"
|
||||
"ny" -> "Chichewa"
|
||||
"pl" -> "Polish"
|
||||
"pt" -> "Portuguese"
|
||||
"pt-BR" -> "Portuguese (Brazil)"
|
||||
"pt-PT" -> "Portuguese (Portugal)"
|
||||
"ps" -> "Pashto"
|
||||
"ro" -> "Romanian"
|
||||
"rm" -> "Romansh"
|
||||
"ru" -> "Russian"
|
||||
"sd" -> "Sindhi"
|
||||
"sh" -> "Serbo-Croatian"
|
||||
"si" -> "Sinhala"
|
||||
"sk" -> "Slovak"
|
||||
"sl" -> "Slovenian"
|
||||
"sm" -> "Samoan"
|
||||
"sn" -> "Shona"
|
||||
"so" -> "Somali"
|
||||
"sq" -> "Albanian"
|
||||
"sr" -> "Serbian"
|
||||
"st" -> "Southern Sotho"
|
||||
"sv" -> "Swedish"
|
||||
"sw" -> "Swahili"
|
||||
"ta" -> "Tamil"
|
||||
"te" -> "Telugu"
|
||||
"tg" -> "Tajik"
|
||||
"th" -> "Thai"
|
||||
"ti" -> "Tigrinya"
|
||||
"tk" -> "Turkmen"
|
||||
"tl" -> "Tagalog"
|
||||
"to" -> "Tongan"
|
||||
"tr" -> "Turkish"
|
||||
"uk" -> "Ukrainian"
|
||||
"ur" -> "Urdu"
|
||||
"uz" -> "Uzbek"
|
||||
"vi" -> "Vietnamese"
|
||||
"yo" -> "Yoruba"
|
||||
"zh" -> "Chinese"
|
||||
"zh-Hans" -> "Chinese (Simplified)"
|
||||
else -> ""
|
||||
"zh-Hant" -> "Chinese (Traditional)"
|
||||
"zh-Habt" -> "Chinese (Hakka)"
|
||||
"zu" -> "Zulu"
|
||||
else -> code
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import ani.dantotsu.App.Companion.context
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.databinding.ActivityImageSearchBinding
|
||||
import ani.dantotsu.initActivity
|
||||
import ani.dantotsu.media.MediaDetailsActivity
|
||||
import ani.dantotsu.others.LangSet
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
@@ -49,6 +50,7 @@ class ImageSearchActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
LangSet.setLocale(this)
|
||||
initActivity(this)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityImageSearchBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
@@ -12,11 +12,17 @@ object AnimeSources : WatchSources() {
|
||||
suspend fun init(fromExtensions: StateFlow<List<AnimeExtension.Installed>>) {
|
||||
// Initialize with the first value from StateFlow
|
||||
val initialExtensions = fromExtensions.first()
|
||||
list = createParsersFromExtensions(initialExtensions)
|
||||
list = createParsersFromExtensions(initialExtensions) + Lazier(
|
||||
{ OfflineAnimeParser() },
|
||||
"Downloaded"
|
||||
)
|
||||
|
||||
// Update as StateFlow emits new values
|
||||
fromExtensions.collect { extensions ->
|
||||
list = createParsersFromExtensions(extensions)
|
||||
list = createParsersFromExtensions(extensions) + Lazier(
|
||||
{ OfflineAnimeParser() },
|
||||
"Downloaded"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import eu.kanade.tachiyomi.animesource.model.Track
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.network.interceptor.CloudflareBypassException
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
@@ -41,6 +42,7 @@ import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.Request
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.File
|
||||
@@ -112,7 +114,14 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
|
||||
seasonGroups.keys.sorted().flatMap { season ->
|
||||
seasonGroups[season]?.sortedBy { it.episode_number }?.map { episode ->
|
||||
if (episode.episode_number != 0f) { // Skip renumbering for episode number 0
|
||||
episode.episode_number = episodeCounter++
|
||||
val potentialNumber =
|
||||
AnimeNameAdapter.findEpisodeNumber(episode.name)
|
||||
if (potentialNumber != null) {
|
||||
episode.episode_number = potentialNumber
|
||||
} else {
|
||||
episode.episode_number = episodeCounter
|
||||
}
|
||||
episodeCounter++
|
||||
}
|
||||
episode
|
||||
} ?: emptyList()
|
||||
@@ -202,7 +211,11 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
|
||||
}
|
||||
return Episode(
|
||||
if (episodeNumberInt.toInt() != -1) {
|
||||
episodeNumberInt.toString()
|
||||
if (sEpisode.episode_number % 1 == 0f) {
|
||||
episodeNumberInt.toInt().toString()
|
||||
} else {
|
||||
sEpisode.episode_number.toString()
|
||||
}
|
||||
} else {
|
||||
sEpisode.name
|
||||
},
|
||||
@@ -603,13 +616,18 @@ class VideoServerPassthrough(val videoServer: VideoServer) : VideoExtractor() {
|
||||
val fileName = queryPairs.find { it.first == "file" }?.second ?: ""
|
||||
|
||||
format = getVideoType(fileName)
|
||||
// this solves a problem no one has, so I'm commenting it out for now
|
||||
//if (format == null) {
|
||||
// val networkHelper = Injekt.get<NetworkHelper>()
|
||||
// format = headRequest(videoUrl, networkHelper)
|
||||
//}
|
||||
}
|
||||
|
||||
// If the format is still undetermined, log an error or handle it appropriately
|
||||
// If the format is still undetermined, log an error
|
||||
if (format == null) {
|
||||
logger("Unknown video format: $videoUrl")
|
||||
FirebaseCrashlytics.getInstance()
|
||||
.recordException(Exception("Unknown video format: $videoUrl"))
|
||||
//FirebaseCrashlytics.getInstance()
|
||||
// .recordException(Exception("Unknown video format: $videoUrl"))
|
||||
format = VideoType.CONTAINER
|
||||
}
|
||||
val headersMap: Map<String, String> =
|
||||
@@ -620,12 +638,12 @@ class VideoServerPassthrough(val videoServer: VideoServer) : VideoExtractor() {
|
||||
number,
|
||||
format,
|
||||
FileUrl(videoUrl, headersMap),
|
||||
aniVideo.totalContentLength.toDouble()
|
||||
if (aniVideo.totalContentLength == 0L) null else aniVideo.bytesDownloaded.toDouble()
|
||||
)
|
||||
}
|
||||
|
||||
private fun getVideoType(fileName: String): VideoType? {
|
||||
return when {
|
||||
val type = when {
|
||||
fileName.endsWith(".mp4", ignoreCase = true) || fileName.endsWith(
|
||||
".mkv",
|
||||
ignoreCase = true
|
||||
@@ -635,6 +653,47 @@ class VideoServerPassthrough(val videoServer: VideoServer) : VideoExtractor() {
|
||||
fileName.endsWith(".mpd", ignoreCase = true) -> VideoType.DASH
|
||||
else -> null
|
||||
}
|
||||
|
||||
return type
|
||||
}
|
||||
|
||||
private fun headRequest(fileName: String, networkHelper: NetworkHelper): VideoType? {
|
||||
return try {
|
||||
logger("attempting head request for $fileName")
|
||||
val request = Request.Builder()
|
||||
.url(fileName)
|
||||
.head()
|
||||
.build()
|
||||
|
||||
networkHelper.client.newCall(request).execute().use { response ->
|
||||
val contentType = response.header("Content-Type")
|
||||
val contentDisposition = response.header("Content-Disposition")
|
||||
|
||||
if (contentType != null) {
|
||||
when {
|
||||
contentType.contains("mpegurl", ignoreCase = true) -> VideoType.M3U8
|
||||
contentType.contains("dash", ignoreCase = true) -> VideoType.DASH
|
||||
contentType.contains("mp4", ignoreCase = true) -> VideoType.CONTAINER
|
||||
else -> null
|
||||
}
|
||||
} else if (contentDisposition != null) {
|
||||
when {
|
||||
contentDisposition.contains("mpegurl", ignoreCase = true) -> VideoType.M3U8
|
||||
contentDisposition.contains("dash", ignoreCase = true) -> VideoType.DASH
|
||||
contentDisposition.contains("mp4", ignoreCase = true) -> VideoType.CONTAINER
|
||||
else -> null
|
||||
}
|
||||
} else {
|
||||
logger("failed head request for $fileName")
|
||||
null
|
||||
}
|
||||
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger("Exception in headRequest: $e")
|
||||
null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun TrackToSubtitle(track: Track): Subtitle {
|
||||
|
||||
@@ -156,9 +156,9 @@ abstract class BaseParser {
|
||||
}
|
||||
|
||||
fun checkIfVariablesAreEmpty() {
|
||||
if (hostUrl.isEmpty()) throw UninitializedPropertyAccessException("Please provide a `hostUrl` for the Parser")
|
||||
if (name.isEmpty()) throw UninitializedPropertyAccessException("Please provide a `name` for the Parser")
|
||||
if (saveName.isEmpty()) throw UninitializedPropertyAccessException("Please provide a `saveName` for the Parser")
|
||||
if (hostUrl.isEmpty()) throw UninitializedPropertyAccessException("Cannot find any installed extensions")
|
||||
if (name.isEmpty()) throw UninitializedPropertyAccessException("Cannot find any installed extensions")
|
||||
if (saveName.isEmpty()) throw UninitializedPropertyAccessException("Cannot find any installed extensions")
|
||||
}
|
||||
|
||||
open var showUserText = ""
|
||||
|
||||
@@ -46,6 +46,19 @@ abstract class WatchSources : BaseSources() {
|
||||
sEpisode = it.sEpisode
|
||||
)
|
||||
}
|
||||
} else if (parser is OfflineAnimeParser) {
|
||||
parser.loadEpisodes(showLink, extra, SAnime.create()).forEach {
|
||||
map[it.number] = Episode(
|
||||
it.number,
|
||||
it.link,
|
||||
it.title,
|
||||
it.description,
|
||||
it.thumbnail,
|
||||
it.isFiller,
|
||||
extra = it.extra,
|
||||
sEpisode = it.sEpisode
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return map
|
||||
|
||||
@@ -7,9 +7,6 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
object MangaSources : MangaReadSources() {
|
||||
// Instantiate the static parser
|
||||
private val offlineMangaParser by lazy { OfflineMangaParser() }
|
||||
|
||||
override var list: List<Lazier<BaseParser>> = emptyList()
|
||||
|
||||
suspend fun init(fromExtensions: StateFlow<List<MangaExtension.Installed>>) {
|
||||
|
||||
106
app/src/main/java/ani/dantotsu/parsers/OfflineAnimeParser.kt
Normal file
106
app/src/main/java/ani/dantotsu/parsers/OfflineAnimeParser.kt
Normal file
@@ -0,0 +1,106 @@
|
||||
package ani.dantotsu.parsers
|
||||
|
||||
import android.os.Environment
|
||||
import ani.dantotsu.currContext
|
||||
import ani.dantotsu.download.DownloadsManager
|
||||
import ani.dantotsu.logger
|
||||
import ani.dantotsu.media.anime.AnimeNameAdapter
|
||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
||||
import eu.kanade.tachiyomi.animesource.model.SEpisodeImpl
|
||||
import me.xdrop.fuzzywuzzy.FuzzySearch
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.File
|
||||
|
||||
class OfflineAnimeParser : AnimeParser() {
|
||||
private val downloadManager = Injekt.get<DownloadsManager>()
|
||||
|
||||
override val name = "Offline"
|
||||
override val saveName = "Offline"
|
||||
override val hostUrl = "Offline"
|
||||
override val isDubAvailableSeparately = false
|
||||
override val isNSFW = false
|
||||
|
||||
override suspend fun loadEpisodes(
|
||||
animeLink: String,
|
||||
extra: Map<String, String>?,
|
||||
sAnime: SAnime
|
||||
): List<Episode> {
|
||||
val directory = File(
|
||||
currContext()?.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
||||
"${DownloadsManager.animeLocation}/$animeLink"
|
||||
)
|
||||
//get all of the folder names and add them to the list
|
||||
val episodes = mutableListOf<Episode>()
|
||||
if (directory.exists()) {
|
||||
directory.listFiles()?.forEach {
|
||||
if (it.isDirectory) {
|
||||
val episode = Episode(
|
||||
it.name,
|
||||
"$animeLink - ${it.name}",
|
||||
it.name,
|
||||
null,
|
||||
null,
|
||||
sEpisode = SEpisodeImpl()
|
||||
)
|
||||
episodes.add(episode)
|
||||
}
|
||||
}
|
||||
episodes.sortBy { AnimeNameAdapter.findEpisodeNumber(it.number) }
|
||||
return episodes
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun loadVideoServers(
|
||||
episodeLink: String,
|
||||
extra: Map<String, String>?,
|
||||
sEpisode: SEpisode
|
||||
): List<VideoServer> {
|
||||
return listOf(
|
||||
VideoServer(
|
||||
episodeLink,
|
||||
offline = true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override suspend fun search(query: String): List<ShowResponse> {
|
||||
val titles = downloadManager.animeDownloadedTypes.map { it.title }.distinct()
|
||||
val returnTitles: MutableList<String> = mutableListOf()
|
||||
for (title in titles) {
|
||||
if (FuzzySearch.ratio(title.lowercase(), query.lowercase()) > 80) {
|
||||
returnTitles.add(title)
|
||||
}
|
||||
}
|
||||
val returnList: MutableList<ShowResponse> = mutableListOf()
|
||||
for (title in returnTitles) {
|
||||
returnList.add(ShowResponse(title, title, title))
|
||||
}
|
||||
return returnList
|
||||
}
|
||||
|
||||
override suspend fun getVideoExtractor(server: VideoServer): VideoExtractor {
|
||||
return OfflineVideoExtractor(server)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class OfflineVideoExtractor(val videoServer: VideoServer) : VideoExtractor() {
|
||||
override val server: VideoServer
|
||||
get() = videoServer
|
||||
|
||||
override suspend fun extract(): VideoContainer {
|
||||
val sublist = emptyList<Subtitle>()
|
||||
//we need to return a "fake" video so that the app doesn't crash
|
||||
val video = Video(
|
||||
null,
|
||||
VideoType.CONTAINER,
|
||||
"",
|
||||
)
|
||||
return VideoContainer(listOf(video), sublist)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -76,7 +76,7 @@ class OfflineMangaParser : MangaParser() {
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<ShowResponse> {
|
||||
val titles = downloadManager.mangaDownloads.map { it.title }.distinct()
|
||||
val titles = downloadManager.mangaDownloadedTypes.map { it.title }.distinct()
|
||||
val returnTitles: MutableList<String> = mutableListOf()
|
||||
for (title in titles) {
|
||||
if (FuzzySearch.ratio(title.lowercase(), query.lowercase()) > 80) {
|
||||
|
||||
@@ -3,10 +3,7 @@ package ani.dantotsu.parsers
|
||||
import android.os.Environment
|
||||
import ani.dantotsu.currContext
|
||||
import ani.dantotsu.download.DownloadsManager
|
||||
import ani.dantotsu.logger
|
||||
import ani.dantotsu.media.manga.MangaNameAdapter
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import me.xdrop.fuzzywuzzy.FuzzySearch
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@@ -53,7 +50,7 @@ class OfflineNovelParser: NovelParser() {
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<ShowResponse> {
|
||||
val titles = downloadManager.novelDownloads.map { it.title }.distinct()
|
||||
val titles = downloadManager.novelDownloadedTypes.map { it.title }.distinct()
|
||||
val returnTitles: MutableList<String> = mutableListOf()
|
||||
for (title in titles) {
|
||||
if (FuzzySearch.ratio(title.lowercase(), query.lowercase()) > 80) {
|
||||
|
||||
@@ -57,11 +57,15 @@ data class VideoServer(
|
||||
val name: String,
|
||||
val embed: FileUrl,
|
||||
val extraData: Map<String, String>? = null,
|
||||
val video: eu.kanade.tachiyomi.animesource.model.Video? = null
|
||||
val video: eu.kanade.tachiyomi.animesource.model.Video? = null,
|
||||
val offline: Boolean = false
|
||||
) : Serializable {
|
||||
constructor(name: String, embedUrl: String, extraData: Map<String, String>? = null)
|
||||
: this(name, FileUrl(embedUrl), extraData)
|
||||
|
||||
constructor(name: String, offline: Boolean)
|
||||
: this(name, FileUrl(""), null, null, offline)
|
||||
|
||||
constructor(
|
||||
name: String,
|
||||
embedUrl: String,
|
||||
|
||||
@@ -11,6 +11,7 @@ data class CurrentNovelReaderSettings(
|
||||
var justify: Boolean = true,
|
||||
var hyphenation: Boolean = true,
|
||||
var useDarkTheme: Boolean = false,
|
||||
var useOledTheme: Boolean = false,
|
||||
var invert: Boolean = false,
|
||||
var maxInlineSize: Int = 720,
|
||||
var maxBlockSize: Int = 1440,
|
||||
|
||||
@@ -61,11 +61,6 @@ class FAQActivity : AppCompatActivity() {
|
||||
currContext()!!.getString(R.string.question_7),
|
||||
currContext()!!.getString(R.string.answer_7)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_menu_book_24,
|
||||
currContext()!!.getString(R.string.question_8),
|
||||
currContext()!!.getString(R.string.answer_8)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_lock_open_24,
|
||||
currContext()!!.getString(R.string.question_9),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package ani.dantotsu.settings
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.AlertDialog
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
@@ -49,74 +50,66 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||
private val animeExtensionManager: AnimeExtensionManager = Injekt.get()
|
||||
private val extensionsAdapter = AnimeExtensionsAdapter(
|
||||
{ pkg ->
|
||||
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<ViewPager2>(R.id.viewPager).visibility = visibility
|
||||
activity.findViewById<TabLayout>(R.id.tabLayout).visibility = visibility
|
||||
activity.findViewById<TextInputLayout>(R.id.searchView).visibility = visibility
|
||||
activity.findViewById<ImageView>(R.id.languageselect).visibility = visibility
|
||||
activity.findViewById<TextView>(R.id.extensions).text = if (show) getString(R.string.extensions) else name
|
||||
activity.findViewById<FrameLayout>(R.id.fragmentExtensionsContainer).visibility =
|
||||
if (show) View.GONE else View.VISIBLE
|
||||
}
|
||||
var itemSelected = false
|
||||
val allSettings = pkg.sources.filterIsInstance<ConfigurableAnimeSource>()
|
||||
if (allSettings.isNotEmpty()) {
|
||||
var selectedSetting = allSettings[0]
|
||||
if (allSettings.size > 1) {
|
||||
val names = allSettings.map { it.lang }.toTypedArray()
|
||||
val names = allSettings.sortedBy { it.lang }.map { LanguageMapper.mapLanguageCodeToName(it.lang) }.toTypedArray()
|
||||
var selectedIndex = 0
|
||||
val dialog = AlertDialog.Builder(requireContext(), R.style.MyPopup)
|
||||
.setTitle("Select a Source")
|
||||
.setSingleChoiceItems(names, selectedIndex) { dialog, which ->
|
||||
itemSelected = true
|
||||
selectedIndex = which
|
||||
selectedSetting = allSettings[selectedIndex]
|
||||
dialog.dismiss()
|
||||
|
||||
// Move the fragment transaction here
|
||||
val eActivity = requireActivity() as ExtensionsActivity
|
||||
eActivity.runOnUiThread {
|
||||
val fragment =
|
||||
AnimeSourcePreferencesFragment().getInstance(selectedSetting.id) {
|
||||
|
||||
eActivity.findViewById<ViewPager2>(R.id.viewPager).visibility =
|
||||
View.VISIBLE
|
||||
eActivity.findViewById<TabLayout>(R.id.tabLayout).visibility =
|
||||
View.VISIBLE
|
||||
eActivity.findViewById<TextInputLayout>(R.id.searchView).visibility =
|
||||
View.VISIBLE
|
||||
eActivity.findViewById<FrameLayout>(R.id.fragmentExtensionsContainer).visibility =
|
||||
View.GONE
|
||||
}
|
||||
parentFragmentManager.beginTransaction()
|
||||
.setCustomAnimations(R.anim.slide_up, R.anim.slide_down)
|
||||
.replace(R.id.fragmentExtensionsContainer, fragment)
|
||||
.addToBackStack(null)
|
||||
.commit()
|
||||
val fragment =
|
||||
AnimeSourcePreferencesFragment().getInstance(selectedSetting.id) {
|
||||
changeUIVisibility(true)
|
||||
}
|
||||
parentFragmentManager.beginTransaction()
|
||||
.setCustomAnimations(R.anim.slide_up, R.anim.slide_down)
|
||||
.replace(R.id.fragmentExtensionsContainer, fragment)
|
||||
.addToBackStack(null)
|
||||
.commit()
|
||||
}
|
||||
.setOnDismissListener {
|
||||
if (!itemSelected) {
|
||||
changeUIVisibility(true)
|
||||
}
|
||||
}
|
||||
.show()
|
||||
dialog.window?.setDimAmount(0.8f)
|
||||
} else {
|
||||
// If there's only one setting, proceed with the fragment transaction
|
||||
val eActivity = requireActivity() as ExtensionsActivity
|
||||
eActivity.runOnUiThread {
|
||||
val fragment =
|
||||
AnimeSourcePreferencesFragment().getInstance(selectedSetting.id) {
|
||||
val fragment =
|
||||
AnimeSourcePreferencesFragment().getInstance(selectedSetting.id) {
|
||||
changeUIVisibility(true)
|
||||
}
|
||||
parentFragmentManager.beginTransaction()
|
||||
.setCustomAnimations(R.anim.slide_up, R.anim.slide_down)
|
||||
.replace(R.id.fragmentExtensionsContainer, fragment)
|
||||
.addToBackStack(null)
|
||||
.commit()
|
||||
|
||||
eActivity.findViewById<ViewPager2>(R.id.viewPager).visibility =
|
||||
View.VISIBLE
|
||||
eActivity.findViewById<TabLayout>(R.id.tabLayout).visibility =
|
||||
View.VISIBLE
|
||||
eActivity.findViewById<TextInputLayout>(R.id.searchView).visibility =
|
||||
View.VISIBLE
|
||||
eActivity.findViewById<FrameLayout>(R.id.fragmentExtensionsContainer).visibility =
|
||||
View.GONE
|
||||
}
|
||||
parentFragmentManager.beginTransaction()
|
||||
.setCustomAnimations(R.anim.slide_up, R.anim.slide_down)
|
||||
.replace(R.id.fragmentExtensionsContainer, fragment)
|
||||
.addToBackStack(null)
|
||||
.commit()
|
||||
}
|
||||
}
|
||||
|
||||
// Hide ViewPager2 and TabLayout
|
||||
val activity = requireActivity() as ExtensionsActivity
|
||||
activity.findViewById<ViewPager2>(R.id.viewPager).visibility = View.GONE
|
||||
activity.findViewById<TabLayout>(R.id.tabLayout).visibility = View.GONE
|
||||
activity.findViewById<TextInputLayout>(R.id.searchView).visibility = View.GONE
|
||||
activity.findViewById<FrameLayout>(R.id.fragmentExtensionsContainer).visibility =
|
||||
View.VISIBLE
|
||||
changeUIVisibility(false)
|
||||
} else {
|
||||
Toast.makeText(requireContext(), "Source is not configurable", Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
@@ -225,6 +218,7 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val extension = getItem(position) // Use getItem() from ListAdapter
|
||||
val nsfw = if (extension.isNsfw) "(18+)" else ""
|
||||
|
||||
@@ -47,24 +47,29 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||
val skipIcons = loadData("skip_extension_icons") ?: false
|
||||
private val mangaExtensionManager: MangaExtensionManager = Injekt.get()
|
||||
private val extensionsAdapter = MangaExtensionsAdapter({ pkg ->
|
||||
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<ViewPager2>(R.id.viewPager).visibility = visibility
|
||||
activity.findViewById<TabLayout>(R.id.tabLayout).visibility = visibility
|
||||
activity.findViewById<TextInputLayout>(R.id.searchView).visibility = visibility
|
||||
activity.findViewById<ImageView>(R.id.languageselect).visibility = visibility
|
||||
activity.findViewById<TextView>(R.id.extensions).text = if (show) getString(R.string.extensions) else name
|
||||
activity.findViewById<FrameLayout>(R.id.fragmentExtensionsContainer).visibility =
|
||||
if (show) View.GONE else View.VISIBLE
|
||||
}
|
||||
var itemSelected = false
|
||||
val allSettings = pkg.sources.filterIsInstance<ConfigurableSource>()
|
||||
if (allSettings.isNotEmpty()) {
|
||||
var selectedSetting = allSettings[0]
|
||||
if (allSettings.size > 1) {
|
||||
val names = allSettings.map { it.lang }.toTypedArray()
|
||||
val names = allSettings.sortedBy { it.lang }.map { LanguageMapper.mapLanguageCodeToName(it.lang) }.toTypedArray()
|
||||
var selectedIndex = 0
|
||||
val dialog = AlertDialog.Builder(requireContext(), R.style.MyPopup)
|
||||
.setTitle("Select a Source")
|
||||
.setSingleChoiceItems(names, selectedIndex) { dialog, which ->
|
||||
itemSelected = true
|
||||
selectedIndex = which
|
||||
selectedSetting = allSettings[selectedIndex]
|
||||
dialog.dismiss()
|
||||
@@ -80,6 +85,11 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||
.addToBackStack(null)
|
||||
.commit()
|
||||
}
|
||||
.setOnDismissListener {
|
||||
if (!itemSelected) {
|
||||
changeUIVisibility(true)
|
||||
}
|
||||
}
|
||||
.show()
|
||||
dialog.window?.setDimAmount(0.8f)
|
||||
} else {
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package ani.dantotsu.settings
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class NovelReaderSettings(
|
||||
var showSource: Boolean = true,
|
||||
var showSystemBars: Boolean = false,
|
||||
var default: CurrentNovelReaderSettings = CurrentNovelReaderSettings(),
|
||||
var askIndividual: Boolean = true,
|
||||
) : Serializable
|
||||
@@ -45,6 +45,6 @@ data class PlayerSettings(
|
||||
var skipTime: Int = 85,
|
||||
|
||||
//Other
|
||||
var cast: Boolean = false,
|
||||
var cast: Boolean = true,
|
||||
var pip: Boolean = true
|
||||
) : Serializable
|
||||
|
||||
@@ -8,6 +8,7 @@ data class ReaderSettings(
|
||||
|
||||
var autoDetectWebtoon: Boolean = true,
|
||||
var default: CurrentReaderSettings = CurrentReaderSettings(),
|
||||
var defaultLN: CurrentNovelReaderSettings = CurrentNovelReaderSettings(),
|
||||
|
||||
var askIndividual: Boolean = true,
|
||||
var updateForH: Boolean = false
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package ani.dantotsu.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import ani.dantotsu.NoPaddingArrayAdapter
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.databinding.ActivityReaderSettingsBinding
|
||||
import ani.dantotsu.initActivity
|
||||
import ani.dantotsu.loadData
|
||||
import ani.dantotsu.media.novel.novelreader.NovelReaderActivity
|
||||
import ani.dantotsu.navBarHeight
|
||||
import ani.dantotsu.others.LangSet
|
||||
import ani.dantotsu.saveData
|
||||
@@ -42,7 +46,7 @@ class ReaderSettingsActivity : AppCompatActivity() {
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
//General
|
||||
//Manga Settings
|
||||
binding.readerSettingsSourceName.isChecked = settings.showSource
|
||||
binding.readerSettingsSourceName.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.showSource = isChecked
|
||||
@@ -54,14 +58,14 @@ class ReaderSettingsActivity : AppCompatActivity() {
|
||||
settings.showSystemBars = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
//Default Manga
|
||||
binding.readerSettingsAutoWebToon.isChecked = settings.autoDetectWebtoon
|
||||
binding.readerSettingsAutoWebToon.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.autoDetectWebtoon = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
//Default
|
||||
|
||||
val layoutList = listOf(
|
||||
binding.readerSettingsPaged,
|
||||
binding.readerSettingsContinuousPaged,
|
||||
@@ -185,6 +189,169 @@ class ReaderSettingsActivity : AppCompatActivity() {
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
//LN settings
|
||||
val layoutListLN = listOf(
|
||||
binding.LNpaged,
|
||||
binding.LNcontinuous
|
||||
)
|
||||
|
||||
binding.LNlayoutText.text = settings.defaultLN.layout.string
|
||||
var selectedLN = layoutListLN[settings.defaultLN.layout.ordinal]
|
||||
selectedLN.alpha = 1f
|
||||
|
||||
layoutListLN.forEachIndexed { index, imageButton ->
|
||||
imageButton.setOnClickListener {
|
||||
selectedLN.alpha = 0.33f
|
||||
selectedLN = imageButton
|
||||
selectedLN.alpha = 1f
|
||||
settings.defaultLN.layout = CurrentNovelReaderSettings.Layouts[index]
|
||||
?: CurrentNovelReaderSettings.Layouts.PAGED
|
||||
binding.LNlayoutText.text = settings.defaultLN.layout.string
|
||||
saveData(reader, settings)
|
||||
}
|
||||
}
|
||||
|
||||
val dualListLN = listOf(
|
||||
binding.LNdualNo,
|
||||
binding.LNdualAuto,
|
||||
binding.LNdualForce
|
||||
)
|
||||
|
||||
binding.LNdualPageText.text = settings.defaultLN.dualPageMode.toString()
|
||||
var selectedDualLN = dualListLN[settings.defaultLN.dualPageMode.ordinal]
|
||||
selectedDualLN.alpha = 1f
|
||||
|
||||
dualListLN.forEachIndexed { index, imageButton ->
|
||||
imageButton.setOnClickListener {
|
||||
selectedDualLN.alpha = 0.33f
|
||||
selectedDualLN = imageButton
|
||||
selectedDualLN.alpha = 1f
|
||||
settings.defaultLN.dualPageMode = CurrentReaderSettings.DualPageModes[index]
|
||||
?: CurrentReaderSettings.DualPageModes.Automatic
|
||||
binding.LNdualPageText.text = settings.defaultLN.dualPageMode.toString()
|
||||
saveData(reader, settings)
|
||||
}
|
||||
}
|
||||
|
||||
binding.LNlineHeight.setText(settings.defaultLN.lineHeight.toString())
|
||||
binding.LNlineHeight.setOnFocusChangeListener { _, hasFocus ->
|
||||
if (!hasFocus) {
|
||||
val value = binding.LNlineHeight.text.toString().toFloatOrNull() ?: 1.4f
|
||||
settings.defaultLN.lineHeight = value
|
||||
binding.LNlineHeight.setText(value.toString())
|
||||
saveData(reader, settings)
|
||||
}
|
||||
}
|
||||
|
||||
binding.LNincrementLineHeight.setOnClickListener {
|
||||
val value = binding.LNlineHeight.text.toString().toFloatOrNull() ?: 1.4f
|
||||
settings.defaultLN.lineHeight = value + 0.1f
|
||||
binding.LNlineHeight.setText(settings.defaultLN.lineHeight.toString())
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.LNdecrementLineHeight.setOnClickListener {
|
||||
val value = binding.LNlineHeight.text.toString().toFloatOrNull() ?: 1.4f
|
||||
settings.defaultLN.lineHeight = value - 0.1f
|
||||
binding.LNlineHeight.setText(settings.defaultLN.lineHeight.toString())
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.LNmargin.setText(settings.defaultLN.margin.toString())
|
||||
binding.LNmargin.setOnFocusChangeListener { _, hasFocus ->
|
||||
if (!hasFocus) {
|
||||
val value = binding.LNmargin.text.toString().toFloatOrNull() ?: 0.06f
|
||||
settings.defaultLN.margin = value
|
||||
binding.LNmargin.setText(value.toString())
|
||||
saveData(reader, settings)
|
||||
}
|
||||
}
|
||||
|
||||
binding.LNincrementMargin.setOnClickListener {
|
||||
val value = binding.LNmargin.text.toString().toFloatOrNull() ?: 0.06f
|
||||
settings.defaultLN.margin = value + 0.01f
|
||||
binding.LNmargin.setText(settings.defaultLN.margin.toString())
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.LNdecrementMargin.setOnClickListener {
|
||||
val value = binding.LNmargin.text.toString().toFloatOrNull() ?: 0.06f
|
||||
settings.defaultLN.margin = value - 0.01f
|
||||
binding.LNmargin.setText(settings.defaultLN.margin.toString())
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.LNmaxInlineSize.setText(settings.defaultLN.maxInlineSize.toString())
|
||||
binding.LNmaxInlineSize.setOnFocusChangeListener { _, hasFocus ->
|
||||
if (!hasFocus) {
|
||||
val value = binding.LNmaxInlineSize.text.toString().toIntOrNull() ?: 720
|
||||
settings.defaultLN.maxInlineSize = value
|
||||
binding.LNmaxInlineSize.setText(value.toString())
|
||||
saveData(reader, settings)
|
||||
}
|
||||
}
|
||||
|
||||
binding.LNincrementMaxInlineSize.setOnClickListener {
|
||||
val value = binding.LNmaxInlineSize.text.toString().toIntOrNull() ?: 720
|
||||
settings.defaultLN.maxInlineSize = value + 10
|
||||
binding.LNmaxInlineSize.setText(settings.defaultLN.maxInlineSize.toString())
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.LNdecrementMaxInlineSize.setOnClickListener {
|
||||
val value = binding.LNmaxInlineSize.text.toString().toIntOrNull() ?: 720
|
||||
settings.defaultLN.maxInlineSize = value - 10
|
||||
binding.LNmaxInlineSize.setText(settings.defaultLN.maxInlineSize.toString())
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.LNmaxBlockSize.setText(settings.defaultLN.maxBlockSize.toString())
|
||||
binding.LNmaxBlockSize.setOnFocusChangeListener { _, hasFocus ->
|
||||
if (!hasFocus) {
|
||||
val value = binding.LNmaxBlockSize.text.toString().toIntOrNull() ?: 720
|
||||
settings.defaultLN.maxBlockSize = value
|
||||
binding.LNmaxBlockSize.setText(value.toString())
|
||||
saveData(reader, settings)
|
||||
}
|
||||
}
|
||||
binding.LNincrementMaxBlockSize.setOnClickListener {
|
||||
val value = binding.LNmaxBlockSize.text.toString().toIntOrNull() ?: 720
|
||||
settings.defaultLN.maxInlineSize = value + 10
|
||||
binding.LNmaxBlockSize.setText(settings.defaultLN.maxInlineSize.toString())
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.LNdecrementMaxBlockSize.setOnClickListener {
|
||||
val value = binding.LNmaxBlockSize.text.toString().toIntOrNull() ?: 720
|
||||
settings.defaultLN.maxBlockSize = value - 10
|
||||
binding.LNmaxBlockSize.setText(settings.defaultLN.maxBlockSize.toString())
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.LNuseDarkTheme.isChecked = settings.defaultLN.useDarkTheme
|
||||
binding.LNuseDarkTheme.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.defaultLN.useDarkTheme = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.LNuseOledTheme.isChecked = settings.defaultLN.useOledTheme
|
||||
binding.LNuseOledTheme.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.defaultLN.useOledTheme = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.LNkeepScreenOn.isChecked = settings.defaultLN.keepScreenOn
|
||||
binding.LNkeepScreenOn.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.defaultLN.keepScreenOn = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.LNvolumeButton.isChecked = settings.defaultLN.volumeButtons
|
||||
binding.LNvolumeButton.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.defaultLN.volumeButtons = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
//Update Progress
|
||||
binding.readerSettingsAskUpdateProgress.isChecked = settings.askIndividual
|
||||
binding.readerSettingsAskUpdateProgress.setOnCheckedChangeListener { _, isChecked ->
|
||||
|
||||
@@ -178,13 +178,18 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListen
|
||||
|
||||
|
||||
binding.customTheme.setOnClickListener {
|
||||
val originalColor = getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getInt(
|
||||
val originalColor = getSharedPreferences("Dantotsu", MODE_PRIVATE).getInt(
|
||||
"custom_theme_int",
|
||||
Color.parseColor("#6200EE")
|
||||
)
|
||||
class CustomColorDialog : SimpleColorDialog() { //idk where to put it
|
||||
override fun onPositiveButtonClick() {
|
||||
restartApp()
|
||||
super.onPositiveButtonClick()
|
||||
}
|
||||
}
|
||||
val tag = "colorPicker"
|
||||
SimpleColorDialog.build()
|
||||
.title("Custom Theme")
|
||||
CustomColorDialog().title("Custom Theme")
|
||||
.colorPreset(originalColor)
|
||||
.colors(this, SimpleColorDialog.BEIGE_COLOR_PALLET)
|
||||
.allowCustom(true)
|
||||
@@ -251,9 +256,9 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListen
|
||||
binding.skipExtensionIcons.setOnCheckedChangeListener { _, isChecked ->
|
||||
saveData("skip_extension_icons", isChecked)
|
||||
}
|
||||
binding.NSFWExtension.isChecked = loadData("NFSWExtension") ?: true
|
||||
binding.NSFWExtension.isChecked = loadData("NSFWExtension") ?: true
|
||||
binding.NSFWExtension.setOnCheckedChangeListener { _, isChecked ->
|
||||
saveData("NFSWExtension", isChecked)
|
||||
saveData("NSFWExtension", isChecked)
|
||||
|
||||
}
|
||||
|
||||
@@ -400,6 +405,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListen
|
||||
uiTheme(true, it)
|
||||
}
|
||||
|
||||
|
||||
var previousStart: View = when (uiSettings.defaultStartUpTab) {
|
||||
0 -> binding.uiSettingsAnime
|
||||
1 -> binding.uiSettingsHome
|
||||
@@ -416,6 +422,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListen
|
||||
initActivity(this)
|
||||
}
|
||||
|
||||
|
||||
binding.uiSettingsAnime.setOnClickListener {
|
||||
uiTheme(0, it)
|
||||
}
|
||||
@@ -782,4 +789,4 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListen
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ data class UserInterfaceSettings(
|
||||
|
||||
//App
|
||||
var immersiveMode: Boolean = false,
|
||||
var immersiveModeList: Boolean = false,
|
||||
var smallView: Boolean = true,
|
||||
var defaultStartUpTab: Int = 1,
|
||||
var homeLayoutShow: MutableList<Boolean> = mutableListOf(
|
||||
|
||||
@@ -68,13 +68,6 @@ class UserInterfaceSettingsActivity : AppCompatActivity() {
|
||||
saveData(ui, settings)
|
||||
restartApp()
|
||||
}
|
||||
binding.uiSettingsImmersiveList.isChecked = settings.immersiveModeList
|
||||
binding.uiSettingsImmersiveList.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.immersiveModeList = isChecked
|
||||
saveData(ui, settings)
|
||||
restartApp()
|
||||
}
|
||||
|
||||
binding.uiSettingsBannerAnimation.isChecked = settings.bannerAnimations
|
||||
binding.uiSettingsBannerAnimation.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.bannerAnimations = isChecked
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package ani.dantotsu.settings.paging
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.LinearInterpolator
|
||||
@@ -91,18 +92,14 @@ class AnimeExtensionPagingSource(
|
||||
val availableExtensions =
|
||||
availableExtensionsFlow.filterNot { it.pkgName in installedExtensions }
|
||||
val query = searchQuery
|
||||
val isNsfwEnabled: Boolean = loadData("NFSWExtension") ?: true
|
||||
val isNsfwEnabled: Boolean = loadData("NSFWExtension") ?: true
|
||||
|
||||
val filteredExtensions = if (query.isEmpty()) {
|
||||
availableExtensions
|
||||
} else {
|
||||
availableExtensions.filter { it.name.contains(query, ignoreCase = true) }
|
||||
}
|
||||
val filternfsw = if (isNsfwEnabled) {
|
||||
filteredExtensions
|
||||
} else {
|
||||
filteredExtensions.filterNot { it.isNsfw }
|
||||
}
|
||||
val filternfsw = if (isNsfwEnabled) filteredExtensions else filteredExtensions.filterNot { it.isNsfw }
|
||||
return try {
|
||||
val sublist = filternfsw.subList(
|
||||
fromIndex = position,
|
||||
@@ -198,6 +195,7 @@ 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)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package ani.dantotsu.settings.paging
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.LinearInterpolator
|
||||
@@ -91,17 +92,13 @@ class MangaExtensionPagingSource(
|
||||
val availableExtensions =
|
||||
availableExtensionsFlow.filterNot { it.pkgName in installedExtensions }
|
||||
val query = searchQuery
|
||||
val isNsfwEnabled: Boolean = loadData("NFSWExtension") ?: true
|
||||
val isNsfwEnabled: Boolean = loadData("NSFWExtension") ?: true
|
||||
val filteredExtensions = if (query.isEmpty()) {
|
||||
availableExtensions
|
||||
} else {
|
||||
availableExtensions.filter { it.name.contains(query, ignoreCase = true) }
|
||||
}
|
||||
val filternfsw = if (isNsfwEnabled) {
|
||||
filteredExtensions
|
||||
} else {
|
||||
filteredExtensions.filterNot { it.isNsfw }
|
||||
}
|
||||
val filternfsw = if (isNsfwEnabled) filteredExtensions else filteredExtensions.filterNot { it.isNsfw }
|
||||
return try {
|
||||
val sublist = filternfsw.subList(
|
||||
fromIndex = position,
|
||||
@@ -194,6 +191,7 @@ 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)
|
||||
|
||||
@@ -87,9 +87,7 @@ class Subscription {
|
||||
progress(index[it.first]!!, parser.name, media.name)
|
||||
val ep: MangaChapter? =
|
||||
SubscriptionHelper.getChapter(context, parser, media.id, media.isAdult)
|
||||
if (ep != null) currActivity()!!.getString(R.string.chapter) + "${ep.number}${
|
||||
if (ep.title != null) " : ${ep.title}" else ""
|
||||
} " + currActivity()!!.getString(R.string.just_released) to null
|
||||
if (ep != null) ep.number + " " + currActivity()!!.getString(R.string.just_released) to null
|
||||
else null
|
||||
} ?: return@map
|
||||
createNotification(context.applicationContext, media, text.first, text.second)
|
||||
|
||||
@@ -42,14 +42,15 @@ class ThemeManager(private val context: Context) {
|
||||
.getString("theme", "PURPLE")!!
|
||||
|
||||
val themeToApply = when (theme) {
|
||||
"PURPLE" -> if (useOLED) R.style.Theme_Dantotsu_PurpleOLED else R.style.Theme_Dantotsu_Purple
|
||||
"BLUE" -> if (useOLED) R.style.Theme_Dantotsu_BlueOLED else R.style.Theme_Dantotsu_Blue
|
||||
"GREEN" -> if (useOLED) R.style.Theme_Dantotsu_GreenOLED else R.style.Theme_Dantotsu_Green
|
||||
"PURPLE" -> if (useOLED) R.style.Theme_Dantotsu_PurpleOLED else R.style.Theme_Dantotsu_Purple
|
||||
"PINK" -> if (useOLED) R.style.Theme_Dantotsu_PinkOLED else R.style.Theme_Dantotsu_Pink
|
||||
"SAIKOU" -> if (useOLED) R.style.Theme_Dantotsu_SaikouOLED else R.style.Theme_Dantotsu_Saikou
|
||||
"RED" -> if (useOLED) R.style.Theme_Dantotsu_RedOLED else R.style.Theme_Dantotsu_Red
|
||||
"LAVENDER" -> if (useOLED) R.style.Theme_Dantotsu_LavenderOLED else R.style.Theme_Dantotsu_Lavender
|
||||
"EMERALD" -> if (useOLED) R.style.Theme_Dantotsu_EmeraldOLED else R.style.Theme_Dantotsu_Emerald
|
||||
"MONOCHROME (BETA)" -> if (useOLED) R.style.Theme_Dantotsu_MonochromeOLED else R.style.Theme_Dantotsu_Monochrome
|
||||
"SAIKOU" -> if (useOLED) R.style.Theme_Dantotsu_SaikouOLED else R.style.Theme_Dantotsu_Saikou
|
||||
else -> if (useOLED) R.style.Theme_Dantotsu_PurpleOLED else R.style.Theme_Dantotsu_Purple
|
||||
}
|
||||
|
||||
@@ -109,14 +110,15 @@ class ThemeManager(private val context: Context) {
|
||||
|
||||
companion object {
|
||||
enum class Theme(val theme: String) {
|
||||
PURPLE("PURPLE"),
|
||||
BLUE("BLUE"),
|
||||
GREEN("GREEN"),
|
||||
PURPLE("PURPLE"),
|
||||
PINK("PINK"),
|
||||
SAIKOU("SAIKOU"),
|
||||
RED("RED"),
|
||||
LAVENDER("LAVENDER"),
|
||||
MONOCHROME("MONOCHROME (BETA)"),
|
||||
SAIKOU("SAIKOU");
|
||||
EMERALD("EMERALD"),
|
||||
MONOCHROME("MONOCHROME (BETA)");
|
||||
|
||||
companion object {
|
||||
fun fromString(value: String): Theme {
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="320dp"
|
||||
android:height="180dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<group android:scaleX="0.6666667"
|
||||
android:scaleY="0.6666667"
|
||||
android:translateX="18"
|
||||
android:translateY="18">
|
||||
<group android:scaleX="0.5625"
|
||||
android:translateX="-5.535">
|
||||
<path
|
||||
android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:fillType="evenOdd">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="49.59793"
|
||||
android:startX="42.9492"
|
||||
android:endY="92.4963"
|
||||
android:endX="85.84757"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0"/>
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:fillColor="#3DDC84"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000"/>
|
||||
</group>
|
||||
|
||||
<group android:scaleX="0.492"
|
||||
android:scaleY="0.24750866"
|
||||
android:translateX="277.2"
|
||||
android:translateY="73.782364">
|
||||
<group android:translateY="145.33594">
|
||||
<path android:pathData="M12.796875,-0L12.796875,-101.109375L34.171875,-101.109375Q42.828125,-101.109375,50.234375,-100.234375Q57.65625,-99.359375,63.84375,-97.171875Q70.03125,-95,74.703125,-91.375Q79.390625,-87.75,82.765625,-82.125Q86.0625,-76.5,87.75,-68.765625Q89.4375,-61.03125,89.4375,-50.5625Q89.4375,-40.078125,87.75,-32.34375Q86.0625,-24.609375,82.765625,-18.984375Q79.390625,-13.359375,74.703125,-9.734375Q70.03125,-6.125,63.84375,-3.9375Q57.65625,-1.765625,50.234375,-0.875Q42.828125,-0,34.171875,-0L12.796875,-0ZM36.359375,-10.828125Q47.109375,-10.828125,54.59375,-12.96875Q62.09375,-15.125,66.875,-19.96875Q71.578125,-24.828125,73.71875,-32.3125Q75.875,-39.796875,75.875,-50.5625Q75.875,-61.3125,73.71875,-68.796875Q71.578125,-76.296875,66.875,-81.140625Q62.09375,-86,54.59375,-88.140625Q47.109375,-90.28125,36.359375,-90.28125L26.015625,-90.28125L26.015625,-10.828125L36.359375,-10.828125Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M113.109375,-60.1875L110.015625,-70.03125Q121.828125,-74.75,134.76562,-74.75Q146.07812,-74.75,152.0625,-70.953125Q158.875,-66.59375,158.875,-56.109375L158.875,-27.359375Q158.875,-21.59375,159.01562,-15.546875Q159.09375,-11.953125,159.71875,-8.09375Q160.28125,-4.4375,161.20312,-1.125L149.67188,1.40625Q148.04688,-3.3125,147.625,-9.140625L146.21875,-9.28125Q137.5,1.6875,124,1.6875Q114.15625,1.6875,108.171875,-3.765625Q102.203125,-9.21875,102.203125,-19.125Q102.203125,-26.515625,105.46875,-31.21875Q108.75,-35.9375,114.71875,-39.171875Q124.140625,-44.296875,141.09375,-44.296875Q143.34375,-44.296875,147.14062,-44.15625L147.14062,-54.84375Q147.14062,-59.90625,144.04688,-62.15625Q140.95312,-64.40625,134.34375,-64.40625Q124.703125,-64.40625,113.109375,-60.1875ZM147.14062,-20.53125L147.14062,-35.296875Q145.23438,-35.4375,141.57812,-35.4375Q135.39062,-35.4375,130.1875,-34.390625Q122.453125,-32.84375,118.203125,-29.5Q113.953125,-26.15625,113.953125,-19.90625Q113.953125,-8.65625,126.1875,-8.65625Q132.51562,-8.65625,138,-12.03125Q142.5,-14.84375,147.14062,-20.53125Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M179.5,-71.859375L191.17188,-74.46875Q192.5,-70.25,193.0625,-66.3125Q193.34375,-64.40625,193.76562,-58.78125L195.25,-58.78125Q199.10938,-65.890625,204.8125,-70.109375Q211.0625,-74.75,218.03125,-74.75Q228.5,-74.75,233.98438,-69.6875Q238.70312,-65.390625,240.53125,-56.53125Q241.71875,-50.484375,241.71875,-38.53125L241.71875,0L229.625,0L229.625,-41.90625Q229.625,-52.390625,227.59375,-56.890625Q224.5625,-63.5625,215.42188,-63.5625Q208.95312,-63.5625,202.76562,-57.375Q198.625,-53.234375,193.90625,-45.21875L193.90625,0L181.8125,0L181.8125,-45Q181.8125,-54.5,181.32812,-61.390625Q181.04688,-65.671875,179.5,-71.859375Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M269.28125,-89.859375L281.375,-89.859375L281.375,-73.125L305.98438,-73.125L305.98438,-62.9375L281.375,-62.9375L281.375,-20.953125Q281.375,-16.734375,281.625,-14.515625Q281.875,-12.3125,282.85938,-11.046875Q284.6875,-8.515625,290.23438,-8.515625Q293.32812,-8.515625,296.21875,-9.140625Q299.17188,-9.78125,301.625,-10.546875Q303.59375,-6.265625,305.21875,-1.125Q296.92188,1.6875,288.48438,1.6875Q282.35938,1.6875,278.67188,0.3125Q274.98438,-1.0625,272.875,-4.15625Q270.6875,-7.390625,269.98438,-11.890625Q269.28125,-16.390625,269.28125,-24.328125L269.28125,-62.9375L258.73438,-62.9375L258.73438,-73.125L269.28125,-73.125L269.28125,-89.859375Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M351.03125,-74.75Q354.46875,-74.75,358.1875,-74.21875Q361.92188,-73.6875,365.51562,-72.21875Q369.09375,-70.671875,372.29688,-68.03125Q375.5,-65.390625,377.95312,-61.171875Q380.42188,-56.890625,381.82812,-50.875Q383.23438,-44.859375,383.23438,-36.5625Q383.23438,-28.265625,381.82812,-22.25Q380.42188,-16.25,377.95312,-12.03125Q375.5,-7.734375,372.29688,-5.0625Q369.09375,-2.390625,365.51562,-0.921875Q361.92188,0.640625,358.1875,1.15625Q354.46875,1.6875,351.03125,1.6875Q347.65625,1.6875,343.95312,1.15625Q340.26562,0.640625,336.6875,-0.921875Q333.09375,-2.390625,329.92188,-5.0625Q326.76562,-7.734375,324.3125,-12.03125Q321.84375,-16.25,320.4375,-22.25Q319.03125,-28.265625,319.03125,-36.5625Q319.03125,-44.859375,320.4375,-50.875Q321.84375,-56.890625,324.3125,-61.171875Q326.76562,-65.390625,329.92188,-68.03125Q333.09375,-70.671875,336.6875,-72.21875Q340.26562,-73.6875,343.92188,-74.21875Q347.57812,-74.75,351.03125,-74.75ZM351.03125,-64.828125Q347.01562,-64.828125,343.46875,-63.5625Q339.92188,-62.296875,337.25,-59.140625Q334.5,-55.90625,332.875,-50.484375Q331.26562,-45.078125,331.26562,-36.5625Q331.26562,-28.125,332.875,-22.671875Q334.5,-17.234375,337.25,-14.0625Q339.92188,-10.828125,343.46875,-9.59375Q347.01562,-8.375,351.03125,-8.375Q355.10938,-8.375,358.71875,-9.59375Q362.34375,-10.828125,365.09375,-14.0625Q367.82812,-17.234375,369.40625,-22.671875Q371,-28.125,371,-36.5625Q371,-45.078125,369.40625,-50.484375Q367.82812,-55.90625,365.09375,-59.140625Q362.34375,-62.296875,358.71875,-63.5625Q355.10938,-64.828125,351.03125,-64.828125Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M408.28125,-89.859375L420.375,-89.859375L420.375,-73.125L444.98438,-73.125L444.98438,-62.9375L420.375,-62.9375L420.375,-20.953125Q420.375,-16.734375,420.625,-14.515625Q420.875,-12.3125,421.85938,-11.046875Q423.6875,-8.515625,429.23438,-8.515625Q432.32812,-8.515625,435.21875,-9.140625Q438.17188,-9.78125,440.625,-10.546875Q442.59375,-6.265625,444.21875,-1.125Q435.92188,1.6875,427.48438,1.6875Q421.35938,1.6875,417.67188,0.3125Q413.98438,-1.0625,411.875,-4.15625Q409.6875,-7.390625,408.98438,-11.890625Q408.28125,-16.390625,408.28125,-24.328125L408.28125,-62.9375L397.73438,-62.9375L397.73438,-73.125L408.28125,-73.125L408.28125,-89.859375Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M484.54688,-74.75Q490.3125,-74.75,496.10938,-73.546875Q501.90625,-72.359375,506.90625,-70.25Q505.92188,-68,504.85938,-65.8125Q503.8125,-63.640625,502.54688,-61.53125Q500.78125,-62.234375,498.64062,-62.9375Q496.5,-63.640625,494.14062,-64.125Q491.78125,-64.625,489.28125,-64.9375Q486.79688,-65.25,484.40625,-65.25Q481.79688,-65.25,479.375,-64.71875Q476.95312,-64.203125,475.07812,-63Q473.21875,-61.8125,472.09375,-59.875Q470.96875,-57.9375,470.96875,-55.0625Q470.96875,-52.109375,472.23438,-50.09375Q473.5,-48.09375,475.67188,-46.75Q477.85938,-45.421875,480.78125,-44.5Q483.70312,-43.59375,487,-42.828125Q492.14062,-41.5625,496.5625,-39.96875Q501,-38.390625,504.23438,-35.859375Q507.46875,-33.328125,509.29688,-29.59375Q511.125,-25.875,511.125,-20.390625Q511.125,-14.625,508.82812,-10.46875Q506.54688,-6.328125,502.64062,-3.625Q498.75,-0.921875,493.54688,0.375Q488.34375,1.6875,482.4375,1.6875Q479.34375,1.6875,476.0625,1.296875Q472.79688,0.921875,469.59375,0.171875Q466.40625,-0.5625,463.3125,-1.609375Q460.21875,-2.671875,457.46875,-3.9375Q458.45312,-6.1875,459.54688,-8.328125Q460.64062,-10.484375,461.82812,-12.59375Q464.15625,-11.609375,466.75,-10.71875Q469.35938,-9.84375,472.09375,-9.203125Q474.84375,-8.578125,477.51562,-8.1875Q480.1875,-7.8125,482.64062,-7.8125Q485.73438,-7.8125,488.65625,-8.515625Q491.57812,-9.21875,493.85938,-10.71875Q496.14062,-12.234375,497.51562,-14.625Q498.89062,-17.015625,498.89062,-20.390625Q498.89062,-23.5625,497.57812,-25.59375Q496.28125,-27.640625,494.09375,-29Q491.92188,-30.375,489,-31.25Q486.09375,-32.140625,482.85938,-32.90625Q477.9375,-34.109375,473.53125,-35.65625Q469.14062,-37.203125,465.875,-39.6875Q462.60938,-42.1875,460.67188,-45.875Q458.73438,-49.578125,458.73438,-55.0625Q458.73438,-60.1875,460.84375,-63.90625Q462.95312,-67.640625,466.5,-70.03125Q470.0625,-72.421875,474.73438,-73.578125Q479.40625,-74.75,484.54688,-74.75Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M590.28125,-1.265625L578.6094,1.34375Q577.28125,-2.890625,576.71875,-6.828125Q576.4375,-8.65625,576.0156,-14.28125L574.53125,-14.28125Q570.6719,-7.171875,564.96875,-2.953125Q558.71875,1.6875,551.75,1.6875Q541.28125,1.6875,535.7969,-3.375Q531.0781,-7.671875,529.25,-16.53125Q528.0625,-22.578125,528.0625,-34.53125L528.0625,-73.125L540.15625,-73.125L540.15625,-31.15625Q540.15625,-20.671875,542.1875,-16.171875Q545.21875,-9.5,554.3594,-9.5Q560.8281,-9.5,567.0156,-15.6875Q571.15625,-19.828125,575.875,-27.84375L575.875,-73.125L587.96875,-73.125L587.96875,-27.984375Q587.96875,-18.640625,588.4531,-11.75Q588.7344,-7.453125,590.28125,-1.265625Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M644.78125,0L644.78125,-95.984375L683.03125,-95.984375L683.03125,0L644.78125,0ZM649.5625,-4.78125L678.25,-4.78125L678.25,-91.203125L649.5625,-91.203125L649.5625,-4.78125Z"
|
||||
android:fillColor="#000000"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="?attr/colorOnPrimaryContainer"/>
|
||||
<solid android:color="@color/grey_nav"/>
|
||||
<corners android:radius="40dp"/>
|
||||
</shape>
|
||||
4
app/src/main/res/drawable/ic_round_filter_24.xml
Normal file
4
app/src/main/res/drawable/ic_round_filter_24.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<vector android:height="24dp" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#000000" android:fillType="evenOdd" android:pathData="M3,7C3,6.448 3.448,6 4,6H20C20.552,6 21,6.448 21,7C21,7.552 20.552,8 20,8H4C3.448,8 3,7.552 3,7ZM6,12C6,11.448 6.448,11 7,11H17C17.552,11 18,11.448 18,12C18,12.552 17.552,13 17,13H7C6.448,13 6,12.552 6,12ZM9,17C9,16.448 9.448,16 10,16H14C14.552,16 15,16.448 15,17C15,17.552 14.552,18 14,18H10C9.448,18 9,17.552 9,17Z"/>
|
||||
</vector>
|
||||
@@ -1,16 +1,16 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="480"
|
||||
android:viewportHeight="480"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="700"
|
||||
android:viewportHeight="768"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<clip-path
|
||||
android:fillColor="#e9e6f4"
|
||||
android:pathData="M125.71,125.71h516.58v516.58h-516.58z"/>
|
||||
<path
|
||||
android:fillColor="#e9e6f4"
|
||||
android:pathData="M298.5,303.98c0,10.32 -6.43,17.41 -7.83,18.82l-140,140C62.36,427.38 0,340.98 0,240c0,-132.55 107.45,-240 240,-240L240.5,0L136.18,104.28c-8.92,8.95 -29.67,33.86 -29.68,71.71 0,10.22 2.27,45.73 31.56,73.57a101,101 0,0 0,45.95 24.93v9.4a27.92,27.92 0,0 0,42 24.23l51.64,-29.81a27.23,27.23 0,0 1,14.21 8.11A27.72,27.72 0,0 1,298.5 303.98Z" />
|
||||
android:pathData="M44.26,128C44.26,173.48 80.53,210.4 125.71,211.63L125.71,128.01L642.29,128.01L642.29,639.97L768,639.97L768,128L44.26,128zM642.29,639.97L125.71,639.97L125.71,639.99L642.29,639.99L642.29,639.97zM125.71,639.97L125.71,556.38C80.54,557.6 44.28,594.5 44.26,639.97L125.71,639.97zM125.71,556.38C126.48,556.35 127.23,556.26 128,556.26L384,556.26C479.14,556.26 556.26,479.13 556.26,384C556.26,288.86 479.13,211.74 384,211.74L128,211.74C127.23,211.74 126.48,211.65 125.71,211.63L125.71,286.18L384,286.18C438.02,286.18 481.82,329.98 481.82,384C481.82,438.03 438.02,481.82 384,481.82L125.71,481.82L125.71,556.38zM125.71,481.82L125.71,286.18L0,286.18L0,481.82L125.71,481.82z"/>
|
||||
<path
|
||||
android:fillColor="#e9e6f4"
|
||||
android:pathData="M329.34,17.18 L189.26,157.26A27.91,27.91 0,0 0,181.5 176.01a29,29 0,0 0,3.43 12.88,28 28,0 0,1 41,-17l53.73,31c15.36,1.41 44.91,7.64 68.06,33.57S373.5,292.38 373.5,304.02c0,37.74 -20.73,62.68 -29.63,71.65l-0.1,0.1L239.55,480h0.45c132.55,0 240,-107.45 240,-240C480,139.02 417.64,52.62 329.34,17.18Z" />
|
||||
<path
|
||||
android:fillColor="#e9e6f4"
|
||||
android:pathData="M299.99,240a11.85,11.85 0,0 1,-6 10.37l-47,27.13 -29,16.76a12,12 0,0 1,-18 -10.37L199.99,196.11a11.95,11.95 0,0 1,18 -10.37l29,16.76 47,27.13A11.85,11.85 0,0 1,299.99 240Z" />
|
||||
android:pathData="m442,366.7l-76.02,-43.89c-13.32,-7.69 -29.96,1.92 -29.96,17.3v87.78c0,15.38 16.65,24.99 29.96,17.3l76.02,-43.89c13.32,-7.69 13.32,-26.91 0,-34.6Z"/>
|
||||
</vector>
|
||||
|
||||
@@ -81,23 +81,6 @@
|
||||
app:tabPaddingStart="16dp"
|
||||
app:tabTextAppearance="@style/NavBarText"
|
||||
app:tabGravity="fill">
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/installed_anime"/>
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/available_anime"/>
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/installed_manga"/>
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Available Manga"
|
||||
tools:ignore="HardcodedText" />
|
||||
</com.google.android.material.tabs.TabLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="32dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -242,7 +242,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="0dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_gravity="center_horizontal|bottom"
|
||||
android:background="?attr/colorSurface"
|
||||
android:translationZ="1dp"
|
||||
app:itemActiveIndicatorStyle="@style/BottomNavBar"
|
||||
|
||||
@@ -1210,7 +1210,7 @@
|
||||
android:fontFamily="@font/poppins_family"
|
||||
android:paddingStart="32dp"
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/show_cast_button_info"
|
||||
android:text=""
|
||||
android:textSize="14sp" />
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -121,28 +121,6 @@
|
||||
|
||||
</com.google.android.material.materialswitch.MaterialSwitch>
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/uiSettingsImmersiveList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:checked="true"
|
||||
android:drawableStart="@drawable/ic_round_fullscreen_24"
|
||||
android:drawablePadding="16dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
android:elegantTextHeight="true"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:minHeight="64dp"
|
||||
android:paddingStart="32dp"
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/immersive_modelist"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:showText="false"
|
||||
app:thumbTint="@color/button_switch_track">
|
||||
|
||||
</com.google.android.material.switchmaterial.SwitchMaterial>
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
@@ -286,4 +264,4 @@
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
@@ -512,6 +512,25 @@
|
||||
app:thumbTint="@color/button_switch_track"
|
||||
tools:ignore="VisualLintButtonSize" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/useOledTheme"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="false"
|
||||
android:drawableStart="@drawable/ic_round_brightness_4_24"
|
||||
android:drawablePadding="16dp"
|
||||
android:elegantTextHeight="true"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:minHeight="64dp"
|
||||
android:text="Use OLED Theme"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
app:thumbTint="@color/button_switch_track"
|
||||
tools:ignore="VisualLintButtonSize" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/keepScreenOn"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
225
app/src/main/res/layout/dialog_layout.xml
Normal file
225
app/src/main/res/layout/dialog_layout.xml
Normal file
@@ -0,0 +1,225 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="170dp"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.58"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:text="@string/layout" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/layoutText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:textColor="?attr/colorSecondary"
|
||||
tools:ignore="TextContrastCheck"
|
||||
tools:text="Continuous" />
|
||||
</LinearLayout>
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/nav_bg_inv"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/animeSourceList"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
app:srcCompat="@drawable/ic_round_view_list_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/nav_bg_inv"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/animeSourceGrid"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
app:srcCompat="@drawable/ic_round_grid_view_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/nav_bg_inv"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/animeSourceCompact"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
app:srcCompat="@drawable/ic_round_view_comfy_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="265dp"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="152dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.58"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:text="Sort" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sortText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:textColor="?attr/colorSecondary"
|
||||
tools:ignore="TextContrastCheck"
|
||||
tools:text="Up to Down" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/nav_bg_inv"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/animeSourceTop"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:rotation="90"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
app:srcCompat="@drawable/ic_round_arrow_back_ios_new_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:id="@+id/animeDownloadContainer"
|
||||
android:orientation="horizontal">
|
||||
<LinearLayout
|
||||
android:layout_width="265dp"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:alpha="0.58"
|
||||
android:text="Download" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/downloadNo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:textColor="?attr/colorSecondary"
|
||||
tools:ignore="TextContrastCheck"
|
||||
tools:text="number" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/nav_bg_inv"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/animeDownloadTop"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
app:srcCompat="@drawable/ic_round_download_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:id="@+id/animeScanlatorContainer">
|
||||
<TextView
|
||||
android:layout_width="265dp"
|
||||
android:layout_height="match_parent"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:alpha="0.58"
|
||||
android:text="Scanlator"
|
||||
android:gravity="center_vertical"/>
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/nav_bg_inv"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp">
|
||||
<ImageButton
|
||||
android:id="@+id/animeScanlatorTop"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
app:srcCompat="@drawable/ic_round_edit_note_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
@@ -174,12 +174,11 @@
|
||||
app:srcCompat="@drawable/ic_round_screen_rotation_alt_24"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck" />
|
||||
|
||||
<ImageButton
|
||||
<androidx.mediarouter.app.MediaRouteButton
|
||||
android:id="@+id/exo_cast"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:backgroundTint="#00FFFFFF"
|
||||
android:src="@drawable/ic_round_cast_24"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
@@ -17,26 +17,17 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<LinearLayout
|
||||
android:id="@+id/incognitoView"
|
||||
<TextView
|
||||
android:id="@+id/incognitoTextView"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="30dp"
|
||||
android:orientation="horizontal"
|
||||
android:text="Incognito Mode"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:textSize="15sp"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:padding="8dp"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/incognitoTextView"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="Incognito Mode"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:textSize="11sp"
|
||||
android:textColor="#4f2dbd"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:background="#00FFFFFF"
|
||||
android:padding="8dp"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
android:hint="@string/manga"
|
||||
android:textColorHint="@color/bg_opp"
|
||||
android:transitionName="@string/search"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
app:boxBackgroundColor="?attr/colorPrimaryContainer"
|
||||
app:boxCornerRadiusBottomEnd="28dp"
|
||||
app:boxCornerRadiusBottomStart="28dp"
|
||||
@@ -80,7 +81,43 @@
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sourceTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:gravity="center"
|
||||
android:text="Downloaded Manga and Novels"
|
||||
android:textSize="14sp"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/downloadedList"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.33"
|
||||
android:padding="8dp"
|
||||
app:srcCompat="@drawable/ic_round_view_list_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/downloadedGrid"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.33"
|
||||
android:padding="8dp"
|
||||
app:srcCompat="@drawable/ic_round_grid_view_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
|
||||
</LinearLayout>
|
||||
<!-- This TextView might overlap with GridView if GridView has items -->
|
||||
<TextView
|
||||
android:id="@+id/noMangaOffline"
|
||||
@@ -91,18 +128,35 @@
|
||||
android:textColor="?attr/colorOnSurface"
|
||||
android:textSize="18sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- for large view -->
|
||||
<GridView
|
||||
android:id="@+id/gridView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:numColumns="auto_fit"
|
||||
android:columnWidth="128dp"
|
||||
android:verticalSpacing="10dp"
|
||||
android:numColumns="1"
|
||||
android:verticalSpacing="20dp"
|
||||
android:horizontalSpacing="10dp"
|
||||
android:padding="10dp"
|
||||
android:gravity="center" />
|
||||
android:paddingStart="25dp"
|
||||
android:paddingEnd="25dp"
|
||||
android:gravity="center"
|
||||
android:scrollbars="none"
|
||||
android:visibility="gone"/>
|
||||
<!-- for compact view -->
|
||||
<GridView
|
||||
android:id="@+id/gridView1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:columnWidth="138dp"
|
||||
android:gravity="center"
|
||||
android:horizontalSpacing="-30dp"
|
||||
android:numColumns="auto_fit"
|
||||
android:paddingStart="-10dp"
|
||||
android:paddingEnd="-10dp"
|
||||
android:scrollbars="none"
|
||||
android:verticalSpacing="20dp"
|
||||
android:visibility="gone"/>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
@@ -8,13 +8,6 @@
|
||||
android:layout_marginStart="-16dp"
|
||||
android:layout_marginEnd="-16dp"
|
||||
android:orientation="vertical">
|
||||
<LinearLayout
|
||||
android:id="@+id/incognitoView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="30dp"
|
||||
android:orientation="horizontal"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/incognitoTextView"
|
||||
@@ -22,8 +15,8 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:text="Incognito Mode"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:textSize="11sp"
|
||||
android:textColor="#4f2dbd"
|
||||
android:textSize="15sp"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:background="#00FFFFFF"
|
||||
android:padding="8dp"
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:backgroundTint="@color/yt_red"
|
||||
android:visibility="gone"
|
||||
android:insetTop="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:text="@string/play_yt"
|
||||
@@ -89,12 +90,12 @@
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/animeSourceSubscribe"
|
||||
android:id="@+id/animeSourceSettings"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:srcCompat="@drawable/ic_round_notifications_none_24"
|
||||
app:srcCompat="@drawable/ic_round_settings_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
</LinearLayout>
|
||||
@@ -106,7 +107,8 @@
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
||||
android:layout_width="0dp"
|
||||
|
||||
android:id="@+id/animeSourceLanguageContainer"
|
||||
android:visibility="gone"
|
||||
android:layout_height="56dp"
|
||||
android:layout_weight="1"
|
||||
android:hint="Language"
|
||||
@@ -134,15 +136,6 @@
|
||||
tools:ignore="LabelFor,TextContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/animeSourceSettings"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:srcCompat="@drawable/ic_round_settings_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -185,19 +178,26 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/animeSourceSearch"
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:padding="12dp"
|
||||
android:text="@string/wrong"
|
||||
android:textAlignment="textEnd"
|
||||
android:textColor="?attr/colorSecondary"
|
||||
tools:ignore="TextContrastCheck" />
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
|
||||
android:id="@+id/animeSourceSearch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:padding="12dp"
|
||||
android:text="@string/wrong"
|
||||
android:textAlignment="textEnd"
|
||||
android:textColor="?attr/colorSecondary"
|
||||
tools:ignore="TextContrastCheck" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
@@ -214,65 +214,25 @@
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:text="@string/eps"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/animeSourceList"
|
||||
android:id="@+id/animeSourceSubscribe"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.33"
|
||||
android:padding="8dp"
|
||||
app:srcCompat="@drawable/ic_round_view_list_24"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:srcCompat="@drawable/ic_round_notifications_none_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/animeSourceGrid"
|
||||
android:id="@+id/animeNestedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.33"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:padding="8dp"
|
||||
app:srcCompat="@drawable/ic_round_grid_view_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/animeSourceCompact"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.33"
|
||||
android:padding="8dp"
|
||||
app:srcCompat="@drawable/ic_round_view_comfy_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/animeDownloadTop"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="1"
|
||||
android:padding="8dp"
|
||||
app:srcCompat="@drawable/ic_round_download_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/animeScanlatorTop"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="1"
|
||||
android:padding="8dp"
|
||||
app:srcCompat="@drawable/ic_round_edit_note_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/animeSourceTop"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="1"
|
||||
android:padding="8dp"
|
||||
android:rotation="90"
|
||||
app:srcCompat="@drawable/ic_round_arrow_back_ios_new_24"
|
||||
app:srcCompat="@drawable/ic_round_filter_24"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
</LinearLayout>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
app:gest_disableGestures="true"
|
||||
app:gest_rotationEnabled="true"
|
||||
app:gest_restrictRotation="true"
|
||||
app:gest_doubleTapZoom="3"
|
||||
app:gest_doubleTapZoom="1.5"
|
||||
app:gest_maxZoom="6">
|
||||
|
||||
<FrameLayout
|
||||
|
||||
@@ -8,13 +8,6 @@
|
||||
android:layout_marginStart="-16dp"
|
||||
android:layout_marginEnd="-16dp"
|
||||
android:orientation="vertical">
|
||||
<LinearLayout
|
||||
android:id="@+id/incognitoView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="30dp"
|
||||
android:orientation="horizontal"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/incognitoTextView"
|
||||
@@ -22,8 +15,8 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:text="Incognito Mode"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:textSize="11sp"
|
||||
android:textColor="#4f2dbd"
|
||||
android:textSize="15sp"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:background="#00FFFFFF"
|
||||
android:padding="8dp"
|
||||
|
||||
@@ -150,7 +150,43 @@
|
||||
android:text="@string/eps" />
|
||||
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/itemCompactType"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone"
|
||||
tools:ignore="UseCompoundDrawables">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/itemCompactTypeImage"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:alpha="0.58"
|
||||
app:srcCompat="@drawable/ic_round_import_contacts_24"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/itemCompactRelation"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.58"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:singleLine="true"
|
||||
android:textAlignment="textEnd"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="italic"
|
||||
android:transitionName="mediaTitle"
|
||||
tools:ignore="TextContrastCheck"
|
||||
tools:text="Relation " />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -15,9 +15,8 @@
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:background="@drawable/bottom_nav"
|
||||
android:elevation="4dp"
|
||||
android:padding="8dp"
|
||||
android:translationZ="12dp"
|
||||
android:elevation="8dp"
|
||||
android:padding="6dp"
|
||||
android:visibility="gone"
|
||||
app:abb_animationDuration="300"
|
||||
app:abb_animationInterpolator="@anim/over_shoot"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_banner_background"/>
|
||||
<foreground android:drawable="@drawable/ic_banner_foreground"/>
|
||||
<foreground android:drawable="@mipmap/ic_banner_foreground"/>
|
||||
</adaptive-icon>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 21 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_banner_foreground.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/ic_banner_foreground.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
@@ -1,647 +0,0 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:locale="en-rUS">
|
||||
|
||||
<string name="repo">rebelonion/Dantotsu</string>
|
||||
<string name="preference_file_key" translatable="false">dantotsuprefs</string>
|
||||
|
||||
<string name="app_name">Dantotsu</string>
|
||||
<string name="slogan">The NEW Best Anime & Manga app for Android.</string>
|
||||
|
||||
<string name="login">Login</string>
|
||||
<string name="logout">Logout</string>
|
||||
|
||||
<string name="discord">https://discord.gg/4HPZ5nAWwM</string>
|
||||
<string name="github">https://github.com/rebelonion/Dantotsu</string>
|
||||
|
||||
<string name="home">Home</string>
|
||||
<string name="anime">Anime</string>
|
||||
<string name="browse_anime">Browse Anime</string>
|
||||
<string name="manga">Manga</string>
|
||||
<string name="browse_manga">Browse Manga</string>
|
||||
<string name="info">Info</string>
|
||||
<string name="watch">Watch</string>
|
||||
<string name="read">Read</string>
|
||||
|
||||
<string name="anime_list">Anime List</string>
|
||||
<string name="manga_list">Manga List</string>
|
||||
|
||||
<string name="sad">X(</string>
|
||||
<string name="oh">:o</string>
|
||||
<string name="colon">" : "</string>
|
||||
|
||||
<string name="no_internet">No Internet Connection</string>
|
||||
<string name="refresh">Refresh</string>
|
||||
|
||||
<string name="search">Search</string>
|
||||
<string name="search_results">Search Results</string>
|
||||
<string name="sort_by">Sort By</string>
|
||||
<string name="genre">Genre</string>
|
||||
<string name="top_score">Top Score</string>
|
||||
<string name="updated">Recently Updated</string>
|
||||
<string name="trending_anime">Trending Anime</string>
|
||||
<string name="popular_anime">Popular Anime</string>
|
||||
<string name="trending_manga">Trending Manga</string>
|
||||
<string name="trending_novel">Trending Novel</string>
|
||||
<string name="popular_manga">Popular Manga</string>
|
||||
|
||||
<string name="username">Username</string>
|
||||
<string name="chapters_read">"Chapters Read "</string>
|
||||
<string name="episodes_watched">"Episodes Watched "</string>
|
||||
<string name="continue_reading">Continue Reading</string>
|
||||
<string name="continue_watching">Continue Watching</string>
|
||||
<string name="recommended">Recommended</string>
|
||||
|
||||
<string name="get_recommendations">Watch/Read some Anime or Manga to get Recommendations</string>
|
||||
<string name="empty">All caught up, when New?</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
|
||||
<string name="add">Add to List</string>
|
||||
<string name="list_editor">List Editor</string>
|
||||
<string name="add_fav">Add to Favourites</string>
|
||||
<string name="notifications">Notifications</string>
|
||||
<string-array name="keys">
|
||||
<item>Reading</item>
|
||||
<item>Watching</item>
|
||||
<item>Completed</item>
|
||||
<item>Paused</item>
|
||||
<item>Dropped</item>
|
||||
<item>Planning</item>
|
||||
<item>Favourites</item>
|
||||
<item>Rewatching</item>
|
||||
<item>Rereading</item>
|
||||
<item>All</item>
|
||||
</string-array>
|
||||
|
||||
<string name="status">STATUS</string>
|
||||
<string-array name="status" translatable="false">
|
||||
<item>PLANNING</item>
|
||||
<item>CURRENT</item>
|
||||
<item>COMPLETED</item>
|
||||
<item>REPEATING</item>
|
||||
<item>PAUSED</item>
|
||||
<item>DROPPED</item>
|
||||
</string-array>
|
||||
<string-array name="status_anime">
|
||||
<item>PLANNING</item>
|
||||
<item>WATCHING</item>
|
||||
<item>COMPLETED</item>
|
||||
<item>RE-WATCHING</item>
|
||||
<item>PAUSED</item>
|
||||
<item>DROPPED</item>
|
||||
</string-array>
|
||||
<string-array name="status_manga">
|
||||
<item>PLANNING</item>
|
||||
<item>READING</item>
|
||||
<item>COMPLETED</item>
|
||||
<item>RE-READING</item>
|
||||
<item>PAUSED</item>
|
||||
<item>DROPPED</item>
|
||||
</string-array>
|
||||
<string name="progress">PROGRESS</string>
|
||||
<string name="score">SCORE</string>
|
||||
<string name="score_suffix">" / 10"</string>
|
||||
<string name="started_at">STARTED AT</string>
|
||||
<string name="completed_at">COMPLETED AT</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="remove">Remove</string>
|
||||
|
||||
<string name="name">Name</string>
|
||||
<string name="name_romaji">Name Romaji</string>
|
||||
<string name="mean_score">Mean Score</string>
|
||||
<string name="format">Format</string>
|
||||
<string name="status_title">Status</string>
|
||||
<string name="total_eps">Total Episodes</string>
|
||||
<string name="total_chaps">Total Chapters</string>
|
||||
<string name="ep_duration">Average Duration</string>
|
||||
<string name="min">" min"</string>
|
||||
<string name="season">Season</string>
|
||||
<string name="start_date">Start Date</string>
|
||||
<string name="end_date">End Date</string>
|
||||
<string name="source">Source</string>
|
||||
<string name="main_studio">Studio</string>
|
||||
<string name="genres">Genres</string>
|
||||
<string name="description">Synopsis</string>
|
||||
<string name="characters">Characters</string>
|
||||
<string name="relations">Relations</string>
|
||||
|
||||
<string name="roles">Roles</string>
|
||||
<string name="details">Details</string>
|
||||
|
||||
<string name="play_yt">Play on Youtube</string>
|
||||
<string name="eps">Episodes</string>
|
||||
<string name="ep">Episode</string>
|
||||
<string name="chaps">Chapters</string>
|
||||
<string name="chap">Chapter</string>
|
||||
<string name="wrong"><u>Wrong Title?</u></string>
|
||||
<string name="source_not_found">
|
||||
Couldn\'t find anything X( \n
|
||||
Try another source.
|
||||
</string>
|
||||
<string name="not_supported">%1$s is not supported!</string>
|
||||
<string name="server_selector">Select Server</string>
|
||||
<string name="auto_select_server">Auto Selecting Server</string>
|
||||
<string name="make_default">Make Default</string>
|
||||
<string name="filler">Filler</string>
|
||||
<string name="adult">Adult</string>
|
||||
<string name="list_only">List Only</string>
|
||||
<string name="tag">Tag</string>
|
||||
<string name="tags">Tags</string>
|
||||
<string name="synonyms">Synonyms</string>
|
||||
<string name="trailer">Trailer</string>
|
||||
<string name="opening">Opening</string>
|
||||
<string name="ending">Ending</string>
|
||||
<string name="prequel">Prequel</string>
|
||||
<string name="sequel">Sequel</string>
|
||||
|
||||
<string name="anilist_settings">Anilist Settings</string>
|
||||
<string name="extension_settings">Extensions</string>
|
||||
<string name="downloads">Downloads</string>
|
||||
<string name="settings">Settings</string>
|
||||
<string name="extensions">Extensions</string>
|
||||
<string name="player_settings">Player Settings</string>
|
||||
<string name="recentlyListOnly">Only show My Shows in Recently Updated</string>
|
||||
<string name="download_manager_select">Download Manager</string>
|
||||
<string name="downloadInSd">Download in SD card</string>
|
||||
<string name="noSdFound">No SD card was Found.</string>
|
||||
<string name="reader_settings">Reader Settings</string>
|
||||
<string name="default_source">Default Source</string>
|
||||
<string name="show_yt">Show Youtube Link</string>
|
||||
<string name="default_ep_view">Default Episode Layout</string>
|
||||
<string name="default_chp_view">Default Chapter Layout</string>
|
||||
<string name="ui">User Interface</string>
|
||||
<string name="common">Common</string>
|
||||
<string name="theme">Theme</string>
|
||||
<string name="ui_settings">UI Settings</string>
|
||||
<string name="about">About</string>
|
||||
<string name="desc">" Dantotsu is crafted from the ashes of Saikou and based on simplistic yet state-of-the-art elegance. It is an Anilist only client, which also lets you stream-download Anime through extensions & Manga.\nDantotsu literally means the \"best of the best\" in japanese. Well, we would like to say this is the best open source app for anime and manga on Android, what would you say?"</string>
|
||||
<string name="devs">Developers</string>
|
||||
<string name="disclaimer">Disclaimer</string>
|
||||
<string name="full_disclaimer">
|
||||
- Dantotsu by itself only provides an anime and manga tracker and does not provide any anime or manga streaming or downloading capabilities.
|
||||
\n\n - Dantotsu or any of its developer/staff don\'t host any of the content found inside Dantotsu. Any and all images and anime/manga information found in the app are taken from various public APIs (AniList, MyAnimeList, Kitsu).
|
||||
\n\n - Furthermore, all of the anime/manga links found in Dantotsu are taken from various 3rd party plugins and have no affiliation with Dantotsu or its staff.
|
||||
\n\n - Dantotsu or it\'s owners aren\'t liable for any misuse of any of the contents found inside or outside of the app and cannot be held accountable for the distribution of any of the contents found inside the app.
|
||||
\n\n - By using Dantotsu, you comply to the fact that the developer of the app is not responsible for any of the contents found in the app. You also agree to the fact that you may not use Dantotsu to download or stream any copyrighted content.
|
||||
\n\n - If the internet infringement issues are involved, please contact the source website. The developer does not assume any legal responsibility.
|
||||
</string>
|
||||
<string name="version_current">Version %1$s</string>
|
||||
<string-array name="tips">
|
||||
<item>You can Long Click an episode/chapter to Mark it as Read.</item>
|
||||
<item>Long Clicking Shows can directly open List Editor.</item>
|
||||
<item>There are few more easter eggs hidden in the App.</item>
|
||||
<item>Challenge: Go to the very bottom of the Popular Anime & Manga</item>
|
||||
<item>Try Long Clicking the Show\'s Title.</item>
|
||||
<item>Damn, why are you wasting your Time?</item>
|
||||
<item>You can Long Click to copy this Message.</item>
|
||||
<item>OMG LOOK! YOU FOUND AN EASTER EGG!?</item>
|
||||
<item>You know who else likes this Animation?</item>
|
||||
<item>MAL support? bruh.</item>
|
||||
<item>Novels? more like NO vels.</item>
|
||||
<item>Long Click the logo to check for App Update</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="themes">
|
||||
<item>Default</item>
|
||||
<item>Theme 1</item>
|
||||
<item>Theme 2</item>
|
||||
<item>Theme 3</item>
|
||||
<item> Theme 4</item>
|
||||
</string-array>
|
||||
|
||||
<string name="video">Video</string>
|
||||
<string name="video_info">Show Video Info</string>
|
||||
<string name="source_info">Show Source Name</string>
|
||||
<string name="video_info_info">Shows what the Resolution of the current video playing, useful for <b>\"Multi Quality\"</b> servers.</string>
|
||||
<string name="default_quality">Auto Quality Selection</string>
|
||||
<string name="height">Height</string>
|
||||
<string name="width">Width</string>
|
||||
<string name="default_quality_info">Automatically uses the closest quality provided by default, ONLY applied for \"Multi Quality\" Servers. Auto changes upon playing a video.</string>
|
||||
<string name="default_playback_speed">Default Playback Speed : %1$s</string>
|
||||
<string name="cursed_speeds">Cursed Speeds</string>
|
||||
<string name="resize_mode_button">Default Resize Mode</string>
|
||||
<string name="subtitles">Subtitles</string>
|
||||
<string name="subtitle_toggle">Subtitles</string>
|
||||
<string name="primary_sub_color_select">Subtitle Color</string>
|
||||
<string name="secondary_sub_color_select">Subtitle Outline Color</string>
|
||||
<string name="secondary_sub_outline_type_select">Subtitle Outline Type</string>
|
||||
<string name="sub_background_color_select">Subtitle Background Color</string>
|
||||
<string name="sub_window_color_select">Subtitle Window Color</string>
|
||||
<string name="sub_window_color_info">"The subtitle window is the part left and right from them. (where the background isn\'t)"</string>
|
||||
<string name="sub_color_info"><b>Note:</b> Changing Subtitle formatting only works with Soft-Subbed Sources such as Zoro!</string>
|
||||
<string name="sub_font_select">Subtitle Font</string>
|
||||
<string name="subtitle_font_size">Subtitle Size</string>
|
||||
|
||||
<string name="auto">Auto</string>
|
||||
<string name="auto_play_next_episode">Autoplay Next Episode</string>
|
||||
<string name="auto_play_next_episode_info">Automatically disables if there is no interaction with player after 1 hour.</string>
|
||||
<string name="auto_skip_fillers">Auto Skip Fillers</string>
|
||||
<string name="auto_skip_fillers_info">Skips filler episodes when going to next episode.</string>
|
||||
|
||||
<string name="update_progress">Update Progress</string>
|
||||
<string name="ask_update_progress_anime">Ask for each Anime \"Individually\"</string>
|
||||
<string name="ask_update_progress_manga">Ask for each Manga \"Individually\"</string>
|
||||
<string name="ask_update_progress_info_ep">Turning off will always automatically update progress when the episode is watched.</string>
|
||||
<string name="ask_update_progress_info_chap">Turning off will always automatically update progress when the chapter is read.</string>
|
||||
<string name="ask_update_progress_hentai">Update Progress for Hentai</string>
|
||||
<string name="ask_update_progress_doujin">Update Progress for Doujins</string>
|
||||
<string name="very_bold">very bold of you sar</string>
|
||||
<string name="watch_complete_percentage">Watch Update Percentage</string>
|
||||
<string name="watch_complete_percentage_info">The percentage at which your Anilist progress should be updated after watching an episode. \nThis also sets the \% for when to preload links for the next episode.</string>
|
||||
|
||||
<string name="behaviour">Behaviour</string>
|
||||
<string name="always_continue">Always Continue from where you left off</string>
|
||||
<string name="pause_video_focus">Pause when not in Focus</string>
|
||||
<string name="gestures">Volume & Brightness Gestures</string>
|
||||
<string name="double_tap">Double tap to Seek</string>
|
||||
<string name="fast_forward">Fast Forward</string>
|
||||
<string name="double_tap_info">Turning off will show fast forward & rewind buttons</string>
|
||||
<string name="seek_time">Seek Time</string>
|
||||
<string name="seek_time_info">Amount of time in seconds for fast forward & rewind.</string>
|
||||
<string name="skip_time">Skip Time</string>
|
||||
<string name="skip_time_info">Setting to 0, hides the Skip Button.</string>
|
||||
<string name="show_cast_button">Show Cast Button</string>
|
||||
<string name="show_cast_button_info">Requires \"Web Video Caster\" app to cast.</string>
|
||||
<string name="picture_in_picture">Picture in Picture</string>
|
||||
<string name="always_minimize">Always Minimize</string>
|
||||
<string name="always_minimize_info">Requires PiP to be enabled, makes the player behave like Youtube Player but better.\nAlso hides the PiP button.</string>
|
||||
|
||||
<string name="app">App</string>
|
||||
<string name="immersive_mode">Hide Status Bar</string>
|
||||
<string name="immersive_mode_info">Requires App restart to fully apply.</string>
|
||||
<string name="home_layout_show">Show/Hide Layouts on Home</string>
|
||||
<string-array name="home_layouts">
|
||||
<item>Continue Watching</item>
|
||||
<item>Favourite Anime</item>
|
||||
<item>Planned Anime</item>
|
||||
<item>Continue Reading</item>
|
||||
<item>Favourite Manga</item>
|
||||
<item>Planned Manga</item>
|
||||
<item>Recommended</item>
|
||||
</string-array>
|
||||
|
||||
<string name="startUpTab">Default Start Up Tab</string>
|
||||
<string name="small_view">Small View in Trending Shows</string>
|
||||
<string name="animations">Animations</string>
|
||||
<string name="banner_animations">Banner Animations</string>
|
||||
<string name="layout_animations">Layout Animations</string>
|
||||
<string name="animation_speed">Overall Speed</string>
|
||||
<string name="empty_fav">Looks like you don\'t like anything,\nTry liking a show to keep it here.</string>
|
||||
<string name="fav_anime">Favourite Anime</string>
|
||||
<string name="fav_manga">Favourite Manga</string>
|
||||
<string name="restart_app">Restart the app?</string>
|
||||
<string name="next">Next</string>
|
||||
<string name="previous">Previous</string>
|
||||
<string name="current_page">Current Page</string>
|
||||
<string name="dubbed">Dubbed</string>
|
||||
<string name="subbed">Subbed</string>
|
||||
<string name="prefer_dub">Prefer Dubbed Anime</string>
|
||||
<string name="none">None</string>
|
||||
<string name="selected_dns">Selected DNS</string>
|
||||
<string name="dns_info">Change if your ISP blocks any source</string>
|
||||
<string name="keep_screen_on">Keep Screen On</string>
|
||||
<string name="layout">Layout</string>
|
||||
<string name="spaced_pages">Spaced Pages</string>
|
||||
<string name="direction">Direction</string>
|
||||
|
||||
<string name="general">General</string>
|
||||
<string name="show_system_bars">Show Status & Navigation Bars</string>
|
||||
<string name="auto_detect_webtoon">Auto Detect Webtoon</string>
|
||||
<string name="auto_detect_webtoon_info">If the Manga is not from Japan, the reader will default to Webtoon Reader Settings</string>
|
||||
<string name="default_settings">Default Settings</string>
|
||||
<string name="horizontal_scroll_bar">Horizontal Scroll Bar</string>
|
||||
<string name="dual_page">Dual Page</string>
|
||||
<string name="dual_page_info">Shows 2 Images in 1 page, will look weird if the images aren\'t the same size</string>
|
||||
<string name="true_colors">True Colors</string>
|
||||
<string name="true_colors_info">(32-bit color Mode) Reduces Banding on the images, may affect performance.</string>
|
||||
<string name="image_rotation">Image Rotation</string>
|
||||
<string name="hide_page_numbers">Hide Page Numbers</string>
|
||||
<string name="sort_by_title">Sort by Title</string>
|
||||
<string name="sort_by_last_updated">Sort by Last Updated</string>
|
||||
<string name="sort_by_score">Sort by Score</string>
|
||||
<string name="over_scroll">Over Scroll to Next/Previous Chapter</string>
|
||||
<string name="volume_buttons">Change pages with Volume Buttons</string>
|
||||
<string name="list_private">Private</string>
|
||||
<string name="wrap_images">Wrap Images</string>
|
||||
<string name="wrap_images_info">Mostly useful for larger devices, removes space between images, if they exist.</string>
|
||||
<string name="reload">Reload</string>
|
||||
<string name="share">Share</string>
|
||||
<string name="skip">Skip</string>
|
||||
<string name="show_skip_time_stamp_button">Show Skip Time Stamp Button</string>
|
||||
<string name="always_load_time_stamps">Always Load Time Stamps</string>
|
||||
<string name="timestamps">Time Stamps</string>
|
||||
<string name="other">Other</string>
|
||||
<string name="auto_skip_op_ed">Auto Skip OP / ED</string>
|
||||
<string name="requires_time_stamps_to_be_enabled">Requires Time Stamps to be Enabled</string>
|
||||
<string name="total_repeats">TOTAL REPEATS</string>
|
||||
<string name="custom_lists">Custom Lists</string>
|
||||
<string name="donate_desc">Want to support Dantotsu\'s Maintainer?\nConsider Donating</string>
|
||||
<string name="donate_goal">No donation goal atm</string>
|
||||
<string name="filter">Filter</string>
|
||||
<string name="year">Year</string>
|
||||
<string name="apply">Apply</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="this_season">This Season</string>
|
||||
<string name="next_season">Next Season</string>
|
||||
<string name="previous_season">Previous Season</string>
|
||||
<string name="include_media_in_list">Include List</string>
|
||||
<string name="release_calendar">Calendar</string>
|
||||
<string name="planned_anime">Planned Anime</string>
|
||||
<string name="planned_manga">Planned Manga</string>
|
||||
<string name="image_long_clicking">Open image by Long Clicking</string>
|
||||
<string name="always_continue_shows">Always continue Shows</string>
|
||||
<string name="timestamp_proxy_desc">Useful if you are getting Handshake Fails</string>
|
||||
<string name="timestamp_proxy">Use Proxy for Timestamps</string>
|
||||
<string name="check_app_updates">Always check for App Updates</string>
|
||||
<string name="author">Author</string>
|
||||
<string name="forks">Versions</string>
|
||||
<string name="faq">FAQ</string>
|
||||
<string name="accounts">Accounts</string>
|
||||
<string name="myanimelist">MyAnimeList</string>
|
||||
<string name="login_with_anilist">Login with Anilist!</string>
|
||||
<string name="anilist">Anilist</string>
|
||||
<string name="account_help">How does this work\?</string>
|
||||
<string name="full_account_help">
|
||||
Dantotsu is an Anilist Based App, so for syncing with your MAL Account, It needs an Anilist account to be logged in.
|
||||
\nOnce logged in with both Anilist and MAL accounts, the app will automatically update your MAL account whenever:
|
||||
\n- Add a new Media
|
||||
\n- Edit a Media
|
||||
\n- Delete a Media
|
||||
|
||||
\n\nNote: The app will not sync old Media\'s from Anilist to MAL, It\'s recommended to sync them.
|
||||
\n- Check __FAQs__ for _Easy Method_
|
||||
|
||||
\n\nAnd for _Intermediates_ :
|
||||
\n- [How to sync Anilist data with MAL](https://anilist.co/forum/thread/2654)
|
||||
\n- [How to sync MAL data with Anilist](https://anilist.co/forum/thread/3393)
|
||||
|
||||
\n\n_It is not required to sync both MAL and Anilist accounts._
|
||||
</string>
|
||||
<string name="notification_for_checking_subscriptions">Show notification for Checking Subscriptions</string>
|
||||
<string name="checking_subscriptions">Notification for Checking Subscriptions</string>
|
||||
<string name="subscriptions_checking_time_s">Subscriptions Update Frequency : %1$s</string>
|
||||
<string name="subscriptions_checking_time">Subscriptions Update Frequency</string>
|
||||
<string name="subscriptions_info">Amount of time for Dantotsu to periodically check for new Episodes/Chapters\n(Less time will cause more battery consumption)</string>
|
||||
<string name="do_not_update">Don\'t Update</string>
|
||||
<string name="loading_next_chap">Loading Next Chapter</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="sort_by_release_date">Sort by Release Date</string>
|
||||
<string name="crop_borders">Crop Borders</string>
|
||||
<string name="note">NOTE</string>
|
||||
|
||||
|
||||
<string name="jobless_message">DAMN! YOU TRULY ARE JOBLESS\nYOU REACHED THE END</string>
|
||||
<string name="file_manager_not_found">Couldn\'t find any File Manager to open SD card</string>
|
||||
<string name="error_loading_data">Error loading data %1$s</string>
|
||||
<string name="long_click_to_check_update">You Long Click the button to check for App Update</string>
|
||||
<string name="saved_to_path">Saved to:\n%s</string>
|
||||
<string name="setting_progress">Setting progress to %1$d</string>
|
||||
<string name="login_anilist_account">Please Login into anilist account!</string>
|
||||
<string name="congrats_vro">Congrats Vro</string>
|
||||
<string name="please_reload">Please Reload.</string>
|
||||
<string name="copied_text">Copied "%1$s"</string>
|
||||
<string name="back_to_exit">Please perform BACK again to Exit</string>
|
||||
<string name="no_internet_connection">No Internet Connection</string>
|
||||
<string name="anilist_not_found">Seems like that wasn\'t found on Anilist.</string>
|
||||
<string name="disabled_auto_skip">Disabled Auto Skipping OP & ED</string>
|
||||
<string name="auto_skip">Auto Skipping OP & ED</string>
|
||||
<string name="copied_to_clipboard">Copied to Clipboard</string>
|
||||
<string name="first_episode">This is the 1st Episode!</string>
|
||||
<string name="reset_auto_update">You can long click List Editor button to Reset Auto Update</string>
|
||||
<string name="autoplay_cancelled">Autoplay cancelled, no Interaction for more than 1 Hour.</string>
|
||||
<string name="auto_select_server_error">Couldn\'t auto select the server, Please try again!</string>
|
||||
<string name="logging_in_mal">Logging in MAL</string>
|
||||
<string name="getting_user_data">Getting User Data</string>
|
||||
<string name="no_next_episode">No next Episode Found!</string>
|
||||
<string name="enable_banner_animations">Try Enabling Banner Animations from Settings</string>
|
||||
<string name="please_login_anilist">Please Login with Anilist!</string>
|
||||
<string name="auto_update_reset">Auto Update Progress has now been Reset-ed</string>
|
||||
<string name="cant_wait">Can\'t Wait, huh? fine X(</string>
|
||||
<string name="downloading">Downloading…</string>
|
||||
<string name="next_chapter_not_found">Next Chapter Not Found</string>
|
||||
<string name="first_chapter">This is the 1st Chapter!</string>
|
||||
<string name="adult_stuff">Adult Stuff?( ͡° ͜ʖ ͡° )</string>
|
||||
<string name="what_did_you_open">What did you even open?</string>
|
||||
<string name="error_getting_data">Error getting Data from Anilist.</string>
|
||||
<string name="empty_response">Empty Response, Does your internet perhaps suck?</string>
|
||||
<string name="error_loading_mal_user_data">Error loading MAL User Data</string>
|
||||
<string name="error_loading_mal_data">Failed to load data from MAL</string>
|
||||
<string name="error_loading_anilist_user_data">Error loading Anilist User Data</string>
|
||||
<string name="episode_not_found">Couldn\'t find episode : %1$s</string>
|
||||
<string name="list_updated">List Updated</string>
|
||||
<string name="deleted_from_list">Deleted from List</string>
|
||||
<string name="no_list_id">No List ID found, reloading…</string>
|
||||
<string name="checking_for_update">Checking for Update</string>
|
||||
<string name="dont_show_again">Don\'t show again for version %1$s</string>
|
||||
<string name="no_update_found">No Update Found</string>
|
||||
<string name="downloading_update">Downloading Update %1$s</string>
|
||||
<string name="permission_required">Please give permission to access Files & Folders from Settings, & Try again.</string>
|
||||
<string name="started_downloading">Started Downloading\n%1$s</string>
|
||||
<string name="install_1dm">Please install 1DM</string>
|
||||
<string name="install_adm">Please install ADM</string>
|
||||
<string name="error_getting_image_data">Error getting Image Data</string>
|
||||
<string name="loading_image_failed">Loading Image Failed</string>
|
||||
<string name="copied_device_info">Copied device info</string>
|
||||
<string name="anilist_down">Seems like Anilist is down, maybe try using a VPN or you can wait for it to come back.</string>
|
||||
<string name="failed_to_load_data">Failed to load saved data of %1$d</string>
|
||||
<string name="access_not_available">Wasn\'t able to get access</string>
|
||||
<string name="mal_login_uri_not_found">Mal Login : Uri not Found</string>
|
||||
<string name="mal_login_code_challenge_not_found">Mal Login : codeChallenge not found</string>
|
||||
<string name="mal_login_code_not_present">Mal Login : Code not present in Redirected URI</string>
|
||||
<string name="refresh_token_load_failed">Refresh Token : Failed to load Saved Token</string>
|
||||
<string name="refreshing_token_failed">Refreshing Token Failed</string>
|
||||
<string name="episode_release_countdown">Episode %1$d will be released in</string>
|
||||
<string name="time_format">%1$d days %2$d hrs %3$d mins %4$d secs</string>
|
||||
<string-array name="sort_by">
|
||||
<item>Score</item>
|
||||
<item>Popular</item>
|
||||
<item>Trending</item>
|
||||
<item>A-Z</item>
|
||||
<item>Z-A</item>
|
||||
<item>What?</item>
|
||||
</string-array>
|
||||
<string name="main_role">MAIN</string>
|
||||
<string name="supporting_role">SUPPORTING</string>
|
||||
|
||||
<string name="status_finished">FINISHED</string>
|
||||
<string name="status_releasing">RELEASING</string>
|
||||
<string name="status_not_yet_released">NOT YET RELEASED</string>
|
||||
<string name="status_cancelled">CANCELLED</string>
|
||||
<string name="status_hiatus">HIATUS</string>
|
||||
|
||||
<string name="type_adaptation">ADAPTATION</string>
|
||||
<string name="type_parent">PARENT</string>
|
||||
<string name="type_character">CHARACTER</string>
|
||||
<string name="type_summary">SUMMARY</string>
|
||||
<string name="type_alternative">ALTERNATIVE</string>
|
||||
<string name="type_other">OTHER</string>
|
||||
<string name="type_source">SOURCE</string>
|
||||
<string name="type_contains">CONTAINS</string>
|
||||
|
||||
<string name="read_on_dantotsu">Read on Dantotsu</string>
|
||||
<string name="watch_on_dantotsu">Watch on Dantotsu</string>
|
||||
<string name="continue_episode">"Continue : Episode "</string>
|
||||
<string name="continue_chapter">"Continue : "</string>
|
||||
<string name="episode">"Episode "</string>
|
||||
<string name="episode_num">"Episode %1$s"</string>
|
||||
<string name="chapter">"Chapter "</string>
|
||||
<string name="chapter_num">"Chapter %1$s"</string>
|
||||
<string name="just_released">- just got released!</string>
|
||||
<string name="checking_subscriptions_title">Checking Subscriptions</string>
|
||||
|
||||
<string name="speed">Speed</string>
|
||||
<string name="auto_update">Auto Update progress for %1$s?</string>
|
||||
<string name="continue_from">Continue from %1$s?</string>
|
||||
<string name="title_update_progress">Update progress on anilist?</string>
|
||||
<string name="incognito_will_not_update">Incognito mode will still ignore progress.</string>
|
||||
<string name="dont_ask_again">"Don\'t ask again for %1$s"</string>
|
||||
<string name="default_speed">Default Speed</string>
|
||||
<string name="default_resize_mode">Default Resize Mode</string>
|
||||
<string name="primary_sub_color">Primary Sub Color</string>
|
||||
<string name="outline_sub_color">Outline Sub Color</string>
|
||||
<string name="outline_type">Outline Type</string>
|
||||
<string name="subtitle_font">Subtitle Font</string>
|
||||
|
||||
|
||||
<string name="yes">Yes</string>
|
||||
<string name="no">No</string>
|
||||
<string name="close">Close</string>
|
||||
<string name= "no_chapter">No Chapter</string>
|
||||
<string name= "content_18">Turn on 18+ Content from your Anilist Settings</string>
|
||||
<string name= "available">Available</string>
|
||||
<string name="lets_go">Let\'s Go</string>
|
||||
<string name="cope">Cope</string>
|
||||
|
||||
<string name="watched_num">"Watched "</string>
|
||||
<string name="read_num">"Read "</string>
|
||||
<string name="episodes_out_of">" out of "</string>
|
||||
<string name="chapters_out_of">" out of "</string>
|
||||
<string name="episodes_total_of">"Total of "</string>
|
||||
<string name="chapters_total_of">"Total of "</string>
|
||||
<string name="no_description_available">"No Description Available"</string>
|
||||
|
||||
<string-array name="manga_directions">
|
||||
<item>Top to Bottom</item>
|
||||
<item>Right to Left</item>
|
||||
<item>Bottom to Top</item>
|
||||
<item>Left to Right</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="manga_layouts">
|
||||
<item>Paged</item>
|
||||
<item>Continuous Paged</item>
|
||||
<item>Continuous</item>
|
||||
</string-array>
|
||||
|
||||
<string name="selected">Selected</string>
|
||||
<string name="found">Found</string>
|
||||
|
||||
<string name="age">"__Age:__ "</string>
|
||||
<string name="birthday">\n"__Birthday:__ "</string>
|
||||
<string name="gender">\n"__Gender:__ "</string>"
|
||||
|
||||
<string name="male">Male</string>
|
||||
<string name="female">Female</string>
|
||||
|
||||
<string name="question_1">What is Dantotsu?\n Why should you use Dantotsu?</string>
|
||||
<string name="answer_1">Dantotsu is crafted from the ashes of Saikou and based on simplistic yet state-of-the-art elegance. It is an Anilist only client, which also lets you stream & download Anime / Manga through extensions. \n>Dantotsu (断トツ; Dan-totsu) literally means the best of the best in Japanese. Well, we would like to say this is the best open source app for anime and manga on Android, but hey, Try it out yourself & judge!</string>
|
||||
|
||||
<string name="question_2">What are some features of Dantotsu?</string>
|
||||
<string name="answer_2">Some mentionable features of Dantotsu are\n\n- Easy and functional way to both, watch anime and read manga and light novels, Ad Free.\n- A completely open source app with a nice UI & Animations\n- 3rd party plugin support \n- Synchronize anime and manga real-time with AniList. Easily categorize anime and manga based on your current status. (Powered by AniList)\n- Find all shows using thoroughly and frequently updated list of all trending, popular and ongoing anime based on scores.\n- View extensive details about anime shows, movies and manga titles. It also features ability to countdown to the next episode of airing anime. (Powered by AniList & MyAnimeList)</string>
|
||||
|
||||
<string name="question_3">What are Artifacts?</string>
|
||||
<string name="answer_3">Whenever a developer commits or pull requests a feature or fix, GitHub automatically makes an APK file for you to use. This APK is called an Artifact. Artifacts through pull requests may or may not be added to the main release of the app. Artifacts have a higher chance of having bugs and glitches. To know if new artifacts are available, star the Dantotsu repository and turn on notifications\n\nTo download an Artifact:\n1) Sign In/Up in GitHub\n2) Go to Dantotsu\n3) Go to actions\n4) Press on the workflow run you want to download the artifact of.\n5) Press on artifact\n6) Extract the file using a zip extractor\n7) Install and enjoy.</string>
|
||||
|
||||
<string name="question_4">Is Dantotsu available for PC?</string>
|
||||
<string name="answer_4">Currently no (for both Windows and Linux). There isn\'t any estimation when it will be available. But you can download any Android emulator and run Dantotsu on it. For Windows 11 users, they can use the Windows Subsystem for Android (WSA) to run Dantotsu in Windows.</string>
|
||||
|
||||
<string name="question_5">Is Dantotsu available for iOS?</string>
|
||||
<string name="answer_5">No, and currently no plans to support iOS</string>
|
||||
|
||||
<string name="question_6">Why are my stats not updating?</string>
|
||||
<string name="answer_6">This is because it updates every 48 hours automatically (by Anilist). If you really need to update your stats, you can force update your stats after going to this [link](https://anilist.co/settings/lists).</string>
|
||||
|
||||
<string name="question_7">How to download Episodes?</string>
|
||||
<string name="answer_7">1. Download 1DM or ADM from Google Play Store.
|
||||
\n2. Enter the app, give storage access and set your preferences (downloading speed, downloading path etc(optional))
|
||||
\n3. Now go to Dantotsu > Settings > Common > Download Managers and choose the download manager you just set up.
|
||||
\n4. Go to your desired episode and press on the download icon of any server. There may be a popup to set your preferences again, just press on "Download" and it will be saved in the directed path.
|
||||
|
||||
\n\nNote: Direct downloads are also possible without a manager but it\'s not recommended.</string>
|
||||
|
||||
<string name="question_8">How to download Manga Chapters?</string>
|
||||
<string name="answer_8">It is yet not possible to download chapters in Dantotsu but this feature will be implemented soon.</string>
|
||||
|
||||
<string name="question_9">How to enable NSFW content?</string>
|
||||
<string name="answer_9">You can enable nsfw content by enabling 18+ contents from this [link](https://anilist.co/settings/media).</string>
|
||||
|
||||
<string name="question_10">How to import my MAL/Kitsu list to Anilist?</string>
|
||||
<string name="answer_10">Here is how you do it,\n\nExport:\n\n1. Go to this [link](https://malscraper.azurewebsites.net).\n2. Give your Kitsu/MAL username and download both anime and manga list. (They will be in XML format)\nNote: You have to write the username of the tracker you selected\n\nImport:\n\n1. After exporting your anime and manga list from Kitsu/MAL, now go [here](https://anilist.co/settings/import) \n2. Select/drop the anime XML file on the box above.\n|→Select/drop the manga XML file on the box below.</string>
|
||||
|
||||
<string name="question_11">How to import my Anilist/Kitsu list to MAL?</string>
|
||||
<string name="answer_11">Here is how you do it,\n\nExport:\n\n1. Go to this [link](https://malscraper.azurewebsites.net/). \n2. Give your Anilist username/Kitsu ID in the \'Username/Kitsu User ID\' box. \n3. Select list type and enable \'update_on_import\'. \n4. Download the file; it will be in .xml format. Be sure to download both Anime and Manga lists.\n\nImport:\n1. To import it in your MAL account, go to this [link](https://myanimelist.net/import.php) and choose \'MyAnimeList Import\' as import type. \n2. Press on \'Choose File\'and select the downloaded anime/manga list XML file. \n3. Press on \'Import Data\'. \nCongratulations, you just imported the selected list to your MAL account.</string>
|
||||
|
||||
<string name="question_12">Why can\'t I find a specific anime/manga title?</string>
|
||||
<string name="answer_12">Let\'s say you are looking for Castlevania in Dantotsu. But Anilist doesn\'t have it, so Dantotsu doesn\'t either.\nA solution to the above problem is as follows:\n1) Go to any anime that\'s not in your list.\n2) Go to the watch section.\n3) Select any source and press on the \'Wrong Title?\'.\n4) Now search for Castlevania (The anime you were looking for) and select it.\n5) ENJOY!\n\nIf you can\'t find the anime even through these steps, then that\'s bad luck for you, bud. Even that source doesn\'t have it. Try a different source.</string>
|
||||
|
||||
<string name="question_13">How to fix sources selecting a completely wrong title?</string>
|
||||
<string name="answer_13">Dantotsu itself doesn\'t host anything but relies on other sources. When showing the episodes, it chooses the 1st result given by the source after searching for the title. Dantotsu has no way of detecting if that\'s legit or not. So, for this, we have the \'Wrong Title?\' just below the source name(above layouts). You can choose the correct result/title by pressing on it and enjoy its episodes.</string>
|
||||
|
||||
<string name="question_14">How to read coloured mangas?</string>
|
||||
<string name="answer_14">Are you in search of coloured manga? Sorry to break it to you but an extremely small amount of mangas have coloured version. Those which has a coloured version is also available in Dantotsu. Let\'s say you want to read the coloured version of chainsaw man. Then follow the below steps ↓\n\n1) Go to Chainsaw Man\n2) Press on \'Read\'\n3) Select any working source\n4) Press on \'Wrong Title\'\n5) Select the colored version chainsaw man\n6) Enjoy\n\nNote: Many sources don\'t have the coloured version available even if it\'s available somewhere on the internet. So try a different source. If none of the sources have it, then a coloured version of your desired manga simply doesn\'t exist. If you can find it on any manga site on the internet, you can suggest that site through the Discord server.</string>
|
||||
|
||||
<string name="question_15">Handshake fails? Why are no timestamps not loading?</string>
|
||||
<string name="answer_15">You can fix this issue by enabling \'Proxy\' from \n\`Settings > Anime > Player Settings > Timestamps > Proxy\`.\nIf the timestamps are still not loading but the handshake failed popup is fixed, then the episode you are watching just doesn\'t have timestamps yet for it.</string>
|
||||
|
||||
<string name="question_16">Having trouble with a source?</string>
|
||||
<string name="answer_16">Some basic fixes would be :\n\n• Restart the app. \n• Use a different DNS from your settings, preferably, CloudFlare. \n• VPN might work as well. \n\nIf you refuse to try the above steps then just use a different source.\n\nNote: Allanime fixes itself most of the time.</string>
|
||||
|
||||
<string name="question_17">Some useful tips and tricks</string>
|
||||
<string name="answer_17">The following presents some tips and tricks you may or may not know about - \n \n \n - By hold pressing the Dantotsu logo in settings, you can check if there are any new updates manually. \n \n - Hold pressing an error message/tag/synonym or title will copy it. \n \n - You can open an episode with other apps by hold pressing any server for that episode. This helps in streaming the episode using other video players or download the episode using download managers. \n \n - You can set up custom lists using this [link](https://anilist.co/settings/lists). (you need to be signed in) \n \n - If your episode/chapter is not being progressed automatically after you finish watching/reading it, then hold press the status bar(planning/repeating/watching button) of that anime/manga. The next time you start a chapter/finish an episode, you will stumble upon a popup. Press yes there. </string>
|
||||
|
||||
|
||||
<string name="subscribed_notification">Subscribed! Receiving notifications, when new episodes are released on %1$s.</string>
|
||||
|
||||
<string name="unsubscribed_notification">Unsubscribed, you will not receive any notifications.</string>
|
||||
<string name="episode_plural">Episodes</string>
|
||||
<string name="episode_singular">Episode</string>
|
||||
<string name="chapter_singular">Chapter</string>
|
||||
<string name="chapter_plural">Chapters</string>
|
||||
|
||||
<string name="filter_format">"Format : %1$s"</string>
|
||||
<string name="filter_sort">"Sort : %1$s"</string>
|
||||
<string name="filter_exclude">"Not %1$s"</string>
|
||||
<string name="search_by_image">Search by Image</string>
|
||||
<string name="upload_image">Upload Image</string>
|
||||
<string name="similarity_text">Similarity: %1$s %%</string>
|
||||
<string name="time_range">From %1$s to %2$s</string>
|
||||
<string name="invalid_url">Invalid URL</string>
|
||||
<string name="no_anilist_id_found">No Anilist ID found</string>
|
||||
<string name="error_loading_image">Error loading image</string>
|
||||
<string name="discord_logout_success">Successfully Logged Out</string>
|
||||
<string name="discord_try_again">Try logging-in again</string>
|
||||
<string name="error_loading_discord_user_data">Error loading Discord User Data</string>
|
||||
<string name="discord_warning"><![CDATA[By logging in, your discord will now show what you are watching & reading on Dantotsu\n\nIf you are on invisible mode, logging in will make you online, when you open Dantotsu.\n\nThis does break the Discord TOS. \nAlthough Discord has never banned anyone for using Custom Rich Presence(what Dantotsu uses), You have still been warned.\n\nDantotsu is not responsible for anything that happens to your account.]]></string>
|
||||
<string name="warning">Warning</string>
|
||||
<string name="view_anime">View Anime</string>
|
||||
<string name="view_manga">View Manga</string>
|
||||
<string name="force_legacy_installer">Force Legacy Installer</string>
|
||||
<string name="extensions_settings">Extensions</string>
|
||||
<string name="NSFWExtention">NSFW Extensions</string>
|
||||
<string name="skip_loading_extension_icons">Skip loading extension icons</string>
|
||||
<string name="use_material_you">Material You</string>
|
||||
<string name="extension_specific_dns">Extension-specific DNS</string>
|
||||
<string name="theme_">Theme:</string>
|
||||
<string name="user_agent">User Agent</string>
|
||||
<string name="custom_theme">Custom Theme</string>
|
||||
<string name="use_custom_theme">Custom theme</string>
|
||||
<string name="use_unique_theme_for_each_item">Color same as Anime/Manga cover</string>
|
||||
<string name="oled_theme_variant">OLED theme variant</string>
|
||||
<string name="installed_anime">Installed Anime</string>
|
||||
<string name="available_anime">Available Anime</string>
|
||||
<string name="installed_manga">Installed Manga</string>
|
||||
<string name="color_picker">Color Picker</string>
|
||||
<string name="random_selection">Random Selection</string>
|
||||
<string name="incognito_mode">Incognito Mode</string>
|
||||
|
||||
</resources>
|
||||
@@ -65,32 +65,32 @@
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Purple" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/mdmd_theme_dark_3_primary</item>
|
||||
<item name="colorOnPrimary">@color/mdmd_theme_dark_3_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/mdmd_theme_dark_3_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/mdmd_theme_dark_3_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/mdmd_theme_dark_3_secondary</item>
|
||||
<item name="colorOnSecondary">@color/mdmd_theme_dark_3_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/mdmd_theme_dark_3_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/mdmd_theme_dark_3_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/mdmd_theme_dark_3_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/mdmd_theme_dark_3_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/mdmd_theme_dark_3_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/mdmd_theme_dark_3_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/mdmd_theme_dark_3_error</item>
|
||||
<item name="colorErrorContainer">@color/mdmd_theme_dark_3_errorContainer</item>
|
||||
<item name="colorOnError">@color/mdmd_theme_dark_3_onError</item>
|
||||
<item name="colorOnErrorContainer">@color/mdmd_theme_dark_3_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/mdmd_theme_dark_3_background</item>
|
||||
<item name="colorOnBackground">@color/mdmd_theme_dark_3_onBackground</item>
|
||||
<item name="colorSurface">@color/mdmd_theme_dark_3_surface</item>
|
||||
<item name="colorOnSurface">@color/mdmd_theme_dark_3_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/mdmd_theme_dark_3_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/mdmd_theme_dark_3_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/mdmd_theme_dark_3_outline</item>
|
||||
<item name="colorOnSurfaceInverse">@color/mdmd_theme_dark_3_inverseOnSurface</item>
|
||||
<item name="colorSurfaceInverse">@color/mdmd_theme_dark_3_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/mdmd_theme_dark_3_inversePrimary</item>
|
||||
<item name="colorPrimary">@color/md_theme_dark_3_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_theme_dark_3_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/md_theme_dark_3_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/md_theme_dark_3_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/md_theme_dark_3_secondary</item>
|
||||
<item name="colorOnSecondary">@color/md_theme_dark_3_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/md_theme_dark_3_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/md_theme_dark_3_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/md_theme_dark_3_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/md_theme_dark_3_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/md_theme_dark_3_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/md_theme_dark_3_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/md_theme_dark_3_error</item>
|
||||
<item name="colorErrorContainer">@color/md_theme_dark_3_errorContainer</item>
|
||||
<item name="colorOnError">@color/md_theme_dark_3_onError</item>
|
||||
<item name="colorOnErrorContainer">@color/md_theme_dark_3_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/md_theme_dark_3_background</item>
|
||||
<item name="colorOnBackground">@color/md_theme_dark_3_onBackground</item>
|
||||
<item name="colorSurface">@color/md_theme_dark_3_surface</item>
|
||||
<item name="colorOnSurface">@color/md_theme_dark_3_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/md_theme_dark_3_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/md_theme_dark_3_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/md_theme_dark_3_outline</item>
|
||||
<item name="colorOnSurfaceInverse">@color/md_theme_dark_3_inverseOnSurface</item>
|
||||
<item name="colorSurfaceInverse">@color/md_theme_dark_3_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_theme_dark_3_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Pink" parent="Theme.Base">
|
||||
@@ -122,6 +122,122 @@
|
||||
<item name="colorPrimaryInverse">@color/md_theme_dark_4_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Saikou" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/md_theme_dark_5_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_theme_dark_5_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/md_theme_dark_5_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/md_theme_dark_5_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/md_theme_dark_5_secondary</item>
|
||||
<item name="colorOnSecondary">@color/md_theme_dark_5_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/md_theme_dark_5_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/md_theme_dark_5_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/md_theme_dark_5_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/md_theme_dark_5_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/md_theme_dark_5_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/md_theme_dark_5_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/md_theme_dark_5_error</item>
|
||||
<item name="colorErrorContainer">@color/md_theme_dark_5_errorContainer</item>
|
||||
<item name="colorOnError">@color/md_theme_dark_5_onError</item>
|
||||
<item name="colorOnErrorContainer">@color/md_theme_dark_5_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/md_theme_dark_5_background</item>
|
||||
<item name="colorOnBackground">@color/md_theme_dark_5_onBackground</item>
|
||||
<item name="colorSurface">@color/md_theme_dark_5_surface</item>
|
||||
<item name="colorOnSurface">@color/md_theme_dark_5_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/md_theme_dark_5_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/md_theme_dark_5_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/md_theme_dark_5_outline</item>
|
||||
<item name="colorOnSurfaceInverse">@color/md_theme_dark_5_inverseOnSurface</item>
|
||||
<item name="colorSurfaceInverse">@color/md_theme_dark_5_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_theme_dark_5_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Red" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/md_theme_dark_6_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_theme_dark_6_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/md_theme_dark_6_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/md_theme_dark_6_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/md_theme_dark_6_secondary</item>
|
||||
<item name="colorOnSecondary">@color/md_theme_dark_6_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/md_theme_dark_6_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/md_theme_dark_6_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/md_theme_dark_6_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/md_theme_dark_6_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/md_theme_dark_6_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/md_theme_dark_6_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/md_theme_dark_6_error</item>
|
||||
<item name="colorErrorContainer">@color/md_theme_dark_6_errorContainer</item>
|
||||
<item name="colorOnError">@color/md_theme_dark_6_onError</item>
|
||||
<item name="colorOnErrorContainer">@color/md_theme_dark_6_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/md_theme_dark_6_background</item>
|
||||
<item name="colorOnBackground">@color/md_theme_dark_6_onBackground</item>
|
||||
<item name="colorSurface">@color/md_theme_dark_6_surface</item>
|
||||
<item name="colorOnSurface">@color/md_theme_dark_6_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/md_theme_dark_6_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/md_theme_dark_6_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/md_theme_dark_6_outline</item>
|
||||
<item name="colorOnSurfaceInverse">@color/md_theme_dark_6_inverseOnSurface</item>
|
||||
<item name="colorSurfaceInverse">@color/md_theme_dark_6_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_theme_dark_6_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Lavender" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/md_theme_dark_7_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_theme_dark_7_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/md_theme_dark_7_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/md_theme_dark_7_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/md_theme_dark_7_secondary</item>
|
||||
<item name="colorOnSecondary">@color/md_theme_dark_7_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/md_theme_dark_7_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/md_theme_dark_7_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/md_theme_dark_7_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/md_theme_dark_7_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/md_theme_dark_7_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/md_theme_dark_7_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/md_theme_dark_7_error</item>
|
||||
<item name="colorErrorContainer">@color/md_theme_dark_7_errorContainer</item>
|
||||
<item name="colorOnError">@color/md_theme_dark_7_onError</item>
|
||||
<item name="colorOnErrorContainer">@color/md_theme_dark_7_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/md_theme_dark_7_background</item>
|
||||
<item name="colorOnBackground">@color/md_theme_dark_7_onBackground</item>
|
||||
<item name="colorSurface">@color/md_theme_dark_7_surface</item>
|
||||
<item name="colorOnSurface">@color/md_theme_dark_7_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/md_theme_dark_7_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/md_theme_dark_7_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/md_theme_dark_7_outline</item>
|
||||
<item name="colorOnSurfaceInverse">@color/md_theme_dark_7_inverseOnSurface</item>
|
||||
<item name="colorSurfaceInverse">@color/md_theme_dark_7_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_theme_dark_7_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Emerald" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/md_theme_dark_8_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_theme_dark_8_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/md_theme_dark_8_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/md_theme_dark_8_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/md_theme_dark_8_secondary</item>
|
||||
<item name="colorOnSecondary">@color/md_theme_dark_8_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/md_theme_dark_8_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/md_theme_dark_8_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/md_theme_dark_8_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/md_theme_dark_8_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/md_theme_dark_8_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/md_theme_dark_8_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/md_theme_dark_8_error</item>
|
||||
<item name="colorErrorContainer">@color/md_theme_dark_8_errorContainer</item>
|
||||
<item name="colorOnError">@color/md_theme_dark_8_onError</item>
|
||||
<item name="colorOnErrorContainer">@color/md_theme_dark_8_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/md_theme_dark_8_background</item>
|
||||
<item name="colorOnBackground">@color/md_theme_dark_8_onBackground</item>
|
||||
<item name="colorSurface">@color/md_theme_dark_8_surface</item>
|
||||
<item name="colorOnSurface">@color/md_theme_dark_8_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/md_theme_dark_8_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/md_theme_dark_8_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/md_theme_dark_8_outline</item>
|
||||
<item name="colorOnSurfaceInverse">@color/md_theme_dark_8_inverseOnSurface</item>
|
||||
<item name="colorSurfaceInverse">@color/md_theme_dark_8_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_theme_dark_8_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Monochrome" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/bg_white</item>
|
||||
<item name="colorOnPrimary">@color/bg_black</item>
|
||||
@@ -151,93 +267,6 @@
|
||||
<item name="colorPrimaryInverse">@color/bg_black</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Red" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/md_0_theme_dark_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_0_theme_dark_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/md_0_theme_dark_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/md_0_theme_dark_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/md_0_theme_dark_secondary</item>
|
||||
<item name="colorOnSecondary">@color/md_0_theme_dark_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/md_0_theme_dark_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/md_0_theme_dark_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/md_0_theme_dark_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/md_0_theme_dark_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/md_0_theme_dark_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/md_0_theme_dark_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/md_0_theme_dark_error</item>
|
||||
<item name="colorErrorContainer">@color/md_0_theme_dark_errorContainer</item>
|
||||
<item name="colorOnError">@color/md_0_theme_dark_onError</item>
|
||||
<item name="colorOnErrorContainer">@color/md_0_theme_dark_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/md_0_theme_dark_background</item>
|
||||
<item name="colorOnBackground">@color/md_0_theme_dark_onBackground</item>
|
||||
<item name="colorSurface">@color/md_0_theme_dark_surface</item>
|
||||
<item name="colorOnSurface">@color/md_0_theme_dark_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/md_0_theme_dark_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/md_0_theme_dark_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/md_0_theme_dark_outline</item>
|
||||
<item name="colorOnSurfaceInverse">@color/md_0_theme_dark_inverseOnSurface</item>
|
||||
<item name="colorSurfaceInverse">@color/md_0_theme_dark_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_0_theme_dark_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Lavender" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/md_1_theme_dark_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_1_theme_dark_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/md_1_theme_dark_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/md_1_theme_dark_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/md_1_theme_dark_secondary</item>
|
||||
<item name="colorOnSecondary">@color/md_1_theme_dark_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/md_1_theme_dark_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/md_1_theme_dark_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/md_1_theme_dark_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/md_1_theme_dark_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/md_1_theme_dark_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/md_1_theme_dark_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/md_1_theme_dark_error</item>
|
||||
<item name="colorErrorContainer">@color/md_1_theme_dark_errorContainer</item>
|
||||
<item name="colorOnError">@color/md_1_theme_dark_onError</item>
|
||||
<item name="colorOnErrorContainer">@color/md_1_theme_dark_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/md_1_theme_dark_background</item>
|
||||
<item name="colorOnBackground">@color/md_1_theme_dark_onBackground</item>
|
||||
<item name="colorSurface">@color/md_1_theme_dark_surface</item>
|
||||
<item name="colorOnSurface">@color/md_1_theme_dark_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/md_1_theme_dark_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/md_1_theme_dark_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/md_1_theme_dark_outline</item>
|
||||
<item name="colorOnSurfaceInverse">@color/md_1_theme_dark_inverseOnSurface</item>
|
||||
<item name="colorSurfaceInverse">@color/md_1_theme_dark_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_1_theme_dark_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Saikou" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/md_theme_dark_5_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_theme_dark_5_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/md_theme_dark_5_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/md_theme_dark_5_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/md_theme_dark_5_secondary</item>
|
||||
<item name="colorOnSecondary">@color/md_theme_dark_5_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/md_theme_dark_5_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/md_theme_dark_5_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/md_theme_dark_5_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/md_theme_dark_5_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/md_theme_dark_5_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/md_theme_dark_5_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/md_theme_dark_5_error</item>
|
||||
<item name="colorErrorContainer">@color/md_theme_dark_5_errorContainer</item>
|
||||
<item name="colorOnError">@color/md_theme_dark_5_onError</item>
|
||||
<item name="colorOnErrorContainer">@color/md_theme_dark_5_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/md_1_theme_dark_background</item>
|
||||
<item name="colorOnBackground">@color/md_theme_dark_5_onBackground</item>
|
||||
<item name="colorSurface">@color/md_theme_dark_5_surface</item>
|
||||
<item name="colorOnSurface">@color/md_theme_dark_5_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/md_theme_dark_5_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/md_theme_dark_5_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/md_theme_dark_5_outline</item>
|
||||
<item name="colorOnSurfaceInverse">@color/md_theme_dark_5_inverseOnSurface</item>
|
||||
<item name="colorSurfaceInverse">@color/md_theme_dark_5_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_theme_dark_5_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.BlueOLED" parent="Theme.Dantotsu.Blue">
|
||||
<item name="android:colorBackground">@color/darkest_Black</item>
|
||||
<item name="colorSurface">@color/darkest_Black</item>
|
||||
@@ -277,5 +306,9 @@
|
||||
<item name="android:colorBackground">@color/darkest_Black</item>
|
||||
<item name="colorSurface">@color/darkest_Black</item>
|
||||
</style>
|
||||
<style name="Theme.Dantotsu.EmeraldOLED" parent="Theme.Dantotsu.Emerald">
|
||||
<item name="android:colorBackground">@color/darkest_Black</item>
|
||||
<item name="colorSurface">@color/darkest_Black</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -24,6 +24,14 @@
|
||||
<color name="yt_red">#CD201F</color>
|
||||
<color name="chip">#a3a2a2</color>
|
||||
<color name="grey_nav">#E8EDEDED</color>
|
||||
<color name="CustomColor1">#93DB00</color>
|
||||
<color name="CustomColor2">#68AF86</color>
|
||||
<color name="CustomColor3">#0096AE</color>
|
||||
<color name="CustomColor4">#000000</color>
|
||||
<color name="light_blue_50">#FFE1F5FE</color>
|
||||
<color name="light_blue_200">#FF81D4FA</color>
|
||||
<color name="light_blue_600">#FF039BE5</color>
|
||||
<color name="light_blue_900">#FF01579B</color>
|
||||
|
||||
<!-- theme 1 -->
|
||||
<color name="seed_1">#00658e</color>
|
||||
@@ -88,6 +96,7 @@
|
||||
<color name="md_theme_dark_1_outlineVariant">#41484D</color>
|
||||
<color name="md_theme_dark_1_scrim">#000000</color>
|
||||
|
||||
<!-- theme 2 -->
|
||||
<color name="seed_2">#426916</color>
|
||||
<color name="md_theme_light_2_primary">#426916</color>
|
||||
<color name="md_theme_light_2_onPrimary">#FFFFFF</color>
|
||||
@@ -150,6 +159,7 @@
|
||||
<color name="md_theme_dark_2_outlineVariant">#44483D</color>
|
||||
<color name="md_theme_dark_2_scrim">#000000</color>
|
||||
|
||||
<!-- theme 3 -->
|
||||
<color name="seed_3">#7c4997</color>
|
||||
<color name="md_theme_light_3_primary">#7C4997</color>
|
||||
<color name="md_theme_light_3_onPrimary">#FFFFFF</color>
|
||||
@@ -181,37 +191,38 @@
|
||||
<color name="md_theme_light_3_surfaceTint">#7C4997</color>
|
||||
<color name="md_theme_light_3_outlineVariant">#CEC3CE</color>
|
||||
<color name="md_theme_light_3_scrim">#000000</color>
|
||||
<color name="mdmd_theme_dark_3_primary">#E7B3FF</color>
|
||||
<color name="mdmd_theme_dark_3_onPrimary">#4A1765</color>
|
||||
<color name="mdmd_theme_dark_3_primaryContainer">#62307D</color>
|
||||
<color name="mdmd_theme_dark_3_onPrimaryContainer">#F6D9FF</color>
|
||||
<color name="mdmd_theme_dark_3_secondary">#D3C0D8</color>
|
||||
<color name="mdmd_theme_dark_3_onSecondary">#382C3E</color>
|
||||
<color name="mdmd_theme_dark_3_secondaryContainer">#504255</color>
|
||||
<color name="mdmd_theme_dark_3_onSecondaryContainer">#F0DCF4</color>
|
||||
<color name="mdmd_theme_dark_3_tertiary">#F5B7B7</color>
|
||||
<color name="mdmd_theme_dark_3_onTertiary">#4C2526</color>
|
||||
<color name="mdmd_theme_dark_3_tertiaryContainer">#663B3B</color>
|
||||
<color name="mdmd_theme_dark_3_onTertiaryContainer">#FFDAD9</color>
|
||||
<color name="mdmd_theme_dark_3_error">#FFB4AB</color>
|
||||
<color name="mdmd_theme_dark_3_errorContainer">#93000A</color>
|
||||
<color name="mdmd_theme_dark_3_onError">#690005</color>
|
||||
<color name="mdmd_theme_dark_3_onErrorContainer">#FFDAD6</color>
|
||||
<color name="mdmd_theme_dark_3_background">#1D1B1E</color>
|
||||
<color name="mdmd_theme_dark_3_onBackground">#E8E0E5</color>
|
||||
<color name="mdmd_theme_dark_3_surface">#1D1B1E</color>
|
||||
<color name="mdmd_theme_dark_3_onSurface">#E8E0E5</color>
|
||||
<color name="mdmd_theme_dark_3_surfaceVariant">#4B444D</color>
|
||||
<color name="mdmd_theme_dark_3_onSurfaceVariant">#CEC3CE</color>
|
||||
<color name="mdmd_theme_dark_3_outline">#978E98</color>
|
||||
<color name="mdmd_theme_dark_3_inverseOnSurface">#1D1B1E</color>
|
||||
<color name="mdmd_theme_dark_3_inverseSurface">#E8E0E5</color>
|
||||
<color name="mdmd_theme_dark_3_inversePrimary">#7C4997</color>
|
||||
<color name="mdmd_theme_dark_3_shadow">#000000</color>
|
||||
<color name="mdmd_theme_dark_3_surfaceTint">#E7B3FF</color>
|
||||
<color name="mdmd_theme_dark_3_outlineVariant">#4B444D</color>
|
||||
<color name="mdmd_theme_dark_3_scrim">#000000</color>
|
||||
<color name="md_theme_dark_3_primary">#E7B3FF</color>
|
||||
<color name="md_theme_dark_3_onPrimary">#4A1765</color>
|
||||
<color name="md_theme_dark_3_primaryContainer">#62307D</color>
|
||||
<color name="md_theme_dark_3_onPrimaryContainer">#F6D9FF</color>
|
||||
<color name="md_theme_dark_3_secondary">#D3C0D8</color>
|
||||
<color name="md_theme_dark_3_onSecondary">#382C3E</color>
|
||||
<color name="md_theme_dark_3_secondaryContainer">#504255</color>
|
||||
<color name="md_theme_dark_3_onSecondaryContainer">#F0DCF4</color>
|
||||
<color name="md_theme_dark_3_tertiary">#F5B7B7</color>
|
||||
<color name="md_theme_dark_3_onTertiary">#4C2526</color>
|
||||
<color name="md_theme_dark_3_tertiaryContainer">#663B3B</color>
|
||||
<color name="md_theme_dark_3_onTertiaryContainer">#FFDAD9</color>
|
||||
<color name="md_theme_dark_3_error">#FFB4AB</color>
|
||||
<color name="md_theme_dark_3_errorContainer">#93000A</color>
|
||||
<color name="md_theme_dark_3_onError">#690005</color>
|
||||
<color name="md_theme_dark_3_onErrorContainer">#FFDAD6</color>
|
||||
<color name="md_theme_dark_3_background">#1D1B1E</color>
|
||||
<color name="md_theme_dark_3_onBackground">#E8E0E5</color>
|
||||
<color name="md_theme_dark_3_surface">#1D1B1E</color>
|
||||
<color name="md_theme_dark_3_onSurface">#E8E0E5</color>
|
||||
<color name="md_theme_dark_3_surfaceVariant">#4B444D</color>
|
||||
<color name="md_theme_dark_3_onSurfaceVariant">#CEC3CE</color>
|
||||
<color name="md_theme_dark_3_outline">#978E98</color>
|
||||
<color name="md_theme_dark_3_inverseOnSurface">#1D1B1E</color>
|
||||
<color name="md_theme_dark_3_inverseSurface">#E8E0E5</color>
|
||||
<color name="md_theme_dark_3_inversePrimary">#7C4997</color>
|
||||
<color name="md_theme_dark_3_shadow">#000000</color>
|
||||
<color name="md_theme_dark_3_surfaceTint">#E7B3FF</color>
|
||||
<color name="md_theme_dark_3_outlineVariant">#4B444D</color>
|
||||
<color name="md_theme_dark_3_scrim">#000000</color>
|
||||
|
||||
<!-- theme 4 -->
|
||||
<color name="seed_4">#e800ac</color>
|
||||
<color name="md_theme_light_4_primary">#B30084</color>
|
||||
<color name="md_theme_light_4_onPrimary">#FFFFFF</color>
|
||||
@@ -274,7 +285,8 @@
|
||||
<color name="md_theme_dark_4_outlineVariant">#504349</color>
|
||||
<color name="md_theme_dark_4_scrim">#000000</color>
|
||||
|
||||
<color name="seed_7">#FF007F
|
||||
<!-- theme 5 -->
|
||||
<color name="seed_5">#FF007F
|
||||
</color> <!-- if there are any issues with Saikou theme message @Wai What to get it fixed, unallocated colors are also set to "#00FF00" as they are not yet being used-->
|
||||
<color name="md_theme_light_5_primary">#FF007F</color>
|
||||
<color name="md_theme_light_5_onPrimary">#EEEEEE
|
||||
@@ -330,7 +342,7 @@
|
||||
<color name="md_theme_dark_5_errorContainer">#00FF00</color>
|
||||
<color name="md_theme_dark_5_onError">#00FF00</color>
|
||||
<color name="md_theme_dark_5_onErrorContainer">#00FF00</color>
|
||||
<color name="md_theme_dark_5_background">#1C1B20</color>
|
||||
<color name="md_theme_dark_5_background">#1C1B1E</color>
|
||||
<color name="md_theme_dark_5_onBackground">#EEEEEE</color>
|
||||
<color name="md_theme_dark_5_surface">#1C1B20</color>
|
||||
<color name="md_theme_dark_5_onSurface">#EEEEEE</color>
|
||||
@@ -345,135 +357,195 @@
|
||||
<color name="md_theme_dark_5_outlineVariant">#00FF00</color>
|
||||
<color name="md_theme_dark_5_scrim">#00FF00</color>
|
||||
|
||||
<color name="seed_5">#c9000b</color>
|
||||
<color name="md_0_theme_light_primary">#C0000A</color>
|
||||
<color name="md_0_theme_light_onPrimary">#FFFFFF</color>
|
||||
<color name="md_0_theme_light_primaryContainer">#FFDAD5</color>
|
||||
<color name="md_0_theme_light_onPrimaryContainer">#410001</color>
|
||||
<color name="md_0_theme_light_secondary">#775652</color>
|
||||
<color name="md_0_theme_light_onSecondary">#FFFFFF</color>
|
||||
<color name="md_0_theme_light_secondaryContainer">#FFDAD5</color>
|
||||
<color name="md_0_theme_light_onSecondaryContainer">#2C1512</color>
|
||||
<color name="md_0_theme_light_tertiary">#705C2E</color>
|
||||
<color name="md_0_theme_light_onTertiary">#FFFFFF</color>
|
||||
<color name="md_0_theme_light_tertiaryContainer">#FCDFA6</color>
|
||||
<color name="md_0_theme_light_onTertiaryContainer">#261A00</color>
|
||||
<color name="md_0_theme_light_error">#BA1A1A</color>
|
||||
<color name="md_0_theme_light_errorContainer">#FFDAD6</color>
|
||||
<color name="md_0_theme_light_onError">#FFFFFF</color>
|
||||
<color name="md_0_theme_light_onErrorContainer">#410002</color>
|
||||
<color name="md_0_theme_light_background">#FFFBFF</color>
|
||||
<color name="md_0_theme_light_onBackground">#201A19</color>
|
||||
<color name="md_0_theme_light_surface">#FFFBFF</color>
|
||||
<color name="md_0_theme_light_onSurface">#201A19</color>
|
||||
<color name="md_0_theme_light_surfaceVariant">#F5DDDA</color>
|
||||
<color name="md_0_theme_light_onSurfaceVariant">#534341</color>
|
||||
<color name="md_0_theme_light_outline">#857370</color>
|
||||
<color name="md_0_theme_light_inverseOnSurface">#FBEEEC</color>
|
||||
<color name="md_0_theme_light_inverseSurface">#362F2E</color>
|
||||
<color name="md_0_theme_light_inversePrimary">#FFB4AA</color>
|
||||
<color name="md_0_theme_light_shadow">#000000</color>
|
||||
<color name="md_0_theme_light_surfaceTint">#C0000A</color>
|
||||
<color name="md_0_theme_light_outlineVariant">#D8C2BE</color>
|
||||
<color name="md_0_theme_light_scrim">#000000</color>
|
||||
<color name="md_0_theme_dark_primary">#FFB4AA</color>
|
||||
<color name="md_0_theme_dark_onPrimary">#690003</color>
|
||||
<color name="md_0_theme_dark_primaryContainer">#930005</color>
|
||||
<color name="md_0_theme_dark_onPrimaryContainer">#FFDAD5</color>
|
||||
<color name="md_0_theme_dark_secondary">#E7BDB7</color>
|
||||
<color name="md_0_theme_dark_onSecondary">#442926</color>
|
||||
<color name="md_0_theme_dark_secondaryContainer">#5D3F3B</color>
|
||||
<color name="md_0_theme_dark_onSecondaryContainer">#FFDAD5</color>
|
||||
<color name="md_0_theme_dark_tertiary">#DFC38C</color>
|
||||
<color name="md_0_theme_dark_onTertiary">#3E2E04</color>
|
||||
<color name="md_0_theme_dark_tertiaryContainer">#574419</color>
|
||||
<color name="md_0_theme_dark_onTertiaryContainer">#FCDFA6</color>
|
||||
<color name="md_0_theme_dark_error">#FFB4AB</color>
|
||||
<color name="md_0_theme_dark_errorContainer">#93000A</color>
|
||||
<color name="md_0_theme_dark_onError">#690005</color>
|
||||
<color name="md_0_theme_dark_onErrorContainer">#FFDAD6</color>
|
||||
<color name="md_0_theme_dark_background">#201A19</color>
|
||||
<color name="md_0_theme_dark_onBackground">#EDE0DE</color>
|
||||
<color name="md_0_theme_dark_surface">#201A19</color>
|
||||
<color name="md_0_theme_dark_onSurface">#EDE0DE</color>
|
||||
<color name="md_0_theme_dark_surfaceVariant">#534341</color>
|
||||
<color name="md_0_theme_dark_onSurfaceVariant">#D8C2BE</color>
|
||||
<color name="md_0_theme_dark_outline">#A08C89</color>
|
||||
<color name="md_0_theme_dark_inverseOnSurface">#201A19</color>
|
||||
<color name="md_0_theme_dark_inverseSurface">#EDE0DE</color>
|
||||
<color name="md_0_theme_dark_inversePrimary">#C0000A</color>
|
||||
<color name="md_0_theme_dark_shadow">#000000</color>
|
||||
<color name="md_0_theme_dark_surfaceTint">#FFB4AA</color>
|
||||
<color name="md_0_theme_dark_outlineVariant">#534341</color>
|
||||
<color name="md_0_theme_dark_scrim">#000000</color>
|
||||
<!-- theme 6 -->
|
||||
<color name="seed_6">#c9000b</color>
|
||||
<color name="md_theme_light_6_primary">#C0000A</color>
|
||||
<color name="md_theme_light_6_onPrimary">#FFFFFF</color>
|
||||
<color name="md_theme_light_6_primaryContainer">#FFDAD5</color>
|
||||
<color name="md_theme_light_6_onPrimaryContainer">#410001</color>
|
||||
<color name="md_theme_light_6_secondary">#775652</color>
|
||||
<color name="md_theme_light_6_onSecondary">#FFFFFF</color>
|
||||
<color name="md_theme_light_6_secondaryContainer">#FFDAD5</color>
|
||||
<color name="md_theme_light_6_onSecondaryContainer">#2C1512</color>
|
||||
<color name="md_theme_light_6_tertiary">#705C2E</color>
|
||||
<color name="md_theme_light_6_onTertiary">#FFFFFF</color>
|
||||
<color name="md_theme_light_6_tertiaryContainer">#FCDFA6</color>
|
||||
<color name="md_theme_light_6_onTertiaryContainer">#261A00</color>
|
||||
<color name="md_theme_light_6_error">#BA1A1A</color>
|
||||
<color name="md_theme_light_6_errorContainer">#FFDAD6</color>
|
||||
<color name="md_theme_light_6_onError">#FFFFFF</color>
|
||||
<color name="md_theme_light_6_onErrorContainer">#410002</color>
|
||||
<color name="md_theme_light_6_background">#FFFBFF</color>
|
||||
<color name="md_theme_light_6_onBackground">#201A19</color>
|
||||
<color name="md_theme_light_6_surface">#FFFBFF</color>
|
||||
<color name="md_theme_light_6_onSurface">#201A19</color>
|
||||
<color name="md_theme_light_6_surfaceVariant">#F5DDDA</color>
|
||||
<color name="md_theme_light_6_onSurfaceVariant">#534341</color>
|
||||
<color name="md_theme_light_6_outline">#857370</color>
|
||||
<color name="md_theme_light_6_inverseOnSurface">#FBEEEC</color>
|
||||
<color name="md_theme_light_6_inverseSurface">#362F2E</color>
|
||||
<color name="md_theme_light_6_inversePrimary">#FFB4AA</color>
|
||||
<color name="md_theme_light_6_shadow">#000000</color>
|
||||
<color name="md_theme_light_6_surfaceTint">#C0000A</color>
|
||||
<color name="md_theme_light_6_outlineVariant">#D8C2BE</color>
|
||||
<color name="md_theme_light_6_scrim">#000000</color>
|
||||
<color name="md_theme_dark_6_primary">#FFB4AA</color>
|
||||
<color name="md_theme_dark_6_onPrimary">#690003</color>
|
||||
<color name="md_theme_dark_6_primaryContainer">#930005</color>
|
||||
<color name="md_theme_dark_6_onPrimaryContainer">#FFDAD5</color>
|
||||
<color name="md_theme_dark_6_secondary">#E7BDB7</color>
|
||||
<color name="md_theme_dark_6_onSecondary">#442926</color>
|
||||
<color name="md_theme_dark_6_secondaryContainer">#5D3F3B</color>
|
||||
<color name="md_theme_dark_6_onSecondaryContainer">#FFDAD5</color>
|
||||
<color name="md_theme_dark_6_tertiary">#DFC38C</color>
|
||||
<color name="md_theme_dark_6_onTertiary">#3E2E04</color>
|
||||
<color name="md_theme_dark_6_tertiaryContainer">#574419</color>
|
||||
<color name="md_theme_dark_6_onTertiaryContainer">#FCDFA6</color>
|
||||
<color name="md_theme_dark_6_error">#FFB4AB</color>
|
||||
<color name="md_theme_dark_6_errorContainer">#93000A</color>
|
||||
<color name="md_theme_dark_6_onError">#690005</color>
|
||||
<color name="md_theme_dark_6_onErrorContainer">#FFDAD6</color>
|
||||
<color name="md_theme_dark_6_background">#201A19</color>
|
||||
<color name="md_theme_dark_6_onBackground">#EDE0DE</color>
|
||||
<color name="md_theme_dark_6_surface">#201A19</color>
|
||||
<color name="md_theme_dark_6_onSurface">#EDE0DE</color>
|
||||
<color name="md_theme_dark_6_surfaceVariant">#534341</color>
|
||||
<color name="md_theme_dark_6_onSurfaceVariant">#D8C2BE</color>
|
||||
<color name="md_theme_dark_6_outline">#A08C89</color>
|
||||
<color name="md_theme_dark_6_inverseOnSurface">#201A19</color>
|
||||
<color name="md_theme_dark_6_inverseSurface">#EDE0DE</color>
|
||||
<color name="md_theme_dark_6_inversePrimary">#C0000A</color>
|
||||
<color name="md_theme_dark_6_shadow">#000000</color>
|
||||
<color name="md_theme_dark_6_surfaceTint">#FFB4AA</color>
|
||||
<color name="md_theme_dark_6_outlineVariant">#534341</color>
|
||||
<color name="md_theme_dark_6_scrim">#000000</color>
|
||||
|
||||
<!-- theme 7 -->
|
||||
<color name="seed_7">#6750A4</color>
|
||||
<color name="md_theme_light_7_primary">#6750A4</color>
|
||||
<color name="md_theme_light_7_onPrimary">#FFFFFF</color>
|
||||
<color name="md_theme_light_7_primaryContainer">#E9DDFF</color>
|
||||
<color name="md_theme_light_7_onPrimaryContainer">#22005D</color>
|
||||
<color name="md_theme_light_7_secondary">#625B71</color>
|
||||
<color name="md_theme_light_7_onSecondary">#FFFFFF</color>
|
||||
<color name="md_theme_light_7_secondaryContainer">#E8DEF8</color>
|
||||
<color name="md_theme_light_7_onSecondaryContainer">#1E192B</color>
|
||||
<color name="md_theme_light_7_tertiary">#7E5260</color>
|
||||
<color name="md_theme_light_7_onTertiary">#FFFFFF</color>
|
||||
<color name="md_theme_light_7_tertiaryContainer">#FFD9E3</color>
|
||||
<color name="md_theme_light_7_onTertiaryContainer">#31101D</color>
|
||||
<color name="md_theme_light_7_error">#BA1A1A</color>
|
||||
<color name="md_theme_light_7_errorContainer">#FFDAD6</color>
|
||||
<color name="md_theme_light_7_onError">#FFFFFF</color>
|
||||
<color name="md_theme_light_7_onErrorContainer">#410002</color>
|
||||
<color name="md_theme_light_7_background">#FFFBFF</color>
|
||||
<color name="md_theme_light_7_onBackground">#1C1B1E</color>
|
||||
<color name="md_theme_light_7_surface">#FFFBFF</color>
|
||||
<color name="md_theme_light_7_onSurface">#1C1B1E</color>
|
||||
<color name="md_theme_light_7_surfaceVariant">#E7E0EB</color>
|
||||
<color name="md_theme_light_7_onSurfaceVariant">#49454E</color>
|
||||
<color name="md_theme_light_7_outline">#7A757F</color>
|
||||
<color name="md_theme_light_7_inverseOnSurface">#F4EFF4</color>
|
||||
<color name="md_theme_light_7_inverseSurface">#313033</color>
|
||||
<color name="md_theme_light_7_inversePrimary">#CFBCFF</color>
|
||||
<color name="md_theme_light_7_shadow">#000000</color>
|
||||
<color name="md_theme_light_7_surfaceTint">#6750A4</color>
|
||||
<color name="md_theme_light_7_outlineVariant">#CAC4CF</color>
|
||||
<color name="md_theme_light_7_scrim">#000000</color>
|
||||
<color name="md_theme_dark_7_primary">#CFBCFF</color>
|
||||
<color name="md_theme_dark_7_onPrimary">#381E72</color>
|
||||
<color name="md_theme_dark_7_primaryContainer">#4F378A</color>
|
||||
<color name="md_theme_dark_7_onPrimaryContainer">#E9DDFF</color>
|
||||
<color name="md_theme_dark_7_secondary">#CBC2DB</color>
|
||||
<color name="md_theme_dark_7_onSecondary">#332D41</color>
|
||||
<color name="md_theme_dark_7_secondaryContainer">#4A4458</color>
|
||||
<color name="md_theme_dark_7_onSecondaryContainer">#E8DEF8</color>
|
||||
<color name="md_theme_dark_7_tertiary">#EFB8C8</color>
|
||||
<color name="md_theme_dark_7_onTertiary">#4A2532</color>
|
||||
<color name="md_theme_dark_7_tertiaryContainer">#633B48</color>
|
||||
<color name="md_theme_dark_7_onTertiaryContainer">#FFD9E3</color>
|
||||
<color name="md_theme_dark_7_error">#FFB4AB</color>
|
||||
<color name="md_theme_dark_7_errorContainer">#93000A</color>
|
||||
<color name="md_theme_dark_7_onError">#690005</color>
|
||||
<color name="md_theme_dark_7_onErrorContainer">#FFDAD6</color>
|
||||
<color name="md_theme_dark_7_background">#1C1B1E</color>
|
||||
<color name="md_theme_dark_7_onBackground">#E6E1E6</color>
|
||||
<color name="md_theme_dark_7_surface">#1C1B1E</color>
|
||||
<color name="md_theme_dark_7_onSurface">#E6E1E6</color>
|
||||
<color name="md_theme_dark_7_surfaceVariant">#49454E</color>
|
||||
<color name="md_theme_dark_7_onSurfaceVariant">#CAC4CF</color>
|
||||
<color name="md_theme_dark_7_outline">#948F99</color>
|
||||
<color name="md_theme_dark_7_inverseOnSurface">#1C1B1E</color>
|
||||
<color name="md_theme_dark_7_inverseSurface">#E6E1E6</color>
|
||||
<color name="md_theme_dark_7_inversePrimary">#6750A4</color>
|
||||
<color name="md_theme_dark_7_shadow">#000000</color>
|
||||
<color name="md_theme_dark_7_surfaceTint">#CFBCFF</color>
|
||||
<color name="md_theme_dark_7_outlineVariant">#49454E</color>
|
||||
<color name="md_theme_dark_7_scrim">#000000</color>
|
||||
|
||||
<!-- theme 8 -->
|
||||
<color name="seed_8">#14AEA7</color>
|
||||
<color name="md_theme_light_8_primary">#006A65</color>
|
||||
<color name="md_theme_light_8_onPrimary">#FFFFFF</color>
|
||||
<color name="md_theme_light_8_primaryContainer">#70F7EF</color>
|
||||
<color name="md_theme_light_8_onPrimaryContainer">#00201E</color>
|
||||
<color name="md_theme_light_8_secondary">#4A6361</color>
|
||||
<color name="md_theme_light_8_onSecondary">#FFFFFF</color>
|
||||
<color name="md_theme_light_8_secondaryContainer">#CCE8E5</color>
|
||||
<color name="md_theme_light_8_onSecondaryContainer">#051F1E</color>
|
||||
<color name="md_theme_light_8_tertiary">#48607B</color>
|
||||
<color name="md_theme_light_8_onTertiary">#FFFFFF</color>
|
||||
<color name="md_theme_light_8_tertiaryContainer">#D0E4FF</color>
|
||||
<color name="md_theme_light_8_onTertiaryContainer">#001D34</color>
|
||||
<color name="md_theme_light_8_error">#BA1A1A</color>
|
||||
<color name="md_theme_light_8_errorContainer">#FFDAD6</color>
|
||||
<color name="md_theme_light_8_onError">#FFFFFF</color>
|
||||
<color name="md_theme_light_8_onErrorContainer">#410002</color>
|
||||
<color name="md_theme_light_8_background">#FAFDFB</color>
|
||||
<color name="md_theme_light_8_onBackground">#191C1C</color>
|
||||
<color name="md_theme_light_8_surface">#FAFDFB</color>
|
||||
<color name="md_theme_light_8_onSurface">#191C1C</color>
|
||||
<color name="md_theme_light_8_surfaceVariant">#DAE5E3</color>
|
||||
<color name="md_theme_light_8_onSurfaceVariant">#3F4948</color>
|
||||
<color name="md_theme_light_8_outline">#6F7978</color>
|
||||
<color name="md_theme_light_8_inverseOnSurface">#EFF1F0</color>
|
||||
<color name="md_theme_light_8_inverseSurface">#2D3131</color>
|
||||
<color name="md_theme_light_8_inversePrimary">#4FDAD2</color>
|
||||
<color name="md_theme_light_8_shadow">#000000</color>
|
||||
<color name="md_theme_light_8_surfaceTint">#006A65</color>
|
||||
<color name="md_theme_light_8_outlineVariant">#BEC9C7</color>
|
||||
<color name="md_theme_light_8_scrim">#000000</color>
|
||||
<color name="md_theme_dark_8_primary">#4FDAD2</color>
|
||||
<color name="md_theme_dark_8_onPrimary">#003734</color>
|
||||
<color name="md_theme_dark_8_primaryContainer">#00504C</color>
|
||||
<color name="md_theme_dark_8_onPrimaryContainer">#70F7EF</color>
|
||||
<color name="md_theme_dark_8_secondary">#B0CCC9</color>
|
||||
<color name="md_theme_dark_8_onSecondary">#1B3533</color>
|
||||
<color name="md_theme_dark_8_secondaryContainer">#324B49</color>
|
||||
<color name="md_theme_dark_8_onSecondaryContainer">#CCE8E5</color>
|
||||
<color name="md_theme_dark_8_tertiary">#B0C9E7</color>
|
||||
<color name="md_theme_dark_8_onTertiary">#19324A</color>
|
||||
<color name="md_theme_dark_8_tertiaryContainer">#314962</color>
|
||||
<color name="md_theme_dark_8_onTertiaryContainer">#D0E4FF</color>
|
||||
<color name="md_theme_dark_8_error">#FFB4AB</color>
|
||||
<color name="md_theme_dark_8_errorContainer">#93000A</color>
|
||||
<color name="md_theme_dark_8_onError">#690005</color>
|
||||
<color name="md_theme_dark_8_onErrorContainer">#FFDAD6</color>
|
||||
<color name="md_theme_dark_8_background">#191C1C</color>
|
||||
<color name="md_theme_dark_8_onBackground">#E0E3E2</color>
|
||||
<color name="md_theme_dark_8_surface">#191C1C</color>
|
||||
<color name="md_theme_dark_8_onSurface">#E0E3E2</color>
|
||||
<color name="md_theme_dark_8_surfaceVariant">#3F4948</color>
|
||||
<color name="md_theme_dark_8_onSurfaceVariant">#BEC9C7</color>
|
||||
<color name="md_theme_dark_8_outline">#889391</color>
|
||||
<color name="md_theme_dark_8_inverseOnSurface">#191C1C</color>
|
||||
<color name="md_theme_dark_8_inverseSurface">#E0E3E2</color>
|
||||
<color name="md_theme_dark_8_inversePrimary">#006A65</color>
|
||||
<color name="md_theme_dark_8_shadow">#000000</color>
|
||||
<color name="md_theme_dark_8_surfaceTint">#4FDAD2</color>
|
||||
<color name="md_theme_dark_8_outlineVariant">#3F4948</color>
|
||||
<color name="md_theme_dark_8_scrim">#000000</color>
|
||||
|
||||
|
||||
|
||||
<color name="seed_6">#6750A4</color>
|
||||
<color name="md_1_theme_light_primary">#6750A4</color>
|
||||
<color name="md_1_theme_light_onPrimary">#FFFFFF</color>
|
||||
<color name="md_1_theme_light_primaryContainer">#E9DDFF</color>
|
||||
<color name="md_1_theme_light_onPrimaryContainer">#22005D</color>
|
||||
<color name="md_1_theme_light_secondary">#625B71</color>
|
||||
<color name="md_1_theme_light_onSecondary">#FFFFFF</color>
|
||||
<color name="md_1_theme_light_secondaryContainer">#E8DEF8</color>
|
||||
<color name="md_1_theme_light_onSecondaryContainer">#1E192B</color>
|
||||
<color name="md_1_theme_light_tertiary">#7E5260</color>
|
||||
<color name="md_1_theme_light_onTertiary">#FFFFFF</color>
|
||||
<color name="md_1_theme_light_tertiaryContainer">#FFD9E3</color>
|
||||
<color name="md_1_theme_light_onTertiaryContainer">#31101D</color>
|
||||
<color name="md_1_theme_light_error">#BA1A1A</color>
|
||||
<color name="md_1_theme_light_errorContainer">#FFDAD6</color>
|
||||
<color name="md_1_theme_light_onError">#FFFFFF</color>
|
||||
<color name="md_1_theme_light_onErrorContainer">#410002</color>
|
||||
<color name="md_1_theme_light_background">#FFFBFF</color>
|
||||
<color name="md_1_theme_light_onBackground">#1C1B1E</color>
|
||||
<color name="md_1_theme_light_surface">#FFFBFF</color>
|
||||
<color name="md_1_theme_light_onSurface">#1C1B1E</color>
|
||||
<color name="md_1_theme_light_surfaceVariant">#E7E0EB</color>
|
||||
<color name="md_1_theme_light_onSurfaceVariant">#49454E</color>
|
||||
<color name="md_1_theme_light_outline">#7A757F</color>
|
||||
<color name="md_1_theme_light_inverseOnSurface">#F4EFF4</color>
|
||||
<color name="md_1_theme_light_inverseSurface">#313033</color>
|
||||
<color name="md_1_theme_light_inversePrimary">#CFBCFF</color>
|
||||
<color name="md_1_theme_light_shadow">#000000</color>
|
||||
<color name="md_1_theme_light_surfaceTint">#6750A4</color>
|
||||
<color name="md_1_theme_light_outlineVariant">#CAC4CF</color>
|
||||
<color name="md_1_theme_light_scrim">#000000</color>
|
||||
<color name="md_1_theme_dark_primary">#CFBCFF</color>
|
||||
<color name="md_1_theme_dark_onPrimary">#381E72</color>
|
||||
<color name="md_1_theme_dark_primaryContainer">#4F378A</color>
|
||||
<color name="md_1_theme_dark_onPrimaryContainer">#E9DDFF</color>
|
||||
<color name="md_1_theme_dark_secondary">#CBC2DB</color>
|
||||
<color name="md_1_theme_dark_onSecondary">#332D41</color>
|
||||
<color name="md_1_theme_dark_secondaryContainer">#4A4458</color>
|
||||
<color name="md_1_theme_dark_onSecondaryContainer">#E8DEF8</color>
|
||||
<color name="md_1_theme_dark_tertiary">#EFB8C8</color>
|
||||
<color name="md_1_theme_dark_onTertiary">#4A2532</color>
|
||||
<color name="md_1_theme_dark_tertiaryContainer">#633B48</color>
|
||||
<color name="md_1_theme_dark_onTertiaryContainer">#FFD9E3</color>
|
||||
<color name="md_1_theme_dark_error">#FFB4AB</color>
|
||||
<color name="md_1_theme_dark_errorContainer">#93000A</color>
|
||||
<color name="md_1_theme_dark_onError">#690005</color>
|
||||
<color name="md_1_theme_dark_onErrorContainer">#FFDAD6</color>
|
||||
<color name="md_1_theme_dark_background">#1C1B1E</color>
|
||||
<color name="md_1_theme_dark_onBackground">#E6E1E6</color>
|
||||
<color name="md_1_theme_dark_surface">#1C1B1E</color>
|
||||
<color name="md_1_theme_dark_onSurface">#E6E1E6</color>
|
||||
<color name="md_1_theme_dark_surfaceVariant">#49454E</color>
|
||||
<color name="md_1_theme_dark_onSurfaceVariant">#CAC4CF</color>
|
||||
<color name="md_1_theme_dark_outline">#948F99</color>
|
||||
<color name="md_1_theme_dark_inverseOnSurface">#1C1B1E</color>
|
||||
<color name="md_1_theme_dark_inverseSurface">#E6E1E6</color>
|
||||
<color name="md_1_theme_dark_inversePrimary">#6750A4</color>
|
||||
<color name="md_1_theme_dark_shadow">#000000</color>
|
||||
<color name="md_1_theme_dark_surfaceTint">#CFBCFF</color>
|
||||
<color name="md_1_theme_dark_outlineVariant">#49454E</color>
|
||||
<color name="md_1_theme_dark_scrim">#000000</color>
|
||||
<color name="CustomColor1">#93DB00</color>
|
||||
<color name="CustomColor2">#68AF86</color>
|
||||
<color name="CustomColor3">#0096AE</color>
|
||||
<color name="CustomColor4">#000000</color>
|
||||
<color name="light_blue_50">#FFE1F5FE</color>
|
||||
<color name="light_blue_200">#FF81D4FA</color>
|
||||
<color name="light_blue_600">#FF039BE5</color>
|
||||
<color name="light_blue_900">#FF01579B</color>
|
||||
</resources>
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
<string name="sub_background_color_select">Subtitle Background Color</string>
|
||||
<string name="sub_window_color_select">Subtitle Window Color</string>
|
||||
<string name="sub_window_color_info">"The subtitle window is the part left and right from them. (where the background isn\'t)"</string>
|
||||
<string name="sub_color_info"><b>Note:</b> Changing Subtitle formatting only works with Soft-Subbed Sources such as Zoro!</string>
|
||||
<string name="sub_color_info"><b>Note:</b> Changing above settings only affects Soft-Subtitles!</string>
|
||||
<string name="sub_font_select">Subtitle Font</string>
|
||||
<string name="subtitle_font_size">Subtitle Size</string>
|
||||
|
||||
@@ -569,9 +569,6 @@
|
||||
|
||||
\n\nNote: Direct downloads are also possible without a manager but it\'s not recommended.</string>
|
||||
|
||||
<string name="question_8">How to download Manga Chapters?</string>
|
||||
<string name="answer_8">It is yet not possible to download chapters in Dantotsu but this feature will be implemented soon.</string>
|
||||
|
||||
<string name="question_9">How to enable NSFW content?</string>
|
||||
<string name="answer_9">You can enable nsfw content by enabling 18+ contents from this [link](https://anilist.co/settings/media).</string>
|
||||
|
||||
@@ -648,5 +645,6 @@
|
||||
<string name="add_widget">Add widget</string>
|
||||
<string name="app_widget_description">This is an app widget description</string>
|
||||
<string name="airing_image">Airing Image</string>
|
||||
<string name="anime_downloads">animeDownloads</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="NavBarText">
|
||||
<item name="android:textAllCaps">true</item>
|
||||
<item name="android:fontFamily">@font/poppins_bold</item>
|
||||
@@ -14,7 +15,6 @@
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
<style name="Suffix">
|
||||
<item name="android:height">54dp</item>
|
||||
<item name="android:fontFamily">@font/poppins_bold</item>
|
||||
@@ -37,19 +37,22 @@
|
||||
<item name="background">@id/bg</item>
|
||||
<item name="cornerFamily">rounded</item>
|
||||
</style>
|
||||
|
||||
<style name="roundedImageView" parent="">
|
||||
<item name="cornerFamily">rounded</item>
|
||||
<item name="cornerSize">16dp</item>
|
||||
</style>
|
||||
|
||||
<style name="MySnackbar" parent="Widget.MaterialComponents.Snackbar">
|
||||
<item name="android:layout_marginLeft">16dp</item>
|
||||
<item name="android:layout_marginRight">16dp</item>
|
||||
<item name="android:background">@drawable/round_corner</item>
|
||||
</style>
|
||||
|
||||
<string name="MySnackBarText" parent="Widget.MaterialComponents.Snackbar.TextView" translatable="false">
|
||||
<item name="android:textColor">@color/bg_opp</item>
|
||||
</string>
|
||||
|
||||
|
||||
<style name="fontTooltip" parent="Widget.Material3.Tooltip">
|
||||
<item name="android:padding">8dp</item>
|
||||
<item name="android:textAppearance">@style/Suffix</item>
|
||||
@@ -62,15 +65,17 @@
|
||||
<item name="android:textColor">?attr/colorOnBackground</item>
|
||||
<item name="android:popupBackground">?attr/colorSurface</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:windowBackground">@drawable/shape_corner_16dp</item>
|
||||
<item name="android:windowIsFloating">true</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
</style>
|
||||
</style>
|
||||
|
||||
<style name="BottomNavBar" parent="">
|
||||
<!-- set background color to transparent -->
|
||||
<item name="android:background">@android:color/transparent</item>
|
||||
</style>
|
||||
<style name="ThemeOverlay_Dantotsu_MediaRouter" parent="ThemeOverlay.AppCompat">
|
||||
</style>
|
||||
</resources>
|
||||
@@ -198,93 +198,6 @@
|
||||
<item name="colorPrimaryInverse">@color/md_theme_light_4_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Monochrome" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/bg_black</item>
|
||||
<item name="colorOnPrimary">@color/bg_white</item>
|
||||
<item name="colorPrimaryContainer">@color/bg_black</item>
|
||||
<item name="colorOnPrimaryContainer">@color/bg_white</item>
|
||||
<item name="colorSecondary">@color/bg_black</item>
|
||||
<item name="colorOnSecondary">@color/bg_white</item>
|
||||
<item name="colorSecondaryContainer">@color/bg_black</item>
|
||||
<item name="colorOnSecondaryContainer">@color/bg_white</item>
|
||||
<item name="colorTertiary">@color/bg_black</item>
|
||||
<item name="colorOnTertiary">@color/bg_white</item>
|
||||
<item name="colorTertiaryContainer">@color/bg_black</item>
|
||||
<item name="colorOnTertiaryContainer">@color/bg_white</item>
|
||||
<item name="colorError">@color/bg_black</item>
|
||||
<item name="colorErrorContainer">@color/bg_black</item>
|
||||
<item name="colorOnError">@color/bg_white</item>
|
||||
<item name="colorOnErrorContainer">@color/bg_white</item>
|
||||
<item name="android:colorBackground">@color/bg_white</item>
|
||||
<item name="colorOnBackground">@color/bg_black</item>
|
||||
<item name="colorSurface">@color/bg_white</item>
|
||||
<item name="colorOnSurface">@color/bg_black</item>
|
||||
<item name="colorSurfaceVariant">@color/bg_white</item>
|
||||
<item name="colorOnSurfaceVariant">@color/bg_black</item>
|
||||
<item name="colorOutline">@color/bg_black</item>
|
||||
<item name="colorOnSurfaceInverse">@color/bg_black</item>
|
||||
<item name="colorSurfaceInverse">@color/bg_white</item>
|
||||
<item name="colorPrimaryInverse">@color/bg_white</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Red" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/md_0_theme_light_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_0_theme_light_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/md_0_theme_light_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/md_0_theme_light_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/md_0_theme_light_secondary</item>
|
||||
<item name="colorOnSecondary">@color/md_0_theme_light_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/md_0_theme_light_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/md_0_theme_light_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/md_0_theme_light_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/md_0_theme_light_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/md_0_theme_light_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/md_0_theme_light_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/md_0_theme_light_error</item>
|
||||
<item name="colorErrorContainer">@color/md_0_theme_light_errorContainer</item>
|
||||
<item name="colorOnError">@color/md_0_theme_light_onError</item>
|
||||
<item name="colorOnErrorContainer">@color/md_0_theme_light_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/md_0_theme_light_background</item>
|
||||
<item name="colorOnBackground">@color/md_0_theme_light_onBackground</item>
|
||||
<item name="colorSurface">@color/md_0_theme_light_surface</item>
|
||||
<item name="colorOnSurface">@color/md_0_theme_light_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/md_0_theme_light_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/md_0_theme_light_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/md_0_theme_light_outline</item>
|
||||
<item name="colorOnSurfaceInverse">@color/md_0_theme_light_inverseOnSurface</item>
|
||||
<item name="colorSurfaceInverse">@color/md_0_theme_light_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_0_theme_light_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Lavender" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/md_1_theme_light_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_1_theme_light_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/md_1_theme_light_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/md_1_theme_light_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/md_1_theme_light_secondary</item>
|
||||
<item name="colorOnSecondary">@color/md_1_theme_light_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/md_1_theme_light_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/md_1_theme_light_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/md_1_theme_light_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/md_1_theme_light_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/md_1_theme_light_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/md_1_theme_light_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/md_1_theme_light_error</item>
|
||||
<item name="colorErrorContainer">@color/md_1_theme_light_errorContainer</item>
|
||||
<item name="colorOnError">@color/md_1_theme_light_onError</item>
|
||||
<item name="colorOnErrorContainer">@color/md_1_theme_light_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/md_1_theme_light_background</item>
|
||||
<item name="colorOnBackground">@color/md_1_theme_light_onBackground</item>
|
||||
<item name="colorSurface">@color/md_1_theme_light_surface</item>
|
||||
<item name="colorOnSurface">@color/md_1_theme_light_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/md_1_theme_light_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/md_1_theme_light_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/md_1_theme_light_outline</item>
|
||||
<item name="colorOnSurfaceInverse">@color/md_1_theme_light_inverseOnSurface</item>
|
||||
<item name="colorSurfaceInverse">@color/md_1_theme_light_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_1_theme_light_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Saikou" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/md_theme_light_5_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_theme_light_5_onPrimary</item>
|
||||
@@ -314,6 +227,122 @@
|
||||
<item name="colorPrimaryInverse">@color/md_theme_light_5_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Red" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/md_theme_light_6_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_theme_light_6_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/md_theme_light_6_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/md_theme_light_6_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/md_theme_light_6_secondary</item>
|
||||
<item name="colorOnSecondary">@color/md_theme_light_6_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/md_theme_light_6_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/md_theme_light_6_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/md_theme_light_6_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/md_theme_light_6_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/md_theme_light_6_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/md_theme_light_6_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/md_theme_light_6_error</item>
|
||||
<item name="colorErrorContainer">@color/md_theme_light_6_errorContainer</item>
|
||||
<item name="colorOnError">@color/md_theme_light_6_onError</item>
|
||||
<item name="colorOnErrorContainer">@color/md_theme_light_6_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/md_theme_light_6_background</item>
|
||||
<item name="colorOnBackground">@color/md_theme_light_6_onBackground</item>
|
||||
<item name="colorSurface">@color/md_theme_light_6_surface</item>
|
||||
<item name="colorOnSurface">@color/md_theme_light_6_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/md_theme_light_6_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/md_theme_light_6_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/md_theme_light_6_outline</item>
|
||||
<item name="colorOnSurfaceInverse">@color/md_theme_light_6_inverseOnSurface</item>
|
||||
<item name="colorSurfaceInverse">@color/md_theme_light_6_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_theme_light_6_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Lavender" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/md_theme_light_7_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_theme_light_7_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/md_theme_light_7_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/md_theme_light_7_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/md_theme_light_7_secondary</item>
|
||||
<item name="colorOnSecondary">@color/md_theme_light_7_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/md_theme_light_7_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/md_theme_light_7_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/md_theme_light_7_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/md_theme_light_7_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/md_theme_light_7_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/md_theme_light_7_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/md_theme_light_7_error</item>
|
||||
<item name="colorErrorContainer">@color/md_theme_light_7_errorContainer</item>
|
||||
<item name="colorOnError">@color/md_theme_light_7_onError</item>
|
||||
<item name="colorOnErrorContainer">@color/md_theme_light_7_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/md_theme_light_7_background</item>
|
||||
<item name="colorOnBackground">@color/md_theme_light_7_onBackground</item>
|
||||
<item name="colorSurface">@color/md_theme_light_7_surface</item>
|
||||
<item name="colorOnSurface">@color/md_theme_light_7_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/md_theme_light_7_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/md_theme_light_7_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/md_theme_light_7_outline</item>
|
||||
<item name="colorOnSurfaceInverse">@color/md_theme_light_7_inverseOnSurface</item>
|
||||
<item name="colorSurfaceInverse">@color/md_theme_light_7_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_theme_light_7_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Emerald" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/md_theme_light_8_primary</item>
|
||||
<item name="colorOnPrimary">@color/md_theme_light_8_onPrimary</item>
|
||||
<item name="colorPrimaryContainer">@color/md_theme_light_8_primaryContainer</item>
|
||||
<item name="colorOnPrimaryContainer">@color/md_theme_light_8_onPrimaryContainer</item>
|
||||
<item name="colorSecondary">@color/md_theme_light_8_secondary</item>
|
||||
<item name="colorOnSecondary">@color/md_theme_light_8_onSecondary</item>
|
||||
<item name="colorSecondaryContainer">@color/md_theme_light_8_secondaryContainer</item>
|
||||
<item name="colorOnSecondaryContainer">@color/md_theme_light_8_onSecondaryContainer</item>
|
||||
<item name="colorTertiary">@color/md_theme_light_8_tertiary</item>
|
||||
<item name="colorOnTertiary">@color/md_theme_light_8_onTertiary</item>
|
||||
<item name="colorTertiaryContainer">@color/md_theme_light_8_tertiaryContainer</item>
|
||||
<item name="colorOnTertiaryContainer">@color/md_theme_light_8_onTertiaryContainer</item>
|
||||
<item name="colorError">@color/md_theme_light_8_error</item>
|
||||
<item name="colorErrorContainer">@color/md_theme_light_8_errorContainer</item>
|
||||
<item name="colorOnError">@color/md_theme_light_8_onError</item>
|
||||
<item name="colorOnErrorContainer">@color/md_theme_light_8_onErrorContainer</item>
|
||||
<item name="android:colorBackground">@color/md_theme_light_8_background</item>
|
||||
<item name="colorOnBackground">@color/md_theme_light_8_onBackground</item>
|
||||
<item name="colorSurface">@color/md_theme_light_8_surface</item>
|
||||
<item name="colorOnSurface">@color/md_theme_light_8_onSurface</item>
|
||||
<item name="colorSurfaceVariant">@color/md_theme_light_8_surfaceVariant</item>
|
||||
<item name="colorOnSurfaceVariant">@color/md_theme_light_8_onSurfaceVariant</item>
|
||||
<item name="colorOutline">@color/md_theme_light_8_outline</item>
|
||||
<item name="colorOnSurfaceInverse">@color/md_theme_light_8_inverseOnSurface</item>
|
||||
<item name="colorSurfaceInverse">@color/md_theme_light_8_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_theme_light_8_inversePrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.Monochrome" parent="Theme.Base">
|
||||
<item name="colorPrimary">@color/bg_black</item>
|
||||
<item name="colorOnPrimary">@color/bg_white</item>
|
||||
<item name="colorPrimaryContainer">@color/bg_black</item>
|
||||
<item name="colorOnPrimaryContainer">@color/bg_white</item>
|
||||
<item name="colorSecondary">@color/bg_black</item>
|
||||
<item name="colorOnSecondary">@color/bg_white</item>
|
||||
<item name="colorSecondaryContainer">@color/bg_black</item>
|
||||
<item name="colorOnSecondaryContainer">@color/bg_white</item>
|
||||
<item name="colorTertiary">@color/bg_black</item>
|
||||
<item name="colorOnTertiary">@color/bg_white</item>
|
||||
<item name="colorTertiaryContainer">@color/bg_black</item>
|
||||
<item name="colorOnTertiaryContainer">@color/bg_white</item>
|
||||
<item name="colorError">@color/bg_black</item>
|
||||
<item name="colorErrorContainer">@color/bg_black</item>
|
||||
<item name="colorOnError">@color/bg_white</item>
|
||||
<item name="colorOnErrorContainer">@color/bg_white</item>
|
||||
<item name="android:colorBackground">@color/bg_white</item>
|
||||
<item name="colorOnBackground">@color/bg_black</item>
|
||||
<item name="colorSurface">@color/bg_white</item>
|
||||
<item name="colorOnSurface">@color/bg_black</item>
|
||||
<item name="colorSurfaceVariant">@color/bg_white</item>
|
||||
<item name="colorOnSurfaceVariant">@color/bg_black</item>
|
||||
<item name="colorOutline">@color/bg_black</item>
|
||||
<item name="colorOnSurfaceInverse">@color/bg_black</item>
|
||||
<item name="colorSurfaceInverse">@color/bg_white</item>
|
||||
<item name="colorPrimaryInverse">@color/bg_white</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dantotsu.AppWidgetContainerParent" parent="@android:style/Theme.DeviceDefault">
|
||||
<!-- Radius of the outer bound of widgets to make the rounded corners -->
|
||||
<item name="appWidgetRadius">16dp</item>
|
||||
|
||||
Reference in New Issue
Block a user