feat(ALsettings): functional backend

This commit is contained in:
sneazy-ibo
2024-07-01 22:53:08 +02:00
parent c2af6f15e5
commit fa55acf770
8 changed files with 470 additions and 73 deletions

View File

@@ -159,6 +159,9 @@
<activity
android:name=".settings.SettingsAddonActivity"
android:parentActivityName=".MainActivity" />
<activity
android:name=".settings.SettingsAnilistActivity"
android:parentActivityName=".MainActivity" />
<activity
android:name=".settings.SettingsMangaActivity"
android:parentActivityName=".MainActivity" />

View File

@@ -10,9 +10,80 @@ import kotlinx.serialization.json.JsonObject
class AnilistMutations {
suspend fun updateSettings(
timezone: String? = null,
titleLanguage: String? = null,
staffNameLanguage: String? = null,
activityMergeTime: Int? = null,
airingNotifications: Boolean? = null,
displayAdultContent: Boolean? = null,
restrictMessagesToFollowing: Boolean? = null
) {
val query = """
mutation (
${"$"}timezone: String,
${"$"}titleLanguage: UserTitleLanguage,
${"$"}staffNameLanguage: UserStaffNameLanguage,
${"$"}activityMergeTime: Int,
${"$"}airingNotifications: Boolean,
${"$"}displayAdultContent: Boolean
${"$"}restrictMessagesToFollowing: Boolean
) {
UpdateUser(
timezone: ${"$"}timezone,
titleLanguage: ${"$"}titleLanguage,
staffNameLanguage: ${"$"}staffNameLanguage,
activityMergeTime: ${"$"}activityMergeTime,
airingNotifications: ${"$"}airingNotifications,
displayAdultContent: ${"$"}displayAdultContent
restrictMessagesToFollowing: ${"$"}restrictMessagesToFollowing
) {
id
options {
timezone
titleLanguage
staffNameLanguage
activityMergeTime
airingNotifications
displayAdultContent
restrictMessagesToFollowing
}
}
}
""".trimIndent()
val variables = """
{
${timezone?.let { """"timezone":"$it"""" } ?: ""}
${titleLanguage?.let { """"titleLanguage":"$it"""" } ?: ""}
${staffNameLanguage?.let { """"staffNameLanguage":"$it"""" } ?: ""}
${activityMergeTime?.let { """"activityMergeTime":$it""" } ?: ""}
${airingNotifications?.let { """"airingNotifications":$it""" } ?: ""}
${displayAdultContent?.let { """"displayAdultContent":$it""" } ?: ""}
${restrictMessagesToFollowing?.let { """"restrictMessagesToFollowing":$it""" } ?: ""}
}
""".trimIndent().replace("\n", "").replace(""" """, "").replace(",}", "}")
executeQuery<JsonObject>(query, variables)
}
suspend fun toggleFav(anime: Boolean = true, id: Int) {
val query =
"""mutation (${"$"}animeId: Int,${"$"}mangaId:Int) { ToggleFavourite(animeId:${"$"}animeId,mangaId:${"$"}mangaId){ anime { edges { id } } manga { edges { id } } } }"""
val query = """
mutation (${"$"}animeId: Int, ${"$"}mangaId: Int) {
ToggleFavourite(animeId: ${"$"}animeId, mangaId: ${"$"}mangaId) {
anime {
edges {
id
}
}
manga {
edges {
id
}
}
}
}
""".trimIndent()
val variables = if (anime) """{"animeId":"$id"}""" else """{"mangaId":"$id"}"""
executeQuery<JsonObject>(query, variables)
}
@@ -25,7 +96,17 @@ class AnilistMutations {
FavType.STAFF -> "staffId"
FavType.STUDIO -> "studioId"
}
val query = """mutation{ToggleFavourite($filter:$id){anime{pageInfo{total}}}}"""
val query = """
mutation {
ToggleFavourite($filter: $id) {
anime {
pageInfo {
total
}
}
}
}
""".trimIndent()
val result = executeQuery<JsonObject>(query)
return result?.get("errors") == null && result != null
}
@@ -46,14 +127,45 @@ class AnilistMutations {
completedAt: FuzzyDate? = null,
customList: List<String>? = null
) {
val query = """
mutation ( ${"$"}mediaID: Int, ${"$"}progress: Int,${"$"}private:Boolean,${"$"}repeat: Int, ${"$"}notes: String, ${"$"}customLists: [String], ${"$"}scoreRaw:Int, ${"$"}status:MediaListStatus, ${"$"}start:FuzzyDateInput${if (startedAt != null) "=" + startedAt.toVariableString() else ""}, ${"$"}completed:FuzzyDateInput${if (completedAt != null) "=" + completedAt.toVariableString() else ""} ) {
SaveMediaListEntry( mediaId: ${"$"}mediaID, progress: ${"$"}progress, repeat: ${"$"}repeat, notes: ${"$"}notes, private: ${"$"}private, scoreRaw: ${"$"}scoreRaw, status:${"$"}status, startedAt: ${"$"}start, completedAt: ${"$"}completed , customLists: ${"$"}customLists ) {
score(format:POINT_10_DECIMAL) startedAt{year month day} completedAt{year month day}
mutation (
${"$"}mediaID: Int,
${"$"}progress: Int,
${"$"}private: Boolean,
${"$"}repeat: Int,
${"$"}notes: String,
${"$"}customLists: [String],
${"$"}scoreRaw: Int,
${"$"}status: MediaListStatus,
${"$"}start: FuzzyDateInput${if (startedAt != null) "=" + startedAt.toVariableString() else ""},
${"$"}completed: FuzzyDateInput${if (completedAt != null) "=" + completedAt.toVariableString() else ""}
) {
SaveMediaListEntry(
mediaId: ${"$"}mediaID,
progress: ${"$"}progress,
repeat: ${"$"}repeat,
notes: ${"$"}notes,
private: ${"$"}private,
scoreRaw: ${"$"}scoreRaw,
status: ${"$"}status,
startedAt: ${"$"}start,
completedAt: ${"$"}completed,
customLists: ${"$"}customLists
) {
score(format: POINT_10_DECIMAL)
startedAt {
year
month
day
}
completedAt {
year
month
day
}
}
}
""".replace("\n", "").replace(""" """, "")
""".trimIndent()
val variables = """{"mediaID":$mediaID
${if (private != null) ""","private":$private""" else ""}
@@ -69,91 +181,168 @@ class AnilistMutations {
}
suspend fun deleteList(listId: Int) {
val query = "mutation(${"$"}id:Int){DeleteMediaListEntry(id:${"$"}id){deleted}}"
val query = """
mutation(${"$"}id: Int) {
DeleteMediaListEntry(id: ${"$"}id) {
deleted
}
}
""".trimIndent()
val variables = """{"id":"$listId"}"""
executeQuery<JsonObject>(query, variables)
}
suspend fun rateReview(reviewId: Int, rating: String): Query.RateReviewResponse? {
val query =
"mutation{RateReview(reviewId:$reviewId,rating:$rating){id mediaId mediaType summary body(asHtml:true)rating ratingAmount userRating score private siteUrl createdAt updatedAt user{id name bannerImage avatar{medium large}}}}"
val query = """
mutation {
RateReview(reviewId: $reviewId, rating: $rating) {
id
mediaId
mediaType
summary
body(asHtml: true)
rating
ratingAmount
userRating
score
private
siteUrl
createdAt
updatedAt
user {
id
name
bannerImage
avatar {
medium
large
}
}
}
}
""".trimIndent()
return executeQuery<Query.RateReviewResponse>(query)
}
suspend fun toggleFollow(id: Int): Query.ToggleFollow? {
return executeQuery<Query.ToggleFollow>(
"""mutation{ToggleFollow(userId:$id){id, isFollowing, isFollower}}"""
)
return executeQuery<Query.ToggleFollow>("""
mutation {
ToggleFollow(userId: $id) {
id
isFollowing
isFollower
}
}
""".trimIndent())
}
suspend fun toggleLike(id: Int, type: String): ToggleLike? {
return executeQuery<ToggleLike>(
"""mutation Like{ToggleLikeV2(id:$id,type:$type){__typename}}"""
)
return executeQuery<ToggleLike>("""
mutation Like {
ToggleLikeV2(id: $id, type: $type) {
__typename
}
}
""".trimIndent())
}
suspend fun postActivity(text: String, edit: Int? = null): String {
val encodedText = text.stringSanitizer()
val query =
"mutation{SaveTextActivity(${if (edit != null) "id:$edit," else ""} text:$encodedText){siteUrl}}"
val query = """
mutation {
SaveTextActivity(${if (edit != null) "id: $edit," else ""} text: $encodedText) {
siteUrl
}
}
""".trimIndent()
val result = executeQuery<JsonObject>(query)
val errors = result?.get("errors")
return errors?.toString()
?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success")
return errors?.toString() ?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success")
}
suspend fun postMessage(
userId: Int,
text: String,
edit: Int? = null,
isPrivate: Boolean = false
): String {
suspend fun postMessage(userId: Int, text: String, edit: Int? = null, isPrivate: Boolean = false): String {
val encodedText = text.replace("", "").stringSanitizer()
val query =
"mutation{SaveMessageActivity(${if (edit != null) "id:$edit," else ""} recipientId:$userId,message:$encodedText,private:$isPrivate){id}}"
val query = """
mutation {
SaveMessageActivity(
${if (edit != null) "id: $edit," else ""}
recipientId: $userId,
message: $encodedText,
private: $isPrivate
) {
id
}
}
""".trimIndent()
val result = executeQuery<JsonObject>(query)
val errors = result?.get("errors")
return errors?.toString()
?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success")
return errors?.toString() ?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success")
}
suspend fun postReply(activityId: Int, text: String, edit: Int? = null): String {
val encodedText = text.stringSanitizer()
val query =
"mutation{SaveActivityReply(${if (edit != null) "id:$edit," else ""} activityId:$activityId,text:$encodedText){id}}"
val query = """
mutation {
SaveActivityReply(
${if (edit != null) "id: $edit," else ""}
activityId: $activityId,
text: $encodedText
) {
id
}
}
""".trimIndent()
val result = executeQuery<JsonObject>(query)
val errors = result?.get("errors")
return errors?.toString()
?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success")
return errors?.toString() ?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success")
}
suspend fun postReview(summary: String, body: String, mediaId: Int, score: Int): String {
val encodedSummary = summary.stringSanitizer()
val encodedBody = body.stringSanitizer()
val query =
"mutation{SaveReview(mediaId:$mediaId,summary:$encodedSummary,body:$encodedBody,score:$score){siteUrl}}"
val query = """
mutation {
SaveReview(
mediaId: $mediaId,
summary: $encodedSummary,
body: $encodedBody,
score: $score
) {
siteUrl
}
}
""".trimIndent()
val result = executeQuery<JsonObject>(query)
val errors = result?.get("errors")
return errors?.toString()
?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success")
return errors?.toString() ?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success")
}
suspend fun deleteActivityReply(activityId: Int): Boolean {
val query = "mutation{DeleteActivityReply(id:$activityId){deleted}}"
val query = """
mutation {
DeleteActivityReply(id: $activityId) {
deleted
}
}
""".trimIndent()
val result = executeQuery<JsonObject>(query)
val errors = result?.get("errors")
return errors == null
}
suspend fun deleteActivity(activityId: Int): Boolean {
val query = "mutation{DeleteActivity(id:$activityId){deleted}}"
val query = """
mutation {
DeleteActivity(id: $activityId) {
deleted
}
}
""".trimIndent()
val result = executeQuery<JsonObject>(query)
val errors = result?.get("errors")
return errors == null
}
private fun String.stringSanitizer(): String {
val sb = StringBuilder()
var i = 0

View File

@@ -42,8 +42,34 @@ class AnilistQueries {
suspend fun getUserData(): Boolean {
val response: Query.Viewer?
measureTimeMillis {
response =
executeQuery("""{Viewer{name options{displayAdultContent}avatar{medium}bannerImage id mediaListOptions{rowOrder animeList{sectionOrder customLists}mangaList{sectionOrder customLists}}statistics{anime{episodesWatched}manga{chaptersRead}}unreadNotificationCount}}""")
response = executeQuery("""
{
Viewer {
name
options {
restrictMessagesToFollowing
displayAdultContent
airingNotifications
staffNameLanguage
titleLanguage
timezone
}
avatar { medium }
bannerImage
id
mediaListOptions {
rowOrder
animeList { sectionOrder customLists }
mangaList { sectionOrder customLists }
}
statistics {
anime { episodesWatched }
manga { chaptersRead }
}
unreadNotificationCount
}
}
""")
}.also { println("time : $it") }
val user = response?.data?.user ?: return false
@@ -60,6 +86,14 @@ class AnilistQueries {
val unread = PrefManager.getVal<Int>(PrefName.UnreadCommentNotifications)
Anilist.unreadNotificationCount += unread
Anilist.initialized = true
user.options?.let {
PrefManager.setVal(PrefName.AnilistTitleLanguage, it.titleLanguage)
PrefManager.setVal(PrefName.AnilistStaffNameLanguage, it.staffNameLanguage)
PrefManager.setVal(PrefName.AnilistDisplayAdultContent, it.displayAdultContent)
PrefManager.setVal(PrefName.AnilistAiringNotifications, it.airingNotifications)
PrefManager.setVal(PrefName.AnilistRestrictMessagesToFollowing, it.restrictMessagesToFollowing)
}
return true
}

View File

@@ -74,7 +74,7 @@ data class User(
@Serializable
data class UserOptions(
// The language the user wants to see media titles in
// @SerialName("titleLanguage") var titleLanguage: UserTitleLanguage?,
@SerialName("titleLanguage") var titleLanguage: UserTitleLanguage?,
// Whether the user has enabled viewing of 18+ content
@SerialName("displayAdultContent") var displayAdultContent: Boolean?,
@@ -94,11 +94,11 @@ data class UserOptions(
// // Minutes between activity for them to be merged together. 0 is Never, Above 2 weeks (20160 mins) is Always.
// @SerialName("activityMergeTime") var activityMergeTime: Int?,
//
// // The language the user wants to see staff and character names in
// // @SerialName("staffNameLanguage") var staffNameLanguage: UserStaffNameLanguage?,
// The language the user wants to see staff and character names in
@SerialName("staffNameLanguage") var staffNameLanguage: UserStaffNameLanguage?,
//
// // Whether the user only allow messages from users they follow
// @SerialName("restrictMessagesToFollowing") var restrictMessagesToFollowing: Boolean?,
// Whether the user only allow messages from users they follow
@SerialName("restrictMessagesToFollowing") var restrictMessagesToFollowing: Boolean?,
// The list activity types the user has disabled from being created from list updates
// @SerialName("disabledListActivity") var disabledListActivity: List<ListActivityOption>?,
@@ -119,6 +119,28 @@ data class UserStatisticTypes(
@SerialName("manga") var manga: UserStatistics?
)
@Serializable
enum class UserTitleLanguage {
@SerialName("ENGLISH")
ENGLISH,
@SerialName("ROMAJI")
ROMAJI,
@SerialName("NATIVE")
NATIVE
}
@Serializable
enum class UserStaffNameLanguage {
@SerialName("ENGLISH")
ENGLISH,
@SerialName("ROMAJI")
ROMAJI,
@SerialName("NATIVE")
NATIVE
}
@Serializable
data class UserStatistics(
//

View File

@@ -1,9 +1,7 @@
package ani.dantotsu.settings
import android.content.Context
import android.os.Bundle
import android.view.ViewGroup
import android.view.animation.LinearInterpolator
import android.widget.ArrayAdapter
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.updateLayoutParams
@@ -11,18 +9,18 @@ import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import ani.dantotsu.R
import ani.dantotsu.databinding.ActivitySettingsAnilistBinding
import ani.dantotsu.databinding.ItemSettingsBinding
import ani.dantotsu.initActivity
import ani.dantotsu.navBarHeight
import ani.dantotsu.restartApp
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.util.Logger
import ani.dantotsu.connections.anilist.AnilistMutations
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import kotlinx.coroutines.launch
class SettingsAnilistActivity : AppCompatActivity() {
private lateinit var binding: ActivitySettingsAnilistBinding
private lateinit var anilistMutations: AnilistMutations
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -32,6 +30,8 @@ class SettingsAnilistActivity : AppCompatActivity() {
binding = ActivitySettingsAnilistBinding.inflate(layoutInflater)
setContentView(binding.root)
anilistMutations = AnilistMutations()
binding.apply {
settingsAnilistLayout.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = statusBarHeight
@@ -41,32 +41,128 @@ class SettingsAnilistActivity : AppCompatActivity() {
onBackPressedDispatcher.onBackPressed()
}
val timeZone = listOf(
"(GMT-06:00) Central Time",
"(GMT-05:00) Eastern Time",
"(GMT-04:00) Atlantic Time",
"(GMT-01:00) Central Time",
"(GMT+00:00) London",
"(GMT+01:00) Berlin",
"(GMT+04:00) Dubai",
"(GMT+05:30) India Standard Time",
"(GMT+06:00) Dhaka",
"(GMT+07:00) Bangkok",
"(GMT+09:00) Tokyo",
)
val titleLang = listOf(
"English (Attack on Titan)",
"Romaji (Shingeki no Kyojin)",
"Native (進撃の巨人)"
)
settingsAnilistLanguage.setText(titleLang[PrefManager.getVal(PrefName.SelectedLanguage)])
settingsAnilistLanguage.setAdapter(
ArrayAdapter(
context, R.layout.item_dropdown, titleLang
)
val staffNameLang = listOf(
"Romaji, Western Order (Killua Zoldyck)",
"Romaji (Zoldyck Killua)",
"Native (キルア=ゾルディック)"
)
settingsAnilistLanguage.setOnItemClickListener { _, _, i, _ ->
PrefManager.setVal(PrefName.SelectedLanguage, i)
settingsAnilistLanguage.clearFocus()
val currentTitleLang = PrefManager.getVal(PrefName.AnilistTitleLanguage, "ENGLISH")
val currentStaffNameLang = PrefManager.getVal(PrefName.AnilistStaffNameLanguage, "ENGLISH")
val titleLangIndex = when (currentTitleLang) {
"ENGLISH" -> 0
"ROMAJI" -> 1
"NATIVE" -> 2
else -> 0
}
val staffNameLangIndex = when (currentStaffNameLang) {
"ENGLISH" -> 0
"ROMAJI" -> 1
"NATIVE" -> 2
else -> 0
}
settingsAnilistTitleLanguage.setText(titleLang[titleLangIndex])
settingsAnilistTitleLanguage.setAdapter(
ArrayAdapter(context, R.layout.item_dropdown, titleLang)
)
settingsAnilistTitleLanguage.setOnItemClickListener { _, _, i, _ ->
val selectedLanguage = when (i) {
0 -> "ENGLISH"
1 -> "ROMAJI"
2 -> "NATIVE"
else -> "ENGLISH"
}
lifecycleScope.launch {
anilistMutations.updateSettings(titleLanguage = selectedLanguage)
PrefManager.setVal(PrefName.AnilistTitleLanguage, selectedLanguage)
}
settingsAnilistTitleLanguage.clearFocus()
}
settingsAnilistStaffLanguage.setText(staffNameLang[staffNameLangIndex])
settingsAnilistStaffLanguage.setAdapter(
ArrayAdapter(context, R.layout.item_dropdown, staffNameLang)
)
settingsAnilistStaffLanguage.setOnItemClickListener { _, _, i, _ ->
val selectedLanguage = when (i) {
0 -> "ENGLISH"
1 -> "ROMAJI"
2 -> "NATIVE"
else -> "ENGLISH"
}
lifecycleScope.launch {
anilistMutations.updateSettings(staffNameLanguage = selectedLanguage)
PrefManager.setVal(PrefName.AnilistStaffNameLanguage, selectedLanguage)
}
settingsAnilistStaffLanguage.clearFocus()
}
// Fetch and set other settings
val displayAdultContent = PrefManager.getVal(PrefName.AnilistDisplayAdultContent, false)
val airingNotifications = PrefManager.getVal(PrefName.AnilistAiringNotifications, false)
val restrictMessagesToFollowing = PrefManager.getVal(PrefName.AnilistRestrictMessagesToFollowing, false)
binding.settingsRecyclerView.adapter = SettingsAdapter(
arrayListOf(
Settings(
type = 2,
name = getString(R.string.airing_notifications),
desc = getString(R.string.airing_notifications_desc),
icon = R.drawable.ic_round_notifications_active_24,
isChecked = airingNotifications,
switch = { isChecked, _ ->
lifecycleScope.launch {
anilistMutations.updateSettings(airingNotifications = isChecked)
PrefManager.setVal(PrefName.AnilistAiringNotifications, isChecked)
}
}
),
Settings(
type = 2,
name = getString(R.string.display_adult_content),
desc = getString(R.string.display_adult_content_desc),
icon = R.drawable.ic_round_nsfw_24,
isChecked = displayAdultContent,
switch = { isChecked, _ ->
lifecycleScope.launch {
anilistMutations.updateSettings(displayAdultContent = isChecked)
PrefManager.setVal(PrefName.AnilistDisplayAdultContent, isChecked)
}
}
),
Settings(
type = 2,
name = getString(R.string.restrict_messages),
desc = getString(R.string.restrict_messages_desc),
icon = R.drawable.ic_round_lock_24,
isChecked = PrefManager.getVal(PrefName.SettingsPreferDub),
icon = R.drawable.ic_round_lock_open_24,
isChecked = restrictMessagesToFollowing,
switch = { isChecked, _ ->
PrefManager.setVal(PrefName.SettingsPreferDub, isChecked)
lifecycleScope.launch {
anilistMutations.updateSettings(restrictMessagesToFollowing = isChecked)
PrefManager.setVal(PrefName.AnilistRestrictMessagesToFollowing, isChecked)
}
}
),
)

View File

@@ -47,6 +47,16 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
IncludeMangaList(Pref(Location.General, Boolean::class, true)),
AdultOnly(Pref(Location.General, Boolean::class, false)),
// Anilist Settings
AnilistTitleLanguage(Pref(Location.General, String::class, "ENGLISH")),
AnilistDisplayAdultContent(Pref(Location.General, Boolean::class, false)),
AnilistAiringNotifications(Pref(Location.General, Boolean::class, false)),
AnilistTimezone(Pref(Location.General, String::class, "(GMT+00:00) London")),
AnilistActivityMergeTime(Pref(Location.General, Int::class, 0)),
AnilistStaffNameLanguage(Pref(Location.General, String::class, "ROMAJI")),
AnilistRestrictMessagesToFollowing(Pref(Location.General, Boolean::class, false)),
AnilistDisabledListActivity(Pref(Location.General, Set::class, setOf<String>())),
//User Interface
UseOLED(Pref(Location.UI, Boolean::class, false)),
UseCustomTheme(Pref(Location.UI, Boolean::class, false)),

View File

@@ -68,7 +68,7 @@
android:layout_marginHorizontal="16dp"
android:alpha="0.58"
android:fontFamily="@font/poppins_bold"
android:text="@string/selected_language" />
android:text="@string/selected_title_language" />
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
@@ -84,7 +84,44 @@
app:startIconDrawable="@drawable/ic_round_dns_24">
<AutoCompleteTextView
android:id="@+id/settingsAnilistLanguage"
android:id="@+id/settings_anilist_title_language"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:fontFamily="@font/poppins_bold"
android:freezesText="false"
android:inputType="none"
android:padding="8dp"
android:text="@string/placeholder"
android:textAllCaps="true"
android:textColor="?android:attr/textColorSecondary"
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="16dp"
android:alpha="0.58"
android:fontFamily="@font/poppins_bold"
android:text="@string/selected_staff_language" />
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginBottom="8dp"
app:boxCornerRadiusBottomEnd="8dp"
app:boxCornerRadiusBottomStart="8dp"
app:boxCornerRadiusTopEnd="8dp"
app:boxCornerRadiusTopStart="8dp"
app:hintAnimationEnabled="true"
app:startIconDrawable="@drawable/ic_round_dns_24">
<AutoCompleteTextView
android:id="@+id/settingsAnilistStaffLanguage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"

View File

@@ -329,7 +329,8 @@
<string name="none">None</string>
<string name="selected_dns">Selected DNS</string>
<string name="dns_info">Change if your ISP blocks any source</string>
<string name="selected_language">Selected Language</string>
<string name="selected_title_language">Selected Title Language</string>
<string name="selected_staff_language">Selected Staff Language</string>
<string name="keep_screen_on">Keep Screen On</string>
<string name="layout">Layout</string>
<string name="spaced_pages">Spaced Pages</string>
@@ -908,6 +909,13 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
<string name="extensions_desc">Manage your reliable repositories</string>
<string name="addons_desc">Get more features out of your app</string>
<string name="alsettings_desc">Change your AniList settings</string>
<string name="airing_notifications">Airing Anime notifications</string>
<string name="airing_notifications_desc">Get notified whenever a new episode drops</string>
<string name="display_adult_content">18+ Content</string>
<string name="display_adult_content_desc">Enable NSFW content</string>
<string name="restrict_messages">Restrict messages to following</string>
<string name="restrict_messages_desc">Allow only users I follow to message me</string>
<string name="notifications_desc">Customise your news and updates</string>
<string name="about_desc">Learn more about Dantotsu</string>
<string name="faq_desc">General questions about Dantotsu</string>
@@ -960,8 +968,6 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
<string name="update_addon">Add-on update available</string>
<string name="install_addon">Install Add-on</string>
<string name="download_addon_not_found">Add-on not found</string>
<string name="restrict_messages">Follower only</string>
<string name="restrict_messages_desc">Restrict Messages to following</string>
<string name="image">Image</string>
<string name="failed_ext_install_conflict">Failed to install extension due to conflict</string>