diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml
index 68444cd8..313a0be5 100644
--- a/.github/workflows/beta.yml
+++ b/.github/workflows/beta.yml
@@ -12,6 +12,7 @@ jobs:
runs-on: ubuntu-latest
env:
CI: true
+ SKIP_BUILD: false
steps:
- name: Checkout repo
@@ -19,14 +20,12 @@ jobs:
with:
fetch-depth: 0
-
- name: Download last SHA artifact
uses: dawidd6/action-download-artifact@v3
with:
workflow: beta.yml
name: last-sha
path: .
-
continue-on-error: true
- name: Get Commits Since Last Run
@@ -39,7 +38,9 @@ jobs:
fi
echo "Commits since $LAST_SHA:"
# Accumulate commit logs in a shell variable
- COMMIT_LOGS=$(git log $LAST_SHA..HEAD --pretty=format:"● %s ~%an")
+ COMMIT_LOGS=$(git log $LAST_SHA..HEAD --pretty=format:"● %s ~%an [֍](https://github.com/${{ github.repository }}/commit/%H)")
+ # Replace commit messages with pull request links
+ COMMIT_LOGS=$(echo "$COMMIT_LOGS" | sed -E 's/#([0-9]+)/[#\1](https:\/\/github.com\/rebelonion\/Dantotsu\/pull\/\1)/g')
# URL-encode the newline characters for GitHub Actions
COMMIT_LOGS="${COMMIT_LOGS//'%'/'%25'}"
COMMIT_LOGS="${COMMIT_LOGS//$'\n'/'%0A'}"
@@ -65,26 +66,40 @@ jobs:
echo "Version $VERSION"
echo "VERSION=$VERSION" >> $GITHUB_ENV
+ - name: List files in the directory
+ run: ls -l
+
- name: Setup JDK 17
+ if: ${{ env.SKIP_BUILD != 'true' }}
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 17
cache: gradle
-
- - name: Decode Keystore File
- run: echo "${{ secrets.KEYSTORE_FILE }}" | base64 -d > $GITHUB_WORKSPACE/key.keystore
-
- - name: List files in the directory
- run: ls -l
-
- - name: Make gradlew executable
- run: chmod +x ./gradlew
-
- - name: Build with Gradle
- run: ./gradlew assembleGoogleAlpha -Pandroid.injected.signing.store.file=$GITHUB_WORKSPACE/key.keystore -Pandroid.injected.signing.store.password=${{ secrets.KEYSTORE_PASSWORD }} -Pandroid.injected.signing.key.alias=${{ secrets.KEY_ALIAS }} -Pandroid.injected.signing.key.password=${{ secrets.KEY_PASSWORD }}
+ - name: Decode Keystore File
+ if: ${{ github.repository == 'rebelonion/Dantotsu' }}
+ run: echo "${{ secrets.KEYSTORE_FILE }}" | base64 -d > $GITHUB_WORKSPACE/key.keystore
+
+ - name: Make gradlew executable
+ if: ${{ env.SKIP_BUILD != 'true' }}
+ run: chmod +x ./gradlew
+
+ - name: Build with Gradle
+ if: ${{ env.SKIP_BUILD != 'true' }}
+ run: |
+ if [ "${{ github.repository }}" == "rebelonion/Dantotsu" ]; then
+ ./gradlew assembleGoogleAlpha \
+ -Pandroid.injected.signing.store.file=$GITHUB_WORKSPACE/key.keystore \
+ -Pandroid.injected.signing.store.password=${{ secrets.KEYSTORE_PASSWORD }} \
+ -Pandroid.injected.signing.key.alias=${{ secrets.KEY_ALIAS }} \
+ -Pandroid.injected.signing.key.password=${{ secrets.KEY_PASSWORD }};
+ else
+ ./gradlew assembleGoogleAlpha;
+ fi
+
- name: Upload a Build Artifact
+ if: ${{ env.SKIP_BUILD != 'true' }}
uses: actions/upload-artifact@v4
with:
name: Dantotsu
@@ -93,25 +108,203 @@ jobs:
path: "app/build/outputs/apk/google/alpha/app-google-alpha.apk"
- name: Upload APK to Discord and Telegram
- if: ${{ github.repository == 'rebelonion/Dantotsu' }}
shell: bash
run: |
- #Discord
+ # Prepare Discord embed
+ fetch_user_details() {
+ local login=$1
+ user_details=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
+ "https://api.github.com/users/$login")
+ name=$(echo "$user_details" | jq -r '.name // .login')
+ login=$(echo "$user_details" | jq -r '.login')
+ avatar_url=$(echo "$user_details" | jq -r '.avatar_url')
+ echo "$name|$login|$avatar_url"
+ }
+
+ # Additional information for the goats
+ declare -A additional_info
+ additional_info["ibo"]="\n Discord: <@951737931159187457>\n AniList: [takarealist112]()"
+ additional_info["aayush262"]="\n Discord: <@918825160654598224>\n AniList: [aayush262]()"
+ additional_info["rebelonion"]="\n Discord: <@714249925248024617>\n AniList: [rebelonion]()\n PornHub: [rebelonion]()"
+
+ # Decimal color codes for contributors
+ declare -A contributor_colors
+ default_color="#ff25f9"
+ contributor_colors["ibo"]="#ff7500"
+ contributor_colors["aayush262"]="#5d689d"
+ contributor_colors["Sadwhy"]="#ff7e95"
+ contributor_colors["rebelonion"]="#d4e5ed"
+ hex_to_decimal() { printf '%d' "0x${1#"#"}"; }
+
+ # Count recent commits and create an associative array
+ declare -A recent_commit_counts
+ while read -r count name; do
+ recent_commit_counts["$name"]=$count
+ done < <(echo "$COMMIT_LOG" | sed 's/%0A/\n/g' | grep -oP '(?<=~)[^[]*' | sort | uniq -c | sort -rn)
+ # Fetch contributors from GitHub
+ contributors=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
+ "https://api.github.com/repos/${{ github.repository }}/contributors")
+
+ # Create a sorted list of contributors based on recent commit counts
+ sorted_contributors=$(for login in $(echo "$contributors" | jq -r '.[].login'); do
+ user_info=$(fetch_user_details "$login")
+ name=$(echo "$user_info" | cut -d'|' -f1)
+ count=${recent_commit_counts["$name"]:-0}
+ echo "$count|$login"
+ done | sort -rn | cut -d'|' -f2)
+
+ # Initialize needed variables
+ developers=""
+ committers_count=0
+ max_commits=0
+ top_contributor=""
+ top_contributor_count=0
+ top_contributor_avatar=""
+ embed_color=$default_color
+
+ # Process contributors in the new order
+ while read -r login; do
+ user_info=$(fetch_user_details "$login")
+ name=$(echo "$user_info" | cut -d'|' -f1)
+ login=$(echo "$user_info" | cut -d'|' -f2)
+ avatar_url=$(echo "$user_info" | cut -d'|' -f3)
+
+ # Only process if they have recent commits
+ commit_count=${recent_commit_counts["$name"]:-0}
+ if [ $commit_count -gt 0 ]; then
+ # Update top contributor information
+ if [ $commit_count -gt $max_commits ]; then
+ max_commits=$commit_count
+ top_contributors=("$login")
+ top_contributor_count=1
+ top_contributor_avatar="$avatar_url"
+ embed_color=$(hex_to_decimal "${contributor_colors[$name]:-$default_color}")
+ elif [ $commit_count -eq $max_commits ]; then
+ top_contributors+=("$login")
+ top_contributor_count=$((top_contributor_count + 1))
+ embed_color=$default_color
+ fi
+
+ # Get commit count for this contributor on the dev branch
+ branch_commit_count=$(git rev-list --count dev --author="$login")
+
+ extra_info="${additional_info[$name]}"
+ if [ -n "$extra_info" ]; then
+ extra_info=$(echo "$extra_info" | sed 's/\\n/\n- /g')
+ fi
+
+ # Construct the developer entry
+ developer_entry="◗ **${name}** ${extra_info}
+ - Github: [${login}](https://github.com/${login})
+ - Commits: ${branch_commit_count}"
+
+ # Add the entry to developers, with a newline if it's not the first entry
+ if [ -n "$developers" ]; then
+ developers="${developers}
+ ${developer_entry}"
+ else
+ developers="${developer_entry}"
+ fi
+ committers_count=$((committers_count + 1))
+ fi
+ done <<< "$sorted_contributors"
+
+ # Set the thumbnail URL and color based on top contributor(s)
+ if [ $top_contributor_count -eq 1 ]; then
+ thumbnail_url="$top_contributor_avatar"
+ else
+ thumbnail_url="https://i.imgur.com/5o3Y9Jb.gif"
+ embed_color=$default_color
+ fi
+
+ # Truncate field values
+ max_length=1000
commit_messages=$(echo "$COMMIT_LOG" | sed 's/%0A/\n/g; s/^/\n/')
- # Truncate commit messages if they are too long
- max_length=1900 # Adjust this value as needed
+ if [ ${#developers} -gt $max_length ]; then
+ developers="${developers:0:$max_length}... (truncated)"
+ fi
if [ ${#commit_messages} -gt $max_length ]; then
commit_messages="${commit_messages:0:$max_length}... (truncated)"
fi
- contentbody=$( jq -nc --arg msg "Alpha-Build: <@&1225347048321191996> **$VERSION**:" --arg commits "$commit_messages" '{"content": ($msg + "\n" + $commits)}' )
- curl -F "payload_json=${contentbody}" -F "dantotsu_debug=@app/build/outputs/apk/google/alpha/app-google-alpha.apk" ${{ secrets.DISCORD_WEBHOOK }}
-
- #Telegram
- curl -F "chat_id=${{ secrets.TELEGRAM_CHANNEL_ID }}" \
- -F "document=@app/build/outputs/apk/google/alpha/app-google-alpha.apk" \
- -F "caption=Alpha-Build: ${VERSION}: ${commit_messages}" \
- https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendDocument
+ # Construct Discord payload
+ discord_data=$(jq -nc \
+ --arg field_value "$commit_messages" \
+ --arg author_value "$developers" \
+ --arg footer_text "Version $VERSION" \
+ --arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%S.000Z)" \
+ --arg thumbnail_url "$thumbnail_url" \
+ --argjson embed_color "$embed_color" \
+ '{
+ "content": "<@&1225347048321191996>",
+ "embeds": [
+ {
+ "title": "New Alpha-Build dropped",
+ "color": $embed_color,
+ "fields": [
+ {
+ "name": "Commits:",
+ "value": $field_value,
+ "inline": true
+ },
+ {
+ "name": "Developers:",
+ "value": $author_value,
+ "inline": false
+ }
+ ],
+ "footer": {
+ "text": $footer_text
+ },
+ "timestamp": $timestamp,
+ "thumbnail": {
+ "url": $thumbnail_url
+ }
+ }
+ ],
+ "attachments": []
+ }')
+
+ # Send Discord message
+ curl -H "Content-Type: application/json" \
+ -d "$discord_data" \
+ ${{ secrets.DISCORD_WEBHOOK }}
+ echo "You have only send an embed to discord due to SKIP_BUILD being set to true"
+
+ # Upload APK to Discord
+ if [ "$SKIP_BUILD" != "true" ]; then
+ curl -F "payload_json=${contentbody}" \
+ -F "dantotsu_debug=@app/build/outputs/apk/google/alpha/app-google-alpha.apk" \
+ ${{ secrets.DISCORD_WEBHOOK }}
+ else
+ echo "Skipping APK upload to Discord due to SKIP_BUILD being set to true"
+ fi
+
+ # Format commit messages for Telegram
+ telegram_commit_messages=$(echo "$COMMIT_LOG" | sed 's/%0A/\n/g' | while read -r line; do
+ message=$(echo "$line" | sed -E 's/● (.*) ~(.*) \[֍\]\((.*)\)/● \1 ~\2 ֍<\/a>/')
+ message=$(echo "$message" | sed -E 's/\[#([0-9]+)\]\((https:\/\/github\.com\/[^)]+)\)/#\1<\/a>/g')
+ echo "$message"
+ done)
+ telegram_commit_messages="${telegram_commit_messages}
"
+
+ # Upload APK to Telegram
+ if [ "$SKIP_BUILD" != "true" ]; then
+ APK_PATH="app/build/outputs/apk/google/alpha/app-google-alpha.apk"
+ response=$(curl -sS -f -X POST \
+ "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendDocument" \
+ -F "chat_id=${{ secrets.TELEGRAM_CHANNEL_ID }}" \
+ -F "document=@$APK_PATH" \
+ -F "caption=New Alpha-Build dropped 🔥
+
+ Commits:
+ ${telegram_commit_messages}
+ version: ${VERSION}" \
+ -F "parse_mode=HTML")
+ else
+ echo "Skipping Telegram message and APK upload due to SKIP_BUILD being set to true"
+ fi
+
env:
COMMIT_LOG: ${{ env.COMMIT_LOG }}
VERSION: ${{ env.VERSION }}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ce03636e..8983d640 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -19,6 +19,7 @@
+
@@ -205,7 +206,7 @@
android:parentActivityName=".MainActivity" />
+ android:windowSoftInputMode="adjustResize|stateVisible" />
()
fun startTorrent() {
if (torrentManager.isAvailable() && PrefManager.getVal(PrefName.TorrentEnabled)) {
@@ -493,35 +496,28 @@ class MainActivity : AppCompatActivity() {
val password = CharArray(16).apply { fill('0') }
// Inflate the dialog layout
- val dialogView = DialogUserAgentBinding.inflate(layoutInflater)
- dialogView.userAgentTextBox.hint = "Password"
- dialogView.subtitle.visibility = View.VISIBLE
- dialogView.subtitle.text = getString(R.string.enter_password_to_decrypt_file)
-
- val dialog = AlertDialog.Builder(this, R.style.MyPopup)
- .setTitle("Enter Password")
- .setView(dialogView.root)
- .setPositiveButton("OK", null)
- .setNegativeButton("Cancel") { dialog, _ ->
+ val dialogView = DialogUserAgentBinding.inflate(layoutInflater).apply {
+ userAgentTextBox.hint = "Password"
+ subtitle.visibility = View.VISIBLE
+ subtitle.text = getString(R.string.enter_password_to_decrypt_file)
+ }
+ customAlertDialog().apply {
+ setTitle("Enter Password")
+ setCustomView(dialogView.root)
+ setPosButton(R.string.yes) {
+ val editText = dialogView.userAgentTextBox
+ if (editText.text?.isNotBlank() == true) {
+ editText.text?.toString()?.trim()?.toCharArray(password)
+ callback(password)
+ } else {
+ toast("Password cannot be empty")
+ }
+ }
+ setNegButton(R.string.cancel) {
password.fill('0')
- dialog.dismiss()
callback(null)
}
- .create()
-
- dialog.window?.setDimAmount(0.8f)
- dialog.show()
-
- // Override the positive button here
- dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
- val editText = dialog.findViewById(R.id.userAgentTextBox)
- if (editText?.text?.isNotBlank() == true) {
- editText.text?.toString()?.trim()?.toCharArray(password)
- dialog.dismiss()
- callback(password)
- } else {
- toast("Password cannot be empty")
- }
+ show()
}
}
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 96ba5d75..3e24492c 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/Anilist.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/Anilist.kt
@@ -312,6 +312,7 @@ object Anilist {
)
val remaining = json.headers["X-RateLimit-Remaining"]?.toIntOrNull() ?: -1
Logger.log("Remaining requests: $remaining")
+ println("Remaining requests: $remaining")
if (json.code == 429) {
val retry = json.headers["Retry-After"]?.toIntOrNull() ?: -1
val passedLimitReset = json.headers["X-RateLimit-Reset"]?.toLongOrNull() ?: 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 ee579e1b..f044349d 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
@@ -6,14 +6,14 @@ import ani.dantotsu.checkGenreTime
import ani.dantotsu.checkId
import ani.dantotsu.connections.anilist.Anilist.authorRoles
import ani.dantotsu.connections.anilist.Anilist.executeQuery
-import ani.dantotsu.connections.anilist.api.Activity
import ani.dantotsu.connections.anilist.api.FeedResponse
import ani.dantotsu.connections.anilist.api.FuzzyDate
+import ani.dantotsu.connections.anilist.api.MediaEdge
+import ani.dantotsu.connections.anilist.api.MediaList
import ani.dantotsu.connections.anilist.api.NotificationResponse
import ani.dantotsu.connections.anilist.api.Page
import ani.dantotsu.connections.anilist.api.Query
import ani.dantotsu.connections.anilist.api.ReplyResponse
-import ani.dantotsu.connections.anilist.api.ToggleLike
import ani.dantotsu.currContext
import ani.dantotsu.isOnline
import ani.dantotsu.logError
@@ -28,6 +28,7 @@ import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.runBlocking
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
@@ -473,9 +474,7 @@ class AnilistQueries {
val toShow: List =
PrefManager.getVal(PrefName.HomeLayout)
if (toShow.getOrNull(7) != true) return null
- var query = """{"""
- query += "Page1:${status(1)}Page2:${status(2)}"
- query += """}""".trimEnd(',')
+ val query = """{Page1:${status(1)}Page2:${status(2)}}"""
val response = executeQuery(query, show = true)
val list = mutableListOf()
val threeDaysAgo = Calendar.getInstance().apply {
@@ -512,8 +511,9 @@ class AnilistQueries {
}
}
- if (anilistActivities.isEmpty() && Anilist.token != null){
- anilistActivities.add(0,
+ if (anilistActivities.isEmpty() && Anilist.token != null) {
+ anilistActivities.add(
+ 0,
User(
Anilist.userid!!,
Anilist.username!!,
@@ -528,205 +528,176 @@ class AnilistQueries {
} else return null
}
- suspend fun initHomePage(): Map> {
+ suspend fun initHomePage(): Map> {
val removeList = PrefManager.getCustomVal("removeList", setOf())
+ val hidePrivate = PrefManager.getVal(PrefName.HidePrivate)
val removedMedia = ArrayList()
val toShow: List =
- PrefManager.getVal(PrefName.HomeLayout) // anime continue, anime fav, anime planned, manga continue, manga fav, manga planned, recommendations
- var query = """{"""
- if (toShow.getOrNull(0) == true) query += """currentAnime: ${
- continueMediaQuery(
- "ANIME",
- "CURRENT"
- )
- }, repeatingAnime: ${continueMediaQuery("ANIME", "REPEATING")}"""
- if (toShow.getOrNull(1) == true) query += """favoriteAnime: ${favMediaQuery(true, 1)}"""
- if (toShow.getOrNull(2) == true) query += """plannedAnime: ${
- continueMediaQuery(
- "ANIME",
- "PLANNING"
- )
- }"""
- if (toShow.getOrNull(3) == true) query += """currentManga: ${
- continueMediaQuery(
- "MANGA",
- "CURRENT"
- )
- }, repeatingManga: ${continueMediaQuery("MANGA", "REPEATING")}"""
- if (toShow.getOrNull(4) == true) query += """favoriteManga: ${favMediaQuery(false, 1)}"""
- if (toShow.getOrNull(5) == true) query += """plannedManga: ${
- continueMediaQuery(
- "MANGA",
- "PLANNING"
- )
- }"""
- if (toShow.getOrNull(6) == true) query += """recommendationQuery: ${recommendationQuery()}, recommendationPlannedQueryAnime: ${
- recommendationPlannedQuery(
- "ANIME"
- )
- }, recommendationPlannedQueryManga: ${recommendationPlannedQuery("MANGA")}"""
- query += """}""".trimEnd(',')
+ PrefManager.getVal(PrefName.HomeLayout) // list of booleans for what to show
+ val queries = mutableListOf()
+ if (toShow.getOrNull(0) == true) {
+ queries.add("""currentAnime: ${continueMediaQuery("ANIME", "CURRENT")}""")
+ queries.add("""repeatingAnime: ${continueMediaQuery("ANIME", "REPEATING")}""")
+ }
+ if (toShow.getOrNull(1) == true) queries.add("""favoriteAnime: ${favMediaQuery(true, 1)}""")
+ if (toShow.getOrNull(2) == true) queries.add(
+ """plannedAnime: ${
+ continueMediaQuery(
+ "ANIME",
+ "PLANNING"
+ )
+ }"""
+ )
+ if (toShow.getOrNull(3) == true) {
+ queries.add("""currentManga: ${continueMediaQuery("MANGA", "CURRENT")}""")
+ queries.add("""repeatingManga: ${continueMediaQuery("MANGA", "REPEATING")}""")
+ }
+ if (toShow.getOrNull(4) == true) queries.add(
+ """favoriteManga: ${
+ favMediaQuery(
+ false,
+ 1
+ )
+ }"""
+ )
+ if (toShow.getOrNull(5) == true) queries.add(
+ """plannedManga: ${
+ continueMediaQuery(
+ "MANGA",
+ "PLANNING"
+ )
+ }"""
+ )
+ if (toShow.getOrNull(6) == true) {
+ queries.add("""recommendationQuery: ${recommendationQuery()}""")
+ queries.add("""recommendationPlannedQueryAnime: ${recommendationPlannedQuery("ANIME")}""")
+ queries.add("""recommendationPlannedQueryManga: ${recommendationPlannedQuery("MANGA")}""")
+ }
+
+ val query = "{${queries.joinToString(",")}}"
val response = executeQuery(query, show = true)
- val returnMap = mutableMapOf>()
- fun current(type: String) {
+ val returnMap = mutableMapOf>()
+
+ fun processMedia(
+ type: String,
+ currentMedia: List?,
+ repeatingMedia: List?
+ ) {
val subMap = mutableMapOf()
val returnArray = arrayListOf()
- val current =
- if (type == "Anime") response?.data?.currentAnime else response?.data?.currentManga
- val repeating =
- if (type == "Anime") response?.data?.repeatingAnime else response?.data?.repeatingManga
- current?.lists?.forEach { li ->
- li.entries?.reversed()?.forEach {
- val m = Media(it)
- if (m.id !in removeList) {
- m.cameFromContinue = true
- subMap[m.id] = m
- } else {
- removedMedia.add(m)
- }
+
+ (currentMedia ?: emptyList()).forEach { entry ->
+ val media = Media(entry)
+ if (media.id !in removeList && (!hidePrivate || !media.isListPrivate)) {
+ media.cameFromContinue = true
+ subMap[media.id] = media
+ } else {
+ removedMedia.add(media)
}
}
- repeating?.lists?.forEach { li ->
- li.entries?.reversed()?.forEach {
- val m = Media(it)
- if (m.id !in removeList) {
- m.cameFromContinue = true
- subMap[m.id] = m
- } else {
- removedMedia.add(m)
- }
+ (repeatingMedia ?: emptyList()).forEach { entry ->
+ val media = Media(entry)
+ if (media.id !in removeList && (!hidePrivate || !media.isListPrivate)) {
+ media.cameFromContinue = true
+ subMap[media.id] = media
+ } else {
+ removedMedia.add(media)
}
}
- if (type != "Anime") {
+ @Suppress("UNCHECKED_CAST")
+ val list = PrefManager.getNullableCustomVal(
+ "continue${type}List",
+ listOf(),
+ List::class.java
+ ) as List
+ if (list.isNotEmpty()) {
+ list.reversed().forEach { id ->
+ subMap[id]?.let { returnArray.add(it) }
+ }
+ subMap.values.forEach {
+ if (!returnArray.contains(it)) returnArray.add(it)
+ }
+ } else {
returnArray.addAll(subMap.values)
- returnMap["current$type"] = returnArray
- return
}
- @Suppress("UNCHECKED_CAST")
- val list = PrefManager.getNullableCustomVal(
- "continueAnimeList",
- listOf(),
- List::class.java
- ) as List
- if (list.isNotEmpty()) {
- list.reversed().forEach {
- if (subMap.containsKey(it)) returnArray.add(subMap[it]!!)
- }
- for (i in subMap) {
- if (i.value !in returnArray) returnArray.add(i.value)
- }
- } else returnArray.addAll(subMap.values)
returnMap["current$type"] = returnArray
-
}
- fun planned(type: String) {
- val subMap = mutableMapOf()
- val returnArray = arrayListOf()
- val current =
- if (type == "Anime") response?.data?.plannedAnime else response?.data?.plannedManga
- current?.lists?.forEach { li ->
- li.entries?.reversed()?.forEach {
- val m = Media(it)
- if (m.id !in removeList) {
- m.cameFromContinue = true
- subMap[m.id] = m
- } else {
- removedMedia.add(m)
- }
- }
- }
- @Suppress("UNCHECKED_CAST")
- val list = PrefManager.getNullableCustomVal(
- "continueAnimeList",
- listOf(),
- List::class.java
- ) as List
- if (list.isNotEmpty()) {
- list.reversed().forEach {
- if (subMap.containsKey(it)) returnArray.add(subMap[it]!!)
- }
- for (i in subMap) {
- if (i.value !in returnArray) returnArray.add(i.value)
- }
- } else returnArray.addAll(subMap.values)
- returnMap["planned$type"] = returnArray
- }
+ if (toShow.getOrNull(0) == true) processMedia(
+ "Anime",
+ response?.data?.currentAnime?.lists?.flatMap { it.entries ?: emptyList() }?.reversed(),
+ response?.data?.repeatingAnime?.lists?.flatMap { it.entries ?: emptyList() }?.reversed()
+ )
+ if (toShow.getOrNull(2) == true) processMedia(
+ "AnimePlanned",
+ response?.data?.plannedAnime?.lists?.flatMap { it.entries ?: emptyList() }?.reversed(),
+ null
+ )
+ if (toShow.getOrNull(3) == true) processMedia(
+ "Manga",
+ response?.data?.currentManga?.lists?.flatMap { it.entries ?: emptyList() }?.reversed(),
+ response?.data?.repeatingManga?.lists?.flatMap { it.entries ?: emptyList() }?.reversed()
+ )
+ if (toShow.getOrNull(5) == true) processMedia(
+ "MangaPlanned",
+ response?.data?.plannedManga?.lists?.flatMap { it.entries ?: emptyList() }?.reversed(),
+ null
+ )
- fun favorite(type: String) {
- val favourites =
- if (type == "Anime") response?.data?.favoriteAnime?.favourites else response?.data?.favoriteManga?.favourites
- val apiMediaList = if (type == "Anime") favourites?.anime else favourites?.manga
+ fun processFavorites(type: String, favorites: List?) {
val returnArray = arrayListOf()
- apiMediaList?.edges?.forEach {
- it.node?.let { i ->
- val m = Media(i).apply { isFav = true }
- if (m.id !in removeList) {
- returnArray.add(m)
+ favorites?.forEach { edge ->
+ edge.node?.let {
+ val media = Media(it).apply { isFav = true }
+ if (media.id !in removeList && (!hidePrivate || !media.isListPrivate)) {
+ returnArray.add(media)
} else {
- removedMedia.add(m)
+ removedMedia.add(media)
}
}
}
returnMap["favorite$type"] = returnArray
}
- if (toShow.getOrNull(0) == true) {
- current("Anime")
- }
- if (toShow.getOrNull(1) == true) {
- favorite("Anime")
- }
- if (toShow.getOrNull(2) == true) {
- planned("Anime")
- }
- if (toShow.getOrNull(3) == true) {
- current("Manga")
- }
- if (toShow.getOrNull(4) == true) {
- favorite("Manga")
- }
- if (toShow.getOrNull(5) == true) {
- planned("Manga")
- }
+ if (toShow.getOrNull(1) == true) processFavorites(
+ "Anime",
+ response?.data?.favoriteAnime?.favourites?.anime?.edges
+ )
+ if (toShow.getOrNull(4) == true) processFavorites(
+ "Manga",
+ response?.data?.favoriteManga?.favourites?.manga?.edges
+ )
+
if (toShow.getOrNull(6) == true) {
val subMap = mutableMapOf()
- response?.data?.recommendationQuery?.apply {
- recommendations?.onEach {
- val json = it.mediaRecommendation
- if (json != null) {
- val m = Media(json)
- m.relation = json.type?.toString()
- subMap[m.id] = m
- }
+ response?.data?.recommendationQuery?.recommendations?.forEach {
+ it.mediaRecommendation?.let { json ->
+ val media = Media(json)
+ media.relation = json.type?.toString()
+ subMap[media.id] = media
}
}
- response?.data?.recommendationPlannedQueryAnime?.apply {
- lists?.forEach { li ->
- li.entries?.forEach {
- val m = Media(it)
- if (m.status == "RELEASING" || m.status == "FINISHED") {
- m.relation = it.media?.type?.toString()
- subMap[m.id] = m
- }
- }
+ response?.data?.recommendationPlannedQueryAnime?.lists?.flatMap {
+ it.entries ?: emptyList()
+ }?.forEach {
+ val media = Media(it)
+ if (media.status in listOf("RELEASING", "FINISHED")) {
+ media.relation = it.media?.type?.toString()
+ subMap[media.id] = media
}
}
- response?.data?.recommendationPlannedQueryManga?.apply {
- lists?.forEach { li ->
- li.entries?.forEach {
- val m = Media(it)
- if (m.status == "RELEASING" || m.status == "FINISHED") {
- m.relation = it.media?.type?.toString()
- subMap[m.id] = m
- }
- }
+ response?.data?.recommendationPlannedQueryManga?.lists?.flatMap {
+ it.entries ?: emptyList()
+ }?.forEach {
+ val media = Media(it)
+ if (media.status in listOf("RELEASING", "FINISHED")) {
+ media.relation = it.media?.type?.toString()
+ subMap[media.id] = media
}
}
- val list = ArrayList(subMap.values.toList())
- list.sortByDescending { it.meanScore }
+ val list = ArrayList(subMap.values).apply { sortByDescending { it.meanScore } }
returnMap["recommendations"] = list
}
@@ -1106,172 +1077,105 @@ query (${"$"}page: Int = 1, ${"$"}id: Int, ${"$"}type: MediaType, ${"$"}isAdult:
return null
}
- private val onListAnime =
- (if (PrefManager.getVal(PrefName.IncludeAnimeList)) "" else "onList:false").replace(
- "\"",
- ""
- )
- private val isAdult =
- (if (PrefManager.getVal(PrefName.AdultOnly)) "isAdult:true" else "").replace("\"", "")
+ private fun mediaList(media1: Page?): ArrayList {
+ val combinedList = arrayListOf()
+ media1?.media?.mapTo(combinedList) { Media(it) }
+ return combinedList
+ }
+
+ private fun getPreference(pref: PrefName): Boolean = PrefManager.getVal(pref)
+
+ private fun buildQueryString(
+ sort: String,
+ type: String,
+ format: String? = null,
+ country: String? = null
+ ): String {
+ val includeList = when {
+ type == "ANIME" && !getPreference(PrefName.IncludeAnimeList) -> "onList:false"
+ type == "MANGA" && !getPreference(PrefName.IncludeMangaList) -> "onList:false"
+ else -> ""
+ }
+ val isAdult = if (getPreference(PrefName.AdultOnly)) "isAdult:true" else ""
+ val formatFilter = format?.let { "format:$it, " } ?: ""
+ val countryFilter = country?.let { "countryOfOrigin:$it, " } ?: ""
+
+ return buildString {
+ append("""Page(page:1,perPage:50){pageInfo{hasNextPage total}media(sort:$sort, type:$type, $formatFilter $countryFilter $includeList $isAdult){id idMal status chapters episodes nextAiringEpisode{episode} isAdult type meanScore isFavourite format bannerImage countryOfOrigin coverImage{large} title{english romaji userPreferred} mediaListEntry{progress private score(format:POINT_100) status}}}""")
+ }
+ }
private fun recentAnimeUpdates(page: Int): String {
- return """Page(page:$page,perPage:50){pageInfo{hasNextPage total}airingSchedules(airingAt_greater:0 airingAt_lesser:${System.currentTimeMillis() / 1000 - 10000} sort:TIME_DESC){episode airingAt media{id idMal status chapters episodes nextAiringEpisode{episode} isAdult type meanScore isFavourite format bannerImage countryOfOrigin coverImage{large} title{english romaji userPreferred} mediaListEntry{progress private score(format:POINT_100) status}}}}"""
- }
-
- private fun trendingMovies(page: Int): String {
- return """Page(page:$page,perPage:50){pageInfo{hasNextPage total}media(sort:POPULARITY_DESC, type: ANIME, format: MOVIE, $onListAnime, $isAdult){id idMal status chapters episodes nextAiringEpisode{episode}isAdult type meanScore isFavourite format bannerImage countryOfOrigin coverImage{large}title{english romaji userPreferred}mediaListEntry{progress private score(format:POINT_100)status}}}"""
- }
-
- private fun topRatedAnime(page: Int): String {
- return """Page(page:$page,perPage:50){pageInfo{hasNextPage total}media(sort: SCORE_DESC, type: ANIME, $onListAnime, $isAdult){id idMal status chapters episodes nextAiringEpisode{episode}isAdult type meanScore isFavourite format bannerImage countryOfOrigin coverImage{large}title{english romaji userPreferred}mediaListEntry{progress private score(format:POINT_100)status}}}"""
- }
-
- private fun mostFavAnime(page: Int): String {
- return """Page(page:$page,perPage:50){pageInfo{hasNextPage total}media(sort:FAVOURITES_DESC,type: ANIME, $onListAnime, $isAdult){id idMal status chapters episodes nextAiringEpisode{episode}isAdult type meanScore isFavourite format bannerImage countryOfOrigin coverImage{large}title{english romaji userPreferred}mediaListEntry{progress private score(format:POINT_100)status}}}"""
- }
-
- suspend fun loadAnimeList(): Map> {
- val list = mutableMapOf>()
- fun query(): String {
- return """{
- recentUpdates:${recentAnimeUpdates(1)}
- recentUpdates2:${recentAnimeUpdates(2)}
- trendingMovies:${trendingMovies(1)}
- trendingMovies2:${trendingMovies(2)}
- topRated:${topRatedAnime(1)}
- topRated2:${topRatedAnime(2)}
- mostFav:${mostFavAnime(1)}
- mostFav2:${mostFavAnime(2)}
- }""".trimIndent()
+ val currentTime = System.currentTimeMillis() / 1000
+ return buildString {
+ append("""Page(page:$page,perPage:50){pageInfo{hasNextPage total}airingSchedules(airingAt_greater:0 airingAt_lesser:${currentTime - 10000} sort:TIME_DESC){episode airingAt media{id idMal status chapters episodes nextAiringEpisode{episode} isAdult type meanScore isFavourite format bannerImage countryOfOrigin coverImage{large} title{english romaji userPreferred} mediaListEntry{progress private score(format:POINT_100) status}}}}""")
}
- executeQuery(query(), force = true)?.data?.apply {
- val listOnly: Boolean = PrefManager.getVal(PrefName.RecentlyListOnly)
- val adultOnly: Boolean = PrefManager.getVal(PrefName.AdultOnly)
- val idArr = mutableListOf()
- list["recentUpdates"] = recentUpdates?.airingSchedules?.mapNotNull { i ->
- i.media?.let {
- if (!idArr.contains(it.id))
- if (!listOnly && it.countryOfOrigin == "JP" && Anilist.adult && adultOnly && it.isAdult == true) {
- idArr.add(it.id)
- Media(it)
- } else if (!listOnly && !adultOnly && (it.countryOfOrigin == "JP" && it.isAdult == false)) {
- idArr.add(it.id)
- Media(it)
- } else if ((listOnly && it.mediaListEntry != null)) {
- idArr.add(it.id)
- Media(it)
- } else null
- else null
+ }
+
+ private fun queryAnimeList(): String {
+ return buildString {
+ append("""{recentUpdates:${recentAnimeUpdates(1)} recentUpdates2:${recentAnimeUpdates(2)} trendingMovies:${buildQueryString("POPULARITY_DESC", "ANIME", "MOVIE")} topRated:${buildQueryString("SCORE_DESC", "ANIME")} mostFav:${buildQueryString("FAVOURITES_DESC", "ANIME")}}""")
+ }
+ }
+
+ private fun queryMangaList(): String {
+ return buildString {
+ append("""{trendingManga:${buildQueryString("POPULARITY_DESC", "MANGA", country = "JP")} trendingManhwa:${buildQueryString("POPULARITY_DESC", "MANGA", country = "KR")} trendingNovel:${buildQueryString("POPULARITY_DESC", "MANGA", format = "NOVEL", country = "JP")} topRated:${buildQueryString("SCORE_DESC", "MANGA")} mostFav:${buildQueryString("FAVOURITES_DESC", "MANGA")}}""")
+ }
+ }
+
+ suspend fun loadAnimeList(): Map> = coroutineScope {
+ val list = mutableMapOf>()
+
+ fun filterRecentUpdates(page: Page?): ArrayList {
+ val listOnly = getPreference(PrefName.RecentlyListOnly)
+ val adultOnly = getPreference(PrefName.AdultOnly)
+ val idArr = mutableSetOf()
+ return page?.airingSchedules?.mapNotNull { i ->
+ i.media?.takeIf { !idArr.contains(it.id) }?.let {
+ val shouldAdd = when {
+ !listOnly && it.countryOfOrigin == "JP" && adultOnly && it.isAdult == true -> true
+ !listOnly && !adultOnly && it.countryOfOrigin == "JP" && it.isAdult == false -> true
+ listOnly && it.mediaListEntry != null -> true
+ else -> false
+ }
+ if (shouldAdd) {
+ idArr.add(it.id)
+ Media(it)
+ } else null
}
}?.toCollection(ArrayList()) ?: arrayListOf()
-
- list["trendingMovies"] =
- trendingMovies?.media?.map { Media(it) }?.toCollection(ArrayList()) ?: arrayListOf()
- list["topRated"] =
- topRated?.media?.map { Media(it) }?.toCollection(ArrayList()) ?: arrayListOf()
- list["mostFav"] =
- mostFav?.media?.map { Media(it) }?.toCollection(ArrayList()) ?: arrayListOf()
-
- list["recentUpdates"]?.addAll(recentUpdates2?.airingSchedules?.mapNotNull { i ->
- i.media?.let {
- if (!idArr.contains(it.id))
- if (!listOnly && it.countryOfOrigin == "JP" && Anilist.adult && adultOnly && it.isAdult == true) {
- idArr.add(it.id)
- Media(it)
- } else if (!listOnly && !adultOnly && (it.countryOfOrigin == "JP" && it.isAdult == false)) {
- idArr.add(it.id)
- Media(it)
- } else if ((listOnly && it.mediaListEntry != null)) {
- idArr.add(it.id)
- Media(it)
- } else null
- else null
- }
- }?.toCollection(ArrayList()) ?: arrayListOf())
- list["trendingMovies"]?.addAll(trendingMovies2?.media?.map { Media(it) }
- ?.toCollection(ArrayList()) ?: arrayListOf())
- list["topRated"]?.addAll(
- topRated2?.media?.map { Media(it) }?.toCollection(ArrayList()) ?: arrayListOf()
- )
- list["mostFav"]?.addAll(
- mostFav2?.media?.map { Media(it) }?.toCollection(ArrayList()) ?: arrayListOf()
- )
}
- return list
+
+ val animeList = async { executeQuery(queryAnimeList(), force = true) }
+
+ animeList.await()?.data?.apply {
+ list["recentUpdates"] = filterRecentUpdates(recentUpdates)
+ list["trendingMovies"] = mediaList(trendingMovies)
+ list["topRated"] = mediaList(topRated)
+ list["mostFav"] = mediaList(mostFav)
+ }
+
+ list
}
- private val onListManga =
- (if (PrefManager.getVal(PrefName.IncludeMangaList)) "" else "onList:false").replace(
- "\"",
- ""
- )
-
- private fun trendingManga(page: Int): String {
- return """Page(page:$page,perPage:50){pageInfo{hasNextPage total}media(sort:POPULARITY_DESC, type: MANGA,countryOfOrigin:JP, $onListManga, $isAdult){id idMal status chapters episodes nextAiringEpisode{episode}isAdult type meanScore isFavourite format bannerImage countryOfOrigin coverImage{large}title{english romaji userPreferred}mediaListEntry{progress private score(format:POINT_100)status}}}"""
- }
-
- private fun trendingManhwa(page: Int): String {
- return """Page(page:$page,perPage:50){pageInfo{hasNextPage total}media(sort:POPULARITY_DESC, type: MANGA, countryOfOrigin:KR, $onListManga, $isAdult){id idMal status chapters episodes nextAiringEpisode{episode}isAdult type meanScore isFavourite format bannerImage countryOfOrigin coverImage{large}title{english romaji userPreferred}mediaListEntry{progress private score(format:POINT_100)status}}}"""
- }
-
- private fun trendingNovel(page: Int): String {
- return """Page(page:$page,perPage:50){pageInfo{hasNextPage total}media(sort:POPULARITY_DESC, type: MANGA, format: NOVEL, countryOfOrigin:JP, $onListManga, $isAdult){id idMal status chapters episodes nextAiringEpisode{episode}isAdult type meanScore isFavourite format bannerImage countryOfOrigin coverImage{large}title{english romaji userPreferred}mediaListEntry{progress private score(format:POINT_100)status}}}"""
- }
-
- private fun topRatedManga(page: Int): String {
- return """Page(page:$page,perPage:50){pageInfo{hasNextPage total}media(sort: SCORE_DESC, type: MANGA, $onListManga, $isAdult){id idMal status chapters episodes nextAiringEpisode{episode}isAdult type meanScore isFavourite format bannerImage countryOfOrigin coverImage{large}title{english romaji userPreferred}mediaListEntry{progress private score(format:POINT_100)status}}}"""
- }
-
- private fun mostFavManga(page: Int): String {
- return """Page(page:$page,perPage:50){pageInfo{hasNextPage total}media(sort:FAVOURITES_DESC,type: MANGA, $onListManga, $isAdult){id idMal status chapters episodes nextAiringEpisode{episode}isAdult type meanScore isFavourite format bannerImage countryOfOrigin coverImage{large}title{english romaji userPreferred}mediaListEntry{progress private score(format:POINT_100)status}}}"""
- }
-
- suspend fun loadMangaList(): Map> {
+ suspend fun loadMangaList(): Map> = coroutineScope {
val list = mutableMapOf>()
- fun query(): String {
- return """{
- trendingManga:${trendingManga(1)}
- trendingManga2:${trendingManga(2)}
- trendingManhwa:${trendingManhwa(1)}
- trendingManhwa2:${trendingManhwa(2)}
- trendingNovel:${trendingNovel(1)}
- trendingNovel2:${trendingNovel(2)}
- topRated:${topRatedManga(1)}
- topRated2:${topRatedManga(2)}
- mostFav:${mostFavManga(1)}
- mostFav2:${mostFavManga(2)}
- }""".trimIndent()
+
+ val mangaList = async { executeQuery(queryMangaList(), force = true) }
+
+ mangaList.await()?.data?.apply {
+ list["trendingManga"] = mediaList(trendingManga)
+ list["trendingManhwa"] = mediaList(trendingManhwa)
+ list["trendingNovel"] = mediaList(trendingNovel)
+ list["topRated"] = mediaList(topRated)
+ list["mostFav"] = mediaList(mostFav)
}
- executeQuery(query(), force = true)?.data?.apply {
- list["trendingManga"] =
- trendingManga?.media?.map { Media(it) }?.toCollection(ArrayList()) ?: arrayListOf()
- list["trendingManhwa"] =
- trendingManhwa?.media?.map { Media(it) }?.toCollection(ArrayList()) ?: arrayListOf()
- list["trendingNovel"] =
- trendingNovel?.media?.map { Media(it) }?.toCollection(ArrayList()) ?: arrayListOf()
- list["topRated"] =
- topRated?.media?.map { Media(it) }?.toCollection(ArrayList()) ?: arrayListOf()
- list["mostFav"] =
- mostFav?.media?.map { Media(it) }?.toCollection(ArrayList()) ?: arrayListOf()
-
- list["trendingManga"]?.addAll(
- trendingManga2?.media?.map { Media(it) }?.toList() ?: arrayListOf()
- )
- list["trendingManhwa"]?.addAll(
- trendingManhwa2?.media?.map { Media(it) }?.toList() ?: arrayListOf()
- )
- list["trendingNovel"]?.addAll(
- trendingNovel2?.media?.map { Media(it) }?.toList() ?: arrayListOf()
- )
- list["topRated"]?.addAll(topRated2?.media?.map { Media(it) }?.toList() ?: arrayListOf())
- list["mostFav"]?.addAll(mostFav2?.media?.map { Media(it) }?.toList() ?: arrayListOf())
- }
-
-
- return list
+ list
}
+
suspend fun recentlyUpdated(
greater: Long = 0,
lesser: Long = System.currentTimeMillis() / 1000 - 10000
@@ -1672,10 +1576,10 @@ Page(page:$page,perPage:50) {
resetNotification: Boolean = true,
type: Boolean? = null
): NotificationResponse? {
- val type_in = "type_in:[AIRING,MEDIA_MERGE,MEDIA_DELETION,MEDIA_DATA_CHANGE]"
+ val typeIn = "type_in:[AIRING,MEDIA_MERGE,MEDIA_DELETION,MEDIA_DATA_CHANGE]"
val reset = if (resetNotification) "true" else "false"
val res = executeQuery(
- """{User(id:$id){unreadNotificationCount}Page(page:$page,perPage:$ITEMS_PER_PAGE){pageInfo{currentPage,hasNextPage}notifications(resetNotificationCount:$reset , ${if (type == true) type_in else ""}){__typename...on AiringNotification{id,type,animeId,episode,contexts,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}},}...on FollowingNotification{id,userId,type,context,createdAt,user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityMessageNotification{id,userId,type,activityId,context,createdAt,message{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityMentionNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplyNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplySubscribedNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityLikeNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplyLikeNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentMentionNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentReplyNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentSubscribedNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentLikeNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadLikeNotification{id,userId,type,threadId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on RelatedMediaAdditionNotification{id,type,context,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaDataChangeNotification{id,type,mediaId,context,reason,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaMergeNotification{id,type,mediaId,deletedMediaTitles,context,reason,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaDeletionNotification{id,type,deletedMediaTitle,context,reason,createdAt,}}}}""",
+ """{User(id:$id){unreadNotificationCount}Page(page:$page,perPage:$ITEMS_PER_PAGE){pageInfo{currentPage,hasNextPage}notifications(resetNotificationCount:$reset , ${if (type == true) typeIn else ""}){__typename...on AiringNotification{id,type,animeId,episode,contexts,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}},}...on FollowingNotification{id,userId,type,context,createdAt,user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityMessageNotification{id,userId,type,activityId,context,createdAt,message{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityMentionNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplyNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplySubscribedNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityLikeNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplyLikeNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentMentionNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentReplyNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentSubscribedNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentLikeNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadLikeNotification{id,userId,type,threadId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on RelatedMediaAdditionNotification{id,type,context,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaDataChangeNotification{id,type,mediaId,context,reason,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaMergeNotification{id,type,mediaId,deletedMediaTitles,context,reason,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaDeletionNotification{id,type,deletedMediaTitle,context,reason,createdAt,}}}}""",
force = true
)
if (res != null && resetNotification) {
diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistViewModel.kt b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistViewModel.kt
index e75383a1..f1db7ff6 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistViewModel.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistViewModel.kt
@@ -91,17 +91,16 @@ class AnilistHomeViewModel : ViewModel() {
fun getHidden(): LiveData> = hidden
- @Suppress("UNCHECKED_CAST")
suspend fun initHomePage() {
val res = Anilist.query.initHomePage()
- res["currentAnime"]?.let { animeContinue.postValue(it as ArrayList?) }
- res["favoriteAnime"]?.let { animeFav.postValue(it as ArrayList?) }
- res["plannedAnime"]?.let { animePlanned.postValue(it as ArrayList?) }
- res["currentManga"]?.let { mangaContinue.postValue(it as ArrayList?) }
- res["favoriteManga"]?.let { mangaFav.postValue(it as ArrayList?) }
- res["plannedManga"]?.let { mangaPlanned.postValue(it as ArrayList?) }
- res["recommendations"]?.let { recommendation.postValue(it as ArrayList?) }
- res["hidden"]?.let { hidden.postValue(it as ArrayList?) }
+ res["currentAnime"]?.let { animeContinue.postValue(it) }
+ res["favoriteAnime"]?.let { animeFav.postValue(it) }
+ res["currentAnimePlanned"]?.let { animePlanned.postValue(it) }
+ res["currentManga"]?.let { mangaContinue.postValue(it) }
+ res["favoriteManga"]?.let { mangaFav.postValue(it) }
+ res["currentMangaPlanned"]?.let { mangaPlanned.postValue(it) }
+ res["recommendations"]?.let { recommendation.postValue(it) }
+ res["hidden"]?.let { hidden.postValue(it) }
}
suspend fun loadMain(context: FragmentActivity) {
diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/api/Data.kt b/app/src/main/java/ani/dantotsu/connections/anilist/api/Data.kt
index e6635b9a..e909a3bc 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/api/Data.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/api/Data.kt
@@ -163,13 +163,9 @@ class Query {
@Serializable
data class Data(
@SerialName("recentUpdates") val recentUpdates: ani.dantotsu.connections.anilist.api.Page?,
- @SerialName("recentUpdates2") val recentUpdates2: ani.dantotsu.connections.anilist.api.Page?,
@SerialName("trendingMovies") val trendingMovies: ani.dantotsu.connections.anilist.api.Page?,
- @SerialName("trendingMovies2") val trendingMovies2: ani.dantotsu.connections.anilist.api.Page?,
@SerialName("topRated") val topRated: ani.dantotsu.connections.anilist.api.Page?,
- @SerialName("topRated2") val topRated2: ani.dantotsu.connections.anilist.api.Page?,
@SerialName("mostFav") val mostFav: ani.dantotsu.connections.anilist.api.Page?,
- @SerialName("mostFav2") val mostFav2: ani.dantotsu.connections.anilist.api.Page?,
)
}
@@ -181,15 +177,10 @@ class Query {
@Serializable
data class Data(
@SerialName("trendingManga") val trendingManga: ani.dantotsu.connections.anilist.api.Page?,
- @SerialName("trendingManga2") val trendingManga2: ani.dantotsu.connections.anilist.api.Page?,
@SerialName("trendingManhwa") val trendingManhwa: ani.dantotsu.connections.anilist.api.Page?,
- @SerialName("trendingManhwa2") val trendingManhwa2: ani.dantotsu.connections.anilist.api.Page?,
@SerialName("trendingNovel") val trendingNovel: ani.dantotsu.connections.anilist.api.Page?,
- @SerialName("trendingNovel2") val trendingNovel2: ani.dantotsu.connections.anilist.api.Page?,
@SerialName("topRated") val topRated: ani.dantotsu.connections.anilist.api.Page?,
- @SerialName("topRated2") val topRated2: ani.dantotsu.connections.anilist.api.Page?,
@SerialName("mostFav") val mostFav: ani.dantotsu.connections.anilist.api.Page?,
- @SerialName("mostFav2") val mostFav2: ani.dantotsu.connections.anilist.api.Page?,
)
}
diff --git a/app/src/main/java/ani/dantotsu/download/anime/OfflineAnimeFragment.kt b/app/src/main/java/ani/dantotsu/download/anime/OfflineAnimeFragment.kt
index 3bcdffe1..4f3876fe 100644
--- a/app/src/main/java/ani/dantotsu/download/anime/OfflineAnimeFragment.kt
+++ b/app/src/main/java/ani/dantotsu/download/anime/OfflineAnimeFragment.kt
@@ -49,6 +49,7 @@ import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
+import ani.dantotsu.util.customAlertDialog
import com.anggrayudi.storage.file.openInputStream
import com.google.android.material.card.MaterialCardView
import com.google.android.material.imageview.ShapeableImageView
@@ -203,25 +204,22 @@ class OfflineAnimeFragment : Fragment(), OfflineAnimeSearchListener {
val type: MediaType = MediaType.ANIME
// Alert dialog to confirm deletion
- val builder =
- androidx.appcompat.app.AlertDialog.Builder(requireContext(), R.style.MyPopup)
- builder.setTitle("Delete ${item.title}?")
- builder.setMessage("Are you sure you want to delete ${item.title}?")
- builder.setPositiveButton("Yes") { _, _ ->
- downloadManager.removeMedia(item.title, type)
- val mediaIds =
- PrefManager.getAnimeDownloadPreferences().all?.filter { it.key.contains(item.title) }?.values
- ?: emptySet()
- if (mediaIds.isEmpty()) {
- snackString("No media found") // if this happens, terrible things have happened
+ requireContext().customAlertDialog().apply {
+ setTitle("Delete ${item.title}?")
+ setMessage("Are you sure you want to delete ${item.title}?")
+ setPosButton(R.string.yes) {
+ downloadManager.removeMedia(item.title, type)
+ val mediaIds = PrefManager.getAnimeDownloadPreferences().all?.filter { it.key.contains(item.title) }?.values ?: emptySet()
+ if (mediaIds.isEmpty()) {
+ snackString("No media found") // if this happens, terrible things have happened
+ }
+ getDownloads()
}
- getDownloads()
+ setNegButton(R.string.no) {
+ // Do nothing
+ }
+ show()
}
- builder.setNegativeButton("No") { _, _ ->
- // Do nothing
- }
- val dialog = builder.show()
- dialog.window?.setDimAmount(0.8f)
true
}
}
diff --git a/app/src/main/java/ani/dantotsu/download/manga/MangaDownloaderService.kt b/app/src/main/java/ani/dantotsu/download/manga/MangaDownloaderService.kt
index 4452a2df..ed3cb02c 100644
--- a/app/src/main/java/ani/dantotsu/download/manga/MangaDownloaderService.kt
+++ b/app/src/main/java/ani/dantotsu/download/manga/MangaDownloaderService.kt
@@ -32,6 +32,7 @@ import ani.dantotsu.media.manga.MangaReadFragment.Companion.ACTION_DOWNLOAD_STAR
import ani.dantotsu.media.manga.MangaReadFragment.Companion.EXTRA_CHAPTER_NUMBER
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
+import ani.dantotsu.util.NumberConverter.Companion.ofLength
import com.anggrayudi.storage.file.deleteRecursively
import com.anggrayudi.storage.file.forceDelete
import com.anggrayudi.storage.file.openOutputStream
@@ -235,7 +236,7 @@ class MangaDownloaderService : Service() {
}
if (bitmap != null) {
- saveToDisk("$index.jpg", outputDir, bitmap)
+ saveToDisk("${index.ofLength(3)}.jpg", outputDir, bitmap)
}
farthest++
diff --git a/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaFragment.kt b/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaFragment.kt
index 6d88918e..dcb462e8 100644
--- a/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaFragment.kt
+++ b/app/src/main/java/ani/dantotsu/download/manga/OfflineMangaFragment.kt
@@ -46,6 +46,7 @@ import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
import ani.dantotsu.util.Logger
+import ani.dantotsu.util.customAlertDialog
import com.anggrayudi.storage.file.openInputStream
import com.google.android.material.card.MaterialCardView
import com.google.android.material.imageview.ShapeableImageView
@@ -201,19 +202,15 @@ class OfflineMangaFragment : Fragment(), OfflineMangaSearchListener {
MediaType.NOVEL
}
// Alert dialog to confirm deletion
- val builder =
- androidx.appcompat.app.AlertDialog.Builder(requireContext(), R.style.MyPopup)
- builder.setTitle("Delete ${item.title}?")
- builder.setMessage("Are you sure you want to delete ${item.title}?")
- builder.setPositiveButton("Yes") { _, _ ->
- downloadManager.removeMedia(item.title, type)
- getDownloads()
- }
- builder.setNegativeButton("No") { _, _ ->
- // Do nothing
- }
- val dialog = builder.show()
- dialog.window?.setDimAmount(0.8f)
+ requireContext().customAlertDialog().apply {
+ setTitle("Delete ${item.title}?")
+ setMessage("Are you sure you want to delete ${item.title}?")
+ setPosButton(R.string.yes) {
+ downloadManager.removeMedia(item.title, type)
+ getDownloads()
+ }
+ setNegButton(R.string.no)
+ }.show()
true
}
}
diff --git a/app/src/main/java/ani/dantotsu/download/video/Helper.kt b/app/src/main/java/ani/dantotsu/download/video/Helper.kt
index b207d634..ab8dd73d 100644
--- a/app/src/main/java/ani/dantotsu/download/video/Helper.kt
+++ b/app/src/main/java/ani/dantotsu/download/video/Helper.kt
@@ -3,7 +3,6 @@ package ani.dantotsu.download.video
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
-import android.app.AlertDialog
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
@@ -29,10 +28,10 @@ import ani.dantotsu.download.anime.AnimeDownloaderService
import ani.dantotsu.download.anime.AnimeServiceDataSingleton
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaType
-import ani.dantotsu.parsers.Subtitle
import ani.dantotsu.parsers.Video
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.util.Logger
+import ani.dantotsu.util.customAlertDialog
import eu.kanade.tachiyomi.network.NetworkHelper
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@@ -72,19 +71,19 @@ object Helper {
episodeImage
)
- val downloadsManger = Injekt.get()
- val downloadCheck = downloadsManger
+ val downloadsManager = Injekt.get()
+ val downloadCheck = downloadsManager
.queryDownload(title, episode, MediaType.ANIME)
if (downloadCheck) {
- AlertDialog.Builder(context, R.style.MyPopup)
- .setTitle("Download Exists")
- .setMessage("A download for this episode already exists. Do you want to overwrite it?")
- .setPositiveButton("Yes") { _, _ ->
+ context.customAlertDialog().apply {
+ setTitle("Download Exists")
+ setMessage("A download for this episode already exists. Do you want to overwrite it?")
+ setPosButton(R.string.yes) {
PrefManager.getAnimeDownloadPreferences().edit()
.remove(animeDownloadTask.getTaskName())
.apply()
- downloadsManger.removeDownload(
+ downloadsManager.removeDownload(
DownloadedType(
title,
episode,
@@ -99,8 +98,9 @@ object Helper {
}
}
}
- .setNegativeButton("No") { _, _ -> }
- .show()
+ setNegButton(R.string.no)
+ show()
+ }
} else {
AnimeServiceDataSingleton.downloadQueue.offer(animeDownloadTask)
if (!AnimeServiceDataSingleton.isServiceRunning) {
diff --git a/app/src/main/java/ani/dantotsu/home/AnimeFragment.kt b/app/src/main/java/ani/dantotsu/home/AnimeFragment.kt
index f9a9f596..87713885 100644
--- a/app/src/main/java/ani/dantotsu/home/AnimeFragment.kt
+++ b/app/src/main/java/ani/dantotsu/home/AnimeFragment.kt
@@ -38,6 +38,7 @@ import ani.dantotsu.snackString
import ani.dantotsu.statusBarHeight
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -289,15 +290,20 @@ class AnimeFragment : Fragment() {
}
}
}
- model.loaded = true
- model.loadTrending(1)
- model.loadAll()
+ }
+ model.loaded = true
+ val loadTrending = async(Dispatchers.IO) { model.loadTrending(1) }
+ val loadAll = async(Dispatchers.IO) { model.loadAll() }
+ val loadPopular = async(Dispatchers.IO) {
model.loadPopular(
- "ANIME", sort = Anilist.sortBy[1], onList = PrefManager.getVal(
- PrefName.PopularAnimeList
- )
+ "ANIME",
+ sort = Anilist.sortBy[1],
+ onList = PrefManager.getVal(PrefName.PopularAnimeList)
)
}
+ loadTrending.await()
+ loadAll.await()
+ loadPopular.await()
live.postValue(false)
_binding?.animeRefresh?.isRefreshing = false
running = false
diff --git a/app/src/main/java/ani/dantotsu/home/HomeFragment.kt b/app/src/main/java/ani/dantotsu/home/HomeFragment.kt
index a66506d9..dfd39e6a 100644
--- a/app/src/main/java/ani/dantotsu/home/HomeFragment.kt
+++ b/app/src/main/java/ani/dantotsu/home/HomeFragment.kt
@@ -50,6 +50,7 @@ import ani.dantotsu.statusBarHeight
import ani.dantotsu.util.Logger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.math.max
@@ -457,54 +458,56 @@ class HomeFragment : Fragment() {
var running = false
val live = Refresh.activity.getOrPut(1) { MutableLiveData(true) }
- live.observe(viewLifecycleOwner)
- {
- if (!running && it) {
+ live.observe(viewLifecycleOwner) { shouldRefresh ->
+ if (!running && shouldRefresh) {
running = true
scope.launch {
withContext(Dispatchers.IO) {
- //Get userData First
- Anilist.userid =
- PrefManager.getNullableVal(PrefName.AnilistUserId, null)
- ?.toIntOrNull()
+ // Get user data first
+ Anilist.userid = PrefManager.getNullableVal(PrefName.AnilistUserId, null)?.toIntOrNull()
if (Anilist.userid == null) {
- getUserId(requireContext()) {
- load()
- }
- } else {
- CoroutineScope(Dispatchers.IO).launch {
+ withContext(Dispatchers.Main) {
getUserId(requireContext()) {
load()
}
}
+ } else {
+ getUserId(requireContext()) {
+ load()
+ }
}
model.loaded = true
- CoroutineScope(Dispatchers.IO).launch {
- model.setListImages()
- }
- CoroutineScope(Dispatchers.IO).launch {
- model.initUserStatus()
- }
- var empty = true
- val homeLayoutShow: List =
- PrefManager.getVal(PrefName.HomeLayout)
- model.initHomePage()
- (array.indices).forEach { i ->
+ model.setListImages()
+ }
+
+ var empty = true
+ val homeLayoutShow: List = PrefManager.getVal(PrefName.HomeLayout)
+
+ withContext(Dispatchers.Main) {
+ homeLayoutShow.indices.forEach { i ->
if (homeLayoutShow.elementAt(i)) {
empty = false
- } else withContext(Dispatchers.Main) {
+ } else {
containers[i].visibility = View.GONE
}
}
- model.empty.postValue(empty)
}
+
+ val initHomePage = async(Dispatchers.IO) { model.initHomePage() }
+ val initUserStatus = async(Dispatchers.IO) { model.initUserStatus() }
+ initHomePage.await()
+ initUserStatus.await()
+
+ withContext(Dispatchers.Main) {
+ model.empty.postValue(empty)
+ binding.homeHiddenItemsContainer.visibility = View.GONE
+ }
+
live.postValue(false)
_binding?.homeRefresh?.isRefreshing = false
running = false
}
- binding.homeHiddenItemsContainer.visibility = View.GONE
}
-
}
}
diff --git a/app/src/main/java/ani/dantotsu/home/LoginFragment.kt b/app/src/main/java/ani/dantotsu/home/LoginFragment.kt
index 5f89464e..13fde1e5 100644
--- a/app/src/main/java/ani/dantotsu/home/LoginFragment.kt
+++ b/app/src/main/java/ani/dantotsu/home/LoginFragment.kt
@@ -12,12 +12,14 @@ import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.Fragment
import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist
+import ani.dantotsu.databinding.DialogUserAgentBinding
import ani.dantotsu.databinding.FragmentLoginBinding
import ani.dantotsu.openLinkInBrowser
import ani.dantotsu.settings.saving.internal.PreferenceKeystore
import ani.dantotsu.settings.saving.internal.PreferencePackager
import ani.dantotsu.toast
import ani.dantotsu.util.Logger
+import ani.dantotsu.util.customAlertDialog
import com.google.android.material.textfield.TextInputEditText
class LoginFragment : Fragment() {
@@ -94,38 +96,31 @@ class LoginFragment : Fragment() {
val password = CharArray(16).apply { fill('0') }
// Inflate the dialog layout
- val dialogView =
- LayoutInflater.from(requireActivity()).inflate(R.layout.dialog_user_agent, null)
- dialogView.findViewById(R.id.userAgentTextBox)?.hint = "Password"
- val subtitleTextView = dialogView.findViewById(R.id.subtitle)
- subtitleTextView?.visibility = View.VISIBLE
- subtitleTextView?.text = "Enter your password to decrypt the file"
+ val dialogView = DialogUserAgentBinding.inflate(layoutInflater).apply {
+ userAgentTextBox.hint = "Password"
+ subtitle.visibility = View.VISIBLE
+ subtitle.text = getString(R.string.enter_password_to_decrypt_file)
+ }
- val dialog = AlertDialog.Builder(requireActivity(), R.style.MyPopup)
- .setTitle("Enter Password")
- .setView(dialogView)
- .setPositiveButton("OK", null)
- .setNegativeButton("Cancel") { dialog, _ ->
+ requireActivity().customAlertDialog().apply {
+ setTitle("Enter Password")
+ setCustomView(dialogView.root)
+ setPosButton(R.string.ok){
+ val editText = dialogView.userAgentTextBox
+ if (editText.text?.isNotBlank() == true) {
+ editText.text?.toString()?.trim()?.toCharArray(password)
+ callback(password)
+ } else {
+ toast("Password cannot be empty")
+ }
+ }
+ setNegButton(R.string.cancel) {
password.fill('0')
- dialog.dismiss()
callback(null)
}
- .create()
+ }.show()
- dialog.window?.setDimAmount(0.8f)
- dialog.show()
- // Override the positive button here
- dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
- val editText = dialog.findViewById(R.id.userAgentTextBox)
- if (editText?.text?.isNotBlank() == true) {
- editText.text?.toString()?.trim()?.toCharArray(password)
- dialog.dismiss()
- callback(password)
- } else {
- toast("Password cannot be empty")
- }
- }
}
private fun restartApp() {
diff --git a/app/src/main/java/ani/dantotsu/home/MangaFragment.kt b/app/src/main/java/ani/dantotsu/home/MangaFragment.kt
index c878c584..0ed19510 100644
--- a/app/src/main/java/ani/dantotsu/home/MangaFragment.kt
+++ b/app/src/main/java/ani/dantotsu/home/MangaFragment.kt
@@ -35,6 +35,7 @@ import ani.dantotsu.snackString
import ani.dantotsu.statusBarHeight
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -274,15 +275,22 @@ class MangaFragment : Fragment() {
}
}
}
- model.loaded = true
- model.loadTrending()
- model.loadAll()
+ }
+ model.loaded = true
+ val loadTrending = async(Dispatchers.IO) { model.loadTrending() }
+ val loadAll = async(Dispatchers.IO) { model.loadAll() }
+ val loadPopular = async(Dispatchers.IO) {
model.loadPopular(
- "MANGA", sort = Anilist.sortBy[1], onList = PrefManager.getVal(
- PrefName.PopularMangaList
- )
+ "MANGA",
+ sort = Anilist.sortBy[1],
+ onList = PrefManager.getVal(PrefName.PopularAnimeList)
)
}
+
+ loadTrending.await()
+ loadAll.await()
+ loadPopular.await()
+
live.postValue(false)
_binding?.mangaRefresh?.isRefreshing = false
running = false
diff --git a/app/src/main/java/ani/dantotsu/home/status/StatusActivity.kt b/app/src/main/java/ani/dantotsu/home/status/StatusActivity.kt
index 7fc0e78b..ced8b2d8 100644
--- a/app/src/main/java/ani/dantotsu/home/status/StatusActivity.kt
+++ b/app/src/main/java/ani/dantotsu/home/status/StatusActivity.kt
@@ -49,7 +49,10 @@ class StatusActivity : AppCompatActivity(), StoriesCallback {
if (activity.getOrNull(position) != null) {
val startFrom = findFirstNonMatch(watchedActivity, activity[position].activity )
val startIndex = if ( startFrom > 0) startFrom else 0
- binding.stories.setStoriesList(activity[position].activity, this, startIndex + 1)
+ binding.stories.setStoriesList(
+ activityList = activity[position].activity,
+ startIndex = startIndex + 1
+ )
} else {
Logger.log("index out of bounds for position $position of size ${activity.size}")
finish()
@@ -92,7 +95,7 @@ class StatusActivity : AppCompatActivity(), StoriesCallback {
val startFrom = findFirstNonMatch(watchedActivity, activity[position].activity )
val startIndex= if ( startFrom > 0) startFrom else 0
binding.stories.startAnimation(slideOutLeft)
- binding.stories.setStoriesList(activity[position].activity, this, startIndex + 1)
+ binding.stories.setStoriesList(activity[position].activity, startIndex + 1)
binding.stories.startAnimation(slideInRight)
} else {
finish()
@@ -107,7 +110,7 @@ class StatusActivity : AppCompatActivity(), StoriesCallback {
val startFrom = findFirstNonMatch(watchedActivity, activity[position].activity )
val startIndex = if ( startFrom > 0) startFrom else 0
binding.stories.startAnimation(slideOutRight)
- binding.stories.setStoriesList(activity[position].activity, this, startIndex + 1)
+ binding.stories.setStoriesList(activity[position].activity,startIndex + 1)
binding.stories.startAnimation(slideInLeft)
} else {
finish()
diff --git a/app/src/main/java/ani/dantotsu/home/status/Stories.kt b/app/src/main/java/ani/dantotsu/home/status/Stories.kt
index d6522844..a141a5d6 100644
--- a/app/src/main/java/ani/dantotsu/home/status/Stories.kt
+++ b/app/src/main/java/ani/dantotsu/home/status/Stories.kt
@@ -5,7 +5,6 @@ import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.util.AttributeSet
-import android.view.Gravity
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
@@ -16,7 +15,6 @@ import androidx.core.app.ActivityOptionsCompat
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
-import androidx.core.widget.NestedScrollView
import androidx.fragment.app.FragmentActivity
import ani.dantotsu.R
import ani.dantotsu.blurImage
@@ -32,6 +30,7 @@ import ani.dantotsu.profile.ProfileActivity
import ani.dantotsu.profile.User
import ani.dantotsu.profile.UsersDialogFragment
import ani.dantotsu.profile.activity.ActivityItemBuilder
+import ani.dantotsu.profile.activity.RepliesBottomDialog
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
@@ -50,7 +49,6 @@ import kotlin.math.abs
class Stories @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), View.OnTouchListener {
- private lateinit var activity: FragmentActivity
private lateinit var binding: FragmentStatusBinding
private lateinit var activityList: List
private lateinit var storiesListener: StoriesCallback
@@ -81,10 +79,9 @@ class Stories @JvmOverloads constructor(
fun setStoriesList(
- activityList: List, activity: FragmentActivity, startIndex: Int = 1
+ activityList: List, startIndex: Int = 1
) {
this.activityList = activityList
- this.activity = activity
this.storyIndex = startIndex
addLoadingViews(activityList)
}
@@ -369,7 +366,9 @@ class Stories @JvmOverloads constructor(
if (
story.status?.contains("completed") == false &&
!story.status.contains("plans") &&
- !story.status.contains("repeating")
+ !story.status.contains("repeating")&&
+ !story.status.contains("paused")&&
+ !story.status.contains("dropped")
) {
"of ${story.media?.title?.userPreferred}"
} else {
@@ -390,7 +389,7 @@ class Stories @JvmOverloads constructor(
story.media?.id
),
ActivityOptionsCompat.makeSceneTransitionAnimation(
- activity,
+ (it.context as FragmentActivity),
binding.coverImage,
ViewCompat.getTransitionName(binding.coverImage)!!
).toBundle()
@@ -428,7 +427,7 @@ class Stories @JvmOverloads constructor(
binding.activityReplies.setColorFilter(ContextCompat.getColor(context, R.color.bg_opp))
binding.activityRepliesContainer.setOnClickListener {
RepliesBottomDialog.newInstance(story.id)
- .show(activity.supportFragmentManager, "replies")
+ .show((it.context as FragmentActivity).supportFragmentManager, "replies")
}
binding.activityLike.setColorFilter(if (story.isLiked == true) likeColor else notLikeColor)
binding.activityLikeCount.text = story.likeCount.toString()
@@ -436,10 +435,9 @@ class Stories @JvmOverloads constructor(
like()
}
binding.activityLikeContainer.setOnLongClickListener {
- val context = activity
UsersDialogFragment().apply {
userList(userList)
- show(context.supportFragmentManager, "dialog")
+ show((it.context as FragmentActivity).supportFragmentManager, "dialog")
}
true
}
diff --git a/app/src/main/java/ani/dantotsu/media/CalendarActivity.kt b/app/src/main/java/ani/dantotsu/media/CalendarActivity.kt
index 66cec7e4..230f3a4e 100644
--- a/app/src/main/java/ani/dantotsu/media/CalendarActivity.kt
+++ b/app/src/main/java/ani/dantotsu/media/CalendarActivity.kt
@@ -30,6 +30,7 @@ class CalendarActivity : AppCompatActivity() {
private lateinit var binding: ActivityListBinding
private val scope = lifecycleScope
private var selectedTabIdx = 1
+ private var showOnlyLibrary = false
private val model: OtherDetailsViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
@@ -38,8 +39,6 @@ class CalendarActivity : AppCompatActivity() {
ThemeManager(this).applyTheme()
binding = ActivityListBinding.inflate(layoutInflater)
-
-
val primaryColor = getThemeColor(com.google.android.material.R.attr.colorSurface)
val primaryTextColor = getThemeColor(com.google.android.material.R.attr.colorPrimary)
val secondaryTextColor = getThemeColor(com.google.android.material.R.attr.colorOutline)
@@ -79,6 +78,17 @@ class CalendarActivity : AppCompatActivity() {
override fun onTabReselected(tab: TabLayout.Tab?) {}
})
+ binding.listed.setOnClickListener {
+ showOnlyLibrary = !showOnlyLibrary
+ binding.listed.setImageResource(
+ if (showOnlyLibrary) R.drawable.ic_round_collections_bookmark_24
+ else R.drawable.ic_round_library_books_24
+ )
+ scope.launch {
+ model.loadCalendar(showOnlyLibrary)
+ }
+ }
+
model.getCalendar().observe(this) {
if (it != null) {
binding.listProgressBar.visibility = View.GONE
@@ -97,11 +107,10 @@ class CalendarActivity : AppCompatActivity() {
live.observe(this) {
if (it) {
scope.launch {
- withContext(Dispatchers.IO) { model.loadCalendar() }
+ withContext(Dispatchers.IO) { model.loadCalendar(showOnlyLibrary) }
live.postValue(false)
}
}
}
-
}
}
diff --git a/app/src/main/java/ani/dantotsu/media/OtherDetailsViewModel.kt b/app/src/main/java/ani/dantotsu/media/OtherDetailsViewModel.kt
index 0be0fc22..a086a765 100644
--- a/app/src/main/java/ani/dantotsu/media/OtherDetailsViewModel.kt
+++ b/app/src/main/java/ani/dantotsu/media/OtherDetailsViewModel.kt
@@ -26,25 +26,50 @@ class OtherDetailsViewModel : ViewModel() {
if (author.value == null) author.postValue(Anilist.query.getAuthorDetails(m))
}
+ private var cachedAllCalendarData: Map>? = null
+ private var cachedLibraryCalendarData: Map>? = null
private val calendar: MutableLiveData