mirror of
https://github.com/rebelonion/Dantotsu.git
synced 2026-01-16 11:13:55 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1eb85d4419 | ||
|
|
20bea76e6c | ||
|
|
866bd3b3a9 | ||
|
|
3567b8dced | ||
|
|
d109914537 | ||
|
|
da4d55a9a8 | ||
|
|
63526c6ed3 | ||
|
|
dc165fa6bc | ||
|
|
dc959796e6 |
@@ -21,7 +21,7 @@ android {
|
||||
minSdk 23
|
||||
targetSdk 34
|
||||
versionCode ((System.currentTimeMillis() / 60000).toInteger())
|
||||
versionName "0.1.1"
|
||||
versionName "0.1.5"
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ dependencies {
|
||||
implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
|
||||
implementation 'com.alexvasilkov:gesture-views:2.8.3'
|
||||
implementation 'com.github.VipulOG:ebook-reader:0.1.6'
|
||||
implementation 'androidx.paging:paging-runtime-ktx:3.2.1'
|
||||
|
||||
// string matching
|
||||
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-feature
|
||||
android:name="android.software.leanback"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
@@ -10,7 +17,8 @@
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32" />
|
||||
|
||||
<!-- For background jobs -->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
@@ -47,7 +55,7 @@
|
||||
android:theme="@style/Theme.Dantotsu"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:ignore="AllowBackup"
|
||||
>
|
||||
android:banner="@drawable/ic_banner_foreground">
|
||||
<activity
|
||||
android:name="ani.dantotsu.media.novel.novelreader.NovelReaderActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
@@ -206,9 +214,12 @@
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.Main" />
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="eu.kanade.tachiyomi.extension.manga.util.MangaExtensionInstallActivity"
|
||||
|
||||
@@ -1,21 +1,30 @@
|
||||
package ani.dantotsu
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
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.RequiresApi
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.animation.doOnEnd
|
||||
import androidx.core.app.ActivityCompat
|
||||
@@ -41,8 +50,10 @@ import ani.dantotsu.media.MediaDetailsActivity
|
||||
import ani.dantotsu.others.CustomBottomDialog
|
||||
import ani.dantotsu.parsers.AnimeSources
|
||||
import ani.dantotsu.parsers.MangaSources
|
||||
import ani.dantotsu.settings.SettingsActivity
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.subcriptions.Subscription.Companion.startSubscription
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.SoftBreakAddsNewLinePlugin
|
||||
@@ -53,6 +64,8 @@ import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import nl.joery.animatedbottombar.AnimatedBottomBar
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.Serializable
|
||||
|
||||
@@ -63,15 +76,26 @@ class MainActivity : AppCompatActivity() {
|
||||
private var load = false
|
||||
|
||||
private var uiSettings = UserInterfaceSettings()
|
||||
private val animeExtensionManager: AnimeExtensionManager by injectLazy()
|
||||
private val mangaExtensionManager: MangaExtensionManager by injectLazy()
|
||||
|
||||
private val animeExtensionManager: AnimeExtensionManager = Injekt.get()
|
||||
private val mangaExtensionManager: MangaExtensionManager = Injekt.get()
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
val bottomBar = findViewById<AnimatedBottomBar>(R.id.navbar)
|
||||
val backgroundDrawable = bottomBar.background as GradientDrawable
|
||||
val currentColor = backgroundDrawable.color?.defaultColor ?: 0
|
||||
val semiTransparentColor = (currentColor and 0x00FFFFFF) or 0x80000000.toInt()
|
||||
backgroundDrawable.setColor(semiTransparentColor)
|
||||
bottomBar.background = backgroundDrawable
|
||||
}
|
||||
|
||||
|
||||
val animeScope = CoroutineScope(Dispatchers.Default)
|
||||
animeScope.launch {
|
||||
animeExtensionManager.findAvailableExtensions()
|
||||
@@ -228,6 +252,11 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
|
||||
//ViewPager
|
||||
private class ViewPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
|
||||
FragmentStateAdapter(fragmentManager, lifecycle) {
|
||||
@@ -244,4 +273,4 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package ani.dantotsu.aniyomi.anime.custom
|
||||
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import ani.dantotsu.media.manga.MangaCache
|
||||
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
||||
import tachiyomi.core.preference.PreferenceStore
|
||||
@@ -28,6 +29,9 @@ class AppModule(val app: Application) : InjektModule {
|
||||
|
||||
addSingletonFactory { MangaExtensionManager(app) }
|
||||
|
||||
val sharedPreferences = app.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
|
||||
addSingleton(sharedPreferences)
|
||||
|
||||
addSingletonFactory {
|
||||
Json {
|
||||
ignoreUnknownKeys = true
|
||||
|
||||
@@ -16,7 +16,7 @@ fun updateProgress(media: Media, number: String) {
|
||||
if (Anilist.userid != null) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val a = number.toFloatOrNull()?.roundToInt()
|
||||
if (a != media.userProgress) {
|
||||
if ((a?:0) > (media.userProgress?:0)) {
|
||||
Anilist.mutation.editList(
|
||||
media.id,
|
||||
a,
|
||||
|
||||
@@ -7,10 +7,12 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import ani.dantotsu.logError
|
||||
import ani.dantotsu.logger
|
||||
import ani.dantotsu.startMainActivity
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
|
||||
class Login : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
val data: Uri? = intent?.data
|
||||
logger(data.toString())
|
||||
try {
|
||||
|
||||
@@ -6,10 +6,12 @@ import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import ani.dantotsu.loadMedia
|
||||
import ani.dantotsu.startMainActivity
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
|
||||
class UrlMedia : Activity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
var id: Int? = intent?.extras?.getInt("media", 0) ?: 0
|
||||
var isMAL = false
|
||||
var continueMedia = true
|
||||
|
||||
@@ -1,21 +1,32 @@
|
||||
package ani.dantotsu.connections.discord
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application.getProcessName
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.connections.discord.Discord.saveToken
|
||||
import ani.dantotsu.startMainActivity
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
|
||||
class Login : AppCompatActivity() {
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
val process = getProcessName()
|
||||
if (packageName != process) WebView.setDataDirectorySuffix(process)
|
||||
}
|
||||
setContentView(R.layout.activity_discord)
|
||||
|
||||
val webView = findViewById<WebView>(R.id.discordWebview)
|
||||
|
||||
webView.apply {
|
||||
settings.javaScriptEnabled = true
|
||||
settings.databaseEnabled = true
|
||||
|
||||
@@ -7,12 +7,14 @@ import androidx.lifecycle.lifecycleScope
|
||||
import ani.dantotsu.*
|
||||
import ani.dantotsu.connections.mal.MAL.clientId
|
||||
import ani.dantotsu.connections.mal.MAL.saveResponse
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class Login : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
try {
|
||||
val data: Uri = intent?.data
|
||||
?: throw Exception(getString(R.string.mal_login_uri_not_found))
|
||||
|
||||
@@ -63,6 +63,7 @@ object Helper {
|
||||
SubtitleType.VTT -> MimeTypes.TEXT_VTT
|
||||
SubtitleType.ASS -> MimeTypes.TEXT_SSA
|
||||
SubtitleType.SRT -> MimeTypes.APPLICATION_SUBRIP
|
||||
SubtitleType.UNKNOWN -> MimeTypes.TEXT_SSA
|
||||
}
|
||||
)
|
||||
.build()
|
||||
|
||||
@@ -17,6 +17,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import ani.dantotsu.media.GenreActivity
|
||||
import ani.dantotsu.MediaPageTransformer
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.databinding.ItemAnimePageBinding
|
||||
import ani.dantotsu.loadData
|
||||
@@ -31,6 +32,8 @@ import ani.dantotsu.setSlideUp
|
||||
import ani.dantotsu.settings.SettingsDialogFragment
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.statusBarHeight
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
|
||||
class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHolder>() {
|
||||
val ready = MutableLiveData(false)
|
||||
@@ -49,6 +52,13 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
|
||||
binding = holder.binding
|
||||
trendingViewPager = binding.animeTrendingViewPager
|
||||
|
||||
val textInputLayout = holder.itemView.findViewById<TextInputLayout>(R.id.animeSearchBar)
|
||||
val currentColor = textInputLayout.boxBackgroundColor
|
||||
val semiTransparentColor = (currentColor and 0x00FFFFFF) or 0x80000000.toInt()
|
||||
textInputLayout.boxBackgroundColor = semiTransparentColor
|
||||
val materialCardView = holder.itemView.findViewById<MaterialCardView>(R.id.animeUserAvatarContainer)
|
||||
materialCardView.setCardBackgroundColor(semiTransparentColor)
|
||||
|
||||
binding.animeTitleContainer.updatePadding(top = statusBarHeight)
|
||||
|
||||
if (uiSettings.smallView) binding.animeTrendingContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
@@ -163,6 +173,7 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
|
||||
fun updateAvatar() {
|
||||
if (Anilist.avatar != null && ready.value == true) {
|
||||
binding.animeUserAvatar.loadImage(Anilist.avatar)
|
||||
binding.animeUserAvatar.imageTintList = null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import ani.dantotsu.media.GenreActivity
|
||||
import ani.dantotsu.MediaPageTransformer
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.databinding.ItemMangaPageBinding
|
||||
import ani.dantotsu.loadData
|
||||
@@ -30,6 +31,8 @@ import ani.dantotsu.setSlideUp
|
||||
import ani.dantotsu.settings.SettingsDialogFragment
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.statusBarHeight
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
|
||||
class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHolder>() {
|
||||
val ready = MutableLiveData(false)
|
||||
@@ -48,6 +51,13 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
|
||||
binding = holder.binding
|
||||
trendingViewPager = binding.mangaTrendingViewPager
|
||||
|
||||
val textInputLayout = holder.itemView.findViewById<TextInputLayout>(R.id.mangaSearchBar)
|
||||
val currentColor = textInputLayout.boxBackgroundColor
|
||||
val semiTransparentColor = (currentColor and 0x00FFFFFF) or 0x80000000.toInt()
|
||||
textInputLayout.boxBackgroundColor = semiTransparentColor
|
||||
val materialCardView = holder.itemView.findViewById<MaterialCardView>(R.id.mangaUserAvatarContainer)
|
||||
materialCardView.setCardBackgroundColor(semiTransparentColor)
|
||||
|
||||
binding.mangaTitleContainer.updatePadding(top = statusBarHeight)
|
||||
|
||||
if (uiSettings.smallView) binding.mangaTrendingContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
@@ -153,6 +163,7 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
|
||||
fun updateAvatar() {
|
||||
if (Anilist.avatar != null && ready.value == true) {
|
||||
binding.mangaUserAvatar.loadImage(Anilist.avatar)
|
||||
binding.mangaUserAvatar.imageTintList = null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,12 @@ import ani.dantotsu.isOnline
|
||||
import ani.dantotsu.navBarHeight
|
||||
import ani.dantotsu.startMainActivity
|
||||
import ani.dantotsu.statusBarHeight
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
|
||||
class NoInternet : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
|
||||
val binding = ActivityNoInternetBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
@@ -15,6 +15,7 @@ import androidx.recyclerview.widget.GridLayoutManager
|
||||
import ani.dantotsu.*
|
||||
import ani.dantotsu.databinding.ActivityAuthorBinding
|
||||
import ani.dantotsu.others.getSerialized
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -28,6 +29,7 @@ class AuthorActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityAuthorBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
||||
@@ -2,7 +2,10 @@ package ani.dantotsu.media
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
@@ -11,7 +14,10 @@ import androidx.lifecycle.lifecycleScope
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.Refresh
|
||||
import ani.dantotsu.databinding.ActivityListBinding
|
||||
import ani.dantotsu.loadData
|
||||
import ani.dantotsu.media.user.ListViewPagerAdapter
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -27,10 +33,40 @@ class CalendarActivity : AppCompatActivity() {
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityListBinding.inflate(layoutInflater)
|
||||
|
||||
|
||||
val typedValue = TypedValue()
|
||||
theme.resolveAttribute(com.google.android.material.R.attr.colorOnPrimary, typedValue, true)
|
||||
val primaryColor = typedValue.data
|
||||
val typedValue2 = TypedValue()
|
||||
theme.resolveAttribute(com.google.android.material.R.attr.colorPrimary, typedValue2, true)
|
||||
val primaryTextColor = typedValue2.data
|
||||
val typedValue3 = TypedValue()
|
||||
theme.resolveAttribute(com.google.android.material.R.attr.colorSecondary, typedValue3, true)
|
||||
val secondaryColor = typedValue3.data
|
||||
|
||||
window.statusBarColor = primaryColor
|
||||
window.navigationBarColor = primaryColor
|
||||
binding.listTabLayout.setBackgroundColor(primaryColor)
|
||||
binding.listAppBar.setBackgroundColor(primaryColor)
|
||||
binding.listTitle.setTextColor(primaryTextColor)
|
||||
binding.listTabLayout.setTabTextColors(primaryTextColor, primaryTextColor)
|
||||
binding.listTabLayout.setSelectedTabIndicatorColor(primaryTextColor)
|
||||
val uiSettings = loadData<UserInterfaceSettings>("ui_settings") ?: UserInterfaceSettings()
|
||||
if (!uiSettings.immersiveMode) {
|
||||
this.window.statusBarColor =
|
||||
ContextCompat.getColor(this, R.color.nav_bg_inv)
|
||||
binding.root.fitsSystemWindows = true
|
||||
|
||||
}else{
|
||||
binding.root.fitsSystemWindows = false
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
||||
}
|
||||
setContentView(binding.root)
|
||||
|
||||
window.statusBarColor = ContextCompat.getColor(this, R.color.nav_bg)
|
||||
binding.listTitle.setText(R.string.release_calendar)
|
||||
binding.listSort.visibility = View.GONE
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import ani.dantotsu.databinding.ActivityCharacterBinding
|
||||
import ani.dantotsu.others.ImageViewDialog
|
||||
import ani.dantotsu.others.getSerialized
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -33,6 +34,7 @@ class CharacterDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChang
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityCharacterBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import ani.dantotsu.initActivity
|
||||
import ani.dantotsu.loadData
|
||||
import ani.dantotsu.navBarHeight
|
||||
import ani.dantotsu.statusBarHeight
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -25,6 +26,7 @@ class GenreActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityGenreBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
initActivity(this)
|
||||
|
||||
@@ -113,6 +113,10 @@ data class Media(
|
||||
this.relation = mediaEdge.relationType?.toString()
|
||||
}
|
||||
|
||||
fun mainName() = nameMAL ?: name ?: nameRomaji
|
||||
fun mainName() = name ?: nameMAL ?: nameRomaji
|
||||
fun mangaName() = if (countryOfOrigin != "JP") mainName() else nameRomaji
|
||||
}
|
||||
}
|
||||
|
||||
object MediaSingleton {
|
||||
var media: Media? = null
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ import ani.dantotsu.saveData
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.snackString
|
||||
import ani.dantotsu.statusBarHeight
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import com.flaviofaria.kenburnsview.RandomTransitionGenerator
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.navigation.NavigationBarView
|
||||
@@ -71,6 +72,7 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityMediaBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
screenWidth = resources.displayMetrics.widthPixels.toFloat()
|
||||
@@ -79,7 +81,8 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||
|
||||
initActivity(this)
|
||||
uiSettings = loadData<UserInterfaceSettings>("ui_settings") ?: UserInterfaceSettings()
|
||||
if (!uiSettings.immersiveMode) this.window.statusBarColor = ContextCompat.getColor(this, R.color.nav_bg_inv)
|
||||
if (!uiSettings.immersiveMode) this.window.statusBarColor =
|
||||
ContextCompat.getColor(this, R.color.nav_bg_inv)
|
||||
|
||||
binding.mediaBanner.updateLayoutParams { height += statusBarHeight }
|
||||
binding.mediaBannerNoKen.updateLayoutParams { height += statusBarHeight }
|
||||
@@ -101,10 +104,14 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||
|
||||
if (uiSettings.bannerAnimations) {
|
||||
val adi = AccelerateDecelerateInterpolator()
|
||||
val generator = RandomTransitionGenerator((10000 + 15000 * (uiSettings.animationSpeed)).toLong(), adi)
|
||||
val generator = RandomTransitionGenerator(
|
||||
(10000 + 15000 * (uiSettings.animationSpeed)).toLong(),
|
||||
adi
|
||||
)
|
||||
binding.mediaBanner.setTransitionGenerator(generator)
|
||||
}
|
||||
val banner = if (uiSettings.bannerAnimations) binding.mediaBanner else binding.mediaBannerNoKen
|
||||
val banner =
|
||||
if (uiSettings.bannerAnimations) binding.mediaBanner else binding.mediaBannerNoKen
|
||||
val viewPager = binding.mediaViewPager
|
||||
tabLayout = binding.mediaTab as NavigationBarView
|
||||
viewPager.isUserInputEnabled = false
|
||||
@@ -162,13 +169,28 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||
R.drawable.ic_round_favorite_24
|
||||
)
|
||||
)
|
||||
val typedValue = TypedValue()
|
||||
this.theme.resolveAttribute(
|
||||
com.google.android.material.R.attr.colorSecondary,
|
||||
typedValue,
|
||||
true
|
||||
)
|
||||
val color = typedValue.data
|
||||
val typedValue2 = TypedValue()
|
||||
this.theme.resolveAttribute(
|
||||
com.google.android.material.R.attr.colorSecondary,
|
||||
typedValue2,
|
||||
true
|
||||
)
|
||||
val color2 = typedValue.data
|
||||
|
||||
PopImageButton(
|
||||
scope,
|
||||
binding.mediaFav,
|
||||
R.drawable.ic_round_favorite_24,
|
||||
R.drawable.ic_round_favorite_border_24,
|
||||
R.color.nav_tab,
|
||||
R.color.fav,
|
||||
R.color.bg_opp,
|
||||
R.color.violet_400,//TODO: Change to colorSecondary
|
||||
media.isFav
|
||||
) {
|
||||
media.isFav = it
|
||||
@@ -180,17 +202,36 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||
null
|
||||
}
|
||||
|
||||
@SuppressLint("ResourceType")
|
||||
fun total() {
|
||||
val text = SpannableStringBuilder().apply {
|
||||
val white = ContextCompat.getColor(this@MediaDetailsActivity, R.color.bg_opp)
|
||||
val typedValue = TypedValue()
|
||||
this@MediaDetailsActivity.theme.resolveAttribute(
|
||||
com.google.android.material.R.attr.colorOnBackground,
|
||||
typedValue,
|
||||
true
|
||||
)
|
||||
val white = typedValue.data
|
||||
if (media.userStatus != null) {
|
||||
append(if (media.anime != null) getString(R.string.watched_num) else getString(R.string.read_num))
|
||||
val typedValue = TypedValue()
|
||||
theme.resolveAttribute(com.google.android.material.R.attr.colorSecondary, typedValue, true)
|
||||
theme.resolveAttribute(
|
||||
com.google.android.material.R.attr.colorSecondary,
|
||||
typedValue,
|
||||
true
|
||||
)
|
||||
bold { color(typedValue.data) { append("${media.userProgress}") } }
|
||||
append(if (media.anime != null) getString(R.string.episodes_out_of) else getString(R.string.chapters_out_of))
|
||||
append(
|
||||
if (media.anime != null) getString(R.string.episodes_out_of) else getString(
|
||||
R.string.chapters_out_of
|
||||
)
|
||||
)
|
||||
} else {
|
||||
append(if (media.anime != null) getString(R.string.episodes_total_of) else getString(R.string.chapters_total_of))
|
||||
append(
|
||||
if (media.anime != null) getString(R.string.episodes_total_of) else getString(
|
||||
R.string.chapters_total_of
|
||||
)
|
||||
)
|
||||
}
|
||||
if (media.anime != null) {
|
||||
if (media.anime!!.nextAiringEpisode != null) {
|
||||
@@ -206,8 +247,12 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||
|
||||
fun progress() {
|
||||
val statuses: Array<String> = resources.getStringArray(R.array.status)
|
||||
val statusStrings = if (media.manga==null) resources.getStringArray(R.array.status_anime) else resources.getStringArray(R.array.status_manga)
|
||||
val userStatus = if(media.userStatus != null) statusStrings[statuses.indexOf(media.userStatus)] else statusStrings[0]
|
||||
val statusStrings =
|
||||
if (media.manga == null) resources.getStringArray(R.array.status_anime) else resources.getStringArray(
|
||||
R.array.status_manga
|
||||
)
|
||||
val userStatus =
|
||||
if (media.userStatus != null) statusStrings[statuses.indexOf(media.userStatus)] else statusStrings[0]
|
||||
|
||||
if (media.userStatus != null) {
|
||||
binding.mediaTotal.visibility = View.VISIBLE
|
||||
@@ -234,7 +279,7 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||
if (it != null) {
|
||||
media = it
|
||||
scope.launch {
|
||||
if(media.isFav!=favButton?.clicked) favButton?.clicked()
|
||||
if (media.isFav != favButton?.clicked) favButton?.clicked()
|
||||
}
|
||||
|
||||
binding.mediaNotify.setOnClickListener {
|
||||
@@ -258,10 +303,15 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||
|
||||
tabLayout.menu.clear()
|
||||
if (media.anime != null) {
|
||||
viewPager.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle, SupportedMedia.ANIME)
|
||||
viewPager.adapter =
|
||||
ViewPagerAdapter(supportFragmentManager, lifecycle, SupportedMedia.ANIME)
|
||||
tabLayout.inflateMenu(R.menu.anime_menu_detail)
|
||||
} else if (media.manga != null) {
|
||||
viewPager.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle, if(media.format=="NOVEL") SupportedMedia.NOVEL else SupportedMedia.MANGA)
|
||||
viewPager.adapter = ViewPagerAdapter(
|
||||
supportFragmentManager,
|
||||
lifecycle,
|
||||
if (media.format == "NOVEL") SupportedMedia.NOVEL else SupportedMedia.MANGA
|
||||
)
|
||||
tabLayout.inflateMenu(R.menu.manga_menu_detail)
|
||||
anime = false
|
||||
}
|
||||
@@ -303,9 +353,10 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||
|
||||
private fun selectFromID(id: Int) {
|
||||
when (id) {
|
||||
R.id.info -> {
|
||||
R.id.info -> {
|
||||
selected = 0
|
||||
}
|
||||
|
||||
R.id.watch, R.id.read -> {
|
||||
selected = 1
|
||||
}
|
||||
@@ -329,9 +380,10 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
private enum class SupportedMedia{
|
||||
private enum class SupportedMedia {
|
||||
ANIME, MANGA, NOVEL
|
||||
}
|
||||
|
||||
//ViewPager
|
||||
private class ViewPagerAdapter(
|
||||
fragmentManager: FragmentManager,
|
||||
@@ -342,13 +394,14 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||
|
||||
override fun getItemCount(): Int = 2
|
||||
|
||||
override fun createFragment(position: Int): Fragment = when (position){
|
||||
override fun createFragment(position: Int): Fragment = when (position) {
|
||||
0 -> MediaInfoFragment()
|
||||
1 -> when(media){
|
||||
1 -> when (media) {
|
||||
SupportedMedia.ANIME -> AnimeWatchFragment()
|
||||
SupportedMedia.MANGA -> MangaReadFragment()
|
||||
SupportedMedia.NOVEL -> NovelReadFragment()
|
||||
}
|
||||
|
||||
else -> MediaInfoFragment()
|
||||
}
|
||||
}
|
||||
@@ -363,27 +416,45 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||
if (mMaxScrollSize == 0) mMaxScrollSize = appBar.totalScrollRange
|
||||
val percentage = abs(i) * 100 / mMaxScrollSize
|
||||
|
||||
binding.mediaCover.visibility = if (binding.mediaCover.scaleX == 0f) View.GONE else View.VISIBLE
|
||||
binding.mediaCover.visibility =
|
||||
if (binding.mediaCover.scaleX == 0f) View.GONE else View.VISIBLE
|
||||
val duration = (200 * uiSettings.animationSpeed).toLong()
|
||||
val typedValue = TypedValue()
|
||||
this@MediaDetailsActivity.theme.resolveAttribute(
|
||||
com.google.android.material.R.attr.colorSecondary,
|
||||
typedValue,
|
||||
true
|
||||
)
|
||||
val color = typedValue.data
|
||||
if (percentage >= percent && !isCollapsed) {
|
||||
isCollapsed = true
|
||||
ObjectAnimator.ofFloat(binding.mediaTitle, "translationX", 0f).setDuration(duration).start()
|
||||
ObjectAnimator.ofFloat(binding.mediaAccessContainer, "translationX", screenWidth).setDuration(duration).start()
|
||||
ObjectAnimator.ofFloat(binding.mediaCover, "translationX", screenWidth).setDuration(duration).start()
|
||||
ObjectAnimator.ofFloat(binding.mediaCollapseContainer, "translationX", screenWidth).setDuration(duration).start()
|
||||
ObjectAnimator.ofFloat(binding.mediaTitle, "translationX", 0f).setDuration(duration)
|
||||
.start()
|
||||
ObjectAnimator.ofFloat(binding.mediaAccessContainer, "translationX", screenWidth)
|
||||
.setDuration(duration).start()
|
||||
ObjectAnimator.ofFloat(binding.mediaCover, "translationX", screenWidth)
|
||||
.setDuration(duration).start()
|
||||
ObjectAnimator.ofFloat(binding.mediaCollapseContainer, "translationX", screenWidth)
|
||||
.setDuration(duration).start()
|
||||
binding.mediaBanner.pause()
|
||||
if (!uiSettings.immersiveMode) this.window.statusBarColor = ContextCompat.getColor(this, R.color.nav_bg)
|
||||
if (!uiSettings.immersiveMode) this.window.statusBarColor = color
|
||||
}
|
||||
if (percentage <= percent && isCollapsed) {
|
||||
isCollapsed = false
|
||||
ObjectAnimator.ofFloat(binding.mediaTitle, "translationX", -screenWidth).setDuration(duration).start()
|
||||
ObjectAnimator.ofFloat(binding.mediaAccessContainer, "translationX", 0f).setDuration(duration).start()
|
||||
ObjectAnimator.ofFloat(binding.mediaCover, "translationX", 0f).setDuration(duration).start()
|
||||
ObjectAnimator.ofFloat(binding.mediaCollapseContainer, "translationX", 0f).setDuration(duration).start()
|
||||
ObjectAnimator.ofFloat(binding.mediaTitle, "translationX", -screenWidth)
|
||||
.setDuration(duration).start()
|
||||
ObjectAnimator.ofFloat(binding.mediaAccessContainer, "translationX", 0f)
|
||||
.setDuration(duration).start()
|
||||
ObjectAnimator.ofFloat(binding.mediaCover, "translationX", 0f).setDuration(duration)
|
||||
.start()
|
||||
ObjectAnimator.ofFloat(binding.mediaCollapseContainer, "translationX", 0f)
|
||||
.setDuration(duration).start()
|
||||
if (uiSettings.bannerAnimations) binding.mediaBanner.resume()
|
||||
if (!uiSettings.immersiveMode) this.window.statusBarColor = ContextCompat.getColor(this, R.color.nav_bg_inv)
|
||||
if (!uiSettings.immersiveMode) this.window.statusBarColor = color
|
||||
}
|
||||
if (percentage == 1 && model.scrolledToTop.value != false) model.scrolledToTop.postValue(false)
|
||||
if (percentage == 1 && model.scrolledToTop.value != false) model.scrolledToTop.postValue(
|
||||
false
|
||||
)
|
||||
if (percentage == 0 && model.scrolledToTop.value != true) model.scrolledToTop.postValue(true)
|
||||
}
|
||||
|
||||
@@ -425,8 +496,10 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||
ObjectAnimator.ofFloat(image, "scaleX", 1f, 0f).setDuration(69).start()
|
||||
ObjectAnimator.ofFloat(image, "scaleY", 1f, 0f).setDuration(100).start()
|
||||
delay(100)
|
||||
|
||||
if (clicked) {
|
||||
ObjectAnimator.ofArgb(image,
|
||||
ObjectAnimator.ofArgb(
|
||||
image,
|
||||
"ColorFilter",
|
||||
ContextCompat.getColor(context, c1),
|
||||
ContextCompat.getColor(context, c2)
|
||||
@@ -439,17 +512,19 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||
ObjectAnimator.ofFloat(image, "scaleX", 1.5f, 1f).setDuration(100).start()
|
||||
ObjectAnimator.ofFloat(image, "scaleY", 1.5f, 1f).setDuration(100).start()
|
||||
delay(200)
|
||||
if (clicked) ObjectAnimator.ofArgb(
|
||||
image,
|
||||
"ColorFilter",
|
||||
ContextCompat.getColor(context, c2),
|
||||
ContextCompat.getColor(context, c1)
|
||||
).setDuration(200).start()
|
||||
if (clicked) {
|
||||
ObjectAnimator.ofArgb(
|
||||
image,
|
||||
"ColorFilter",
|
||||
ContextCompat.getColor(context, c2),
|
||||
ContextCompat.getColor(context, c1)
|
||||
).setDuration(200).start()
|
||||
}
|
||||
}
|
||||
|
||||
fun enabled(enabled: Boolean) {
|
||||
disabled = !enabled
|
||||
image.alpha = if(disabled) 0.33f else 1f
|
||||
image.alpha = if (disabled) 0.33f else 1f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package ani.dantotsu.media
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import androidx.fragment.app.FragmentManager
|
||||
@@ -40,6 +42,8 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class MediaDetailsViewModel : ViewModel() {
|
||||
val scrolledToTop = MutableLiveData(true)
|
||||
@@ -48,11 +52,13 @@ class MediaDetailsViewModel : ViewModel() {
|
||||
saveData("$id-select", data, activity)
|
||||
}
|
||||
|
||||
|
||||
fun loadSelected(media: Media): Selected {
|
||||
val sharedPreferences = Injekt.get<SharedPreferences>()
|
||||
val data = loadData<Selected>("${media.id}-select") ?: Selected().let {
|
||||
it.sourceIndex = if (media.isAdult) 0 else when (media.anime != null) {
|
||||
true -> loadData("settings_def_anime_source_s_r") ?: 0
|
||||
else -> loadData("settings_def_manga_source_s_r") ?: 0
|
||||
true -> sharedPreferences.getInt("settings_def_anime_source_s_r", 0)
|
||||
else -> sharedPreferences.getInt(("settings_def_manga_source_s_r"), 0)
|
||||
}
|
||||
it.preferDub = loadData("settings_prefer_dub") ?: false
|
||||
saveSelected(media.id, it)
|
||||
|
||||
@@ -15,6 +15,7 @@ import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.databinding.BottomSheetMediaListSmallBinding
|
||||
import ani.dantotsu.connections.mal.MAL
|
||||
import ani.dantotsu.others.getSerialized
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@@ -16,6 +16,7 @@ import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.connections.anilist.AnilistSearch
|
||||
import ani.dantotsu.connections.anilist.SearchResults
|
||||
import ani.dantotsu.databinding.ActivitySearchBinding
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
@@ -37,6 +38,7 @@ class SearchActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivitySearchBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
initActivity(this)
|
||||
|
||||
@@ -15,6 +15,7 @@ import androidx.recyclerview.widget.GridLayoutManager
|
||||
import ani.dantotsu.*
|
||||
import ani.dantotsu.databinding.ActivityStudioBinding
|
||||
import ani.dantotsu.others.getSerialized
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -28,6 +29,7 @@ class StudioActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityStudioBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
||||
48
app/src/main/java/ani/dantotsu/media/SubtitleDownloader.kt
Normal file
48
app/src/main/java/ani/dantotsu/media/SubtitleDownloader.kt
Normal file
@@ -0,0 +1,48 @@
|
||||
package ani.dantotsu.media
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Environment
|
||||
import ani.dantotsu.parsers.SubtitleType
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import okhttp3.Request
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.FileInputStream
|
||||
|
||||
class SubtitleDownloader {
|
||||
|
||||
companion object {
|
||||
//doesn't really download the subtitles -\_(o_o)_/-
|
||||
suspend fun downloadSubtitles(context: Context, url: String): SubtitleType =
|
||||
withContext(Dispatchers.IO) {
|
||||
// Initialize the NetworkHelper instance. Replace this line based on how you usually initialize it
|
||||
val networkHelper = Injekt.get<NetworkHelper>()
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.build()
|
||||
|
||||
val response = networkHelper.client.newCall(request).execute()
|
||||
|
||||
// Check if response is successful
|
||||
if (response.isSuccessful) {
|
||||
val responseBody = response.body?.string()
|
||||
|
||||
|
||||
val subtitleType = when {
|
||||
responseBody?.contains("[Script Info]") == true -> SubtitleType.ASS
|
||||
responseBody?.contains("WEBVTT") == true -> SubtitleType.VTT
|
||||
else -> SubtitleType.SRT
|
||||
}
|
||||
|
||||
return@withContext subtitleType
|
||||
} else {
|
||||
return@withContext SubtitleType.UNKNOWN
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package ani.dantotsu.media.anime
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
||||
@@ -53,6 +53,7 @@ import androidx.media3.datasource.okhttp.OkHttpDataSource
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
||||
import androidx.media3.exoplayer.util.EventLogger
|
||||
import androidx.media3.session.MediaSession
|
||||
import androidx.media3.ui.*
|
||||
import androidx.media3.ui.CaptionStyleCompat.*
|
||||
@@ -65,6 +66,7 @@ import ani.dantotsu.connections.updateProgress
|
||||
import ani.dantotsu.databinding.ActivityExoplayerBinding
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.media.MediaDetailsViewModel
|
||||
import ani.dantotsu.media.SubtitleDownloader
|
||||
import ani.dantotsu.others.AniSkip
|
||||
import ani.dantotsu.others.AniSkip.getType
|
||||
import ani.dantotsu.others.Download.download
|
||||
@@ -74,6 +76,7 @@ import ani.dantotsu.parsers.*
|
||||
import ani.dantotsu.settings.PlayerSettings
|
||||
import ani.dantotsu.settings.PlayerSettingsActivity
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.android.material.slider.Slider
|
||||
import com.lagradost.nicehttp.ignoreAllSSLErrors
|
||||
@@ -81,12 +84,15 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.internal.immutableListOf
|
||||
import java.util.*
|
||||
import java.util.concurrent.*
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
@UnstableApi
|
||||
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
|
||||
class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
@@ -183,7 +189,10 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
val displayCutout = window.decorView.rootWindowInsets.displayCutout
|
||||
if (displayCutout != null) {
|
||||
if (displayCutout.boundingRects.size > 0) {
|
||||
notchHeight = min(displayCutout.boundingRects[0].width(), displayCutout.boundingRects[0].height())
|
||||
notchHeight = min(
|
||||
displayCutout.boundingRects[0].width(),
|
||||
displayCutout.boundingRects[0].height()
|
||||
)
|
||||
checkNotch()
|
||||
}
|
||||
}
|
||||
@@ -194,101 +203,104 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
private fun checkNotch() {
|
||||
if (notchHeight != 0) {
|
||||
val orientation = resources.configuration.orientation
|
||||
playerView.findViewById<View>(R.id.exo_controller_margin).updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
marginStart = notchHeight
|
||||
marginEnd = notchHeight
|
||||
topMargin = 0
|
||||
} else {
|
||||
topMargin = notchHeight
|
||||
marginStart = 0
|
||||
marginEnd = 0
|
||||
playerView.findViewById<View>(R.id.exo_controller_margin)
|
||||
.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
marginStart = notchHeight
|
||||
marginEnd = notchHeight
|
||||
topMargin = 0
|
||||
} else {
|
||||
topMargin = notchHeight
|
||||
marginStart = 0
|
||||
marginEnd = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
playerView.findViewById<View>(androidx.media3.ui.R.id.exo_buffering).translationY =
|
||||
(if (orientation == Configuration.ORIENTATION_LANDSCAPE) 0 else (notchHeight + 8f.px)).dp
|
||||
exoBrightnessCont.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
marginEnd = if (orientation == Configuration.ORIENTATION_LANDSCAPE) notchHeight else 0
|
||||
marginEnd =
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) notchHeight else 0
|
||||
}
|
||||
exoVolumeCont.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
marginStart = if (orientation == Configuration.ORIENTATION_LANDSCAPE) notchHeight else 0
|
||||
marginStart =
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) notchHeight else 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupSubFormatting(playerView: PlayerView, settings: PlayerSettings) {
|
||||
val primaryColor = when (settings.primaryColor) {
|
||||
0 -> Color.BLACK
|
||||
1 -> Color.DKGRAY
|
||||
2 -> Color.GRAY
|
||||
3 -> Color.LTGRAY
|
||||
4 -> Color.WHITE
|
||||
5 -> Color.RED
|
||||
6 -> Color.YELLOW
|
||||
7 -> Color.GREEN
|
||||
8 -> Color.CYAN
|
||||
9 -> Color.BLUE
|
||||
10 -> Color.MAGENTA
|
||||
11 -> Color.TRANSPARENT
|
||||
0 -> Color.BLACK
|
||||
1 -> Color.DKGRAY
|
||||
2 -> Color.GRAY
|
||||
3 -> Color.LTGRAY
|
||||
4 -> Color.WHITE
|
||||
5 -> Color.RED
|
||||
6 -> Color.YELLOW
|
||||
7 -> Color.GREEN
|
||||
8 -> Color.CYAN
|
||||
9 -> Color.BLUE
|
||||
10 -> Color.MAGENTA
|
||||
11 -> Color.TRANSPARENT
|
||||
else -> Color.WHITE
|
||||
}
|
||||
val secondaryColor = when (settings.secondaryColor) {
|
||||
0 -> Color.BLACK
|
||||
1 -> Color.DKGRAY
|
||||
2 -> Color.GRAY
|
||||
3 -> Color.LTGRAY
|
||||
4 -> Color.WHITE
|
||||
5 -> Color.RED
|
||||
6 -> Color.YELLOW
|
||||
7 -> Color.GREEN
|
||||
8 -> Color.CYAN
|
||||
9 -> Color.BLUE
|
||||
10 -> Color.MAGENTA
|
||||
11 -> Color.TRANSPARENT
|
||||
0 -> Color.BLACK
|
||||
1 -> Color.DKGRAY
|
||||
2 -> Color.GRAY
|
||||
3 -> Color.LTGRAY
|
||||
4 -> Color.WHITE
|
||||
5 -> Color.RED
|
||||
6 -> Color.YELLOW
|
||||
7 -> Color.GREEN
|
||||
8 -> Color.CYAN
|
||||
9 -> Color.BLUE
|
||||
10 -> Color.MAGENTA
|
||||
11 -> Color.TRANSPARENT
|
||||
else -> Color.BLACK
|
||||
}
|
||||
val outline = when (settings.outline) {
|
||||
0 -> EDGE_TYPE_OUTLINE // Normal
|
||||
1 -> EDGE_TYPE_DEPRESSED // Shine
|
||||
2 -> EDGE_TYPE_DROP_SHADOW // Drop shadow
|
||||
3 -> EDGE_TYPE_NONE // No outline
|
||||
0 -> EDGE_TYPE_OUTLINE // Normal
|
||||
1 -> EDGE_TYPE_DEPRESSED // Shine
|
||||
2 -> EDGE_TYPE_DROP_SHADOW // Drop shadow
|
||||
3 -> EDGE_TYPE_NONE // No outline
|
||||
else -> EDGE_TYPE_OUTLINE // Normal
|
||||
}
|
||||
val subBackground = when (settings.subBackground) {
|
||||
0 -> Color.TRANSPARENT
|
||||
1 -> Color.BLACK
|
||||
2 -> Color.DKGRAY
|
||||
3 -> Color.GRAY
|
||||
4 -> Color.LTGRAY
|
||||
5 -> Color.WHITE
|
||||
6 -> Color.RED
|
||||
7 -> Color.YELLOW
|
||||
8 -> Color.GREEN
|
||||
9 -> Color.CYAN
|
||||
10 -> Color.BLUE
|
||||
11 -> Color.MAGENTA
|
||||
0 -> Color.TRANSPARENT
|
||||
1 -> Color.BLACK
|
||||
2 -> Color.DKGRAY
|
||||
3 -> Color.GRAY
|
||||
4 -> Color.LTGRAY
|
||||
5 -> Color.WHITE
|
||||
6 -> Color.RED
|
||||
7 -> Color.YELLOW
|
||||
8 -> Color.GREEN
|
||||
9 -> Color.CYAN
|
||||
10 -> Color.BLUE
|
||||
11 -> Color.MAGENTA
|
||||
else -> Color.TRANSPARENT
|
||||
}
|
||||
val subWindow = when (settings.subWindow) {
|
||||
0 -> Color.TRANSPARENT
|
||||
1 -> Color.BLACK
|
||||
2 -> Color.DKGRAY
|
||||
3 -> Color.GRAY
|
||||
4 -> Color.LTGRAY
|
||||
5 -> Color.WHITE
|
||||
6 -> Color.RED
|
||||
7 -> Color.YELLOW
|
||||
8 -> Color.GREEN
|
||||
9 -> Color.CYAN
|
||||
10 -> Color.BLUE
|
||||
11 -> Color.MAGENTA
|
||||
0 -> Color.TRANSPARENT
|
||||
1 -> Color.BLACK
|
||||
2 -> Color.DKGRAY
|
||||
3 -> Color.GRAY
|
||||
4 -> Color.LTGRAY
|
||||
5 -> Color.WHITE
|
||||
6 -> Color.RED
|
||||
7 -> Color.YELLOW
|
||||
8 -> Color.GREEN
|
||||
9 -> Color.CYAN
|
||||
10 -> Color.BLUE
|
||||
11 -> Color.MAGENTA
|
||||
else -> Color.TRANSPARENT
|
||||
}
|
||||
val font = when (settings.font) {
|
||||
0 -> ResourcesCompat.getFont(this, R.font.poppins_semi_bold)
|
||||
1 -> ResourcesCompat.getFont(this, R.font.poppins_bold)
|
||||
2 -> ResourcesCompat.getFont(this, R.font.poppins)
|
||||
3 -> ResourcesCompat.getFont(this, R.font.poppins_thin)
|
||||
0 -> ResourcesCompat.getFont(this, R.font.poppins_semi_bold)
|
||||
1 -> ResourcesCompat.getFont(this, R.font.poppins_bold)
|
||||
2 -> ResourcesCompat.getFont(this, R.font.poppins)
|
||||
3 -> ResourcesCompat.getFont(this, R.font.poppins_thin)
|
||||
else -> ResourcesCompat.getFont(this, R.font.poppins_semi_bold)
|
||||
}
|
||||
playerView.subtitleView?.setStyle(
|
||||
@@ -305,6 +317,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityExoplayerBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
@@ -316,8 +329,18 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
finishAndRemoveTask()
|
||||
}
|
||||
|
||||
settings = loadData("player_settings") ?: PlayerSettings().apply { saveData("player_settings", this) }
|
||||
uiSettings = loadData("ui_settings") ?: UserInterfaceSettings().apply { saveData("ui_settings", this) }
|
||||
settings = loadData("player_settings") ?: PlayerSettings().apply {
|
||||
saveData(
|
||||
"player_settings",
|
||||
this
|
||||
)
|
||||
}
|
||||
uiSettings = loadData("ui_settings") ?: UserInterfaceSettings().apply {
|
||||
saveData(
|
||||
"ui_settings",
|
||||
this
|
||||
)
|
||||
}
|
||||
|
||||
playerView = findViewById(R.id.player_view)
|
||||
exoQuality = playerView.findViewById(R.id.exo_quality)
|
||||
@@ -360,17 +383,20 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
requestedOrientation = rotation
|
||||
it.visibility = View.GONE
|
||||
}
|
||||
orientationListener = object : OrientationEventListener(this, SensorManager.SENSOR_DELAY_UI) {
|
||||
override fun onOrientationChanged(orientation: Int) {
|
||||
if (orientation in 45..135) {
|
||||
if (rotation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE) exoRotate.visibility = View.VISIBLE
|
||||
rotation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
|
||||
} else if (orientation in 225..315) {
|
||||
if (rotation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) exoRotate.visibility = View.VISIBLE
|
||||
rotation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||
orientationListener =
|
||||
object : OrientationEventListener(this, SensorManager.SENSOR_DELAY_UI) {
|
||||
override fun onOrientationChanged(orientation: Int) {
|
||||
if (orientation in 45..135) {
|
||||
if (rotation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE) exoRotate.visibility =
|
||||
View.VISIBLE
|
||||
rotation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
|
||||
} else if (orientation in 225..315) {
|
||||
if (rotation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) exoRotate.visibility =
|
||||
View.VISIBLE
|
||||
rotation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
orientationListener?.enable()
|
||||
}
|
||||
|
||||
@@ -378,7 +404,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
|
||||
|
||||
playerView.subtitleView?.alpha = when (settings.subtitles) {
|
||||
true -> 1f
|
||||
true -> 1f
|
||||
false -> 0f
|
||||
}
|
||||
val fontSize = settings.fontSize.toFloat()
|
||||
@@ -401,7 +427,10 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
isTimeStampsLoaded = true
|
||||
exoSkipOpEd.visibility = if (it != null) {
|
||||
val adGroups = it.flatMap {
|
||||
listOf(it.interval.startTime.toLong() * 1000, it.interval.endTime.toLong() * 1000)
|
||||
listOf(
|
||||
it.interval.startTime.toLong() * 1000,
|
||||
it.interval.endTime.toLong() * 1000
|
||||
)
|
||||
}.toLongArray()
|
||||
val playedAdGroups = it.flatMap {
|
||||
listOf(false, false)
|
||||
@@ -441,7 +470,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
|
||||
// Picture-in-picture
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
pipEnabled = packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) && settings.pip
|
||||
pipEnabled =
|
||||
packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) && settings.pip
|
||||
if (pipEnabled) {
|
||||
exoPip.visibility = View.VISIBLE
|
||||
exoPip.setOnClickListener {
|
||||
@@ -456,7 +486,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
val container = playerView.findViewById<View>(R.id.exo_controller_cont)
|
||||
val screen = playerView.findViewById<View>(R.id.exo_black_screen)
|
||||
val lockButton = playerView.findViewById<ImageButton>(R.id.exo_unlock)
|
||||
val timeline = playerView.findViewById<ExtendedTimeBar>(androidx.media3.ui.R.id.exo_progress)
|
||||
val timeline =
|
||||
playerView.findViewById<ExtendedTimeBar>(androidx.media3.ui.R.id.exo_progress)
|
||||
playerView.findViewById<ImageButton>(R.id.exo_lock).setOnClickListener {
|
||||
locked = true
|
||||
screen.visibility = View.GONE
|
||||
@@ -496,17 +527,22 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
dialog.findViewById<Slider>(R.id.seekbar).addOnChangeListener { _, value, _ ->
|
||||
settings.skipTime = value.toInt()
|
||||
saveData(player, settings)
|
||||
playerView.findViewById<TextView>(R.id.exo_skip_time).text = settings.skipTime.toString()
|
||||
dialog.findViewById<TextView>(R.id.seekbar_value).text = settings.skipTime.toString()
|
||||
playerView.findViewById<TextView>(R.id.exo_skip_time).text =
|
||||
settings.skipTime.toString()
|
||||
dialog.findViewById<TextView>(R.id.seekbar_value).text =
|
||||
settings.skipTime.toString()
|
||||
}
|
||||
dialog.findViewById<Slider>(R.id.seekbar).addOnSliderTouchListener(object : Slider.OnSliderTouchListener {
|
||||
override fun onStartTrackingTouch(slider: Slider) {}
|
||||
override fun onStopTrackingTouch(slider: Slider) {
|
||||
dialog.dismiss()
|
||||
}
|
||||
})
|
||||
dialog.findViewById<TextView>(R.id.seekbar_title).text = getString(R.string.skip_time)
|
||||
dialog.findViewById<TextView>(R.id.seekbar_value).text = settings.skipTime.toString()
|
||||
dialog.findViewById<Slider>(R.id.seekbar)
|
||||
.addOnSliderTouchListener(object : Slider.OnSliderTouchListener {
|
||||
override fun onStartTrackingTouch(slider: Slider) {}
|
||||
override fun onStopTrackingTouch(slider: Slider) {
|
||||
dialog.dismiss()
|
||||
}
|
||||
})
|
||||
dialog.findViewById<TextView>(R.id.seekbar_title).text =
|
||||
getString(R.string.skip_time)
|
||||
dialog.findViewById<TextView>(R.id.seekbar_value).text =
|
||||
settings.skipTime.toString()
|
||||
@Suppress("DEPRECATION")
|
||||
dialog.window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
dialog.show()
|
||||
@@ -521,7 +557,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
val brightnessRunnable = Runnable {
|
||||
if (exoBrightnessCont.alpha == 1f)
|
||||
lifecycleScope.launch {
|
||||
ObjectAnimator.ofFloat(exoBrightnessCont, "alpha", 1f, 0f).setDuration(gestureSpeed).start()
|
||||
ObjectAnimator.ofFloat(exoBrightnessCont, "alpha", 1f, 0f)
|
||||
.setDuration(gestureSpeed).start()
|
||||
delay(gestureSpeed)
|
||||
exoBrightnessCont.visibility = View.GONE
|
||||
checkNotch()
|
||||
@@ -530,7 +567,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
val volumeRunnable = Runnable {
|
||||
if (exoVolumeCont.alpha == 1f)
|
||||
lifecycleScope.launch {
|
||||
ObjectAnimator.ofFloat(exoVolumeCont, "alpha", 1f, 0f).setDuration(gestureSpeed).start()
|
||||
ObjectAnimator.ofFloat(exoVolumeCont, "alpha", 1f, 0f).setDuration(gestureSpeed)
|
||||
.start()
|
||||
delay(gestureSpeed)
|
||||
exoVolumeCont.visibility = View.GONE
|
||||
checkNotch()
|
||||
@@ -548,25 +586,65 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
fun handleController() {
|
||||
if (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) !isInPictureInPictureMode else true) {
|
||||
if (playerView.isControllerFullyVisible) {
|
||||
ObjectAnimator.ofFloat(playerView.findViewById(R.id.exo_controller), "alpha", 1f, 0f)
|
||||
ObjectAnimator.ofFloat(
|
||||
playerView.findViewById(R.id.exo_controller),
|
||||
"alpha",
|
||||
1f,
|
||||
0f
|
||||
)
|
||||
.setDuration(controllerDuration).start()
|
||||
ObjectAnimator.ofFloat(playerView.findViewById(R.id.exo_bottom_cont), "translationY", 0f, 128f)
|
||||
ObjectAnimator.ofFloat(
|
||||
playerView.findViewById(R.id.exo_bottom_cont),
|
||||
"translationY",
|
||||
0f,
|
||||
128f
|
||||
)
|
||||
.apply { interpolator = overshoot;duration = controllerDuration;start() }
|
||||
ObjectAnimator.ofFloat(playerView.findViewById(R.id.exo_timeline_cont), "translationY", 0f, 128f)
|
||||
ObjectAnimator.ofFloat(
|
||||
playerView.findViewById(R.id.exo_timeline_cont),
|
||||
"translationY",
|
||||
0f,
|
||||
128f
|
||||
)
|
||||
.apply { interpolator = overshoot;duration = controllerDuration;start() }
|
||||
ObjectAnimator.ofFloat(playerView.findViewById(R.id.exo_top_cont), "translationY", 0f, -128f)
|
||||
ObjectAnimator.ofFloat(
|
||||
playerView.findViewById(R.id.exo_top_cont),
|
||||
"translationY",
|
||||
0f,
|
||||
-128f
|
||||
)
|
||||
.apply { interpolator = overshoot;duration = controllerDuration;start() }
|
||||
playerView.postDelayed({ playerView.hideController() }, controllerDuration)
|
||||
} else {
|
||||
checkNotch()
|
||||
playerView.showController()
|
||||
ObjectAnimator.ofFloat(playerView.findViewById(R.id.exo_controller), "alpha", 0f, 1f)
|
||||
ObjectAnimator.ofFloat(
|
||||
playerView.findViewById(R.id.exo_controller),
|
||||
"alpha",
|
||||
0f,
|
||||
1f
|
||||
)
|
||||
.setDuration(controllerDuration).start()
|
||||
ObjectAnimator.ofFloat(playerView.findViewById(R.id.exo_bottom_cont), "translationY", 128f, 0f)
|
||||
ObjectAnimator.ofFloat(
|
||||
playerView.findViewById(R.id.exo_bottom_cont),
|
||||
"translationY",
|
||||
128f,
|
||||
0f
|
||||
)
|
||||
.apply { interpolator = overshoot;duration = controllerDuration;start() }
|
||||
ObjectAnimator.ofFloat(playerView.findViewById(R.id.exo_timeline_cont), "translationY", 128f, 0f)
|
||||
ObjectAnimator.ofFloat(
|
||||
playerView.findViewById(R.id.exo_timeline_cont),
|
||||
"translationY",
|
||||
128f,
|
||||
0f
|
||||
)
|
||||
.apply { interpolator = overshoot;duration = controllerDuration;start() }
|
||||
ObjectAnimator.ofFloat(playerView.findViewById(R.id.exo_top_cont), "translationY", -128f, 0f)
|
||||
ObjectAnimator.ofFloat(
|
||||
playerView.findViewById(R.id.exo_top_cont),
|
||||
"translationY",
|
||||
-128f,
|
||||
0f
|
||||
)
|
||||
.apply { interpolator = overshoot;duration = controllerDuration;start() }
|
||||
}
|
||||
}
|
||||
@@ -651,8 +729,10 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
}
|
||||
|
||||
if (!settings.doubleTap) {
|
||||
playerView.findViewById<View>(R.id.exo_fast_forward_button_cont).visibility = View.VISIBLE
|
||||
playerView.findViewById<View>(R.id.exo_fast_rewind_button_cont).visibility = View.VISIBLE
|
||||
playerView.findViewById<View>(R.id.exo_fast_forward_button_cont).visibility =
|
||||
View.VISIBLE
|
||||
playerView.findViewById<View>(R.id.exo_fast_rewind_button_cont).visibility =
|
||||
View.VISIBLE
|
||||
playerView.findViewById<ImageButton>(R.id.exo_fast_forward_button).setOnClickListener {
|
||||
if (isInitialized) {
|
||||
seek(true)
|
||||
@@ -696,7 +776,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
|
||||
exoBrightness.addOnChangeListener { _, value, _ ->
|
||||
val lp = window.attributes
|
||||
lp.screenBrightness = brightnessConverter((value.takeIf { !it.isNaN() } ?: 0f) / 10, false)
|
||||
lp.screenBrightness =
|
||||
brightnessConverter((value.takeIf { !it.isNaN() } ?: 0f) / 10, false)
|
||||
window.attributes = lp
|
||||
brightnessHide()
|
||||
}
|
||||
@@ -757,7 +838,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSingleClick(event: MotionEvent) = if (isSeeking) doubleTap(false, event) else handleController()
|
||||
override fun onSingleClick(event: MotionEvent) =
|
||||
if (isSeeking) doubleTap(false, event) else handleController()
|
||||
})
|
||||
val rewindArea = playerView.findViewById<View>(R.id.exo_rewind_area)
|
||||
rewindArea.isClickable = true
|
||||
@@ -786,7 +868,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSingleClick(event: MotionEvent) = if (isSeeking) doubleTap(true, event) else handleController()
|
||||
override fun onSingleClick(event: MotionEvent) =
|
||||
if (isSeeking) doubleTap(true, event) else handleController()
|
||||
})
|
||||
val forwardArea = playerView.findViewById<View>(R.id.exo_forward_area)
|
||||
forwardArea.isClickable = true
|
||||
@@ -817,7 +900,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
}
|
||||
|
||||
model.watchSources = if (media.isAdult) HAnimeSources else AnimeSources
|
||||
serverInfo.text = model.watchSources!!.names.getOrNull(media.selected!!.sourceIndex) ?: model.watchSources!!.names[0]
|
||||
serverInfo.text = model.watchSources!!.names.getOrNull(media.selected!!.sourceIndex)
|
||||
?: model.watchSources!!.names[0]
|
||||
|
||||
model.epChanged.observe(this) {
|
||||
epChanging = !it
|
||||
@@ -906,7 +990,10 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
rpc?.send {
|
||||
type = RPC.Type.WATCHING
|
||||
activityName = media.userPreferredName
|
||||
details = ep.title?.takeIf { it.isNotEmpty() } ?: getString(R.string.episode_num, ep.number)
|
||||
details = ep.title?.takeIf { it.isNotEmpty() } ?: getString(
|
||||
R.string.episode_num,
|
||||
ep.number
|
||||
)
|
||||
state = "Episode : ${ep.number}/${media.anime?.totalEpisodes ?: "??"}"
|
||||
media.cover?.let { cover ->
|
||||
largeImage = RPC.Link(media.userPreferredName, cover)
|
||||
@@ -922,25 +1009,25 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
//FullScreen
|
||||
isFullscreen = loadData("${media.id}_fullscreenInt", this) ?: isFullscreen
|
||||
playerView.resizeMode = when (isFullscreen) {
|
||||
0 -> AspectRatioFrameLayout.RESIZE_MODE_FIT
|
||||
1 -> AspectRatioFrameLayout.RESIZE_MODE_ZOOM
|
||||
2 -> AspectRatioFrameLayout.RESIZE_MODE_FILL
|
||||
0 -> AspectRatioFrameLayout.RESIZE_MODE_FIT
|
||||
1 -> AspectRatioFrameLayout.RESIZE_MODE_ZOOM
|
||||
2 -> AspectRatioFrameLayout.RESIZE_MODE_FILL
|
||||
else -> AspectRatioFrameLayout.RESIZE_MODE_FIT
|
||||
}
|
||||
|
||||
exoScreen.setOnClickListener {
|
||||
if (isFullscreen < 2) isFullscreen += 1 else isFullscreen = 0
|
||||
playerView.resizeMode = when (isFullscreen) {
|
||||
0 -> AspectRatioFrameLayout.RESIZE_MODE_FIT
|
||||
1 -> AspectRatioFrameLayout.RESIZE_MODE_ZOOM
|
||||
2 -> AspectRatioFrameLayout.RESIZE_MODE_FILL
|
||||
0 -> AspectRatioFrameLayout.RESIZE_MODE_FIT
|
||||
1 -> AspectRatioFrameLayout.RESIZE_MODE_ZOOM
|
||||
2 -> AspectRatioFrameLayout.RESIZE_MODE_FILL
|
||||
else -> AspectRatioFrameLayout.RESIZE_MODE_FIT
|
||||
}
|
||||
snackString(
|
||||
when (isFullscreen) {
|
||||
0 -> "Original"
|
||||
1 -> "Zoom"
|
||||
2 -> "Stretch"
|
||||
0 -> "Original"
|
||||
1 -> "Zoom"
|
||||
2 -> "Stretch"
|
||||
else -> "Original"
|
||||
}
|
||||
)
|
||||
@@ -959,7 +1046,11 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
|
||||
//Settings
|
||||
exoSettings.setOnClickListener {
|
||||
saveData("${media.id}_${media.anime!!.selectedEpisode}", exoPlayer.currentPosition, this)
|
||||
saveData(
|
||||
"${media.id}_${media.anime!!.selectedEpisode}",
|
||||
exoPlayer.currentPosition,
|
||||
this
|
||||
)
|
||||
val intent = Intent(this, PlayerSettingsActivity::class.java).apply {
|
||||
putExtra("subtitle", subtitle)
|
||||
}
|
||||
@@ -979,7 +1070,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
|
||||
playbackParameters = PlaybackParameters(speeds[curSpeed])
|
||||
var speed: Float
|
||||
val speedDialog = AlertDialog.Builder(this, R.style.DialogTheme).setTitle(getString(R.string.speed))
|
||||
val speedDialog =
|
||||
AlertDialog.Builder(this, R.style.DialogTheme).setTitle(getString(R.string.speed))
|
||||
exoSpeed.setOnClickListener {
|
||||
speedDialog.setSingleChoiceItems(speedsName, curSpeed) { dialog, i ->
|
||||
if (isInitialized) {
|
||||
@@ -1018,16 +1110,19 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
|
||||
isFullscreen = settings.resize
|
||||
playerView.resizeMode = when (settings.resize) {
|
||||
0 -> AspectRatioFrameLayout.RESIZE_MODE_FIT
|
||||
1 -> AspectRatioFrameLayout.RESIZE_MODE_ZOOM
|
||||
2 -> AspectRatioFrameLayout.RESIZE_MODE_FILL
|
||||
0 -> AspectRatioFrameLayout.RESIZE_MODE_FIT
|
||||
1 -> AspectRatioFrameLayout.RESIZE_MODE_ZOOM
|
||||
2 -> AspectRatioFrameLayout.RESIZE_MODE_FILL
|
||||
else -> AspectRatioFrameLayout.RESIZE_MODE_FIT
|
||||
}
|
||||
|
||||
preloading = false
|
||||
val showProgressDialog = if (settings.askIndividual) loadData<Boolean>("${media.id}_progressDialog") ?: true else false
|
||||
val showProgressDialog =
|
||||
if (settings.askIndividual) loadData<Boolean>("${media.id}_progressDialog")
|
||||
?: true else false
|
||||
if (showProgressDialog && Anilist.userid != null && if (media.isAdult) settings.updateForH else true)
|
||||
AlertDialog.Builder(this, R.style.DialogTheme).setTitle(getString(R.string.auto_update, media.userPreferredName))
|
||||
AlertDialog.Builder(this, R.style.DialogTheme)
|
||||
.setTitle(getString(R.string.auto_update, media.userPreferredName))
|
||||
.apply {
|
||||
setOnCancelListener { hideSystemBars() }
|
||||
setCancelable(false)
|
||||
@@ -1074,16 +1169,16 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
|
||||
subtitle = intent.getSerialized("subtitle")
|
||||
?: when (val subLang: String? = loadData("subLang_${media.id}", this)) {
|
||||
null -> {
|
||||
null -> {
|
||||
when (episode.selectedSubtitle) {
|
||||
null -> null
|
||||
-1 -> ext.subtitles.find { it.language.trim() == "English" || it.language == "en-US" }
|
||||
-1 -> ext.subtitles.find { it.language.trim() == "English" || it.language == "en-US" }
|
||||
else -> ext.subtitles.getOrNull(episode.selectedSubtitle!!)
|
||||
}
|
||||
}
|
||||
|
||||
"None" -> ext.subtitles.let { null }
|
||||
else -> ext.subtitles.find { it.language == subLang }
|
||||
else -> ext.subtitles.find { it.language == subLang }
|
||||
}
|
||||
|
||||
//Subtitles
|
||||
@@ -1091,21 +1186,44 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
exoSubtitle.setOnClickListener {
|
||||
subClick()
|
||||
}
|
||||
|
||||
var sub: MediaItem.SubtitleConfiguration? = null
|
||||
if (subtitle != null) {
|
||||
sub = MediaItem.SubtitleConfiguration
|
||||
.Builder(Uri.parse(subtitle!!.file.url))
|
||||
.setSelectionFlags(C.SELECTION_FLAG_FORCED)
|
||||
.setMimeType(
|
||||
when (subtitle?.type) {
|
||||
SubtitleType.VTT -> MimeTypes.TEXT_VTT
|
||||
SubtitleType.ASS -> MimeTypes.TEXT_SSA
|
||||
SubtitleType.SRT -> MimeTypes.APPLICATION_SUBRIP
|
||||
else -> MimeTypes.TEXT_UNKNOWN
|
||||
}
|
||||
)
|
||||
.build()
|
||||
//var localFile: String? = null
|
||||
if (subtitle?.type == SubtitleType.UNKNOWN) {
|
||||
val context = this
|
||||
runBlocking {
|
||||
val type = SubtitleDownloader.downloadSubtitles(context, subtitle!!.file.url)
|
||||
val fileUri = Uri.parse(subtitle!!.file.url)
|
||||
sub = MediaItem.SubtitleConfiguration
|
||||
.Builder(fileUri)
|
||||
.setSelectionFlags(C.SELECTION_FLAG_DEFAULT)
|
||||
.setMimeType(
|
||||
when (type) {
|
||||
SubtitleType.VTT -> MimeTypes.TEXT_SSA
|
||||
SubtitleType.ASS -> MimeTypes.TEXT_SSA
|
||||
SubtitleType.SRT -> MimeTypes.TEXT_SSA
|
||||
else -> MimeTypes.TEXT_SSA
|
||||
}
|
||||
)
|
||||
.setId("69")
|
||||
.build()
|
||||
}
|
||||
println("sub: $sub")
|
||||
} else {
|
||||
sub = MediaItem.SubtitleConfiguration
|
||||
.Builder(Uri.parse(subtitle!!.file.url))
|
||||
.setSelectionFlags(C.SELECTION_FLAG_FORCED)
|
||||
.setMimeType(
|
||||
when (subtitle?.type) {
|
||||
SubtitleType.VTT -> MimeTypes.TEXT_VTT
|
||||
SubtitleType.ASS -> MimeTypes.TEXT_SSA
|
||||
SubtitleType.SRT -> MimeTypes.APPLICATION_SUBRIP
|
||||
else -> MimeTypes.TEXT_UNKNOWN
|
||||
}
|
||||
)
|
||||
.setId("69")
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
@@ -1113,7 +1231,9 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
}
|
||||
|
||||
val but = playerView.findViewById<ImageButton>(R.id.exo_download)
|
||||
if (video?.format == VideoType.CONTAINER || (loadData<Int>("settings_download_manager") ?: 0) != 0) {
|
||||
if (video?.format == VideoType.CONTAINER || (loadData<Int>("settings_download_manager")
|
||||
?: 0) != 0
|
||||
) {
|
||||
but.visibility = View.VISIBLE
|
||||
but.setOnClickListener {
|
||||
download(this, episode, animeTitle.text.toString())
|
||||
@@ -1146,12 +1266,15 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
val mimeType = when (video?.format) {
|
||||
VideoType.M3U8 -> MimeTypes.APPLICATION_M3U8
|
||||
VideoType.DASH -> MimeTypes.APPLICATION_MPD
|
||||
else -> MimeTypes.APPLICATION_MP4
|
||||
else -> MimeTypes.APPLICATION_MP4
|
||||
}
|
||||
|
||||
val builder = MediaItem.Builder().setUri(video!!.file.url).setMimeType(mimeType)
|
||||
|
||||
if (sub != null) builder.setSubtitleConfigurations(mutableListOf(sub))
|
||||
if (sub != null) {
|
||||
val listofnotnullsubs = immutableListOf(sub).filterNotNull()
|
||||
builder.setSubtitleConfigurations(listofnotnullsubs)
|
||||
}
|
||||
mediaItem = builder.build()
|
||||
|
||||
//Source
|
||||
@@ -1163,8 +1286,23 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
trackSelector = DefaultTrackSelector(this)
|
||||
trackSelector.setParameters(
|
||||
trackSelector.buildUponParameters()
|
||||
.setMinVideoSize(loadData("maxWidth", this) ?: 720, loadData("maxHeight", this) ?: 480)
|
||||
.setAllowVideoMixedMimeTypeAdaptiveness(true)
|
||||
.setAllowVideoNonSeamlessAdaptiveness(true)
|
||||
.setSelectUndeterminedTextLanguage(true)
|
||||
.setAllowAudioMixedMimeTypeAdaptiveness(true)
|
||||
.setAllowMultipleAdaptiveSelections(true)
|
||||
.setPreferredTextLanguage(subtitle?.language ?: "en")
|
||||
.setPreferredTextRoleFlags(C.ROLE_FLAG_SUBTITLE)
|
||||
.setRendererDisabled(C.TRACK_TYPE_VIDEO, false)
|
||||
.setRendererDisabled(C.TRACK_TYPE_AUDIO, false)
|
||||
.setRendererDisabled(C.TRACK_TYPE_TEXT, false)
|
||||
.setMinVideoSize(
|
||||
loadData("maxWidth", this) ?: 720,
|
||||
loadData("maxHeight", this) ?: 480
|
||||
)
|
||||
.setMaxVideoSize(1, 1)
|
||||
//.setOverrideForType(
|
||||
// TrackSelectionOverride(trackSelector, 2))
|
||||
)
|
||||
|
||||
if (playbackPosition != 0L && !changingServer && !settings.alwaysContinue) {
|
||||
@@ -1181,7 +1319,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
)
|
||||
)
|
||||
)
|
||||
AlertDialog.Builder(this, R.style.DialogTheme).setTitle(getString(R.string.continue_from, time)).apply {
|
||||
AlertDialog.Builder(this, R.style.DialogTheme)
|
||||
.setTitle(getString(R.string.continue_from, time)).apply {
|
||||
setCancelable(false)
|
||||
setPositiveButton(getString(R.string.yes)) { d, _ ->
|
||||
buildExoplayer()
|
||||
@@ -1214,6 +1353,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
}
|
||||
playerView.player = exoPlayer
|
||||
|
||||
|
||||
try {
|
||||
mediaSession = MediaSession.Builder(this, exoPlayer).build()
|
||||
} catch (e: Exception) {
|
||||
@@ -1221,8 +1361,34 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
}
|
||||
|
||||
exoPlayer.addListener(this)
|
||||
exoPlayer.addAnalyticsListener(EventLogger())
|
||||
isInitialized = true
|
||||
}
|
||||
/*private fun selectSubtitleTrack() {
|
||||
// Get the current track groups
|
||||
val trackGroups = exoPlayer.currentTrackGroups
|
||||
|
||||
// Prepare a track selector parameters builder
|
||||
val parametersBuilder = DefaultTrackSelector.ParametersBuilder(this)
|
||||
|
||||
// Iterate through the track groups to find the subtitle tracks
|
||||
for (i in 0 until trackGroups.length) {
|
||||
val trackGroup = trackGroups[i]
|
||||
for (j in 0 until trackGroup.length) {
|
||||
val trackMetadata = trackGroup.getFormat(j)
|
||||
|
||||
// Check if the track is a subtitle track
|
||||
if (MimeTypes.isText(trackMetadata.sampleMimeType)) {
|
||||
parametersBuilder.setRendererDisabled(i, false) // Enable the renderer for this track group
|
||||
parametersBuilder.setSelectionOverride(i, trackGroups, DefaultTrackSelector.SelectionOverride(j, 0)) // Override to select this track
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the track selector parameters to select the subtitle
|
||||
trackSelector.setParameters(parametersBuilder)
|
||||
}*/
|
||||
|
||||
private fun releasePlayer() {
|
||||
isPlayerPlaying = exoPlayer.playWhenReady
|
||||
@@ -1266,7 +1432,11 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
orientationListener?.disable()
|
||||
if (isInitialized) {
|
||||
playerView.player?.pause()
|
||||
saveData("${media.id}_${media.anime!!.selectedEpisode}", exoPlayer.currentPosition, this)
|
||||
saveData(
|
||||
"${media.id}_${media.anime!!.selectedEpisode}",
|
||||
exoPlayer.currentPosition,
|
||||
this
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1304,7 +1474,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
playerView.keepScreenOn = isPlaying
|
||||
(exoPlay.drawable as Animatable?)?.start()
|
||||
if (!this.isDestroyed) Glide.with(this)
|
||||
.load(if (isPlaying) R.drawable.anim_play_to_pause else R.drawable.anim_pause_to_play).into(exoPlay)
|
||||
.load(if (isPlaying) R.drawable.anim_play_to_pause else R.drawable.anim_pause_to_play)
|
||||
.into(exoPlay)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1383,7 +1554,10 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
exoPlayer.seekTo((new.interval.endTime * 1000).toLong())
|
||||
}
|
||||
}
|
||||
if (settings.autoSkipOPED && (new.skipType == "op" || new.skipType == "ed") && !skippedTimeStamps.contains(new)) {
|
||||
if (settings.autoSkipOPED && (new.skipType == "op" || new.skipType == "ed") && !skippedTimeStamps.contains(
|
||||
new
|
||||
)
|
||||
) {
|
||||
exoPlayer.seekTo((new.interval.endTime * 1000).toLong())
|
||||
skippedTimeStamps.add(new)
|
||||
}
|
||||
@@ -1400,6 +1574,27 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
}
|
||||
|
||||
override fun onTracksChanged(tracks: Tracks) {
|
||||
tracks.groups.forEach {
|
||||
println("Track__: $it")
|
||||
println("Track__: ${it.length}")
|
||||
println("Track__: ${it.isSelected}")
|
||||
println("Track__: ${it.type}")
|
||||
println("Track__: ${it.mediaTrackGroup.id}")
|
||||
if (it.type == 3 && it.mediaTrackGroup.id == "1:"){
|
||||
playerView.player?.trackSelectionParameters =
|
||||
playerView.player?.trackSelectionParameters?.buildUpon()
|
||||
?.setOverrideForType(
|
||||
TrackSelectionOverride(it.mediaTrackGroup, it.length - 1))
|
||||
?.build()!!
|
||||
}else if(it.type == 3){
|
||||
playerView.player?.trackSelectionParameters =
|
||||
playerView.player?.trackSelectionParameters?.buildUpon()
|
||||
?.addOverride(
|
||||
TrackSelectionOverride(it.mediaTrackGroup, listOf()))
|
||||
?.build()!!
|
||||
}
|
||||
}
|
||||
println("Track: ${tracks.groups.size}")
|
||||
if (tracks.groups.size <= 2) exoQuality.visibility = View.GONE
|
||||
else {
|
||||
exoQuality.visibility = View.VISIBLE
|
||||
@@ -1426,6 +1621,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
private var isBuffering = true
|
||||
override fun onPlaybackStateChanged(playbackState: Int) {
|
||||
if (playbackState == ExoPlayer.STATE_READY) {
|
||||
|
||||
exoPlayer.play()
|
||||
if (episodeLength == 0f) {
|
||||
episodeLength = exoPlayer.duration.toFloat()
|
||||
@@ -1453,7 +1649,9 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
var i = 1
|
||||
while (isFiller) {
|
||||
if (episodeArr.size > currentEpisodeIndex + i) {
|
||||
isFiller = if (settings.autoSkipFiller) episodes[episodeArr[currentEpisodeIndex + i]]?.filler ?: false else false
|
||||
isFiller =
|
||||
if (settings.autoSkipFiller) episodes[episodeArr[currentEpisodeIndex + i]]?.filler
|
||||
?: false else false
|
||||
if (!isFiller) runnable.invoke(i)
|
||||
i++
|
||||
} else {
|
||||
@@ -1509,7 +1707,10 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
shareVideo.setDataAndType(Uri.parse(videoURL), "video/*")
|
||||
shareVideo.setPackage("com.instantbits.cast.webvideo")
|
||||
if (subtitle != null) shareVideo.putExtra("subtitle", subtitle!!.file.url)
|
||||
shareVideo.putExtra("title", media.userPreferredName + " : Ep " + episodeTitleArr[currentEpisodeIndex])
|
||||
shareVideo.putExtra(
|
||||
"title",
|
||||
media.userPreferredName + " : Ep " + episodeTitleArr[currentEpisodeIndex]
|
||||
)
|
||||
shareVideo.putExtra("poster", episode.thumb?.url ?: media.cover)
|
||||
val headers = Bundle()
|
||||
defaultHeaders.forEach {
|
||||
@@ -1579,7 +1780,10 @@ class ExoplayerView : AppCompatActivity(), Player.Listener {
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) {
|
||||
override fun onPictureInPictureModeChanged(
|
||||
isInPictureInPictureMode: Boolean,
|
||||
newConfig: Configuration
|
||||
) {
|
||||
onPiPChanged(isInPictureInPictureMode)
|
||||
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import ani.dantotsu.media.MediaDetailsViewModel
|
||||
import ani.dantotsu.others.Download.download
|
||||
import ani.dantotsu.parsers.VideoExtractor
|
||||
import ani.dantotsu.parsers.VideoType
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -9,6 +9,8 @@ import ani.dantotsu.databinding.ItemEpisodeCompactBinding
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.setAnimation
|
||||
import ani.dantotsu.connections.updateProgress
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class MangaChapterAdapter(
|
||||
private var type: Int,
|
||||
@@ -63,12 +65,12 @@ class MangaChapterAdapter(
|
||||
val ep = arr[position]
|
||||
binding.itemEpisodeNumber.text = ep.number
|
||||
if (media.userProgress != null) {
|
||||
if ((ep.number.toFloatOrNull() ?: 9999f) <= media.userProgress!!.toFloat())
|
||||
if ((MangaNameAdapter.findChapterNumber(ep.number) ?: 9999f) <= media.userProgress!!.toFloat())
|
||||
binding.itemEpisodeViewedCover.visibility = View.VISIBLE
|
||||
else {
|
||||
binding.itemEpisodeViewedCover.visibility = View.GONE
|
||||
binding.itemEpisodeCont.setOnLongClickListener {
|
||||
updateProgress(media, ep.number)
|
||||
updateProgress(media, MangaNameAdapter.findChapterNumber(ep.number).toString())
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -91,14 +93,14 @@ class MangaChapterAdapter(
|
||||
} else binding.itemChapterTitle.visibility = View.GONE
|
||||
|
||||
if (media.userProgress != null) {
|
||||
if ((ep.number.toFloatOrNull() ?: 9999f) <= media.userProgress!!.toFloat()) {
|
||||
if ((MangaNameAdapter.findChapterNumber(ep.number) ?: 9999f) <= media.userProgress!!.toFloat()) {
|
||||
binding.itemEpisodeViewedCover.visibility = View.VISIBLE
|
||||
binding.itemEpisodeViewed.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.itemEpisodeViewedCover.visibility = View.GONE
|
||||
binding.itemEpisodeViewed.visibility = View.GONE
|
||||
binding.root.setOnLongClickListener {
|
||||
updateProgress(media, ep.number)
|
||||
updateProgress(media, MangaNameAdapter.findChapterNumber(ep.number).toString())
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -113,4 +115,6 @@ class MangaChapterAdapter(
|
||||
fun updateType(t: Int) {
|
||||
type = t
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package ani.dantotsu.media.manga
|
||||
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class MangaNameAdapter {
|
||||
companion object {
|
||||
fun findChapterNumber(text: String): Float? {
|
||||
val regex = "(chapter|chap|ch|c)[\\s:.\\-]*([\\d]+\\.?[\\d]*)"
|
||||
val pattern: Pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE)
|
||||
val matcher: Matcher = pattern.matcher(text)
|
||||
|
||||
return if (matcher.find()) {
|
||||
matcher.group(2)?.toFloat()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,7 +174,9 @@ class MangaReadAdapter(
|
||||
val anilistEp = (media.userProgress ?: 0).plus(1)
|
||||
val appEp = loadData<String>("${media.id}_current_chp")?.toIntOrNull() ?: 1
|
||||
var continueEp = (if (anilistEp > appEp) anilistEp else appEp).toString()
|
||||
if (chapters.contains(continueEp)) {
|
||||
val formattedChapters = chapters.map { MangaNameAdapter.findChapterNumber(it)?.toInt()?.toString() }
|
||||
if (formattedChapters.contains(continueEp)) {
|
||||
continueEp = chapters[formattedChapters.indexOf(continueEp)]
|
||||
binding.animeSourceContinue.visibility = View.VISIBLE
|
||||
handleProgress(
|
||||
binding.itemEpisodeProgressCont,
|
||||
|
||||
@@ -116,10 +116,10 @@ abstract class BaseImageAdapter(
|
||||
abstract suspend fun loadImage(position: Int, parent: View): Boolean
|
||||
|
||||
companion object {
|
||||
/*suspend fun Context.loadBitmap(link: FileUrl, transforms: List<BitmapTransformation>): Bitmap? {
|
||||
suspend fun Context.loadBitmap_old(link: FileUrl, transforms: List<BitmapTransformation>): Bitmap? {
|
||||
return tryWithSuspend {
|
||||
withContext(Dispatchers.IO) {
|
||||
Glide.with(this@loadBitmap)
|
||||
Glide.with(this@loadBitmap_old)
|
||||
.asBitmap()
|
||||
.let {
|
||||
if (link.url.startsWith("file://")) {
|
||||
@@ -142,7 +142,7 @@ abstract class BaseImageAdapter(
|
||||
.get()
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
suspend fun Context.loadBitmap(link: FileUrl, transforms: List<BitmapTransformation>): Bitmap? {
|
||||
return tryWithSuspend {
|
||||
@@ -156,10 +156,6 @@ abstract class BaseImageAdapter(
|
||||
.skipMemoryCache(true)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
} else {
|
||||
println("bitmap from cache")
|
||||
println(link.url)
|
||||
println(mangaCache.get(link.url))
|
||||
println("cache size: ${mangaCache.size()}")
|
||||
mangaCache.get(link.url)?.let { imageData ->
|
||||
val bitmap = imageData.fetchAndProcessImage(imageData.page, imageData.source, context = this@loadBitmap)
|
||||
it.load(bitmap)
|
||||
|
||||
@@ -14,6 +14,7 @@ import ani.dantotsu.currActivity
|
||||
import ani.dantotsu.databinding.BottomSheetSelectorBinding
|
||||
import ani.dantotsu.media.manga.MangaChapter
|
||||
import ani.dantotsu.media.MediaDetailsViewModel
|
||||
import ani.dantotsu.media.MediaSingleton
|
||||
import ani.dantotsu.others.getSerialized
|
||||
import ani.dantotsu.tryWith
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -49,7 +50,8 @@ class ChapterLoaderDialog : BottomSheetDialogFragment() {
|
||||
activity?.runOnUiThread {
|
||||
tryWith { dismiss() }
|
||||
if(launch) {
|
||||
val intent = Intent(activity, MangaReaderActivity::class.java).apply { putExtra("media", m) }
|
||||
MediaSingleton.media = m
|
||||
val intent = Intent(activity, MangaReaderActivity::class.java)//.apply { putExtra("media", m) }
|
||||
activity.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,10 @@ import ani.dantotsu.connections.updateProgress
|
||||
import ani.dantotsu.databinding.ActivityMangaReaderBinding
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.media.MediaDetailsViewModel
|
||||
import ani.dantotsu.media.MediaSingleton
|
||||
import ani.dantotsu.media.manga.MangaCache
|
||||
import ani.dantotsu.media.manga.MangaChapter
|
||||
import ani.dantotsu.media.manga.MangaNameAdapter
|
||||
import ani.dantotsu.others.ImageViewDialog
|
||||
import ani.dantotsu.others.getSerialized
|
||||
import ani.dantotsu.parsers.HMangaSources
|
||||
@@ -43,10 +45,16 @@ import ani.dantotsu.settings.CurrentReaderSettings.DualPageModes.*
|
||||
import ani.dantotsu.settings.CurrentReaderSettings.Layouts.*
|
||||
import ani.dantotsu.settings.ReaderSettings
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import com.alexvasilkov.gestures.views.GestureFrameLayout
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||
import com.google.firebase.crashlytics.ktx.crashlytics
|
||||
import com.google.firebase.ktx.Firebase
|
||||
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@@ -118,6 +126,7 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityMangaReaderBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
@@ -164,10 +173,13 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||
|
||||
media = if (model.getMedia().value == null)
|
||||
try {
|
||||
(intent.getSerialized("media")) ?: return
|
||||
//(intent.getSerialized("media")) ?: return
|
||||
MediaSingleton.media ?: return
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
return
|
||||
} finally {
|
||||
MediaSingleton.media = null
|
||||
}
|
||||
else model.getMedia().value ?: return
|
||||
model.setMedia(media)
|
||||
@@ -180,6 +192,29 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||
|
||||
model.mangaReadSources = if (media.isAdult) HMangaSources else MangaSources
|
||||
binding.mangaReaderSource.visibility = if (settings.showSource) View.VISIBLE else View.GONE
|
||||
if(model.mangaReadSources!!.names.isEmpty()){
|
||||
//try to reload sources
|
||||
try {
|
||||
if (media.isAdult) {
|
||||
val mangaSources = MangaSources
|
||||
val scope = lifecycleScope
|
||||
scope.launch(Dispatchers.IO) {
|
||||
mangaSources.init(Injekt.get<MangaExtensionManager>().installedExtensionsFlow)
|
||||
}
|
||||
model.mangaReadSources = mangaSources
|
||||
}else{
|
||||
val mangaSources = HMangaSources
|
||||
val scope = lifecycleScope
|
||||
scope.launch(Dispatchers.IO) {
|
||||
mangaSources.init(Injekt.get<MangaExtensionManager>().installedExtensionsFlow)
|
||||
}
|
||||
model.mangaReadSources = mangaSources
|
||||
}
|
||||
}catch (e: Exception){
|
||||
Firebase.crashlytics.recordException(e)
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
binding.mangaReaderSource.text = model.mangaReadSources!!.names[media.selected!!.sourceIndex]
|
||||
|
||||
binding.mangaReaderTitle.text = media.userPreferredName
|
||||
@@ -677,7 +712,7 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||
progressDialog?.setCancelable(false)
|
||||
?.setPositiveButton(getString(R.string.yes)) { dialog, _ ->
|
||||
saveData("${media.id}_save_progress", true)
|
||||
updateProgress(media, media.manga!!.selectedChapter!!)
|
||||
updateProgress(media, MangaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!).toString())
|
||||
dialog.dismiss()
|
||||
runnable.run()
|
||||
}
|
||||
@@ -689,7 +724,7 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||
progressDialog?.show()
|
||||
} else {
|
||||
if (loadData<Boolean>("${media.id}_save_progress") != false && if (media.isAdult) settings.updateForH else true)
|
||||
updateProgress(media, media.manga!!.selectedChapter!!)
|
||||
updateProgress(media, MangaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!).toString())
|
||||
runnable.run()
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -13,6 +13,7 @@ import ani.dantotsu.loadImage
|
||||
import ani.dantotsu.media.MediaDetailsViewModel
|
||||
import ani.dantotsu.others.getSerialized
|
||||
import ani.dantotsu.parsers.ShowResponse
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import ani.dantotsu.settings.CurrentReaderSettings
|
||||
import ani.dantotsu.settings.NovelReaderSettings
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.snackString
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import ani.dantotsu.tryWith
|
||||
import com.google.android.material.slider.Slider
|
||||
import com.vipulog.ebookreader.Book
|
||||
@@ -135,6 +136,7 @@ class NovelReaderActivity : AppCompatActivity(), EbookReaderEventListener {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityNovelReaderBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
||||
@@ -2,7 +2,10 @@ package ani.dantotsu.media.user
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
@@ -12,6 +15,9 @@ import androidx.lifecycle.lifecycleScope
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.Refresh
|
||||
import ani.dantotsu.databinding.ActivityListBinding
|
||||
import ani.dantotsu.loadData
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -26,10 +32,39 @@ class ListActivity : AppCompatActivity() {
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityListBinding.inflate(layoutInflater)
|
||||
|
||||
val typedValue = TypedValue()
|
||||
theme.resolveAttribute(com.google.android.material.R.attr.colorOnPrimary, typedValue, true)
|
||||
val primaryColor = typedValue.data
|
||||
val typedValue2 = TypedValue()
|
||||
theme.resolveAttribute(com.google.android.material.R.attr.colorPrimary, typedValue2, true)
|
||||
val primaryTextColor = typedValue2.data
|
||||
val typedValue3 = TypedValue()
|
||||
theme.resolveAttribute(com.google.android.material.R.attr.colorSecondary, typedValue3, true)
|
||||
val secondaryColor = typedValue3.data
|
||||
|
||||
window.statusBarColor = primaryColor
|
||||
window.navigationBarColor = primaryColor
|
||||
binding.listTabLayout.setBackgroundColor(primaryColor)
|
||||
binding.listAppBar.setBackgroundColor(primaryColor)
|
||||
binding.listTitle.setTextColor(primaryTextColor)
|
||||
binding.listTabLayout.setTabTextColors(primaryTextColor, primaryTextColor)
|
||||
binding.listTabLayout.setSelectedTabIndicatorColor(primaryTextColor)
|
||||
val uiSettings = loadData<UserInterfaceSettings>("ui_settings") ?: UserInterfaceSettings()
|
||||
if (!uiSettings.immersiveMode) {
|
||||
this.window.statusBarColor =
|
||||
ContextCompat.getColor(this, R.color.nav_bg_inv)
|
||||
binding.root.fitsSystemWindows = true
|
||||
|
||||
}else{
|
||||
binding.root.fitsSystemWindows = false
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
||||
}
|
||||
setContentView(binding.root)
|
||||
|
||||
window.statusBarColor = ContextCompat.getColor(this, R.color.nav_bg)
|
||||
val anime = intent.getBooleanExtra("anime", true)
|
||||
binding.listTitle.text = intent.getStringExtra("username") + "'s " + (if (anime) "Anime" else "Manga") + " List"
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import ani.dantotsu.databinding.FragmentListBinding
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.media.MediaAdaptor
|
||||
import ani.dantotsu.media.OtherDetailsViewModel
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
|
||||
class ListFragment : Fragment() {
|
||||
private var _binding: FragmentListBinding? = null
|
||||
|
||||
@@ -12,12 +12,14 @@ import ani.dantotsu.FileUrl
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.databinding.BottomSheetImageBinding
|
||||
import ani.dantotsu.media.manga.mangareader.BaseImageAdapter.Companion.loadBitmap
|
||||
import ani.dantotsu.media.manga.mangareader.BaseImageAdapter.Companion.loadBitmap_old
|
||||
import ani.dantotsu.media.manga.mangareader.BaseImageAdapter.Companion.mergeBitmap
|
||||
import ani.dantotsu.openLinkInBrowser
|
||||
import ani.dantotsu.saveImageToDownloads
|
||||
import ani.dantotsu.setSafeOnClickListener
|
||||
import ani.dantotsu.shareImage
|
||||
import ani.dantotsu.snackString
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import ani.dantotsu.toast
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
|
||||
import com.davemorrissey.labs.subscaleview.ImageSource
|
||||
@@ -76,8 +78,12 @@ class ImageViewDialog : BottomSheetDialogFragment() {
|
||||
lifecycleScope.launch {
|
||||
val binding = _binding ?: return@launch
|
||||
|
||||
var bitmap = requireContext().loadBitmap(image, trans1 ?: listOf())
|
||||
val bitmap2 = if (image2 != null) requireContext().loadBitmap(image2, trans2 ?: listOf()) else null
|
||||
var bitmap = requireContext().loadBitmap_old(image, trans1 ?: listOf())
|
||||
var bitmap2 = if (image2 != null) requireContext().loadBitmap_old(image2, trans2 ?: listOf()) else null
|
||||
if (bitmap == null) {
|
||||
bitmap = requireContext().loadBitmap(image, trans1 ?: listOf())
|
||||
bitmap2 = if (image2 != null) requireContext().loadBitmap(image2, trans2 ?: listOf()) else null
|
||||
}
|
||||
|
||||
bitmap = if (bitmap2 != null && bitmap != null) mergeBitmap(bitmap, bitmap2,) else bitmap
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import ani.dantotsu.R
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.databinding.ActivityImageSearchBinding
|
||||
import ani.dantotsu.media.MediaDetailsActivity
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import ani.dantotsu.toast
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -46,6 +47,7 @@ class ImageSearchActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityImageSearchBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
||||
@@ -32,8 +32,10 @@ abstract class AnimeParser : BaseParser() {
|
||||
* Returns null, if no latest episode is found.
|
||||
* **/
|
||||
open suspend fun getLatestEpisode(animeLink: String, extra: Map<String, String>?, sAnime: SAnime, latest: Float): Episode?{
|
||||
return loadEpisodes(animeLink, extra, sAnime)
|
||||
val episodes = loadEpisodes(animeLink, extra, sAnime)
|
||||
val max = episodes
|
||||
.maxByOrNull { it.number.toFloatOrNull()?:0f }
|
||||
return max
|
||||
?.takeIf { latest < (it.number.toFloatOrNull() ?: 0.001f) }
|
||||
}
|
||||
|
||||
@@ -171,6 +173,17 @@ abstract class AnimeParser : BaseParser() {
|
||||
}
|
||||
}
|
||||
|
||||
class EmptyAnimeParser: AnimeParser() {
|
||||
override val name: String = "None"
|
||||
override val saveName: String = "None"
|
||||
|
||||
override val isDubAvailableSeparately: Boolean = false
|
||||
override suspend fun loadEpisodes(animeLink: String, extra: Map<String, String>?, sAnime: SAnime): List<Episode> = emptyList()
|
||||
override suspend fun loadVideoServers(episodeLink: String, extra: Map<String, String>?, sEpisode: SEpisode): List<VideoServer> = emptyList()
|
||||
|
||||
override suspend fun search(query: String): List<ShowResponse> = emptyList()
|
||||
}
|
||||
|
||||
/**
|
||||
* A class for containing Episode data of a particular parser
|
||||
* **/
|
||||
|
||||
@@ -38,7 +38,10 @@ import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.OutputStream
|
||||
@@ -66,6 +69,7 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
|
||||
override val saveName = extension.name
|
||||
override val hostUrl = extension.sources.first().name
|
||||
override val isDubAvailableSeparately = false
|
||||
override val isNSFW = extension.isNsfw
|
||||
override suspend fun loadEpisodes(animeLink: String, extra: Map<String, String>?, sAnime: SAnime): List<Episode> {
|
||||
val source = extension.sources.first()
|
||||
if (source is AnimeCatalogueSource) {
|
||||
@@ -176,6 +180,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
|
||||
override val name = extension.name
|
||||
override val saveName = extension.name
|
||||
override val hostUrl = extension.sources.first().name
|
||||
override val isNSFW = extension.isNsfw
|
||||
|
||||
override suspend fun loadChapters(mangaLink: String, extra: Map<String, String>?, sManga: SManga): List<MangaChapter> {
|
||||
val source = extension.sources.first() as? CatalogueSource ?: return emptyList()
|
||||
@@ -385,22 +390,22 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
|
||||
|
||||
|
||||
private fun SChapterToMangaChapter(sChapter: SChapter): MangaChapter {
|
||||
val parsedChapterTitle = parseChapterTitle(sChapter.name)
|
||||
/*val parsedChapterTitle = parseChapterTitle(sChapter.name)
|
||||
val number = if (sChapter.chapter_number.toInt() != -1){
|
||||
sChapter.chapter_number.toString()
|
||||
} else if(parsedChapterTitle.first != null || parsedChapterTitle.second != null){
|
||||
(parsedChapterTitle.first ?: "") + "." + (parsedChapterTitle.second ?: "")
|
||||
}else{
|
||||
sChapter.name
|
||||
}
|
||||
}*/
|
||||
return MangaChapter(
|
||||
number,
|
||||
sChapter.name,
|
||||
sChapter.url,
|
||||
if (parsedChapterTitle.first != null || parsedChapterTitle.second != null) {
|
||||
parsedChapterTitle.third
|
||||
} else {
|
||||
sChapter.name
|
||||
},
|
||||
//if (parsedChapterTitle.first != null || parsedChapterTitle.second != null) {
|
||||
// parsedChapterTitle.third
|
||||
//} else {
|
||||
sChapter.name,
|
||||
//},
|
||||
null,
|
||||
sChapter
|
||||
)
|
||||
@@ -496,7 +501,24 @@ class VideoServerPassthrough(val videoServer: VideoServer) : VideoExtractor() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun TrackToSubtitle(track: Track, type: SubtitleType = SubtitleType.VTT): Subtitle {
|
||||
return Subtitle(track.lang, track.url, type)
|
||||
private fun TrackToSubtitle(track: Track): Subtitle {
|
||||
//use Dispatchers.IO to make a HTTP request to determine the subtitle type
|
||||
var type: SubtitleType? = null
|
||||
runBlocking {
|
||||
type = findSubtitleType(track.url)
|
||||
}
|
||||
return Subtitle(track.lang, track.url, type?: SubtitleType.SRT)
|
||||
}
|
||||
|
||||
private fun findSubtitleType(url: String): SubtitleType? {
|
||||
// First, try to determine the type based on the URL file extension
|
||||
var type: SubtitleType? = when {
|
||||
url.endsWith(".vtt", true) -> SubtitleType.VTT
|
||||
url.endsWith(".ass", true) -> SubtitleType.ASS
|
||||
url.endsWith(".srt", true) -> SubtitleType.SRT
|
||||
else -> SubtitleType.UNKNOWN
|
||||
}
|
||||
|
||||
return type
|
||||
}
|
||||
}
|
||||
@@ -57,17 +57,17 @@ abstract class BaseParser {
|
||||
setUserText("Searching : ${mediaObj.mainName()}")
|
||||
val results = search(mediaObj.mainName())
|
||||
val sortedResults = if (results.isNotEmpty()) {
|
||||
results.sortedByDescending { FuzzySearch.ratio(it.name, mediaObj.mainName()) }
|
||||
results.sortedByDescending { FuzzySearch.ratio(it.name.lowercase(), mediaObj.mainName().lowercase()) }
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
response = sortedResults.firstOrNull()
|
||||
|
||||
if (response == null || FuzzySearch.ratio(response.name, mediaObj.mainName()) < 100) {
|
||||
if (response == null || FuzzySearch.ratio(response.name.lowercase(), mediaObj.mainName().lowercase()) < 100) {
|
||||
setUserText("Searching : ${mediaObj.nameRomaji}")
|
||||
val romajiResults = search(mediaObj.nameRomaji)
|
||||
val sortedRomajiResults = if (romajiResults.isNotEmpty()) {
|
||||
romajiResults.sortedByDescending { FuzzySearch.ratio(it.name, mediaObj.nameRomaji) }
|
||||
romajiResults.sortedByDescending { FuzzySearch.ratio(it.name.lowercase(), mediaObj.nameRomaji.lowercase()) }
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
@@ -78,10 +78,10 @@ abstract class BaseParser {
|
||||
logger("No exact match found in results. Using closest match from RomajiResults.")
|
||||
closestRomaji
|
||||
} else {
|
||||
val romajiRatio = FuzzySearch.ratio(closestRomaji?.name ?: "", mediaObj.nameRomaji)
|
||||
val mainNameRatio = FuzzySearch.ratio(response.name, mediaObj.mainName())
|
||||
logger("Fuzzy ratio for closest match in results: $mainNameRatio")
|
||||
logger("Fuzzy ratio for closest match in RomajiResults: $romajiRatio")
|
||||
val romajiRatio = FuzzySearch.ratio(closestRomaji?.name?.lowercase() ?: "", mediaObj.nameRomaji.lowercase())
|
||||
val mainNameRatio = FuzzySearch.ratio(response.name.lowercase(), mediaObj.mainName().lowercase())
|
||||
logger("Fuzzy ratio for closest match in results: $mainNameRatio for ${response.name.lowercase()}")
|
||||
logger("Fuzzy ratio for closest match in RomajiResults: $romajiRatio for ${closestRomaji?.name?.lowercase() ?: "None"}")
|
||||
|
||||
if (romajiRatio > mainNameRatio) {
|
||||
logger("RomajiResults has a closer match. Replacing response.")
|
||||
|
||||
@@ -11,9 +11,11 @@ import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||
abstract class WatchSources : BaseSources() {
|
||||
|
||||
override operator fun get(i: Int): AnimeParser {
|
||||
return (list.getOrNull(i)?:list[0]).get.value as AnimeParser
|
||||
return (list.getOrNull(i) ?: list.firstOrNull())?.get?.value as? AnimeParser
|
||||
?: EmptyAnimeParser()
|
||||
}
|
||||
|
||||
|
||||
suspend fun loadEpisodesFromMedia(i: Int, media: Media): MutableMap<String, Episode> {
|
||||
return tryWithSuspend(true) {
|
||||
val res = get(i).autoSearch(media) ?: return@tryWithSuspend mutableMapOf()
|
||||
@@ -40,7 +42,8 @@ abstract class WatchSources : BaseSources() {
|
||||
abstract class MangaReadSources : BaseSources() {
|
||||
|
||||
override operator fun get(i: Int): MangaParser {
|
||||
return (list.getOrNull(i)?:list[0]).get.value as MangaParser
|
||||
return (list.getOrNull(i)?:list.firstOrNull())?.get?.value as? MangaParser
|
||||
?: EmptyMangaParser()
|
||||
}
|
||||
|
||||
suspend fun loadChaptersFromMedia(i: Int, media: Media): MutableMap<String, MangaChapter> {
|
||||
|
||||
@@ -3,6 +3,7 @@ package ani.dantotsu.parsers
|
||||
import android.graphics.Bitmap
|
||||
import ani.dantotsu.FileUrl
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.media.manga.MangaNameAdapter
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
@@ -23,9 +24,11 @@ abstract class MangaParser : BaseParser() {
|
||||
* Returns null, if no latest chapter is found.
|
||||
* **/
|
||||
open suspend fun getLatestChapter(mangaLink: String, extra: Map<String, String>?, sManga: SManga, latest: Float): MangaChapter? {
|
||||
return loadChapters(mangaLink, extra, sManga)
|
||||
.maxByOrNull { it.number.toFloatOrNull() ?: 0f }
|
||||
?.takeIf { latest < (it.number.toFloatOrNull() ?: 0.001f) }
|
||||
val chapter = loadChapters(mangaLink, extra, sManga)
|
||||
val max = chapter
|
||||
.maxByOrNull { MangaNameAdapter.findChapterNumber(it.number) ?: 0f }
|
||||
return max
|
||||
?.takeIf { latest < (MangaNameAdapter.findChapterNumber(it.number) ?: 0.001f) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -33,26 +36,21 @@ abstract class MangaParser : BaseParser() {
|
||||
* **/
|
||||
abstract suspend fun loadImages(chapterLink: String, sChapter: SChapter): List<MangaImage>
|
||||
|
||||
override suspend fun autoSearch(mediaObj: Media): ShowResponse? {
|
||||
var response = loadSavedShowResponse(mediaObj.id)
|
||||
if (response != null) {
|
||||
saveShowResponse(mediaObj.id, response, true)
|
||||
} else {
|
||||
setUserText("Searching : ${mediaObj.mangaName()}")
|
||||
response = search(mediaObj.mangaName()).let { if (it.isNotEmpty()) it[0] else null }
|
||||
|
||||
if (response == null) {
|
||||
setUserText("Searching : ${mediaObj.nameRomaji}")
|
||||
response = search(mediaObj.nameRomaji).let { if (it.isNotEmpty()) it[0] else null }
|
||||
}
|
||||
saveShowResponse(mediaObj.id, response)
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
open fun getTransformation(): BitmapTransformation? = null
|
||||
}
|
||||
|
||||
class EmptyMangaParser: MangaParser() {
|
||||
override val name: String = "None"
|
||||
override val saveName: String = "None"
|
||||
|
||||
override suspend fun loadChapters(mangaLink: String, extra: Map<String, String>?, sManga: SManga): List<MangaChapter> = emptyList()
|
||||
|
||||
override suspend fun loadImages(chapterLink: String, sChapter: SChapter): List<MangaImage> = emptyList()
|
||||
|
||||
override suspend fun search(query: String): List<ShowResponse> = emptyList()
|
||||
}
|
||||
|
||||
data class MangaChapter(
|
||||
/**
|
||||
* Number of the Chapter in "String",
|
||||
|
||||
@@ -29,7 +29,9 @@ object MangaSources : MangaReadSources() {
|
||||
}
|
||||
|
||||
object HMangaSources : MangaReadSources() {
|
||||
val aList: List<Lazier<BaseParser>> = lazyList(
|
||||
)
|
||||
val aList: List<Lazier<BaseParser>> = lazyList()
|
||||
suspend fun init(fromExtensions: StateFlow<List<MangaExtension.Installed>>) {
|
||||
//todo
|
||||
}
|
||||
override val list = listOf(aList,MangaSources.list).flatten()
|
||||
}
|
||||
|
||||
@@ -159,5 +159,5 @@ enum class VideoType{
|
||||
}
|
||||
|
||||
enum class SubtitleType{
|
||||
VTT, ASS, SRT
|
||||
VTT, ASS, SRT, UNKNOWN
|
||||
}
|
||||
@@ -2,103 +2,84 @@ package ani.dantotsu.settings
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.ContextCompat.getSystemService
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.databinding.FragmentAnimeExtensionsBinding
|
||||
import ani.dantotsu.loadData
|
||||
import com.bumptech.glide.Glide
|
||||
import ani.dantotsu.settings.paging.AnimeExtensionAdapter
|
||||
import ani.dantotsu.settings.paging.AnimeExtensionsViewModel
|
||||
import ani.dantotsu.settings.paging.AnimeExtensionsViewModelFactory
|
||||
import ani.dantotsu.settings.paging.OnAnimeInstallClickListener
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class AnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||
class AnimeExtensionsFragment : Fragment(),
|
||||
SearchQueryHandler, OnAnimeInstallClickListener {
|
||||
private var _binding: FragmentAnimeExtensionsBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
val skipIcons = loadData("skip_extension_icons") ?: false
|
||||
private val viewModel: AnimeExtensionsViewModel by viewModels {
|
||||
AnimeExtensionsViewModelFactory(animeExtensionManager)
|
||||
}
|
||||
|
||||
private lateinit var extensionsRecyclerView: RecyclerView
|
||||
private lateinit var allextenstionsRecyclerView: RecyclerView
|
||||
private val animeExtensionManager: AnimeExtensionManager = Injekt.get<AnimeExtensionManager>()
|
||||
private val extensionsAdapter = AnimeExtensionsAdapter ({ pkg ->
|
||||
if(pkg.hasUpdate){
|
||||
val notificationManager =
|
||||
requireContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
animeExtensionManager.updateExtension(pkg)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{ installStep ->
|
||||
val builder = NotificationCompat.Builder(
|
||||
requireContext(),
|
||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_round_sync_24)
|
||||
.setContentTitle("Updating extension")
|
||||
.setContentText("Step: $installStep")
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
notificationManager.notify(1, builder.build())
|
||||
},
|
||||
{ error ->
|
||||
val builder = NotificationCompat.Builder(
|
||||
requireContext(),
|
||||
Notifications.CHANNEL_DOWNLOADER_ERROR
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_round_info_24)
|
||||
.setContentTitle("Update failed")
|
||||
.setContentText("Error: ${error.message}")
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
notificationManager.notify(1, builder.build())
|
||||
},
|
||||
{
|
||||
val builder = NotificationCompat.Builder(
|
||||
requireContext(),
|
||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||
)
|
||||
.setSmallIcon(androidx.media3.ui.R.drawable.exo_ic_check)
|
||||
.setContentTitle("Update complete")
|
||||
.setContentText("The extension has been successfully updated.")
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
notificationManager.notify(1, builder.build())
|
||||
}
|
||||
)
|
||||
}else {
|
||||
animeExtensionManager.uninstallExtension(pkg.pkgName)
|
||||
private val adapter by lazy {
|
||||
AnimeExtensionAdapter(this)
|
||||
}
|
||||
|
||||
private val animeExtensionManager: AnimeExtensionManager = Injekt.get()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentAnimeExtensionsBinding.inflate(inflater, container, false)
|
||||
|
||||
binding.allAnimeExtensionsRecyclerView.isNestedScrollingEnabled = true
|
||||
binding.allAnimeExtensionsRecyclerView.adapter = adapter
|
||||
binding.allAnimeExtensionsRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||
(binding.allAnimeExtensionsRecyclerView.layoutManager as LinearLayoutManager).isItemPrefetchEnabled = false
|
||||
|
||||
lifecycleScope.launch {
|
||||
viewModel.pagerFlow.collectLatest {
|
||||
adapter.submitData(it)
|
||||
}
|
||||
}
|
||||
}, skipIcons)
|
||||
private val allExtensionsAdapter = AllAnimeExtensionsAdapter(lifecycleScope, { pkgName ->
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun updateContentBasedOnQuery(query: String?) {
|
||||
viewModel.setSearchQuery(query ?: "")
|
||||
}
|
||||
|
||||
override fun onInstallClick(pkg: AnimeExtension.Available) {
|
||||
val context = requireContext()
|
||||
if (isAdded) {
|
||||
val notificationManager =
|
||||
requireContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
// Start the installation process
|
||||
animeExtensionManager.installExtension(pkgName)
|
||||
animeExtensionManager.installExtension(pkg)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{ installStep ->
|
||||
val builder = NotificationCompat.Builder(
|
||||
requireContext(),
|
||||
context,
|
||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_round_sync_24)
|
||||
@@ -108,72 +89,30 @@ class AnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||
notificationManager.notify(1, builder.build())
|
||||
},
|
||||
{ error ->
|
||||
FirebaseCrashlytics.getInstance().recordException(error)
|
||||
val builder = NotificationCompat.Builder(
|
||||
requireContext(),
|
||||
context,
|
||||
Notifications.CHANNEL_DOWNLOADER_ERROR
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_round_info_24)
|
||||
.setContentTitle("Installation failed")
|
||||
.setContentTitle("Installation failed: ${error.message}")
|
||||
.setContentText("Error: ${error.message}")
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
notificationManager.notify(1, builder.build())
|
||||
},
|
||||
{
|
||||
val builder = NotificationCompat.Builder(
|
||||
requireContext(),
|
||||
context,
|
||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||
)
|
||||
.setSmallIcon(androidx.media3.ui.R.drawable.exo_ic_check)
|
||||
.setSmallIcon(R.drawable.ic_round_download_24)
|
||||
.setContentTitle("Installation complete")
|
||||
.setContentText("The extension has been successfully installed.")
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
notificationManager.notify(1, builder.build())
|
||||
viewModel.invalidatePager()
|
||||
}
|
||||
)
|
||||
}, skipIcons)
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
_binding = FragmentAnimeExtensionsBinding.inflate(inflater, container, false)
|
||||
|
||||
extensionsRecyclerView = binding.animeExtensionsRecyclerView
|
||||
extensionsRecyclerView.layoutManager = LinearLayoutManager( requireContext())
|
||||
extensionsRecyclerView.adapter = extensionsAdapter
|
||||
|
||||
allextenstionsRecyclerView = binding.allAnimeExtensionsRecyclerView
|
||||
allextenstionsRecyclerView.layoutManager = LinearLayoutManager( requireContext())
|
||||
allextenstionsRecyclerView.adapter = allExtensionsAdapter
|
||||
|
||||
lifecycleScope.launch {
|
||||
animeExtensionManager.installedExtensionsFlow.collect { extensions ->
|
||||
extensionsAdapter.updateData(extensions)
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
combine(
|
||||
animeExtensionManager.availableExtensionsFlow,
|
||||
animeExtensionManager.installedExtensionsFlow
|
||||
) { availableExtensions, installedExtensions ->
|
||||
// Pair of available and installed extensions
|
||||
Pair(availableExtensions, installedExtensions)
|
||||
}.collect { pair ->
|
||||
val (availableExtensions, installedExtensions) = pair
|
||||
allExtensionsAdapter.updateData(availableExtensions, installedExtensions)
|
||||
}
|
||||
}
|
||||
val extensionsRecyclerView: RecyclerView = binding.animeExtensionsRecyclerView
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun updateContentBasedOnQuery(query: String?) {
|
||||
if (query.isNullOrEmpty()) {
|
||||
allExtensionsAdapter.filter("") // Reset the filter
|
||||
allextenstionsRecyclerView.visibility = View.VISIBLE
|
||||
extensionsRecyclerView.visibility = View.VISIBLE
|
||||
println("asdf: ${allExtensionsAdapter.getItemCount()}")
|
||||
} else {
|
||||
allExtensionsAdapter.filter(query)
|
||||
allextenstionsRecyclerView.visibility = View.VISIBLE
|
||||
extensionsRecyclerView.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,112 +121,4 @@ class AnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||
}
|
||||
|
||||
|
||||
private class AnimeExtensionsAdapter(private val onUninstallClicked: (AnimeExtension.Installed) -> Unit, skipIcons: Boolean) : RecyclerView.Adapter<AnimeExtensionsAdapter.ViewHolder>() {
|
||||
|
||||
private var extensions: List<AnimeExtension.Installed> = emptyList()
|
||||
val skipIcons = skipIcons
|
||||
|
||||
fun updateData(newExtensions: List<AnimeExtension.Installed>) {
|
||||
extensions = newExtensions
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_extension, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val extension = extensions[position]
|
||||
holder.extensionNameTextView.text = extension.name
|
||||
if (!skipIcons) {
|
||||
holder.extensionIconImageView.setImageDrawable(extension.icon)
|
||||
}
|
||||
if(extension.hasUpdate){
|
||||
holder.closeTextView.text = "Update"
|
||||
holder.closeTextView.setTextColor(ContextCompat.getColor(holder.itemView.context, R.color.warning))
|
||||
}else{
|
||||
holder.closeTextView.text = "Uninstall"
|
||||
}
|
||||
holder.closeTextView.setOnClickListener {
|
||||
onUninstallClicked(extension)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = extensions.size
|
||||
|
||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
||||
val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView)
|
||||
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
||||
}
|
||||
}
|
||||
|
||||
private class AllAnimeExtensionsAdapter(private val coroutineScope: CoroutineScope,
|
||||
private val onButtonClicked: (AnimeExtension.Available) -> Unit, skipIcons: Boolean) : RecyclerView.Adapter<AllAnimeExtensionsAdapter.ViewHolder>() {
|
||||
private var extensions: List<AnimeExtension.Available> = emptyList()
|
||||
val skipIcons = skipIcons
|
||||
|
||||
fun updateData(newExtensions: List<AnimeExtension.Available>, installedExtensions: List<AnimeExtension.Installed> = emptyList()) {
|
||||
val installedPkgNames = installedExtensions.map { it.pkgName }.toSet()
|
||||
extensions = newExtensions.filter { it.pkgName !in installedPkgNames }
|
||||
filteredExtensions = extensions
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AllAnimeExtensionsAdapter.ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_extension_all, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val extension = filteredExtensions[position]
|
||||
holder.extensionNameTextView.text = extension.name
|
||||
if (!skipIcons) {
|
||||
coroutineScope.launch {
|
||||
val drawable = urlToDrawable(holder.itemView.context, extension.iconUrl)
|
||||
holder.extensionIconImageView.setImageDrawable(drawable)
|
||||
}
|
||||
}
|
||||
holder.closeTextView.text = "Install"
|
||||
holder.closeTextView.setOnClickListener {
|
||||
onButtonClicked(extension)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = filteredExtensions.size
|
||||
|
||||
private var filteredExtensions: List<AnimeExtension.Available> = emptyList()
|
||||
|
||||
fun filter(query: String) {
|
||||
filteredExtensions = if (query.isEmpty()) {
|
||||
extensions
|
||||
} else {
|
||||
extensions.filter { it.name.contains(query, ignoreCase = true) }
|
||||
}
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
||||
val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView)
|
||||
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
||||
}
|
||||
|
||||
suspend fun urlToDrawable(context: Context, url: String): Drawable? {
|
||||
return withContext(Dispatchers.IO) {
|
||||
try {
|
||||
return@withContext Glide.with(context)
|
||||
.load(url)
|
||||
.submit()
|
||||
.get()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return@withContext null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.SearchView
|
||||
import android.widget.TextView
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
@@ -33,6 +34,7 @@ import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||
import ani.dantotsu.databinding.ActivityExtensionsBinding
|
||||
import ani.dantotsu.home.AnimeFragment
|
||||
import ani.dantotsu.home.MangaFragment
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
@@ -49,20 +51,17 @@ import uy.kohesive.injekt.injectLazy
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
class ExtensionsActivity : AppCompatActivity() {
|
||||
class ExtensionsActivity : AppCompatActivity() {
|
||||
private val restartMainActivity = object : OnBackPressedCallback(false) {
|
||||
override fun handleOnBackPressed() = startMainActivity(this@ExtensionsActivity)
|
||||
}
|
||||
lateinit var binding: ActivityExtensionsBinding
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityExtensionsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
@@ -71,12 +70,14 @@ class ExtensionsActivity : AppCompatActivity() {
|
||||
val viewPager = findViewById<ViewPager2>(R.id.viewPager)
|
||||
|
||||
viewPager.adapter = object : FragmentStateAdapter(this) {
|
||||
override fun getItemCount(): Int = 2
|
||||
override fun getItemCount(): Int = 4
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return when (position) {
|
||||
0 -> AnimeExtensionsFragment()
|
||||
1 -> MangaExtensionsFragment()
|
||||
0 -> InstalledAnimeExtensionsFragment()
|
||||
1 -> AnimeExtensionsFragment()
|
||||
2 -> InstalledMangaExtensionsFragment()
|
||||
3 -> MangaExtensionsFragment()
|
||||
else -> AnimeExtensionsFragment()
|
||||
}
|
||||
}
|
||||
@@ -84,8 +85,10 @@ class ExtensionsActivity : AppCompatActivity() {
|
||||
|
||||
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
|
||||
tab.text = when (position) {
|
||||
0 -> "Anime" // Your tab title
|
||||
1 -> "Manga" // Your tab title
|
||||
0 -> "Installed Anime"
|
||||
1 -> "Available Anime"
|
||||
2 -> "Installed Manga"
|
||||
3 -> "Available Manga"
|
||||
else -> null
|
||||
}
|
||||
}.attach()
|
||||
@@ -132,4 +135,4 @@ class ExtensionsActivity : AppCompatActivity() {
|
||||
|
||||
interface SearchQueryHandler {
|
||||
fun updateContentBasedOnQuery(query: String?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,33 +7,105 @@ import ani.dantotsu.R
|
||||
import ani.dantotsu.currContext
|
||||
import ani.dantotsu.databinding.ActivityFaqBinding
|
||||
import ani.dantotsu.initActivity
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
|
||||
class FAQActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivityFaqBinding
|
||||
|
||||
private val faqs = listOf(
|
||||
private val faqs by lazy {
|
||||
listOf(
|
||||
|
||||
Triple(R.drawable.ic_round_help_24, currContext()!!.getString(R.string.question_1), currContext()!!.getString(R.string.answer_1)),
|
||||
Triple(R.drawable.ic_round_auto_awesome_24, currContext()!!.getString(R.string.question_2), currContext()!!.getString(R.string.answer_2)),
|
||||
Triple(R.drawable.ic_round_auto_awesome_24, currContext()!!.getString(R.string.question_17), currContext()!!.getString(R.string.answer_17)),
|
||||
Triple(R.drawable.ic_round_download_24, currContext()!!.getString(R.string.question_3), currContext()!!.getString(R.string.answer_3)),
|
||||
Triple(R.drawable.ic_round_help_24, currContext()!!.getString(R.string.question_16), currContext()!!.getString(R.string.answer_16)),
|
||||
Triple(R.drawable.ic_round_dns_24, currContext()!!.getString(R.string.question_4), currContext()!!.getString(R.string.answer_4)),
|
||||
Triple(R.drawable.ic_baseline_screen_lock_portrait_24, currContext()!!.getString(R.string.question_5), currContext()!!.getString(R.string.answer_5)),
|
||||
Triple(R.drawable.ic_anilist, currContext()!!.getString(R.string.question_6), currContext()!!.getString(R.string.answer_6)),
|
||||
Triple(R.drawable.ic_round_movie_filter_24, currContext()!!.getString(R.string.question_7), currContext()!!.getString(R.string.answer_7)),
|
||||
Triple(R.drawable.ic_round_menu_book_24, currContext()!!.getString(R.string.question_8), currContext()!!.getString(R.string.answer_8)),
|
||||
Triple(R.drawable.ic_round_lock_open_24, currContext()!!.getString(R.string.question_9), currContext()!!.getString(R.string.answer_9)),
|
||||
Triple(R.drawable.ic_round_smart_button_24, currContext()!!.getString(R.string.question_10), currContext()!!.getString(R.string.answer_10)),
|
||||
Triple(R.drawable.ic_round_smart_button_24, currContext()!!.getString(R.string.question_11), currContext()!!.getString(R.string.answer_11)),
|
||||
Triple(R.drawable.ic_round_info_24, currContext()!!.getString(R.string.question_12), currContext()!!.getString(R.string.answer_12)),
|
||||
Triple(R.drawable.ic_round_help_24, currContext()!!.getString(R.string.question_13), currContext()!!.getString(R.string.answer_13)),
|
||||
Triple(R.drawable.ic_round_art_track_24, currContext()!!.getString(R.string.question_14), currContext()!!.getString(R.string.answer_14)),
|
||||
Triple(R.drawable.ic_round_video_settings_24, currContext()!!.getString(R.string.question_15), currContext()!!.getString(R.string.answer_15))
|
||||
Triple(
|
||||
R.drawable.ic_round_help_24,
|
||||
currContext()!!.getString(R.string.question_1),
|
||||
currContext()!!.getString(R.string.answer_1)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_auto_awesome_24,
|
||||
currContext()!!.getString(R.string.question_2),
|
||||
currContext()!!.getString(R.string.answer_2)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_auto_awesome_24,
|
||||
currContext()!!.getString(R.string.question_17),
|
||||
currContext()!!.getString(R.string.answer_17)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_download_24,
|
||||
currContext()!!.getString(R.string.question_3),
|
||||
currContext()!!.getString(R.string.answer_3)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_help_24,
|
||||
currContext()!!.getString(R.string.question_16),
|
||||
currContext()!!.getString(R.string.answer_16)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_dns_24,
|
||||
currContext()!!.getString(R.string.question_4),
|
||||
currContext()!!.getString(R.string.answer_4)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_baseline_screen_lock_portrait_24,
|
||||
currContext()!!.getString(R.string.question_5),
|
||||
currContext()!!.getString(R.string.answer_5)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_anilist,
|
||||
currContext()!!.getString(R.string.question_6),
|
||||
currContext()!!.getString(R.string.answer_6)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_movie_filter_24,
|
||||
currContext()!!.getString(R.string.question_7),
|
||||
currContext()!!.getString(R.string.answer_7)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_menu_book_24,
|
||||
currContext()!!.getString(R.string.question_8),
|
||||
currContext()!!.getString(R.string.answer_8)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_lock_open_24,
|
||||
currContext()!!.getString(R.string.question_9),
|
||||
currContext()!!.getString(R.string.answer_9)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_smart_button_24,
|
||||
currContext()!!.getString(R.string.question_10),
|
||||
currContext()!!.getString(R.string.answer_10)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_smart_button_24,
|
||||
currContext()!!.getString(R.string.question_11),
|
||||
currContext()!!.getString(R.string.answer_11)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_info_24,
|
||||
currContext()!!.getString(R.string.question_12),
|
||||
currContext()!!.getString(R.string.answer_12)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_help_24,
|
||||
currContext()!!.getString(R.string.question_13),
|
||||
currContext()!!.getString(R.string.answer_13)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_art_track_24,
|
||||
currContext()!!.getString(R.string.question_14),
|
||||
currContext()!!.getString(R.string.answer_14)
|
||||
),
|
||||
Triple(
|
||||
R.drawable.ic_round_video_settings_24,
|
||||
currContext()!!.getString(R.string.question_15),
|
||||
currContext()!!.getString(R.string.answer_15)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityFaqBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
package ani.dantotsu.settings
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.databinding.FragmentAnimeExtensionsBinding
|
||||
import ani.dantotsu.loadData
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||
import kotlinx.coroutines.launch
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class InstalledAnimeExtensionsFragment : Fragment() {
|
||||
private var _binding: FragmentAnimeExtensionsBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
private lateinit var extensionsRecyclerView: RecyclerView
|
||||
val skipIcons = loadData("skip_extension_icons") ?: false
|
||||
private val animeExtensionManager: AnimeExtensionManager = Injekt.get()
|
||||
private val extensionsAdapter = AnimeExtensionsAdapter({ pkg ->
|
||||
if (isAdded) { // Check if the fragment is currently added to its activity
|
||||
val context = requireContext() // Store context in a variable
|
||||
val notificationManager =
|
||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // Initialize NotificationManager once
|
||||
|
||||
if (pkg.hasUpdate) {
|
||||
animeExtensionManager.updateExtension(pkg)
|
||||
.observeOn(AndroidSchedulers.mainThread()) // Observe on main thread
|
||||
.subscribe(
|
||||
{ installStep ->
|
||||
val builder = NotificationCompat.Builder(
|
||||
context,
|
||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_round_sync_24)
|
||||
.setContentTitle("Updating extension")
|
||||
.setContentText("Step: $installStep")
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
notificationManager.notify(1, builder.build())
|
||||
},
|
||||
{ error ->
|
||||
FirebaseCrashlytics.getInstance().recordException(error)
|
||||
Log.e("AnimeExtensionsAdapter", "Error: ", error) // Log the error
|
||||
val builder = NotificationCompat.Builder(
|
||||
context,
|
||||
Notifications.CHANNEL_DOWNLOADER_ERROR
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_round_info_24)
|
||||
.setContentTitle("Update failed: ${error.message}")
|
||||
.setContentText("Error: ${error.message}")
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
notificationManager.notify(1, builder.build())
|
||||
},
|
||||
{
|
||||
val builder = NotificationCompat.Builder(
|
||||
context,
|
||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||
)
|
||||
.setSmallIcon(androidx.media3.ui.R.drawable.exo_ic_check)
|
||||
.setContentTitle("Update complete")
|
||||
.setContentText("The extension has been successfully updated.")
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
notificationManager.notify(1, builder.build())
|
||||
}
|
||||
)
|
||||
} else {
|
||||
animeExtensionManager.uninstallExtension(pkg.pkgName)
|
||||
}
|
||||
}
|
||||
}, skipIcons)
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentAnimeExtensionsBinding.inflate(inflater, container, false)
|
||||
|
||||
extensionsRecyclerView = binding.allAnimeExtensionsRecyclerView
|
||||
extensionsRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||
extensionsRecyclerView.adapter = extensionsAdapter
|
||||
|
||||
|
||||
lifecycleScope.launch {
|
||||
animeExtensionManager.installedExtensionsFlow.collect { extensions ->
|
||||
extensionsAdapter.updateData(extensions)
|
||||
}
|
||||
}
|
||||
val extensionsRecyclerView: RecyclerView = binding.allAnimeExtensionsRecyclerView
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView();_binding = null
|
||||
}
|
||||
|
||||
|
||||
private class AnimeExtensionsAdapter(
|
||||
private val onUninstallClicked: (AnimeExtension.Installed) -> Unit,
|
||||
skipIcons: Boolean
|
||||
) : ListAdapter<AnimeExtension.Installed, AnimeExtensionsAdapter.ViewHolder>(
|
||||
DIFF_CALLBACK_INSTALLED
|
||||
) {
|
||||
|
||||
val skipIcons = skipIcons
|
||||
|
||||
fun updateData(newExtensions: List<AnimeExtension.Installed>) {
|
||||
submitList(newExtensions) // Use submitList instead of manual list handling
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_extension, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val extension = getItem(position) // Use getItem() from ListAdapter
|
||||
holder.extensionNameTextView.text = extension.name
|
||||
if (!skipIcons) {
|
||||
holder.extensionIconImageView.setImageDrawable(extension.icon)
|
||||
}
|
||||
if (extension.hasUpdate) {
|
||||
holder.closeTextView.text = "Update"
|
||||
holder.closeTextView.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
holder.itemView.context,
|
||||
R.color.warning
|
||||
)
|
||||
)
|
||||
} else {
|
||||
holder.closeTextView.text = "Uninstall"
|
||||
}
|
||||
holder.closeTextView.setOnClickListener {
|
||||
onUninstallClicked(extension)
|
||||
}
|
||||
}
|
||||
|
||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
||||
val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView)
|
||||
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val DIFF_CALLBACK_INSTALLED =
|
||||
object : DiffUtil.ItemCallback<AnimeExtension.Installed>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: AnimeExtension.Installed,
|
||||
newItem: AnimeExtension.Installed
|
||||
): Boolean {
|
||||
return oldItem.pkgName == newItem.pkgName
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: AnimeExtension.Installed,
|
||||
newItem: AnimeExtension.Installed
|
||||
): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
package ani.dantotsu.settings
|
||||
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.databinding.FragmentMangaExtensionsBinding
|
||||
import ani.dantotsu.loadData
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
|
||||
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
||||
import kotlinx.coroutines.launch
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class InstalledMangaExtensionsFragment : Fragment() {
|
||||
private var _binding: FragmentMangaExtensionsBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
private lateinit var extensionsRecyclerView: RecyclerView
|
||||
val skipIcons = loadData("skip_extension_icons") ?: false
|
||||
private val mangaExtensionManager: MangaExtensionManager = Injekt.get()
|
||||
private val extensionsAdapter = MangaExtensionsAdapter({ pkg ->
|
||||
if (isAdded) { // Check if the fragment is currently added to its activity
|
||||
val context = requireContext() // Store context in a variable
|
||||
val notificationManager =
|
||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // Initialize NotificationManager once
|
||||
|
||||
if (pkg.hasUpdate) {
|
||||
mangaExtensionManager.updateExtension(pkg)
|
||||
.observeOn(AndroidSchedulers.mainThread()) // Observe on main thread
|
||||
.subscribe(
|
||||
{ installStep ->
|
||||
val builder = NotificationCompat.Builder(
|
||||
context,
|
||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_round_sync_24)
|
||||
.setContentTitle("Updating extension")
|
||||
.setContentText("Step: $installStep")
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
notificationManager.notify(1, builder.build())
|
||||
},
|
||||
{ error ->
|
||||
FirebaseCrashlytics.getInstance().recordException(error)
|
||||
Log.e("MangaExtensionsAdapter", "Error: ", error) // Log the error
|
||||
val builder = NotificationCompat.Builder(
|
||||
context,
|
||||
Notifications.CHANNEL_DOWNLOADER_ERROR
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_round_info_24)
|
||||
.setContentTitle("Update failed: ${error.message}")
|
||||
.setContentText("Error: ${error.message}")
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
notificationManager.notify(1, builder.build())
|
||||
},
|
||||
{
|
||||
val builder = NotificationCompat.Builder(
|
||||
context,
|
||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||
)
|
||||
.setSmallIcon(androidx.media3.ui.R.drawable.exo_ic_check)
|
||||
.setContentTitle("Update complete")
|
||||
.setContentText("The extension has been successfully updated.")
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
notificationManager.notify(1, builder.build())
|
||||
}
|
||||
)
|
||||
} else {
|
||||
mangaExtensionManager.uninstallExtension(pkg.pkgName)
|
||||
}
|
||||
}
|
||||
}, skipIcons)
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentMangaExtensionsBinding.inflate(inflater, container, false)
|
||||
|
||||
extensionsRecyclerView = binding.allMangaExtensionsRecyclerView
|
||||
extensionsRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||
extensionsRecyclerView.adapter = extensionsAdapter
|
||||
|
||||
|
||||
lifecycleScope.launch {
|
||||
mangaExtensionManager.installedExtensionsFlow.collect { extensions ->
|
||||
extensionsAdapter.updateData(extensions)
|
||||
}
|
||||
}
|
||||
val extensionsRecyclerView: RecyclerView = binding.allMangaExtensionsRecyclerView
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView();_binding = null
|
||||
}
|
||||
|
||||
|
||||
private class MangaExtensionsAdapter(
|
||||
private val onUninstallClicked: (MangaExtension.Installed) -> Unit,
|
||||
skipIcons: Boolean
|
||||
) : ListAdapter<MangaExtension.Installed, MangaExtensionsAdapter.ViewHolder>(
|
||||
DIFF_CALLBACK_INSTALLED
|
||||
) {
|
||||
|
||||
val skipIcons = skipIcons
|
||||
|
||||
fun updateData(newExtensions: List<MangaExtension.Installed>) {
|
||||
submitList(newExtensions) // Use submitList instead of manual list handling
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_extension, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val extension = getItem(position) // Use getItem() from ListAdapter
|
||||
holder.extensionNameTextView.text = extension.name
|
||||
if (!skipIcons) {
|
||||
holder.extensionIconImageView.setImageDrawable(extension.icon)
|
||||
}
|
||||
if (extension.hasUpdate) {
|
||||
holder.closeTextView.text = "Update"
|
||||
holder.closeTextView.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
holder.itemView.context,
|
||||
R.color.warning
|
||||
)
|
||||
)
|
||||
} else {
|
||||
holder.closeTextView.text = "Uninstall"
|
||||
}
|
||||
holder.closeTextView.setOnClickListener {
|
||||
onUninstallClicked(extension)
|
||||
}
|
||||
}
|
||||
|
||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
||||
val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView)
|
||||
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val DIFF_CALLBACK_INSTALLED =
|
||||
object : DiffUtil.ItemCallback<MangaExtension.Installed>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: MangaExtension.Installed,
|
||||
newItem: MangaExtension.Installed
|
||||
): Boolean {
|
||||
return oldItem.pkgName == newItem.pkgName
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: MangaExtension.Installed,
|
||||
newItem: MangaExtension.Installed
|
||||
): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -2,103 +2,85 @@ package ani.dantotsu.settings
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.databinding.FragmentMangaBinding
|
||||
import ani.dantotsu.databinding.FragmentMangaExtensionsBinding
|
||||
import ani.dantotsu.loadData
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
|
||||
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import ani.dantotsu.settings.paging.MangaExtensionAdapter
|
||||
import ani.dantotsu.settings.paging.MangaExtensionsViewModel
|
||||
import ani.dantotsu.settings.paging.MangaExtensionsViewModelFactory
|
||||
import ani.dantotsu.settings.paging.OnMangaInstallClickListener
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
|
||||
class MangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||
class MangaExtensionsFragment : Fragment(),
|
||||
SearchQueryHandler, OnMangaInstallClickListener {
|
||||
private var _binding: FragmentMangaExtensionsBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
val skipIcons = loadData("skip_extension_icons") ?: false
|
||||
private val viewModel: MangaExtensionsViewModel by viewModels {
|
||||
MangaExtensionsViewModelFactory(mangaExtensionManager)
|
||||
}
|
||||
|
||||
private lateinit var extensionsRecyclerView: RecyclerView
|
||||
private lateinit var allextenstionsRecyclerView: RecyclerView
|
||||
private val mangaExtensionManager:MangaExtensionManager = Injekt.get<MangaExtensionManager>()
|
||||
private val extensionsAdapter = MangaExtensionsAdapter ({ pkg ->
|
||||
if(pkg.hasUpdate){
|
||||
val notificationManager =
|
||||
requireContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
mangaExtensionManager.updateExtension(pkg)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{ installStep ->
|
||||
val builder = NotificationCompat.Builder(
|
||||
requireContext(),
|
||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_round_sync_24)
|
||||
.setContentTitle("Updating extension")
|
||||
.setContentText("Step: $installStep")
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
notificationManager.notify(1, builder.build())
|
||||
},
|
||||
{ error ->
|
||||
val builder = NotificationCompat.Builder(
|
||||
requireContext(),
|
||||
Notifications.CHANNEL_DOWNLOADER_ERROR
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_round_info_24)
|
||||
.setContentTitle("Update failed")
|
||||
.setContentText("Error: ${error.message}")
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
notificationManager.notify(1, builder.build())
|
||||
},
|
||||
{
|
||||
val builder = NotificationCompat.Builder(
|
||||
requireContext(),
|
||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||
)
|
||||
.setSmallIcon(androidx.media3.ui.R.drawable.exo_ic_check)
|
||||
.setContentTitle("Update complete")
|
||||
.setContentText("The extension has been successfully updated.")
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
notificationManager.notify(1, builder.build())
|
||||
}
|
||||
)
|
||||
}else {
|
||||
mangaExtensionManager.uninstallExtension(pkg.pkgName)
|
||||
private val adapter by lazy {
|
||||
MangaExtensionAdapter(this)
|
||||
}
|
||||
|
||||
private val mangaExtensionManager: MangaExtensionManager = Injekt.get()
|
||||
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentMangaExtensionsBinding.inflate(inflater, container, false)
|
||||
|
||||
binding.allMangaExtensionsRecyclerView.isNestedScrollingEnabled = true
|
||||
binding.allMangaExtensionsRecyclerView.adapter = adapter
|
||||
binding.allMangaExtensionsRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||
(binding.allMangaExtensionsRecyclerView.layoutManager as LinearLayoutManager).isItemPrefetchEnabled = false
|
||||
|
||||
lifecycleScope.launch {
|
||||
viewModel.pagerFlow.collectLatest {
|
||||
adapter.submitData(it)
|
||||
}
|
||||
}
|
||||
}, skipIcons)
|
||||
private val allExtensionsAdapter =
|
||||
AllMangaExtensionsAdapter(lifecycleScope, { pkgName ->
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun updateContentBasedOnQuery(query: String?) {
|
||||
viewModel.setSearchQuery(query ?: "")
|
||||
}
|
||||
|
||||
override fun onInstallClick(pkg: MangaExtension.Available) {
|
||||
if (isAdded) { // Check if the fragment is currently added to its activity
|
||||
val context = requireContext()
|
||||
val notificationManager =
|
||||
requireContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
// Start the installation process
|
||||
mangaExtensionManager.installExtension(pkgName)
|
||||
mangaExtensionManager.installExtension(pkg)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{ installStep ->
|
||||
val builder = NotificationCompat.Builder(
|
||||
requireContext(),
|
||||
context,
|
||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_round_sync_24)
|
||||
@@ -108,72 +90,30 @@ class MangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||
notificationManager.notify(1, builder.build())
|
||||
},
|
||||
{ error ->
|
||||
FirebaseCrashlytics.getInstance().recordException(error)
|
||||
val builder = NotificationCompat.Builder(
|
||||
requireContext(),
|
||||
context,
|
||||
Notifications.CHANNEL_DOWNLOADER_ERROR
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_round_info_24)
|
||||
.setContentTitle("Installation failed")
|
||||
.setContentTitle("Installation failed: ${error.message}")
|
||||
.setContentText("Error: ${error.message}")
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
notificationManager.notify(1, builder.build())
|
||||
},
|
||||
{
|
||||
val builder = NotificationCompat.Builder(
|
||||
requireContext(),
|
||||
context,
|
||||
Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||
)
|
||||
.setSmallIcon(androidx.media3.ui.R.drawable.exo_ic_check)
|
||||
.setSmallIcon(R.drawable.ic_round_download_24)
|
||||
.setContentTitle("Installation complete")
|
||||
.setContentText("The extension has been successfully installed.")
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
notificationManager.notify(1, builder.build())
|
||||
viewModel.invalidatePager()
|
||||
}
|
||||
)
|
||||
}, skipIcons)
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
_binding = FragmentMangaExtensionsBinding.inflate(inflater, container, false)
|
||||
|
||||
extensionsRecyclerView = binding.mangaExtensionsRecyclerView
|
||||
extensionsRecyclerView.layoutManager = LinearLayoutManager( requireContext())
|
||||
extensionsRecyclerView.adapter = extensionsAdapter
|
||||
|
||||
allextenstionsRecyclerView = binding.allMangaExtensionsRecyclerView
|
||||
allextenstionsRecyclerView.layoutManager = LinearLayoutManager( requireContext())
|
||||
allextenstionsRecyclerView.adapter = allExtensionsAdapter
|
||||
|
||||
lifecycleScope.launch {
|
||||
mangaExtensionManager.installedExtensionsFlow.collect { extensions ->
|
||||
extensionsAdapter.updateData(extensions)
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
combine(
|
||||
mangaExtensionManager.availableExtensionsFlow,
|
||||
mangaExtensionManager.installedExtensionsFlow
|
||||
) { availableExtensions, installedExtensions ->
|
||||
// Pair of available and installed extensions
|
||||
Pair(availableExtensions, installedExtensions)
|
||||
}.collect { pair ->
|
||||
val (availableExtensions, installedExtensions) = pair
|
||||
allExtensionsAdapter.updateData(availableExtensions, installedExtensions)
|
||||
}
|
||||
}
|
||||
val extensionsRecyclerView: RecyclerView = binding.mangaExtensionsRecyclerView
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun updateContentBasedOnQuery(query: String?) {
|
||||
if (query.isNullOrEmpty()) {
|
||||
allExtensionsAdapter.filter("") // Reset the filter
|
||||
allextenstionsRecyclerView.visibility = View.VISIBLE
|
||||
extensionsRecyclerView.visibility = View.VISIBLE
|
||||
} else {
|
||||
allExtensionsAdapter.filter(query)
|
||||
allextenstionsRecyclerView.visibility = View.VISIBLE
|
||||
extensionsRecyclerView.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,112 +121,6 @@ class MangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||
super.onDestroyView();_binding = null
|
||||
}
|
||||
|
||||
private class MangaExtensionsAdapter(private val onUninstallClicked: (MangaExtension.Installed) -> Unit, skipIcons: Boolean) : RecyclerView.Adapter<MangaExtensionsAdapter.ViewHolder>() {
|
||||
|
||||
private var extensions: List<MangaExtension.Installed> = emptyList()
|
||||
val skipIcons = skipIcons
|
||||
|
||||
fun updateData(newExtensions: List<MangaExtension.Installed>) {
|
||||
extensions = newExtensions
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_extension, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val extension = extensions[position]
|
||||
holder.extensionNameTextView.text = extension.name
|
||||
if(!skipIcons) {
|
||||
holder.extensionIconImageView.setImageDrawable(extension.icon)
|
||||
}
|
||||
if(extension.hasUpdate){
|
||||
holder.closeTextView.text = "Update"
|
||||
holder.closeTextView.setTextColor(ContextCompat.getColor(holder.itemView.context, R.color.warning))
|
||||
}else{
|
||||
holder.closeTextView.text = "Uninstall"
|
||||
}
|
||||
holder.closeTextView.setOnClickListener {
|
||||
onUninstallClicked(extension)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = extensions.size
|
||||
|
||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
||||
val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView)
|
||||
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
||||
}
|
||||
}
|
||||
|
||||
private class AllMangaExtensionsAdapter(private val coroutineScope: CoroutineScope,
|
||||
private val onButtonClicked: (MangaExtension.Available) -> Unit, skipIcons: Boolean) : RecyclerView.Adapter<AllMangaExtensionsAdapter.ViewHolder>() {
|
||||
private var extensions: List<MangaExtension.Available> = emptyList()
|
||||
val skipIcons = skipIcons
|
||||
|
||||
fun updateData(newExtensions: List<MangaExtension.Available>, installedExtensions: List<MangaExtension.Installed> = emptyList()) {
|
||||
val installedPkgNames = installedExtensions.map { it.pkgName }.toSet()
|
||||
extensions = newExtensions.filter { it.pkgName !in installedPkgNames }
|
||||
filteredExtensions = extensions
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AllMangaExtensionsAdapter.ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_extension_all, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val extension = filteredExtensions[position]
|
||||
holder.extensionNameTextView.text = extension.name
|
||||
if (!skipIcons) {
|
||||
coroutineScope.launch {
|
||||
val drawable = urlToDrawable(holder.itemView.context, extension.iconUrl)
|
||||
holder.extensionIconImageView.setImageDrawable(drawable)
|
||||
}
|
||||
}
|
||||
holder.closeTextView.text = "Install"
|
||||
holder.closeTextView.setOnClickListener {
|
||||
onButtonClicked(extension)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = filteredExtensions.size
|
||||
|
||||
private var filteredExtensions: List<MangaExtension.Available> = emptyList()
|
||||
|
||||
fun filter(query: String) {
|
||||
filteredExtensions = if (query.isEmpty()) {
|
||||
extensions
|
||||
} else {
|
||||
extensions.filter { it.name.contains(query, ignoreCase = true) }
|
||||
}
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
||||
val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView)
|
||||
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
||||
}
|
||||
|
||||
suspend fun urlToDrawable(context: Context, url: String): Drawable? {
|
||||
return withContext(Dispatchers.IO) {
|
||||
try {
|
||||
return@withContext Glide.with(context)
|
||||
.load(url)
|
||||
.submit()
|
||||
.get()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return@withContext null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import ani.dantotsu.databinding.ActivityPlayerSettingsBinding
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.others.getSerialized
|
||||
import ani.dantotsu.parsers.Subtitle
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@@ -30,6 +31,7 @@ class PlayerSettingsActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityPlayerSettingsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
||||
@@ -12,12 +12,14 @@ import ani.dantotsu.navBarHeight
|
||||
import ani.dantotsu.saveData
|
||||
import ani.dantotsu.snackString
|
||||
import ani.dantotsu.statusBarHeight
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
|
||||
class ReaderSettingsActivity : AppCompatActivity() {
|
||||
lateinit var binding: ActivityReaderSettingsBinding
|
||||
private val reader = "reader_settings"
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityReaderSettingsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
@@ -31,6 +32,8 @@ import ani.dantotsu.subcriptions.Notifications.Companion.openSettings
|
||||
import ani.dantotsu.subcriptions.Subscription.Companion.defaultTime
|
||||
import ani.dantotsu.subcriptions.Subscription.Companion.startSubscription
|
||||
import ani.dantotsu.subcriptions.Subscription.Companion.timeMinutes
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||
import io.noties.markwon.Markwon
|
||||
@@ -54,6 +57,7 @@ class SettingsActivity : AppCompatActivity() {
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
@@ -98,18 +102,34 @@ OS Version: $CODENAME $RELEASE ($SDK_INT)
|
||||
binding.settingsUseMaterialYou.isChecked = getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getBoolean("use_material_you", false)
|
||||
binding.settingsUseMaterialYou.setOnCheckedChangeListener { _, isChecked ->
|
||||
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit().putBoolean("use_material_you", isChecked).apply()
|
||||
restartApp()
|
||||
}
|
||||
|
||||
val animeSource = loadData<Int>("settings_def_anime_source_s")?.let { if (it >= AnimeSources.names.size) 0 else it } ?: 0
|
||||
if (MangaSources.names.isNotEmpty() && animeSource in 0 until MangaSources.names.size) {
|
||||
binding.mangaSource.setText(MangaSources.names[animeSource], false)
|
||||
val themeString = getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getString("theme", "PURPLE")!!
|
||||
binding.themeSwitcher.setText(themeString.substring(0, 1) + themeString.substring(1).lowercase())
|
||||
|
||||
binding.themeSwitcher.setAdapter(ArrayAdapter(this, R.layout.item_dropdown, ThemeManager.Companion.Theme.values().map { it.theme.substring(0, 1) + it.theme.substring(1).lowercase() }))
|
||||
|
||||
binding.themeSwitcher.setOnItemClickListener { _, _, i, _ ->
|
||||
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit().putString("theme", ThemeManager.Companion.Theme.values()[i].theme).apply()
|
||||
//ActivityHelper.shouldRefreshMainActivity = true
|
||||
binding.themeSwitcher.clearFocus()
|
||||
restartApp()
|
||||
|
||||
}
|
||||
|
||||
//val animeSource = loadData<Int>("settings_def_anime_source_s")?.let { if (it >= AnimeSources.names.size) 0 else it } ?: 0
|
||||
val animeSource = getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getInt("settings_def_anime_source_s_r", 0)
|
||||
if (AnimeSources.names.isNotEmpty() && animeSource in 0 until AnimeSources.names.size) {
|
||||
binding.animeSource.setText(AnimeSources.names[animeSource], false)
|
||||
|
||||
}
|
||||
|
||||
binding.animeSource.setAdapter(ArrayAdapter(this, R.layout.item_dropdown, AnimeSources.names))
|
||||
|
||||
binding.animeSource.setOnItemClickListener { _, _, i, _ ->
|
||||
saveData("settings_def_anime_source_s", i)
|
||||
//saveData("settings_def_anime_source_s", i)
|
||||
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit().putInt("settings_def_anime_source_s_r", i).apply()
|
||||
binding.animeSource.clearFocus()
|
||||
}
|
||||
|
||||
@@ -148,6 +168,15 @@ OS Version: $CODENAME $RELEASE ($SDK_INT)
|
||||
true
|
||||
}
|
||||
|
||||
val exDns = listOf("None", "Cloudflare", "Google", "AdGuard", "Quad9", "AliDNS", "DNSPod", "360", "Quad101", "Mullvad", "Controld", "Njalla", "Shecan")
|
||||
binding.settingsExtensionDns.setText(exDns[networkPreferences.dohProvider().get()], false)
|
||||
binding.settingsExtensionDns.setAdapter(ArrayAdapter(this, R.layout.item_dropdown, exDns))
|
||||
binding.settingsExtensionDns.setOnItemClickListener { _, _, i, _ ->
|
||||
networkPreferences.dohProvider().set(i)
|
||||
binding.settingsExtensionDns.clearFocus()
|
||||
Toast.makeText(this, "Restart app to apply changes", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
binding.settingsDownloadInSd.isChecked = loadData("sd_dl") ?: false
|
||||
binding.settingsDownloadInSd.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) {
|
||||
@@ -186,7 +215,8 @@ OS Version: $CODENAME $RELEASE ($SDK_INT)
|
||||
saveData("settings_prefer_dub", isChecked)
|
||||
}
|
||||
|
||||
val mangaSource = loadData<Int>("settings_def_manga_source_s")?.let { if (it >= MangaSources.names.size) 0 else it } ?: 0
|
||||
//val mangaSource = loadData<Int>("settings_def_manga_source_s")?.let { if (it >= MangaSources.names.size) 0 else it } ?: 0
|
||||
val mangaSource = getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getInt("settings_def_manga_source_s_r", 0)
|
||||
if (MangaSources.names.isNotEmpty() && mangaSource in 0 until MangaSources.names.size) {
|
||||
binding.mangaSource.setText(MangaSources.names[mangaSource], false)
|
||||
}
|
||||
@@ -196,7 +226,8 @@ OS Version: $CODENAME $RELEASE ($SDK_INT)
|
||||
|
||||
// Set up the item click listener for the dropdown.
|
||||
binding.mangaSource.setOnItemClickListener { _, _, i, _ ->
|
||||
saveData("settings_def_manga_source_s", i)
|
||||
//saveData("settings_def_manga_source_s", i)
|
||||
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit().putInt("settings_def_manga_source_s_r", i).apply()
|
||||
binding.mangaSource.clearFocus()
|
||||
}
|
||||
|
||||
@@ -377,7 +408,7 @@ OS Version: $CODENAME $RELEASE ($SDK_INT)
|
||||
}
|
||||
}
|
||||
|
||||
var curTime = loadData<Int>("subscriptions_time") ?: defaultTime
|
||||
var curTime = loadData<Int>("subscriptions_time_r") ?: defaultTime
|
||||
val timeNames = timeMinutes.map {
|
||||
val mins = it % 60
|
||||
val hours = it / 60
|
||||
@@ -390,7 +421,7 @@ OS Version: $CODENAME $RELEASE ($SDK_INT)
|
||||
speedDialog.setSingleChoiceItems(timeNames, curTime) { dialog, i ->
|
||||
curTime = i
|
||||
binding.settingsSubscriptionsTime.text = getString(R.string.subscriptions_checking_time_s, timeNames[i])
|
||||
saveData("subscriptions_time", curTime)
|
||||
saveData("subscriptions_time_r", curTime)
|
||||
dialog.dismiss()
|
||||
startSubscription(true)
|
||||
}.show()
|
||||
@@ -534,7 +565,7 @@ OS Version: $CODENAME $RELEASE ($SDK_INT)
|
||||
title = "Enjoying the App?"
|
||||
addView(TextView(this@SettingsActivity).apply {
|
||||
text =
|
||||
"Consider donating!r"
|
||||
"Consider donating!"
|
||||
})
|
||||
|
||||
setNegativeButton("no moners :(") {
|
||||
@@ -553,4 +584,18 @@ OS Version: $CODENAME $RELEASE ($SDK_INT)
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun restartApp() {
|
||||
Snackbar.make(
|
||||
binding.root,
|
||||
R.string.restart_app, Snackbar.LENGTH_SHORT
|
||||
).apply {
|
||||
val mainIntent =
|
||||
Intent.makeRestartActivityTask(context.packageManager.getLaunchIntentForPackage(context.packageName)!!.component)
|
||||
setAction("Do it!") {
|
||||
context.startActivity(mainIntent)
|
||||
Runtime.getRuntime().exit(0)
|
||||
}
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import ani.dantotsu.*
|
||||
import ani.dantotsu.databinding.ActivityUserInterfaceSettingsBinding
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
||||
class UserInterfaceSettingsActivity : AppCompatActivity() {
|
||||
@@ -15,6 +16,7 @@ class UserInterfaceSettingsActivity : AppCompatActivity() {
|
||||
private val ui = "ui_settings"
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityUserInterfaceSettingsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
package ani.dantotsu.settings.paging
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.PagingDataAdapter
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import androidx.paging.cachedIn
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.databinding.ItemExtensionAllBinding
|
||||
import ani.dantotsu.loadData
|
||||
import com.bumptech.glide.Glide
|
||||
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
|
||||
|
||||
class AnimeExtensionsViewModelFactory(
|
||||
private val animeExtensionManager: AnimeExtensionManager
|
||||
) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return AnimeExtensionsViewModel(animeExtensionManager) as T
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class AnimeExtensionsViewModel(
|
||||
private val animeExtensionManager: AnimeExtensionManager
|
||||
) : ViewModel() {
|
||||
private val searchQuery = MutableStateFlow("")
|
||||
private var currentPagingSource: AnimeExtensionPagingSource? = null
|
||||
fun setSearchQuery(query: String) {
|
||||
searchQuery.value = query
|
||||
}
|
||||
fun invalidatePager() {
|
||||
currentPagingSource?.invalidate()
|
||||
}
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val pagerFlow: Flow<PagingData<AnimeExtension.Available>> = searchQuery.flatMapLatest { query ->
|
||||
Pager(
|
||||
PagingConfig(
|
||||
pageSize = 15,
|
||||
initialLoadSize = 15,
|
||||
prefetchDistance = 15
|
||||
)
|
||||
) {
|
||||
AnimeExtensionPagingSource(
|
||||
animeExtensionManager.availableExtensionsFlow,
|
||||
animeExtensionManager.installedExtensionsFlow,
|
||||
searchQuery
|
||||
).also { currentPagingSource = it }
|
||||
}.flow
|
||||
}.cachedIn(viewModelScope)
|
||||
}
|
||||
|
||||
class AnimeExtensionPagingSource(
|
||||
private val availableExtensionsFlow: StateFlow<List<AnimeExtension.Available>>,
|
||||
private val installedExtensionsFlow: StateFlow<List<AnimeExtension.Installed>>,
|
||||
private val searchQuery: StateFlow<String>
|
||||
) : PagingSource<Int, AnimeExtension.Available>() {
|
||||
|
||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, AnimeExtension.Available> {
|
||||
val position = params.key ?: 0
|
||||
val installedExtensions = installedExtensionsFlow.first().map { it.pkgName }.toSet()
|
||||
val availableExtensions = availableExtensionsFlow.first().filterNot { it.pkgName in installedExtensions }
|
||||
val query = searchQuery.first()
|
||||
val filteredExtensions = if (query.isEmpty()) {
|
||||
availableExtensions
|
||||
} else {
|
||||
availableExtensions.filter { it.name.contains(query, ignoreCase = true) }
|
||||
}
|
||||
|
||||
return try {
|
||||
val sublist = filteredExtensions.subList(
|
||||
fromIndex = position,
|
||||
toIndex = (position + params.loadSize).coerceAtMost(filteredExtensions.size)
|
||||
)
|
||||
LoadResult.Page(
|
||||
data = sublist,
|
||||
prevKey = if (position == 0) null else position - params.loadSize,
|
||||
nextKey = if (position + params.loadSize >= filteredExtensions.size) null else position + params.loadSize
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
LoadResult.Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRefreshKey(state: PagingState<Int, AnimeExtension.Available>): Int? {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
class AnimeExtensionAdapter(private val clickListener: OnAnimeInstallClickListener) :
|
||||
PagingDataAdapter<AnimeExtension.Available, AnimeExtensionAdapter.AnimeExtensionViewHolder>(
|
||||
DIFF_CALLBACK
|
||||
) {
|
||||
|
||||
private val skipIcons = loadData("skip_extension_icons") ?: false
|
||||
|
||||
companion object {
|
||||
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<AnimeExtension.Available>() {
|
||||
override fun areItemsTheSame(oldItem: AnimeExtension.Available, newItem: AnimeExtension.Available): Boolean {
|
||||
// Your logic here
|
||||
return oldItem.pkgName == newItem.pkgName
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: AnimeExtension.Available, newItem: AnimeExtension.Available): Boolean {
|
||||
// Your logic here
|
||||
return oldItem == newItem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AnimeExtensionViewHolder {
|
||||
val binding = ItemExtensionAllBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return AnimeExtensionViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: AnimeExtensionViewHolder, position: Int) {
|
||||
val extension = getItem(position)
|
||||
if (extension != null) {
|
||||
if (!skipIcons) {
|
||||
Glide.with(holder.itemView.context)
|
||||
.load(extension.iconUrl)
|
||||
.into(holder.extensionIconImageView)
|
||||
}
|
||||
holder.bind(extension)
|
||||
}
|
||||
}
|
||||
|
||||
inner class AnimeExtensionViewHolder(private val binding: ItemExtensionAllBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||
init {
|
||||
binding.closeTextView.setOnClickListener {
|
||||
val extension = getItem(bindingAdapterPosition)
|
||||
if (extension != null) {
|
||||
clickListener.onInstallClick(extension)
|
||||
}
|
||||
}
|
||||
}
|
||||
val extensionIconImageView: ImageView = binding.extensionIconImageView
|
||||
fun bind(extension: AnimeExtension.Available) {
|
||||
binding.extensionNameTextView.text = extension.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface OnAnimeInstallClickListener {
|
||||
fun onInstallClick(pkg: AnimeExtension.Available)
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package ani.dantotsu.settings.paging
|
||||
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.PagingDataAdapter
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import androidx.paging.cachedIn
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.databinding.ItemExtensionAllBinding
|
||||
import ani.dantotsu.loadData
|
||||
import com.bumptech.glide.Glide
|
||||
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
|
||||
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import java.lang.Math.min
|
||||
|
||||
class MangaExtensionsViewModelFactory(
|
||||
private val mangaExtensionManager: MangaExtensionManager
|
||||
) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return MangaExtensionsViewModel(mangaExtensionManager) as T
|
||||
}
|
||||
}
|
||||
|
||||
class MangaExtensionsViewModel(
|
||||
private val mangaExtensionManager: MangaExtensionManager
|
||||
) : ViewModel() {
|
||||
private val searchQuery = MutableStateFlow("")
|
||||
private var currentPagingSource: MangaExtensionPagingSource? = null
|
||||
|
||||
fun setSearchQuery(query: String) {
|
||||
searchQuery.value = query
|
||||
}
|
||||
|
||||
fun invalidatePager() {
|
||||
currentPagingSource?.invalidate()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val pagerFlow: Flow<PagingData<MangaExtension.Available>> = searchQuery.flatMapLatest { query ->
|
||||
Pager(
|
||||
PagingConfig(
|
||||
pageSize = 15,
|
||||
initialLoadSize = 15,
|
||||
prefetchDistance = 15
|
||||
)
|
||||
) {
|
||||
MangaExtensionPagingSource(
|
||||
mangaExtensionManager.availableExtensionsFlow,
|
||||
mangaExtensionManager.installedExtensionsFlow,
|
||||
searchQuery
|
||||
).also { currentPagingSource = it }
|
||||
}.flow
|
||||
}.cachedIn(viewModelScope)
|
||||
}
|
||||
|
||||
|
||||
class MangaExtensionPagingSource(
|
||||
private val availableExtensionsFlow: StateFlow<List<MangaExtension.Available>>,
|
||||
private val installedExtensionsFlow: StateFlow<List<MangaExtension.Installed>>,
|
||||
private val searchQuery: StateFlow<String>
|
||||
) : PagingSource<Int, MangaExtension.Available>() {
|
||||
|
||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MangaExtension.Available> {
|
||||
val position = params.key ?: 0
|
||||
val installedExtensions = installedExtensionsFlow.first().map { it.pkgName }.toSet()
|
||||
val availableExtensions = availableExtensionsFlow.first().filterNot { it.pkgName in installedExtensions }
|
||||
val query = searchQuery.first()
|
||||
val filteredExtensions = if (query.isEmpty()) {
|
||||
availableExtensions
|
||||
} else {
|
||||
availableExtensions.filter { it.name.contains(query, ignoreCase = true) }
|
||||
}
|
||||
|
||||
return try {
|
||||
val sublist = filteredExtensions.subList(
|
||||
fromIndex = position,
|
||||
toIndex = (position + params.loadSize).coerceAtMost(filteredExtensions.size)
|
||||
)
|
||||
LoadResult.Page(
|
||||
data = sublist,
|
||||
prevKey = if (position == 0) null else position - params.loadSize,
|
||||
nextKey = if (position + params.loadSize >= filteredExtensions.size) null else position + params.loadSize
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
LoadResult.Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRefreshKey(state: PagingState<Int, MangaExtension.Available>): Int? {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
class MangaExtensionAdapter(private val clickListener: OnMangaInstallClickListener) :
|
||||
PagingDataAdapter<MangaExtension.Available, MangaExtensionAdapter.MangaExtensionViewHolder>(
|
||||
DIFF_CALLBACK
|
||||
) {
|
||||
|
||||
private val skipIcons = loadData("skip_extension_icons") ?: false
|
||||
|
||||
companion object {
|
||||
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<MangaExtension.Available>() {
|
||||
override fun areItemsTheSame(oldItem: MangaExtension.Available, newItem: MangaExtension.Available): Boolean {
|
||||
// Your logic here
|
||||
return oldItem.pkgName == newItem.pkgName
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: MangaExtension.Available, newItem: MangaExtension.Available): Boolean {
|
||||
// Your logic here
|
||||
return oldItem == newItem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MangaExtensionViewHolder {
|
||||
val binding = ItemExtensionAllBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return MangaExtensionViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: MangaExtensionViewHolder, position: Int) {
|
||||
val extension = getItem(position)
|
||||
if (extension != null) {
|
||||
if (!skipIcons) {
|
||||
Glide.with(holder.itemView.context)
|
||||
.load(extension.iconUrl)
|
||||
.into(holder.extensionIconImageView)
|
||||
}
|
||||
holder.bind(extension)
|
||||
}
|
||||
}
|
||||
|
||||
inner class MangaExtensionViewHolder(private val binding: ItemExtensionAllBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||
init {
|
||||
binding.closeTextView.setOnClickListener {
|
||||
val extension = getItem(bindingAdapterPosition)
|
||||
if (extension != null) {
|
||||
clickListener.onInstallClick(extension)
|
||||
}
|
||||
}
|
||||
}
|
||||
val extensionIconImageView: ImageView = binding.extensionIconImageView
|
||||
fun bind(extension: MangaExtension.Available) {
|
||||
binding.extensionNameTextView.text = extension.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface OnMangaInstallClickListener {
|
||||
fun onInstallClick(pkg: MangaExtension.Available)
|
||||
}
|
||||
@@ -40,7 +40,7 @@ class AlarmReceiver : BroadcastReceiver() {
|
||||
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
val curTime = loadData<Int>("subscriptions_time", context) ?: defaultTime
|
||||
val curTime = loadData<Int>("subscriptions_time_r", context) ?: defaultTime
|
||||
|
||||
if (timeMinutes[curTime] > 0)
|
||||
alarmManager.setRepeating(
|
||||
|
||||
@@ -16,8 +16,8 @@ import kotlinx.coroutines.launch
|
||||
@SuppressLint("MissingPermission")
|
||||
class Subscription {
|
||||
companion object {
|
||||
const val defaultTime = 8
|
||||
val timeMinutes = arrayOf(0L, 5, 10, 15, 30, 45, 60, 90, 120, 180, 240, 360, 480, 720, 1440)
|
||||
const val defaultTime = 3
|
||||
val timeMinutes = arrayOf(0L, 120, 180, 240, 360, 480, 720, 1440)
|
||||
|
||||
private var alreadyStarted = false
|
||||
fun Context.startSubscription(force: Boolean = false) {
|
||||
|
||||
@@ -9,16 +9,18 @@ import ani.dantotsu.parsers.*
|
||||
import ani.dantotsu.saveData
|
||||
import ani.dantotsu.tryWithSuspend
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.media.manga.MangaNameAdapter
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
|
||||
class SubscriptionHelper {
|
||||
companion object {
|
||||
private fun loadSelected(context: Context, mediaId: Int, isAdult: Boolean, isAnime: Boolean): Selected {
|
||||
val sharedPreferences = context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
|
||||
val data = loadData<Selected>("${mediaId}-select", context) ?: Selected().let {
|
||||
it.sourceIndex =
|
||||
if (isAdult) 0
|
||||
else if (isAnime) {loadData("settings_def_anime_source_s_r", context) ?: 0}
|
||||
else loadData("settings_def_manga_source_s_r", context) ?: 0
|
||||
else if (isAnime) {sharedPreferences.getInt("settings_def_anime_source_s_r",0)}
|
||||
else {sharedPreferences.getInt("settings_def_manga_source_s_r",0)}
|
||||
it.preferDub = loadData("settings_prefer_dub", context) ?: false
|
||||
it
|
||||
}
|
||||
@@ -75,7 +77,7 @@ class SubscriptionHelper {
|
||||
}
|
||||
|
||||
return chp?.apply {
|
||||
selected.latest = number.toFloat()
|
||||
selected.latest = MangaNameAdapter.findChapterNumber(number) ?: 0f
|
||||
saveSelected(context, id, selected)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class SubscriptionWorker(val context: Context, params: WorkerParameters) : Corou
|
||||
|
||||
private const val SUBSCRIPTION_WORK_NAME = "work_subscription"
|
||||
fun enqueue(context: Context) {
|
||||
val curTime = loadData<Int>("subscriptions_time") ?: defaultTime
|
||||
val curTime = loadData<Int>("subscriptions_time_r") ?: defaultTime
|
||||
if(timeMinutes[curTime]>0L) {
|
||||
val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
|
||||
val periodicSyncDataWork = PeriodicWorkRequest.Builder(
|
||||
|
||||
56
app/src/main/java/ani/dantotsu/themes/ThemeManager.kt
Normal file
56
app/src/main/java/ani/dantotsu/themes/ThemeManager.kt
Normal file
@@ -0,0 +1,56 @@
|
||||
package ani.dantotsu.themes
|
||||
|
||||
import android.content.Context
|
||||
import ani.dantotsu.R
|
||||
|
||||
class ThemeManager(private val context: Context) {
|
||||
fun applyTheme() {
|
||||
if(context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getBoolean("use_material_you", false)){
|
||||
return
|
||||
}
|
||||
when (context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getString("theme", "PURPLE")!!) {
|
||||
"PURPLE" -> {
|
||||
context.setTheme(R.style.Theme_Dantotsu_Purple)
|
||||
}
|
||||
"BLUE" -> {
|
||||
context.setTheme(R.style.Theme_Dantotsu_Blue)
|
||||
}
|
||||
"GREEN" -> {
|
||||
context.setTheme(R.style.Theme_Dantotsu_Green)
|
||||
}
|
||||
"PINK" -> {
|
||||
context.setTheme(R.style.Theme_Dantotsu_Pink)
|
||||
}
|
||||
"RED" -> {
|
||||
context.setTheme(R.style.Theme_Dantotsu_Red)
|
||||
}
|
||||
"LAVENDER" -> {
|
||||
context.setTheme(R.style.Theme_Dantotsu_Lavender)
|
||||
}
|
||||
"MONOCHROME (BETA)" -> {
|
||||
context.setTheme(R.style.Theme_Dantotsu_Monochrome)
|
||||
}
|
||||
else -> {
|
||||
context.setTheme(R.style.Theme_Dantotsu_Purple)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object{
|
||||
enum class Theme(val theme: String) {
|
||||
PURPLE("PURPLE"),
|
||||
BLUE("BLUE"),
|
||||
GREEN("GREEN"),
|
||||
PINK("PINK"),
|
||||
RED("RED"),
|
||||
LAVENDER("LAVENDER"),
|
||||
MONOCHROME("MONOCHROME (BETA)");
|
||||
|
||||
companion object {
|
||||
fun fromString(value: String): Theme {
|
||||
return values().find { it.theme == value } ?: PURPLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,18 +6,25 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import okhttp3.Headers
|
||||
import rx.subjects.Subject
|
||||
import java.io.IOException
|
||||
import java.io.ObjectInputStream
|
||||
import java.io.ObjectOutputStream
|
||||
import java.io.Serializable
|
||||
|
||||
data class Track(val url: String, val lang: String)
|
||||
data class Track(val url: String, val lang: String) : Serializable
|
||||
|
||||
open class Video(
|
||||
val url: String = "",
|
||||
val quality: String = "",
|
||||
var videoUrl: String? = null,
|
||||
val headers: Headers? = null,
|
||||
headers: Headers? = null,
|
||||
// "url", "language-label-2", "url2", "language-label-2"
|
||||
val subtitleTracks: List<Track> = emptyList(),
|
||||
val audioTracks: List<Track> = emptyList(),
|
||||
) : ProgressListener {
|
||||
) : Serializable, ProgressListener {
|
||||
|
||||
@Transient
|
||||
var headers: Headers? = headers
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
constructor(
|
||||
@@ -89,4 +96,27 @@ open class Video(
|
||||
READY,
|
||||
ERROR,
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun writeObject(out: ObjectOutputStream) {
|
||||
out.defaultWriteObject()
|
||||
val headersMap: Map<String, List<String>> = headers?.toMultimap() ?: emptyMap()
|
||||
out.writeObject(headersMap)
|
||||
}
|
||||
|
||||
@Throws(IOException::class, ClassNotFoundException::class)
|
||||
private fun readObject(input: ObjectInputStream) {
|
||||
input.defaultReadObject()
|
||||
val headersMap = input.readObject() as? Map<String, List<String>>
|
||||
headers = headersMap?.let { map ->
|
||||
val builder = Headers.Builder()
|
||||
for ((key, values) in map) {
|
||||
for (value in values) {
|
||||
builder.add(key, value)
|
||||
}
|
||||
}
|
||||
builder.build()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.extension.anime.util
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import eu.kanade.tachiyomi.extension.InstallStep
|
||||
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
||||
import eu.kanade.tachiyomi.util.system.hasMiuiPackageInstaller
|
||||
@@ -24,6 +25,7 @@ class AnimeExtensionInstallActivity : Activity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
|
||||
val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE)
|
||||
.setDataAndType(intent.data, intent.type)
|
||||
|
||||
@@ -108,8 +108,11 @@ internal class AnimeExtensionInstaller(private val context: Context) {
|
||||
// Get the current download status
|
||||
.map {
|
||||
downloadManager.query(query).use { cursor ->
|
||||
cursor.moveToFirst()
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS))
|
||||
if (cursor.moveToFirst()) {
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS))
|
||||
} else {
|
||||
DownloadManager.STATUS_FAILED
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ignore duplicate results
|
||||
|
||||
@@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.extension.manga.util
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import eu.kanade.tachiyomi.extension.InstallStep
|
||||
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
|
||||
import eu.kanade.tachiyomi.util.system.hasMiuiPackageInstaller
|
||||
@@ -24,6 +25,7 @@ class MangaExtensionInstallActivity : Activity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
|
||||
val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE)
|
||||
.setDataAndType(intent.data, intent.type)
|
||||
|
||||
@@ -13,7 +13,7 @@ class NetworkPreferences(
|
||||
}
|
||||
|
||||
fun dohProvider(): Preference<Int> {
|
||||
return preferenceStore.getInt("doh_provider", 1)
|
||||
return preferenceStore.getInt("doh_provider", 0)
|
||||
}
|
||||
|
||||
fun defaultUserAgent(): Preference<String> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/bg_opp" android:state_checked="false"/>
|
||||
<item android:color="?attr/colorSecondary" android:state_checked="true"/>
|
||||
<item android:color="?attr/colorOnBackground" android:state_checked="false"/>
|
||||
<item android:color="?attr/colorPrimaryContainer" android:state_checked="true"/>
|
||||
</selector>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_selected="true" android:color="@color/bg_black"/>
|
||||
<item android:color="@color/nav_tab"/>
|
||||
<item android:state_selected="true" android:color="?attr/colorPrimary"/>
|
||||
<item android:color="?attr/colorSecondary"/>
|
||||
</selector>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_selected="true" android:color="@color/bg_opp"/>
|
||||
<item android:color="@color/nav_tab"/>
|
||||
<item android:state_selected="true" android:color="?attr/colorOnPrimary"/>
|
||||
<item android:color="?attr/colorOnSecondary"/>
|
||||
</selector>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- Color when the TextInputLayout is focused -->
|
||||
<item android:color="?attr/colorPrimary" android:state_focused="true"/>
|
||||
<!-- Color when the TextInputLayout is not focused (unselected) -->
|
||||
<item android:color="?attr/colorPrimaryContainer"/>
|
||||
</selector>
|
||||
67
app/src/main/res/drawable-v24/ic_banner_foreground.xml
Normal file
67
app/src/main/res/drawable-v24/ic_banner_foreground.xml
Normal file
@@ -0,0 +1,67 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="320dp"
|
||||
android:height="180dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<group android:scaleX="0.6666667"
|
||||
android:scaleY="0.6666667"
|
||||
android:translateX="18"
|
||||
android:translateY="18">
|
||||
<group android:scaleX="0.5625"
|
||||
android:translateX="-5.535">
|
||||
<path
|
||||
android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:fillType="evenOdd">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="49.59793"
|
||||
android:startX="42.9492"
|
||||
android:endY="92.4963"
|
||||
android:endX="85.84757"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0"/>
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:fillColor="#3DDC84"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000"/>
|
||||
</group>
|
||||
|
||||
<group android:scaleX="0.492"
|
||||
android:scaleY="0.24750866"
|
||||
android:translateX="277.2"
|
||||
android:translateY="73.782364">
|
||||
<group android:translateY="145.33594">
|
||||
<path android:pathData="M12.796875,-0L12.796875,-101.109375L34.171875,-101.109375Q42.828125,-101.109375,50.234375,-100.234375Q57.65625,-99.359375,63.84375,-97.171875Q70.03125,-95,74.703125,-91.375Q79.390625,-87.75,82.765625,-82.125Q86.0625,-76.5,87.75,-68.765625Q89.4375,-61.03125,89.4375,-50.5625Q89.4375,-40.078125,87.75,-32.34375Q86.0625,-24.609375,82.765625,-18.984375Q79.390625,-13.359375,74.703125,-9.734375Q70.03125,-6.125,63.84375,-3.9375Q57.65625,-1.765625,50.234375,-0.875Q42.828125,-0,34.171875,-0L12.796875,-0ZM36.359375,-10.828125Q47.109375,-10.828125,54.59375,-12.96875Q62.09375,-15.125,66.875,-19.96875Q71.578125,-24.828125,73.71875,-32.3125Q75.875,-39.796875,75.875,-50.5625Q75.875,-61.3125,73.71875,-68.796875Q71.578125,-76.296875,66.875,-81.140625Q62.09375,-86,54.59375,-88.140625Q47.109375,-90.28125,36.359375,-90.28125L26.015625,-90.28125L26.015625,-10.828125L36.359375,-10.828125Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M113.109375,-60.1875L110.015625,-70.03125Q121.828125,-74.75,134.76562,-74.75Q146.07812,-74.75,152.0625,-70.953125Q158.875,-66.59375,158.875,-56.109375L158.875,-27.359375Q158.875,-21.59375,159.01562,-15.546875Q159.09375,-11.953125,159.71875,-8.09375Q160.28125,-4.4375,161.20312,-1.125L149.67188,1.40625Q148.04688,-3.3125,147.625,-9.140625L146.21875,-9.28125Q137.5,1.6875,124,1.6875Q114.15625,1.6875,108.171875,-3.765625Q102.203125,-9.21875,102.203125,-19.125Q102.203125,-26.515625,105.46875,-31.21875Q108.75,-35.9375,114.71875,-39.171875Q124.140625,-44.296875,141.09375,-44.296875Q143.34375,-44.296875,147.14062,-44.15625L147.14062,-54.84375Q147.14062,-59.90625,144.04688,-62.15625Q140.95312,-64.40625,134.34375,-64.40625Q124.703125,-64.40625,113.109375,-60.1875ZM147.14062,-20.53125L147.14062,-35.296875Q145.23438,-35.4375,141.57812,-35.4375Q135.39062,-35.4375,130.1875,-34.390625Q122.453125,-32.84375,118.203125,-29.5Q113.953125,-26.15625,113.953125,-19.90625Q113.953125,-8.65625,126.1875,-8.65625Q132.51562,-8.65625,138,-12.03125Q142.5,-14.84375,147.14062,-20.53125Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M179.5,-71.859375L191.17188,-74.46875Q192.5,-70.25,193.0625,-66.3125Q193.34375,-64.40625,193.76562,-58.78125L195.25,-58.78125Q199.10938,-65.890625,204.8125,-70.109375Q211.0625,-74.75,218.03125,-74.75Q228.5,-74.75,233.98438,-69.6875Q238.70312,-65.390625,240.53125,-56.53125Q241.71875,-50.484375,241.71875,-38.53125L241.71875,0L229.625,0L229.625,-41.90625Q229.625,-52.390625,227.59375,-56.890625Q224.5625,-63.5625,215.42188,-63.5625Q208.95312,-63.5625,202.76562,-57.375Q198.625,-53.234375,193.90625,-45.21875L193.90625,0L181.8125,0L181.8125,-45Q181.8125,-54.5,181.32812,-61.390625Q181.04688,-65.671875,179.5,-71.859375Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M269.28125,-89.859375L281.375,-89.859375L281.375,-73.125L305.98438,-73.125L305.98438,-62.9375L281.375,-62.9375L281.375,-20.953125Q281.375,-16.734375,281.625,-14.515625Q281.875,-12.3125,282.85938,-11.046875Q284.6875,-8.515625,290.23438,-8.515625Q293.32812,-8.515625,296.21875,-9.140625Q299.17188,-9.78125,301.625,-10.546875Q303.59375,-6.265625,305.21875,-1.125Q296.92188,1.6875,288.48438,1.6875Q282.35938,1.6875,278.67188,0.3125Q274.98438,-1.0625,272.875,-4.15625Q270.6875,-7.390625,269.98438,-11.890625Q269.28125,-16.390625,269.28125,-24.328125L269.28125,-62.9375L258.73438,-62.9375L258.73438,-73.125L269.28125,-73.125L269.28125,-89.859375Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M351.03125,-74.75Q354.46875,-74.75,358.1875,-74.21875Q361.92188,-73.6875,365.51562,-72.21875Q369.09375,-70.671875,372.29688,-68.03125Q375.5,-65.390625,377.95312,-61.171875Q380.42188,-56.890625,381.82812,-50.875Q383.23438,-44.859375,383.23438,-36.5625Q383.23438,-28.265625,381.82812,-22.25Q380.42188,-16.25,377.95312,-12.03125Q375.5,-7.734375,372.29688,-5.0625Q369.09375,-2.390625,365.51562,-0.921875Q361.92188,0.640625,358.1875,1.15625Q354.46875,1.6875,351.03125,1.6875Q347.65625,1.6875,343.95312,1.15625Q340.26562,0.640625,336.6875,-0.921875Q333.09375,-2.390625,329.92188,-5.0625Q326.76562,-7.734375,324.3125,-12.03125Q321.84375,-16.25,320.4375,-22.25Q319.03125,-28.265625,319.03125,-36.5625Q319.03125,-44.859375,320.4375,-50.875Q321.84375,-56.890625,324.3125,-61.171875Q326.76562,-65.390625,329.92188,-68.03125Q333.09375,-70.671875,336.6875,-72.21875Q340.26562,-73.6875,343.92188,-74.21875Q347.57812,-74.75,351.03125,-74.75ZM351.03125,-64.828125Q347.01562,-64.828125,343.46875,-63.5625Q339.92188,-62.296875,337.25,-59.140625Q334.5,-55.90625,332.875,-50.484375Q331.26562,-45.078125,331.26562,-36.5625Q331.26562,-28.125,332.875,-22.671875Q334.5,-17.234375,337.25,-14.0625Q339.92188,-10.828125,343.46875,-9.59375Q347.01562,-8.375,351.03125,-8.375Q355.10938,-8.375,358.71875,-9.59375Q362.34375,-10.828125,365.09375,-14.0625Q367.82812,-17.234375,369.40625,-22.671875Q371,-28.125,371,-36.5625Q371,-45.078125,369.40625,-50.484375Q367.82812,-55.90625,365.09375,-59.140625Q362.34375,-62.296875,358.71875,-63.5625Q355.10938,-64.828125,351.03125,-64.828125Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M408.28125,-89.859375L420.375,-89.859375L420.375,-73.125L444.98438,-73.125L444.98438,-62.9375L420.375,-62.9375L420.375,-20.953125Q420.375,-16.734375,420.625,-14.515625Q420.875,-12.3125,421.85938,-11.046875Q423.6875,-8.515625,429.23438,-8.515625Q432.32812,-8.515625,435.21875,-9.140625Q438.17188,-9.78125,440.625,-10.546875Q442.59375,-6.265625,444.21875,-1.125Q435.92188,1.6875,427.48438,1.6875Q421.35938,1.6875,417.67188,0.3125Q413.98438,-1.0625,411.875,-4.15625Q409.6875,-7.390625,408.98438,-11.890625Q408.28125,-16.390625,408.28125,-24.328125L408.28125,-62.9375L397.73438,-62.9375L397.73438,-73.125L408.28125,-73.125L408.28125,-89.859375Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M484.54688,-74.75Q490.3125,-74.75,496.10938,-73.546875Q501.90625,-72.359375,506.90625,-70.25Q505.92188,-68,504.85938,-65.8125Q503.8125,-63.640625,502.54688,-61.53125Q500.78125,-62.234375,498.64062,-62.9375Q496.5,-63.640625,494.14062,-64.125Q491.78125,-64.625,489.28125,-64.9375Q486.79688,-65.25,484.40625,-65.25Q481.79688,-65.25,479.375,-64.71875Q476.95312,-64.203125,475.07812,-63Q473.21875,-61.8125,472.09375,-59.875Q470.96875,-57.9375,470.96875,-55.0625Q470.96875,-52.109375,472.23438,-50.09375Q473.5,-48.09375,475.67188,-46.75Q477.85938,-45.421875,480.78125,-44.5Q483.70312,-43.59375,487,-42.828125Q492.14062,-41.5625,496.5625,-39.96875Q501,-38.390625,504.23438,-35.859375Q507.46875,-33.328125,509.29688,-29.59375Q511.125,-25.875,511.125,-20.390625Q511.125,-14.625,508.82812,-10.46875Q506.54688,-6.328125,502.64062,-3.625Q498.75,-0.921875,493.54688,0.375Q488.34375,1.6875,482.4375,1.6875Q479.34375,1.6875,476.0625,1.296875Q472.79688,0.921875,469.59375,0.171875Q466.40625,-0.5625,463.3125,-1.609375Q460.21875,-2.671875,457.46875,-3.9375Q458.45312,-6.1875,459.54688,-8.328125Q460.64062,-10.484375,461.82812,-12.59375Q464.15625,-11.609375,466.75,-10.71875Q469.35938,-9.84375,472.09375,-9.203125Q474.84375,-8.578125,477.51562,-8.1875Q480.1875,-7.8125,482.64062,-7.8125Q485.73438,-7.8125,488.65625,-8.515625Q491.57812,-9.21875,493.85938,-10.71875Q496.14062,-12.234375,497.51562,-14.625Q498.89062,-17.015625,498.89062,-20.390625Q498.89062,-23.5625,497.57812,-25.59375Q496.28125,-27.640625,494.09375,-29Q491.92188,-30.375,489,-31.25Q486.09375,-32.140625,482.85938,-32.90625Q477.9375,-34.109375,473.53125,-35.65625Q469.14062,-37.203125,465.875,-39.6875Q462.60938,-42.1875,460.67188,-45.875Q458.73438,-49.578125,458.73438,-55.0625Q458.73438,-60.1875,460.84375,-63.90625Q462.95312,-67.640625,466.5,-70.03125Q470.0625,-72.421875,474.73438,-73.578125Q479.40625,-74.75,484.54688,-74.75Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M590.28125,-1.265625L578.6094,1.34375Q577.28125,-2.890625,576.71875,-6.828125Q576.4375,-8.65625,576.0156,-14.28125L574.53125,-14.28125Q570.6719,-7.171875,564.96875,-2.953125Q558.71875,1.6875,551.75,1.6875Q541.28125,1.6875,535.7969,-3.375Q531.0781,-7.671875,529.25,-16.53125Q528.0625,-22.578125,528.0625,-34.53125L528.0625,-73.125L540.15625,-73.125L540.15625,-31.15625Q540.15625,-20.671875,542.1875,-16.171875Q545.21875,-9.5,554.3594,-9.5Q560.8281,-9.5,567.0156,-15.6875Q571.15625,-19.828125,575.875,-27.84375L575.875,-73.125L587.96875,-73.125L587.96875,-27.984375Q587.96875,-18.640625,588.4531,-11.75Q588.7344,-7.453125,590.28125,-1.265625Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path android:pathData="M644.78125,0L644.78125,-95.984375L683.03125,-95.984375L683.03125,0L644.78125,0ZM649.5625,-4.78125L678.25,-4.78125L678.25,-91.203125L649.5625,-91.203125L649.5625,-4.78125Z"
|
||||
android:fillColor="#000000"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/nav_bg"/>
|
||||
<solid android:color="?attr/colorPrimaryContainer"/>
|
||||
<corners android:radius="40dp"/>
|
||||
</shape>
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/pink_500_25"
|
||||
android:color="?attr/colorSecondaryContainer"
|
||||
android:radius="20dp" />
|
||||
@@ -3,6 +3,6 @@
|
||||
<gradient
|
||||
android:type="linear"
|
||||
android:angle="90"
|
||||
android:startColor="@color/bg"
|
||||
android:startColor="?android:colorBackground"
|
||||
android:endColor="@color/nav_bg_inv" />
|
||||
</shape>
|
||||
@@ -10,7 +10,7 @@
|
||||
android:id="@+id/mediaTab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/nav_bg"
|
||||
android:background="?attr/colorPrimaryContainer"
|
||||
android:translationZ="0dp"
|
||||
app:itemPaddingTop="32dp"
|
||||
app:menuGravity="center"
|
||||
@@ -29,7 +29,7 @@
|
||||
android:id="@+id/mediaAppBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/bg"
|
||||
android:background="?android:colorBackground"
|
||||
android:translationZ="5dp">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
@@ -37,7 +37,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="false"
|
||||
app:contentScrim="@color/nav_bg"
|
||||
app:contentScrim="?android:colorBackground"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
|
||||
|
||||
<com.flaviofaria.kenburnsview.KenBurnsView
|
||||
@@ -104,6 +104,7 @@
|
||||
android:singleLine="false"
|
||||
android:text="@string/slogan"
|
||||
android:textSize="16sp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
android:transitionName="mediaTitle" />
|
||||
|
||||
<TextView
|
||||
@@ -137,7 +138,7 @@
|
||||
android:singleLine="true"
|
||||
android:text="@string/add"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="?attr/colorSecondary"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
app:cornerRadius="16dp"
|
||||
@@ -171,7 +172,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:background="@color/nav_bg"
|
||||
android:background="?attr/colorOnBackground"
|
||||
android:ellipsize="marquee"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
@@ -206,7 +207,7 @@
|
||||
android:lineSpacingExtra="-8sp"
|
||||
android:marqueeRepeatLimit="marquee_forever"
|
||||
android:maxLines="2"
|
||||
android:textColor="@color/fg"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
android:textSize="16sp"
|
||||
tools:text="Watched 10 out of 10" />
|
||||
|
||||
@@ -218,7 +219,7 @@
|
||||
android:padding="8dp"
|
||||
android:tintMode="src_atop"
|
||||
app:srcCompat="@drawable/ic_round_favorite_border_24"
|
||||
app:tint="@color/nav_tab"
|
||||
app:tint="?attr/colorSecondary"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
|
||||
<ImageView
|
||||
@@ -228,7 +229,7 @@
|
||||
android:layout_marginStart="-8dp"
|
||||
android:padding="8dp"
|
||||
app:srcCompat="@drawable/ic_round_share_24"
|
||||
app:tint="@color/nav_tab"
|
||||
app:tint="?attr/colorSecondary"
|
||||
app:tintMode="src_atop"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
|
||||
@@ -281,7 +282,7 @@
|
||||
android:layout_gravity="end"
|
||||
android:layout_margin="16dp"
|
||||
android:translationZ="7dp"
|
||||
app:cardBackgroundColor="@color/nav_bg"
|
||||
app:cardBackgroundColor="?android:colorBackground"
|
||||
app:cardCornerRadius="16dp">
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:background="@color/nav_bg"
|
||||
android:background="?attr/colorSecondary"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
@@ -21,6 +21,7 @@
|
||||
android:singleLine="true"
|
||||
android:textAlignment="center"
|
||||
android:textSize="20sp"
|
||||
android:textColor="?attr/colorOnSecondary"
|
||||
tools:text="@string/name" />
|
||||
|
||||
|
||||
@@ -56,7 +57,7 @@
|
||||
android:layout_gravity="end"
|
||||
android:layout_margin="16dp"
|
||||
android:translationZ="2dp"
|
||||
app:cardBackgroundColor="@color/nav_bg"
|
||||
app:cardBackgroundColor="?attr/colorSecondary"
|
||||
app:cardCornerRadius="16dp">
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
android:id="@+id/characterAppBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/bg">
|
||||
app:contentScrim="?android:colorBackground">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:id="@+id/characterCollapsing"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="false"
|
||||
app:contentScrim="@color/nav_bg"
|
||||
app:contentScrim="?android:colorBackground"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
|
||||
|
||||
<com.flaviofaria.kenburnsview.KenBurnsView
|
||||
@@ -98,7 +98,7 @@
|
||||
android:layout_gravity="end"
|
||||
android:layout_margin="16dp"
|
||||
android:translationZ="2dp"
|
||||
app:cardBackgroundColor="@color/nav_bg"
|
||||
app:cardBackgroundColor="?android:colorBackground"
|
||||
app:cardCornerRadius="16dp">
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
android:background="@color/nav_bg_inv"
|
||||
android:padding="16dp"
|
||||
app:srcCompat="@drawable/ic_round_arrow_back_ios_new_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
android:text="@string/faq"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:drawableTint="@color/bg_opp"
|
||||
app:drawableTint="?attr/colorOnBackground"
|
||||
app:drawableStartCompat="@drawable/ic_round_arrow_back_ios_new_24" />
|
||||
|
||||
<ani.dantotsu.FadingEdgeRecyclerView
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/search_by_image"
|
||||
app:drawableStartCompat="@drawable/ic_round_arrow_back_ios_new_24"
|
||||
app:drawableTint="@color/bg_opp" />
|
||||
app:drawableTint="?attr/colorOnBackground" />
|
||||
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
@@ -47,10 +47,10 @@
|
||||
android:elegantTextHeight="true"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:text="@string/upload_image"
|
||||
android:textColor="@color/button_icon"
|
||||
android:textColor="?attr/colorOnPrimary"
|
||||
app:cornerRadius="16dp"
|
||||
app:icon="@drawable/ic_round_image_search_24"
|
||||
app:iconTint="@color/button_icon" />
|
||||
app:iconTint="?attr/colorOnPrimary"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".media.user.ListActivity">
|
||||
tools:context=".media.user.ListActivity"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/listProgressBar"
|
||||
@@ -14,9 +15,10 @@
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/listAppBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/nav_bg"
|
||||
android:background="?attr/colorPrimaryContainer"
|
||||
android:theme="@style/Theme.Dantotsu.AppBarOverlay">
|
||||
|
||||
<LinearLayout
|
||||
@@ -34,6 +36,7 @@
|
||||
android:gravity="center"
|
||||
android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title"
|
||||
android:textSize="16sp"
|
||||
android:textColor="?attr/colorOnPrimaryContainer"
|
||||
tools:text="@string/app_name" />
|
||||
|
||||
<Space
|
||||
@@ -49,7 +52,7 @@
|
||||
android:layout_marginRight="16dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="@string/sort_by"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
app:srcCompat="@drawable/ic_round_sort_24" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -58,7 +61,7 @@
|
||||
android:id="@+id/listTabLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:background="@color/nav_bg"
|
||||
android:background="?attr/colorPrimaryContainer"
|
||||
app:tabContentStart="32dp"
|
||||
app:tabMode="scrollable"
|
||||
app:tabPaddingEnd="16dp"
|
||||
|
||||
@@ -41,13 +41,12 @@
|
||||
app:abb_animationDuration="300"
|
||||
app:abb_animationInterpolator="@anim/over_shoot"
|
||||
app:abb_badgeBackgroundColor="#F44336"
|
||||
|
||||
app:abb_indicatorColor="?attr/colorSecondary"
|
||||
app:abb_indicatorLocation="bottom"
|
||||
app:abb_indicatorMargin="28dp"
|
||||
app:abb_selectedTabType="text"
|
||||
app:abb_tabColor="@color/nav_tab"
|
||||
app:abb_tabColorDisabled="@color/nav_tab_disabled"
|
||||
app:abb_tabColor="?attr/colorSecondary"
|
||||
app:abb_tabColorDisabled="?attr/colorSecondaryContainer"
|
||||
app:abb_tabColorSelected="?attr/colorPrimary"
|
||||
app:abb_tabs="@menu/bottom_navbar_menu"
|
||||
app:abb_textAppearance="@style/NavBarText"
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
app:cardBackgroundColor="#000000"
|
||||
app:cardBackgroundColor="?attr/colorSurface"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:contentPadding="8dp"
|
||||
app:strokeColor="?attr/colorSecondary"
|
||||
@@ -70,7 +70,7 @@
|
||||
android:layout_marginEnd="8dp"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/bg_white"
|
||||
android:textColor="?attr/colorOnSurface"
|
||||
android:textSize="16sp" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
app:cardBackgroundColor="#000000"
|
||||
app:cardBackgroundColor="?attr/colorSurface"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:contentPadding="8dp"
|
||||
app:strokeColor="?attr/colorSecondary"
|
||||
@@ -108,7 +108,7 @@
|
||||
android:layout_marginEnd="8dp"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/bg_white"
|
||||
android:textColor="?attr/colorOnSurface"
|
||||
android:textSize="16sp" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
android:layout_marginEnd="8dp"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/bg_white"
|
||||
android:textColor="?android:colorBackground"
|
||||
android:textSize="16sp" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
android:layout_marginEnd="8dp"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/bg_white"
|
||||
android:textColor="?android:colorBackground"
|
||||
android:textSize="16sp" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
@@ -269,6 +269,10 @@
|
||||
android:fontFamily="@font/poppins"
|
||||
android:singleLine="false"
|
||||
android:textColor="@color/bg_white"
|
||||
android:shadowColor="#000"
|
||||
android:shadowDx="1"
|
||||
android:shadowDy="1"
|
||||
android:shadowRadius="1"
|
||||
android:textSize="12sp"
|
||||
tools:ignore="TextContrastCheck"
|
||||
tools:text="@string/popular_anime" />
|
||||
@@ -357,7 +361,7 @@
|
||||
app:labelStyle="@style/fontTooltip"
|
||||
app:thumbRadius="8dp"
|
||||
app:tickColor="#0000"
|
||||
app:trackColorInactive="@color/bg_white"
|
||||
app:trackColorInactive="?android:colorBackground"
|
||||
app:trackHeight="2dp" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
android:id="@+id/mediaAppBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/bg"
|
||||
android:background="?android:colorBackground"
|
||||
android:translationZ="5dp">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
@@ -17,7 +17,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="false"
|
||||
app:contentScrim="@color/nav_bg"
|
||||
app:contentScrim="?android:colorBackground"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
|
||||
|
||||
<com.flaviofaria.kenburnsview.KenBurnsView
|
||||
@@ -85,6 +85,7 @@
|
||||
android:singleLine="false"
|
||||
android:text="@string/slogan"
|
||||
android:textSize="16sp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
android:transitionName="mediaTitle" />
|
||||
|
||||
<TextView
|
||||
@@ -121,7 +122,7 @@
|
||||
android:singleLine="true"
|
||||
android:text="@string/add"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="?attr/colorSecondary"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
app:cornerRadius="16dp"
|
||||
@@ -153,7 +154,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:background="@color/nav_bg"
|
||||
app:contentScrim="?android:colorBackground"
|
||||
android:ellipsize="marquee"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
@@ -188,7 +189,7 @@
|
||||
android:lineSpacingExtra="-8sp"
|
||||
android:marqueeRepeatLimit="marquee_forever"
|
||||
android:maxLines="2"
|
||||
android:textColor="@color/fg"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
android:textSize="16sp"
|
||||
tools:text="Watched 10 out of 10" />
|
||||
|
||||
@@ -200,7 +201,7 @@
|
||||
android:padding="8dp"
|
||||
android:tintMode="src_atop"
|
||||
app:srcCompat="@drawable/ic_round_favorite_border_24"
|
||||
app:tint="@color/nav_tab"
|
||||
app:tint="?attr/colorSecondary"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
|
||||
<ImageView
|
||||
@@ -210,7 +211,7 @@
|
||||
android:layout_marginStart="-8dp"
|
||||
android:padding="8dp"
|
||||
app:srcCompat="@drawable/ic_round_share_24"
|
||||
app:tint="@color/nav_tab"
|
||||
app:tint="?attr/colorSecondary"
|
||||
app:tintMode="src_atop"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck" />
|
||||
|
||||
@@ -241,14 +242,14 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="0dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@color/nav_bg"
|
||||
android:background="?attr/colorSurface"
|
||||
android:translationZ="1dp"
|
||||
app:itemActiveIndicatorStyle="@style/BottomNavBar"
|
||||
app:itemIconTint="@color/tab_layout_icon"
|
||||
app:itemRippleColor="?attr/colorSecondary"
|
||||
app:itemRippleColor="?attr/colorPrimary"
|
||||
app:itemTextAppearanceActive="@style/NavBarText"
|
||||
app:itemTextAppearanceInactive="@style/NavBarText"
|
||||
app:itemTextColor="@color/tab_layout_text"
|
||||
app:itemTextColor="@color/tab_layout_icon"
|
||||
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/poppins_thin"
|
||||
android:text="@string/sad"
|
||||
android:textColor="@color/pink_500"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:textSize="64sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@@ -38,6 +38,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/no_internet"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/noInternetSad" />
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
android:background="@color/nav_bg_inv"
|
||||
android:padding="16dp"
|
||||
app:srcCompat="@drawable/ic_round_arrow_back_ios_new_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/video_info"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:showText="false"
|
||||
app:thumbTint="@color/button_switch_track">
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
android:background="@color/nav_bg_inv"
|
||||
android:padding="16dp"
|
||||
app:srcCompat="@drawable/ic_round_arrow_back_ios_new_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/source_info"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:showText="false"
|
||||
app:thumbTint="@color/button_switch_track">
|
||||
@@ -122,7 +122,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/show_system_bars"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -163,7 +163,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/auto_detect_webtoon"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -231,7 +231,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_round_amp_stories_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -249,7 +249,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_view_array_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -267,7 +267,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_view_column_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -320,7 +320,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:rotation="0"
|
||||
android:src="@drawable/ic_round_swipe_up_alt_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -374,7 +374,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_round_close_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -392,7 +392,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_screen_rotation_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -410,7 +410,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_menu_book_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -442,7 +442,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/over_scroll"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -462,7 +462,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/true_colors"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -494,7 +494,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/image_rotation"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -514,7 +514,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/crop_borders"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -535,7 +535,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/spaced_pages"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -555,7 +555,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/hide_page_numbers"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -575,7 +575,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/horizontal_scroll_bar"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -596,7 +596,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/keep_screen_on"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -616,7 +616,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/volume_buttons"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -636,7 +636,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/wrap_images"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -668,7 +668,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/image_long_clicking"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -703,7 +703,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/ask_update_progress_manga"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -738,7 +738,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/ask_update_progress_doujin"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
android:background="@color/nav_bg_inv"
|
||||
android:padding="16dp"
|
||||
app:srcCompat="@drawable/ic_round_arrow_back_ios_new_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_brightness_high_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_round_brightness_4_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_brightness_auto_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
@@ -172,11 +172,45 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/use_material_you"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
app:thumbTint="@color/button_switch_track" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.58"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:text="@string/theme_" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:boxCornerRadiusBottomEnd="8dp"
|
||||
app:boxCornerRadiusBottomStart="8dp"
|
||||
app:boxCornerRadiusTopEnd="8dp"
|
||||
app:boxCornerRadiusTopStart="8dp"
|
||||
app:hintAnimationEnabled="true"
|
||||
app:startIconDrawable="@drawable/ic_round_source_24">
|
||||
|
||||
<AutoCompleteTextView
|
||||
android:id="@+id/themeSwitcher"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:freezesText="false"
|
||||
android:inputType="none"
|
||||
android:padding="8dp"
|
||||
android:text="@string/watch"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="14sp"
|
||||
tools:ignore="LabelFor,TextContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</ani.dantotsu.others.Xpandable>
|
||||
|
||||
<ani.dantotsu.others.Xpandable
|
||||
@@ -236,7 +270,7 @@
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:padding="16dp"
|
||||
android:text="@string/logout"
|
||||
android:textColor="?attr/colorSecondaryVariant"
|
||||
android:textColor="?attr/colorSecondary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -312,7 +346,7 @@
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:padding="16dp"
|
||||
android:text="@string/logout"
|
||||
android:textColor="?attr/colorSecondaryVariant"
|
||||
android:textColor="?attr/colorSecondary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -348,7 +382,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="@drawable/ic_discord"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<LinearLayout
|
||||
@@ -380,7 +414,7 @@
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:padding="16dp"
|
||||
android:text="@string/logout"
|
||||
android:textColor="?attr/colorSecondaryVariant"
|
||||
android:textColor="?attr/colorSecondary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -411,7 +445,7 @@
|
||||
android:layout_height="64dp"
|
||||
android:layout_marginStart="-32dp"
|
||||
android:layout_marginEnd="-32dp"
|
||||
android:background="@color/bg"
|
||||
android:background="?android:colorBackground"
|
||||
android:drawablePadding="16dp"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:gravity="center_vertical"
|
||||
@@ -421,7 +455,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/account_help"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableStartCompat="@drawable/ic_round_help_24"
|
||||
app:drawableTint="?attr/colorPrimary" />
|
||||
@@ -456,7 +490,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/force_legacy_installer"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -474,7 +508,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/skip_loading_extension_icons"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -499,6 +533,40 @@
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.58"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:text="@string/extension_specific_dns" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:boxCornerRadiusBottomEnd="8dp"
|
||||
app:boxCornerRadiusBottomStart="8dp"
|
||||
app:boxCornerRadiusTopEnd="8dp"
|
||||
app:boxCornerRadiusTopStart="8dp"
|
||||
app:hintAnimationEnabled="true"
|
||||
app:startIconDrawable="@drawable/ic_round_dns_24">
|
||||
|
||||
<AutoCompleteTextView
|
||||
android:id="@+id/settingsExtensionDns"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:freezesText="false"
|
||||
android:inputType="none"
|
||||
android:padding="8dp"
|
||||
android:text="@string/none"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="14sp"
|
||||
tools:ignore="LabelFor,TextContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
|
||||
</ani.dantotsu.others.Xpandable>
|
||||
|
||||
@@ -547,7 +615,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_movie_filter_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -566,7 +634,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_round_home_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -584,7 +652,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_import_contacts_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -613,7 +681,7 @@
|
||||
android:text="@string/ui_settings"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_round_auto_awesome_24"
|
||||
app:iconPadding="16dp"
|
||||
@@ -687,7 +755,7 @@
|
||||
android:text="@string/download_manager_select"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_round_download_24"
|
||||
app:iconPadding="16dp"
|
||||
@@ -705,7 +773,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/downloadInSd"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -723,7 +791,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/always_continue_shows"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -741,7 +809,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/recentlyListOnly"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -777,7 +845,7 @@
|
||||
android:text="@string/subscriptions_checking_time_s"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_round_notifications_none_24"
|
||||
app:iconPadding="16dp"
|
||||
@@ -804,7 +872,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/notification_for_checking_subscriptions"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -873,7 +941,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/prefer_dub"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -892,7 +960,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/show_yt"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -927,7 +995,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_view_list_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -946,7 +1014,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_round_grid_view_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -964,7 +1032,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_view_comfy_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -995,7 +1063,7 @@
|
||||
android:text="@string/player_settings"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_round_video_settings_24"
|
||||
app:iconPadding="16dp"
|
||||
@@ -1090,7 +1158,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_view_list_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -1108,7 +1176,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_view_comfy_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -1138,7 +1206,7 @@
|
||||
android:text="@string/reader_settings"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_round_reader_settings"
|
||||
app:iconPadding="16dp"
|
||||
@@ -1178,7 +1246,7 @@
|
||||
android:layout_marginStart="-32dp"
|
||||
android:layout_marginEnd="-32dp"
|
||||
android:background="@drawable/ui_bg"
|
||||
android:backgroundTint="@color/bg_opp"
|
||||
android:backgroundTint="?attr/colorOnBackground"
|
||||
android:backgroundTintMode="src_atop"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:insetTop="0dp"
|
||||
@@ -1188,7 +1256,7 @@
|
||||
android:text="@string/faq"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_round_help_24"
|
||||
app:iconPadding="16dp"
|
||||
@@ -1207,7 +1275,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/check_app_updates"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -1228,7 +1296,7 @@
|
||||
android:text="@string/devs"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_round_accessible_forward_24"
|
||||
app:iconPadding="16dp"
|
||||
@@ -1249,7 +1317,7 @@
|
||||
android:text="@string/forks"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_round_restaurant_24"
|
||||
app:iconPadding="16dp"
|
||||
@@ -1270,7 +1338,7 @@
|
||||
android:text="@string/disclaimer"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_round_info_24"
|
||||
app:iconPadding="16dp"
|
||||
@@ -1347,7 +1415,7 @@
|
||||
android:layout_weight="1"
|
||||
android:padding="6dp"
|
||||
android:src="@drawable/ic_discord"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
@@ -1357,7 +1425,7 @@
|
||||
android:layout_margin="8dp"
|
||||
android:padding="6dp"
|
||||
android:src="@drawable/ic_github"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:background="@color/nav_bg"
|
||||
android:background="?attr/colorSecondary"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
@@ -21,6 +21,7 @@
|
||||
android:singleLine="true"
|
||||
android:textAlignment="center"
|
||||
android:textSize="20sp"
|
||||
android:textColor="?attr/colorOnSecondary"
|
||||
tools:text="@string/main_studio" />
|
||||
|
||||
|
||||
@@ -56,7 +57,7 @@
|
||||
android:layout_gravity="end"
|
||||
android:layout_margin="16dp"
|
||||
android:translationZ="2dp"
|
||||
app:cardBackgroundColor="@color/nav_bg"
|
||||
app:cardBackgroundColor="?attr/colorSecondary"
|
||||
app:cardCornerRadius="16dp">
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
android:background="@color/nav_bg_inv"
|
||||
android:padding="16dp"
|
||||
app:srcCompat="@drawable/ic_round_arrow_back_ios_new_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/immersive_mode"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:showText="false"
|
||||
app:thumbTint="@color/button_switch_track">
|
||||
@@ -141,7 +141,7 @@
|
||||
android:text="@string/home_layout_show"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_round_playlist_add_24"
|
||||
app:iconPadding="16dp"
|
||||
@@ -169,7 +169,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/small_view"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -203,7 +203,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/banner_animations"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:showText="false"
|
||||
app:thumbTint="@color/button_switch_track">
|
||||
@@ -225,7 +225,7 @@
|
||||
android:paddingEnd="32dp"
|
||||
android:text="@string/layout_animations"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_round_amp_stories_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_view_column_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_round_close_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_screen_rotation_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_menu_book_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -231,7 +231,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_minus"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_add"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
@@ -300,7 +300,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_minus"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -334,7 +334,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_add"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
@@ -368,7 +368,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_minus"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -402,7 +402,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_add"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
@@ -445,7 +445,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_minus"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -479,7 +479,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_add"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
@@ -505,7 +505,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="Use Dark Theme"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -524,7 +524,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/keep_screen_on"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -544,7 +544,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/volume_buttons"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_round_amp_stories_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_view_array_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_view_column_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:rotation="0"
|
||||
android:src="@drawable/ic_round_swipe_up_alt_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleX="-1"
|
||||
android:src="@drawable/ic_round_close_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -224,7 +224,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_screen_rotation_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -242,7 +242,7 @@
|
||||
android:alpha="0.33"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_round_menu_book_24"
|
||||
app:tint="@color/bg_opp"
|
||||
app:tint="?attr/colorOnBackground"
|
||||
tools:ignore="ContentDescription,SpeakableTextPresentCheck,ImageContrastCheck" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -270,7 +270,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/over_scroll"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -288,7 +288,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/true_colors"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -316,7 +316,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/image_rotation"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -334,7 +334,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/crop_borders"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -353,7 +353,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/spaced_pages"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -371,7 +371,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/hide_page_numbers"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -389,7 +389,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/horizontal_scroll_bar"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -407,7 +407,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/keep_screen_on"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -425,7 +425,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/volume_buttons"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -443,7 +443,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/wrap_images"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
@@ -470,7 +470,7 @@
|
||||
android:minHeight="64dp"
|
||||
android:text="@string/image_long_clicking"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:buttonTint="?attr/colorPrimary"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
@@ -69,6 +70,7 @@
|
||||
android:insetBottom="0dp"
|
||||
android:padding="8dp"
|
||||
android:textSize="16sp"
|
||||
app:strokeColor="?attr/colorPrimaryContainer"
|
||||
android:visibility="gone"
|
||||
app:cornerRadius="16dp"
|
||||
tools:ignore="SpeakableTextPresentCheck"
|
||||
@@ -86,6 +88,7 @@
|
||||
android:insetBottom="0dp"
|
||||
android:padding="8dp"
|
||||
android:textSize="16sp"
|
||||
app:strokeColor="?attr/colorPrimaryContainer"
|
||||
android:visibility="gone"
|
||||
app:cornerRadius="16dp"
|
||||
tools:ignore="SpeakableTextPresentCheck"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
android:layout_height="4dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="14dp"
|
||||
app:cardBackgroundColor="@color/nav_tab"
|
||||
app:cardBackgroundColor="?attr/colorPrimary"
|
||||
app:cardCornerRadius="2dp"
|
||||
app:cardElevation="0dp"/>
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
android:layout_height="4dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="8dp"
|
||||
app:cardBackgroundColor="@color/nav_tab"
|
||||
app:cardBackgroundColor="?attr/colorPrimary"
|
||||
app:cardCornerRadius="2dp"
|
||||
app:cardElevation="0dp" />
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
android:textSize="16sp"
|
||||
android:visibility="gone"
|
||||
app:cornerRadius="16dp"
|
||||
app:strokeColor="?attr/colorPrimaryContainer"
|
||||
tools:ignore="SpeakableTextPresentCheck"
|
||||
tools:visibility="visible" />
|
||||
|
||||
@@ -117,6 +118,7 @@
|
||||
android:text="@string/save"
|
||||
android:textSize="16sp"
|
||||
app:cornerRadius="16dp"
|
||||
app:strokeColor="?attr/colorPrimaryContainer"
|
||||
tools:ignore="SpeakableTextPresentCheck" />
|
||||
|
||||
<Button
|
||||
@@ -134,6 +136,7 @@
|
||||
android:text="@string/share"
|
||||
android:textSize="16sp"
|
||||
app:cornerRadius="16dp"
|
||||
app:strokeColor="?attr/colorPrimaryContainer"
|
||||
tools:ignore="SpeakableTextPresentCheck" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
app:boxCornerRadiusTopEnd="16dp"
|
||||
app:boxCornerRadiusTopStart="16dp"
|
||||
app:hintAnimationEnabled="true"
|
||||
app:boxStrokeColor="@color/text_input_layout_stroke_color"
|
||||
app:startIconDrawable="@drawable/ic_round_playlist_play_24">
|
||||
|
||||
<AutoCompleteTextView
|
||||
@@ -73,6 +74,7 @@
|
||||
android:text="@string/watch"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
|
||||
android:textSize="14sp"
|
||||
tools:ignore="LabelFor,TextContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
@@ -96,6 +98,7 @@
|
||||
app:boxCornerRadiusTopStart="16dp"
|
||||
app:endIconMode="none"
|
||||
app:hintAnimationEnabled="true"
|
||||
app:boxStrokeColor="@color/text_input_layout_stroke_color"
|
||||
app:startIconDrawable="@drawable/ic_round_add_circle_outline_24"
|
||||
app:suffixTextAppearance="@style/Suffix">
|
||||
|
||||
@@ -124,7 +127,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="-2dp"
|
||||
|
||||
app:strokeColor="?attr/colorPrimaryContainer"
|
||||
android:elevation="0dp"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:insetTop="0dp"
|
||||
@@ -154,6 +157,7 @@
|
||||
app:endIconMode="none"
|
||||
app:hintAnimationEnabled="true"
|
||||
app:startIconDrawable="@drawable/ic_round_star_24"
|
||||
app:boxStrokeColor="@color/text_input_layout_stroke_color"
|
||||
app:suffixText="@string/score_suffix"
|
||||
app:suffixTextAppearance="@style/Suffix">
|
||||
|
||||
@@ -193,6 +197,7 @@
|
||||
app:endIconMode="none"
|
||||
app:hintAnimationEnabled="true"
|
||||
app:startIconDrawable="@drawable/ic_round_date_range_24"
|
||||
app:boxStrokeColor="@color/text_input_layout_stroke_color"
|
||||
app:suffixTextAppearance="@style/Suffix">
|
||||
|
||||
<AutoCompleteTextView
|
||||
@@ -227,6 +232,7 @@
|
||||
app:boxCornerRadiusTopStart="16dp"
|
||||
app:endIconMode="none"
|
||||
app:hintAnimationEnabled="true"
|
||||
app:boxStrokeColor="@color/text_input_layout_stroke_color"
|
||||
app:suffixTextAppearance="@style/Suffix">
|
||||
|
||||
<AutoCompleteTextView
|
||||
@@ -362,6 +368,7 @@
|
||||
android:layout_width="128dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_gravity="center"
|
||||
app:strokeColor="?attr/colorPrimaryContainer"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:insetTop="0dp"
|
||||
android:insetBottom="0dp"
|
||||
@@ -378,6 +385,7 @@
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
app:strokeColor="?attr/colorPrimaryContainer"
|
||||
android:insetTop="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:padding="8dp"
|
||||
@@ -392,7 +400,7 @@
|
||||
android:layout_height="4dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="14dp"
|
||||
app:cardBackgroundColor="@color/nav_tab"
|
||||
app:cardBackgroundColor="?attr/colorPrimary"
|
||||
app:cardCornerRadius="2dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
app:boxCornerRadiusTopEnd="16dp"
|
||||
app:boxCornerRadiusTopStart="16dp"
|
||||
app:hintAnimationEnabled="true"
|
||||
app:boxStrokeColor="@color/text_input_layout_stroke_color"
|
||||
app:startIconDrawable="@drawable/ic_round_playlist_play_24">
|
||||
|
||||
<AutoCompleteTextView
|
||||
@@ -92,6 +93,7 @@
|
||||
app:boxCornerRadiusTopStart="16dp"
|
||||
app:endIconMode="none"
|
||||
app:hintAnimationEnabled="true"
|
||||
app:boxStrokeColor="@color/text_input_layout_stroke_color"
|
||||
app:startIconDrawable="@drawable/ic_round_add_circle_outline_24"
|
||||
app:suffixTextAppearance="@style/Suffix">
|
||||
|
||||
@@ -122,6 +124,7 @@
|
||||
android:layout_marginTop="-2dp"
|
||||
android:elevation="0dp"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
app:strokeColor="?attr/colorPrimaryContainer"
|
||||
android:insetTop="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:minWidth="@null"
|
||||
@@ -150,6 +153,7 @@
|
||||
app:hintAnimationEnabled="true"
|
||||
app:startIconDrawable="@drawable/ic_round_star_24"
|
||||
app:suffixText="@string/score_suffix"
|
||||
app:boxStrokeColor="@color/text_input_layout_stroke_color"
|
||||
app:suffixTextAppearance="@style/Suffix">
|
||||
|
||||
<AutoCompleteTextView
|
||||
@@ -180,6 +184,7 @@
|
||||
android:layout_height="56dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
app:strokeColor="?attr/colorPrimaryContainer"
|
||||
android:insetTop="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:padding="8dp"
|
||||
@@ -195,7 +200,7 @@
|
||||
android:layout_height="4dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="14dp"
|
||||
app:cardBackgroundColor="@color/nav_tab"
|
||||
app:cardBackgroundColor="?attr/colorPrimary"
|
||||
app:cardCornerRadius="2dp"
|
||||
app:cardElevation="0dp" >
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
app:boxCornerRadiusBottomStart="16dp"
|
||||
app:boxCornerRadiusTopEnd="16dp"
|
||||
app:boxCornerRadiusTopStart="16dp"
|
||||
app:boxStrokeColor="@color/text_input_layout_stroke_color"
|
||||
app:hintAnimationEnabled="true">
|
||||
|
||||
<AutoCompleteTextView
|
||||
@@ -71,6 +72,7 @@
|
||||
app:boxCornerRadiusBottomStart="16dp"
|
||||
app:boxCornerRadiusTopEnd="16dp"
|
||||
app:boxCornerRadiusTopStart="16dp"
|
||||
app:boxStrokeColor="@color/text_input_layout_stroke_color"
|
||||
app:hintAnimationEnabled="true">
|
||||
|
||||
<AutoCompleteTextView
|
||||
@@ -110,6 +112,7 @@
|
||||
app:boxCornerRadiusBottomStart="16dp"
|
||||
app:boxCornerRadiusTopEnd="16dp"
|
||||
app:boxCornerRadiusTopStart="16dp"
|
||||
app:boxStrokeColor="@color/text_input_layout_stroke_color"
|
||||
app:hintAnimationEnabled="true">
|
||||
|
||||
<AutoCompleteTextView
|
||||
@@ -140,6 +143,7 @@
|
||||
app:boxCornerRadiusBottomStart="16dp"
|
||||
app:boxCornerRadiusTopEnd="16dp"
|
||||
app:boxCornerRadiusTopStart="16dp"
|
||||
app:boxStrokeColor="@color/text_input_layout_stroke_color"
|
||||
app:hintAnimationEnabled="true">
|
||||
|
||||
<AutoCompleteTextView
|
||||
@@ -248,6 +252,7 @@
|
||||
<Button
|
||||
android:id="@+id/searchFilterCancel"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton"
|
||||
app:strokeColor="?attr/colorPrimaryContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_margin="8dp"
|
||||
@@ -264,6 +269,7 @@
|
||||
<Button
|
||||
android:id="@+id/searchFilterApply"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton"
|
||||
app:strokeColor="?attr/colorPrimaryContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_margin="8dp"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user