Merge branch 'dev' into zephyr

This commit is contained in:
ibo
2024-03-28 01:48:35 +01:00
committed by GitHub
47 changed files with 1497 additions and 479 deletions

View File

@@ -73,12 +73,24 @@
android:resource="@xml/upcoming_widget_info" />
</receiver>
<activity
android:name=".widgets.upcoming.UpcomingWidgetConfigureActivity"
android:name=".widgets.upcoming.UpcomingWidgetConfigure"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<receiver
android:name=".widgets.statistics.ProfileStatsWidget"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/statistics_widget_info" />
</receiver>
<receiver android:name=".notifications.IncognitoNotificationClickReceiver" />
<activity
@@ -115,6 +127,14 @@
android:name=".settings.ExtensionsActivity"
android:parentActivityName=".MainActivity"
android:windowSoftInputMode="adjustResize|stateHidden" />
<activity
android:name=".widgets.statistics.ProfileStatsConfigure"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
<activity
android:name=".profile.ProfileActivity"
android:parentActivityName=".MainActivity"

View File

@@ -0,0 +1,146 @@
package ani.dantotsu.media
import java.util.Locale
import java.util.regex.Matcher
import java.util.regex.Pattern
object MediaNameAdapter {
private const val REGEX_ITEM = "[\\s:.\\-]*(\\d+\\.?\\d*)[\\s:.\\-]*"
private const val REGEX_PART_NUMBER = "(?<!part\\s)\\b(\\d+)\\b"
private const val REGEX_EPISODE =
"(episode|episodio|ep|e)${REGEX_ITEM}\\(?\\s*(sub|subbed|dub|dubbed)*\\s*\\)?\\s*"
private const val REGEX_SEASON = "(season|s)[\\s:.\\-]*(\\d+)[\\s:.\\-]*"
private const val REGEX_SUBDUB = "^(soft)?[\\s-]*(sub|dub|mixed)(bed|s)?\\s*$"
private const val REGEX_CHAPTER = "(chapter|chap|ch|c)${REGEX_ITEM}"
fun setSubDub(text: String, typeToSetTo: SubDubType): String? {
val subdubPattern: Pattern = Pattern.compile(REGEX_SUBDUB, Pattern.CASE_INSENSITIVE)
val subdubMatcher: Matcher = subdubPattern.matcher(text)
return if (subdubMatcher.find()) {
val soft = subdubMatcher.group(1)
val subdub = subdubMatcher.group(2)
val bed = subdubMatcher.group(3) ?: ""
val toggled = when (typeToSetTo) {
SubDubType.SUB -> "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
}
}
}
}

View File

@@ -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 =
"(?<!part\\s)\\b(\\d+)\\b"
const val seasonRegex = "(season|s)[\\s:.\\-]*(\\d+)[\\s:.\\-]*"
const val subdubRegex = "^(soft)?[\\s-]*(sub|dub|mixed)(bed|s)?\\s*$"
fun setSubDub(text: String, typeToSetTo: SubDubType): String? {
val subdubPattern: Pattern = Pattern.compile(subdubRegex, Pattern.CASE_INSENSITIVE)
val subdubMatcher: Matcher = subdubPattern.matcher(text)
return if (subdubMatcher.find()) {
val soft = subdubMatcher.group(1)
val subdub = subdubMatcher.group(2)
val bed = subdubMatcher.group(3) ?: ""
val toggled = when (typeToSetTo) {
SubDubType.SUB -> "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
}
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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
} ?: ""

View File

@@ -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 ""}")
}

View File

@@ -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
}

View File

@@ -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 = "(?<!part\\s)\\b(\\d+)\\b"
fun findChapterNumber(text: String): Float? {
val pattern: Pattern = Pattern.compile(chapterRegex, Pattern.CASE_INSENSITIVE)
val matcher: Matcher = pattern.matcher(text)
return if (matcher.find()) {
matcher.group(2)?.toFloat()
} else {
val failedChapterNumberPattern: Pattern =
Pattern.compile(filedChapterNumberRegex, Pattern.CASE_INSENSITIVE)
val failedChapterNumberMatcher: Matcher =
failedChapterNumberPattern.matcher(text)
if (failedChapterNumberMatcher.find()) {
failedChapterNumberMatcher.group(1)?.toFloat()
} else {
null
}
}
}
}
}

View File

@@ -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.media.anime.handleProgress
import ani.dantotsu.openSettings
@@ -385,8 +386,8 @@ class MangaReadAdapter(
)
}
val startChapter = MangaNameAdapter.findChapterNumber(names[limit * (position)])
val endChapter = MangaNameAdapter.findChapterNumber(names[last - 1])
val startChapter = MediaNameAdapter.findChapterNumber(names[limit * (position)])
val endChapter = MediaNameAdapter.findChapterNumber(names[last - 1])
val startChapterString = if (startChapter != null) {
"Ch.$startChapter"
} else {
@@ -448,7 +449,7 @@ class MangaReadAdapter(
chapter.scanlator !in hiddenScanlators
}
val formattedChapters = filteredChapters.map {
MangaNameAdapter.findChapterNumber(it)?.toInt()?.toString()
MediaNameAdapter.findChapterNumber(it)?.toInt()?.toString()
}
if (formattedChapters.contains(continueEp)) {
continueEp = chapters[formattedChapters.indexOf(continueEp)]

View File

@@ -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.media.manga.mangareader.ChapterLoaderDialog
import ani.dantotsu.navBarHeight
import ani.dantotsu.notifications.subscription.SubscriptionHelper
@@ -227,7 +228,7 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
val chapters = media.manga?.chapters?.values?.toList()
//filter by selected language
val progressChapterIndex = (chapters?.indexOfFirst {
MangaNameAdapter.findChapterNumber(it.number)?.toInt() == selected
MediaNameAdapter.findChapterNumber(it.number)?.toInt() == selected
} ?: 0) + 1
if (progressChapterIndex < 0 || n < 1 || chapters == null) return

View File

@@ -57,9 +57,9 @@ import ani.dantotsu.logError
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaDetailsViewModel
import ani.dantotsu.media.MediaSingleton
import ani.dantotsu.media.MediaNameAdapter
import ani.dantotsu.media.manga.MangaCache
import ani.dantotsu.media.manga.MangaChapter
import ani.dantotsu.media.manga.MangaNameAdapter
import ani.dantotsu.others.ImageViewDialog
import ani.dantotsu.parsers.HMangaSources
import ani.dantotsu.parsers.MangaImage
@@ -180,7 +180,7 @@ class MangaReaderActivity : AppCompatActivity() {
defaultSettings = loadReaderSettings("reader_settings") ?: defaultSettings
onBackPressedDispatcher.addCallback(this) {
val chapter = (MangaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!)
val chapter = (MediaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!)
?.minus(1L) ?: 0).toString()
if (chapter == "0.0" && PrefManager.getVal(PrefName.ChapterZeroReader)
// Not asking individually or incognito
@@ -978,7 +978,7 @@ class MangaReaderActivity : AppCompatActivity() {
PrefManager.setCustomVal("${media.id}_save_progress", true)
updateProgress(
media,
MangaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!)
MediaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!)
.toString()
)
dialog.dismiss()
@@ -1000,7 +1000,7 @@ class MangaReaderActivity : AppCompatActivity() {
)
updateProgress(
media,
MangaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!)
MediaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!)
.toString()
)
runnable.run()

View File

@@ -3,13 +3,11 @@ package ani.dantotsu.notifications.subscription
import ani.dantotsu.R
import ani.dantotsu.currContext
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaNameAdapter
import ani.dantotsu.media.Selected
import ani.dantotsu.media.manga.MangaNameAdapter
import ani.dantotsu.parsers.AnimeParser
import ani.dantotsu.parsers.AnimeSources
import ani.dantotsu.parsers.Episode
import ani.dantotsu.parsers.HAnimeSources
import ani.dantotsu.parsers.HMangaSources
import ani.dantotsu.parsers.MangaChapter
import ani.dantotsu.parsers.MangaParser
import ani.dantotsu.parsers.MangaSources
@@ -105,7 +103,7 @@ class SubscriptionHelper {
}
return chp?.apply {
selected.latest = MangaNameAdapter.findChapterNumber(number) ?: 0f
selected.latest = MediaNameAdapter.findChapterNumber(number) ?: 0f
saveSelected(id, selected)
}
}

View File

@@ -3,7 +3,7 @@ package ani.dantotsu.parsers
import android.content.Context
import ani.dantotsu.FileUrl
import ani.dantotsu.currContext
import ani.dantotsu.media.anime.AnimeNameAdapter
import ani.dantotsu.media.MediaNameAdapter
import ani.dantotsu.media.manga.ImageData
import ani.dantotsu.media.manga.MangaCache
import ani.dantotsu.snackString
@@ -73,12 +73,12 @@ 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 ->
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 {

View File

@@ -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) }
}
/**

View File

@@ -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()

View File

@@ -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()

View File

@@ -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(

View File

@@ -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)

View File

@@ -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

View File

@@ -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))
}
)
}

View File

@@ -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

View File

@@ -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

View File

@@ -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))
}
)
}

View File

@@ -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
}
}

View File

@@ -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"
}
}

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@@ -0,0 +1,13 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:tint="#000000"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp">
<path
android:fillColor="@android:color/white"
android:pathData="M14,5c0,-1.1 -0.9,-2 -2,-2h-1L11,2c0,-0.55 -0.45,-1 -1,-1L6,1c-0.55,0 -1,0.45 -1,1v1L4,3c-1.1,0 -2,0.9 -2,2v15c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2h8L22,5h-8zM12,18h-2v-2h2v2zM12,9h-2L10,7h2v2zM16,18h-2v-2h2v2zM16,9h-2L14,7h2v2zM20,18h-2v-2h2v2zM20,9h-2L18,7h2v2z"/>
</vector>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="rectangle">
<corners
android:topLeftRadius="28dp"
android:topRightRadius="28dp"
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp"/>
</shape>
</item>
<item
android:left="-3dp"
android:right="-3dp"
android:bottom="-50dp">
<shape>
<stroke android:width="2dp" android:color="@color/bg_white" />
<corners
android:topLeftRadius="28dp"
android:topRightRadius="28dp"
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp"/>
</shape>
</item>
</layer-list>

View File

@@ -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"

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/allAnimeExtensionsRecyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>

View File

@@ -7,7 +7,7 @@
android:paddingEnd="16dp">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/allMangaExtensionsRecyclerView"
android:id="@+id/allExtensionsRecyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />

View File

@@ -0,0 +1,188 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:theme="@style/Theme.Dantotsu.AppWidgetContainer"
android:orientation="vertical">
<ImageView
android:id="@+id/backgroundView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/widget_stats_rounded"
tools:ignore="ContentDescription"/>
<LinearLayout
android:id="@+id/headerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:layout_margin="4dp"
android:orientation="horizontal"
android:baselineAligned="false">
<ImageView
android:id="@+id/userAvatar"
android:layout_width="32dp"
android:layout_height="32dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_dantotsu_round"
tools:ignore="ContentDescription"/>
<TextView
android:id="@+id/userLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="8dp"
android:fontFamily="@font/poppins_bold"
android:textSize="18sp"
android:text="@string/loading"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:padding="4dp"
android:orientation="vertical"
android:background="@drawable/widget_stats_rounded"
android:layout_below="@id/headerLayout">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_gravity="center"
android:orientation="horizontal"
android:baselineAligned="false">
<LinearLayout
android:id="@+id/topLeft"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:orientation="vertical"
tools:ignore="NestedWeights">
<TextView
android:id="@+id/topLeftItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:fontFamily="@font/poppins_bold"
android:text="@string/loading"/>
<TextView
android:id="@+id/topLeftLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/anime_watched" />
</LinearLayout>
<RelativeLayout
android:id="@+id/dividerTop"
android:layout_width="4dp"
android:layout_height="match_parent"
android:layout_marginTop="4dp"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/topRight"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/topRightItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:fontFamily="@font/poppins_bold"
android:text="@string/loading"/>
<TextView
android:id="@+id/topRightLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/episodes_watched_n"/>
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:id="@+id/dividerMiddle"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_margin="4dp"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/bottomLeft"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_gravity="center"
android:orientation="horizontal"
android:baselineAligned="false">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:orientation="vertical"
tools:ignore="NestedWeights">
<TextView
android:id="@+id/bottomLeftItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:fontFamily="@font/poppins_bold"
android:text="@string/loading"/>
<TextView
android:id="@+id/bottomLeftLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/manga_read"
android:layout_gravity="center"
android:gravity="center"/>
</LinearLayout>
<RelativeLayout
android:id="@+id/dividerBottom"
android:layout_width="4dp"
android:layout_height="match_parent"
android:layout_marginBottom="4dp"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/bottomRight"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/bottomRightItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:fontFamily="@font/poppins_bold"
android:text="@string/loading"/>
<TextView
android:id="@+id/bottomRightLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/chapters_read_n"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>

View File

@@ -0,0 +1,139 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:gravity="center"
android:fontFamily="@font/poppins_bold"
android:text="@string/profile_stats_widget" />
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/useAppTheme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:checked="false"
android:drawableStart="@drawable/ic_palette"
android:drawablePadding="16dp"
android:elegantTextHeight="true"
android:fontFamily="@font/poppins_bold"
android:minHeight="64dp"
android:text="@string/use_app_theme"
android:textAlignment="viewStart"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:drawableTint="?attr/colorPrimary"
app:showText="false"
app:thumbTint="@color/button_switch_track" />
<Button
android:id="@+id/topBackgroundButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_marginStart="-31dp"
android:layout_marginEnd="-31dp"
android:background="@drawable/ui_bg"
android:backgroundTint="?attr/colorSecondary"
android:backgroundTintMode="src_atop"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="31dp"
android:paddingEnd="31dp"
android:text="@string/top_background_color"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:icon="@drawable/shape_corner_16dp"
app:iconPadding="16dp"
app:iconSize="24dp"
app:iconTint="?attr/colorPrimary" />
<Button
android:id="@+id/bottomBackgroundButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_marginStart="-31dp"
android:layout_marginEnd="-31dp"
android:background="@drawable/ui_bg"
android:backgroundTint="?attr/colorSecondary"
android:backgroundTintMode="src_atop"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="31dp"
android:paddingEnd="31dp"
android:text="@string/bottom_background_color"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:icon="@drawable/shape_corner_16dp"
app:iconPadding="16dp"
app:iconSize="24dp"
app:iconTint="?attr/colorPrimary" />
<Button
android:id="@+id/titleColorButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_marginStart="-31dp"
android:layout_marginEnd="-31dp"
android:background="@drawable/ui_bg"
android:backgroundTint="?attr/colorSecondary"
android:backgroundTintMode="src_atop"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="31dp"
android:paddingEnd="31dp"
android:text="@string/title_color"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:icon="@drawable/shape_corner_16dp"
app:iconPadding="16dp"
app:iconSize="24dp"
app:iconTint="?attr/colorPrimary" />
<Button
android:id="@+id/statsColorButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_marginStart="-31dp"
android:layout_marginEnd="-31dp"
android:background="@drawable/ui_bg"
android:backgroundTint="?attr/colorSecondary"
android:backgroundTintMode="src_atop"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="31dp"
android:paddingEnd="31dp"
android:text="@string/stat_text_color"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:icon="@drawable/shape_corner_16dp"
app:iconPadding="16dp"
app:iconSize="24dp"
app:iconTint="?attr/colorPrimary" />
<com.google.android.material.button.MaterialButton
android:id="@+id/add_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/add_widget" />
</LinearLayout>

View File

@@ -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"/>
<RelativeLayout
android:id="@+id/widgetContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp">
android:padding="16dp">
<ImageView
android:id="@+id/logoView"

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
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" />
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/useAppTheme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:checked="false"
android:drawableStart="@drawable/ic_palette"
android:drawablePadding="16dp"
android:elegantTextHeight="true"
android:fontFamily="@font/poppins_bold"
android:minHeight="64dp"
android:text="@string/use_app_theme"
android:textAlignment="viewStart"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:drawableTint="?attr/colorPrimary"
app:showText="false"
app:thumbTint="@color/button_switch_track" />
<Button
android:id="@+id/topBackgroundButton"
android:layout_width="match_parent"
@@ -31,7 +51,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" />
@@ -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" />
<Button
android:id="@+id/add_button"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/add_widget" />

View File

@@ -9,6 +9,7 @@
<color name="bg_opp">@color/bg_black</color>
<color name="fg">#A8000000</color>
<color name="bg_black_50" alpha="128">#80000000</color>
<color name="bg_white_50" alpha="128">#80FFFFFF</color>
<color name="nav_bg">#fff</color>
<color name="nav_bg_inv">#00BFAEAE</color>
<color name="gradiant_bg_start">#ACACAC</color>

View File

@@ -53,7 +53,9 @@
<string name="username">Username</string>
<string name="chapters_read">"Chapters Read "</string>
<string name="chapters_read_n">"Chapters\nRead "</string>
<string name="episodes_watched">"Episodes Watched "</string>
<string name="episodes_watched_n">"Episodes\nWatched "</string>
<string name="continue_reading">Continue Reading</string>
<string name="continue_watching">Continue Watching</string>
<string name="recommended">Recommended</string>
@@ -412,6 +414,13 @@
<string name="crop_borders">Crop Borders</string>
<string name="note">NOTE</string>
<string name="installing_extension">Installing extension</string>
<string name="installation_failed">Installation failed: %1$s</string>
<string name="installation_complete">Installation complete</string>
<string name="extension_has_been_installed">The extension has been successfully installed.</string>
<string name="extension_installed">Extension installed</string>
<string name="error_message">Error: %1$s</string>
<string name="install_step">Step: %1$s</string>
<string name="jobless_message">DAMN! YOU TRULY ARE JOBLESS\nYOU REACHED THE END</string>
<string name="file_manager_not_found">Couldn\'t find any File Manager to open SD card</string>
@@ -673,6 +682,7 @@
<string name="NSFWExtention">NSFW Extensions</string>
<string name="skip_loading_extension_icons">Skip loading extension icons</string>
<string name="use_material_you">Material You</string>
<string name="use_app_theme">Use App Theme</string>
<string name="extension_specific_dns">Extension-specific DNS</string>
<string name="theme_">Theme:</string>
<string name="user_agent">User Agent</string>
@@ -824,10 +834,20 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
<string name="donate">donate :)</string>
<string name="do_it">Do it!</string>
<string name="password">Password</string>
<string name="profile_stats_widget">Track progress directly from your home screen</string>
<string name="anime_watched">Anime\nWatched</string>
<string name="manga_read">Manga\nRead</string>
<string name="loading">Loading…</string>
<string name="user_stats">%1$s\'s Stats</string>
<string name="please">Please</string>
<string name="log_in">log in</string>
<string name="or_join">or join</string>
<string name="top_background_color">Top background color</string>
<string name="bottom_background_color">Bottom Background Color</string>
<string name="countdown_text_color">Countdown Text Color</string>
<string name="title_color">Title Color</string>
<string name="stat_text_color">Stats Text Color</string>
<string name="placeholder">Placeholder</string>
</resources>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/profile_stats_widget"
android:initialKeyguardLayout="@layout/statistics_widget"
android:initialLayout="@layout/statistics_widget"
android:targetCellWidth="3"
android:targetCellHeight="2"
android:minResizeWidth="180dp"
android:minResizeHeight="110dp"
android:previewImage="@drawable/statistics_widget_preview"
android:previewLayout="@layout/statistics_widget"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen"
android:configure="ani.dantotsu.widgets.statistics.ProfileStatsConfigure" />

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/upcoming_anime"
android:configure="ani.dantotsu.widgets.upcoming.UpcomingWidgetConfigureActivity"
android:configure="ani.dantotsu.widgets.upcoming.UpcomingWidgetConfigure"
android:initialKeyguardLayout="@layout/upcoming_widget"
android:initialLayout="@layout/upcoming_widget"
android:minWidth="160dp"
android:minHeight="80dp"
android:previewImage="@drawable/example_appwidget_preview"
android:previewImage="@drawable/upcoming_widget_preview"
android:previewLayout="@layout/upcoming_widget"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="3600000"

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/profile_stats_widget"
android:initialKeyguardLayout="@layout/statistics_widget"
android:initialLayout="@layout/statistics_widget"
android:minWidth="180dp"
android:minHeight="110dp"
android:minResizeWidth="180dp"
android:minResizeHeight="110dp"
android:previewImage="@drawable/statistics_widget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen"
android:configure="ani.dantotsu.widgets.statistics.ProfileStatsConfigure" />

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/upcoming_anime"
android:configure="ani.dantotsu.widgets.upcoming.UpcomingWidgetConfigureActivity"
android:configure="ani.dantotsu.widgets.upcoming.UpcomingWidgetConfigure"
android:initialKeyguardLayout="@layout/upcoming_widget"
android:initialLayout="@layout/upcoming_widget"
android:minWidth="160dp"
android:minHeight="80dp"
android:previewImage="@drawable/example_appwidget_preview"
android:previewImage="@drawable/upcoming_widget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="3600000"
android:widgetCategory="home_screen"/>