clean Sad's shit

This commit is contained in:
Finnley Somdahl 2024-01-13 11:20:02 -06:00
parent 84e300482a
commit cc5b512441
53 changed files with 652 additions and 466 deletions

View file

@ -11,12 +11,14 @@ import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.provider.Settings import android.provider.Settings
import android.util.Log
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.animation.AnticipateInterpolator import android.view.animation.AnticipateInterpolator
import android.widget.TextView import android.widget.TextView
import androidx.activity.addCallback import androidx.activity.addCallback
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.annotation.OptIn
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.animation.doOnEnd import androidx.core.animation.doOnEnd
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
@ -26,12 +28,14 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.offline.Download
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
import ani.dantotsu.App.Companion.context
import ani.dantotsu.connections.anilist.Anilist import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.AnilistHomeViewModel import ani.dantotsu.connections.anilist.AnilistHomeViewModel
import ani.dantotsu.databinding.ActivityMainBinding import ani.dantotsu.databinding.ActivityMainBinding
import ani.dantotsu.databinding.SplashScreenBinding import ani.dantotsu.databinding.SplashScreenBinding
import ani.dantotsu.download.video.Helper
import ani.dantotsu.home.AnimeFragment import ani.dantotsu.home.AnimeFragment
import ani.dantotsu.home.HomeFragment import ani.dantotsu.home.HomeFragment
import ani.dantotsu.home.LoginFragment import ani.dantotsu.home.LoginFragment
@ -46,6 +50,7 @@ import ani.dantotsu.themes.ThemeManager
import io.noties.markwon.Markwon import io.noties.markwon.Markwon
import io.noties.markwon.SoftBreakAddsNewLinePlugin import io.noties.markwon.SoftBreakAddsNewLinePlugin
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -61,6 +66,7 @@ class MainActivity : AppCompatActivity() {
private var uiSettings = UserInterfaceSettings() private var uiSettings = UserInterfaceSettings()
@OptIn(UnstableApi::class)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
ThemeManager(this).applyTheme() ThemeManager(this).applyTheme()
LangSet.setLocale(this) LangSet.setLocale(this)
@ -149,48 +155,49 @@ class MainActivity : AppCompatActivity() {
} }
} }
if (!isOnline(this)) { if (!isOnline(this)) {
snackString(this@MainActivity.getString(R.string.no_internet_connection)) snackString(this@MainActivity.getString(R.string.no_internet_connection))
startActivity(Intent(this, NoInternet::class.java)) startActivity(Intent(this, NoInternet::class.java))
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE) getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
.edit() .edit()
.putBoolean("offlineMode", true) .putBoolean("offlineMode", true)
.apply()} else { .apply()
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE) } else {
.edit() getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
.putBoolean("offlineMode", false) .edit()
.apply() .putBoolean("offlineMode", false)
val model: AnilistHomeViewModel by viewModels() .apply()
model.genres.observe(this) { it -> val model: AnilistHomeViewModel by viewModels()
if (it != null) { model.genres.observe(this) { it ->
if (it) { if (it != null) {
val navbar = binding.includedNavbar.navbar if (it) {
bottomBar = navbar val navbar = binding.includedNavbar.navbar
navbar.visibility = View.VISIBLE bottomBar = navbar
binding.mainProgressBar.visibility = View.GONE navbar.visibility = View.VISIBLE
val mainViewPager = binding.viewpager binding.mainProgressBar.visibility = View.GONE
mainViewPager.isUserInputEnabled = false val mainViewPager = binding.viewpager
mainViewPager.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle) mainViewPager.isUserInputEnabled = false
mainViewPager.setPageTransformer(ZoomOutPageTransformer(uiSettings)) mainViewPager.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle)
navbar.setOnTabSelectListener(object : mainViewPager.setPageTransformer(ZoomOutPageTransformer(uiSettings))
AnimatedBottomBar.OnTabSelectListener { navbar.setOnTabSelectListener(object :
override fun onTabSelected( AnimatedBottomBar.OnTabSelectListener {
lastIndex: Int, override fun onTabSelected(
lastTab: AnimatedBottomBar.Tab?, lastIndex: Int,
newIndex: Int, lastTab: AnimatedBottomBar.Tab?,
newTab: AnimatedBottomBar.Tab newIndex: Int,
) { newTab: AnimatedBottomBar.Tab
navbar.animate().translationZ(12f).setDuration(200).start() ) {
selectedOption = newIndex navbar.animate().translationZ(12f).setDuration(200).start()
mainViewPager.setCurrentItem(newIndex, false) selectedOption = newIndex
mainViewPager.setCurrentItem(newIndex, false)
}
})
navbar.selectTabAt(selectedOption)
mainViewPager.post { mainViewPager.setCurrentItem(selectedOption, false) }
} else {
binding.mainProgressBar.visibility = View.GONE
} }
}) }
navbar.selectTabAt(selectedOption)
mainViewPager.post { mainViewPager.setCurrentItem(selectedOption, false) }
} else {
binding.mainProgressBar.visibility = View.GONE
}
} }
}
//Load Data //Load Data
if (!load) { if (!load) {
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
@ -249,7 +256,7 @@ class MainActivity : AppCompatActivity() {
} }
} }
GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) {
val index = Helper.downloadManager(this@MainActivity).downloadIndex val index = Helper.downloadManager(this@MainActivity).downloadIndex
val downloadCursor = index.getDownloads() val downloadCursor = index.getDownloads()
while (downloadCursor.moveToNext()) { while (downloadCursor.moveToNext()) {
val download = downloadCursor.download val download = downloadCursor.download
@ -267,8 +274,6 @@ class MainActivity : AppCompatActivity() {
} }
} }
} }

View file

@ -7,7 +7,6 @@ import androidx.annotation.OptIn
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.database.StandaloneDatabaseProvider import androidx.media3.database.StandaloneDatabaseProvider
import androidx.media3.datasource.cache.SimpleCache
import ani.dantotsu.download.DownloadsManager import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.media.manga.MangaCache import ani.dantotsu.media.manga.MangaCache
import ani.dantotsu.parsers.novel.NovelExtensionManager import ani.dantotsu.parsers.novel.NovelExtensionManager
@ -31,7 +30,8 @@ import uy.kohesive.injekt.api.addSingletonFactory
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
class AppModule(val app: Application) : InjektModule { class AppModule(val app: Application) : InjektModule {
@OptIn(UnstableApi::class) override fun InjektRegistrar.registerInjectables() { @OptIn(UnstableApi::class)
override fun InjektRegistrar.registerInjectables() {
addSingleton(app) addSingleton(app)
addSingletonFactory { DownloadsManager(app) } addSingletonFactory { DownloadsManager(app) }

View file

@ -10,7 +10,6 @@ import ani.dantotsu.toast
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.math.roundToInt
fun updateProgress(media: Media, number: String) { fun updateProgress(media: Media, number: String) {
val incognito = currContext()?.getSharedPreferences("Dantotsu", 0) val incognito = currContext()?.getSharedPreferences("Dantotsu", 0)

View file

@ -17,7 +17,6 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.offline.Download
import androidx.media3.exoplayer.offline.DownloadManager import androidx.media3.exoplayer.offline.DownloadManager
import androidx.media3.exoplayer.offline.DownloadService import androidx.media3.exoplayer.offline.DownloadService
import ani.dantotsu.FileUrl import ani.dantotsu.FileUrl
@ -25,8 +24,8 @@ import ani.dantotsu.R
import ani.dantotsu.currActivity import ani.dantotsu.currActivity
import ani.dantotsu.download.DownloadedType import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.download.video.Helper
import ani.dantotsu.download.video.ExoplayerDownloadService import ani.dantotsu.download.video.ExoplayerDownloadService
import ani.dantotsu.download.video.Helper
import ani.dantotsu.logger import ani.dantotsu.logger
import ani.dantotsu.media.Media import ani.dantotsu.media.Media
import ani.dantotsu.media.anime.AnimeWatchFragment import ani.dantotsu.media.anime.AnimeWatchFragment
@ -80,12 +79,13 @@ class AnimeDownloaderService : Service() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
notificationManager = NotificationManagerCompat.from(this) notificationManager = NotificationManagerCompat.from(this)
builder = NotificationCompat.Builder(this, Notifications.CHANNEL_DOWNLOADER_PROGRESS).apply { builder =
setContentTitle("Anime Download Progress") NotificationCompat.Builder(this, Notifications.CHANNEL_DOWNLOADER_PROGRESS).apply {
setSmallIcon(R.drawable.ic_round_download_24) setContentTitle("Anime Download Progress")
priority = NotificationCompat.PRIORITY_DEFAULT setSmallIcon(R.drawable.ic_round_download_24)
setOnlyAlertOnce(true) priority = NotificationCompat.PRIORITY_DEFAULT
} setOnlyAlertOnce(true)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground( startForeground(
NOTIFICATION_ID, NOTIFICATION_ID,
@ -154,7 +154,9 @@ class AnimeDownloaderService : Service() {
fun cancelDownload(taskName: String) { fun cancelDownload(taskName: String) {
CoroutineScope(Dispatchers.Default).launch { CoroutineScope(Dispatchers.Default).launch {
mutex.withLock { mutex.withLock {
val url = AnimeServiceDataSingleton.downloadQueue.find { it.getTaskName() == taskName }?.video?.file?.url ?: "" val url =
AnimeServiceDataSingleton.downloadQueue.find { it.getTaskName() == taskName }?.video?.file?.url
?: ""
DownloadService.sendRemoveDownload( DownloadService.sendRemoveDownload(
this@AnimeDownloaderService, this@AnimeDownloaderService,
ExoplayerDownloadService::class.java, ExoplayerDownloadService::class.java,
@ -188,7 +190,8 @@ class AnimeDownloaderService : Service() {
notificationManager.notify(NOTIFICATION_ID, builder.build()) notificationManager.notify(NOTIFICATION_ID, builder.build())
} }
@androidx.annotation.OptIn(UnstableApi::class) suspend fun download(task: DownloadTask) { @androidx.annotation.OptIn(UnstableApi::class)
suspend fun download(task: DownloadTask) {
try { try {
val downloadManager = Helper.downloadManager(this@AnimeDownloaderService) val downloadManager = Helper.downloadManager(this@AnimeDownloaderService)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
@ -212,11 +215,13 @@ class AnimeDownloaderService : Service() {
Helper.downloadVideo( Helper.downloadVideo(
it, it,
task.video, task.video,
task.subtitle) task.subtitle
)
} }
saveMediaInfo(task) saveMediaInfo(task)
val downloadStarted = hasDownloadStarted(downloadManager, task, 30000) // 30 seconds timeout val downloadStarted =
hasDownloadStarted(downloadManager, task, 30000) // 30 seconds timeout
if (!downloadStarted) { if (!downloadStarted) {
logger("Download failed to start") logger("Download failed to start")
@ -238,11 +243,15 @@ class AnimeDownloaderService : Service() {
notificationManager.notify(NOTIFICATION_ID, builder.build()) notificationManager.notify(NOTIFICATION_ID, builder.build())
snackString("${task.title} - ${task.episode} Download failed") snackString("${task.title} - ${task.episode} Download failed")
logger("Download failed: ${download.failureReason}") logger("Download failed: ${download.failureReason}")
FirebaseCrashlytics.getInstance().recordException(Exception("Anime Download failed:" + FirebaseCrashlytics.getInstance().recordException(
" ${download.failureReason}" + Exception(
" url: ${task.video.file.url}" + "Anime Download failed:" +
" title: ${task.title}" + " ${download.failureReason}" +
" episode: ${task.episode}")) " url: ${task.video.file.url}" +
" title: ${task.title}" +
" episode: ${task.episode}"
)
)
broadcastDownloadFailed(task.getTaskName()) broadcastDownloadFailed(task.getTaskName())
break break
} }
@ -251,7 +260,10 @@ class AnimeDownloaderService : Service() {
builder.setContentText("${task.title} - ${task.episode} Download completed") builder.setContentText("${task.title} - ${task.episode} Download completed")
notificationManager.notify(NOTIFICATION_ID, builder.build()) notificationManager.notify(NOTIFICATION_ID, builder.build())
snackString("${task.title} - ${task.episode} Download completed") snackString("${task.title} - ${task.episode} Download completed")
getSharedPreferences(getString(R.string.anime_downloads), Context.MODE_PRIVATE).edit().putString( getSharedPreferences(
getString(R.string.anime_downloads),
Context.MODE_PRIVATE
).edit().putString(
task.getTaskName(), task.getTaskName(),
task.video.file.url task.video.file.url
).apply() ).apply()
@ -272,7 +284,10 @@ class AnimeDownloaderService : Service() {
snackString("${task.title} - ${task.episode} Download stopped") snackString("${task.title} - ${task.episode} Download stopped")
break break
} }
broadcastDownloadProgress(task.getTaskName(), download.percentDownloaded.toInt()) broadcastDownloadProgress(
task.getTaskName(),
download.percentDownloaded.toInt()
)
if (notifi) { if (notifi) {
notificationManager.notify(NOTIFICATION_ID, builder.build()) notificationManager.notify(NOTIFICATION_ID, builder.build())
} }
@ -288,7 +303,12 @@ class AnimeDownloaderService : Service() {
} }
} }
@androidx.annotation.OptIn(UnstableApi::class) suspend fun hasDownloadStarted(downloadManager: DownloadManager, task: DownloadTask, timeout: Long): Boolean { @androidx.annotation.OptIn(UnstableApi::class)
suspend fun hasDownloadStarted(
downloadManager: DownloadManager,
task: DownloadTask,
timeout: Long
): Boolean {
val startTime = System.currentTimeMillis() val startTime = System.currentTimeMillis()
while (System.currentTimeMillis() - startTime < timeout) { while (System.currentTimeMillis() - startTime < timeout) {
val download = downloadManager.downloadIndex.getDownload(task.video.file.url) val download = downloadManager.downloadIndex.getDownload(task.video.file.url)
@ -331,7 +351,11 @@ class AnimeDownloaderService : Service() {
media.banner = media.banner?.let { downloadImage(it, directory, "banner.jpg") } media.banner = media.banner?.let { downloadImage(it, directory, "banner.jpg") }
if (task.episodeImage != null) { if (task.episodeImage != null) {
media.anime?.episodes?.get(task.episode)?.let { episode -> media.anime?.episodes?.get(task.episode)?.let { episode ->
episode.thumb = downloadImage(task.episodeImage, episodeDirectory, "episodeImage.jpg")?.let { episode.thumb = downloadImage(
task.episodeImage,
episodeDirectory,
"episodeImage.jpg"
)?.let {
FileUrl( FileUrl(
it it
) )
@ -412,7 +436,8 @@ class AnimeDownloaderService : Service() {
} }
private val cancelReceiver = object : BroadcastReceiver() { private val cancelReceiver = object : BroadcastReceiver() {
@androidx.annotation.OptIn(UnstableApi::class) override fun onReceive(context: Context, intent: Intent) { @androidx.annotation.OptIn(UnstableApi::class)
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == ACTION_CANCEL_DOWNLOAD) { if (intent.action == ACTION_CANCEL_DOWNLOAD) {
val taskName = intent.getStringExtra(EXTRA_TASK_NAME) val taskName = intent.getStringExtra(EXTRA_TASK_NAME)
taskName?.let { taskName?.let {

View file

@ -21,7 +21,8 @@ class OfflineMangaAdapter(
private val inflater: LayoutInflater = private val inflater: LayoutInflater =
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
private var originalItems: List<OfflineMangaModel> = items private var originalItems: List<OfflineMangaModel> = items
private var style = context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getInt("offline_view", 0) private var style =
context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getInt("offline_view", 0)
override fun getCount(): Int { override fun getCount(): Int {
return items.size return items.size
@ -38,14 +39,14 @@ class OfflineMangaAdapter(
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val view: View = convertView ?: when(style) { val view: View = convertView ?: when (style) {
0 -> inflater.inflate(R.layout.item_media_large, parent, false) // large view 0 -> inflater.inflate(R.layout.item_media_large, parent, false) // large view
1 -> inflater.inflate(R.layout.item_media_compact, parent, false) // compact view 1 -> inflater.inflate(R.layout.item_media_compact, parent, false) // compact view
else -> inflater.inflate(R.layout.item_media_compact, parent, false) // compact view else -> inflater.inflate(R.layout.item_media_compact, parent, false) // compact view
} }
val item = getItem(position) as OfflineMangaModel val item = getItem(position) as OfflineMangaModel
val imageView = view!!.findViewById<ImageView>(R.id.itemCompactImage) val imageView = view.findViewById<ImageView>(R.id.itemCompactImage)
val titleTextView = view.findViewById<TextView>(R.id.itemCompactTitle) val titleTextView = view.findViewById<TextView>(R.id.itemCompactTitle)
val itemScore = view.findViewById<TextView>(R.id.itemCompactScore) val itemScore = view.findViewById<TextView>(R.id.itemCompactScore)
val itemScoreBG = view.findViewById<View>(R.id.itemCompactScoreBG) val itemScoreBG = view.findViewById<View>(R.id.itemCompactScoreBG)
@ -55,22 +56,21 @@ class OfflineMangaAdapter(
val type = view.findViewById<TextView>(R.id.itemCompactRelation) val type = view.findViewById<TextView>(R.id.itemCompactRelation)
val typeView = view.findViewById<LinearLayout>(R.id.itemCompactType) val typeView = view.findViewById<LinearLayout>(R.id.itemCompactType)
if (style == 0){ if (style == 0) {
val bannerView = view.findViewById<ImageView>(R.id.itemCompactBanner) // for large view val bannerView = view.findViewById<ImageView>(R.id.itemCompactBanner) // for large view
val chapters = view.findViewById<TextView>(R.id.itemTotal) val chapters = view.findViewById<TextView>(R.id.itemTotal)
chapters.text = " Chapters" chapters.text = " Chapters"
bannerView.setImageURI(item.banner) bannerView.setImageURI(item.banner)
totalchapter.text = item.totalchapter totalchapter.text = item.totalchapter
} } else if (style == 1) {
val readchapter =
else if (style == 1){ view.findViewById<TextView>(R.id.itemCompactUserProgress) // for compact view
val readchapter = view.findViewById<TextView>(R.id.itemCompactUserProgress) // for compact view
readchapter.text = item.readchapter readchapter.text = item.readchapter
totalchapter.text = " | " + item.totalchapter totalchapter.text = " | " + item.totalchapter
} }
// Bind item data to the views // Bind item data to the views
typeimage.setImageResource(if (item.type == "Novel" ) R.drawable.ic_round_book_24 else R.drawable.ic_round_import_contacts_24) typeimage.setImageResource(if (item.type == "Novel") R.drawable.ic_round_book_24 else R.drawable.ic_round_import_contacts_24)
type.text = item.type type.text = item.type
typeView.visibility = View.VISIBLE typeView.visibility = View.VISIBLE
imageView.setImageURI(item.image) imageView.setImageURI(item.image)
@ -103,8 +103,9 @@ class OfflineMangaAdapter(
notifyDataSetChanged() notifyDataSetChanged()
} }
fun notifyNewGrid(){ fun notifyNewGrid() {
style = context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getInt("offline_view", 0) style =
context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getInt("offline_view", 0)
notifyDataSetChanged() notifyDataSetChanged()
} }
} }

View file

@ -20,6 +20,7 @@ import android.widget.AbsListView
import android.widget.AutoCompleteTextView import android.widget.AutoCompleteTextView
import android.widget.GridView import android.widget.GridView
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.cardview.widget.CardView import androidx.cardview.widget.CardView
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
@ -76,7 +77,8 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
val animeUserAvatar = view.findViewById<ShapeableImageView>(R.id.offlineMangaUserAvatar) val animeUserAvatar = view.findViewById<ShapeableImageView>(R.id.offlineMangaUserAvatar)
animeUserAvatar.setSafeOnClickListener { animeUserAvatar.setSafeOnClickListener {
val dialogFragment = SettingsDialogFragment.newInstance2(SettingsDialogFragment.Companion.PageType2.OfflineMANGA) val dialogFragment =
SettingsDialogFragment.newInstance2(SettingsDialogFragment.Companion.PageType2.OfflineMANGA)
dialogFragment.show((it.context as AppCompatActivity).supportFragmentManager, "dialog") dialogFragment.show((it.context as AppCompatActivity).supportFragmentManager, "dialog")
} }
@ -92,7 +94,7 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
override fun afterTextChanged(s: Editable?) { override fun afterTextChanged(s: Editable?) {
} }
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int, ) { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
} }
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
@ -143,7 +145,8 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
adapter.notifyNewGrid() adapter.notifyNewGrid()
} }
gridView = if(style == 0) view.findViewById(R.id.gridView) else view.findViewById(R.id.gridView1) gridView =
if (style == 0) view.findViewById(R.id.gridView) else view.findViewById(R.id.gridView1)
gridView.visibility = View.VISIBLE gridView.visibility = View.VISIBLE
getDownloads() getDownloads()
@ -173,17 +176,20 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
} }
val total = view.findViewById<TextView>(R.id.total) val total = view.findViewById<TextView>(R.id.total)
total.text = if (gridView.count > 0) "Manga and Novels (${gridView.count})" else "Empty List" total.text =
if (gridView.count > 0) "Manga and Novels (${gridView.count})" else "Empty List"
gridView.setOnItemLongClickListener { parent, view, position, id -> gridView.setOnItemLongClickListener { parent, view, position, id ->
// Get the OfflineMangaModel that was clicked // Get the OfflineMangaModel that was clicked
val item = adapter.getItem(position) as OfflineMangaModel val item = adapter.getItem(position) as OfflineMangaModel
val type: DownloadedType.Type = if (downloadManager.mangaDownloadedTypes.any { it.title == item.title }) { val type: DownloadedType.Type =
DownloadedType.Type.MANGA if (downloadManager.mangaDownloadedTypes.any { it.title == item.title }) {
} else { DownloadedType.Type.MANGA
DownloadedType.Type.NOVEL } else {
} DownloadedType.Type.NOVEL
}
// Alert dialog to confirm deletion // Alert dialog to confirm deletion
val builder = androidx.appcompat.app.AlertDialog.Builder(requireContext(), R.style.MyPopup) val builder =
androidx.appcompat.app.AlertDialog.Builder(requireContext(), R.style.MyPopup)
builder.setTitle("Delete ${item.title}?") builder.setTitle("Delete ${item.title}?")
builder.setMessage("Are you sure you want to delete ${item.title}?") builder.setMessage("Are you sure you want to delete ${item.title}?")
builder.setPositiveButton("Yes") { _, _ -> builder.setPositiveButton("Yes") { _, _ ->
@ -194,7 +200,7 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
builder.setNegativeButton("No") { _, _ -> builder.setNegativeButton("No") { _, _ ->
// Do nothing // Do nothing
} }
val dialog = builder.show() val dialog = builder.show()
dialog.window?.setDimAmount(0.8f) dialog.window?.setDimAmount(0.8f)
true true
} }
@ -253,7 +259,12 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
// Implement behavior for different scroll states if needed // Implement behavior for different scroll states if needed
} }
override fun onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int, totalItemCount: Int) { override fun onScroll(
view: AbsListView,
firstVisibleItem: Int,
visibleItemCount: Int,
totalItemCount: Int
) {
val first = view.getChildAt(0) val first = view.getChildAt(0)
val visibility = first != null && first.top < -height val visibility = first != null && first.top < -height
scrollTop.visibility = if (visibility) View.VISIBLE else View.GONE scrollTop.visibility = if (visibility) View.VISIBLE else View.GONE
@ -365,17 +376,40 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
val title = mediaModel.nameMAL ?: mediaModel.nameRomaji val title = mediaModel.nameMAL ?: mediaModel.nameRomaji
val score = ((if (mediaModel.userScore == 0) (mediaModel.meanScore val score = ((if (mediaModel.userScore == 0) (mediaModel.meanScore
?: 0) else mediaModel.userScore) / 10.0).toString() ?: 0) else mediaModel.userScore) / 10.0).toString()
val isOngoing = mediaModel.status == currActivity()!!.getString(R.string.status_releasing) val isOngoing =
mediaModel.status == currActivity()!!.getString(R.string.status_releasing)
val isUserScored = mediaModel.userScore != 0 val isUserScored = mediaModel.userScore != 0
val readchapter = (mediaModel.userProgress ?: "~").toString() val readchapter = (mediaModel.userProgress ?: "~").toString()
val totalchapter = "${mediaModel.manga?.totalChapters ?: "??"}" val totalchapter = "${mediaModel.manga?.totalChapters ?: "??"}"
val chapters = " Chapters" val chapters = " Chapters"
return OfflineMangaModel(title, score, totalchapter, readchapter, type, chapters, isOngoing, isUserScored, coverUri , bannerUri ) return OfflineMangaModel(
title,
score,
totalchapter,
readchapter,
type,
chapters,
isOngoing,
isUserScored,
coverUri,
bannerUri
)
} catch (e: Exception) { } catch (e: Exception) {
logger("Error loading media.json: ${e.message}") logger("Error loading media.json: ${e.message}")
logger(e.printStackTrace()) logger(e.printStackTrace())
FirebaseCrashlytics.getInstance().recordException(e) FirebaseCrashlytics.getInstance().recordException(e)
return OfflineMangaModel("unknown", "0", "??", "??","movie" ,"hmm", false, false, null , null) return OfflineMangaModel(
"unknown",
"0",
"??",
"??",
"movie",
"hmm",
false,
false,
null,
null
)
} }
} }
} }

View file

@ -6,7 +6,7 @@ data class OfflineMangaModel(
val title: String, val title: String,
val score: String, val score: String,
val totalchapter: String, val totalchapter: String,
val readchapter : String, val readchapter: String,
val type: String, val type: String,
val chapters: String, val chapters: String,
val isOngoing: Boolean, val isOngoing: Boolean,

View file

@ -11,7 +11,8 @@ import androidx.media3.exoplayer.scheduler.Scheduler
import ani.dantotsu.R import ani.dantotsu.R
@UnstableApi @UnstableApi
class ExoplayerDownloadService : DownloadService(1, 2000, "download_service", R.string.downloads, 0) { class ExoplayerDownloadService :
DownloadService(1, 2000, "download_service", R.string.downloads, 0) {
companion object { companion object {
private const val JOB_ID = 1 private const val JOB_ID = 1
private const val FOREGROUND_NOTIFICATION_ID = 1 private const val FOREGROUND_NOTIFICATION_ID = 1

View file

@ -17,7 +17,6 @@ import androidx.core.content.ContextCompat.getString
import androidx.media3.common.C import androidx.media3.common.C
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem
import androidx.media3.common.MimeTypes import androidx.media3.common.MimeTypes
import androidx.media3.common.TrackSelectionParameters
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.database.StandaloneDatabaseProvider import androidx.media3.database.StandaloneDatabaseProvider
import androidx.media3.datasource.DataSource import androidx.media3.datasource.DataSource
@ -31,7 +30,6 @@ import androidx.media3.exoplayer.offline.DownloadHelper
import androidx.media3.exoplayer.offline.DownloadManager import androidx.media3.exoplayer.offline.DownloadManager
import androidx.media3.exoplayer.offline.DownloadService import androidx.media3.exoplayer.offline.DownloadService
import androidx.media3.exoplayer.scheduler.Requirements import androidx.media3.exoplayer.scheduler.Requirements
import androidx.media3.ui.TrackSelectionDialogBuilder
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.defaultHeaders import ani.dantotsu.defaultHeaders
import ani.dantotsu.download.DownloadedType import ani.dantotsu.download.DownloadedType
@ -246,7 +244,7 @@ object Helper {
.queryDownload(title, episode, DownloadedType.Type.ANIME) .queryDownload(title, episode, DownloadedType.Type.ANIME)
if (downloadCheck) { if (downloadCheck) {
AlertDialog.Builder(context , R.style.MyPopup) AlertDialog.Builder(context, R.style.MyPopup)
.setTitle("Download Exists") .setTitle("Download Exists")
.setMessage("A download for this episode already exists. Do you want to overwrite it?") .setMessage("A download for this episode already exists. Do you want to overwrite it?")
.setPositiveButton("Yes") { _, _ -> .setPositiveButton("Yes") { _, _ ->

View file

@ -2,7 +2,6 @@ package ani.dantotsu.home
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
@ -27,7 +26,6 @@ import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.AnilistAnimeViewModel import ani.dantotsu.connections.anilist.AnilistAnimeViewModel
import ani.dantotsu.connections.anilist.SearchResults import ani.dantotsu.connections.anilist.SearchResults
import ani.dantotsu.connections.anilist.getUserId import ani.dantotsu.connections.anilist.getUserId
import ani.dantotsu.currContext
import ani.dantotsu.databinding.FragmentAnimeBinding import ani.dantotsu.databinding.FragmentAnimeBinding
import ani.dantotsu.loadData import ani.dantotsu.loadData
import ani.dantotsu.media.MediaAdaptor import ani.dantotsu.media.MediaAdaptor
@ -52,14 +50,14 @@ class AnimeFragment : Fragment() {
private lateinit var animePageAdapter: AnimePageAdapter private lateinit var animePageAdapter: AnimePageAdapter
private var uiSettings: UserInterfaceSettings = private var uiSettings: UserInterfaceSettings =
loadData("ui_settings") ?: UserInterfaceSettings() loadData("ui_settings") ?: UserInterfaceSettings()
val model: AnilistAnimeViewModel by activityViewModels() val model: AnilistAnimeViewModel by activityViewModels()
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View { ): View {
_binding = FragmentAnimeBinding.inflate(inflater, container, false) _binding = FragmentAnimeBinding.inflate(inflater, container, false)
return binding.root return binding.root
@ -81,11 +79,11 @@ class AnimeFragment : Fragment() {
if (displayCutout != null) { if (displayCutout != null) {
if (displayCutout.boundingRects.size > 0) { if (displayCutout.boundingRects.size > 0) {
height = max( height = max(
statusBarHeight, statusBarHeight,
min( min(
displayCutout.boundingRects[0].width(), displayCutout.boundingRects[0].width(),
displayCutout.boundingRects[0].height() displayCutout.boundingRects[0].height()
) )
) )
} }
} }
@ -104,12 +102,12 @@ class AnimeFragment : Fragment() {
if (model.notSet) { if (model.notSet) {
model.notSet = false model.notSet = false
model.searchResults = SearchResults( model.searchResults = SearchResults(
"ANIME", "ANIME",
isAdult = false, isAdult = false,
onList = false, onList = false,
results = mutableListOf(), results = mutableListOf(),
hasNextPage = true, hasNextPage = true,
sort = Anilist.sortBy[1] sort = Anilist.sortBy[1]
) )
} }
val popularAdaptor = MediaAdaptor(1, model.searchResults.results, requireActivity()) val popularAdaptor = MediaAdaptor(1, model.searchResults.results, requireActivity())
@ -177,7 +175,7 @@ class AnimeFragment : Fragment() {
} }
binding.animePageRecyclerView.addOnScrollListener(object : binding.animePageRecyclerView.addOnScrollListener(object :
RecyclerView.OnScrollListener() { RecyclerView.OnScrollListener() {
override fun onScrolled(v: RecyclerView, dx: Int, dy: Int) { override fun onScrolled(v: RecyclerView, dx: Int, dy: Int) {
if (!v.canScrollVertically(1)) { if (!v.canScrollVertically(1)) {
if (model.searchResults.hasNextPage && model.searchResults.results.isNotEmpty() && !loading) { if (model.searchResults.hasNextPage && model.searchResults.results.isNotEmpty() && !loading) {
@ -217,19 +215,19 @@ class AnimeFragment : Fragment() {
model.getTrending().observe(viewLifecycleOwner) { model.getTrending().observe(viewLifecycleOwner) {
if (it != null) { if (it != null) {
animePageAdapter.updateTrending( animePageAdapter.updateTrending(
MediaAdaptor( MediaAdaptor(
if (uiSettings.smallView) 3 else 2, if (uiSettings.smallView) 3 else 2,
it, it,
requireActivity(), requireActivity(),
viewPager = animePageAdapter.trendingViewPager viewPager = animePageAdapter.trendingViewPager
) )
) )
animePageAdapter.updateAvatar() animePageAdapter.updateAvatar()
} }
} }
} }
binding.animePageScrollTop.translationY = binding.animePageScrollTop.translationY =
-(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat() -(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat()
} }
} }
@ -247,13 +245,13 @@ class AnimeFragment : Fragment() {
animePageAdapter.onSeasonLongClick = { i -> animePageAdapter.onSeasonLongClick = { i ->
val (season, year) = Anilist.currentSeasons[i] val (season, year) = Anilist.currentSeasons[i]
ContextCompat.startActivity( ContextCompat.startActivity(
requireContext(), requireContext(),
Intent(requireContext(), SearchActivity::class.java) Intent(requireContext(), SearchActivity::class.java)
.putExtra("type", "ANIME") .putExtra("type", "ANIME")
.putExtra("season", season) .putExtra("season", season)
.putExtra("seasonYear", year.toString()) .putExtra("seasonYear", year.toString())
.putExtra("search", true), .putExtra("search", true),
null null
) )
true true
} }

View file

@ -152,8 +152,8 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
fun setIncognito() { fun setIncognito() {
val incognito = currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE) val incognito = currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
?.getBoolean("incognito", false) ?: false ?.getBoolean("incognito", false) ?: false
if(incognito) { if (incognito) {
binding.incognitoTextView.visibility = View.VISIBLE binding.incognitoTextView.visibility = View.VISIBLE
if (!uiSettings.immersiveMode) { if (!uiSettings.immersiveMode) {
binding.root.fitsSystemWindows = true binding.root.fitsSystemWindows = true

View file

@ -358,11 +358,13 @@ class HomeFragment : Fragment() {
} }
} }
} }
private fun setIncognito() { private fun setIncognito() {
val incognito = currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE) val incognito = currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
?.getBoolean("incognito", false) ?: false ?.getBoolean("incognito", false) ?: false
if(incognito) { if (incognito) {
val uiSettings = loadData<UserInterfaceSettings>("ui_settings") ?: UserInterfaceSettings() val uiSettings =
loadData<UserInterfaceSettings>("ui_settings") ?: UserInterfaceSettings()
binding.incognitoTextView.visibility = View.VISIBLE binding.incognitoTextView.visibility = View.VISIBLE
if (!uiSettings.immersiveMode) { if (!uiSettings.immersiveMode) {
binding.root.fitsSystemWindows = true binding.root.fitsSystemWindows = true
@ -377,6 +379,7 @@ class HomeFragment : Fragment() {
binding.incognitoTextView.visibility = View.GONE binding.incognitoTextView.visibility = View.GONE
} }
} }
override fun onResume() { override fun onResume() {
if (!model.loaded) Refresh.activity[1]!!.postValue(true) if (!model.loaded) Refresh.activity[1]!!.postValue(true)
setIncognito() setIncognito()

View file

@ -2,7 +2,6 @@ package ani.dantotsu.home
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
@ -25,7 +24,6 @@ import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.AnilistMangaViewModel import ani.dantotsu.connections.anilist.AnilistMangaViewModel
import ani.dantotsu.connections.anilist.SearchResults import ani.dantotsu.connections.anilist.SearchResults
import ani.dantotsu.connections.anilist.getUserId import ani.dantotsu.connections.anilist.getUserId
import ani.dantotsu.currContext
import ani.dantotsu.databinding.FragmentMangaBinding import ani.dantotsu.databinding.FragmentMangaBinding
import ani.dantotsu.loadData import ani.dantotsu.loadData
import ani.dantotsu.media.MediaAdaptor import ani.dantotsu.media.MediaAdaptor
@ -48,14 +46,14 @@ class MangaFragment : Fragment() {
private lateinit var mangaPageAdapter: MangaPageAdapter private lateinit var mangaPageAdapter: MangaPageAdapter
private var uiSettings: UserInterfaceSettings = private var uiSettings: UserInterfaceSettings =
loadData("ui_settings") ?: UserInterfaceSettings() loadData("ui_settings") ?: UserInterfaceSettings()
val model: AnilistMangaViewModel by activityViewModels() val model: AnilistMangaViewModel by activityViewModels()
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View { ): View {
_binding = FragmentMangaBinding.inflate(inflater, container, false) _binding = FragmentMangaBinding.inflate(inflater, container, false)
return binding.root return binding.root
@ -76,11 +74,11 @@ class MangaFragment : Fragment() {
if (displayCutout != null) { if (displayCutout != null) {
if (displayCutout.boundingRects.size > 0) { if (displayCutout.boundingRects.size > 0) {
height = max( height = max(
statusBarHeight, statusBarHeight,
min( min(
displayCutout.boundingRects[0].width(), displayCutout.boundingRects[0].width(),
displayCutout.boundingRects[0].height() displayCutout.boundingRects[0].height()
) )
) )
} }
} }
@ -98,18 +96,18 @@ class MangaFragment : Fragment() {
if (model.notSet) { if (model.notSet) {
model.notSet = false model.notSet = false
model.searchResults = SearchResults( model.searchResults = SearchResults(
"MANGA", "MANGA",
isAdult = false, isAdult = false,
onList = false, onList = false,
results = arrayListOf(), results = arrayListOf(),
hasNextPage = true, hasNextPage = true,
sort = Anilist.sortBy[1] sort = Anilist.sortBy[1]
) )
} }
val popularAdaptor = MediaAdaptor(1, model.searchResults.results, requireActivity()) val popularAdaptor = MediaAdaptor(1, model.searchResults.results, requireActivity())
val progressAdaptor = ProgressAdapter(searched = model.searched) val progressAdaptor = ProgressAdapter(searched = model.searched)
binding.mangaPageRecyclerView.adapter = binding.mangaPageRecyclerView.adapter =
ConcatAdapter(mangaPageAdapter, popularAdaptor, progressAdaptor) ConcatAdapter(mangaPageAdapter, popularAdaptor, progressAdaptor)
val layout = LinearLayoutManager(requireContext()) val layout = LinearLayoutManager(requireContext())
binding.mangaPageRecyclerView.layoutManager = layout binding.mangaPageRecyclerView.layoutManager = layout
@ -135,7 +133,7 @@ class MangaFragment : Fragment() {
} }
binding.mangaPageRecyclerView.addOnScrollListener(object : binding.mangaPageRecyclerView.addOnScrollListener(object :
RecyclerView.OnScrollListener() { RecyclerView.OnScrollListener() {
override fun onScrolled(v: RecyclerView, dx: Int, dy: Int) { override fun onScrolled(v: RecyclerView, dx: Int, dy: Int) {
if (!v.canScrollVertically(1)) { if (!v.canScrollVertically(1)) {
if (model.searchResults.hasNextPage && model.searchResults.results.isNotEmpty() && !loading) { if (model.searchResults.hasNextPage && model.searchResults.results.isNotEmpty() && !loading) {
@ -175,19 +173,19 @@ class MangaFragment : Fragment() {
model.getTrending().observe(viewLifecycleOwner) { model.getTrending().observe(viewLifecycleOwner) {
if (it != null) { if (it != null) {
mangaPageAdapter.updateTrending( mangaPageAdapter.updateTrending(
MediaAdaptor( MediaAdaptor(
if (uiSettings.smallView) 3 else 2, if (uiSettings.smallView) 3 else 2,
it, it,
requireActivity(), requireActivity(),
viewPager = mangaPageAdapter.trendingViewPager viewPager = mangaPageAdapter.trendingViewPager
) )
) )
mangaPageAdapter.updateAvatar() mangaPageAdapter.updateAvatar()
} }
} }
} }
binding.mangaPageScrollTop.translationY = binding.mangaPageScrollTop.translationY =
-(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat() -(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat()
} }
} }

View file

@ -144,8 +144,8 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
fun setIncognito() { fun setIncognito() {
val incognito = currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE) val incognito = currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
?.getBoolean("incognito", false) ?: false ?.getBoolean("incognito", false) ?: false
if(incognito) { if (incognito) {
binding.incognitoTextView.visibility = View.VISIBLE binding.incognitoTextView.visibility = View.VISIBLE
if (!uiSettings.immersiveMode) { if (!uiSettings.immersiveMode) {
binding.root.fitsSystemWindows = true binding.root.fitsSystemWindows = true

View file

@ -318,8 +318,7 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
) )
if (media.format == "NOVEL") { if (media.format == "NOVEL") {
tabLayout.inflateMenu(R.menu.novel_menu_detail) tabLayout.inflateMenu(R.menu.novel_menu_detail)
} } else {
else {
tabLayout.inflateMenu(R.menu.manga_menu_detail) tabLayout.inflateMenu(R.menu.manga_menu_detail)
} }
anime = false anime = false
@ -365,6 +364,7 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
R.id.info -> { R.id.info -> {
selected = 0 selected = 0
} }
R.id.watch, R.id.read -> { R.id.watch, R.id.read -> {
selected = 1 selected = 1
} }

View file

@ -29,8 +29,8 @@ class SubtitleDownloader {
val subtitleType = when { val subtitleType = when {
responseBody?.contains("[Script Info]") == true -> SubtitleType.ASS responseBody.contains("[Script Info]") == true -> SubtitleType.ASS
responseBody?.contains("WEBVTT") == true -> SubtitleType.VTT responseBody.contains("WEBVTT") == true -> SubtitleType.VTT
else -> SubtitleType.SRT else -> SubtitleType.SRT
} }

View file

@ -5,7 +5,8 @@ import java.util.regex.Pattern
class AnimeNameAdapter { class AnimeNameAdapter {
companion object { companion object {
const val episodeRegex = "(episode|ep|e)[\\s:.\\-]*([\\d]+\\.?[\\d]*)[\\s:.\\-]*\\(?\\s*(sub|subbed|dub|dubbed)*\\s*\\)?\\s*" const val episodeRegex =
"(episode|ep|e)[\\s:.\\-]*([\\d]+\\.?[\\d]*)[\\s:.\\-]*\\(?\\s*(sub|subbed|dub|dubbed)*\\s*\\)?\\s*"
const val seasonRegex = "(season|s)[\\s:.\\-]*(\\d+)[\\s:.\\-]*" const val seasonRegex = "(season|s)[\\s:.\\-]*(\\d+)[\\s:.\\-]*"
fun findSeasonNumber(text: String): Int? { fun findSeasonNumber(text: String): Int? {

View file

@ -14,10 +14,9 @@ import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import ani.dantotsu.* import ani.dantotsu.*
import ani.dantotsu.databinding.DialogLayoutBinding
import ani.dantotsu.databinding.ItemAnimeWatchBinding import ani.dantotsu.databinding.ItemAnimeWatchBinding
import ani.dantotsu.databinding.ItemChipBinding import ani.dantotsu.databinding.ItemChipBinding
import ani.dantotsu.databinding.DialogLayoutBinding
import ani.dantotsu.media.anime.AnimeNameAdapter
import ani.dantotsu.media.Media import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsActivity import ani.dantotsu.media.MediaDetailsActivity
import ani.dantotsu.media.SourceSearchDialogFragment import ani.dantotsu.media.SourceSearchDialogFragment
@ -45,6 +44,7 @@ class AnimeWatchAdapter(
val bind = ItemAnimeWatchBinding.inflate(LayoutInflater.from(parent.context), parent, false) val bind = ItemAnimeWatchBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(bind) return ViewHolder(bind)
} }
private var nestedDialog: AlertDialog? = null private var nestedDialog: AlertDialog? = null
@ -234,11 +234,11 @@ class AnimeWatchAdapter(
dialogBinding.animeScanlatorContainer.visibility = View.GONE dialogBinding.animeScanlatorContainer.visibility = View.GONE
dialogBinding.animeDownloadContainer.visibility = View.GONE dialogBinding.animeDownloadContainer.visibility = View.GONE
nestedDialog = AlertDialog.Builder(fragment.requireContext() , R.style.MyPopup) nestedDialog = AlertDialog.Builder(fragment.requireContext(), R.style.MyPopup)
.setTitle("Options") .setTitle("Options")
.setView(dialogView) .setView(dialogView)
.setPositiveButton("OK") { _, _ -> .setPositiveButton("OK") { _, _ ->
if (run) fragment.onIconPressed(style, reversed) if (run) fragment.onIconPressed(style, reversed)
} }
.setNegativeButton("Cancel") { _, _ -> .setNegativeButton("Cancel") { _, _ ->
} }
@ -311,74 +311,74 @@ class AnimeWatchAdapter(
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
fun handleEpisodes() { fun handleEpisodes() {
val binding = _binding val binding = _binding
if (binding != null) { if (binding != null) {
if (media.anime?.episodes != null) { if (media.anime?.episodes != null) {
val episodes = media.anime.episodes!!.keys.toTypedArray() val episodes = media.anime.episodes!!.keys.toTypedArray()
val anilistEp = (media.userProgress ?: 0).plus(1) val anilistEp = (media.userProgress ?: 0).plus(1)
val appEp = loadData<String>("${media.id}_current_ep")?.toIntOrNull() ?: 1 val appEp = loadData<String>("${media.id}_current_ep")?.toIntOrNull() ?: 1
var continueEp = (if (anilistEp > appEp) anilistEp else appEp).toString() var continueEp = (if (anilistEp > appEp) anilistEp else appEp).toString()
if (episodes.contains(continueEp)) { if (episodes.contains(continueEp)) {
binding.animeSourceContinue.visibility = View.VISIBLE binding.animeSourceContinue.visibility = View.VISIBLE
handleProgress( handleProgress(
binding.itemEpisodeProgressCont, binding.itemEpisodeProgressCont,
binding.itemEpisodeProgress, binding.itemEpisodeProgress,
binding.itemEpisodeProgressEmpty, binding.itemEpisodeProgressEmpty,
media.id, media.id,
continueEp continueEp
) )
if ((binding.itemEpisodeProgress.layoutParams as LinearLayout.LayoutParams).weight > fragment.playerSettings.watchPercentage) { if ((binding.itemEpisodeProgress.layoutParams as LinearLayout.LayoutParams).weight > fragment.playerSettings.watchPercentage) {
val e = episodes.indexOf(continueEp) val e = episodes.indexOf(continueEp)
if (e != -1 && e + 1 < episodes.size) { if (e != -1 && e + 1 < episodes.size) {
continueEp = episodes[e + 1] continueEp = episodes[e + 1]
handleProgress( handleProgress(
binding.itemEpisodeProgressCont, binding.itemEpisodeProgressCont,
binding.itemEpisodeProgress, binding.itemEpisodeProgress,
binding.itemEpisodeProgressEmpty, binding.itemEpisodeProgressEmpty,
media.id, media.id,
continueEp continueEp
) )
}
} }
} val ep = media.anime.episodes!![continueEp]!!
val ep = media.anime.episodes!![continueEp]!!
val cleanedTitle = ep.title?.let { AnimeNameAdapter.removeEpisodeNumber(it) } val cleanedTitle = ep.title?.let { AnimeNameAdapter.removeEpisodeNumber(it) }
binding.itemEpisodeImage.loadImage( binding.itemEpisodeImage.loadImage(
ep.thumb ?: FileUrl[media.banner ?: media.cover], 0 ep.thumb ?: FileUrl[media.banner ?: media.cover], 0
) )
if (ep.filler) binding.itemEpisodeFillerView.visibility = View.VISIBLE if (ep.filler) binding.itemEpisodeFillerView.visibility = View.VISIBLE
binding.animeSourceContinueText.text = binding.animeSourceContinueText.text =
currActivity()!!.getString(R.string.continue_episode) + "${ep.number}${if (ep.filler) " - Filler" else ""}${"\n$cleanedTitle"}" currActivity()!!.getString(R.string.continue_episode) + "${ep.number}${if (ep.filler) " - Filler" else ""}${"\n$cleanedTitle"}"
binding.animeSourceContinue.setOnClickListener { binding.animeSourceContinue.setOnClickListener {
fragment.onEpisodeClick(continueEp) fragment.onEpisodeClick(continueEp)
}
if (fragment.continueEp) {
if ((binding.itemEpisodeProgress.layoutParams as LinearLayout.LayoutParams).weight < fragment.playerSettings.watchPercentage) {
binding.animeSourceContinue.performClick()
fragment.continueEp = false
} }
if (fragment.continueEp) {
if ((binding.itemEpisodeProgress.layoutParams as LinearLayout.LayoutParams).weight < fragment.playerSettings.watchPercentage) {
binding.animeSourceContinue.performClick()
fragment.continueEp = false
}
}
} else {
binding.animeSourceContinue.visibility = View.GONE
} }
binding.animeSourceProgressBar.visibility = View.GONE
if (media.anime.episodes!!.isNotEmpty())
binding.animeSourceNotFound.visibility = View.GONE
else
binding.animeSourceNotFound.visibility = View.VISIBLE
} else { } else {
binding.animeSourceContinue.visibility = View.GONE binding.animeSourceContinue.visibility = View.GONE
}
binding.animeSourceProgressBar.visibility = View.GONE
if (media.anime.episodes!!.isNotEmpty())
binding.animeSourceNotFound.visibility = View.GONE binding.animeSourceNotFound.visibility = View.GONE
else clearChips()
binding.animeSourceNotFound.visibility = View.VISIBLE binding.animeSourceProgressBar.visibility = View.VISIBLE
} else { }
binding.animeSourceContinue.visibility = View.GONE
binding.animeSourceNotFound.visibility = View.GONE
clearChips()
binding.animeSourceProgressBar.visibility = View.VISIBLE
} }
} }
}
private fun setLanguageList(lang: Int, source: Int) { private fun setLanguageList(lang: Int, source: Int) {
val binding = _binding val binding = _binding
@ -401,7 +401,8 @@ fun handleEpisodes() {
parser.extension.sources.map { LanguageMapper.mapLanguageCodeToName(it.lang) } parser.extension.sources.map { LanguageMapper.mapLanguageCodeToName(it.lang) }
) )
val items = adapter.count val items = adapter.count
if (items > 1) binding?.animeSourceLanguageContainer?.visibility = View.VISIBLE else binding?.animeSourceLanguageContainer?.visibility = View.GONE if (items > 1) binding?.animeSourceLanguageContainer?.visibility =
View.VISIBLE else binding?.animeSourceLanguageContainer?.visibility = View.GONE
binding?.animeSourceLanguage?.setAdapter(adapter) binding?.animeSourceLanguage?.setAdapter(adapter)

View file

@ -320,9 +320,10 @@ class AnimeWatchFragment : Fragment() {
if (allSettings.isNotEmpty()) { if (allSettings.isNotEmpty()) {
var selectedSetting = allSettings[0] var selectedSetting = allSettings[0]
if (allSettings.size > 1) { if (allSettings.size > 1) {
val names = allSettings.map { LanguageMapper.mapLanguageCodeToName(it.lang) }.toTypedArray() val names =
allSettings.map { LanguageMapper.mapLanguageCodeToName(it.lang) }.toTypedArray()
var selectedIndex = 0 var selectedIndex = 0
val dialog = AlertDialog.Builder(requireContext() , R.style.MyPopup) val dialog = AlertDialog.Builder(requireContext(), R.style.MyPopup)
.setTitle("Select a Source") .setTitle("Select a Source")
.setSingleChoiceItems(names, selectedIndex) { dialog, which -> .setSingleChoiceItems(names, selectedIndex) { dialog, which ->
selectedIndex = which selectedIndex = which

View file

@ -26,18 +26,18 @@ class CustomCastThemeFactory : MediaRouteDialogFactory() {
} }
} }
class CustomMediaRouterChooserDialogFragment: MediaRouteChooserDialogFragment() { class CustomMediaRouterChooserDialogFragment : MediaRouteChooserDialogFragment() {
override fun onCreateChooserDialog( override fun onCreateChooserDialog(
context: Context, context: Context,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): MediaRouteChooserDialog = ): MediaRouteChooserDialog =
MediaRouteChooserDialog(context, R.style.MyPopup) MediaRouteChooserDialog(context, R.style.MyPopup)
} }
class CustomMediaRouteControllerDialogFragment: MediaRouteControllerDialogFragment() { class CustomMediaRouteControllerDialogFragment : MediaRouteControllerDialogFragment() {
override fun onCreateControllerDialog( override fun onCreateControllerDialog(
context: Context, context: Context,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): MediaRouteControllerDialog = ): MediaRouteControllerDialog =
MediaRouteControllerDialog(context, R.style.MyPopup) MediaRouteControllerDialog(context, R.style.MyPopup)
} }

View file

@ -11,7 +11,6 @@ import ani.dantotsu.connections.updateProgress
import ani.dantotsu.databinding.ItemEpisodeCompactBinding import ani.dantotsu.databinding.ItemEpisodeCompactBinding
import ani.dantotsu.databinding.ItemEpisodeGridBinding import ani.dantotsu.databinding.ItemEpisodeGridBinding
import ani.dantotsu.databinding.ItemEpisodeListBinding import ani.dantotsu.databinding.ItemEpisodeListBinding
import ani.dantotsu.media.anime.AnimeNameAdapter
import ani.dantotsu.media.Media import ani.dantotsu.media.Media
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.load.model.GlideUrl
@ -77,11 +76,11 @@ class EpisodeAdapter(
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val ep = arr[position] val ep = arr[position]
val title = if (!ep.title.isNullOrEmpty() && ep.title != "null") { val title = if (!ep.title.isNullOrEmpty() && ep.title != "null") {
ep.title?.let { AnimeNameAdapter.removeEpisodeNumber(it) } ep.title?.let { AnimeNameAdapter.removeEpisodeNumber(it) }
} else { } else {
ep.number ep.number
} ?: "" } ?: ""
when (holder) { when (holder) {
is EpisodeListViewHolder -> { is EpisodeListViewHolder -> {

View file

@ -339,7 +339,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
setContentView(binding.root) setContentView(binding.root)
//Initialize //Initialize
isCastApiAvailable = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS isCastApiAvailable = GoogleApiAvailability.getInstance()
.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS
try { try {
castContext = CastContext.getSharedInstance(this) castContext = CastContext.getSharedInstance(this)
castPlayer = CastPlayer(castContext!!) castPlayer = CastPlayer(castContext!!)

View file

@ -23,7 +23,6 @@ import ani.dantotsu.databinding.ItemUrlBinding
import ani.dantotsu.download.video.Helper import ani.dantotsu.download.video.Helper
import ani.dantotsu.media.Media import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsViewModel import ani.dantotsu.media.MediaDetailsViewModel
import ani.dantotsu.others.Download.download
import ani.dantotsu.parsers.VideoExtractor import ani.dantotsu.parsers.VideoExtractor
import ani.dantotsu.parsers.VideoType import ani.dantotsu.parsers.VideoType
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -275,7 +274,8 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
// media!!.userPreferredName // media!!.userPreferredName
//) //)
val episode = media!!.anime!!.episodes!![media!!.anime!!.selectedEpisode!!]!! val episode = media!!.anime!!.episodes!![media!!.anime!!.selectedEpisode!!]!!
val video = if (extractor.videos.size > episode.selectedVideo) extractor.videos[episode.selectedVideo] else null val video =
if (extractor.videos.size > episode.selectedVideo) extractor.videos[episode.selectedVideo] else null
if (video != null) { if (video != null) {
Helper.startAnimeDownloadService( Helper.startAnimeDownloadService(
requireActivity(), requireActivity(),
@ -284,7 +284,7 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
video, video,
null, null,
media, media,
episode.thumb?.url?: media!!.banner?: media!!.cover episode.thumb?.url ?: media!!.banner ?: media!!.cover
) )
} }
dismiss() dismiss()

View file

@ -48,7 +48,9 @@ class MangaReadAdapter(
val bind = ItemAnimeWatchBinding.inflate(LayoutInflater.from(parent.context), parent, false) val bind = ItemAnimeWatchBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(bind) return ViewHolder(bind)
} }
private var nestedDialog: AlertDialog? = null private var nestedDialog: AlertDialog? = null
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val binding = holder.binding val binding = holder.binding
@ -211,7 +213,8 @@ class MangaReadAdapter(
dialogBinding.animeScanlatorTop.setOnClickListener { dialogBinding.animeScanlatorTop.setOnClickListener {
val dialogView2 = val dialogView2 =
LayoutInflater.from(currContext()).inflate(R.layout.custom_dialog_layout, null) LayoutInflater.from(currContext()).inflate(R.layout.custom_dialog_layout, null)
val checkboxContainer = dialogView2.findViewById<LinearLayout>(R.id.checkboxContainer) val checkboxContainer =
dialogView2.findViewById<LinearLayout>(R.id.checkboxContainer)
// Dynamically add checkboxes // Dynamically add checkboxes
options.forEach { option -> options.forEach { option ->
@ -248,12 +251,12 @@ class MangaReadAdapter(
dialog.window?.setDimAmount(0.8f) dialog.window?.setDimAmount(0.8f)
} }
nestedDialog = AlertDialog.Builder(fragment.requireContext() , R.style.MyPopup) nestedDialog = AlertDialog.Builder(fragment.requireContext(), R.style.MyPopup)
.setTitle("Options") .setTitle("Options")
.setView(dialogView) .setView(dialogView)
.setPositiveButton("OK") { _, _ -> .setPositiveButton("OK") { _, _ ->
if(run) fragment.onIconPressed(style, reversed) if (run) fragment.onIconPressed(style, reversed)
if (dialogBinding.downloadNo.text != "0"){ if (dialogBinding.downloadNo.text != "0") {
fragment.multiDownload(dialogBinding.downloadNo.text.toString().toInt()) fragment.multiDownload(dialogBinding.downloadNo.text.toString().toInt())
} }
} }
@ -293,6 +296,7 @@ class MangaReadAdapter(
0 0
) )
} }
val startChapter = MangaNameAdapter.findChapterNumber(names[limit * (position)]) val startChapter = MangaNameAdapter.findChapterNumber(names[limit * (position)])
val endChapter = MangaNameAdapter.findChapterNumber(names[last - 1]) val endChapter = MangaNameAdapter.findChapterNumber(names[last - 1])
val startChapterString = if (startChapter != null) { val startChapterString = if (startChapter != null) {
@ -425,7 +429,8 @@ class MangaReadAdapter(
parser.extension.sources.map { LanguageMapper.mapLanguageCodeToName(it.lang) } parser.extension.sources.map { LanguageMapper.mapLanguageCodeToName(it.lang) }
) )
val items = adapter.count val items = adapter.count
if (items > 1) binding?.animeSourceLanguageContainer?.visibility = View.VISIBLE else binding?.animeSourceLanguageContainer?.visibility = View.GONE if (items > 1) binding?.animeSourceLanguageContainer?.visibility =
View.VISIBLE else binding?.animeSourceLanguageContainer?.visibility = View.GONE
binding?.animeSourceLanguage?.setAdapter(adapter) binding?.animeSourceLanguage?.setAdapter(adapter)

View file

@ -197,12 +197,15 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
override fun onScanlatorsSelected() { override fun onScanlatorsSelected() {
updateChapters() updateChapters()
} }
fun multiDownload(n: Int) { fun multiDownload(n: Int) {
//get last viewed chapter //get last viewed chapter
val selected = media.userProgress val selected = media.userProgress
val chapters = media.manga?.chapters?.values?.toList() val chapters = media.manga?.chapters?.values?.toList()
//filter by selected language //filter by selected language
val progressChapterIndex = (chapters?.indexOfFirst { MangaNameAdapter.findChapterNumber(it.number)?.toInt() == selected } ?: 0) + 1 val progressChapterIndex = (chapters?.indexOfFirst {
MangaNameAdapter.findChapterNumber(it.number)?.toInt() == selected
} ?: 0) + 1
if (progressChapterIndex < 0 || n < 1 || chapters == null) return if (progressChapterIndex < 0 || n < 1 || chapters == null) return
@ -363,7 +366,8 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
if (allSettings.isNotEmpty()) { if (allSettings.isNotEmpty()) {
var selectedSetting = allSettings[0] var selectedSetting = allSettings[0]
if (allSettings.size > 1) { if (allSettings.size > 1) {
val names = allSettings.map { LanguageMapper.mapLanguageCodeToName(it.lang) }.toTypedArray() val names =
allSettings.map { LanguageMapper.mapLanguageCodeToName(it.lang) }.toTypedArray()
var selectedIndex = 0 var selectedIndex = 0
val dialog = AlertDialog.Builder(requireContext(), R.style.MyPopup) val dialog = AlertDialog.Builder(requireContext(), R.style.MyPopup)
.setTitle("Select a Source") .setTitle("Select a Source")

View file

@ -89,7 +89,8 @@ abstract class BaseImageAdapter(
} }
} else { } else {
val detector = GestureDetectorCompat(view.context, object : GesturesListener() { val detector = GestureDetectorCompat(view.context, object : GesturesListener() {
override fun onSingleClick(event: MotionEvent) = activity.handleController(event = event) override fun onSingleClick(event: MotionEvent) =
activity.handleController(event = event)
}) })
view.findViewById<View>(R.id.imgProgCover).apply { view.findViewById<View>(R.id.imgProgCover).apply {
setOnTouchListener { _, event -> setOnTouchListener { _, event ->

View file

@ -93,12 +93,14 @@ open class ImageAdapter(
override fun getItemCount(): Int = images.size override fun getItemCount(): Int = images.size
override fun isZoomed(): Boolean { override fun isZoomed(): Boolean {
val imageView = activity.findViewById<SubsamplingScaleImageView>(R.id.imgProgImageNoGestures) val imageView =
activity.findViewById<SubsamplingScaleImageView>(R.id.imgProgImageNoGestures)
return imageView.scale > imageView.minScale return imageView.scale > imageView.minScale
} }
override fun setZoom(zoom: Float) { override fun setZoom(zoom: Float) {
val imageView = activity.findViewById<SubsamplingScaleImageView>(R.id.imgProgImageNoGestures) val imageView =
activity.findViewById<SubsamplingScaleImageView>(R.id.imgProgImageNoGestures)
imageView.setScaleAndCenter(zoom, imageView.center) imageView.setScaleAndCenter(zoom, imageView.center)
} }
} }

View file

@ -255,7 +255,8 @@ class MangaReaderActivity : AppCompatActivity() {
} }
showProgressDialog = showProgressDialog =
if (settings.askIndividual) loadData<Boolean>("${media.id}_progressDialog")?: true else false if (settings.askIndividual) loadData<Boolean>("${media.id}_progressDialog")
?: true else false
//Chapter Change //Chapter Change
fun change(index: Int) { fun change(index: Int) {
@ -850,7 +851,8 @@ class MangaReaderActivity : AppCompatActivity() {
private fun progress(runnable: Runnable) { private fun progress(runnable: Runnable) {
if (maxChapterPage - currentChapterPage <= 1 && Anilist.userid != null) { if (maxChapterPage - currentChapterPage <= 1 && Anilist.userid != null) {
showProgressDialog = showProgressDialog =
if (settings.askIndividual) loadData<Boolean>("${media.id}_progressDialog")?: true else false if (settings.askIndividual) loadData<Boolean>("${media.id}_progressDialog")
?: true else false
if (showProgressDialog) { if (showProgressDialog) {
val dialogView = layoutInflater.inflate(R.layout.item_custom_dialog, null) val dialogView = layoutInflater.inflate(R.layout.item_custom_dialog, null)

View file

@ -42,7 +42,11 @@ class NovelResponseAdapter(
.into(binding.itemEpisodeImage) .into(binding.itemEpisodeImage)
val typedValue = TypedValue() val typedValue = TypedValue()
fragment.requireContext().theme?.resolveAttribute(com.google.android.material.R.attr.colorOnBackground, typedValue, true) fragment.requireContext().theme?.resolveAttribute(
com.google.android.material.R.attr.colorOnBackground,
typedValue,
true
)
val color = typedValue.data val color = typedValue.data
binding.itemEpisodeTitle.text = novel.name binding.itemEpisodeTitle.text = novel.name
@ -98,14 +102,19 @@ class NovelResponseAdapter(
} }
binding.root.setOnLongClickListener { binding.root.setOnLongClickListener {
val builder = androidx.appcompat.app.AlertDialog.Builder(fragment.requireContext(), R.style.DialogTheme) val builder = androidx.appcompat.app.AlertDialog.Builder(
fragment.requireContext(),
R.style.DialogTheme
)
builder.setTitle("Delete ${novel.name}?") builder.setTitle("Delete ${novel.name}?")
builder.setMessage("Are you sure you want to delete ${novel.name}?") builder.setMessage("Are you sure you want to delete ${novel.name}?")
builder.setPositiveButton("Yes") { _, _ -> builder.setPositiveButton("Yes") { _, _ ->
downloadedCheckCallback.deleteDownload(novel) downloadedCheckCallback.deleteDownload(novel)
deleteDownload(novel.link) deleteDownload(novel.link)
snackString("Deleted ${novel.name}") snackString("Deleted ${novel.name}")
if (binding.itemEpisodeFiller.text.toString().contains("Download", ignoreCase = true)) { if (binding.itemEpisodeFiller.text.toString()
.contains("Download", ignoreCase = true)
) {
binding.itemEpisodeFiller.text = "" binding.itemEpisodeFiller.text = ""
} }
} }

View file

@ -148,7 +148,8 @@ class NovelReaderActivity : AppCompatActivity(), EbookReaderEventListener {
Toast.makeText(this, "Please update WebView from PlayStore", Toast.LENGTH_LONG).show() Toast.makeText(this, "Please update WebView from PlayStore", Toast.LENGTH_LONG).show()
//open playstore //open playstore
val intent = Intent(Intent.ACTION_VIEW) val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("https://play.google.com/store/apps/details?id=com.google.android.webview") intent.data =
Uri.parse("https://play.google.com/store/apps/details?id=com.google.android.webview")
startActivity(intent) startActivity(intent)
//stop reader //stop reader
finish() finish()
@ -270,7 +271,8 @@ class NovelReaderActivity : AppCompatActivity(), EbookReaderEventListener {
binding.bookReader.getAppearance { binding.bookReader.getAppearance {
currentTheme = it currentTheme = it
themes.add(0, it) themes.add(0, it)
settings.defaultLN = loadData("${sanitizedBookId}_current_settings") ?: settings.defaultLN settings.defaultLN =
loadData("${sanitizedBookId}_current_settings") ?: settings.defaultLN
applySettings() applySettings()
} }
@ -351,7 +353,7 @@ class NovelReaderActivity : AppCompatActivity(), EbookReaderEventListener {
saveData("${sanitizedBookId}_current_settings", settings.defaultLN) saveData("${sanitizedBookId}_current_settings", settings.defaultLN)
hideBars() hideBars()
if(settings.defaultLN.useOledTheme) { if (settings.defaultLN.useOledTheme) {
themes.forEach { theme -> themes.forEach { theme ->
theme.darkBg = Color.parseColor("#000000") theme.darkBg = Color.parseColor("#000000")
} }

View file

@ -22,7 +22,6 @@ import ani.dantotsu.databinding.ActivityListBinding
import ani.dantotsu.loadData import ani.dantotsu.loadData
import ani.dantotsu.navBarHeight import ani.dantotsu.navBarHeight
import ani.dantotsu.others.LangSet import ani.dantotsu.others.LangSet
import ani.dantotsu.saveData
import ani.dantotsu.settings.UserInterfaceSettings import ani.dantotsu.settings.UserInterfaceSettings
import ani.dantotsu.statusBarHeight import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager import ani.dantotsu.themes.ThemeManager

View file

@ -7,10 +7,10 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import ani.dantotsu.databinding.FragmentOfflineBinding
import ani.dantotsu.isOnline
import ani.dantotsu.App import ani.dantotsu.App
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.databinding.FragmentOfflineBinding
import ani.dantotsu.isOnline
import ani.dantotsu.navBarHeight import ani.dantotsu.navBarHeight
import ani.dantotsu.startMainActivity import ani.dantotsu.startMainActivity
import ani.dantotsu.statusBarHeight import ani.dantotsu.statusBarHeight
@ -26,8 +26,10 @@ class OfflineFragment : Fragment() {
topMargin = statusBarHeight topMargin = statusBarHeight
bottomMargin = navBarHeight bottomMargin = navBarHeight
} }
val offline = App.context?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)?.getBoolean("offlineMode", false) ?: false val offline = App.context?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
binding.noInternet.text = if (!isOnline(requireContext())) getString(R.string.no_internet) else "OFFLINE MODE" ?.getBoolean("offlineMode", false) ?: false
binding.noInternet.text =
if (!isOnline(requireContext())) getString(R.string.no_internet) else "OFFLINE MODE"
binding.refreshButton.setOnClickListener { binding.refreshButton.setOnClickListener {
if (!isOnline(requireContext()) && offline) { if (!isOnline(requireContext()) && offline) {
startMainActivity(requireActivity()) startMainActivity(requireActivity())

View file

@ -17,7 +17,6 @@ import ani.dantotsu.media.anime.AnimeNameAdapter
import ani.dantotsu.media.manga.ImageData import ani.dantotsu.media.manga.ImageData
import ani.dantotsu.media.manga.MangaCache import ani.dantotsu.media.manga.MangaCache
import ani.dantotsu.snackString import ani.dantotsu.snackString
import com.google.firebase.crashlytics.FirebaseCrashlytics
import eu.kanade.tachiyomi.animesource.AnimeCatalogueSource import eu.kanade.tachiyomi.animesource.AnimeCatalogueSource
import eu.kanade.tachiyomi.animesource.model.AnimesPage import eu.kanade.tachiyomi.animesource.model.AnimesPage
import eu.kanade.tachiyomi.animesource.model.SAnime import eu.kanade.tachiyomi.animesource.model.SAnime
@ -317,6 +316,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
} }
return ret return ret
} }
suspend fun imageList(chapterLink: String, sChapter: SChapter): List<ImageData> { suspend fun imageList(chapterLink: String, sChapter: SChapter): List<ImageData> {
val source = try { val source = try {
extension.sources[sourceLanguage] extension.sources[sourceLanguage]
@ -329,7 +329,8 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
try { try {
println("source.name " + source.name) println("source.name " + source.name)
val res = source.getPageList(sChapter) val res = source.getPageList(sChapter)
val reIndexedPages = res.mapIndexed { index, page -> Page(index, page.url, page.imageUrl, page.uri) } val reIndexedPages =
res.mapIndexed { index, page -> Page(index, page.url, page.imageUrl, page.uri) }
val semaphore = Semaphore(5) val semaphore = Semaphore(5)
val deferreds = reIndexedPages.map { page -> val deferreds = reIndexedPages.map { page ->
@ -367,7 +368,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
// Convert InputStream to Bitmap // Convert InputStream to Bitmap
val bitmap = BitmapFactory.decodeStream(inputStream) val bitmap = BitmapFactory.decodeStream(inputStream)
inputStream?.close() inputStream.close()
ani.dantotsu.media.manga.saveImage( ani.dantotsu.media.manga.saveImage(
bitmap, bitmap,
context.contentResolver, context.contentResolver,
@ -409,7 +410,7 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() {
) )
} }
inputStream?.close() inputStream.close()
} catch (e: Exception) { } catch (e: Exception) {
// Handle any exceptions // Handle any exceptions
println("An error occurred: ${e.message}") println("An error occurred: ${e.message}")
@ -628,7 +629,7 @@ class VideoServerPassthrough(val videoServer: VideoServer) : VideoExtractor() {
if (format == null) { if (format == null) {
logger("Unknown video format: $videoUrl") logger("Unknown video format: $videoUrl")
//FirebaseCrashlytics.getInstance() //FirebaseCrashlytics.getInstance()
// .recordException(Exception("Unknown video format: $videoUrl")) // .recordException(Exception("Unknown video format: $videoUrl"))
format = VideoType.CONTAINER format = VideoType.CONTAINER
} }
val headersMap: Map<String, String> = val headersMap: Map<String, String> =
@ -706,7 +707,7 @@ class VideoServerPassthrough(val videoServer: VideoServer) : VideoExtractor() {
return Subtitle(track.lang, track.url, type ?: SubtitleType.SRT) return Subtitle(track.lang, track.url, type ?: SubtitleType.SRT)
} }
private fun findSubtitleType(url: String): SubtitleType? { private fun findSubtitleType(url: String): SubtitleType {
// First, try to determine the type based on the URL file extension // First, try to determine the type based on the URL file extension
val type: SubtitleType = when { val type: SubtitleType = when {
url.endsWith(".vtt", true) -> SubtitleType.VTT url.endsWith(".vtt", true) -> SubtitleType.VTT

View file

@ -34,7 +34,7 @@ abstract class NovelParser : BaseParser() {
//val query = mediaObj.name ?: mediaObj.nameRomaji //val query = mediaObj.name ?: mediaObj.nameRomaji
//return search(query).sortByVolume(query) //return search(query).sortByVolume(query)
val results: List<ShowResponse> val results: List<ShowResponse>
return if(mediaObj.name != null) { return if (mediaObj.name != null) {
val query = mediaObj.name val query = mediaObj.name
results = search(query).sortByVolume(query) results = search(query).sortByVolume(query)
results.ifEmpty { results.ifEmpty {

View file

@ -3,7 +3,6 @@ package ani.dantotsu.parsers
import android.os.Environment import android.os.Environment
import ani.dantotsu.currContext import ani.dantotsu.currContext
import ani.dantotsu.download.DownloadsManager import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.logger
import ani.dantotsu.media.anime.AnimeNameAdapter import ani.dantotsu.media.anime.AnimeNameAdapter
import eu.kanade.tachiyomi.animesource.model.SAnime import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode import eu.kanade.tachiyomi.animesource.model.SEpisode

View file

@ -9,7 +9,7 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.File import java.io.File
class OfflineNovelParser: NovelParser() { class OfflineNovelParser : NovelParser() {
private val downloadManager = Injekt.get<DownloadsManager>() private val downloadManager = Injekt.get<DownloadsManager>()
override val hostUrl: String = "Offline" override val hostUrl: String = "Offline"
@ -31,7 +31,7 @@ class OfflineNovelParser: NovelParser() {
if (it.isDirectory) { if (it.isDirectory) {
val chapter = Book( val chapter = Book(
it.name, it.name,
it.absolutePath + "/cover.jpg", it.absolutePath + "/cover.jpg",
null, null,
listOf(it.absolutePath + "/0.epub") listOf(it.absolutePath + "/0.epub")
) )
@ -72,7 +72,8 @@ class OfflineNovelParser: NovelParser() {
} }
} }
} }
val cover = currContext()?.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.absolutePath + "/Dantotsu/Novel/$title/cover.jpg" val cover =
currContext()?.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.absolutePath + "/Dantotsu/Novel/$title/cover.jpg"
names.forEach { names.forEach {
returnList.add(ShowResponse(it, it, cover)) returnList.add(ShowResponse(it, it, cover))
} }

View file

@ -111,11 +111,12 @@ internal object NovelExtensionLoader {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
private fun getSignatureHash(pkgInfo: PackageInfo): List<String>? { private fun getSignatureHash(pkgInfo: PackageInfo): List<String>? {
val signatures = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && pkgInfo.signingInfo != null) { val signatures =
pkgInfo.signingInfo.apkContentsSigners if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && pkgInfo.signingInfo != null) {
} else { pkgInfo.signingInfo.apkContentsSigners
pkgInfo.signatures } else {
} pkgInfo.signatures
}
return if (!signatures.isNullOrEmpty()) { return if (!signatures.isNullOrEmpty()) {
signatures.map { Hash.sha256(it.toByteArray()) } signatures.map { Hash.sha256(it.toByteArray()) }
} else { } else {

View file

@ -9,9 +9,7 @@ import android.text.TextWatcher
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.AutoCompleteTextView import android.widget.AutoCompleteTextView
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
@ -117,17 +115,17 @@ class ExtensionsActivity : AppCompatActivity() {
initActivity(this) initActivity(this)
binding.languageselect.visibility = View.GONE binding.languageselect.visibility = View.GONE
/* TODO /* TODO
binding.languageselect.setOnClickListener { binding.languageselect.setOnClickListener {
val popup = PopupMenu(this, it) val popup = PopupMenu(this, it)
popup.inflate(R.menu.launguage_selector_menu) popup.inflate(R.menu.launguage_selector_menu)
popup.setOnMenuItemClickListener { menuItem -> popup.setOnMenuItemClickListener { menuItem ->
true true
} }
popup.setOnDismissListener { popup.setOnDismissListener {
} }
popup.show() popup.show()
}*/ }*/
binding.settingsContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> { binding.settingsContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = statusBarHeight topMargin = statusBarHeight
bottomMargin = navBarHeight bottomMargin = navBarHeight

View file

@ -18,83 +18,83 @@ class FAQActivity : AppCompatActivity() {
Triple( Triple(
R.drawable.ic_round_help_24, R.drawable.ic_round_help_24,
currContext()?.getString(R.string.question_1)?:"", currContext()?.getString(R.string.question_1) ?: "",
currContext()?.getString(R.string.answer_1)?:"" currContext()?.getString(R.string.answer_1) ?: ""
), ),
Triple( Triple(
R.drawable.ic_round_auto_awesome_24, R.drawable.ic_round_auto_awesome_24,
currContext()?.getString(R.string.question_2)?:"", currContext()?.getString(R.string.question_2) ?: "",
currContext()?.getString(R.string.answer_2)?:"" currContext()?.getString(R.string.answer_2) ?: ""
), ),
Triple( Triple(
R.drawable.ic_round_auto_awesome_24, R.drawable.ic_round_auto_awesome_24,
currContext()?.getString(R.string.question_17)?:"", currContext()?.getString(R.string.question_17) ?: "",
currContext()?.getString(R.string.answer_17)?:"" currContext()?.getString(R.string.answer_17) ?: ""
), ),
Triple( Triple(
R.drawable.ic_round_download_24, R.drawable.ic_round_download_24,
currContext()?.getString(R.string.question_3)?:"", currContext()?.getString(R.string.question_3) ?: "",
currContext()?.getString(R.string.answer_3)?:"" currContext()?.getString(R.string.answer_3) ?: ""
), ),
Triple( Triple(
R.drawable.ic_round_help_24, R.drawable.ic_round_help_24,
currContext()?.getString(R.string.question_16)?:"", currContext()?.getString(R.string.question_16) ?: "",
currContext()?.getString(R.string.answer_16)?:"" currContext()?.getString(R.string.answer_16) ?: ""
), ),
Triple( Triple(
R.drawable.ic_round_dns_24, R.drawable.ic_round_dns_24,
currContext()?.getString(R.string.question_4)?:"", currContext()?.getString(R.string.question_4) ?: "",
currContext()?.getString(R.string.answer_4)?:"" currContext()?.getString(R.string.answer_4) ?: ""
), ),
Triple( Triple(
R.drawable.ic_baseline_screen_lock_portrait_24, R.drawable.ic_baseline_screen_lock_portrait_24,
currContext()?.getString(R.string.question_5)?:"", currContext()?.getString(R.string.question_5) ?: "",
currContext()?.getString(R.string.answer_5)?:"" currContext()?.getString(R.string.answer_5) ?: ""
), ),
Triple( Triple(
R.drawable.ic_anilist, R.drawable.ic_anilist,
currContext()?.getString(R.string.question_6)?:"", currContext()?.getString(R.string.question_6) ?: "",
currContext()?.getString(R.string.answer_6)?:"" currContext()?.getString(R.string.answer_6) ?: ""
), ),
Triple( Triple(
R.drawable.ic_round_movie_filter_24, R.drawable.ic_round_movie_filter_24,
currContext()?.getString(R.string.question_7)?:"", currContext()?.getString(R.string.question_7) ?: "",
currContext()?.getString(R.string.answer_7)?:"" currContext()?.getString(R.string.answer_7) ?: ""
), ),
Triple( Triple(
R.drawable.ic_round_lock_open_24, R.drawable.ic_round_lock_open_24,
currContext()?.getString(R.string.question_9)?:"", currContext()?.getString(R.string.question_9) ?: "",
currContext()?.getString(R.string.answer_9)?:"" currContext()?.getString(R.string.answer_9) ?: ""
), ),
Triple( Triple(
R.drawable.ic_round_smart_button_24, R.drawable.ic_round_smart_button_24,
currContext()?.getString(R.string.question_10)?:"", currContext()?.getString(R.string.question_10) ?: "",
currContext()?.getString(R.string.answer_10)?:"" currContext()?.getString(R.string.answer_10) ?: ""
), ),
Triple( Triple(
R.drawable.ic_round_smart_button_24, R.drawable.ic_round_smart_button_24,
currContext()?.getString(R.string.question_11)?:"", currContext()?.getString(R.string.question_11) ?: "",
currContext()?.getString(R.string.answer_11)?:"" currContext()?.getString(R.string.answer_11) ?: ""
), ),
Triple( Triple(
R.drawable.ic_round_info_24, R.drawable.ic_round_info_24,
currContext()?.getString(R.string.question_12)?:"", currContext()?.getString(R.string.question_12) ?: "",
currContext()?.getString(R.string.answer_12)?:"" currContext()?.getString(R.string.answer_12) ?: ""
), ),
Triple( Triple(
R.drawable.ic_round_help_24, R.drawable.ic_round_help_24,
currContext()?.getString(R.string.question_13)?:"", currContext()?.getString(R.string.question_13) ?: "",
currContext()?.getString(R.string.answer_13)?:"" currContext()?.getString(R.string.answer_13) ?: ""
), ),
Triple( Triple(
R.drawable.ic_round_art_track_24, R.drawable.ic_round_art_track_24,
currContext()?.getString(R.string.question_14)?:"", currContext()?.getString(R.string.question_14) ?: "",
currContext()?.getString(R.string.answer_14)?:"" currContext()?.getString(R.string.answer_14) ?: ""
), ),
Triple( Triple(
R.drawable.ic_round_video_settings_24, R.drawable.ic_round_video_settings_24,
currContext()?.getString(R.string.question_15)?:"", currContext()?.getString(R.string.question_15) ?: "",
currContext()?.getString(R.string.answer_15)?:"" currContext()?.getString(R.string.answer_15) ?: ""
) )
) )
} }

View file

@ -50,7 +50,7 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
private val animeExtensionManager: AnimeExtensionManager = Injekt.get() private val animeExtensionManager: AnimeExtensionManager = Injekt.get()
private val extensionsAdapter = AnimeExtensionsAdapter( private val extensionsAdapter = AnimeExtensionsAdapter(
{ pkg -> { pkg ->
val name= pkg.name val name = pkg.name
val changeUIVisibility: (Boolean) -> Unit = { show -> val changeUIVisibility: (Boolean) -> Unit = { show ->
val activity = requireActivity() as ExtensionsActivity val activity = requireActivity() as ExtensionsActivity
val visibility = if (show) View.VISIBLE else View.GONE val visibility = if (show) View.VISIBLE else View.GONE
@ -58,7 +58,8 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
activity.findViewById<TabLayout>(R.id.tabLayout).visibility = visibility activity.findViewById<TabLayout>(R.id.tabLayout).visibility = visibility
activity.findViewById<TextInputLayout>(R.id.searchView).visibility = visibility activity.findViewById<TextInputLayout>(R.id.searchView).visibility = visibility
activity.findViewById<ImageView>(R.id.languageselect).visibility = visibility activity.findViewById<ImageView>(R.id.languageselect).visibility = visibility
activity.findViewById<TextView>(R.id.extensions).text = if (show) getString(R.string.extensions) else name activity.findViewById<TextView>(R.id.extensions).text =
if (show) getString(R.string.extensions) else name
activity.findViewById<FrameLayout>(R.id.fragmentExtensionsContainer).visibility = activity.findViewById<FrameLayout>(R.id.fragmentExtensionsContainer).visibility =
if (show) View.GONE else View.VISIBLE if (show) View.GONE else View.VISIBLE
} }
@ -67,7 +68,8 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
if (allSettings.isNotEmpty()) { if (allSettings.isNotEmpty()) {
var selectedSetting = allSettings[0] var selectedSetting = allSettings[0]
if (allSettings.size > 1) { if (allSettings.size > 1) {
val names = allSettings.map { LanguageMapper.mapLanguageCodeToName(it.lang) }.toTypedArray() val names = allSettings.map { LanguageMapper.mapLanguageCodeToName(it.lang) }
.toTypedArray()
var selectedIndex = 0 var selectedIndex = 0
val dialog = AlertDialog.Builder(requireContext(), R.style.MyPopup) val dialog = AlertDialog.Builder(requireContext(), R.style.MyPopup)
.setTitle("Select a Source") .setTitle("Select a Source")

View file

@ -47,72 +47,76 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
private lateinit var extensionsRecyclerView: RecyclerView private lateinit var extensionsRecyclerView: RecyclerView
private val skipIcons = loadData("skip_extension_icons") ?: false private val skipIcons = loadData("skip_extension_icons") ?: false
private val mangaExtensionManager: MangaExtensionManager = Injekt.get() private val mangaExtensionManager: MangaExtensionManager = Injekt.get()
private val extensionsAdapter = MangaExtensionsAdapter({ pkg -> private val extensionsAdapter = MangaExtensionsAdapter(
val name= pkg.name { pkg ->
val changeUIVisibility: (Boolean) -> Unit = { show -> val name = pkg.name
val activity = requireActivity() as ExtensionsActivity val changeUIVisibility: (Boolean) -> Unit = { show ->
val visibility = if (show) View.VISIBLE else View.GONE val activity = requireActivity() as ExtensionsActivity
activity.findViewById<ViewPager2>(R.id.viewPager).visibility = visibility val visibility = if (show) View.VISIBLE else View.GONE
activity.findViewById<TabLayout>(R.id.tabLayout).visibility = visibility activity.findViewById<ViewPager2>(R.id.viewPager).visibility = visibility
activity.findViewById<TextInputLayout>(R.id.searchView).visibility = visibility activity.findViewById<TabLayout>(R.id.tabLayout).visibility = visibility
activity.findViewById<ImageView>(R.id.languageselect).visibility = visibility activity.findViewById<TextInputLayout>(R.id.searchView).visibility = visibility
activity.findViewById<TextView>(R.id.extensions).text = if (show) getString(R.string.extensions) else name activity.findViewById<ImageView>(R.id.languageselect).visibility = visibility
activity.findViewById<FrameLayout>(R.id.fragmentExtensionsContainer).visibility = activity.findViewById<TextView>(R.id.extensions).text =
if (show) View.GONE else View.VISIBLE if (show) getString(R.string.extensions) else name
} activity.findViewById<FrameLayout>(R.id.fragmentExtensionsContainer).visibility =
var itemSelected = false if (show) View.GONE else View.VISIBLE
val allSettings = pkg.sources.filterIsInstance<ConfigurableSource>() }
if (allSettings.isNotEmpty()) { var itemSelected = false
var selectedSetting = allSettings[0] val allSettings = pkg.sources.filterIsInstance<ConfigurableSource>()
if (allSettings.size > 1) { if (allSettings.isNotEmpty()) {
val names = allSettings.map { LanguageMapper.mapLanguageCodeToName(it.lang) }.toTypedArray() var selectedSetting = allSettings[0]
var selectedIndex = 0 if (allSettings.size > 1) {
val dialog = AlertDialog.Builder(requireContext(), R.style.MyPopup) val names = allSettings.map { LanguageMapper.mapLanguageCodeToName(it.lang) }
.setTitle("Select a Source") .toTypedArray()
.setSingleChoiceItems(names, selectedIndex) { dialog, which -> var selectedIndex = 0
itemSelected = true val dialog = AlertDialog.Builder(requireContext(), R.style.MyPopup)
selectedIndex = which .setTitle("Select a Source")
selectedSetting = allSettings[selectedIndex] .setSingleChoiceItems(names, selectedIndex) { dialog, which ->
dialog.dismiss() itemSelected = true
selectedIndex = which
selectedSetting = allSettings[selectedIndex]
dialog.dismiss()
// Move the fragment transaction here // Move the fragment transaction here
val fragment = val fragment =
MangaSourcePreferencesFragment().getInstance(selectedSetting.id) { MangaSourcePreferencesFragment().getInstance(selectedSetting.id) {
changeUIVisibility(true)
}
parentFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.slide_up, R.anim.slide_down)
.replace(R.id.fragmentExtensionsContainer, fragment)
.addToBackStack(null)
.commit()
}
.setOnDismissListener {
if (!itemSelected) {
changeUIVisibility(true) changeUIVisibility(true)
} }
parentFragmentManager.beginTransaction() }
.setCustomAnimations(R.anim.slide_up, R.anim.slide_down) .show()
.replace(R.id.fragmentExtensionsContainer, fragment) dialog.window?.setDimAmount(0.8f)
.addToBackStack(null) } else {
.commit() // If there's only one setting, proceed with the fragment transaction
} val fragment =
.setOnDismissListener { MangaSourcePreferencesFragment().getInstance(selectedSetting.id) {
if (!itemSelected) {
changeUIVisibility(true) changeUIVisibility(true)
} }
} parentFragmentManager.beginTransaction()
.show() .setCustomAnimations(R.anim.slide_up, R.anim.slide_down)
dialog.window?.setDimAmount(0.8f) .replace(R.id.fragmentExtensionsContainer, fragment)
} else { .addToBackStack(null)
// If there's only one setting, proceed with the fragment transaction .commit()
val fragment = MangaSourcePreferencesFragment().getInstance(selectedSetting.id) {
changeUIVisibility(true)
} }
parentFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.slide_up, R.anim.slide_down)
.replace(R.id.fragmentExtensionsContainer, fragment)
.addToBackStack(null)
.commit()
}
// Hide ViewPager2 and TabLayout // Hide ViewPager2 and TabLayout
changeUIVisibility(false) changeUIVisibility(false)
} else { } else {
Toast.makeText(requireContext(), "Source is not configurable", Toast.LENGTH_SHORT) Toast.makeText(requireContext(), "Source is not configurable", Toast.LENGTH_SHORT)
.show() .show()
} }
}, },
{ pkg: MangaExtension.Installed , forceDelete: Boolean -> { pkg: MangaExtension.Installed, forceDelete: Boolean ->
if (isAdded) { // Check if the fragment is currently added to its activity if (isAdded) { // Check if the fragment is currently added to its activity
val context = requireContext() // Store context in a variable val context = requireContext() // Store context in a variable
val notificationManager = val notificationManager =

View file

@ -39,10 +39,11 @@ class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler {
private lateinit var extensionsRecyclerView: RecyclerView private lateinit var extensionsRecyclerView: RecyclerView
val skipIcons = loadData("skip_extension_icons") ?: false val skipIcons = loadData("skip_extension_icons") ?: false
private val novelExtensionManager: NovelExtensionManager = Injekt.get() private val novelExtensionManager: NovelExtensionManager = Injekt.get()
private val extensionsAdapter = NovelExtensionsAdapter({ pkg -> private val extensionsAdapter = NovelExtensionsAdapter(
Toast.makeText(requireContext(), "Source is not configurable", Toast.LENGTH_SHORT) { pkg ->
.show() Toast.makeText(requireContext(), "Source is not configurable", Toast.LENGTH_SHORT)
}, .show()
},
{ pkg, forceDelete -> { pkg, forceDelete ->
if (isAdded) { // Check if the fragment is currently added to its activity if (isAdded) { // Check if the fragment is currently added to its activity
val context = requireContext() // Store context in a variable val context = requireContext() // Store context in a variable

View file

@ -97,7 +97,21 @@ class PlayerSettingsActivity : AppCompatActivity() {
val speeds = val speeds =
arrayOf(0.25f, 0.33f, 0.5f, 0.66f, 0.75f, 1f, 1.15f, 1.25f, 1.33f, 1.5f, 1.66f, 1.75f, 2f) arrayOf(
0.25f,
0.33f,
0.5f,
0.66f,
0.75f,
1f,
1.15f,
1.25f,
1.33f,
1.5f,
1.66f,
1.75f,
2f
)
val cursedSpeeds = arrayOf(1f, 1.25f, 1.5f, 1.75f, 2f, 2.5f, 3f, 4f, 5f, 10f, 25f, 50f) val cursedSpeeds = arrayOf(1f, 1.25f, 1.5f, 1.75f, 2f, 2.5f, 3f, 4f, 5f, 10f, 25f, 50f)
var curSpeedArr = if (settings.cursedSpeeds) cursedSpeeds else speeds var curSpeedArr = if (settings.cursedSpeeds) cursedSpeeds else speeds
var speedsName = curSpeedArr.map { "${it}x" }.toTypedArray() var speedsName = curSpeedArr.map { "${it}x" }.toTypedArray()
@ -106,13 +120,14 @@ class PlayerSettingsActivity : AppCompatActivity() {
val speedDialog = AlertDialog.Builder(this, R.style.DialogTheme) val speedDialog = AlertDialog.Builder(this, R.style.DialogTheme)
.setTitle(getString(R.string.default_speed)) .setTitle(getString(R.string.default_speed))
binding.playerSettingsSpeed.setOnClickListener { binding.playerSettingsSpeed.setOnClickListener {
val dialog = speedDialog.setSingleChoiceItems(speedsName, settings.defaultSpeed) { dialog, i -> val dialog =
settings.defaultSpeed = i speedDialog.setSingleChoiceItems(speedsName, settings.defaultSpeed) { dialog, i ->
binding.playerSettingsSpeed.text = settings.defaultSpeed = i
getString(R.string.default_playback_speed, speedsName[i]) binding.playerSettingsSpeed.text =
saveData(player, settings) getString(R.string.default_playback_speed, speedsName[i])
dialog.dismiss() saveData(player, settings)
}.show() dialog.dismiss()
}.show()
dialog.window?.setDimAmount(0.8f) dialog.window?.setDimAmount(0.8f)
} }
@ -256,11 +271,12 @@ class PlayerSettingsActivity : AppCompatActivity() {
val resizeDialog = AlertDialog.Builder(this, R.style.DialogTheme) val resizeDialog = AlertDialog.Builder(this, R.style.DialogTheme)
.setTitle(getString(R.string.default_resize_mode)) .setTitle(getString(R.string.default_resize_mode))
binding.playerResizeMode.setOnClickListener { binding.playerResizeMode.setOnClickListener {
val dialog = resizeDialog.setSingleChoiceItems(resizeModes, settings.resize) { dialog, count -> val dialog =
settings.resize = count resizeDialog.setSingleChoiceItems(resizeModes, settings.resize) { dialog, count ->
saveData(player, settings) settings.resize = count
dialog.dismiss() saveData(player, settings)
}.show() dialog.dismiss()
}.show()
dialog.window?.setDimAmount(0.8f) dialog.window?.setDimAmount(0.8f)
} }
fun restartApp() { fun restartApp() {
@ -382,7 +398,10 @@ class PlayerSettingsActivity : AppCompatActivity() {
val outlineDialog = AlertDialog.Builder(this, R.style.DialogTheme) val outlineDialog = AlertDialog.Builder(this, R.style.DialogTheme)
.setTitle(getString(R.string.outline_type)) .setTitle(getString(R.string.outline_type))
binding.videoSubOutline.setOnClickListener { binding.videoSubOutline.setOnClickListener {
val dialog = outlineDialog.setSingleChoiceItems(typesOutline, settings.outline) { dialog, count -> val dialog = outlineDialog.setSingleChoiceItems(
typesOutline,
settings.outline
) { dialog, count ->
settings.outline = count settings.outline = count
saveData(player, settings) saveData(player, settings)
dialog.dismiss() dialog.dismiss()

View file

@ -1,17 +1,13 @@
package ani.dantotsu.settings package ani.dantotsu.settings
import android.os.Bundle import android.os.Bundle
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.AdapterView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import ani.dantotsu.NoPaddingArrayAdapter
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.databinding.ActivityReaderSettingsBinding import ani.dantotsu.databinding.ActivityReaderSettingsBinding
import ani.dantotsu.initActivity import ani.dantotsu.initActivity
import ani.dantotsu.loadData import ani.dantotsu.loadData
import ani.dantotsu.media.novel.novelreader.NovelReaderActivity
import ani.dantotsu.navBarHeight import ani.dantotsu.navBarHeight
import ani.dantotsu.others.LangSet import ani.dantotsu.others.LangSet
import ani.dantotsu.saveData import ani.dantotsu.saveData

View file

@ -58,7 +58,7 @@ import uy.kohesive.injekt.api.get
import kotlin.random.Random import kotlin.random.Random
class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListener { class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListener {
private val restartMainActivity = object : OnBackPressedCallback(false) { private val restartMainActivity = object : OnBackPressedCallback(false) {
override fun handleOnBackPressed() = startMainActivity(this@SettingsActivity) override fun handleOnBackPressed() = startMainActivity(this@SettingsActivity)
} }
@ -67,7 +67,8 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListen
private val networkPreferences = Injekt.get<NetworkPreferences>() private val networkPreferences = Injekt.get<NetworkPreferences>()
private var cursedCounter = 0 private var cursedCounter = 0
@OptIn(UnstableApi::class) @SuppressLint("SetTextI18n") @OptIn(UnstableApi::class)
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
LangSet.setLocale(this) LangSet.setLocale(this)
@ -188,12 +189,14 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListen
"custom_theme_int", "custom_theme_int",
Color.parseColor("#6200EE") Color.parseColor("#6200EE")
) )
class CustomColorDialog : SimpleColorDialog() { //idk where to put it class CustomColorDialog : SimpleColorDialog() { //idk where to put it
override fun onPositiveButtonClick() { override fun onPositiveButtonClick() {
restartApp() restartApp()
super.onPositiveButtonClick() super.onPositiveButtonClick()
} }
} }
val tag = "colorPicker" val tag = "colorPicker"
CustomColorDialog().title("Custom Theme") CustomColorDialog().title("Custom Theme")
.colorPreset(originalColor) .colorPreset(originalColor)
@ -240,7 +243,10 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListen
AlertDialog.Builder(this, R.style.DialogTheme).setTitle("Download Manager") AlertDialog.Builder(this, R.style.DialogTheme).setTitle("Download Manager")
var downloadManager = loadData<Int>("settings_download_manager") ?: 0 var downloadManager = loadData<Int>("settings_download_manager") ?: 0
binding.settingsDownloadManager.setOnClickListener { binding.settingsDownloadManager.setOnClickListener {
val dialog = downloadManagerDialog.setSingleChoiceItems(managers, downloadManager) { dialog, count -> val dialog = downloadManagerDialog.setSingleChoiceItems(
managers,
downloadManager
) { dialog, count ->
downloadManager = count downloadManager = count
saveData("settings_download_manager", downloadManager) saveData("settings_download_manager", downloadManager)
dialog.dismiss() dialog.dismiss()
@ -255,7 +261,11 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListen
.setPositiveButton("Yes") { dialog, _ -> .setPositiveButton("Yes") { dialog, _ ->
val downloadsManager = Injekt.get<DownloadsManager>() val downloadsManager = Injekt.get<DownloadsManager>()
downloadsManager.purgeDownloads(DownloadedType.Type.ANIME) downloadsManager.purgeDownloads(DownloadedType.Type.ANIME)
DownloadService.sendRemoveAllDownloads(this, ExoplayerDownloadService::class.java, false) DownloadService.sendRemoveAllDownloads(
this,
ExoplayerDownloadService::class.java,
false
)
dialog.dismiss() dialog.dismiss()
} }
.setNegativeButton("No") { dialog, _ -> .setNegativeButton("No") { dialog, _ ->

View file

@ -1,7 +1,7 @@
package ani.dantotsu.settings package ani.dantotsu.settings
import android.content.Intent
import android.content.Context import android.content.Context
import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.util.TypedValue import android.util.TypedValue
@ -9,25 +9,24 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import ani.dantotsu.BottomSheetDialogFragment import ani.dantotsu.BottomSheetDialogFragment
import ani.dantotsu.R
import ani.dantotsu.MainActivity import ani.dantotsu.MainActivity
import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.databinding.BottomSheetSettingsBinding import ani.dantotsu.databinding.BottomSheetSettingsBinding
import ani.dantotsu.download.manga.OfflineMangaFragment import ani.dantotsu.download.manga.OfflineMangaFragment
import ani.dantotsu.loadImage
import ani.dantotsu.openLinkInBrowser
import ani.dantotsu.others.imagesearch.ImageSearchActivity
import ani.dantotsu.setSafeOnClickListener
import ani.dantotsu.startMainActivity
import ani.dantotsu.currContext
import ani.dantotsu.home.AnimeFragment import ani.dantotsu.home.AnimeFragment
import ani.dantotsu.home.HomeFragment import ani.dantotsu.home.HomeFragment
import ani.dantotsu.home.LoginFragment import ani.dantotsu.home.LoginFragment
import ani.dantotsu.home.MangaFragment import ani.dantotsu.home.MangaFragment
import ani.dantotsu.home.NoInternet import ani.dantotsu.home.NoInternet
import ani.dantotsu.loadImage
import ani.dantotsu.offline.OfflineFragment import ani.dantotsu.offline.OfflineFragment
import ani.dantotsu.openLinkInBrowser
import ani.dantotsu.others.imagesearch.ImageSearchActivity
import ani.dantotsu.setSafeOnClickListener
import ani.dantotsu.startMainActivity
class SettingsDialogFragment() : BottomSheetDialogFragment() { class SettingsDialogFragment : BottomSheetDialogFragment() {
private var _binding: BottomSheetSettingsBinding? = null private var _binding: BottomSheetSettingsBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
@ -36,8 +35,10 @@ class SettingsDialogFragment() : BottomSheetDialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
pageType = arguments?.getSerializable("pageType") as? PageType ?: PageType.HOME pageType = arguments?.getSerializable("pageType") as? PageType ?: PageType.HOME
pageType2 = arguments?.getSerializable("pageType2") as? PageType2 ?: PageType2.OfflineMANGA // changed when offline home page comes pageType2 = arguments?.getSerializable("pageType2") as? PageType2
?: PageType2.OfflineMANGA // changed when offline home page comes
} }
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@ -81,8 +82,8 @@ class SettingsDialogFragment() : BottomSheetDialogFragment() {
) ?: false ) ?: false
binding.settingsIncognito.setOnCheckedChangeListener { _, isChecked -> binding.settingsIncognito.setOnCheckedChangeListener { _, isChecked ->
context?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)?.edit() context?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)?.edit()
?.putBoolean("incognito", isChecked)?.apply() ?.putBoolean("incognito", isChecked)?.apply()
} }
binding.settingsExtensionSettings.setSafeOnClickListener { binding.settingsExtensionSettings.setSafeOnClickListener {
startActivity(Intent(activity, ExtensionsActivity::class.java)) startActivity(Intent(activity, ExtensionsActivity::class.java))
@ -102,7 +103,8 @@ class SettingsDialogFragment() : BottomSheetDialogFragment() {
} }
binding.settingsDownloads.isChecked = binding.settingsDownloads.isChecked =
context?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)?.getBoolean("offlineMode", false) ?: false context?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
?.getBoolean("offlineMode", false) ?: false
binding.settingsDownloads.setOnCheckedChangeListener { _, isChecked -> binding.settingsDownloads.setOnCheckedChangeListener { _, isChecked ->
if (!isChecked) { if (!isChecked) {
@ -112,11 +114,16 @@ class SettingsDialogFragment() : BottomSheetDialogFragment() {
intent.putExtra("FRAGMENT_CLASS_NAME", MangaFragment::class.java.name) intent.putExtra("FRAGMENT_CLASS_NAME", MangaFragment::class.java.name)
startActivity(intent) startActivity(intent)
} }
PageType2.OfflineHOME -> { //no offline home for now PageType2.OfflineHOME -> { //no offline home for now
val intent = Intent(activity, MainActivity::class.java) val intent = Intent(activity, MainActivity::class.java)
intent.putExtra("FRAGMENT_CLASS_NAME", if (Anilist.token != null) HomeFragment::class.java.name else LoginFragment::class.java.name) intent.putExtra(
"FRAGMENT_CLASS_NAME",
if (Anilist.token != null) HomeFragment::class.java.name else LoginFragment::class.java.name
)
startActivity(intent) startActivity(intent)
} }
PageType2.OfflineANIME -> { //no offline anime for now PageType2.OfflineANIME -> { //no offline anime for now
val intent = Intent(activity, MainActivity::class.java) val intent = Intent(activity, MainActivity::class.java)
intent.putExtra("FRAGMENT_CLASS_NAME", AnimeFragment::class.java.name) intent.putExtra("FRAGMENT_CLASS_NAME", AnimeFragment::class.java.name)
@ -127,14 +134,19 @@ class SettingsDialogFragment() : BottomSheetDialogFragment() {
when (pageType) { when (pageType) {
PageType.MANGA -> { PageType.MANGA -> {
val intent = Intent(activity, NoInternet::class.java) val intent = Intent(activity, NoInternet::class.java)
intent.putExtra("FRAGMENT_CLASS_NAME", OfflineMangaFragment::class.java.name) intent.putExtra(
"FRAGMENT_CLASS_NAME",
OfflineMangaFragment::class.java.name
)
startActivity(intent) startActivity(intent)
} }
PageType.ANIME -> {
val intent = Intent(activity, NoInternet::class.java) PageType.ANIME -> {
intent.putExtra("FRAGMENT_CLASS_NAME", OfflineFragment::class.java.name) val intent = Intent(activity, NoInternet::class.java)
startActivity(intent) intent.putExtra("FRAGMENT_CLASS_NAME", OfflineFragment::class.java.name)
} startActivity(intent)
}
PageType.HOME -> { PageType.HOME -> {
val intent = Intent(activity, NoInternet::class.java) val intent = Intent(activity, NoInternet::class.java)
intent.putExtra("FRAGMENT_CLASS_NAME", OfflineFragment::class.java.name) intent.putExtra("FRAGMENT_CLASS_NAME", OfflineFragment::class.java.name)
@ -145,8 +157,8 @@ class SettingsDialogFragment() : BottomSheetDialogFragment() {
dismiss() dismiss()
context?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)?.edit() context?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)?.edit()
?.putBoolean("offlineMode", isChecked)?.apply() ?.putBoolean("offlineMode", isChecked)?.apply()
}
} }
}
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
@ -157,9 +169,11 @@ class SettingsDialogFragment() : BottomSheetDialogFragment() {
enum class PageType { enum class PageType {
MANGA, ANIME, HOME MANGA, ANIME, HOME
} }
enum class PageType2 { enum class PageType2 {
OfflineMANGA, OfflineANIME, OfflineHOME OfflineMANGA, OfflineANIME, OfflineHOME
} }
fun newInstance(pageType: PageType): SettingsDialogFragment { fun newInstance(pageType: PageType): SettingsDialogFragment {
val fragment = SettingsDialogFragment() val fragment = SettingsDialogFragment()
val args = Bundle() val args = Bundle()
@ -167,6 +181,7 @@ class SettingsDialogFragment() : BottomSheetDialogFragment() {
fragment.arguments = args fragment.arguments = args
return fragment return fragment
} }
fun newInstance2(pageType: PageType2): SettingsDialogFragment { fun newInstance2(pageType: PageType2): SettingsDialogFragment {
val fragment = SettingsDialogFragment() val fragment = SettingsDialogFragment()
val args = Bundle() val args = Bundle()

View file

@ -44,14 +44,14 @@ class UserInterfaceSettingsActivity : AppCompatActivity() {
binding.uiSettingsHomeLayout.setOnClickListener { binding.uiSettingsHomeLayout.setOnClickListener {
val dialog = AlertDialog.Builder(this, R.style.DialogTheme) val dialog = AlertDialog.Builder(this, R.style.DialogTheme)
.setTitle(getString(R.string.home_layout_show)).apply { .setTitle(getString(R.string.home_layout_show)).apply {
setMultiChoiceItems( setMultiChoiceItems(
views, views,
settings.homeLayoutShow.toBooleanArray() settings.homeLayoutShow.toBooleanArray()
) { _, i, value -> ) { _, i, value ->
settings.homeLayoutShow[i] = value settings.homeLayoutShow[i] = value
saveData(ui, settings) saveData(ui, settings)
} }
}.show() }.show()
dialog.window?.setDimAmount(0.8f) dialog.window?.setDimAmount(0.8f)
} }

View file

@ -99,7 +99,8 @@ class AnimeExtensionPagingSource(
} else { } else {
availableExtensions.filter { it.name.contains(query, ignoreCase = true) } availableExtensions.filter { it.name.contains(query, ignoreCase = true) }
} }
val filternfsw = if (isNsfwEnabled) filteredExtensions else filteredExtensions.filterNot { it.isNsfw } val filternfsw =
if (isNsfwEnabled) filteredExtensions else filteredExtensions.filterNot { it.isNsfw }
return try { return try {
val sublist = filternfsw.subList( val sublist = filternfsw.subList(
fromIndex = position, fromIndex = position,

View file

@ -98,7 +98,8 @@ class MangaExtensionPagingSource(
} else { } else {
availableExtensions.filter { it.name.contains(query, ignoreCase = true) } availableExtensions.filter { it.name.contains(query, ignoreCase = true) }
} }
val filternfsw = if (isNsfwEnabled) filteredExtensions else filteredExtensions.filterNot { it.isNsfw } val filternfsw =
if (isNsfwEnabled) filteredExtensions else filteredExtensions.filterNot { it.isNsfw }
return try { return try {
val sublist = filternfsw.subList( val sublist = filternfsw.subList(
fromIndex = position, fromIndex = position,
@ -192,6 +193,7 @@ class MangaExtensionAdapter(private val clickListener: OnMangaInstallClickListen
} }
val extensionIconImageView: ImageView = binding.extensionIconImageView val extensionIconImageView: ImageView = binding.extensionIconImageView
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
fun bind(extension: MangaExtension.Available) { fun bind(extension: MangaExtension.Available) {
val nsfw = if (extension.isNsfw) "(18+)" else "" val nsfw = if (extension.isNsfw) "(18+)" else ""

View file

@ -4,17 +4,16 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri
import android.widget.RemoteViews import android.widget.RemoteViews
import android.widget.RemoteViewsService import android.widget.RemoteViewsService
import androidx.core.net.toUri
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.logger import ani.dantotsu.logger
import java.io.InputStream import java.io.InputStream
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.URL import java.net.URL
class CurrentlyAiringRemoteViewsFactory(private val context: Context, intent: Intent) : RemoteViewsService.RemoteViewsFactory { class CurrentlyAiringRemoteViewsFactory(private val context: Context, intent: Intent) :
RemoteViewsService.RemoteViewsFactory {
private var widgetItems = mutableListOf<WidgetItem>() private var widgetItems = mutableListOf<WidgetItem>()
override fun onCreate() { override fun onCreate() {
@ -22,7 +21,11 @@ class CurrentlyAiringRemoteViewsFactory(private val context: Context, intent: In
widgetItems.clear() widgetItems.clear()
logger("CurrentlyAiringRemoteViewsFactory onCreate") logger("CurrentlyAiringRemoteViewsFactory onCreate")
widgetItems = List(4) { widgetItems = List(4) {
WidgetItem("Show $it", "$it days $it hours $it minutes", "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg") WidgetItem(
"Show $it",
"$it days $it hours $it minutes",
"https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg"
)
}.toMutableList() }.toMutableList()
} }
@ -30,11 +33,41 @@ class CurrentlyAiringRemoteViewsFactory(private val context: Context, intent: In
// 4 items for testing // 4 items for testing
logger("CurrentlyAiringRemoteViewsFactory onDataSetChanged") logger("CurrentlyAiringRemoteViewsFactory onDataSetChanged")
widgetItems.clear() widgetItems.clear()
widgetItems.add(WidgetItem("Show 1", "1 day 2 hours 3 minutes", "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg")) widgetItems.add(
widgetItems.add(WidgetItem("Show 2", "2 days 3 hours 4 minutes", "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg")) WidgetItem(
widgetItems.add(WidgetItem("Show 3", "3 days 4 hours 5 minutes", "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg")) "Show 1",
widgetItems.add(WidgetItem("Show 4", "4 days 5 hours 6 minutes", "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg")) "1 day 2 hours 3 minutes",
widgetItems.add(WidgetItem("Show 5", "5 days 6 hours 7 minutes", "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg")) "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg"
)
)
widgetItems.add(
WidgetItem(
"Show 2",
"2 days 3 hours 4 minutes",
"https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg"
)
)
widgetItems.add(
WidgetItem(
"Show 3",
"3 days 4 hours 5 minutes",
"https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg"
)
)
widgetItems.add(
WidgetItem(
"Show 4",
"4 days 5 hours 6 minutes",
"https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg"
)
)
widgetItems.add(
WidgetItem(
"Show 5",
"5 days 6 hours 7 minutes",
"https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg"
)
)
} }
override fun onDestroy() { override fun onDestroy() {

View file

@ -3,6 +3,7 @@ package ani.dantotsu.widgets
import android.content.Intent import android.content.Intent
import android.widget.RemoteViewsService import android.widget.RemoteViewsService
import ani.dantotsu.logger import ani.dantotsu.logger
class CurrentlyAiringRemoteViewsService : RemoteViewsService() { class CurrentlyAiringRemoteViewsService : RemoteViewsService() {
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory { override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
logger("CurrentlyAiringRemoteViewsFactory onGetViewFactory") logger("CurrentlyAiringRemoteViewsFactory onGetViewFactory")

View file

@ -20,7 +20,11 @@ import ani.dantotsu.R
* App Widget Configuration implemented in [CurrentlyAiringWidgetConfigureActivity] * App Widget Configuration implemented in [CurrentlyAiringWidgetConfigureActivity]
*/ */
class CurrentlyAiringWidget : AppWidgetProvider() { class CurrentlyAiringWidget : AppWidgetProvider() {
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
appWidgetIds.forEach { appWidgetId -> appWidgetIds.forEach { appWidgetId ->
val intent = Intent(context, CurrentlyAiringRemoteViewsService::class.java).apply { val intent = Intent(context, CurrentlyAiringRemoteViewsService::class.java).apply {
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
@ -36,6 +40,7 @@ class CurrentlyAiringWidget : AppWidgetProvider() {
} }
super.onUpdate(context, appWidgetManager, appWidgetIds) super.onUpdate(context, appWidgetManager, appWidgetIds)
} }
override fun onDeleted(context: Context, appWidgetIds: IntArray) { override fun onDeleted(context: Context, appWidgetIds: IntArray) {
// When the user deletes the widget, delete the preference associated with it. // When the user deletes the widget, delete the preference associated with it.
for (appWidgetId in appWidgetIds) { for (appWidgetId in appWidgetIds) {
@ -51,6 +56,7 @@ class CurrentlyAiringWidget : AppWidgetProvider() {
override fun onDisabled(context: Context) { override fun onDisabled(context: Context) {
super.onDisabled(context) super.onDisabled(context)
} }
companion object { companion object {
fun updateAppWidget( fun updateAppWidget(
context: Context, context: Context,
@ -60,10 +66,15 @@ class CurrentlyAiringWidget : AppWidgetProvider() {
) { ) {
// Create an intent to launch the configuration activity when the widget is clicked // Create an intent to launch the configuration activity when the widget is clicked
val intent = Intent(context, CurrentlyAiringWidgetConfigureActivity::class.java) val intent = Intent(context, CurrentlyAiringWidgetConfigureActivity::class.java)
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) val pendingIntent =
PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
// Get the gradient drawable resource and update its start color with the user-selected color // Get the gradient drawable resource and update its start color with the user-selected color
val gradientDrawable = ResourcesCompat.getDrawable(context.resources, R.drawable.gradient_background, null) as GradientDrawable val gradientDrawable = ResourcesCompat.getDrawable(
context.resources,
R.drawable.gradient_background,
null
) as GradientDrawable
gradientDrawable.colors = intArrayOf(color, Color.GRAY) // End color is gray. gradientDrawable.colors = intArrayOf(color, Color.GRAY) // End color is gray.
// Create the RemoteViews object and set the background // Create the RemoteViews object and set the background

View file

@ -57,7 +57,7 @@ class CurrentlyAiringWidgetConfigureActivity : Activity() {
binding = CurrentlyAiringWidgetConfigureBinding.inflate(layoutInflater) binding = CurrentlyAiringWidgetConfigureBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
appWidgetText = binding.appwidgetText as EditText appWidgetText = binding.appwidgetText
binding.addButton.setOnClickListener(onClickListener) binding.addButton.setOnClickListener(onClickListener)
// Find the widget id from the intent. // Find the widget id from the intent.