diff --git a/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaFragment.kt b/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaFragment.kt index 35865f2c..887ae61a 100644 --- a/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaFragment.kt +++ b/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaFragment.kt @@ -1,16 +1,19 @@ package ani.dantotsu.download.manga import android.animation.ObjectAnimator +import android.content.Context import android.content.Intent import android.net.Uri import android.os.Build import android.os.Bundle import android.os.Environment +import android.util.TypedValue import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.animation.OvershootInterpolator import android.widget.GridView +import androidx.appcompat.app.AppCompatActivity import androidx.cardview.widget.CardView import androidx.core.view.updatePaddingRelative import androidx.fragment.app.Fragment @@ -24,9 +27,15 @@ import ani.dantotsu.download.DownloadsManager import ani.dantotsu.logger import ani.dantotsu.media.Media import ani.dantotsu.media.MediaDetailsActivity +import ani.dantotsu.media.manga.MangaNameAdapter import ani.dantotsu.navBarHeight import ani.dantotsu.px +import ani.dantotsu.setSafeOnClickListener +import ani.dantotsu.settings.SettingsDialogFragment import ani.dantotsu.statusBarHeight +import com.google.android.material.card.MaterialCardView +import com.google.android.material.imageview.ShapeableImageView +import com.google.android.material.textfield.TextInputLayout import com.google.firebase.crashlytics.FirebaseCrashlytics import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -46,6 +55,28 @@ class OfflineMangaFragment: Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_manga_offline, container, false) + + val textInputLayout = view.findViewById(R.id.offlineMangaSearchBar) + val currentColor = textInputLayout.boxBackgroundColor + val semiTransparentColor = (currentColor and 0x00FFFFFF) or 0xA8000000.toInt() + textInputLayout.boxBackgroundColor = semiTransparentColor + val materialCardView = view.findViewById(R.id.offlineMangaAvatarContainer) + materialCardView.setCardBackgroundColor(semiTransparentColor) + val typedValue = TypedValue() + requireContext().theme?.resolveAttribute(android.R.attr.windowBackground, typedValue, true) + val color = typedValue.data + + val animeUserAvatar= view.findViewById(R.id.offlineMangaUserAvatar) + animeUserAvatar.setSafeOnClickListener { + SettingsDialogFragment(SettingsDialogFragment.Companion.PageType.HOME).show((it.context as AppCompatActivity).supportFragmentManager, "dialog") + } + + val colorOverflow = currContext()?.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)?.getBoolean("colorOverflow", false) ?: false + if (!colorOverflow) { + textInputLayout.boxBackgroundColor = (color and 0x00FFFFFF) or 0x28000000.toInt() + materialCardView.setCardBackgroundColor((color and 0x00FFFFFF) or 0x28000000.toInt()) + } + gridView = view.findViewById(R.id.gridView) getDownloads() adapter = OfflineMangaAdapter(requireContext(), downloads) @@ -81,13 +112,6 @@ class OfflineMangaFragment: Fragment() { } } } - val refreshLayout = view.findViewById(R.id.mangaRefresh) - refreshLayout.setSlingshotDistance(height + 128) - refreshLayout.setProgressViewEndTarget(false, height + 128) - refreshLayout.setOnRefreshListener { - Refresh.activity[this.hashCode()]!!.postValue(true) - } - val scrollTop = view.findViewById(R.id.mangaPageScrollTop) var visible = false fun animate() { diff --git a/app/src/main/java/ani/dantotsu/media/Selected.kt b/app/src/main/java/ani/dantotsu/media/Selected.kt index 9982db51..d12a9b95 100644 --- a/app/src/main/java/ani/dantotsu/media/Selected.kt +++ b/app/src/main/java/ani/dantotsu/media/Selected.kt @@ -14,4 +14,5 @@ data class Selected( var server: String? = null, var video: Int = 0, var latest: Float = 0f, + var scanlators: List? = null, ) : Serializable diff --git a/app/src/main/java/ani/dantotsu/media/manga/MangaChapter.kt b/app/src/main/java/ani/dantotsu/media/manga/MangaChapter.kt index 06bbc5ac..0bfc3237 100644 --- a/app/src/main/java/ani/dantotsu/media/manga/MangaChapter.kt +++ b/app/src/main/java/ani/dantotsu/media/manga/MangaChapter.kt @@ -12,9 +12,10 @@ data class MangaChapter( var title: String? = null, var description: String? = null, var sChapter: SChapter, - var progress: String? = null, + val scanlator: String? = null, + var progress: String? = "" ) : Serializable { - constructor(chapter: MangaChapter) : this(chapter.number, chapter.link, chapter.title, chapter.description, chapter.sChapter) + constructor(chapter: MangaChapter) : this(chapter.number, chapter.link, chapter.title, chapter.description, chapter.sChapter, chapter.scanlator) private val images = mutableListOf() fun images(): List = images diff --git a/app/src/main/java/ani/dantotsu/media/manga/MangaChapterAdapter.kt b/app/src/main/java/ani/dantotsu/media/manga/MangaChapterAdapter.kt index 0320e4b3..4480d7a6 100644 --- a/app/src/main/java/ani/dantotsu/media/manga/MangaChapterAdapter.kt +++ b/app/src/main/java/ani/dantotsu/media/manga/MangaChapterAdapter.kt @@ -76,6 +76,7 @@ class MangaChapterAdapter( // Find the position of the chapter and notify only that item val position = arr.indexOfFirst { it.number == chapterNumber } if (position != -1) { + arr[position].progress = "Downloaded" notifyItemChanged(position) } } @@ -113,8 +114,10 @@ class MangaChapterAdapter( RecyclerView.ViewHolder(binding.root) { fun bind(chapterNumber: String, progress: String?) { if (progress != null) { - binding.itemChapterTitle.text = "Downloading: ${progress}%" + binding.itemChapterTitle.visibility = View.VISIBLE + binding.itemChapterTitle.text = "$progress" }else{ + binding.itemChapterTitle.visibility = View.GONE binding.itemChapterTitle.text = "" } if (activeDownloads.contains(chapterNumber)) { @@ -186,16 +189,9 @@ class MangaChapterAdapter( holder.bind(ep.number, ep.progress) setAnimation(fragment.requireContext(), holder.binding.root, fragment.uiSettings) binding.itemChapterNumber.text = ep.number - /*if (!ep.progress.isNullOrEmpty()) { - binding.itemChapterTitle.text = ep.progress - binding.itemChapterTitle.setOnLongClickListener { - binding.itemChapterTitle.maxLines.apply { - binding.itemChapterTitle.maxLines = if (this == 1) 3 else 1 - } - true - } - binding.itemChapterTitle.visibility = View.VISIBLE - } else*/ binding.itemChapterTitle.visibility = View.VISIBLE + if (ep.progress.isNullOrEmpty()) { + binding.itemChapterTitle.visibility = View.GONE + } else binding.itemChapterTitle.visibility = View.VISIBLE if (media.userProgress != null) { if ((MangaNameAdapter.findChapterNumber(ep.number) @@ -227,4 +223,4 @@ class MangaChapterAdapter( } -} +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/media/manga/MangaReadAdapter.kt b/app/src/main/java/ani/dantotsu/media/manga/MangaReadAdapter.kt index 4fd43ba8..8ef56d92 100644 --- a/app/src/main/java/ani/dantotsu/media/manga/MangaReadAdapter.kt +++ b/app/src/main/java/ani/dantotsu/media/manga/MangaReadAdapter.kt @@ -1,16 +1,19 @@ package ani.dantotsu.media.manga import android.annotation.SuppressLint +import android.app.AlertDialog import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ArrayAdapter +import android.widget.CheckBox import android.widget.ImageView import android.widget.LinearLayout import androidx.core.content.ContextCompat import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.RecyclerView import ani.dantotsu.* +import ani.dantotsu.App.Companion.context import ani.dantotsu.media.anime.handleProgress import ani.dantotsu.databinding.ItemAnimeWatchBinding import ani.dantotsu.databinding.ItemChipBinding @@ -37,6 +40,9 @@ class MangaReadAdapter( var subscribe: MediaDetailsActivity.PopImageButton? = null private var _binding: ItemAnimeWatchBinding? = null + val hiddenScanlators = mutableListOf() + var scanlatorSelectionListener: ScanlatorSelectionListener? = null + var options = listOf() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val bind = ItemAnimeWatchBinding.inflate(LayoutInflater.from(parent.context), parent, false) @@ -131,6 +137,46 @@ class MangaReadAdapter( binding.animeSourceTop.rotation = if (reversed) -90f else 90f fragment.onIconPressed(style, reversed) } + + binding.animeScanlatorTop.setOnClickListener { + val dialogView = LayoutInflater.from(currContext()).inflate(R.layout.custom_dialog_layout, null) + val checkboxContainer = dialogView.findViewById(R.id.checkboxContainer) + + // Dynamically add checkboxes + + options.forEach { option -> + val checkBox = CheckBox(currContext()).apply { + text = option + } + //set checked if it's already selected + if(media.selected!!.scanlators != null){ + checkBox.isChecked = media.selected!!.scanlators?.contains(option) != true + scanlatorSelectionListener?.onScanlatorsSelected() + }else{ + checkBox.isChecked = true + } + checkboxContainer.addView(checkBox) + } + + // Create AlertDialog + AlertDialog.Builder(currContext()) + .setView(dialogView) + .setPositiveButton("OK") { dialog, which -> + //add unchecked to hidden + hiddenScanlators.clear() + for (i in 0 until checkboxContainer.childCount) { + val checkBox = checkboxContainer.getChildAt(i) as CheckBox + if (!checkBox.isChecked) { + hiddenScanlators.add(checkBox.text.toString()) + } + } + media.selected!!.scanlators = hiddenScanlators + scanlatorSelectionListener?.onScanlatorsSelected() + } + .setNegativeButton("Cancel", null) + .show() + } + var selected = when (style) { 0 -> binding.animeSourceList 1 -> binding.animeSourceCompact @@ -201,6 +247,7 @@ class MangaReadAdapter( @SuppressLint("SetTextI18n") fun handleChapters() { + val binding = _binding if (binding != null) { if (media.manga?.chapters != null) { @@ -208,7 +255,11 @@ class MangaReadAdapter( val anilistEp = (media.userProgress ?: 0).plus(1) val appEp = loadData("${media.id}_current_chp")?.toIntOrNull() ?: 1 var continueEp = (if (anilistEp > appEp) anilistEp else appEp).toString() - val formattedChapters = chapters.map { MangaNameAdapter.findChapterNumber(it)?.toInt()?.toString() } + val filteredChapters = chapters.filter { chapterKey -> + val chapter = media.manga.chapters!![chapterKey]!! + chapter.scanlator !in hiddenScanlators + } + val formattedChapters = filteredChapters.map { MangaNameAdapter.findChapterNumber(it)?.toInt()?.toString() } if (formattedChapters.contains(continueEp)) { continueEp = chapters[formattedChapters.indexOf(continueEp)] binding.animeSourceContinue.visibility = View.VISIBLE @@ -278,4 +329,8 @@ class MangaReadAdapter( override fun getItemCount(): Int = 1 inner class ViewHolder(val binding: ItemAnimeWatchBinding) : RecyclerView.ViewHolder(binding.root) -} \ No newline at end of file +} + +interface ScanlatorSelectionListener { + fun onScanlatorsSelected() +} diff --git a/app/src/main/java/ani/dantotsu/media/manga/MangaReadFragment.kt b/app/src/main/java/ani/dantotsu/media/manga/MangaReadFragment.kt index eaa3af9b..46f41f54 100644 --- a/app/src/main/java/ani/dantotsu/media/manga/MangaReadFragment.kt +++ b/app/src/main/java/ani/dantotsu/media/manga/MangaReadFragment.kt @@ -67,7 +67,7 @@ import kotlin.math.roundToInt import android.Manifest import androidx.core.app.ActivityCompat -open class MangaReadFragment : Fragment() { +open class MangaReadFragment : Fragment(), ScanlatorSelectionListener { private var _binding: FragmentAnimeWatchBinding? = null private val binding get() = _binding!! private val model: MediaDetailsViewModel by activityViewModels() @@ -160,6 +160,7 @@ open class MangaReadFragment : Fragment() { model.mangaReadSources = if (media.isAdult) HMangaSources else MangaSources headerAdapter = MangaReadAdapter(it, this, model.mangaReadSources!!) + headerAdapter.scanlatorSelectionListener = this chapterAdapter = MangaChapterAdapter(style ?: uiSettings.mangaDefaultView, media, this) for (download in downloadManager.mangaDownloads){ @@ -182,45 +183,70 @@ open class MangaReadFragment : Fragment() { } } - model.getMangaChapters().observe(viewLifecycleOwner) { loadedChapters -> - if (loadedChapters != null) { - val chapters = loadedChapters[media.selected!!.sourceIndex] - if (chapters != null) { - media.manga?.chapters = chapters + model.getMangaChapters().observe(viewLifecycleOwner) { _ -> + updateChapters() + } + } - //CHIP GROUP - val total = chapters.size - val divisions = total.toDouble() / 10 - start = 0 - end = null - val limit = when { - (divisions < 25) -> 25 - (divisions < 50) -> 50 - else -> 100 - } - headerAdapter.clearChips() - if (total > limit) { - val arr = chapters.keys.toTypedArray() - val stored = ceil((total).toDouble() / limit).toInt() - val position = clamp(media.selected!!.chip, 0, stored - 1) - val last = if (position + 1 == stored) total else (limit * (position + 1)) - start = limit * (position) - end = last - 1 - headerAdapter.updateChips( - limit, - arr, - (1..stored).toList().toTypedArray(), - position - ) - } + override fun onScanlatorsSelected() { + updateChapters() + } - headerAdapter.subscribeButton(true) - reload() + private fun updateChapters() { + val loadedChapters = model.getMangaChapters().value + if (loadedChapters != null) { + val chapters = loadedChapters[media.selected!!.sourceIndex] + if (chapters != null) { + headerAdapter.options = getScanlators(chapters) + val filteredChapters = chapters.filterNot { (_, chapter) -> + chapter.scanlator in headerAdapter.hiddenScanlators } + + media.manga?.chapters = filteredChapters.toMutableMap() + + //CHIP GROUP + val total = filteredChapters.size + val divisions = total.toDouble() / 10 + start = 0 + end = null + val limit = when { + (divisions < 25) -> 25 + (divisions < 50) -> 50 + else -> 100 + } + headerAdapter.clearChips() + if (total > limit) { + val arr = filteredChapters.keys.toTypedArray() + val stored = ceil((total).toDouble() / limit).toInt() + val position = clamp(media.selected!!.chip, 0, stored - 1) + val last = if (position + 1 == stored) total else (limit * (position + 1)) + start = limit * (position) + end = last - 1 + headerAdapter.updateChips( + limit, + arr, + (1..stored).toList().toTypedArray(), + position + ) + } + + headerAdapter.subscribeButton(true) + reload() } } } + fun getScanlators(chap: MutableMap?): List { + val scanlators = mutableListOf() + if (chap != null) { + val chapters = chap.values + for (chapter in chapters) { + scanlators.add(chapter.scanlator ?: "Unknown") + } + } + return scanlators.distinct() + } + fun onSourceChange(i: Int): MangaParser { media.manga?.chapters = null reload() @@ -453,7 +479,7 @@ open class MangaReadFragment : Fragment() { ACTION_DOWNLOAD_PROGRESS -> { val chapterNumber = intent.getStringExtra(EXTRA_CHAPTER_NUMBER) val progress = intent.getIntExtra("progress", 0) - //chapterNumber?.let { chapterAdapter.updateDownloadProgress(it, progress) } + chapterNumber?.let { chapterAdapter.updateDownloadProgress(it, progress) } } } diff --git a/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt b/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt index e02dd933..18d5fce1 100644 --- a/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt +++ b/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt @@ -532,8 +532,9 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() { return MangaChapter( sChapter.name, sChapter.url, - "", + sChapter.name, null, + sChapter.scanlator, sChapter ) } diff --git a/app/src/main/java/ani/dantotsu/parsers/MangaParser.kt b/app/src/main/java/ani/dantotsu/parsers/MangaParser.kt index 0500cc32..ed481c9d 100644 --- a/app/src/main/java/ani/dantotsu/parsers/MangaParser.kt +++ b/app/src/main/java/ani/dantotsu/parsers/MangaParser.kt @@ -67,7 +67,7 @@ data class MangaChapter( //Self-Descriptive val title: String? = null, val description: String? = null, - + val scanlator: String? = null, val sChapter: SChapter, ) diff --git a/app/src/main/java/ani/dantotsu/parsers/OfflineMangaParser.kt b/app/src/main/java/ani/dantotsu/parsers/OfflineMangaParser.kt index 1340160a..50e3fed3 100644 --- a/app/src/main/java/ani/dantotsu/parsers/OfflineMangaParser.kt +++ b/app/src/main/java/ani/dantotsu/parsers/OfflineMangaParser.kt @@ -3,6 +3,7 @@ package ani.dantotsu.parsers import android.os.Environment import ani.dantotsu.currContext import ani.dantotsu.download.DownloadsManager +import ani.dantotsu.media.manga.MangaNameAdapter import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import me.xdrop.fuzzywuzzy.FuzzySearch @@ -30,10 +31,11 @@ class OfflineMangaParser: MangaParser() { if (directory.exists()) { directory.listFiles()?.forEach { if (it.isDirectory) { - val chapter = MangaChapter(it.name, "$mangaLink/${it.name}", it.name, null, SChapter.create()) + val chapter = MangaChapter(it.name, "$mangaLink/${it.name}", it.name, null, null, SChapter.create()) chapters.add(chapter) } } + chapters.sortBy { MangaNameAdapter.findChapterNumber(it.number) } return chapters } return emptyList() diff --git a/app/src/main/java/ani/dantotsu/settings/SettingsActivity.kt b/app/src/main/java/ani/dantotsu/settings/SettingsActivity.kt index 24702c5a..651ad8e6 100644 --- a/app/src/main/java/ani/dantotsu/settings/SettingsActivity.kt +++ b/app/src/main/java/ani/dantotsu/settings/SettingsActivity.kt @@ -170,7 +170,7 @@ OS Version: $CODENAME $RELEASE ($SDK_INT) binding.skipExtensionIcons.setOnCheckedChangeListener { _, isChecked -> saveData("skip_extension_icons", isChecked) } - binding.NSFWExtension.isChecked = loadData("NFSWExtension") ?: false + binding.NSFWExtension.isChecked = loadData("NFSWExtension") ?: true binding.NSFWExtension.setOnCheckedChangeListener { _, isChecked -> saveData("NFSWExtension", isChecked) diff --git a/app/src/main/java/ani/dantotsu/settings/paging/AnimePagingSource.kt b/app/src/main/java/ani/dantotsu/settings/paging/AnimePagingSource.kt index 5bba24f0..7761ed2e 100644 --- a/app/src/main/java/ani/dantotsu/settings/paging/AnimePagingSource.kt +++ b/app/src/main/java/ani/dantotsu/settings/paging/AnimePagingSource.kt @@ -78,7 +78,7 @@ class AnimeExtensionPagingSource( val installedExtensions = installedExtensionsFlow.first().map { it.pkgName }.toSet() val availableExtensions = availableExtensionsFlow.first().filterNot { it.pkgName in installedExtensions } val query = searchQuery.first() - var isNsfwEnabled: Boolean = loadData("NFSWExtension") ?: false + var isNsfwEnabled: Boolean = loadData("NFSWExtension") ?: true val filteredExtensions = if (query.isEmpty()) { availableExtensions } else { diff --git a/app/src/main/res/layout/activity_container.xml b/app/src/main/res/layout/activity_container.xml index 1d249e3e..5e87e267 100644 --- a/app/src/main/res/layout/activity_container.xml +++ b/app/src/main/res/layout/activity_container.xml @@ -1,5 +1,6 @@ diff --git a/app/src/main/res/layout/activity_no_internet.xml b/app/src/main/res/layout/activity_no_internet.xml index 2847ee2e..eaeac199 100644 --- a/app/src/main/res/layout/activity_no_internet.xml +++ b/app/src/main/res/layout/activity_no_internet.xml @@ -20,6 +20,7 @@ diff --git a/app/src/main/res/layout/custom_dialog_layout.xml b/app/src/main/res/layout/custom_dialog_layout.xml new file mode 100644 index 00000000..1cd9e7de --- /dev/null +++ b/app/src/main/res/layout/custom_dialog_layout.xml @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_manga_offline.xml b/app/src/main/res/layout/fragment_manga_offline.xml index 663c2e2f..3972cd2a 100644 --- a/app/src/main/res/layout/fragment_manga_offline.xml +++ b/app/src/main/res/layout/fragment_manga_offline.xml @@ -6,8 +6,7 @@ android:layout_height="match_parent" tools:context=".home.MangaFragment"> - - + android:layout_margin="32dp" + android:orientation="horizontal"> + + + + + + + + + + + + + - + + + @@ -91,7 +92,7 @@ android:id="@+id/itemEpisodeViewed" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="end" + android:layout_gravity="start" android:layout_margin="8dp" android:visibility="gone" app:srcCompat="@drawable/ic_round_remove_red_eye_24"