diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index fdab5a4c..e3ff41fa 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -73,12 +73,24 @@
android:resource="@xml/upcoming_widget_info" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
"sub"
+ SubDubType.DUB -> "dub"
+ SubDubType.NULL -> ""
+ }
+ val toggledCasePreserved =
+ if (subdub?.get(0)?.isUpperCase() == true || soft?.get(0)
+ ?.isUpperCase() == true
+ ) toggled.replaceFirstChar {
+ if (it.isLowerCase()) it.titlecase(
+ Locale.ROOT
+ ) else it.toString()
+ } else toggled
+
+ subdubMatcher.replaceFirst(toggledCasePreserved + bed)
+ } else {
+ null
+ }
+ }
+
+ fun getSubDub(text: String): SubDubType {
+ val subdubPattern: Pattern = Pattern.compile(REGEX_SUBDUB, Pattern.CASE_INSENSITIVE)
+ val subdubMatcher: Matcher = subdubPattern.matcher(text)
+
+ return if (subdubMatcher.find()) {
+ val subdub = subdubMatcher.group(2)?.lowercase(Locale.ROOT)
+ when (subdub) {
+ "sub" -> SubDubType.SUB
+ "dub" -> SubDubType.DUB
+ else -> SubDubType.NULL
+ }
+ } else {
+ SubDubType.NULL
+ }
+ }
+
+ enum class SubDubType {
+ SUB, DUB, NULL
+ }
+
+ fun findSeasonNumber(text: String): Int? {
+ val seasonPattern: Pattern = Pattern.compile(REGEX_SEASON, Pattern.CASE_INSENSITIVE)
+ val seasonMatcher: Matcher = seasonPattern.matcher(text)
+
+ return if (seasonMatcher.find()) {
+ seasonMatcher.group(2)?.toInt()
+ } else {
+ null
+ }
+ }
+
+ fun findEpisodeNumber(text: String): Float? {
+ val episodePattern: Pattern = Pattern.compile(REGEX_EPISODE, Pattern.CASE_INSENSITIVE)
+ val episodeMatcher: Matcher = episodePattern.matcher(text)
+
+ return if (episodeMatcher.find()) {
+ if (episodeMatcher.group(2) != null) {
+ episodeMatcher.group(2)?.toFloat()
+ } else {
+ val failedEpisodeNumberPattern: Pattern =
+ Pattern.compile(REGEX_PART_NUMBER, Pattern.CASE_INSENSITIVE)
+ val failedEpisodeNumberMatcher: Matcher =
+ failedEpisodeNumberPattern.matcher(text)
+ if (failedEpisodeNumberMatcher.find()) {
+ failedEpisodeNumberMatcher.group(1)?.toFloat()
+ } else {
+ null
+ }
+ }
+ } else {
+ null
+ }
+ }
+
+ fun removeEpisodeNumber(text: String): String {
+ val regexPattern = Regex(REGEX_EPISODE, RegexOption.IGNORE_CASE)
+ val removedNumber = text.replace(regexPattern, "").ifEmpty {
+ text
+ }
+ val letterPattern = Regex("[a-zA-Z]")
+ return if (letterPattern.containsMatchIn(removedNumber)) {
+ removedNumber
+ } else {
+ text
+ }
+ }
+
+
+ fun removeEpisodeNumberCompletely(text: String): String {
+ val regexPattern = Regex(REGEX_EPISODE, RegexOption.IGNORE_CASE)
+ val removedNumber = text.replace(regexPattern, "")
+ return if (removedNumber.equals(text, true)) { // if nothing was removed
+ val failedEpisodeNumberPattern =
+ Regex(REGEX_PART_NUMBER, RegexOption.IGNORE_CASE)
+ failedEpisodeNumberPattern.replace(removedNumber) { mr ->
+ mr.value.replaceFirst(mr.groupValues[1], "")
+ }
+ } else {
+ removedNumber
+ }
+ }
+
+ fun findChapterNumber(text: String): Float? {
+ val pattern: Pattern = Pattern.compile(REGEX_CHAPTER, Pattern.CASE_INSENSITIVE)
+ val matcher: Matcher = pattern.matcher(text)
+
+ return if (matcher.find()) {
+ matcher.group(2)?.toFloat()
+ } else {
+ val failedChapterNumberPattern: Pattern =
+ Pattern.compile(REGEX_PART_NUMBER, Pattern.CASE_INSENSITIVE)
+ val failedChapterNumberMatcher: Matcher =
+ failedChapterNumberPattern.matcher(text)
+ if (failedChapterNumberMatcher.find()) {
+ failedChapterNumberMatcher.group(1)?.toFloat()
+ } else {
+ null
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/media/anime/AnimeNameAdapter.kt b/app/src/main/java/ani/dantotsu/media/anime/AnimeNameAdapter.kt
deleted file mode 100644
index 16142902..00000000
--- a/app/src/main/java/ani/dantotsu/media/anime/AnimeNameAdapter.kt
+++ /dev/null
@@ -1,127 +0,0 @@
-package ani.dantotsu.media.anime
-
-import java.util.Locale
-import java.util.regex.Matcher
-import java.util.regex.Pattern
-
-class AnimeNameAdapter {
- companion object {
- const val episodeRegex =
- "(episode|episodio|ep|e)[\\s:.\\-]*(\\d+\\.?\\d*)[\\s:.\\-]*\\(?\\s*(sub|subbed|dub|dubbed)*\\s*\\)?\\s*"
- const val failedEpisodeNumberRegex =
- "(? "sub"
- SubDubType.DUB -> "dub"
- SubDubType.NULL -> ""
- }
- val toggledCasePreserved =
- if (subdub?.get(0)?.isUpperCase() == true || soft?.get(0)
- ?.isUpperCase() == true
- ) toggled.replaceFirstChar {
- if (it.isLowerCase()) it.titlecase(
- Locale.ROOT
- ) else it.toString()
- } else toggled
-
- subdubMatcher.replaceFirst(toggledCasePreserved + bed)
- } else {
- null
- }
- }
-
- fun getSubDub(text: String): SubDubType {
- val subdubPattern: Pattern = Pattern.compile(subdubRegex, Pattern.CASE_INSENSITIVE)
- val subdubMatcher: Matcher = subdubPattern.matcher(text)
-
- return if (subdubMatcher.find()) {
- val subdub = subdubMatcher.group(2)?.lowercase(Locale.ROOT)
- when (subdub) {
- "sub" -> SubDubType.SUB
- "dub" -> SubDubType.DUB
- else -> SubDubType.NULL
- }
- } else {
- SubDubType.NULL
- }
- }
-
- enum class SubDubType {
- SUB, DUB, NULL
- }
-
- fun findSeasonNumber(text: String): Int? {
- val seasonPattern: Pattern = Pattern.compile(seasonRegex, Pattern.CASE_INSENSITIVE)
- val seasonMatcher: Matcher = seasonPattern.matcher(text)
-
- return if (seasonMatcher.find()) {
- seasonMatcher.group(2)?.toInt()
- } else {
- null
- }
- }
-
- fun findEpisodeNumber(text: String): Float? {
- val episodePattern: Pattern = Pattern.compile(episodeRegex, Pattern.CASE_INSENSITIVE)
- val episodeMatcher: Matcher = episodePattern.matcher(text)
-
- return if (episodeMatcher.find()) {
- if (episodeMatcher.group(2) != null) {
- episodeMatcher.group(2)?.toFloat()
- } else {
- val failedEpisodeNumberPattern: Pattern =
- Pattern.compile(failedEpisodeNumberRegex, Pattern.CASE_INSENSITIVE)
- val failedEpisodeNumberMatcher: Matcher =
- failedEpisodeNumberPattern.matcher(text)
- if (failedEpisodeNumberMatcher.find()) {
- failedEpisodeNumberMatcher.group(1)?.toFloat()
- } else {
- null
- }
- }
- } else {
- null
- }
- }
-
- fun removeEpisodeNumber(text: String): String {
- val regexPattern = Regex(episodeRegex, RegexOption.IGNORE_CASE)
- val removedNumber = text.replace(regexPattern, "").ifEmpty {
- text
- }
- val letterPattern = Regex("[a-zA-Z]")
- return if (letterPattern.containsMatchIn(removedNumber)) {
- removedNumber
- } else {
- text
- }
- }
-
-
- fun removeEpisodeNumberCompletely(text: String): String {
- val regexPattern = Regex(episodeRegex, RegexOption.IGNORE_CASE)
- val removedNumber = text.replace(regexPattern, "")
- return if (removedNumber.equals(text, true)) { // if nothing was removed
- val failedEpisodeNumberPattern =
- Regex(failedEpisodeNumberRegex, RegexOption.IGNORE_CASE)
- failedEpisodeNumberPattern.replace(removedNumber) { mr ->
- mr.value.replaceFirst(mr.groupValues[1], "")
- }
- } else {
- removedNumber
- }
- }
- }
-}
diff --git a/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchAdapter.kt b/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchAdapter.kt
index 792a687c..14c73770 100644
--- a/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchAdapter.kt
@@ -26,6 +26,7 @@ import ani.dantotsu.isOnline
import ani.dantotsu.loadImage
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsActivity
+import ani.dantotsu.media.MediaNameAdapter
import ani.dantotsu.media.SourceSearchDialogFragment
import ani.dantotsu.openSettings
import ani.dantotsu.others.LanguageMapper
@@ -403,7 +404,7 @@ class AnimeWatchAdapter(
}
val ep = media.anime.episodes!![continueEp]!!
- val cleanedTitle = ep.title?.let { AnimeNameAdapter.removeEpisodeNumber(it) }
+ val cleanedTitle = ep.title?.let { MediaNameAdapter.removeEpisodeNumber(it) }
binding.itemEpisodeImage.loadImage(
ep.thumb ?: FileUrl[media.banner ?: media.cover], 0
diff --git a/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchFragment.kt b/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchFragment.kt
index f02a556d..8298318c 100644
--- a/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchFragment.kt
+++ b/app/src/main/java/ani/dantotsu/media/anime/AnimeWatchFragment.kt
@@ -41,6 +41,7 @@ import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsActivity
import ani.dantotsu.media.MediaDetailsViewModel
import ani.dantotsu.media.MediaType
+import ani.dantotsu.media.MediaNameAdapter
import ani.dantotsu.navBarHeight
import ani.dantotsu.notifications.subscription.SubscriptionHelper
import ani.dantotsu.notifications.subscription.SubscriptionHelper.Companion.saveSubscription
@@ -224,7 +225,7 @@ class AnimeWatchFragment : Fragment() {
if (media.anime!!.kitsuEpisodes!!.containsKey(i)) {
episode.desc =
media.anime!!.kitsuEpisodes!![i]?.desc ?: episode.desc
- episode.title = if (AnimeNameAdapter.removeEpisodeNumberCompletely(
+ episode.title = if (MediaNameAdapter.removeEpisodeNumberCompletely(
episode.title ?: ""
).isBlank()
) media.anime!!.kitsuEpisodes!![i]?.title
diff --git a/app/src/main/java/ani/dantotsu/media/anime/EpisodeAdapters.kt b/app/src/main/java/ani/dantotsu/media/anime/EpisodeAdapters.kt
index 21f3e439..68d3aabd 100644
--- a/app/src/main/java/ani/dantotsu/media/anime/EpisodeAdapters.kt
+++ b/app/src/main/java/ani/dantotsu/media/anime/EpisodeAdapters.kt
@@ -21,6 +21,7 @@ import ani.dantotsu.databinding.ItemEpisodeListBinding
import ani.dantotsu.download.anime.AnimeDownloaderService
import ani.dantotsu.download.video.Helper
import ani.dantotsu.media.Media
+import ani.dantotsu.media.MediaNameAdapter
import ani.dantotsu.setAnimation
import ani.dantotsu.settings.saving.PrefManager
import com.bumptech.glide.Glide
@@ -102,7 +103,7 @@ class EpisodeAdapter(
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val ep = arr[position]
val title = if (!ep.title.isNullOrEmpty() && ep.title != "null") {
- ep.title?.let { AnimeNameAdapter.removeEpisodeNumber(it) }
+ ep.title?.let { MediaNameAdapter.removeEpisodeNumber(it) }
} else {
ep.number
} ?: ""
diff --git a/app/src/main/java/ani/dantotsu/media/anime/ExoplayerView.kt b/app/src/main/java/ani/dantotsu/media/anime/ExoplayerView.kt
index df031443..0ca02de7 100644
--- a/app/src/main/java/ani/dantotsu/media/anime/ExoplayerView.kt
+++ b/app/src/main/java/ani/dantotsu/media/anime/ExoplayerView.kt
@@ -113,6 +113,7 @@ import ani.dantotsu.isOnline
import ani.dantotsu.logError
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsViewModel
+import ani.dantotsu.media.MediaNameAdapter
import ani.dantotsu.media.SubtitleDownloader
import ani.dantotsu.okHttpClient
import ani.dantotsu.others.AniSkip
@@ -998,7 +999,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
episodeTitleArr = arrayListOf()
episodes.forEach {
val episode = it.value
- val cleanedTitle = AnimeNameAdapter.removeEpisodeNumberCompletely(episode.title ?: "")
+ val cleanedTitle = MediaNameAdapter.removeEpisodeNumberCompletely(episode.title ?: "")
episodeTitleArr.add("Episode ${episode.number}${if (episode.filler) " [Filler]" else ""}${if (cleanedTitle.isNotBlank() && cleanedTitle != "null") ": $cleanedTitle" else ""}")
}
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 19d039f5..393d87b9 100644
--- a/app/src/main/java/ani/dantotsu/media/manga/MangaChapterAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/media/manga/MangaChapterAdapter.kt
@@ -15,6 +15,7 @@ import ani.dantotsu.currContext
import ani.dantotsu.databinding.ItemChapterListBinding
import ani.dantotsu.databinding.ItemEpisodeCompactBinding
import ani.dantotsu.media.Media
+import ani.dantotsu.media.MediaNameAdapter
import ani.dantotsu.setAnimation
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@@ -267,10 +268,10 @@ class MangaChapterAdapter(
val binding = holder.binding
setAnimation(fragment.requireContext(), holder.binding.root)
val ep = arr[position]
- val parsedNumber = MangaNameAdapter.findChapterNumber(ep.number)?.toInt()
+ val parsedNumber = MediaNameAdapter.findChapterNumber(ep.number)?.toInt()
binding.itemEpisodeNumber.text = parsedNumber?.toString() ?: ep.number
if (media.userProgress != null) {
- if ((MangaNameAdapter.findChapterNumber(ep.number)
+ if ((MediaNameAdapter.findChapterNumber(ep.number)
?: 9999f) <= media.userProgress!!.toFloat()
)
binding.itemEpisodeViewedCover.visibility = View.VISIBLE
@@ -279,7 +280,7 @@ class MangaChapterAdapter(
binding.itemEpisodeCont.setOnLongClickListener {
updateProgress(
media,
- MangaNameAdapter.findChapterNumber(ep.number).toString()
+ MediaNameAdapter.findChapterNumber(ep.number).toString()
)
true
}
@@ -315,7 +316,7 @@ class MangaChapterAdapter(
} else binding.itemChapterTitle.visibility = View.VISIBLE
if (media.userProgress != null) {
- if ((MangaNameAdapter.findChapterNumber(ep.number)
+ if ((MediaNameAdapter.findChapterNumber(ep.number)
?: 9999f) <= media.userProgress!!.toFloat()
) {
binding.itemEpisodeViewedCover.visibility = View.VISIBLE
@@ -326,7 +327,7 @@ class MangaChapterAdapter(
binding.root.setOnLongClickListener {
updateProgress(
media,
- MangaNameAdapter.findChapterNumber(ep.number).toString()
+ MediaNameAdapter.findChapterNumber(ep.number).toString()
)
true
}
diff --git a/app/src/main/java/ani/dantotsu/media/manga/MangaNameAdapter.kt b/app/src/main/java/ani/dantotsu/media/manga/MangaNameAdapter.kt
deleted file mode 100644
index d265b69a..00000000
--- a/app/src/main/java/ani/dantotsu/media/manga/MangaNameAdapter.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package ani.dantotsu.media.manga
-
-import java.util.regex.Matcher
-import java.util.regex.Pattern
-
-class MangaNameAdapter {
- companion object {
- private const val chapterRegex = "(chapter|chap|ch|c)[\\s:.\\-]*(\\d+\\.?\\d*)[\\s:.\\-]*"
- private const val filedChapterNumberRegex = "(?
- return when (AnimeNameAdapter.getSubDub(value.value.toString())) {
- AnimeNameAdapter.Companion.SubDubType.SUB -> false
- AnimeNameAdapter.Companion.SubDubType.DUB -> true
- AnimeNameAdapter.Companion.SubDubType.NULL -> false
+ return when (MediaNameAdapter.getSubDub(value.value.toString())) {
+ MediaNameAdapter.SubDubType.SUB -> false
+ MediaNameAdapter.SubDubType.DUB -> true
+ MediaNameAdapter.SubDubType.NULL -> false
}
}
}
@@ -92,8 +92,8 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
val configurableSource = extension.sources[sourceLanguage] as? ConfigurableAnimeSource
?: return
val type = when (setDub) {
- true -> AnimeNameAdapter.Companion.SubDubType.DUB
- false -> AnimeNameAdapter.Companion.SubDubType.SUB
+ true -> MediaNameAdapter.SubDubType.DUB
+ false -> MediaNameAdapter.SubDubType.SUB
}
currContext()?.let { context ->
val sharedPreferences =
@@ -101,9 +101,9 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
configurableSource.getPreferenceKey(),
Context.MODE_PRIVATE
)
- sharedPreferences.all.filterValues { AnimeNameAdapter.getSubDub(it.toString()) != AnimeNameAdapter.Companion.SubDubType.NULL }
+ sharedPreferences.all.filterValues { MediaNameAdapter.getSubDub(it.toString()) != MediaNameAdapter.SubDubType.NULL }
.forEach { value ->
- val setValue = AnimeNameAdapter.setSubDub(value.value.toString(), type)
+ val setValue = MediaNameAdapter.setSubDub(value.value.toString(), type)
if (setValue != null) {
sharedPreferences.edit().putString(value.key, setValue).apply()
}
@@ -122,9 +122,9 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
Context.MODE_PRIVATE
)
sharedPreferences.all.filterValues {
- AnimeNameAdapter.setSubDub(
+ MediaNameAdapter.setSubDub(
it.toString(),
- AnimeNameAdapter.Companion.SubDubType.NULL
+ MediaNameAdapter.SubDubType.NULL
) != null
}
.forEach { _ -> return true }
@@ -150,7 +150,7 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
val sortedEpisodes = if (res[0].episode_number == -1f) {
// Find the number in the string and sort by that number
val sortedByStringNumber = res.sortedBy {
- val matchResult = AnimeNameAdapter.findEpisodeNumber(it.name)
+ val matchResult = MediaNameAdapter.findEpisodeNumber(it.name)
val number = matchResult ?: Float.MAX_VALUE
it.episode_number = number // Store the found number in episode_number
number
@@ -171,13 +171,13 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
var episodeCounter = 1f
// Group by season, sort within each season, and then renumber while keeping episode number 0 as is
val seasonGroups =
- res.groupBy { AnimeNameAdapter.findSeasonNumber(it.name) ?: 0 }
+ res.groupBy { MediaNameAdapter.findSeasonNumber(it.name) ?: 0 }
seasonGroups.keys.sortedBy { it }
.flatMap { season ->
seasonGroups[season]?.sortedBy { it.episode_number }?.map { episode ->
if (episode.episode_number != 0f) { // Skip renumbering for episode number 0
val potentialNumber =
- AnimeNameAdapter.findEpisodeNumber(episode.name)
+ MediaNameAdapter.findEpisodeNumber(episode.name)
if (potentialNumber != null) {
episode.episode_number = potentialNumber
} else {
diff --git a/app/src/main/java/ani/dantotsu/parsers/MangaParser.kt b/app/src/main/java/ani/dantotsu/parsers/MangaParser.kt
index cd757307..bf67a8ca 100644
--- a/app/src/main/java/ani/dantotsu/parsers/MangaParser.kt
+++ b/app/src/main/java/ani/dantotsu/parsers/MangaParser.kt
@@ -1,7 +1,7 @@
package ani.dantotsu.parsers
import ani.dantotsu.FileUrl
-import ani.dantotsu.media.manga.MangaNameAdapter
+import ani.dantotsu.media.MediaNameAdapter
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
@@ -33,9 +33,9 @@ abstract class MangaParser : BaseParser() {
): MangaChapter? {
val chapter = loadChapters(mangaLink, extra, sManga)
val max = chapter
- .maxByOrNull { MangaNameAdapter.findChapterNumber(it.number) ?: 0f }
+ .maxByOrNull { MediaNameAdapter.findChapterNumber(it.number) ?: 0f }
return max
- ?.takeIf { latest < (MangaNameAdapter.findChapterNumber(it.number) ?: 0.001f) }
+ ?.takeIf { latest < (MediaNameAdapter.findChapterNumber(it.number) ?: 0.001f) }
}
/**
diff --git a/app/src/main/java/ani/dantotsu/parsers/OfflineAnimeParser.kt b/app/src/main/java/ani/dantotsu/parsers/OfflineAnimeParser.kt
index 57098894..582419c9 100644
--- a/app/src/main/java/ani/dantotsu/parsers/OfflineAnimeParser.kt
+++ b/app/src/main/java/ani/dantotsu/parsers/OfflineAnimeParser.kt
@@ -5,7 +5,7 @@ import android.os.Environment
import ani.dantotsu.currContext
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.media.MediaType
-import ani.dantotsu.media.anime.AnimeNameAdapter
+import ani.dantotsu.media.MediaNameAdapter
import ani.dantotsu.tryWithSuspend
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
@@ -54,7 +54,7 @@ class OfflineAnimeParser : AnimeParser() {
episodes.add(episode)
}
}
- episodes.sortBy { AnimeNameAdapter.findEpisodeNumber(it.number) }
+ episodes.sortBy { MediaNameAdapter.findEpisodeNumber(it.number) }
return episodes
}
return emptyList()
diff --git a/app/src/main/java/ani/dantotsu/parsers/OfflineMangaParser.kt b/app/src/main/java/ani/dantotsu/parsers/OfflineMangaParser.kt
index 29149873..983a53ec 100644
--- a/app/src/main/java/ani/dantotsu/parsers/OfflineMangaParser.kt
+++ b/app/src/main/java/ani/dantotsu/parsers/OfflineMangaParser.kt
@@ -3,7 +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 ani.dantotsu.media.MediaNameAdapter
import ani.dantotsu.util.Logger
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
@@ -43,7 +43,7 @@ class OfflineMangaParser : MangaParser() {
chapters.add(chapter)
}
}
- chapters.sortBy { MangaNameAdapter.findChapterNumber(it.number) }
+ chapters.sortBy { MediaNameAdapter.findChapterNumber(it.number) }
return chapters
}
return emptyList()
diff --git a/app/src/main/java/ani/dantotsu/parsers/OfflineNovelParser.kt b/app/src/main/java/ani/dantotsu/parsers/OfflineNovelParser.kt
index 534c3ac5..11009aed 100644
--- a/app/src/main/java/ani/dantotsu/parsers/OfflineNovelParser.kt
+++ b/app/src/main/java/ani/dantotsu/parsers/OfflineNovelParser.kt
@@ -3,7 +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 ani.dantotsu.media.MediaNameAdapter
import me.xdrop.fuzzywuzzy.FuzzySearch
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@@ -38,7 +38,7 @@ class OfflineNovelParser : NovelParser() {
chapters.add(chapter)
}
}
- chapters.sortBy { MangaNameAdapter.findChapterNumber(it.name) }
+ chapters.sortBy { MediaNameAdapter.findChapterNumber(it.name) }
return chapters.first()
}
return Book(
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt b/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt
index 0b35f047..42ee6973 100644
--- a/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt
+++ b/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt
@@ -21,7 +21,7 @@ import nl.joery.animatedbottombar.AnimatedBottomBar
class FeedActivity : AppCompatActivity() {
private lateinit var binding: ActivityFeedBinding
private var selected: Int = 0
- private lateinit var navBar: AnimatedBottomBar
+ lateinit var navBar: AnimatedBottomBar
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/FeedFragment.kt b/app/src/main/java/ani/dantotsu/profile/activity/FeedFragment.kt
index f50502f1..40c96829 100644
--- a/app/src/main/java/ani/dantotsu/profile/activity/FeedFragment.kt
+++ b/app/src/main/java/ani/dantotsu/profile/activity/FeedFragment.kt
@@ -50,16 +50,21 @@ class FeedFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
activity = requireActivity()
- binding.listRecyclerView.setBaseline((activity as ProfileActivity).navBar)
+ userId = arguments?.getInt("userId", -1)
+ activityId = arguments?.getInt("activityId", -1) ?: -1
+ if (userId == -1) userId = null
+ global = arguments?.getBoolean("global", false) ?: false
+
+ val navBar = if (userId != null)
+ (activity as ProfileActivity).navBar
+ else
+ (activity as FeedActivity).navBar
+ binding.listRecyclerView.setBaseline(navBar)
binding.listRecyclerView.adapter = adapter
binding.listRecyclerView.layoutManager =
LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
binding.listProgressBar.visibility = ViewGroup.VISIBLE
- userId = arguments?.getInt("userId", -1)
- activityId = arguments?.getInt("activityId", -1) ?: -1
- if (userId == -1) userId = null
- global = arguments?.getBoolean("global", false) ?: false
}
@SuppressLint("ClickableViewAccessibility")
@@ -67,7 +72,11 @@ class FeedFragment : Fragment() {
super.onResume()
if (this::binding.isInitialized) {
binding.root.requestLayout()
- binding.listRecyclerView.setBaseline((activity as ProfileActivity).navBar)
+ val navBar = if (userId != null)
+ (activity as ProfileActivity).navBar
+ else
+ (activity as FeedActivity).navBar
+ binding.listRecyclerView.setBaseline(navBar)
if (!loadedFirstTime) {
activity.lifecycleScope.launch(Dispatchers.IO) {
val nulledId = if (activityId == -1) null else activityId
diff --git a/app/src/main/java/ani/dantotsu/settings/AnimeExtensionsFragment.kt b/app/src/main/java/ani/dantotsu/settings/AnimeExtensionsFragment.kt
index a6d6c39e..fe7b81d2 100644
--- a/app/src/main/java/ani/dantotsu/settings/AnimeExtensionsFragment.kt
+++ b/app/src/main/java/ani/dantotsu/settings/AnimeExtensionsFragment.kt
@@ -13,7 +13,7 @@ import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import ani.dantotsu.R
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
-import ani.dantotsu.databinding.FragmentAnimeExtensionsBinding
+import ani.dantotsu.databinding.FragmentExtensionsBinding
import ani.dantotsu.settings.paging.AnimeExtensionAdapter
import ani.dantotsu.settings.paging.AnimeExtensionsViewModel
import ani.dantotsu.settings.paging.AnimeExtensionsViewModelFactory
@@ -30,7 +30,7 @@ import uy.kohesive.injekt.api.get
class AnimeExtensionsFragment : Fragment(),
SearchQueryHandler, OnAnimeInstallClickListener {
- private var _binding: FragmentAnimeExtensionsBinding? = null
+ private var _binding: FragmentExtensionsBinding? = null
private val binding get() = _binding!!
private val viewModel: AnimeExtensionsViewModel by viewModels {
@@ -48,12 +48,12 @@ class AnimeExtensionsFragment : Fragment(),
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
- _binding = FragmentAnimeExtensionsBinding.inflate(inflater, container, false)
+ _binding = FragmentExtensionsBinding.inflate(inflater, container, false)
- binding.allAnimeExtensionsRecyclerView.isNestedScrollingEnabled = false
- binding.allAnimeExtensionsRecyclerView.adapter = adapter
- binding.allAnimeExtensionsRecyclerView.layoutManager = LinearLayoutManager(context)
- (binding.allAnimeExtensionsRecyclerView.layoutManager as LinearLayoutManager).isItemPrefetchEnabled =
+ binding.allExtensionsRecyclerView.isNestedScrollingEnabled = false
+ binding.allExtensionsRecyclerView.adapter = adapter
+ binding.allExtensionsRecyclerView.layoutManager = LinearLayoutManager(context)
+ (binding.allExtensionsRecyclerView.layoutManager as LinearLayoutManager).isItemPrefetchEnabled =
true
lifecycleScope.launch {
@@ -91,8 +91,8 @@ class AnimeExtensionsFragment : Fragment(),
Notifications.CHANNEL_DOWNLOADER_PROGRESS
)
.setSmallIcon(R.drawable.ic_round_sync_24)
- .setContentTitle("Installing extension")
- .setContentText("Step: $installStep")
+ .setContentTitle(getString(R.string.installing_extension))
+ .setContentText(getString(R.string.install_step, installStep))
.setPriority(NotificationCompat.PRIORITY_LOW)
notificationManager.notify(1, builder.build())
},
@@ -103,11 +103,11 @@ class AnimeExtensionsFragment : Fragment(),
Notifications.CHANNEL_DOWNLOADER_ERROR
)
.setSmallIcon(R.drawable.ic_round_info_24)
- .setContentTitle("Installation failed: ${error.message}")
- .setContentText("Error: ${error.message}")
+ .setContentTitle(getString(R.string.installation_failed, error.message))
+ .setContentText(getString(R.string.error_message, error.message))
.setPriority(NotificationCompat.PRIORITY_HIGH)
notificationManager.notify(1, builder.build())
- snackString("Installation failed: ${error.message}")
+ snackString(getString(R.string.installation_failed, error.message))
},
{
val builder = NotificationCompat.Builder(
@@ -115,12 +115,12 @@ class AnimeExtensionsFragment : Fragment(),
Notifications.CHANNEL_DOWNLOADER_PROGRESS
)
.setSmallIcon(R.drawable.ic_download_24)
- .setContentTitle("Installation complete")
- .setContentText("The extension has been successfully installed.")
+ .setContentTitle(getString(R.string.installation_complete))
+ .setContentText(getString(R.string.extension_has_been_installed))
.setPriority(NotificationCompat.PRIORITY_LOW)
notificationManager.notify(1, builder.build())
viewModel.invalidatePager()
- snackString("Extension installed")
+ snackString(getString(R.string.extension_installed))
}
)
}
diff --git a/app/src/main/java/ani/dantotsu/settings/InstalledAnimeExtensionsFragment.kt b/app/src/main/java/ani/dantotsu/settings/InstalledAnimeExtensionsFragment.kt
index e25fb822..3f1a3c49 100644
--- a/app/src/main/java/ani/dantotsu/settings/InstalledAnimeExtensionsFragment.kt
+++ b/app/src/main/java/ani/dantotsu/settings/InstalledAnimeExtensionsFragment.kt
@@ -24,7 +24,7 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import ani.dantotsu.R
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
-import ani.dantotsu.databinding.FragmentAnimeExtensionsBinding
+import ani.dantotsu.databinding.FragmentExtensionsBinding
import ani.dantotsu.others.LanguageMapper
import ani.dantotsu.parsers.AnimeSources
import ani.dantotsu.settings.extensionprefs.AnimeSourcePreferencesFragment
@@ -49,7 +49,7 @@ import java.util.Locale
class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
- private var _binding: FragmentAnimeExtensionsBinding? = null
+ private var _binding: FragmentExtensionsBinding? = null
private val binding get() = _binding!!
private lateinit var extensionsRecyclerView: RecyclerView
private val skipIcons: Boolean = PrefManager.getVal(PrefName.SkipExtensionIcons)
@@ -183,9 +183,9 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
- _binding = FragmentAnimeExtensionsBinding.inflate(inflater, container, false)
+ _binding = FragmentExtensionsBinding.inflate(inflater, container, false)
- extensionsRecyclerView = binding.allAnimeExtensionsRecyclerView
+ extensionsRecyclerView = binding.allExtensionsRecyclerView
extensionsRecyclerView.layoutManager = LinearLayoutManager(requireContext())
extensionsRecyclerView.adapter = extensionsAdapter
diff --git a/app/src/main/java/ani/dantotsu/settings/InstalledMangaExtensionsFragment.kt b/app/src/main/java/ani/dantotsu/settings/InstalledMangaExtensionsFragment.kt
index 24780ef5..90bfa771 100644
--- a/app/src/main/java/ani/dantotsu/settings/InstalledMangaExtensionsFragment.kt
+++ b/app/src/main/java/ani/dantotsu/settings/InstalledMangaExtensionsFragment.kt
@@ -26,7 +26,7 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import ani.dantotsu.R
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
-import ani.dantotsu.databinding.FragmentMangaExtensionsBinding
+import ani.dantotsu.databinding.FragmentExtensionsBinding
import ani.dantotsu.others.LanguageMapper
import ani.dantotsu.parsers.MangaSources
import ani.dantotsu.settings.extensionprefs.MangaSourcePreferencesFragment
@@ -48,7 +48,7 @@ import java.util.Collections
import java.util.Locale
class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
- private var _binding: FragmentMangaExtensionsBinding? = null
+ private var _binding: FragmentExtensionsBinding? = null
private val binding get() = _binding!!
private lateinit var extensionsRecyclerView: RecyclerView
private val skipIcons: Boolean = PrefManager.getVal(PrefName.SkipExtensionIcons)
@@ -181,9 +181,9 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
- _binding = FragmentMangaExtensionsBinding.inflate(inflater, container, false)
+ _binding = FragmentExtensionsBinding.inflate(inflater, container, false)
- extensionsRecyclerView = binding.allMangaExtensionsRecyclerView
+ extensionsRecyclerView = binding.allExtensionsRecyclerView
extensionsRecyclerView.layoutManager = LinearLayoutManager(requireContext())
extensionsRecyclerView.adapter = extensionsAdapter
diff --git a/app/src/main/java/ani/dantotsu/settings/MangaExtensionsFragment.kt b/app/src/main/java/ani/dantotsu/settings/MangaExtensionsFragment.kt
index 6f7276ad..c5118096 100644
--- a/app/src/main/java/ani/dantotsu/settings/MangaExtensionsFragment.kt
+++ b/app/src/main/java/ani/dantotsu/settings/MangaExtensionsFragment.kt
@@ -13,7 +13,7 @@ import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import ani.dantotsu.R
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
-import ani.dantotsu.databinding.FragmentMangaExtensionsBinding
+import ani.dantotsu.databinding.FragmentExtensionsBinding
import ani.dantotsu.settings.paging.MangaExtensionAdapter
import ani.dantotsu.settings.paging.MangaExtensionsViewModel
import ani.dantotsu.settings.paging.MangaExtensionsViewModelFactory
@@ -30,7 +30,7 @@ import uy.kohesive.injekt.api.get
class MangaExtensionsFragment : Fragment(),
SearchQueryHandler, OnMangaInstallClickListener {
- private var _binding: FragmentMangaExtensionsBinding? = null
+ private var _binding: FragmentExtensionsBinding? = null
private val binding get() = _binding!!
private val viewModel: MangaExtensionsViewModel by viewModels {
@@ -49,12 +49,12 @@ class MangaExtensionsFragment : Fragment(),
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
- _binding = FragmentMangaExtensionsBinding.inflate(inflater, container, false)
+ _binding = FragmentExtensionsBinding.inflate(inflater, container, false)
- binding.allMangaExtensionsRecyclerView.isNestedScrollingEnabled = false
- binding.allMangaExtensionsRecyclerView.adapter = adapter
- binding.allMangaExtensionsRecyclerView.layoutManager = LinearLayoutManager(context)
- (binding.allMangaExtensionsRecyclerView.layoutManager as LinearLayoutManager).isItemPrefetchEnabled =
+ binding.allExtensionsRecyclerView.isNestedScrollingEnabled = false
+ binding.allExtensionsRecyclerView.adapter = adapter
+ binding.allExtensionsRecyclerView.layoutManager = LinearLayoutManager(context)
+ (binding.allExtensionsRecyclerView.layoutManager as LinearLayoutManager).isItemPrefetchEnabled =
true
lifecycleScope.launch {
@@ -92,8 +92,8 @@ class MangaExtensionsFragment : Fragment(),
Notifications.CHANNEL_DOWNLOADER_PROGRESS
)
.setSmallIcon(R.drawable.ic_round_sync_24)
- .setContentTitle("Installing extension")
- .setContentText("Step: $installStep")
+ .setContentTitle(getString(R.string.installing_extension))
+ .setContentText(getString(R.string.install_step, installStep))
.setPriority(NotificationCompat.PRIORITY_LOW)
notificationManager.notify(1, builder.build())
},
@@ -104,11 +104,11 @@ class MangaExtensionsFragment : Fragment(),
Notifications.CHANNEL_DOWNLOADER_ERROR
)
.setSmallIcon(R.drawable.ic_round_info_24)
- .setContentTitle("Installation failed: ${error.message}")
- .setContentText("Error: ${error.message}")
+ .setContentTitle(getString(R.string.installation_failed, error.message))
+ .setContentText(getString(R.string.error_message, error.message))
.setPriority(NotificationCompat.PRIORITY_HIGH)
notificationManager.notify(1, builder.build())
- snackString("Installation failed: ${error.message}")
+ snackString(getString(R.string.installation_failed, error.message))
},
{
val builder = NotificationCompat.Builder(
@@ -116,12 +116,12 @@ class MangaExtensionsFragment : Fragment(),
Notifications.CHANNEL_DOWNLOADER_PROGRESS
)
.setSmallIcon(R.drawable.ic_download_24)
- .setContentTitle("Installation complete")
- .setContentText("The extension has been successfully installed.")
+ .setContentTitle(getString(R.string.installation_complete))
+ .setContentText(getString(R.string.extension_has_been_installed))
.setPriority(NotificationCompat.PRIORITY_LOW)
notificationManager.notify(1, builder.build())
viewModel.invalidatePager()
- snackString("Extension installed")
+ snackString(getString(R.string.extension_installed))
}
)
}
diff --git a/app/src/main/java/ani/dantotsu/widgets/statistics/ProfileStatsConfigure.kt b/app/src/main/java/ani/dantotsu/widgets/statistics/ProfileStatsConfigure.kt
new file mode 100644
index 00000000..b3ddec46
--- /dev/null
+++ b/app/src/main/java/ani/dantotsu/widgets/statistics/ProfileStatsConfigure.kt
@@ -0,0 +1,268 @@
+package ani.dantotsu.widgets.statistics
+
+import android.app.Activity
+import android.appwidget.AppWidgetManager
+import android.content.Context
+import android.content.Intent
+import android.content.res.ColorStateList
+import android.graphics.Color
+import android.os.Bundle
+import android.util.TypedValue
+import android.view.View
+import androidx.appcompat.app.AppCompatActivity
+import ani.dantotsu.R
+import ani.dantotsu.databinding.StatisticsWidgetConfigureBinding
+
+import ani.dantotsu.themes.ThemeManager
+import ani.dantotsu.widgets.upcoming.UpcomingWidget
+import com.google.android.material.button.MaterialButton
+import eltos.simpledialogfragment.SimpleDialog
+import eltos.simpledialogfragment.color.SimpleColorDialog
+
+/**
+ * The configuration screen for the [ProfileStatsWidget] AppWidget.
+ */
+class ProfileStatsConfigure : AppCompatActivity(),
+ SimpleDialog.OnDialogResultListener {
+ private var appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID
+ private var isMonetEnabled = false
+ private var onClickListener = View.OnClickListener {
+ val context = this@ProfileStatsConfigure
+
+ // It is the responsibility of the configuration activity to update the app widget
+ val appWidgetManager = AppWidgetManager.getInstance(context)
+ //updateAppWidget(context, appWidgetManager, appWidgetId)
+
+
+ ProfileStatsWidget.updateAppWidget(
+ context,
+ appWidgetManager,
+ appWidgetId
+ )
+
+ // Make sure we pass back the original appWidgetId
+ val resultValue = Intent()
+ resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
+ setResult(RESULT_OK, resultValue)
+ finish()
+ }
+ private lateinit var binding: StatisticsWidgetConfigureBinding
+
+ public override fun onCreate(icicle: Bundle?) {
+
+ ThemeManager(this).applyTheme()
+ super.onCreate(icicle)
+
+ // Set the result to CANCELED. This will cause the widget host to cancel
+ // out of the widget placement if the user presses the back button.
+ setResult(RESULT_CANCELED)
+
+ binding = StatisticsWidgetConfigureBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ val prefs = getSharedPreferences(ProfileStatsWidget.PREFS_NAME, Context.MODE_PRIVATE)
+ val topBackground = prefs.getInt(ProfileStatsWidget.PREF_BACKGROUND_COLOR, Color.parseColor("#80000000"))
+ (binding.topBackgroundButton as MaterialButton).iconTint = ColorStateList.valueOf(topBackground)
+ binding.topBackgroundButton.setOnClickListener {
+ val tag = ProfileStatsWidget.PREF_BACKGROUND_COLOR
+ SimpleColorDialog().title(R.string.custom_theme)
+ .colorPreset(topBackground)
+ .colors(
+ this@ProfileStatsConfigure,
+ SimpleColorDialog.MATERIAL_COLOR_PALLET
+ )
+ .setupColorWheelAlpha(true)
+ .allowCustom(true)
+ .showOutline(0x46000000)
+ .gridNumColumn(5)
+ .choiceMode(SimpleColorDialog.SINGLE_CHOICE)
+ .neg()
+ .show(this@ProfileStatsConfigure, tag)
+ }
+ val bottomBackground = prefs.getInt(ProfileStatsWidget.PREF_BACKGROUND_FADE, Color.parseColor("#00000000"))
+ (binding.bottomBackgroundButton as MaterialButton).iconTint = ColorStateList.valueOf(bottomBackground)
+ binding.bottomBackgroundButton.setOnClickListener {
+ val tag = ProfileStatsWidget.PREF_BACKGROUND_FADE
+ SimpleColorDialog().title(R.string.custom_theme)
+ .colorPreset(bottomBackground)
+ .colors(
+ this@ProfileStatsConfigure,
+ SimpleColorDialog.MATERIAL_COLOR_PALLET
+ )
+ .setupColorWheelAlpha(true)
+ .allowCustom(true)
+ .showOutline(0x46000000)
+ .gridNumColumn(5)
+ .choiceMode(SimpleColorDialog.SINGLE_CHOICE)
+ .neg()
+ .show(this@ProfileStatsConfigure, tag)
+ }
+ val titleColor = prefs.getInt(ProfileStatsWidget.PREF_TITLE_TEXT_COLOR, Color.WHITE)
+ (binding.titleColorButton as MaterialButton).iconTint = ColorStateList.valueOf(titleColor)
+ binding.titleColorButton.setOnClickListener {
+ val tag = ProfileStatsWidget.PREF_TITLE_TEXT_COLOR
+ SimpleColorDialog().title(R.string.custom_theme)
+ .colorPreset(titleColor)
+ .colors(
+ this@ProfileStatsConfigure,
+ SimpleColorDialog.MATERIAL_COLOR_PALLET
+ )
+ .setupColorWheelAlpha(true)
+ .allowCustom(true)
+ .showOutline(0x46000000)
+ .gridNumColumn(5)
+ .choiceMode(SimpleColorDialog.SINGLE_CHOICE)
+ .neg()
+ .show(this@ProfileStatsConfigure, tag)
+ }
+ val statsColor = prefs.getInt(ProfileStatsWidget.PREF_STATS_TEXT_COLOR, Color.WHITE)
+ (binding.statsColorButton as MaterialButton).iconTint = ColorStateList.valueOf(statsColor)
+ binding.statsColorButton.setOnClickListener {
+ val tag = ProfileStatsWidget.PREF_STATS_TEXT_COLOR
+ SimpleColorDialog().title(R.string.custom_theme)
+ .colorPreset(statsColor)
+ .colors(
+ this@ProfileStatsConfigure,
+ SimpleColorDialog.MATERIAL_COLOR_PALLET
+ )
+ .setupColorWheelAlpha(true)
+ .allowCustom(true)
+ .showOutline(0x46000000)
+ .gridNumColumn(5)
+ .choiceMode(SimpleColorDialog.SINGLE_CHOICE)
+ .neg()
+ .show(this@ProfileStatsConfigure, tag)
+ }
+ binding.useAppTheme.setOnCheckedChangeListener { _, isChecked ->
+ isMonetEnabled = isChecked
+ if (isChecked) {
+ binding.topBackgroundButton.visibility = View.GONE
+ binding.bottomBackgroundButton.visibility = View.GONE
+ binding.titleColorButton.visibility = View.GONE
+ binding.statsColorButton.visibility = View.GONE
+ themeColors()
+
+ } else {
+ binding.topBackgroundButton.visibility = View.VISIBLE
+ binding.bottomBackgroundButton.visibility = View.VISIBLE
+ binding.titleColorButton.visibility = View.VISIBLE
+ binding.statsColorButton.visibility = View.VISIBLE
+ }
+ }
+ binding.addButton.setOnClickListener(onClickListener)
+
+ // Find the widget id from the intent.
+ val intent = intent
+ val extras = intent.extras
+ if (extras != null) {
+ appWidgetId = extras.getInt(
+ AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID
+ )
+ }
+
+ // If this activity was started with an intent without an app widget ID, finish with an error.
+ if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
+ finish()
+ return
+ }
+ }
+
+ private fun themeColors() {
+ val typedValueSurface = TypedValue()
+ theme.resolveAttribute(
+ com.google.android.material.R.attr.colorSurface,
+ typedValueSurface,
+ true
+ )
+ val backgroundColor = typedValueSurface.data
+
+ val typedValuePrimary = TypedValue()
+ theme.resolveAttribute(
+ com.google.android.material.R.attr.colorPrimary,
+ typedValuePrimary,
+ true
+ )
+ val textColor = typedValuePrimary.data
+
+ val typedValueOutline = TypedValue()
+ theme.resolveAttribute(
+ com.google.android.material.R.attr.colorOutline,
+ typedValueOutline,
+ true
+ )
+ val subTextColor = typedValueOutline.data
+
+ getSharedPreferences(ProfileStatsWidget.PREFS_NAME, Context.MODE_PRIVATE).edit().apply {
+ putInt(ProfileStatsWidget.PREF_BACKGROUND_COLOR, backgroundColor)
+ putInt(ProfileStatsWidget.PREF_BACKGROUND_FADE, backgroundColor)
+ putInt(ProfileStatsWidget.PREF_TITLE_TEXT_COLOR, textColor)
+ putInt(ProfileStatsWidget.PREF_STATS_TEXT_COLOR, subTextColor)
+ apply()
+ }
+ }
+
+ override fun onResult(dialogTag: String, which: Int, extras: Bundle): Boolean {
+ if (which == SimpleDialog.OnDialogResultListener.BUTTON_POSITIVE) {
+ if (!isMonetEnabled) {
+ when (dialogTag) {
+ ProfileStatsWidget.PREF_BACKGROUND_COLOR -> {
+ getSharedPreferences(
+ ProfileStatsWidget.PREFS_NAME,
+ Context.MODE_PRIVATE
+ ).edit()
+ .putInt(
+ ProfileStatsWidget.PREF_BACKGROUND_COLOR,
+ extras.getInt(SimpleColorDialog.COLOR)
+ )
+ .apply()
+ (binding.topBackgroundButton as MaterialButton).iconTint =
+ ColorStateList.valueOf(extras.getInt(SimpleColorDialog.COLOR))
+ }
+
+ ProfileStatsWidget.PREF_BACKGROUND_FADE -> {
+ getSharedPreferences(
+ ProfileStatsWidget.PREFS_NAME,
+ Context.MODE_PRIVATE
+ ).edit()
+ .putInt(
+ ProfileStatsWidget.PREF_BACKGROUND_FADE,
+ extras.getInt(SimpleColorDialog.COLOR)
+ )
+ .apply()
+ (binding.bottomBackgroundButton as MaterialButton).iconTint =
+ ColorStateList.valueOf(extras.getInt(SimpleColorDialog.COLOR))
+ }
+
+ ProfileStatsWidget.PREF_TITLE_TEXT_COLOR -> {
+ getSharedPreferences(
+ ProfileStatsWidget.PREFS_NAME,
+ Context.MODE_PRIVATE
+ ).edit()
+ .putInt(
+ ProfileStatsWidget.PREF_TITLE_TEXT_COLOR,
+ extras.getInt(SimpleColorDialog.COLOR)
+ )
+ .apply()
+ (binding.titleColorButton as MaterialButton).iconTint =
+ ColorStateList.valueOf(extras.getInt(SimpleColorDialog.COLOR))
+ }
+
+ ProfileStatsWidget.PREF_STATS_TEXT_COLOR -> {
+ getSharedPreferences(
+ ProfileStatsWidget.PREFS_NAME,
+ Context.MODE_PRIVATE
+ ).edit()
+ .putInt(
+ ProfileStatsWidget.PREF_STATS_TEXT_COLOR,
+ extras.getInt(SimpleColorDialog.COLOR)
+ )
+ .apply()
+ (binding.statsColorButton as MaterialButton).iconTint =
+ ColorStateList.valueOf(extras.getInt(SimpleColorDialog.COLOR))
+ }
+ }
+ }
+ }
+ return true
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/widgets/statistics/ProfileStatsWidget.kt b/app/src/main/java/ani/dantotsu/widgets/statistics/ProfileStatsWidget.kt
new file mode 100644
index 00000000..06202ea0
--- /dev/null
+++ b/app/src/main/java/ani/dantotsu/widgets/statistics/ProfileStatsWidget.kt
@@ -0,0 +1,259 @@
+package ani.dantotsu.widgets.statistics
+
+import android.app.PendingIntent
+import android.appwidget.AppWidgetManager
+import android.appwidget.AppWidgetProvider
+import android.content.Context
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Color
+import android.graphics.drawable.GradientDrawable
+import android.widget.RemoteViews
+import androidx.core.content.res.ResourcesCompat
+import ani.dantotsu.MainActivity
+import ani.dantotsu.R
+import ani.dantotsu.connections.anilist.Anilist
+import ani.dantotsu.profile.ProfileActivity
+import ani.dantotsu.settings.saving.PrefManager
+import ani.dantotsu.settings.saving.PrefName
+import ani.dantotsu.util.BitmapUtil
+import ani.dantotsu.widgets.WidgetSizeProvider
+import kotlinx.coroutines.DelicateCoroutinesApi
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
+import tachiyomi.core.util.lang.launchIO
+import java.io.InputStream
+import java.net.HttpURLConnection
+import java.net.URL
+
+/**
+ * Implementation of App Widget functionality.
+ */
+class ProfileStatsWidget : AppWidgetProvider() {
+ override fun onUpdate(
+ context: Context,
+ appWidgetManager: AppWidgetManager,
+ appWidgetIds: IntArray
+ ) {
+ appWidgetIds.forEach { appWidgetId ->
+ updateAppWidget(context, appWidgetManager, appWidgetId)
+ }
+ super.onUpdate(context, appWidgetManager, appWidgetIds)
+ }
+
+ override fun onDeleted(context: Context, appWidgetIds: IntArray) {
+ super.onDeleted(context, appWidgetIds)
+ }
+
+ override fun onEnabled(context: Context) {
+ super.onEnabled(context)
+ }
+
+ override fun onDisabled(context: Context) {
+ super.onDisabled(context)
+ }
+
+ companion object {
+ private fun downloadImageAsBitmap(imageUrl: String): Bitmap? {
+ var bitmap: Bitmap? = null
+
+ runBlocking(Dispatchers.IO) {
+ var inputStream: InputStream? = null
+ var urlConnection: HttpURLConnection? = null
+ try {
+ val url = URL(imageUrl)
+ urlConnection = url.openConnection() as HttpURLConnection
+ urlConnection.requestMethod = "GET"
+ urlConnection.connect()
+
+ if (urlConnection.responseCode == HttpURLConnection.HTTP_OK) {
+ inputStream = urlConnection.inputStream
+ bitmap = BitmapFactory.decodeStream(inputStream)
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ inputStream?.close()
+ urlConnection?.disconnect()
+ }
+ }
+ return bitmap?.let { BitmapUtil.roundCorners(it) }
+ }
+
+ @OptIn(DelicateCoroutinesApi::class)
+ fun updateAppWidget(
+ context: Context,
+ appWidgetManager: AppWidgetManager,
+ appWidgetId: Int
+ ) {
+
+ val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
+ val backgroundColor =
+ prefs.getInt(PREF_BACKGROUND_COLOR, Color.parseColor("#80000000"))
+ val backgroundFade = prefs.getInt(PREF_BACKGROUND_FADE, Color.parseColor("#00000000"))
+ val titleTextColor = prefs.getInt(PREF_TITLE_TEXT_COLOR, Color.WHITE)
+ val statsTextColor = prefs.getInt(PREF_STATS_TEXT_COLOR, Color.WHITE)
+
+ val gradientDrawable = ResourcesCompat.getDrawable(
+ context.resources,
+ R.drawable.linear_gradient_black,
+ null
+ ) as GradientDrawable
+ gradientDrawable.colors = intArrayOf(backgroundColor, backgroundFade)
+ val widgetSizeProvider = WidgetSizeProvider(context)
+ var (width, height) = widgetSizeProvider.getWidgetsSize(appWidgetId)
+ if (width > 0 && height > 0) {
+ gradientDrawable.cornerRadius = 64f
+ } else {
+ width = 300
+ height = 300
+ }
+
+ launchIO {
+ val userPref = PrefManager.getVal(PrefName.AnilistUserId, "")
+ val userId = if (userPref.isNotEmpty()) userPref.toInt() else Anilist.userid
+ ?: if (Anilist.query.getUserData()) Anilist.userid else null
+ userId?.let {
+ val respond = Anilist.query.getUserProfile(it)
+ respond?.data?.user?.let { user ->
+ withContext(Dispatchers.Main) {
+ val views = RemoteViews(context.packageName, R.layout.statistics_widget).apply {
+ setImageViewBitmap(
+ R.id.backgroundView,
+ BitmapUtil.convertDrawableToBitmap(
+ gradientDrawable,
+ width,
+ height
+ )
+ )
+ setOnClickPendingIntent(
+ R.id.userAvatar,
+ PendingIntent.getActivity(
+ context,
+ 1,
+ Intent(context, ProfileStatsConfigure::class.java).apply {
+ putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
+ },
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+ )
+ setTextColor(R.id.userLabel, titleTextColor)
+ setTextColor(R.id.topLeftItem, statsTextColor)
+ setTextColor(R.id.topLeftLabel, statsTextColor)
+ setTextColor(R.id.topRightItem, statsTextColor)
+ setTextColor(R.id.topRightLabel, statsTextColor)
+ setTextColor(R.id.bottomLeftItem, statsTextColor)
+ setTextColor(R.id.bottomLeftLabel, statsTextColor)
+ setTextColor(R.id.bottomRightItem, statsTextColor)
+ setTextColor(R.id.bottomRightLabel, statsTextColor)
+
+ setImageViewBitmap(
+ R.id.userAvatar,
+ user.avatar?.medium?.let { it1 -> downloadImageAsBitmap(it1) }
+ )
+ setTextViewText(
+ R.id.userLabel,
+ context.getString(R.string.user_stats, user.name)
+ )
+
+ setTextViewText(
+ R.id.topLeftItem,
+ user.statistics.anime.count.toString()
+ )
+ setTextViewText(
+ R.id.topLeftLabel,
+ context.getString(R.string.anime_watched)
+ )
+
+ setTextViewText(
+ R.id.topRightItem,
+ user.statistics.anime.episodesWatched.toString()
+ )
+ setTextViewText(
+ R.id.topRightLabel,
+ context.getString(R.string.episodes_watched_n)
+ )
+
+ setTextViewText(
+ R.id.bottomLeftItem,
+ user.statistics.manga.count.toString()
+ )
+ setTextViewText(
+ R.id.bottomLeftLabel,
+ context.getString(R.string.manga_read)
+ )
+
+ setTextViewText(
+ R.id.bottomRightItem,
+ user.statistics.manga.chaptersRead.toString()
+ )
+ setTextViewText(
+ R.id.bottomRightLabel,
+ context.getString(R.string.chapters_read_n)
+ )
+
+ val intent = Intent(context, ProfileActivity::class.java)
+ .putExtra("userId", it)
+ val pendingIntent = PendingIntent.getActivity(
+ context, 0, intent, PendingIntent.FLAG_IMMUTABLE
+ )
+ setOnClickPendingIntent(R.id.widgetContainer, pendingIntent)
+ }
+ // Instruct the widget manager to update the widget
+ appWidgetManager.updateAppWidget(appWidgetId, views)
+ }
+ } ?: showLoginCascade(context, appWidgetManager, appWidgetId)
+ } ?: showLoginCascade(context, appWidgetManager, appWidgetId)
+ }
+ }
+
+ private suspend fun showLoginCascade(
+ context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int
+ ) {
+
+ withContext(Dispatchers.Main) {
+ val views = RemoteViews(context.packageName, R.layout.statistics_widget)
+
+ views.setTextViewText(R.id.topLeftItem, "")
+ views.setTextViewText(
+ R.id.topLeftLabel,
+ context.getString(R.string.please)
+ )
+
+ views.setTextViewText(R.id.topRightItem, "")
+ views.setTextViewText(
+ R.id.topRightLabel,
+ context.getString(R.string.log_in)
+ )
+
+ views.setTextViewText(
+ R.id.bottomLeftItem,
+ context.getString(R.string.or_join)
+ )
+ views.setTextViewText(R.id.bottomLeftLabel, "")
+
+ views.setTextViewText(
+ R.id.bottomRightItem,
+ context.getString(R.string.anilist)
+ )
+ views.setTextViewText(R.id.bottomRightLabel, "")
+
+ val intent = Intent(context, MainActivity::class.java)
+ val pendingIntent = PendingIntent.getActivity(
+ context, 0, intent, PendingIntent.FLAG_IMMUTABLE
+ )
+ views.setOnClickPendingIntent(R.id.widgetContainer, pendingIntent)
+
+ appWidgetManager.updateAppWidget(appWidgetId, views)
+ }
+ }
+
+ const val PREFS_NAME = "ani.dantotsu.widgets.ResumableWidget"
+ const val PREF_BACKGROUND_COLOR = "background_color"
+ const val PREF_BACKGROUND_FADE = "background_fade"
+ const val PREF_TITLE_TEXT_COLOR = "title_text_color"
+ const val PREF_STATS_TEXT_COLOR = "stats_text_color"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidget.kt b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidget.kt
index a9f22130..fc8850f3 100644
--- a/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidget.kt
+++ b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidget.kt
@@ -10,7 +10,6 @@ import android.graphics.drawable.GradientDrawable
import android.net.Uri
import android.os.Bundle
import android.widget.RemoteViews
-import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import ani.dantotsu.MainActivity
import ani.dantotsu.R
@@ -19,7 +18,7 @@ import ani.dantotsu.widgets.WidgetSizeProvider
/**
* Implementation of App Widget functionality.
- * App Widget Configuration implemented in [UpcomingWidgetConfigureActivity]
+ * App Widget Configuration implemented in [UpcomingWidgetConfigure]
*/
class UpcomingWidget : AppWidgetProvider() {
override fun onUpdate(
@@ -69,8 +68,8 @@ class UpcomingWidget : AppWidgetProvider() {
): RemoteViews {
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
val backgroundColor =
- prefs.getInt(PREF_BACKGROUND_COLOR, ContextCompat.getColor(context, R.color.theme))
- val backgroundFade = prefs.getInt(PREF_BACKGROUND_FADE, Color.GRAY)
+ prefs.getInt(PREF_BACKGROUND_COLOR, Color.parseColor("#80000000"))
+ val backgroundFade = prefs.getInt(PREF_BACKGROUND_FADE, Color.parseColor("#00000000"))
val titleTextColor = prefs.getInt(PREF_TITLE_TEXT_COLOR, Color.WHITE)
val countdownTextColor = prefs.getInt(PREF_COUNTDOWN_TEXT_COLOR, Color.WHITE)
@@ -80,14 +79,14 @@ class UpcomingWidget : AppWidgetProvider() {
}
val gradientDrawable = ResourcesCompat.getDrawable(
context.resources,
- R.drawable.gradient_background,
+ R.drawable.linear_gradient_black,
null
) as GradientDrawable
gradientDrawable.colors = intArrayOf(backgroundColor, backgroundFade)
val widgetSizeProvider = WidgetSizeProvider(context)
var (width, height) = widgetSizeProvider.getWidgetsSize(appWidgetId)
if (width > 0 && height > 0) {
- gradientDrawable.cornerRadius = 50f
+ gradientDrawable.cornerRadius = 64f
} else {
width = 300
height = 300
@@ -118,7 +117,7 @@ class UpcomingWidget : AppWidgetProvider() {
PendingIntent.getActivity(
context,
1,
- Intent(context, UpcomingWidgetConfigureActivity::class.java).apply {
+ Intent(context, UpcomingWidgetConfigure::class.java).apply {
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
},
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
diff --git a/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidgetConfigure.kt b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidgetConfigure.kt
new file mode 100644
index 00000000..a465a48a
--- /dev/null
+++ b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidgetConfigure.kt
@@ -0,0 +1,240 @@
+package ani.dantotsu.widgets.upcoming
+
+import android.appwidget.AppWidgetManager
+import android.content.Context
+import android.content.Intent
+import android.content.res.ColorStateList
+import android.graphics.Color
+import android.os.Bundle
+import android.util.TypedValue
+import android.view.View
+import androidx.appcompat.app.AppCompatActivity
+import ani.dantotsu.R
+import ani.dantotsu.databinding.UpcomingWidgetConfigureBinding
+import ani.dantotsu.themes.ThemeManager
+import com.google.android.material.button.MaterialButton
+import eltos.simpledialogfragment.SimpleDialog
+import eltos.simpledialogfragment.color.SimpleColorDialog
+
+/**
+ * The configuration screen for the [UpcomingWidget] AppWidget.
+ */
+class UpcomingWidgetConfigure : AppCompatActivity(),
+ SimpleDialog.OnDialogResultListener {
+ private var appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID
+ private var isMonetEnabled = false
+ private var onClickListener = View.OnClickListener {
+ val context = this@UpcomingWidgetConfigure
+ val appWidgetManager = AppWidgetManager.getInstance(context)
+
+ updateAppWidget(
+ context,
+ appWidgetManager,
+ appWidgetId,
+ )
+
+ val resultValue = Intent()
+ resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
+ setResult(RESULT_OK, resultValue)
+ finish()
+ }
+ private lateinit var binding: UpcomingWidgetConfigureBinding
+
+ public override fun onCreate(icicle: Bundle?) {
+ ThemeManager(this).applyTheme()
+ super.onCreate(icicle)
+ setResult(RESULT_CANCELED)
+
+ binding = UpcomingWidgetConfigureBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ val prefs = getSharedPreferences(UpcomingWidget.PREFS_NAME, Context.MODE_PRIVATE)
+ val topBackground = prefs.getInt(UpcomingWidget.PREF_BACKGROUND_COLOR, Color.parseColor("#80000000"))
+ (binding.topBackgroundButton as MaterialButton).iconTint = ColorStateList.valueOf(topBackground)
+ binding.topBackgroundButton.setOnClickListener {
+ val tag = UpcomingWidget.PREF_BACKGROUND_COLOR
+ SimpleColorDialog().title(R.string.custom_theme)
+ .colorPreset(topBackground)
+ .colors(
+ this@UpcomingWidgetConfigure,
+ SimpleColorDialog.MATERIAL_COLOR_PALLET
+ )
+ .setupColorWheelAlpha(true)
+ .allowCustom(true)
+ .showOutline(0x46000000)
+ .gridNumColumn(5)
+ .choiceMode(SimpleColorDialog.SINGLE_CHOICE)
+ .neg()
+ .show(this@UpcomingWidgetConfigure, tag)
+ }
+ val bottomBackground = prefs.getInt(UpcomingWidget.PREF_BACKGROUND_FADE, Color.parseColor("#00000000"))
+ (binding.bottomBackgroundButton as MaterialButton).iconTint = ColorStateList.valueOf(bottomBackground)
+ binding.bottomBackgroundButton.setOnClickListener {
+ val tag = UpcomingWidget.PREF_BACKGROUND_FADE
+ SimpleColorDialog().title(R.string.custom_theme)
+ .colorPreset(bottomBackground)
+ .colors(
+ this@UpcomingWidgetConfigure,
+ SimpleColorDialog.MATERIAL_COLOR_PALLET
+ )
+ .setupColorWheelAlpha(true)
+ .allowCustom(true)
+ .showOutline(0x46000000)
+ .gridNumColumn(5)
+ .choiceMode(SimpleColorDialog.SINGLE_CHOICE)
+ .neg()
+ .show(this@UpcomingWidgetConfigure, tag)
+ }
+ val titleTextColor = prefs.getInt(UpcomingWidget.PREF_TITLE_TEXT_COLOR, Color.WHITE)
+ (binding.titleColorButton as MaterialButton).iconTint = ColorStateList.valueOf(titleTextColor)
+ binding.titleColorButton.setOnClickListener {
+ val tag = UpcomingWidget.PREF_TITLE_TEXT_COLOR
+ SimpleColorDialog().title(R.string.custom_theme)
+ .colorPreset(titleTextColor)
+ .colors(
+ this@UpcomingWidgetConfigure,
+ SimpleColorDialog.MATERIAL_COLOR_PALLET
+ )
+ .allowCustom(true)
+ .showOutline(0x46000000)
+ .gridNumColumn(5)
+ .choiceMode(SimpleColorDialog.SINGLE_CHOICE)
+ .neg()
+ .show(this@UpcomingWidgetConfigure, tag)
+ }
+ val countdownTextColor = prefs.getInt(UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR, Color.WHITE)
+ (binding.countdownColorButton as MaterialButton).iconTint = ColorStateList.valueOf(countdownTextColor)
+ binding.countdownColorButton.setOnClickListener {
+ val tag = UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR
+ SimpleColorDialog().title(R.string.custom_theme)
+ .colorPreset(countdownTextColor)
+ .colors(
+ this@UpcomingWidgetConfigure,
+ SimpleColorDialog.MATERIAL_COLOR_PALLET
+ )
+ .allowCustom(true)
+ .showOutline(0x46000000)
+ .gridNumColumn(5)
+ .choiceMode(SimpleColorDialog.SINGLE_CHOICE)
+ .neg()
+ .show(this@UpcomingWidgetConfigure, tag)
+ }
+ binding.useAppTheme.setOnCheckedChangeListener { _, isChecked ->
+ isMonetEnabled = isChecked
+ if (isChecked) {
+ binding.topBackgroundButton.visibility = View.GONE
+ binding.bottomBackgroundButton.visibility = View.GONE
+ binding.titleColorButton.visibility = View.GONE
+ binding.countdownColorButton.visibility = View.GONE
+ themeColors()
+
+ } else {
+ binding.topBackgroundButton.visibility = View.VISIBLE
+ binding.bottomBackgroundButton.visibility = View.VISIBLE
+ binding.titleColorButton.visibility = View.VISIBLE
+ binding.countdownColorButton.visibility = View.VISIBLE
+ }
+ }
+ binding.addButton.setOnClickListener(onClickListener)
+
+ val intent = intent
+ val extras = intent.extras
+ if (extras != null) {
+ appWidgetId = extras.getInt(
+ AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID
+ )
+ }
+
+ if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
+ finish()
+ return
+ }
+ }
+
+ private fun themeColors() {
+ val typedValueSurface = TypedValue()
+ theme.resolveAttribute(com.google.android.material.R.attr.colorSurface, typedValueSurface, true)
+ val backgroundColor = typedValueSurface.data
+
+ val typedValuePrimary = TypedValue()
+ theme.resolveAttribute(com.google.android.material.R.attr.colorPrimary, typedValuePrimary, true)
+ val textColor = typedValuePrimary.data
+
+ val typedValueOutline = TypedValue()
+ theme.resolveAttribute(com.google.android.material.R.attr.colorOutline, typedValueOutline, true)
+ val subTextColor = typedValueOutline.data
+
+ getSharedPreferences(UpcomingWidget.PREFS_NAME, Context.MODE_PRIVATE).edit().apply {
+ putInt(UpcomingWidget.PREF_BACKGROUND_COLOR, backgroundColor)
+ putInt(UpcomingWidget.PREF_BACKGROUND_FADE, backgroundColor)
+ putInt(UpcomingWidget.PREF_TITLE_TEXT_COLOR, textColor)
+ putInt(UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR, subTextColor)
+ apply()
+ }
+ }
+
+ override fun onResult(dialogTag: String, which: Int, extras: Bundle): Boolean {
+ if (which == SimpleDialog.OnDialogResultListener.BUTTON_POSITIVE) {
+ if (!isMonetEnabled) {
+ when (dialogTag) {
+ UpcomingWidget.PREF_BACKGROUND_COLOR -> {
+ getSharedPreferences(
+ UpcomingWidget.PREFS_NAME,
+ Context.MODE_PRIVATE
+ ).edit()
+ .putInt(
+ UpcomingWidget.PREF_BACKGROUND_COLOR,
+ extras.getInt(SimpleColorDialog.COLOR)
+ )
+ .apply()
+ (binding.topBackgroundButton as MaterialButton).iconTint =
+ ColorStateList.valueOf(extras.getInt(SimpleColorDialog.COLOR))
+ }
+
+ UpcomingWidget.PREF_BACKGROUND_FADE -> {
+ getSharedPreferences(
+ UpcomingWidget.PREFS_NAME,
+ Context.MODE_PRIVATE
+ ).edit()
+ .putInt(
+ UpcomingWidget.PREF_BACKGROUND_FADE,
+ extras.getInt(SimpleColorDialog.COLOR)
+ )
+ .apply()
+ (binding.bottomBackgroundButton as MaterialButton).iconTint =
+ ColorStateList.valueOf(extras.getInt(SimpleColorDialog.COLOR))
+ }
+
+ UpcomingWidget.PREF_TITLE_TEXT_COLOR -> {
+ getSharedPreferences(
+ UpcomingWidget.PREFS_NAME,
+ Context.MODE_PRIVATE
+ ).edit()
+ .putInt(
+ UpcomingWidget.PREF_TITLE_TEXT_COLOR,
+ extras.getInt(SimpleColorDialog.COLOR)
+ )
+ .apply()
+ (binding.titleColorButton as MaterialButton).iconTint =
+ ColorStateList.valueOf(extras.getInt(SimpleColorDialog.COLOR))
+ }
+
+ UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR -> {
+ getSharedPreferences(
+ UpcomingWidget.PREFS_NAME,
+ Context.MODE_PRIVATE
+ ).edit()
+ .putInt(
+ UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR,
+ extras.getInt(SimpleColorDialog.COLOR)
+ )
+ .apply()
+ (binding.countdownColorButton as MaterialButton).iconTint =
+ ColorStateList.valueOf(extras.getInt(SimpleColorDialog.COLOR))
+ }
+
+ }
+ }
+ }
+ return true
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidgetConfigureActivity.kt b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidgetConfigureActivity.kt
deleted file mode 100644
index f14efaa7..00000000
--- a/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidgetConfigureActivity.kt
+++ /dev/null
@@ -1,195 +0,0 @@
-package ani.dantotsu.widgets.upcoming
-
-import android.appwidget.AppWidgetManager
-import android.content.Context
-import android.content.Intent
-import android.graphics.Color
-import android.os.Bundle
-import android.view.View
-import androidx.appcompat.app.AppCompatActivity
-import androidx.core.content.ContextCompat
-import ani.dantotsu.R
-import ani.dantotsu.databinding.UpcomingWidgetConfigureBinding
-import ani.dantotsu.themes.ThemeManager
-import eltos.simpledialogfragment.SimpleDialog
-import eltos.simpledialogfragment.color.SimpleColorDialog
-
-/**
- * The configuration screen for the [UpcomingWidget] AppWidget.
- */
-class UpcomingWidgetConfigureActivity : AppCompatActivity(),
- SimpleDialog.OnDialogResultListener {
- private var appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID
-
- private var onClickListener = View.OnClickListener {
- val context = this@UpcomingWidgetConfigureActivity
- val appWidgetManager = AppWidgetManager.getInstance(context)
-
- updateAppWidget(
- context,
- appWidgetManager,
- appWidgetId,
- )
-
- val resultValue = Intent()
- resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
- setResult(RESULT_OK, resultValue)
- finish()
- }
- private lateinit var binding: UpcomingWidgetConfigureBinding
-
- public override fun onCreate(icicle: Bundle?) {
- ThemeManager(this).applyTheme()
- super.onCreate(icicle)
- setResult(RESULT_CANCELED)
-
- binding = UpcomingWidgetConfigureBinding.inflate(layoutInflater)
- setContentView(binding.root)
- val prefs = getSharedPreferences(UpcomingWidget.PREFS_NAME, Context.MODE_PRIVATE)
-
- binding.topBackgroundButton.setOnClickListener {
- val tag = UpcomingWidget.PREF_BACKGROUND_COLOR
- SimpleColorDialog().title(R.string.custom_theme)
- .colorPreset(
- prefs.getInt(
- UpcomingWidget.PREF_BACKGROUND_COLOR,
- ContextCompat.getColor(this, R.color.theme)
- )
- )
- .colors(
- this@UpcomingWidgetConfigureActivity,
- SimpleColorDialog.MATERIAL_COLOR_PALLET
- )
- .setupColorWheelAlpha(true)
- .allowCustom(true)
- .showOutline(0x46000000)
- .gridNumColumn(5)
- .choiceMode(SimpleColorDialog.SINGLE_CHOICE)
- .neg()
- .show(this@UpcomingWidgetConfigureActivity, tag)
- }
- binding.bottomBackgroundButton.setOnClickListener {
- val tag = UpcomingWidget.PREF_BACKGROUND_FADE
- SimpleColorDialog().title(R.string.custom_theme)
- .colorPreset(prefs.getInt(UpcomingWidget.PREF_BACKGROUND_FADE, Color.GRAY))
- .colors(
- this@UpcomingWidgetConfigureActivity,
- SimpleColorDialog.MATERIAL_COLOR_PALLET
- )
- .setupColorWheelAlpha(true)
- .allowCustom(true)
- .showOutline(0x46000000)
- .gridNumColumn(5)
- .choiceMode(SimpleColorDialog.SINGLE_CHOICE)
- .neg()
- .show(this@UpcomingWidgetConfigureActivity, tag)
- }
- binding.titleColorButton.setOnClickListener {
- val tag = UpcomingWidget.PREF_TITLE_TEXT_COLOR
- SimpleColorDialog().title(R.string.custom_theme)
- .colorPreset(prefs.getInt(UpcomingWidget.PREF_TITLE_TEXT_COLOR, Color.WHITE))
- .colors(
- this@UpcomingWidgetConfigureActivity,
- SimpleColorDialog.MATERIAL_COLOR_PALLET
- )
- .allowCustom(true)
- .showOutline(0x46000000)
- .gridNumColumn(5)
- .choiceMode(SimpleColorDialog.SINGLE_CHOICE)
- .neg()
- .show(this@UpcomingWidgetConfigureActivity, tag)
- }
- binding.countdownColorButton.setOnClickListener {
- val tag = UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR
- SimpleColorDialog().title(R.string.custom_theme)
- .colorPreset(
- prefs.getInt(
- UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR,
- Color.WHITE
- )
- )
- .colors(
- this@UpcomingWidgetConfigureActivity,
- SimpleColorDialog.MATERIAL_COLOR_PALLET
- )
- .allowCustom(true)
- .showOutline(0x46000000)
- .gridNumColumn(5)
- .choiceMode(SimpleColorDialog.SINGLE_CHOICE)
- .neg()
- .show(this@UpcomingWidgetConfigureActivity, tag)
- }
-
- binding.addButton.setOnClickListener(onClickListener)
-
- val intent = intent
- val extras = intent.extras
- if (extras != null) {
- appWidgetId = extras.getInt(
- AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID
- )
- }
-
- if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
- finish()
- return
- }
- }
-
- override fun onResult(dialogTag: String, which: Int, extras: Bundle): Boolean {
- if (which == SimpleDialog.OnDialogResultListener.BUTTON_POSITIVE) {
- when (dialogTag) {
- UpcomingWidget.PREF_BACKGROUND_COLOR -> {
- getSharedPreferences(
- UpcomingWidget.PREFS_NAME,
- Context.MODE_PRIVATE
- ).edit()
- .putInt(
- UpcomingWidget.PREF_BACKGROUND_COLOR,
- extras.getInt(SimpleColorDialog.COLOR)
- )
- .apply()
- }
-
- UpcomingWidget.PREF_BACKGROUND_FADE -> {
- getSharedPreferences(
- UpcomingWidget.PREFS_NAME,
- Context.MODE_PRIVATE
- ).edit()
- .putInt(
- UpcomingWidget.PREF_BACKGROUND_FADE,
- extras.getInt(SimpleColorDialog.COLOR)
- )
- .apply()
- }
-
- UpcomingWidget.PREF_TITLE_TEXT_COLOR -> {
- getSharedPreferences(
- UpcomingWidget.PREFS_NAME,
- Context.MODE_PRIVATE
- ).edit()
- .putInt(
- UpcomingWidget.PREF_TITLE_TEXT_COLOR,
- extras.getInt(SimpleColorDialog.COLOR)
- )
- .apply()
- }
-
- UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR -> {
- getSharedPreferences(
- UpcomingWidget.PREFS_NAME,
- Context.MODE_PRIVATE
- ).edit()
- .putInt(
- UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR,
- extras.getInt(SimpleColorDialog.COLOR)
- )
- .apply()
- }
-
- }
- }
- return true
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/res/drawable-nodpi/example_appwidget_preview.png b/app/src/main/res/drawable-nodpi/example_appwidget_preview.png
deleted file mode 100644
index 52c4ef28..00000000
Binary files a/app/src/main/res/drawable-nodpi/example_appwidget_preview.png and /dev/null differ
diff --git a/app/src/main/res/drawable-nodpi/statistics_widget_preview.png b/app/src/main/res/drawable-nodpi/statistics_widget_preview.png
new file mode 100644
index 00000000..85d3aaef
Binary files /dev/null and b/app/src/main/res/drawable-nodpi/statistics_widget_preview.png differ
diff --git a/app/src/main/res/drawable-nodpi/upcoming_widget_preview.png b/app/src/main/res/drawable-nodpi/upcoming_widget_preview.png
new file mode 100644
index 00000000..fcfa6e7d
Binary files /dev/null and b/app/src/main/res/drawable-nodpi/upcoming_widget_preview.png differ
diff --git a/app/src/main/res/drawable/ic_camera_roll_24.xml b/app/src/main/res/drawable/ic_camera_roll_24.xml
new file mode 100644
index 00000000..1c4b99e3
--- /dev/null
+++ b/app/src/main/res/drawable/ic_camera_roll_24.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/widget_stats_rounded.xml b/app/src/main/res/drawable/widget_stats_rounded.xml
new file mode 100644
index 00000000..933eab8b
--- /dev/null
+++ b/app/src/main/res/drawable/widget_stats_rounded.xml
@@ -0,0 +1,27 @@
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_player_settings.xml b/app/src/main/res/layout/activity_player_settings.xml
index 729a4788..afbc7ee2 100644
--- a/app/src/main/res/layout/activity_player_settings.xml
+++ b/app/src/main/res/layout/activity_player_settings.xml
@@ -177,7 +177,8 @@
android:layout_height="64dp"
android:fontFamily="@font/poppins_bold"
android:gravity="center_vertical"
- android:paddingHorizontal="32dp"
+ android:paddingStart="48dp"
+ android:paddingEnd="32dp"
android:text="@string/sub_text_example"
android:textColor="?attr/colorSecondary"
app:drawableEndCompat="@drawable/ic_round_arrow_drop_down_24"
diff --git a/app/src/main/res/layout/fragment_anime_extensions.xml b/app/src/main/res/layout/fragment_anime_extensions.xml
deleted file mode 100644
index 2ccb2d42..00000000
--- a/app/src/main/res/layout/fragment_anime_extensions.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_manga_extensions.xml b/app/src/main/res/layout/fragment_extensions.xml
similarity index 89%
rename from app/src/main/res/layout/fragment_manga_extensions.xml
rename to app/src/main/res/layout/fragment_extensions.xml
index 99067aea..d51f19be 100644
--- a/app/src/main/res/layout/fragment_manga_extensions.xml
+++ b/app/src/main/res/layout/fragment_extensions.xml
@@ -7,7 +7,7 @@
android:paddingEnd="16dp">
diff --git a/app/src/main/res/layout/statistics_widget.xml b/app/src/main/res/layout/statistics_widget.xml
new file mode 100644
index 00000000..d4bb070f
--- /dev/null
+++ b/app/src/main/res/layout/statistics_widget.xml
@@ -0,0 +1,188 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/statistics_widget_configure.xml b/app/src/main/res/layout/statistics_widget_configure.xml
new file mode 100644
index 00000000..6d33cc25
--- /dev/null
+++ b/app/src/main/res/layout/statistics_widget_configure.xml
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/upcoming_widget.xml b/app/src/main/res/layout/upcoming_widget.xml
index 209b300e..c2122a31 100644
--- a/app/src/main/res/layout/upcoming_widget.xml
+++ b/app/src/main/res/layout/upcoming_widget.xml
@@ -9,14 +9,14 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
- android:src="@drawable/gradient_background"
+ android:src="@drawable/linear_gradient_black"
tools:ignore="ContentDescription"/>
+ android:padding="16dp">
@@ -10,8 +10,28 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
+ android:fontFamily="@font/poppins_bold"
android:text="@string/configure" />
+
+
@@ -55,7 +75,7 @@
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
- app:icon="@drawable/ic_round_color_picker_24"
+ app:icon="@drawable/shape_corner_16dp"
app:iconPadding="16dp"
app:iconSize="24dp"
app:iconTint="?attr/colorPrimary" />
@@ -79,7 +99,7 @@
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
- app:icon="@drawable/ic_round_color_picker_24"
+ app:icon="@drawable/shape_corner_16dp"
app:iconPadding="16dp"
app:iconSize="24dp"
app:iconTint="?attr/colorPrimary" />
@@ -103,14 +123,14 @@
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
- app:icon="@drawable/ic_round_color_picker_24"
+ app:icon="@drawable/shape_corner_16dp"
app:iconPadding="16dp"
app:iconSize="24dp"
app:iconTint="?attr/colorPrimary" />
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 065f0e6b..f7e02089 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -9,6 +9,7 @@
@color/bg_black
#A8000000
#80000000
+ #80FFFFFF
#fff
#00BFAEAE
#ACACAC
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a6945a88..6ea85551 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -53,7 +53,9 @@
Username
"Chapters Read "
+ "Chapters\nRead "
"Episodes Watched "
+ "Episodes\nWatched "
Continue Reading
Continue Watching
Recommended
@@ -412,6 +414,13 @@
Crop Borders
NOTE
+ Installing extension
+ Installation failed: %1$s
+ Installation complete
+ The extension has been successfully installed.
+ Extension installed
+ Error: %1$s
+ Step: %1$s
DAMN! YOU TRULY ARE JOBLESS\nYOU REACHED THE END
Couldn\'t find any File Manager to open SD card
@@ -673,6 +682,7 @@
NSFW Extensions
Skip loading extension icons
Material You
+ Use App Theme
Extension-specific DNS
Theme:
User Agent
@@ -824,10 +834,20 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
donate :)
Do it!
Password
-
+ Track progress directly from your home screen
+ Anime\nWatched
+ Manga\nRead
+ Loading…
+ %1$s\'s Stats
+
+ Please
+ log in
+ or join
+
Top background color
Bottom Background Color
Countdown Text Color
Title Color
+ Stats Text Color
Placeholder
diff --git a/app/src/main/res/xml-v31/statistics_widget_info.xml b/app/src/main/res/xml-v31/statistics_widget_info.xml
new file mode 100644
index 00000000..5ede252a
--- /dev/null
+++ b/app/src/main/res/xml-v31/statistics_widget_info.xml
@@ -0,0 +1,15 @@
+
+
diff --git a/app/src/main/res/xml-v31/upcoming_widget_info.xml b/app/src/main/res/xml-v31/upcoming_widget_info.xml
index e8376331..d9983e50 100644
--- a/app/src/main/res/xml-v31/upcoming_widget_info.xml
+++ b/app/src/main/res/xml-v31/upcoming_widget_info.xml
@@ -1,12 +1,12 @@
+
diff --git a/app/src/main/res/xml/upcoming_widget_info.xml b/app/src/main/res/xml/upcoming_widget_info.xml
index e82356cc..052c7b65 100644
--- a/app/src/main/res/xml/upcoming_widget_info.xml
+++ b/app/src/main/res/xml/upcoming_widget_info.xml
@@ -1,12 +1,12 @@
\ No newline at end of file