mirror of
https://github.com/rebelonion/Dantotsu.git
synced 2026-01-27 15:41:03 +00:00
feat(ALsettings): customList editor
This commit is contained in:
@@ -47,6 +47,10 @@ object Anilist {
|
||||
var rowOrder: String? = null
|
||||
var activityMergeTime: Int? = null
|
||||
var timezone: String? = null
|
||||
var animeCustomLists: List<String>? = null
|
||||
var mangaCustomLists: List<String>? = null
|
||||
var animeSplitCompletedSectionByFormat: Boolean = false
|
||||
var mangaSplitCompletedSectionByFormat: Boolean = false
|
||||
|
||||
val sortBy = listOf(
|
||||
"SCORE_DESC",
|
||||
@@ -183,7 +187,8 @@ object Anilist {
|
||||
"2 days" to 2880,
|
||||
"3 days" to 4320,
|
||||
"1 week" to 10080,
|
||||
"Always" to 20160
|
||||
"2 weeks" to 20160,
|
||||
"Always" to 29160
|
||||
)
|
||||
|
||||
private val cal: Calendar = Calendar.getInstance()
|
||||
|
||||
@@ -127,6 +127,51 @@ class AnilistMutations {
|
||||
ANIME, MANGA, CHARACTER, STAFF, STUDIO
|
||||
}
|
||||
|
||||
suspend fun deleteCustomList(name: String, type: String): Boolean {
|
||||
val query = """
|
||||
mutation (${"$"}name: String, ${"$"}type: MediaType) {
|
||||
DeleteCustomList(customList: ${"$"}name, type: ${"$"}type) {
|
||||
deleted
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
val variables = """
|
||||
{
|
||||
"name": "$name",
|
||||
"type": "$type"
|
||||
}
|
||||
""".trimIndent()
|
||||
val result = executeQuery<JsonObject>(query, variables)
|
||||
return result?.get("errors") == null
|
||||
}
|
||||
|
||||
suspend fun updateCustomLists(animeCustomLists: List<String>?, mangaCustomLists: List<String>?): Boolean {
|
||||
val query = """
|
||||
mutation (${"$"}animeListOptions: MediaListOptionsInput, ${"$"}mangaListOptions: MediaListOptionsInput) {
|
||||
UpdateUser(animeListOptions: ${"$"}animeListOptions, mangaListOptions: ${"$"}mangaListOptions) {
|
||||
mediaListOptions {
|
||||
animeList {
|
||||
customLists
|
||||
}
|
||||
mangaList {
|
||||
customLists
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
val variables = """
|
||||
{
|
||||
${animeCustomLists?.let { """"animeListOptions": {"customLists": ${Gson().toJson(it)}}""" } ?: ""}
|
||||
${if (animeCustomLists != null && mangaCustomLists != null) "," else ""}
|
||||
${mangaCustomLists?.let { """"mangaListOptions": {"customLists": ${Gson().toJson(it)}}""" } ?: ""}
|
||||
}
|
||||
""".trimIndent().replace("\n", "").replace(""" """, "").replace(",}", "}")
|
||||
|
||||
val result = executeQuery<JsonObject>(query, variables)
|
||||
return result?.get("errors") == null
|
||||
}
|
||||
|
||||
suspend fun editList(
|
||||
mediaID: Int,
|
||||
progress: Int? = null,
|
||||
@@ -237,7 +282,8 @@ class AnilistMutations {
|
||||
}
|
||||
|
||||
suspend fun toggleFollow(id: Int): Query.ToggleFollow? {
|
||||
return executeQuery<Query.ToggleFollow>("""
|
||||
return executeQuery<Query.ToggleFollow>(
|
||||
"""
|
||||
mutation {
|
||||
ToggleFollow(userId: $id) {
|
||||
id
|
||||
@@ -249,7 +295,8 @@ class AnilistMutations {
|
||||
}
|
||||
|
||||
suspend fun toggleLike(id: Int, type: String): ToggleLike? {
|
||||
return executeQuery<ToggleLike>("""
|
||||
return executeQuery<ToggleLike>(
|
||||
"""
|
||||
mutation Like {
|
||||
ToggleLikeV2(id: $id, type: $type) {
|
||||
__typename
|
||||
|
||||
@@ -61,8 +61,8 @@ class AnilistQueries {
|
||||
mediaListOptions {
|
||||
scoreFormat
|
||||
rowOrder
|
||||
animeList { sectionOrder customLists }
|
||||
mangaList { sectionOrder customLists }
|
||||
animeList { sectionOrder customLists splitCompletedSectionByFormat }
|
||||
mangaList { sectionOrder customLists splitCompletedSectionByFormat }
|
||||
}
|
||||
statistics {
|
||||
anime { episodesWatched }
|
||||
@@ -100,6 +100,16 @@ class AnilistQueries {
|
||||
user.mediaListOptions?.let {
|
||||
Anilist.scoreFormat = it.scoreFormat.toString()
|
||||
Anilist.rowOrder = it.rowOrder
|
||||
|
||||
it.animeList?.let { animeList ->
|
||||
Anilist.animeCustomLists = animeList.customLists
|
||||
Anilist.animeSplitCompletedSectionByFormat = animeList.splitCompletedSectionByFormat ?: false
|
||||
}
|
||||
|
||||
it.mangaList?.let { mangaList ->
|
||||
Anilist.mangaCustomLists = mangaList.customLists
|
||||
Anilist.mangaSplitCompletedSectionByFormat = mangaList.splitCompletedSectionByFormat ?: false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||
binding.mediaTotal.visibility = View.VISIBLE
|
||||
binding.mediaAddToList.text = userStatus
|
||||
} else {
|
||||
binding.mediaAddToList.setText(R.string.add)
|
||||
binding.mediaAddToList.setText(R.string.add_list)
|
||||
}
|
||||
total()
|
||||
binding.mediaAddToList.setOnClickListener {
|
||||
|
||||
@@ -21,7 +21,6 @@ import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.copyToClipboard
|
||||
import ani.dantotsu.currContext
|
||||
import ani.dantotsu.databinding.ActivityExtensionsBinding
|
||||
import ani.dantotsu.databinding.DialogRepositoriesBinding
|
||||
import ani.dantotsu.databinding.ItemRepositoryBinding
|
||||
@@ -327,7 +326,7 @@ class ExtensionsActivity : AppCompatActivity() {
|
||||
val alertDialog = AlertDialog.Builder(this@ExtensionsActivity, R.style.MyPopup)
|
||||
.setTitle(R.string.edit_repositories)
|
||||
.setView(dialogView.root)
|
||||
.setPositiveButton(getString(R.string.add)) { _, _ ->
|
||||
.setPositiveButton(getString(R.string.add_list)) { _, _ ->
|
||||
if (!dialogView.repositoryTextBox.text.isNullOrBlank())
|
||||
processUserInput(dialogView.repositoryTextBox.text.toString(), type)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.HapticFeedbackConstants
|
||||
import android.view.View
|
||||
import android.widget.ArrayAdapter
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.widget.TextView
|
||||
@@ -23,7 +22,6 @@ import ani.dantotsu.loadImage
|
||||
import ani.dantotsu.navBarHeight
|
||||
import ani.dantotsu.openLinkInBrowser
|
||||
import ani.dantotsu.others.CustomBottomDialog
|
||||
import ani.dantotsu.restartApp
|
||||
import ani.dantotsu.settings.saving.PrefManager
|
||||
import ani.dantotsu.settings.saving.PrefName
|
||||
import ani.dantotsu.startMainActivity
|
||||
@@ -117,6 +115,7 @@ class SettingsAccountActivity : AppCompatActivity() {
|
||||
} else {
|
||||
settingsAnilistAvatar.setImageResource(R.drawable.ic_round_person_24)
|
||||
settingsAnilistUsername.visibility = View.GONE
|
||||
settingsRecyclerView.visibility = View.GONE
|
||||
settingsAnilistLogin.setText(R.string.login)
|
||||
settingsAnilistLogin.setOnClickListener {
|
||||
Anilist.loginIntent(context)
|
||||
@@ -148,7 +147,7 @@ class SettingsAccountActivity : AppCompatActivity() {
|
||||
reload()
|
||||
}
|
||||
|
||||
settingsImageSwitcher.visibility = View.VISIBLE
|
||||
settingsPresenceSwitcher.visibility = View.VISIBLE
|
||||
var initialStatus = when (PrefManager.getVal<String>(PrefName.DiscordStatus)) {
|
||||
"online" -> R.drawable.discord_status_online
|
||||
"idle" -> R.drawable.discord_status_idle
|
||||
@@ -156,11 +155,11 @@ class SettingsAccountActivity : AppCompatActivity() {
|
||||
"invisible" -> R.drawable.discord_status_invisible
|
||||
else -> R.drawable.discord_status_online
|
||||
}
|
||||
settingsImageSwitcher.setImageResource(initialStatus)
|
||||
settingsPresenceSwitcher.setImageResource(initialStatus)
|
||||
|
||||
val zoomInAnimation =
|
||||
AnimationUtils.loadAnimation(context, R.anim.bounce_zoom)
|
||||
settingsImageSwitcher.setOnClickListener {
|
||||
settingsPresenceSwitcher.setOnClickListener {
|
||||
var status = "online"
|
||||
initialStatus = when (initialStatus) {
|
||||
R.drawable.discord_status_online -> {
|
||||
@@ -187,16 +186,16 @@ class SettingsAccountActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
PrefManager.setVal(PrefName.DiscordStatus, status)
|
||||
settingsImageSwitcher.setImageResource(initialStatus)
|
||||
settingsImageSwitcher.startAnimation(zoomInAnimation)
|
||||
settingsPresenceSwitcher.setImageResource(initialStatus)
|
||||
settingsPresenceSwitcher.startAnimation(zoomInAnimation)
|
||||
}
|
||||
settingsImageSwitcher.setOnLongClickListener {
|
||||
settingsPresenceSwitcher.setOnLongClickListener {
|
||||
it.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||
DiscordDialogFragment().show(supportFragmentManager, "dialog")
|
||||
true
|
||||
}
|
||||
} else {
|
||||
settingsImageSwitcher.visibility = View.GONE
|
||||
settingsPresenceSwitcher.visibility = View.GONE
|
||||
settingsDiscordAvatar.setImageResource(R.drawable.ic_round_person_24)
|
||||
settingsDiscordUsername.visibility = View.GONE
|
||||
settingsDiscordLogin.setText(R.string.login)
|
||||
|
||||
@@ -3,7 +3,10 @@ package ani.dantotsu.settings
|
||||
import android.os.Bundle
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.LinearLayout
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
@@ -21,6 +24,9 @@ import ani.dantotsu.navBarHeight
|
||||
import ani.dantotsu.restartApp
|
||||
import ani.dantotsu.statusBarHeight
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import ani.dantotsu.toast
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class SettingsAnilistActivity : AppCompatActivity() {
|
||||
@@ -160,6 +166,26 @@ class SettingsAnilistActivity : AppCompatActivity() {
|
||||
settingsAnilistRowOrder.clearFocus()
|
||||
}
|
||||
|
||||
val containers = listOf(binding.animeCustomListsContainer, binding.mangaCustomListsContainer)
|
||||
val customLists = listOf(Anilist.animeCustomLists, Anilist.mangaCustomLists)
|
||||
val buttons = listOf(binding.addAnimeListButton, binding.addMangaListButton)
|
||||
|
||||
containers.forEachIndexed { index, container ->
|
||||
customLists[index]?.forEach { listName ->
|
||||
addCustomListItem(listName, container, index == 0)
|
||||
}
|
||||
}
|
||||
|
||||
buttons.forEachIndexed { index, button ->
|
||||
button.setOnClickListener {
|
||||
addCustomListItem("", containers[index], index == 0)
|
||||
}
|
||||
}
|
||||
|
||||
binding.SettingsAnilistCustomListSave.setOnClickListener {
|
||||
saveCustomLists()
|
||||
}
|
||||
|
||||
val currentTimezone = Anilist.timezone?.let { Anilist.getDisplayTimezone(it) } ?: "(GMT+00:00) London"
|
||||
settingsAnilistTimezone.setText(currentTimezone)
|
||||
settingsAnilistTimezone.setAdapter(
|
||||
@@ -238,4 +264,76 @@ class SettingsAnilistActivity : AppCompatActivity() {
|
||||
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||
|
||||
}
|
||||
private fun addCustomListItem(listName: String, container: LinearLayout, isAnime: Boolean) {
|
||||
val customListItemView = layoutInflater.inflate(R.layout.item_custom_list, container, false)
|
||||
val textInputLayout = customListItemView.findViewById<TextInputLayout>(R.id.customListItem)
|
||||
val editText = textInputLayout.editText as? TextInputEditText
|
||||
editText?.setText(listName)
|
||||
textInputLayout.setEndIconOnClickListener {
|
||||
val name = editText?.text.toString()
|
||||
if (name.isNotEmpty()) {
|
||||
val listExists = if (isAnime) {
|
||||
Anilist.animeCustomLists?.contains(name) ?: false
|
||||
} else {
|
||||
Anilist.mangaCustomLists?.contains(name) ?: false
|
||||
}
|
||||
|
||||
if (listExists) {
|
||||
AlertDialog.Builder(this@SettingsAnilistActivity, R.style.MyPopup)
|
||||
.setTitle(getString(R.string.delete_custom_list))
|
||||
.setMessage(getString(R.string.delete_custom_list_confirm, name))
|
||||
.setPositiveButton(getString(R.string.delete)) { _, _ ->
|
||||
deleteCustomList(name, isAnime)
|
||||
container.removeView(customListItemView)
|
||||
}
|
||||
.setNegativeButton(getString(R.string.cancel), null)
|
||||
.show()
|
||||
} else {
|
||||
container.removeView(customListItemView)
|
||||
}
|
||||
} else {
|
||||
container.removeView(customListItemView)
|
||||
}
|
||||
}
|
||||
container.addView(customListItemView)
|
||||
}
|
||||
|
||||
private fun deleteCustomList(name: String, isAnime: Boolean) {
|
||||
lifecycleScope.launch {
|
||||
val type = if (isAnime) "ANIME" else "MANGA"
|
||||
val success = anilistMutations.deleteCustomList(name, type)
|
||||
if (success) {
|
||||
if (isAnime) {
|
||||
Anilist.animeCustomLists = Anilist.animeCustomLists?.filter { it != name }
|
||||
} else {
|
||||
Anilist.mangaCustomLists = Anilist.mangaCustomLists?.filter { it != name }
|
||||
}
|
||||
toast("Custom list deleted")
|
||||
} else {
|
||||
toast("Failed to delete custom list")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveCustomLists() {
|
||||
val animeCustomLists = binding.animeCustomListsContainer.children
|
||||
.mapNotNull { (it.findViewById<TextInputLayout>(R.id.customListItem).editText as? TextInputEditText)?.text?.toString() }
|
||||
.filter { it.isNotEmpty() }
|
||||
.toList()
|
||||
val mangaCustomLists = binding.mangaCustomListsContainer.children
|
||||
.mapNotNull { (it.findViewById<TextInputLayout>(R.id.customListItem).editText as? TextInputEditText)?.text?.toString() }
|
||||
.filter { it.isNotEmpty() }
|
||||
.toList()
|
||||
|
||||
lifecycleScope.launch {
|
||||
val success = anilistMutations.updateCustomLists(animeCustomLists, mangaCustomLists)
|
||||
if (success) {
|
||||
Anilist.animeCustomLists = animeCustomLists
|
||||
Anilist.mangaCustomLists = mangaCustomLists
|
||||
toast("Custom lists saved")
|
||||
} else {
|
||||
toast("Failed to save custom lists")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,7 @@
|
||||
android:marqueeRepeatLimit="marquee_forever"
|
||||
android:padding="8dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/add"
|
||||
android:text="@string/add_list"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="?attr/colorSecondary"
|
||||
android:textSize="14sp"
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
android:marqueeRepeatLimit="marquee_forever"
|
||||
android:padding="8dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/add"
|
||||
android:text="@string/add_list"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="?attr/colorSecondary"
|
||||
android:textSize="14sp"
|
||||
|
||||
@@ -265,7 +265,7 @@
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/settingsImageSwitcher"
|
||||
android:id="@+id/settingsPresenceSwitcher"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/discord_rich_presence"
|
||||
|
||||
@@ -292,6 +292,69 @@
|
||||
android:textSize="14sp"
|
||||
tools:ignore="LabelFor,TextContrastCheck,DuplicateSpeakableTextCheck" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="32dp"
|
||||
android:alpha="0.58"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:text="@string/custom_anime_list" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/animeCustomListsContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="32dp"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/addAnimeListButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/custom_anime_list"
|
||||
android:layout_marginHorizontal="36dp"
|
||||
android:layout_marginVertical="12dp"
|
||||
android:src="@drawable/ic_circle_add"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
app:tint="?attr/colorPrimary"/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="32dp"
|
||||
android:alpha="0.58"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:text="@string/custom_manga_list" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/mangaCustomListsContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="32dp"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/addMangaListButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/custom_manga_list"
|
||||
android:layout_marginHorizontal="36dp"
|
||||
android:layout_marginVertical="12dp"
|
||||
android:src="@drawable/ic_circle_add"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
app:tint="?attr/colorPrimary"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/SettingsAnilistCustomListSave"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="32dp"
|
||||
android:layout_gravity="end"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:text="@string/save" />
|
||||
|
||||
</ani.dantotsu.others.Xpandable>
|
||||
|
||||
<TextView
|
||||
|
||||
23
app/src/main/res/layout/item_custom_list.xml
Normal file
23
app/src/main/res/layout/item_custom_list.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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="horizontal">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="?attr/textInputFilledStyle"
|
||||
android:id="@+id/customListItem"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:boxBackgroundColor="?attr/colorSurface"
|
||||
app:boxStrokeColor="?attr/colorPrimaryContainer"
|
||||
app:endIconMode ="custom"
|
||||
app:endIconDrawable ="@drawable/ic_round_delete_24">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
||||
@@ -66,7 +66,7 @@
|
||||
<string name="empty">All caught up, when New?</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
|
||||
<string name="add">Add to List</string>
|
||||
<string name="add_list">Add to List</string>
|
||||
<string name="list_editor">List Editor</string>
|
||||
<string name="add_fav">Add to Favourites</string>
|
||||
<string name="notifications">Notifications</string>
|
||||
@@ -337,6 +337,10 @@
|
||||
<string name="selected_score_format">Scoring System</string>
|
||||
<string name="selected_time_zone">Timezone</string>
|
||||
<string name="selected_row_order">Default List Order</string>
|
||||
<string name="custom_anime_list">Custom Anime Lists</string>
|
||||
<string name="custom_manga_list">Custom Manga Lists</string>
|
||||
<string name="delete_custom_list">Delete Custom List</string>
|
||||
<string name="delete_custom_list_confirm">Are you sure you want to delete %1$s ?</string>
|
||||
<string name="keep_screen_on">Keep Screen On</string>
|
||||
<string name="layout">Layout</string>
|
||||
<string name="spaced_pages">Spaced Pages</string>
|
||||
|
||||
Reference in New Issue
Block a user