This commit is contained in:
tutel
2024-03-10 19:52:17 +02:00
19 changed files with 457 additions and 282 deletions

View File

@@ -156,7 +156,7 @@ fun initActivity(a: Activity) {
navBarHeight = this.getInsets(WindowInsetsCompat.Type.systemBars()).bottom
}
}
a.hideStatusBar()
WindowInsetsControllerCompat(window, window.decorView).hide(WindowInsetsCompat.Type.statusBars())
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && statusBarHeight == 0 && a.resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
window.decorView.rootWindowInsets?.displayCutout?.apply {
if (boundingRects.size > 0) {
@@ -176,40 +176,47 @@ fun initActivity(a: Activity) {
}
}
@Suppress("DEPRECATION")
fun Activity.hideSystemBars() {
window.decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_FULLSCREEN
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
)
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
controller.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
controller.hide(WindowInsetsCompat.Type.systemBars())
}
}
@Suppress("DEPRECATION")
fun Activity.hideStatusBar() {
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
fun Activity.setNavigationTheme() {
val a = TypedValue()
theme.resolveAttribute(android.R.attr.colorBackground, a, true)
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && a.isColorType)
|| (a.type >= TypedValue.TYPE_FIRST_COLOR_INT && a.type <= TypedValue.TYPE_LAST_COLOR_INT)) {
window.navigationBarColor = a.data
}
}
open class BottomSheetDialogFragment : BottomSheetDialogFragment() {
override fun onStart() {
super.onStart()
val window = dialog?.window
val decorView: View = window?.decorView ?: return
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
if (this.resources.configuration.orientation != Configuration.ORIENTATION_PORTRAIT) {
val behavior = BottomSheetBehavior.from(requireView().parent as View)
behavior.state = BottomSheetBehavior.STATE_EXPANDED
dialog?.window?.let { window ->
WindowCompat.setDecorFitsSystemWindows(window, false)
val immersiveMode: Boolean = PrefManager.getVal(PrefName.ImmersiveMode)
if (immersiveMode) {
WindowInsetsControllerCompat(
window, window.decorView
).hide(WindowInsetsCompat.Type.statusBars())
}
if (this.resources.configuration.orientation != Configuration.ORIENTATION_PORTRAIT) {
val behavior = BottomSheetBehavior.from(requireView().parent as View)
behavior.state = BottomSheetBehavior.STATE_EXPANDED
}
val typedValue = TypedValue()
val theme = requireContext().theme
theme.resolveAttribute(
com.google.android.material.R.attr.colorSurface,
typedValue,
true
)
window.navigationBarColor = typedValue.data
}
val typedValue = TypedValue()
val theme = requireContext().theme
theme.resolveAttribute(
com.google.android.material.R.attr.colorSurface,
typedValue,
true
)
window.navigationBarColor = typedValue.data
}
override fun show(manager: FragmentManager, tag: String?) {

View File

@@ -22,9 +22,6 @@ import androidx.annotation.OptIn
import androidx.appcompat.app.AppCompatActivity
import androidx.core.animation.doOnEnd
import androidx.core.content.ContextCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.core.view.doOnAttach
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
@@ -146,24 +143,14 @@ class MainActivity : AppCompatActivity() {
finish()
}
doubleBackToExitPressedOnce = true
WindowInsetsControllerCompat(window, window.decorView)
.show(WindowInsetsCompat.Type.navigationBars())
snackString(this@MainActivity.getString(R.string.back_to_exit)).apply {
this?.addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
super.onDismissed(transientBottomBar, event)
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
controller.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
controller.hide(WindowInsetsCompat.Type.navigationBars())
}
doubleBackToExitPressedOnce = false
}
})
}
Handler(Looper.getMainLooper()).postDelayed(
{ doubleBackToExitPressedOnce = false },
2000
)
}
val preferences: SourcePreferences = Injekt.get()
@@ -369,13 +356,11 @@ class MainActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
WindowCompat.setDecorFitsSystemWindows(window, false)
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
controller.hide(WindowInsetsCompat.Type.navigationBars())
initActivity(this)
binding.includedNavbar.navbarContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
bottomMargin = navBarHeight
}
window.navigationBarColor = getColor(android.R.color.transparent)
}
//ViewPager

View File

@@ -52,7 +52,7 @@ class AnilistQueries {
Anilist.episodesWatched = user.statistics?.anime?.episodesWatched
Anilist.chapterRead = user.statistics?.manga?.chaptersRead
Anilist.adult = user.options?.displayAdultContent ?: false
Anilist.unreadNotificationCount = user.unreadNotificationCount?:0
Anilist.unreadNotificationCount = user.unreadNotificationCount ?: 0
return true
}
@@ -281,7 +281,8 @@ class AnilistQueries {
} else {
if (currContext()?.let { isOnline(it) } == true) {
snackString(currContext()?.getString(R.string.error_getting_data))
} else { }
} else {
}
}
}
val mal = async {
@@ -335,7 +336,11 @@ class AnilistQueries {
returnArray.addAll(map.values)
return returnArray
}
val list = PrefManager.getNullableCustomVal("continueAnimeList", listOf<Int>(), List::class.java) as List<Int>
val list = PrefManager.getNullableCustomVal(
"continueAnimeList",
listOf<Int>(),
List::class.java
) as List<Int>
if (list.isNotEmpty()) {
list.reversed().forEach {
if (map.containsKey(it)) returnArray.add(map[it]!!)
@@ -351,7 +356,7 @@ class AnilistQueries {
return """ MediaListCollection(userId: ${Anilist.userid}, type: $type, status: $status , sort: UPDATED_TIME ) { lists { entries { progress private score(format:POINT_100) status media { id idMal type isAdult status chapters episodes nextAiringEpisode {episode} meanScore isFavourite format bannerImage coverImage{large} title { english romaji userPreferred } } } } } """
}
suspend fun favMedia(anime: Boolean, id: Int? = Anilist.userid ): ArrayList<Media> {
suspend fun favMedia(anime: Boolean, id: Int? = Anilist.userid): ArrayList<Media> {
var hasNextPage = true
var page = 0
@@ -375,7 +380,7 @@ class AnilistQueries {
return responseArray
}
private fun favMediaQuery(anime: Boolean, page: Int, id: Int?= Anilist.userid ): String {
private fun favMediaQuery(anime: Boolean, page: Int, id: Int? = Anilist.userid): String {
return """User(id:${id}){id favourites{${if (anime) "anime" else "manga"}(page:$page){pageInfo{hasNextPage}edges{favouriteOrder node{id idMal isAdult mediaListEntry{ progress private score(format:POINT_100) status } chapters isFavourite format episodes nextAiringEpisode{episode}meanScore isFavourite format startDate{year month day} title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}}}"""
}
@@ -487,7 +492,11 @@ class AnilistQueries {
returnMap["current$type"] = returnArray
return
}
val list = PrefManager.getNullableCustomVal("continueAnimeList", listOf<Int>(), List::class.java) as List<Int>
val list = PrefManager.getNullableCustomVal(
"continueAnimeList",
listOf<Int>(),
List::class.java
) as List<Int>
if (list.isNotEmpty()) {
list.reversed().forEach {
if (subMap.containsKey(it)) returnArray.add(subMap[it]!!)
@@ -512,7 +521,11 @@ class AnilistQueries {
subMap[m.id] = m
}
}
val list = PrefManager.getNullableCustomVal("continueAnimeList", listOf<Int>(), List::class.java) as List<Int>
val list = PrefManager.getNullableCustomVal(
"continueAnimeList",
listOf<Int>(),
List::class.java
) as List<Int>
if (list.isNotEmpty()) {
list.reversed().forEach {
if (subMap.containsKey(it)) returnArray.add(subMap[it]!!)
@@ -1291,64 +1304,44 @@ Page(page:$page,perPage:50) {
)
}
suspend fun userFavMedia(anime: Boolean, id: Int): ArrayList<Media> {
var hasNextPage = true
var page = 0
suspend fun getNextPage(page: Int): List<Media> {
val response = executeQuery<Query.User>("""{${userFavMediaQuery(anime, page, id)}}""")
val favourites = response?.data?.user?.favourites
val apiMediaList = if (anime) favourites?.anime else favourites?.manga
hasNextPage = apiMediaList?.pageInfo?.hasNextPage ?: false
return apiMediaList?.edges?.mapNotNull {
it.node?.let { i ->
Media(i).apply { isFav = true }
}
} ?: return listOf()
}
val responseArray = arrayListOf<Media>()
while (hasNextPage) {
page++
responseArray.addAll(getNextPage(page))
}
return responseArray
}
private fun userFavMediaQuery(anime: Boolean, page: Int, id: Int): String {
return """User(id:${id}){id favourites{${if (anime) "anime" else "manga"}(page:$page){pageInfo{hasNextPage}edges{favouriteOrder node{id idMal isAdult mediaListEntry{ progress private score(format:POINT_100) status } chapters isFavourite format episodes nextAiringEpisode{episode}meanScore isFavourite format startDate{year month day} title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}}}"""
}
suspend fun userFollowing(id: Int): Query.Following?{
return executeQuery<Query.Following>("""{Page {following(userId:${id},sort:[USERNAME]){id name avatar{large medium}bannerImage}}}""", force = true)
suspend fun userFollowing(id: Int): Query.Following? {
return executeQuery<Query.Following>(
"""{Page {following(userId:${id},sort:[USERNAME]){id name avatar{large medium}bannerImage}}}""",
force = true
)
}
suspend fun userFollowers(id: Int): Query.Follower?{
return executeQuery<Query.Follower>("""{Page {followers(userId:${id},sort:[USERNAME]){id name avatar{large medium}bannerImage}}}""", force = true)
suspend fun userFollowers(id: Int): Query.Follower? {
return executeQuery<Query.Follower>(
"""{Page {followers(userId:${id},sort:[USERNAME]){id name avatar{large medium}bannerImage}}}""",
force = true
)
}
private suspend fun userBannerImage(type: String,id: Int?): String? {
val response =
executeQuery<Query.MediaListCollection>("""{ MediaListCollection(userId: ${id}, type: $type, chunk:1,perChunk:25, sort: [SCORE_DESC,UPDATED_TIME_DESC]) { lists { entries{ media { id bannerImage } } } } } """)
val random = response?.data?.mediaListCollection?.lists?.mapNotNull {
it.entries?.mapNotNull { entry ->
val imageUrl = entry.media?.bannerImage
if (imageUrl != null && imageUrl != "null") imageUrl
else null
}
}?.flatten()?.randomOrNull() ?: return null
return random
suspend fun initProfilePage(id: Int): Query.ProfilePageMedia? {
return executeQuery<Query.ProfilePageMedia>(
"""{
favoriteAnime:${userFavMediaQuery(true, 1, id)}
favoriteManga:${userFavMediaQuery(false, 1, id)}
animeMediaList:${bannerImageQuery("ANIME", id)}
mangaMediaList:${bannerImageQuery("MANGA", id)}
}""".trimIndent(), force = true
)
}
suspend fun getUserBannerImages(id: Int? = Anilist.userid): ArrayList<String?> {
val default = arrayListOf<String?>(null, null)
default[0] = userBannerImage("ANIME", id)
default[1] = userBannerImage("MANGA",id)
return default
private fun bannerImageQuery(type: String, id: Int?): String {
return """MediaListCollection(userId: ${id}, type: $type, chunk:1,perChunk:25, sort: [SCORE_DESC,UPDATED_TIME_DESC]) { lists { entries{ media { id bannerImage } } } }"""
}
suspend fun getNotifications(id: Int, page: Int = 1): NotificationResponse? {
val res = executeQuery<NotificationResponse>("""{User(id:$id){unreadNotificationCount}Page(page:$page,perPage:$ITEMS_PER_PAGE){notifications(resetNotificationCount:true){__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)
val res = executeQuery<NotificationResponse>(
"""{User(id:$id){unreadNotificationCount}Page(page:$page,perPage:$ITEMS_PER_PAGE){notifications(resetNotificationCount:true){__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) {
Anilist.unreadNotificationCount = 0
}
@@ -1359,7 +1352,9 @@ Page(page:$page,perPage:50) {
val filter = if (userId != null) "userId:$userId,"
else if (global) "isFollowing:false,"
else "isFollowing:true,"
val res = executeQuery<FeedResponse>("""{Page(page:$page,perPage:$ITEMS_PER_PAGE){activities(${filter}sort:ID_DESC){__typename ... on TextActivity{id userId type replyCount text(asHtml:true)siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on ListActivity{id userId type replyCount status progress siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}media{id title{english romaji native userPreferred}bannerImage coverImage{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on MessageActivity{id recipientId messengerId type replyCount message(asHtml:true)isLocked isSubscribed isLiked isPrivate siteUrl createdAt recipient{id name bannerImage avatar{medium large}}messenger{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}}}}""")
val res = executeQuery<FeedResponse>(
"""{Page(page:$page,perPage:$ITEMS_PER_PAGE){activities(${filter}sort:ID_DESC){__typename ... on TextActivity{id userId type replyCount text(asHtml:true)siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on ListActivity{id userId type replyCount status progress siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}media{id title{english romaji native userPreferred}bannerImage coverImage{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on MessageActivity{id recipientId messengerId type replyCount message(asHtml:true)isLocked isSubscribed isLiked isPrivate siteUrl createdAt recipient{id name bannerImage avatar{medium large}}messenger{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}}}}"""
)
return res
}

View File

@@ -7,10 +7,8 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import ani.dantotsu.BuildConfig
import ani.dantotsu.R
import ani.dantotsu.connections.comments.CommentsAPI
import ani.dantotsu.connections.discord.Discord
import ani.dantotsu.connections.mal.MAL
import ani.dantotsu.media.Character
import ani.dantotsu.media.Media
import ani.dantotsu.others.AppUpdater
import ani.dantotsu.settings.saving.PrefManager
@@ -335,24 +333,57 @@ class GenresViewModel : ViewModel() {
}
}
class ProfileViewModel : ViewModel(){
class ProfileViewModel : ViewModel() {
private val mangaFav: MutableLiveData<ArrayList<Media>> =
MutableLiveData<ArrayList<Media>>(null)
fun getMangaFav(): LiveData<ArrayList<Media>> = mangaFav
private val animeFav: MutableLiveData<ArrayList<Media>> =
MutableLiveData<ArrayList<Media>>(null)
fun getAnimeFav(): LiveData<ArrayList<Media>> = animeFav
private val listImages: MutableLiveData<ArrayList<String?>> =
MutableLiveData<ArrayList<String?>>(arrayListOf())
fun getListImages(): LiveData<ArrayList<String?>> = listImages
suspend fun setData(id: Int) {
mangaFav.postValue(Anilist.query.userFavMedia(false, id))
animeFav.postValue(Anilist.query.userFavMedia(true, id))
listImages.postValue(Anilist.query.getUserBannerImages(id))
val res = Anilist.query.initProfilePage(id)
val mangaList = res?.data?.favoriteManga?.favourites?.manga?.edges?.mapNotNull {
it.node?.let { i ->
Media(i).apply { isFav = true }
}
}
mangaFav.postValue(ArrayList(mangaList ?: arrayListOf()))
val animeList = res?.data?.favoriteAnime?.favourites?.anime?.edges?.mapNotNull {
it.node?.let { i ->
Media(i).apply { isFav = true }
}
}
animeFav.postValue(ArrayList(animeList ?: arrayListOf()))
val bannerImages = arrayListOf<String?>(null, null)
val animeRandom = res?.data?.animeMediaList?.lists?.mapNotNull {
it.entries?.mapNotNull { entry ->
val imageUrl = entry.media?.bannerImage
if (imageUrl != null && imageUrl != "null") imageUrl
else null
}
}?.flatten()?.randomOrNull()
bannerImages[0] = animeRandom
val mangaRandom = res?.data?.mangaMediaList?.lists?.mapNotNull {
it.entries?.mapNotNull { entry ->
val imageUrl = entry.media?.bannerImage
if (imageUrl != null && imageUrl != "null") imageUrl
else null
}
}?.flatten()?.randomOrNull()
bannerImages[1] = mangaRandom
listImages.postValue(bannerImages)
}
fun refresh() {

View File

@@ -139,6 +139,20 @@ class Query {
)
}
@Serializable
data class ProfilePageMedia(
@SerialName("data")
val data: Data?
) {
@Serializable
data class Data(
@SerialName("favoriteAnime") val favoriteAnime: ani.dantotsu.connections.anilist.api.User?,
@SerialName("favoriteManga") val favoriteManga: ani.dantotsu.connections.anilist.api.User?,
@SerialName("animeMediaList") val animeMediaList: ani.dantotsu.connections.anilist.api.MediaListCollection?,
@SerialName("mangaMediaList") val mangaMediaList: ani.dantotsu.connections.anilist.api.MediaListCollection?
)
}
@Serializable
data class ToggleFollow(
@SerialName("data")

View File

@@ -63,6 +63,10 @@ data class Activity(
val createdAt: Int,
@SerialName("user")
val user: User?,
@SerialName("recipient")
val recipient: User?,
@SerialName("messenger")
val messenger: User?,
@SerialName("media")
val media: Media?,
@SerialName("replies")

View File

@@ -5,13 +5,12 @@ import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Context.INPUT_METHOD_SERVICE
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
@@ -27,36 +26,15 @@ import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.comments.Comment
import ani.dantotsu.connections.comments.CommentResponse
import ani.dantotsu.connections.comments.CommentsAPI
import ani.dantotsu.copyToClipboard
import ani.dantotsu.databinding.FragmentCommentsBinding
import ani.dantotsu.loadImage
import ani.dantotsu.media.MediaDetailsActivity
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
import com.bumptech.glide.Glide
import com.bumptech.glide.RequestBuilder
import com.bumptech.glide.RequestManager
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.gif.GifDrawable
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.xwray.groupie.GroupieAdapter
import com.xwray.groupie.Section
import io.noties.markwon.AbstractMarkwonPlugin
import io.noties.markwon.Markwon
import io.noties.markwon.MarkwonConfiguration
import io.noties.markwon.SoftBreakAddsNewLinePlugin
import io.noties.markwon.editor.MarkwonEditor
import io.noties.markwon.editor.MarkwonEditorTextWatcher
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin
import io.noties.markwon.ext.tables.TablePlugin
import io.noties.markwon.ext.tasklist.TaskListPlugin
import io.noties.markwon.html.HtmlPlugin
import io.noties.markwon.html.TagHandlerNoOp
import io.noties.markwon.image.AsyncDrawable
import io.noties.markwon.image.glide.GlideImagesPlugin
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -64,6 +42,7 @@ import java.text.SimpleDateFormat
import java.util.Locale
import java.util.TimeZone
@SuppressLint("ClickableViewAccessibility")
class CommentsFragment : Fragment() {
lateinit var binding: FragmentCommentsBinding
lateinit var activity: AppCompatActivity
@@ -193,8 +172,68 @@ class CommentsFragment : Fragment() {
}
var isFetching = false
binding.commentsList.setOnTouchListener(
object : View.OnTouchListener {
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
if (event?.action == MotionEvent.ACTION_UP) {
if (!binding.commentsList.canScrollVertically(1) && !isFetching &&
(binding.commentsList.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() == (binding.commentsList.adapter!!.itemCount - 1)
) {
if (pagesLoaded < totalPages) {
binding.commentBottomRefresh.visibility = View.VISIBLE
loadMoreComments()
lifecycleScope.launch {
kotlinx.coroutines.delay(1000)
withContext(Dispatchers.Main) {
binding.commentBottomRefresh.visibility = View.GONE
}
}
} else {
snackString("No more comments")
}
}
}
return false
}
private fun loadMoreComments() {
isFetching = true
lifecycleScope.launch {
val comments = fetchComments()
comments?.comments?.forEach { comment ->
updateUIWithComment(comment)
}
totalPages = comments?.totalPages ?: 1
pagesLoaded++
isFetching = false
}
}
private suspend fun fetchComments(): CommentResponse? {
return withContext(Dispatchers.IO) {
CommentsAPI.getCommentsForId(mediaId, pagesLoaded + 1, filterTag)
}
}
//adds additional comments to the section
private suspend fun updateUIWithComment(comment: Comment) {
withContext(Dispatchers.Main) {
section.add(
CommentItem(
comment,
buildMarkwon(activity),
section,
this@CommentsFragment,
backgroundColor,
0
)
)
}
}
})
//if we have scrolled to the bottom of the list, load more comments
binding.commentsList.addOnScrollListener(object :
/*binding.commentsList.addOnScrollListener(object :
androidx.recyclerview.widget.RecyclerView.OnScrollListener() {
override fun onScrolled(
recyclerView: androidx.recyclerview.widget.RecyclerView,
@@ -245,7 +284,7 @@ class CommentsFragment : Fragment() {
)
}
}
})
})*/
binding.commentInput.addTextChangedListener(object : TextWatcher {

View File

@@ -601,6 +601,7 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
super.onResume()
binding.mediaInfoProgressBar.visibility = progress
binding.animeSourceRecycler.layoutManager?.onRestoreInstanceState(state)
requireActivity().setNavigationTheme()
}
override fun onPause() {

View File

@@ -285,7 +285,7 @@ class MangaReaderActivity : AppCompatActivity() {
binding.mangaReaderNextChapter.performClick()
}
binding.mangaReaderNextChapter.setOnClickListener {
if (defaultSettings.direction == RIGHT_TO_LEFT) {
if (defaultSettings.direction == RIGHT_TO_LEFT || defaultSettings.direction == BOTTOM_TO_TOP) {
if (currentChapterIndex > 0) change(currentChapterIndex - 1)
else snackString(getString(R.string.first_chapter))
} else {
@@ -298,7 +298,7 @@ class MangaReaderActivity : AppCompatActivity() {
binding.mangaReaderPreviousChapter.performClick()
}
binding.mangaReaderPreviousChapter.setOnClickListener {
if (defaultSettings.direction == RIGHT_TO_LEFT) {
if (defaultSettings.direction == RIGHT_TO_LEFT || defaultSettings.direction == BOTTOM_TO_TOP) {
if (chaptersArr.size > currentChapterIndex + 1) progress { change(currentChapterIndex + 1) }
else snackString(getString(R.string.next_chapter_not_found))
} else {
@@ -315,7 +315,7 @@ class MangaReaderActivity : AppCompatActivity() {
PrefManager.setCustomVal("${media.id}_current_chp", chap.number)
currentChapterIndex = chaptersArr.indexOf(chap.number)
binding.mangaReaderChapterSelect.setSelection(currentChapterIndex)
if (defaultSettings.direction == RIGHT_TO_LEFT) {
if (defaultSettings.direction == RIGHT_TO_LEFT || defaultSettings.direction == BOTTOM_TO_TOP) {
binding.mangaReaderNextChap.text =
chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: ""
binding.mangaReaderPrevChap.text =
@@ -439,6 +439,10 @@ class MangaReaderActivity : AppCompatActivity() {
if ((defaultSettings.direction == TOP_TO_BOTTOM || defaultSettings.direction == BOTTOM_TO_TOP)) {
binding.mangaReaderSwipy.vertical = true
if (defaultSettings.direction == TOP_TO_BOTTOM) {
binding.mangaReaderNextChap.text =
chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: ""
binding.mangaReaderPrevChap.text =
chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: ""
binding.BottomSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex + 1)
?: getString(R.string.no_chapter)
binding.TopSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex - 1)
@@ -450,6 +454,10 @@ class MangaReaderActivity : AppCompatActivity() {
binding.mangaReaderNextChapter.performClick()
}
} else {
binding.mangaReaderNextChap.text =
chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: ""
binding.mangaReaderPrevChap.text =
chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: ""
binding.BottomSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex - 1)
?: getString(R.string.no_chapter)
binding.TopSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex + 1)
@@ -729,7 +737,7 @@ class MangaReaderActivity : AppCompatActivity() {
val screenWidth = Resources.getSystem().displayMetrics.widthPixels
//if in the 1st 1/5th of the screen width, left and lower than 1/5th of the screen height, left
if (screenWidth / 5 in x + 1..<y) {
pressLocation = if (defaultSettings.direction == RIGHT_TO_LEFT) {
pressLocation = if (defaultSettings.direction == RIGHT_TO_LEFT || defaultSettings.direction == BOTTOM_TO_TOP) {
pressPos.RIGHT
} else {
pressPos.LEFT
@@ -737,7 +745,7 @@ class MangaReaderActivity : AppCompatActivity() {
}
//if in the last 1/5th of the screen width, right and lower than 1/5th of the screen height, right
else if (x > screenWidth - screenWidth / 5 && y > screenWidth / 5) {
pressLocation = if (defaultSettings.direction == RIGHT_TO_LEFT) {
pressLocation = if (defaultSettings.direction == RIGHT_TO_LEFT || defaultSettings.direction == BOTTOM_TO_TOP) {
pressPos.LEFT
} else {
pressPos.RIGHT

View File

@@ -1,8 +1,10 @@
package ani.dantotsu.profile
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
import android.widget.PopupMenu
@@ -29,13 +31,15 @@ import ani.dantotsu.snackString
import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.toast
import com.google.android.material.appbar.AppBarLayout
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import nl.joery.animatedbottombar.AnimatedBottomBar
import kotlin.math.abs
class ProfileActivity : AppCompatActivity() {
class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListener {
lateinit var binding: ActivityProfileBinding
private var selected: Int = 1
private lateinit var navBar: AnimatedBottomBar
@@ -47,6 +51,7 @@ class ProfileActivity : AppCompatActivity() {
initActivity(this)
binding = ActivityProfileBinding.inflate(layoutInflater)
setContentView(binding.root)
screenWidth = resources.displayMetrics.widthPixels.toFloat()
navBar = binding.profileNavBar
navBar.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin = navBarHeight }
val feedTab = navBar.createTab(R.drawable.ic_round_filter_24, "Feed")
@@ -57,6 +62,7 @@ class ProfileActivity : AppCompatActivity() {
navBar.addTab(statsTab)
navBar.visibility = View.GONE
binding.profileViewPager.isUserInputEnabled = false
lifecycleScope.launch(Dispatchers.IO) {
val userid = intent.getIntExtra("userId", 0)
val respond = Anilist.query.getUserProfile(userid)
@@ -72,6 +78,7 @@ class ProfileActivity : AppCompatActivity() {
}
binding.profileViewPager.adapter =
ViewPagerAdapter(supportFragmentManager, lifecycle, user)
binding.profileViewPager.setOffscreenPageLimit(3)
binding.profileViewPager.setCurrentItem(selected, false)
navBar.visibility = View.VISIBLE
navBar.selectTabAt(selected)
@@ -163,10 +170,50 @@ class ProfileActivity : AppCompatActivity() {
)
}
mMaxScrollSize = binding.profileAppBar.totalScrollRange
binding.profileAppBar.addOnOffsetChangedListener(this@ProfileActivity)
}
}
}
//Collapsing UI Stuff
private var isCollapsed = false
private val percent = 45
private var mMaxScrollSize = 0
private var screenWidth: Float = 0f
override fun onOffsetChanged(appBar: AppBarLayout, i: Int) {
if (mMaxScrollSize == 0) mMaxScrollSize = appBar.totalScrollRange
val percentage = abs(i) * 100 / mMaxScrollSize
binding.profileUserAvatarContainer.visibility =
if (binding.profileUserAvatarContainer.scaleX == 0f) View.GONE else View.VISIBLE
val duration = (200 * (PrefManager.getVal(PrefName.AnimationSpeed) as Float)).toLong()
val typedValue = TypedValue()
this@ProfileActivity.theme.resolveAttribute(
com.google.android.material.R.attr.colorSecondary,
typedValue,
true
)
val color = typedValue.data
if (percentage >= percent && !isCollapsed) {
isCollapsed = true
ObjectAnimator.ofFloat(binding.profileUserDataContainer, "translationX", screenWidth)
.setDuration(duration).start()
ObjectAnimator.ofFloat(binding.profileUserAvatarContainer, "translationX", screenWidth)
.setDuration(duration).start()
binding.profileBannerImage.pause()
}
if (percentage <= percent && isCollapsed) {
isCollapsed = false
ObjectAnimator.ofFloat(binding.profileUserDataContainer, "translationX", 0f)
.setDuration(duration).start()
ObjectAnimator.ofFloat(binding.profileUserAvatarContainer, "translationX", 0f).setDuration(duration)
.start()
if (PrefManager.getVal(PrefName.BannerAnimations)) binding.profileBannerImage.resume()
}
}
override fun onResume() {
if (this::navBar.isInitialized) {
navBar.selectTabAt(selected)

View File

@@ -5,6 +5,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
@@ -16,6 +17,7 @@ import ani.dantotsu.profile.ChartBuilder.Companion.ChartPacket
import ani.dantotsu.profile.ChartBuilder.Companion.ChartType
import ani.dantotsu.profile.ChartBuilder.Companion.MediaType
import ani.dantotsu.profile.ChartBuilder.Companion.StatType
import ani.dantotsu.statusBarHeight
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartType
import com.xwray.groupie.GroupieAdapter
import kotlinx.coroutines.Dispatchers
@@ -32,6 +34,7 @@ class StatsFragment :
private var statType: StatType = StatType.COUNT
private lateinit var user: Query.UserProfile
private lateinit var activity: ProfileActivity
private var loadedFirstTime = false
override fun onCreateView(
inflater: LayoutInflater,
@@ -49,10 +52,11 @@ class StatsFragment :
binding.statisticList.adapter = adapter
binding.statisticList.setHasFixedSize(true)
binding.statisticList.isNestedScrollingEnabled = false
binding.statisticList.isNestedScrollingEnabled = true
binding.statisticList.layoutManager = LinearLayoutManager(requireContext())
binding.statisticProgressBar.visibility = View.VISIBLE
binding.compare.visibility = if (user.id == Anilist.userid) View.GONE else View.VISIBLE
binding.filterContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> { topMargin = statusBarHeight }
binding.sourceType.setAdapter(
ArrayAdapter(
@@ -98,29 +102,32 @@ class StatsFragment :
}
binding.filterContainer.visibility = View.GONE
activity.lifecycleScope.launch {
stats.clear()
stats.add(Anilist.query.getUserStatistics(user.id)?.data?.user)
withContext(Dispatchers.Main) {
binding.filterContainer.visibility = View.VISIBLE
binding.sourceType.setOnItemClickListener { _, _, i, _ ->
type = MediaType.entries.toTypedArray()[i]
loadStats(type == MediaType.ANIME)
}
binding.sourceFilter.setOnItemClickListener { _, _, i, _ ->
statType = StatType.entries.toTypedArray()[i]
loadStats(type == MediaType.ANIME)
}
loadStats(type == MediaType.ANIME)
binding.statisticProgressBar.visibility = View.GONE
}
}
}
override fun onResume() {
super.onResume()
if (this::binding.isInitialized) {
binding.root.requestLayout()
if (!loadedFirstTime) {
activity.lifecycleScope.launch {
stats.clear()
stats.add(Anilist.query.getUserStatistics(user.id)?.data?.user)
withContext(Dispatchers.Main) {
binding.filterContainer.visibility = View.VISIBLE
binding.sourceType.setOnItemClickListener { _, _, i, _ ->
type = MediaType.entries.toTypedArray()[i]
loadStats(type == MediaType.ANIME)
}
binding.sourceFilter.setOnItemClickListener { _, _, i, _ ->
statType = StatType.entries.toTypedArray()[i]
loadStats(type == MediaType.ANIME)
}
loadStats(type == MediaType.ANIME)
binding.statisticProgressBar.visibility = View.GONE
}
}
loadedFirstTime = true
}
}
loadStats(type == MediaType.ANIME)
}

View File

@@ -33,15 +33,15 @@ class ActivityItem(
override fun bind(viewBinding: ItemActivityBinding, position: Int) {
binding = viewBinding
binding.activityUserName.text = activity.user?.name
binding.activityUserAvatar.loadImage(activity.user?.avatar?.medium)
binding.activityUserName.text = activity.user?.name ?: activity.messenger?.name
binding.activityUserAvatar.loadImage(activity.user?.avatar?.medium ?: activity.messenger?.avatar?.medium)
binding.activityTime.text = ActivityItemBuilder.getDateTime(activity.createdAt)
val likeColor = ContextCompat.getColor(binding.root.context, R.color.yt_red)
val notLikeColor = ContextCompat.getColor(binding.root.context, R.color.bg_opp)
binding.activityLike.setColorFilter(if (activity.isLiked == true) likeColor else notLikeColor)
binding.commentRepliesContainer.visibility =
if (activity.replyCount > 0) View.VISIBLE else View.GONE
binding.activityLikeCount.text = activity.likeCount.toString()
binding.activityLikeCount.text = (activity.likeCount?:0).toString()
binding.activityLike.setOnClickListener {
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
@@ -55,7 +55,7 @@ class ActivityItem(
} else {
activity.likeCount = activity.likeCount?.plus(1)
}
binding.activityLikeCount.text = activity.likeCount.toString()
binding.activityLikeCount.text = (activity.likeCount?:0).toString()
activity.isLiked = !activity.isLiked!!
binding.activityLike.setColorFilter(if (activity.isLiked == true) likeColor else notLikeColor)
@@ -99,6 +99,15 @@ class ActivityItem(
markwon.setMarkdown(binding.activityContent, activity.text ?: "")
}
}
"MessageActivity" -> {
binding.activityBannerContainer.visibility = View.GONE
binding.activityContent.visibility = View.VISIBLE
if (!(context as android.app.Activity).isDestroyed) {
val markwon = buildMarkwon(context, false)
markwon.setMarkdown(binding.activityContent, activity.message ?: "")
}
}
}
}

View File

@@ -28,6 +28,9 @@ class FeedFragment : Fragment() {
private var activityList: List<Activity> = emptyList()
private lateinit var activity: androidx.activity.ComponentActivity
private var page: Int = 1
private var loadedFirstTime = false
private var userId: Int? = null
private var global: Boolean = false
override fun onCreateView(
inflater: LayoutInflater,
@@ -38,7 +41,6 @@ class FeedFragment : Fragment() {
return binding.root
}
@SuppressLint("ClickableViewAccessibility")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
activity = requireActivity()
@@ -46,55 +48,55 @@ class FeedFragment : Fragment() {
binding.listRecyclerView.layoutManager =
LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
binding.listProgressBar.visibility = ViewGroup.VISIBLE
var userId: Int? = arguments?.getInt("userId", -1)
userId = arguments?.getInt("userId", -1)
if (userId == -1) userId = null
val global = arguments?.getBoolean("global", false) ?: false
activity.lifecycleScope.launch(Dispatchers.IO) {
val res = Anilist.query.getFeed(userId, global)
withContext(Dispatchers.Main) {
res?.data?.page?.activities?.let { activities ->
activityList = activities
adapter.update(activityList.map { ActivityItem(it) { _, _ -> } })
}
binding.listProgressBar.visibility = ViewGroup.GONE
val scrollView = if (activity is ProfileActivity) {
(activity as ProfileActivity).binding.profileScrollView
} else {
binding.listRecyclerView
}
binding.listRecyclerView.setOnTouchListener { _, event ->
if (event?.action == MotionEvent.ACTION_UP) {
if (adapter.itemCount % AnilistQueries.ITEMS_PER_PAGE != 0) {
snackString("No more activities")
} else if (!scrollView.canScrollVertically(1) && !binding.feedRefresh.isVisible
&& binding.listRecyclerView.adapter!!.itemCount != 0 &&
(binding.listRecyclerView.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() == (binding.listRecyclerView.adapter!!.itemCount - 1)
) {
page++
binding.feedRefresh.visibility = ViewGroup.VISIBLE
activity.lifecycleScope.launch(Dispatchers.IO) {
val res = Anilist.query.getFeed(userId, global, page)
withContext(Dispatchers.Main) {
res?.data?.page?.activities?.let { activities ->
activityList += activities
adapter.addAll(activities.map { ActivityItem(it) { _, _ -> } })
}
binding.feedRefresh.visibility = ViewGroup.GONE
}
}
}
}
false
}
}
}
global = arguments?.getBoolean("global", false) ?: false
}
@SuppressLint("ClickableViewAccessibility")
override fun onResume() {
super.onResume()
if (this::binding.isInitialized) {
binding.root.requestLayout()
if (!loadedFirstTime) {
activity.lifecycleScope.launch(Dispatchers.IO) {
val res = Anilist.query.getFeed(userId, global)
withContext(Dispatchers.Main) {
res?.data?.page?.activities?.let { activities ->
activityList = activities
adapter.update(activityList.map { ActivityItem(it) { _, _ -> } })
}
binding.listProgressBar.visibility = ViewGroup.GONE
val scrollView = binding.listRecyclerView
binding.listRecyclerView.setOnTouchListener { _, event ->
if (event?.action == MotionEvent.ACTION_UP) {
if (adapter.itemCount % AnilistQueries.ITEMS_PER_PAGE != 0 && !global) {
snackString("No more activities")
} else if (!scrollView.canScrollVertically(1) && !binding.feedRefresh.isVisible
&& binding.listRecyclerView.adapter!!.itemCount != 0 &&
(binding.listRecyclerView.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() == (binding.listRecyclerView.adapter!!.itemCount - 1)
) {
page++
binding.feedRefresh.visibility = ViewGroup.VISIBLE
activity.lifecycleScope.launch(Dispatchers.IO) {
val res = Anilist.query.getFeed(userId, global, page)
withContext(Dispatchers.Main) {
res?.data?.page?.activities?.let { activities ->
activityList += activities
adapter.addAll(activities.map { ActivityItem(it) { _, _ -> } })
}
binding.feedRefresh.visibility = ViewGroup.GONE
}
}
}
}
false
}
}
}
loadedFirstTime = true
}
}
}

View File

@@ -25,6 +25,12 @@ class DevelopersDialogFragment : BottomSheetDialogFragment() {
"Contributor",
"https://github.com/aayush2622"
),
Developer(
"AbandonedCart",
"https://avatars.githubusercontent.com/u/1173913?v=4",
"Contributor",
"https://github.com/AbandonedCart"
),
Developer(
"Sadwhy",
"https://avatars.githubusercontent.com/u/99601717?v=4",

View File

@@ -19,17 +19,18 @@
android:layout_height="wrap_content" />
</LinearLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/profileScrollView"
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/profileAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="72dp"
android:scrollbars="none">
android:translationZ="5dp">
<LinearLayout
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:layout_height="wrap_content"
android:fitsSystemWindows="false"
app:contentScrim="?android:colorBackground"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<FrameLayout
android:id="@+id/profileTopContainer"
@@ -129,15 +130,24 @@
</LinearLayout>
</FrameLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/profileViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="SpeakableTextPresentCheck" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</LinearLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.core.widget.NestedScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_marginBottom="72dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/profileViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:nestedScrollingEnabled="true"
tools:ignore="SpeakableTextPresentCheck" />
</LinearLayout>
<nl.joery.animatedbottombar.AnimatedBottomBar

View File

@@ -21,65 +21,64 @@
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.core.widget.NestedScrollView
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
android:layout_height="wrap_content"
android:gravity="end"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<LinearLayout
<ImageView
android:id="@+id/commentFilter"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginEnd="12dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/sort_by"
app:srcCompat="@drawable/ic_round_filter_alt_24"
app:tint="?attr/colorOnBackground" />
<ImageView
android:id="@+id/commentSort"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginEnd="12dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/sort_by"
app:srcCompat="@drawable/ic_round_sort_24"
app:tint="?attr/colorOnBackground" />
</LinearLayout>
<ProgressBar
android:id="@+id/commentsProgressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginTop="64dp" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/commentsList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:nestedScrollingEnabled="true"
android:visibility="gone"
tools:listitem="@layout/item_comments"
tools:visibility="visible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/commentFilter"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginEnd="12dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/sort_by"
app:srcCompat="@drawable/ic_round_filter_alt_24"
app:tint="?attr/colorOnBackground" />
<ImageView
android:id="@+id/commentSort"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginEnd="12dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/sort_by"
app:srcCompat="@drawable/ic_round_sort_24"
app:tint="?attr/colorOnBackground" />
</LinearLayout>
<ProgressBar
android:id="@+id/commentsProgressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginTop="64dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/commentsList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="false"
android:visibility="gone"
tools:listitem="@layout/item_comments"
tools:visibility="visible" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<ProgressBar
android:id="@+id/commentBottomRefresh"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="32dp"
android:visibility="gone" />
</FrameLayout>
</LinearLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
@@ -133,8 +132,8 @@
android:id="@+id/commentInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="?android:colorBackground"
android:orientation="horizontal"
android:paddingTop="8dp"
android:paddingBottom="8dp">
@@ -172,18 +171,18 @@
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:background="@drawable/ic_label_off_24"
android:layout_marginEnd="8dp"
android:background="@drawable/ic_label_off_24"
android:visibility="gone"
tools:visibility="visible"
tools:ignore="ContentDescription" />
tools:ignore="ContentDescription"
tools:visibility="visible" />
<ImageButton
android:id="@+id/commentSend"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginEnd="12dp"
android:layout_gravity="center"
android:layout_marginEnd="12dp"
android:background="@drawable/ic_round_send_24"
android:visibility="gone"
tools:ignore="ContentDescription"

View File

@@ -1,9 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:nestedScrollingEnabled="true"
android:orientation="vertical">
<LinearLayout
@@ -144,8 +149,8 @@
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:fontFamily="@font/poppins_bold"
android:text="@string/stats"
android:padding="8dp"
android:text="@string/stats"
android:textSize="18sp"
tools:ignore="HardcodedText" />
@@ -344,9 +349,9 @@
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:fontFamily="@font/poppins_bold"
android:text="@string/about_me"
android:padding="8dp"
android:textSize="18sp"/>
android:text="@string/about_me"
android:textSize="18sp" />
<WebView
android:id="@+id/profileUserBio"
@@ -356,6 +361,7 @@
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:ellipsize="end"
android:nestedScrollingEnabled="true"
android:padding="16dp"
android:textAlignment="textStart"
tools:text="@string/slogan" />
@@ -464,8 +470,8 @@
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:fontFamily="@font/poppins_bold"
android:text="@string/fav_character"
android:padding="8dp"
android:text="@string/fav_character"
android:textSize="18sp" />
<ani.dantotsu.FadingEdgeRecyclerView
@@ -497,8 +503,8 @@
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:fontFamily="@font/poppins_bold"
android:text="@string/fav_staff"
android:padding="8dp"
android:text="@string/fav_staff"
android:textSize="18sp" />
<ani.dantotsu.FadingEdgeRecyclerView
@@ -515,4 +521,5 @@
tools:listitem="@layout/item_media_compact"
tools:orientation="horizontal" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View File

@@ -14,7 +14,9 @@
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="vertical"
android:padding="16dp">
android:paddingBottom="16dp"
android:paddingStart="16dp"
android:paddingEnd="16dp">
<LinearLayout
android:layout_width="match_parent"
@@ -123,5 +125,6 @@
android:id="@+id/statisticList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="true"
tools:listitem="@layout/item_chart" />
</LinearLayout>

View File

@@ -1,6 +1,7 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="Theme.Base" parent="Theme.Material3.DayNight">
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">?android:colorBackground</item>
<item name="android:windowTranslucentStatus">false</item>