diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 9b071c2b..c64a42af 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -132,10 +132,11 @@
-
-
+
+
+
diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/Anilist.kt b/app/src/main/java/ani/dantotsu/connections/anilist/Anilist.kt
index a712aba3..6b0d288c 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/Anilist.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/Anilist.kt
@@ -15,6 +15,8 @@ import ani.dantotsu.snackString
import ani.dantotsu.toast
import ani.dantotsu.util.Logger
import java.util.Calendar
+import java.util.Locale
+import kotlin.math.abs
object Anilist {
val query: AnilistQueries = AnilistQueries()
@@ -22,7 +24,7 @@ object Anilist {
var token: String? = null
var username: String? = null
- var adult: Boolean = false
+
var userid: Int? = null
var avatar: String? = null
var bg: String? = null
@@ -36,6 +38,17 @@ object Anilist {
var rateLimitReset: Long = 0
var initialized = false
+ var adult: Boolean = false
+ var titleLanguage: String? = null
+ var staffNameLanguage: String? = null
+ var airingNotifications: Boolean = false
+ var restrictMessagesToFollowing: Boolean = false
+ var scoreFormat: String? = null
+ var rowOrder: String? = null
+ var activityMergeTime: Int? = null
+ var timezone: String? = null
+ var animeCustomLists: List? = null
+ var mangaCustomLists: List? = null
val sortBy = listOf(
"SCORE_DESC",
@@ -96,6 +109,86 @@ object Anilist {
"Original Creator", "Story & Art", "Story"
)
+ val timeZone = listOf(
+ "(GMT-11:00) Pago Pago",
+ "(GMT-10:00) Hawaii Time",
+ "(GMT-09:00) Alaska Time",
+ "(GMT-08:00) Pacific Time",
+ "(GMT-07:00) Mountain Time",
+ "(GMT-06:00) Central Time",
+ "(GMT-05:00) Eastern Time",
+ "(GMT-04:00) Atlantic Time - Halifax",
+ "(GMT-03:00) Sao Paulo",
+ "(GMT-02:00) Mid-Atlantic",
+ "(GMT-01:00) Azores",
+ "(GMT+00:00) London",
+ "(GMT+01:00) Berlin",
+ "(GMT+02:00) Helsinki",
+ "(GMT+03:00) Istanbul",
+ "(GMT+04:00) Dubai",
+ "(GMT+04:30) Kabul",
+ "(GMT+05:00) Maldives",
+ "(GMT+05:30) India Standard Time",
+ "(GMT+05:45) Kathmandu",
+ "(GMT+06:00) Dhaka",
+ "(GMT+06:30) Cocos",
+ "(GMT+07:00) Bangkok",
+ "(GMT+08:00) Hong Kong",
+ "(GMT+08:30) Pyongyang",
+ "(GMT+09:00) Tokyo",
+ "(GMT+09:30) Central Time - Darwin",
+ "(GMT+10:00) Eastern Time - Brisbane",
+ "(GMT+10:30) Central Time - Adelaide",
+ "(GMT+11:00) Eastern Time - Melbourne, Sydney",
+ "(GMT+12:00) Nauru",
+ "(GMT+13:00) Auckland",
+ "(GMT+14:00) Kiritimati",
+ )
+
+ val titleLang = listOf(
+ "English (Attack on Titan)",
+ "Romaji (Shingeki no Kyojin)",
+ "Native (進撃の巨人)"
+ )
+
+ val staffNameLang = listOf(
+ "Romaji, Western Order (Killua Zoldyck)",
+ "Romaji (Zoldyck Killua)",
+ "Native (キルア=ゾルディック)"
+ )
+
+ val ScoreFormat = listOf(
+ "100 Point (55/100)",
+ "10 Point Decimal (5.5/10)",
+ "10 Point (5/10)",
+ "5 Star (3/5)",
+ "3 Point Smiley :)"
+ )
+
+ val rowOrderMap = mapOf(
+ "Score" to "score",
+ "Title" to "title",
+ "Last Updated" to "updatedAt",
+ "Last Added" to "id"
+ )
+
+ val activityMergeTimeMap = mapOf(
+ "Never" to 0,
+ "30 mins" to 30,
+ "69 mins" to 69,
+ "1 hour" to 60,
+ "2 hours" to 120,
+ "3 hours" to 180,
+ "6 hours" to 360,
+ "12 hours" to 720,
+ "1 day" to 1440,
+ "2 days" to 2880,
+ "3 days" to 4320,
+ "1 week" to 10080,
+ "2 weeks" to 20160,
+ "Always" to 29160
+ )
+
private val cal: Calendar = Calendar.getInstance()
private val currentYear = cal.get(Calendar.YEAR)
private val currentSeason: Int = when (cal.get(Calendar.MONTH)) {
@@ -106,6 +199,32 @@ object Anilist {
else -> 0
}
+ fun getDisplayTimezone(apiTimezone: String): String {
+ val parts = apiTimezone.split(":")
+ if (parts.size != 2) return "(GMT+00:00) London"
+
+ val hours = parts[0].toIntOrNull() ?: 0
+ val minutes = parts[1].toIntOrNull() ?: 0
+ val sign = if (hours >= 0) "+" else "-"
+ val formattedHours = String.format(Locale.US, "%02d", abs(hours))
+ val formattedMinutes = String.format(Locale.US, "%02d", minutes)
+
+ val searchString = "(GMT$sign$formattedHours:$formattedMinutes)"
+ return timeZone.find { it.contains(searchString) } ?: "(GMT+00:00) London"
+ }
+
+ fun getApiTimezone(displayTimezone: String): String {
+ val regex = """\(GMT([+-])(\d{2}):(\d{2})\)""".toRegex()
+ val matchResult = regex.find(displayTimezone)
+ return if (matchResult != null) {
+ val (sign, hours, minutes) = matchResult.destructured
+ val formattedSign = if (sign == "+") "" else "-"
+ "$formattedSign$hours:$minutes"
+ } else {
+ "00:00"
+ }
+ }
+
private fun getSeason(next: Boolean): Pair {
var newSeason = if (next) currentSeason + 1 else currentSeason - 1
var newYear = currentYear
diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistMutations.kt b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistMutations.kt
index 3d7ac85e..de0f6e2f 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistMutations.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistMutations.kt
@@ -10,9 +10,92 @@ 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,
+ scoreFormat: String? = null,
+ rowOrder: String? = null,
+ ) {
+ val query = """
+ mutation (
+ ${"$"}timezone: String,
+ ${"$"}titleLanguage: UserTitleLanguage,
+ ${"$"}staffNameLanguage: UserStaffNameLanguage,
+ ${"$"}activityMergeTime: Int,
+ ${"$"}airingNotifications: Boolean,
+ ${"$"}displayAdultContent: Boolean,
+ ${"$"}restrictMessagesToFollowing: Boolean,
+ ${"$"}scoreFormat: ScoreFormat,
+ ${"$"}rowOrder: String
+ ) {
+ UpdateUser(
+ timezone: ${"$"}timezone,
+ titleLanguage: ${"$"}titleLanguage,
+ staffNameLanguage: ${"$"}staffNameLanguage,
+ activityMergeTime: ${"$"}activityMergeTime,
+ airingNotifications: ${"$"}airingNotifications,
+ displayAdultContent: ${"$"}displayAdultContent,
+ restrictMessagesToFollowing: ${"$"}restrictMessagesToFollowing,
+ scoreFormat: ${"$"}scoreFormat,
+ rowOrder: ${"$"}rowOrder,
+ ) {
+ id
+ options {
+ timezone
+ titleLanguage
+ staffNameLanguage
+ activityMergeTime
+ airingNotifications
+ displayAdultContent
+ restrictMessagesToFollowing
+ }
+ mediaListOptions {
+ scoreFormat
+ rowOrder
+ }
+ }
+ }
+ """.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""" } ?: ""}
+ ${scoreFormat?.let { """"scoreFormat":"$it"""" } ?: ""}
+ ${rowOrder?.let { """"rowOrder":"$it"""" } ?: ""}
+ }
+ """.trimIndent().replace("\n", "").replace(""" """, "").replace(",}", "}")
+
+ executeQuery(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(query, variables)
}
@@ -25,7 +108,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(query)
return result?.get("errors") == null && result != null
}
@@ -34,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(query, variables)
+ return result?.get("errors") == null
+ }
+
+ suspend fun updateCustomLists(animeCustomLists: List?, mangaCustomLists: List?): 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(query, variables)
+ return result?.get("errors") == null
+ }
+
suspend fun editList(
mediaID: Int,
progress: Int? = null,
@@ -46,14 +184,45 @@ class AnilistMutations {
completedAt: FuzzyDate? = null,
customList: List? = 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 +238,170 @@ 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(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)
}
suspend fun toggleFollow(id: Int): Query.ToggleFollow? {
return executeQuery(
- """mutation{ToggleFollow(userId:$id){id, isFollowing, isFollower}}"""
- )
+ """
+ mutation {
+ ToggleFollow(userId: $id) {
+ id
+ isFollowing
+ isFollower
+ }
+ }
+ """.trimIndent())
}
suspend fun toggleLike(id: Int, type: String): ToggleLike? {
return executeQuery(
- """mutation Like{ToggleLikeV2(id:$id,type:$type){__typename}}"""
- )
+ """
+ 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(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(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(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(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(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(query)
val errors = result?.get("errors")
return errors == null
}
-
private fun String.stringSanitizer(): String {
val sb = StringBuilder()
var i = 0
diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
index a834acc3..dc77be30 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
@@ -43,8 +43,8 @@ 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{timezone titleLanguage staffNameLanguage activityMergeTime airingNotifications displayAdultContent restrictMessagesToFollowing} avatar{medium} bannerImage id mediaListOptions{scoreFormat rowOrder animeList{customLists} mangaList{customLists}} statistics{anime{episodesWatched} manga{chaptersRead}} unreadNotificationCount}}""")
}.also { println("time : $it") }
val user = response?.data?.user ?: return false
@@ -61,6 +61,27 @@ class AnilistQueries {
val unread = PrefManager.getVal(PrefName.UnreadCommentNotifications)
Anilist.unreadNotificationCount += unread
Anilist.initialized = true
+
+ user.options?.let {
+ Anilist.titleLanguage = it.titleLanguage.toString()
+ Anilist.staffNameLanguage = it.staffNameLanguage.toString()
+ Anilist.airingNotifications = it.airingNotifications ?: false
+ Anilist.restrictMessagesToFollowing = it.restrictMessagesToFollowing ?: false
+ Anilist.timezone = it.timezone
+ Anilist.activityMergeTime = it.activityMergeTime
+ }
+ user.mediaListOptions?.let {
+ Anilist.scoreFormat = it.scoreFormat.toString()
+ Anilist.rowOrder = it.rowOrder
+
+ it.animeList?.let { animeList ->
+ Anilist.animeCustomLists = animeList.customLists
+ }
+
+ it.mangaList?.let { mangaList ->
+ Anilist.mangaCustomLists = mangaList.customLists
+ }
+ }
return true
}
diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/api/User.kt b/app/src/main/java/ani/dantotsu/connections/anilist/api/User.kt
index 9117c144..b887c710 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/api/User.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/api/User.kt
@@ -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?,
@@ -88,17 +88,17 @@ data class UserOptions(
// // Notification options
// // @SerialName("notificationOptions") var notificationOptions: List?,
//
- // // The user's timezone offset (Auth user only)
- // @SerialName("timezone") var timezone: String?,
+ // The user's timezone offset (Auth user only)
+ @SerialName("timezone") var timezone: String?,
//
- // // Minutes between activity for them to be merged together. 0 is Never, Above 2 weeks (20160 mins) is Always.
- // @SerialName("activityMergeTime") var activityMergeTime: Int?,
+ // 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?,
@@ -119,6 +119,26 @@ 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(
//
@@ -164,7 +184,7 @@ data class Favourites(
@Serializable
data class MediaListOptions(
// The score format the user is using for media lists
- @SerialName("scoreFormat") var scoreFormat: String?,
+ @SerialName("scoreFormat") var scoreFormat: ScoreFormat?,
// The default order list rows should be displayed in
@SerialName("rowOrder") var rowOrder: String?,
@@ -176,13 +196,27 @@ data class MediaListOptions(
@SerialName("mangaList") var mangaList: MediaListTypeOptions?,
)
+@Serializable
+enum class ScoreFormat {
+ @SerialName("POINT_100")
+ POINT_100,
+ @SerialName("POINT_10_DECIMAL")
+ POINT_10_DECIMAL,
+ @SerialName("POINT_10")
+ POINT_10,
+ @SerialName("POINT_5")
+ POINT_5,
+ @SerialName("POINT_3")
+ POINT_3,
+}
+
@Serializable
data class MediaListTypeOptions(
// The order each list should be displayed in
@SerialName("sectionOrder") var sectionOrder: List?,
- // If the completed sections of the list should be separated by format
- @SerialName("splitCompletedSectionByFormat") var splitCompletedSectionByFormat: Boolean?,
+ // // If the completed sections of the list should be separated by format
+ // @SerialName("splitCompletedSectionByFormat") var splitCompletedSectionByFormat: Boolean?,
// The names of the user's custom lists
@SerialName("customLists") var customLists: List?,
diff --git a/app/src/main/java/ani/dantotsu/media/MediaDetailsActivity.kt b/app/src/main/java/ani/dantotsu/media/MediaDetailsActivity.kt
index 048ba398..d9b44e99 100644
--- a/app/src/main/java/ani/dantotsu/media/MediaDetailsActivity.kt
+++ b/app/src/main/java/ani/dantotsu/media/MediaDetailsActivity.kt
@@ -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 {
diff --git a/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt b/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt
index 52ba668b..c37e0c14 100644
--- a/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt
+++ b/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt
@@ -252,14 +252,14 @@ class StatsFragment :
stat?.statistics?.anime?.scores?.map {
convertScore(
it.score,
- stat.mediaListOptions.scoreFormat
+ stat.mediaListOptions.scoreFormat.toString()
)
} ?: emptyList()
} else {
stat?.statistics?.manga?.scores?.map {
convertScore(
it.score,
- stat.mediaListOptions.scoreFormat
+ stat.mediaListOptions.scoreFormat.toString()
)
} ?: emptyList()
}
diff --git a/app/src/main/java/ani/dantotsu/settings/AnilistSettingsActivity.kt b/app/src/main/java/ani/dantotsu/settings/AnilistSettingsActivity.kt
new file mode 100644
index 00000000..684fb8db
--- /dev/null
+++ b/app/src/main/java/ani/dantotsu/settings/AnilistSettingsActivity.kt
@@ -0,0 +1,340 @@
+package ani.dantotsu.settings
+
+import android.os.Bundle
+import android.view.ViewGroup
+import android.widget.ArrayAdapter
+import android.widget.LinearLayout
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.children
+import androidx.core.view.updateLayoutParams
+import androidx.lifecycle.lifecycleScope
+import androidx.recyclerview.widget.LinearLayoutManager
+import ani.dantotsu.R
+import ani.dantotsu.connections.anilist.Anilist
+import ani.dantotsu.connections.anilist.Anilist.ScoreFormat
+import ani.dantotsu.connections.anilist.Anilist.activityMergeTimeMap
+import ani.dantotsu.connections.anilist.Anilist.rowOrderMap
+import ani.dantotsu.connections.anilist.Anilist.staffNameLang
+import ani.dantotsu.connections.anilist.Anilist.titleLang
+import ani.dantotsu.connections.anilist.AnilistMutations
+import ani.dantotsu.databinding.ActivitySettingsAnilistBinding
+import ani.dantotsu.initActivity
+import ani.dantotsu.navBarHeight
+import ani.dantotsu.restartApp
+import ani.dantotsu.statusBarHeight
+import ani.dantotsu.themes.ThemeManager
+import ani.dantotsu.toast
+import ani.dantotsu.util.customAlertDialog
+import com.google.android.material.textfield.TextInputEditText
+import com.google.android.material.textfield.TextInputLayout
+import kotlinx.coroutines.launch
+
+class AnilistSettingsActivity : AppCompatActivity() {
+ private lateinit var binding: ActivitySettingsAnilistBinding
+ private lateinit var anilistMutations: AnilistMutations
+
+ enum class FormatLang {
+ ENGLISH,
+ ROMAJI,
+ NATIVE
+ }
+
+ enum class FormatScore {
+ POINT_100,
+ POINT_10_DECIMAL,
+ POINT_10,
+ POINT_5,
+ POINT_3,
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ ThemeManager(this).applyTheme()
+ initActivity(this)
+ val context = this
+ binding = ActivitySettingsAnilistBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ anilistMutations = AnilistMutations()
+
+ binding.apply {
+ settingsAnilistLayout.updateLayoutParams {
+ topMargin = statusBarHeight
+ bottomMargin = navBarHeight
+ }
+ binding.anilistSettingsBack.setOnClickListener {
+ onBackPressedDispatcher.onBackPressed()
+ }
+
+ val currentTitleLang = Anilist.titleLanguage
+ val titleFormat = FormatLang.entries.firstOrNull { it.name == currentTitleLang } ?: FormatLang.ENGLISH
+
+ settingsAnilistTitleLanguage.setText(titleLang[titleFormat.ordinal])
+ 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)
+ Anilist.titleLanguage = selectedLanguage
+ restartApp()
+ }
+ settingsAnilistTitleLanguage.clearFocus()
+ }
+
+ val currentStaffNameLang = Anilist.staffNameLanguage
+ val staffNameFormat = FormatLang.entries.firstOrNull { it.name == currentStaffNameLang } ?: FormatLang.ENGLISH
+
+ settingsAnilistStaffLanguage.setText(staffNameLang[staffNameFormat.ordinal])
+ 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)
+ Anilist.staffNameLanguage = selectedLanguage
+ restartApp()
+ }
+ settingsAnilistStaffLanguage.clearFocus()
+ }
+
+ val currentMergeTimeDisplay = activityMergeTimeMap.entries.firstOrNull { it.value == Anilist.activityMergeTime }?.key
+ ?: "${Anilist.activityMergeTime} mins"
+ settingsAnilistActivityMergeTime.setText(currentMergeTimeDisplay)
+ settingsAnilistActivityMergeTime.setAdapter(
+ ArrayAdapter(context, R.layout.item_dropdown, activityMergeTimeMap.keys.toList())
+ )
+ settingsAnilistActivityMergeTime.setOnItemClickListener { _, _, i, _ ->
+ val selectedDisplayTime = activityMergeTimeMap.keys.toList()[i]
+ val selectedApiTime = activityMergeTimeMap[selectedDisplayTime] ?: 0
+ lifecycleScope.launch {
+ anilistMutations.updateSettings(activityMergeTime = selectedApiTime)
+ Anilist.activityMergeTime = selectedApiTime
+ restartApp()
+ }
+ settingsAnilistActivityMergeTime.clearFocus()
+ }
+
+ val currentScoreFormat = Anilist.scoreFormat
+ val scoreFormat = FormatScore.entries.firstOrNull{ it.name == currentScoreFormat } ?: FormatScore.POINT_100
+ settingsAnilistScoreFormat.setText(ScoreFormat[scoreFormat.ordinal])
+ settingsAnilistScoreFormat.setAdapter(
+ ArrayAdapter(context, R.layout.item_dropdown, ScoreFormat)
+ )
+ settingsAnilistScoreFormat.setOnItemClickListener { _, _, i, _ ->
+ val selectedFormat = when (i) {
+ 0 -> "POINT_100"
+ 1 -> "POINT_10_DECIMAL"
+ 2 -> "POINT_10"
+ 3 -> "POINT_5"
+ 4 -> "POINT_3"
+ else -> "POINT_100"
+ }
+ lifecycleScope.launch {
+ anilistMutations.updateSettings(scoreFormat = selectedFormat)
+ Anilist.scoreFormat = selectedFormat
+ restartApp()
+ }
+ settingsAnilistScoreFormat.clearFocus()
+ }
+
+ val currentRowOrder = rowOrderMap.entries.firstOrNull { it.value == Anilist.rowOrder }?.key ?: "Score"
+ settingsAnilistRowOrder.setText(currentRowOrder)
+ settingsAnilistRowOrder.setAdapter(
+ ArrayAdapter(context, R.layout.item_dropdown, rowOrderMap.keys.toList())
+ )
+ settingsAnilistRowOrder.setOnItemClickListener { _, _, i, _ ->
+ val selectedDisplayOrder = rowOrderMap.keys.toList()[i]
+ val selectedApiOrder = rowOrderMap[selectedDisplayOrder] ?: "score"
+ lifecycleScope.launch {
+ anilistMutations.updateSettings(rowOrder = selectedApiOrder)
+ Anilist.rowOrder = selectedApiOrder
+ restartApp()
+ }
+ 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(
+ ArrayAdapter(context, R.layout.item_dropdown, Anilist.timeZone)
+ )
+ settingsAnilistTimezone.setOnItemClickListener { _, _, i, _ ->
+ val selectedTimezone = Anilist.timeZone[i]
+ val apiTimezone = Anilist.getApiTimezone(selectedTimezone)
+ lifecycleScope.launch {
+ anilistMutations.updateSettings(timezone = apiTimezone)
+ Anilist.timezone = apiTimezone
+ restartApp()
+ }
+ settingsAnilistTimezone.clearFocus()
+ }
+
+ val displayAdultContent = Anilist.adult
+ val airingNotifications = Anilist.airingNotifications
+
+ binding.settingsRecyclerView1.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)
+ Anilist.airingNotifications = isChecked
+ restartApp()
+ }
+ }
+ ),
+ 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)
+ Anilist.adult = isChecked
+ restartApp()
+ }
+ }
+ ),
+ )
+ )
+ binding.settingsRecyclerView1.layoutManager =
+ LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
+
+ }
+
+ binding.settingsRecyclerView2.adapter = SettingsAdapter(
+ arrayListOf(
+ Settings(
+ type = 2,
+ name = getString(R.string.restrict_messages),
+ desc = getString(R.string.restrict_messages_desc),
+ icon = R.drawable.ic_round_lock_open_24,
+ isChecked = Anilist.restrictMessagesToFollowing,
+ switch = { isChecked, _ ->
+ lifecycleScope.launch {
+ anilistMutations.updateSettings(restrictMessagesToFollowing = isChecked)
+ Anilist.restrictMessagesToFollowing = isChecked
+ restartApp()
+ }
+ }
+ ),
+ )
+ )
+ binding.settingsRecyclerView2.layoutManager =
+ 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(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) {
+ customAlertDialog().apply {
+ setTitle(getString(R.string.delete_custom_list))
+ setMessage(getString(R.string.delete_custom_list_confirm, name))
+ setPosButton(getString(R.string.delete)) {
+ deleteCustomList(name, isAnime)
+ container.removeView(customListItemView)
+ }
+ setNegButton(getString(R.string.cancel))
+ }.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(R.id.customListItem).editText as? TextInputEditText)?.text?.toString() }
+ .filter { it.isNotEmpty() }
+ .toList()
+ val mangaCustomLists = binding.mangaCustomListsContainer.children
+ .mapNotNull { (it.findViewById(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")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/settings/ExtensionsActivity.kt b/app/src/main/java/ani/dantotsu/settings/ExtensionsActivity.kt
index 46d42eb9..dd11df3a 100644
--- a/app/src/main/java/ani/dantotsu/settings/ExtensionsActivity.kt
+++ b/app/src/main/java/ani/dantotsu/settings/ExtensionsActivity.kt
@@ -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
@@ -321,7 +320,7 @@ class ExtensionsActivity : AppCompatActivity() {
customAlertDialog().apply {
setTitle(R.string.edit_repositories)
setCustomView(dialogView.root)
- setPosButton(R.string.add) {
+ setPosButton(R.string.add_list) {
if (!dialogView.repositoryTextBox.text.isNullOrBlank()) {
processUserInput(dialogView.repositoryTextBox.text.toString(), type)
}
diff --git a/app/src/main/java/ani/dantotsu/settings/SettingsAccountActivity.kt b/app/src/main/java/ani/dantotsu/settings/SettingsAccountActivity.kt
index 7bebb68f..204feb97 100644
--- a/app/src/main/java/ani/dantotsu/settings/SettingsAccountActivity.kt
+++ b/app/src/main/java/ani/dantotsu/settings/SettingsAccountActivity.kt
@@ -1,5 +1,6 @@
package ani.dantotsu.settings
+import android.content.Intent
import android.os.Bundle
import android.view.HapticFeedbackConstants
import android.view.View
@@ -9,6 +10,8 @@ import android.widget.TextView
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.updateLayoutParams
+import androidx.lifecycle.lifecycleScope
+import androidx.recyclerview.widget.LinearLayoutManager
import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.discord.Discord
@@ -26,6 +29,7 @@ import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager
import io.noties.markwon.Markwon
import io.noties.markwon.SoftBreakAddsNewLinePlugin
+import kotlinx.coroutines.launch
class SettingsAccountActivity : AppCompatActivity() {
private lateinit var binding: ActivitySettingsAccountsBinding
@@ -111,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)
@@ -142,7 +147,7 @@ class SettingsAccountActivity : AppCompatActivity() {
reload()
}
- settingsImageSwitcher.visibility = View.VISIBLE
+ settingsPresenceSwitcher.visibility = View.VISIBLE
var initialStatus = when (PrefManager.getVal(PrefName.DiscordStatus)) {
"online" -> R.drawable.discord_status_online
"idle" -> R.drawable.discord_status_idle
@@ -150,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 -> {
@@ -181,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)
@@ -202,6 +207,25 @@ class SettingsAccountActivity : AppCompatActivity() {
}
reload()
}
- }
+ binding.settingsRecyclerView.adapter = SettingsAdapter(
+ arrayListOf(
+ Settings(
+ type = 1,
+ name = getString(R.string.anilist_settings),
+ desc = getString(R.string.alsettings_desc),
+ icon = R.drawable.ic_anilist,
+ onClick = {
+ lifecycleScope.launch {
+ Anilist.query.getUserData()
+ startActivity(Intent(context, AnilistSettingsActivity::class.java))
+ }
+ },
+ isActivity = true
+ ),
+ )
+ )
+ binding.settingsRecyclerView.layoutManager =
+ LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
+ }
}
diff --git a/app/src/main/res/drawable/ic_round_lock_24.xml b/app/src/main/res/drawable/ic_round_lock_24.xml
index 68cb9c1f..87281bf0 100644
--- a/app/src/main/res/drawable/ic_round_lock_24.xml
+++ b/app/src/main/res/drawable/ic_round_lock_24.xml
@@ -1,6 +1,7 @@
+
+
@@ -281,27 +291,13 @@
-
-
-
+ android:layout_height="match_parent"
+ android:nestedScrollingEnabled="false"
+ android:requiresFadingEdge="vertical"
+ tools:itemCount="1"
+ tools:listitem="@layout/item_settings" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_settings_anilist.xml b/app/src/main/res/layout/activity_settings_anilist.xml
new file mode 100644
index 00000000..aa7bdd9e
--- /dev/null
+++ b/app/src/main/res/layout/activity_settings_anilist.xml
@@ -0,0 +1,419 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_custom_list.xml b/app/src/main/res/layout/item_custom_list.xml
new file mode 100644
index 00000000..44e8fafc
--- /dev/null
+++ b/app/src/main/res/layout/item_custom_list.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a4d5a027..a6ae420c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -66,7 +66,7 @@
All caught up, when New?
Settings
- Add to List
+ Add to List
List Editor
Add to Favourites
Notifications
@@ -331,7 +331,19 @@
Prefer Dubbed Anime
None
Selected DNS
+ Anime and Manga
+ List Settings
Change if your ISP blocks any source
+ Selected Title Language
+ Selected Staff Language
+ Activity Merge Time
+ Scoring System
+ Timezone
+ Default List Order
+ Custom Anime Lists
+ Custom Manga Lists
+ Delete Custom List
+ Are you sure you want to delete %1$s ?
Keep Screen On
Layout
Spaced Pages
@@ -390,7 +402,6 @@
FAQ
Accounts
Add-ons
- Get more features out of your app
MyAnimeList
Login with Anilist!
Anilist
@@ -909,11 +920,20 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
\[%1$s\] Unknown
Anilist, MAL and Discord.\nWhat more could you need?
Change the vibe of your app
- Manage your reliable repositories
UI and other mischievous stuff
- Customise your news and updates
Choose how you watch
Choose how you read
+ Manage your reliable repositories
+ Get more features out of your app
+ Change your AniList settings
+ Airing Anime notifications
+ Get notified whenever a new episode drops
+ 18+ Content
+ Enable NSFW content
+ Restrict messages to following
+ Allow only users I follow to message me
+
+ Customise your news and updates
Learn more about Dantotsu
General questions about Dantotsu
Check Github for app updates
@@ -967,6 +987,7 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
Add-on update available
Install Add-on
Add-on not found
+
Image
Clear History
Failed to install extension due to conflict