diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8590ff4d..12e7eccc 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -115,7 +115,7 @@
android:windowSoftInputMode="adjustResize|stateHidden"
android:parentActivityName=".MainActivity" />
diff --git a/app/src/main/java/ani/dantotsu/Functions.kt b/app/src/main/java/ani/dantotsu/Functions.kt
index 683263a7..67af749c 100644
--- a/app/src/main/java/ani/dantotsu/Functions.kt
+++ b/app/src/main/java/ani/dantotsu/Functions.kt
@@ -28,6 +28,7 @@ import android.telephony.TelephonyManager
import android.text.InputFilter
import android.text.Spanned
import android.util.AttributeSet
+import android.util.Log
import android.util.TypedValue
import android.view.*
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
@@ -129,7 +130,8 @@ var loadIsMAL = false
fun logger(e: Any?, print: Boolean = true) {
if (print)
- println(e)
+ //println(e)
+ Log.d("Logger", e.toString())
}
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 91244488..e1b52dba 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
@@ -8,10 +8,10 @@ import ani.dantotsu.connections.anilist.Anilist.authorRoles
import ani.dantotsu.connections.anilist.Anilist.executeQuery
import ani.dantotsu.connections.anilist.api.FeedResponse
import ani.dantotsu.connections.anilist.api.FuzzyDate
-import ani.dantotsu.connections.anilist.api.Notification
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.ToggleLike
import ani.dantotsu.currContext
import ani.dantotsu.isOnline
import ani.dantotsu.logError
@@ -1265,10 +1265,15 @@ Page(page:$page,perPage:50) {
}
suspend fun toggleFollow(id: Int): Query.ToggleFollow? {
- val response = executeQuery(
+ return executeQuery(
"""mutation{ToggleFollow(userId:$id){id, isFollowing, isFollower}}"""
)
- return response
+ }
+
+ suspend fun toggleLike(id: Int, type: String): ToggleLike? {
+ return executeQuery(
+ """mutation Like{ToggleLikeV2(id:$id,type:$type){__typename}}"""
+ )
}
suspend fun getUserProfile(id: Int): Query.UserProfileResponse? {
@@ -1342,8 +1347,8 @@ Page(page:$page,perPage:50) {
return default
}
- suspend fun getNotifications(id: Int): NotificationResponse? {
- val res = executeQuery("""{User(id:$id){unreadNotificationCount}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)
+ suspend fun getNotifications(id: Int, page: Int = 1): NotificationResponse? {
+ val res = executeQuery("""{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
}
@@ -1354,7 +1359,11 @@ Page(page:$page,perPage:50) {
val filter = if (userId != null) "userId:$userId,"
else if (global) "isFollowing:false,"
else "isFollowing:true,"
- val res = executeQuery("""{Page(page:$page,perPage:25){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("""{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
}
+
+ companion object {
+ const val ITEMS_PER_PAGE = 25
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/api/Feed.kt b/app/src/main/java/ani/dantotsu/connections/anilist/api/Feed.kt
index ca31d6f9..b8cc5cc9 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/api/Feed.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/api/Feed.kt
@@ -7,19 +7,19 @@ import kotlinx.serialization.Serializable
data class FeedResponse(
@SerialName("data")
val data: Data
-) {
+) : java.io.Serializable {
@Serializable
data class Data(
@SerialName("Page")
val page: ActivityPage
- )
+ ) : java.io.Serializable
}
@Serializable
data class ActivityPage(
@SerialName("activities")
val activities: List
-)
+) : java.io.Serializable
@Serializable
data class Activity(
@@ -52,9 +52,9 @@ data class Activity(
@SerialName("isSubscribed")
val isSubscribed: Boolean,
@SerialName("likeCount")
- val likeCount: Int?,
+ var likeCount: Int?,
@SerialName("isLiked")
- val isLiked: Boolean?,
+ var isLiked: Boolean?,
@SerialName("isPinned")
val isPinned: Boolean?,
@SerialName("isPrivate")
@@ -69,7 +69,7 @@ data class Activity(
val replies: List?,
@SerialName("likes")
val likes: List?,
-)
+) : java.io.Serializable
@Serializable
data class Reply(
@@ -89,4 +89,22 @@ data class Reply(
val user: User,
@SerialName("likes")
val likes: List?,
-)
\ No newline at end of file
+) : java.io.Serializable
+
+@Serializable
+data class ToggleLike(
+ @SerialName("data")
+ val data: Data
+) : java.io.Serializable {
+ @Serializable
+ data class Data(
+ @SerialName("ToggleLikeV2")
+ val toggleLike: LikeData
+ ) : java.io.Serializable
+}
+
+@Serializable
+data class LikeData(
+ @SerialName("__typename")
+ val typename: String
+) : java.io.Serializable
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt b/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt
index fa30f6a3..daa984bc 100644
--- a/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt
+++ b/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt
@@ -14,6 +14,7 @@ import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.api.User
import ani.dantotsu.databinding.ActivityFollowBinding
import ani.dantotsu.initActivity
+import ani.dantotsu.navBarHeight
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.statusBarHeight
@@ -36,6 +37,7 @@ class FollowActivity : AppCompatActivity(){
initActivity(this)
binding = ActivityFollowBinding.inflate(layoutInflater)
binding.listToolbar.updateLayoutParams { topMargin = statusBarHeight }
+ binding.listFrameLayout.updateLayoutParams { bottomMargin = navBarHeight }
setContentView(binding.root)
val layoutType = PrefManager.getVal(PrefName.FollowerLayout)
selected = getSelected(layoutType)
diff --git a/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt b/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt
index b180a833..a7f8216d 100644
--- a/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt
+++ b/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt
@@ -22,7 +22,7 @@ import ani.dantotsu.initActivity
import ani.dantotsu.loadImage
import ani.dantotsu.navBarHeight
import ani.dantotsu.others.ImageViewDialog
-import ani.dantotsu.profile.activity.ActivityActivity
+import ani.dantotsu.profile.activity.FeedFragment
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
@@ -36,8 +36,8 @@ import nl.joery.animatedbottombar.AnimatedBottomBar
class ProfileActivity : AppCompatActivity() {
- private lateinit var binding: ActivityProfileBinding
- private var selected: Int = 0
+ lateinit var binding: ActivityProfileBinding
+ private var selected: Int = 1
private lateinit var navBar: AnimatedBottomBar
@SuppressLint("SetTextI18n")
@@ -49,8 +49,10 @@ class ProfileActivity : AppCompatActivity() {
setContentView(binding.root)
navBar = binding.profileNavBar
navBar.updateLayoutParams { bottomMargin = navBarHeight }
+ val feedTab = navBar.createTab(R.drawable.ic_round_filter_24, "Feed")
val profileTab = navBar.createTab(R.drawable.ic_round_person_24, "Profile")
val statsTab = navBar.createTab(R.drawable.ic_stats_24, "Stats")
+ navBar.addTab(feedTab)
navBar.addTab(profileTab)
navBar.addTab(statsTab)
navBar.visibility = View.GONE
@@ -70,6 +72,7 @@ class ProfileActivity : AppCompatActivity() {
}
binding.profileViewPager.adapter =
ViewPagerAdapter(supportFragmentManager, lifecycle, user)
+ binding.profileViewPager.setCurrentItem(selected, false)
navBar.visibility = View.VISIBLE
navBar.selectTabAt(selected)
navBar.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener {
@@ -106,15 +109,6 @@ class ProfileActivity : AppCompatActivity() {
}
binding.profileProgressBar.visibility = View.GONE
binding.profileTopContainer.visibility = View.VISIBLE
- binding.profileActivityButton.setOnClickListener {
- ContextCompat.startActivity(
- this@ProfileActivity,
- Intent(this@ProfileActivity, ActivityActivity::class.java)
- .putExtra("userId", user.id)
- .putExtra("username", user.name),
- null
- )
- }
binding.profileMenuButton.setOnClickListener {
val popup = PopupMenu(this@ProfileActivity, binding.profileMenuButton)
popup.menuInflater.inflate(R.menu.menu_profile, popup.menu)
@@ -161,7 +155,6 @@ class ProfileActivity : AppCompatActivity() {
binding.profileBannerImage.updateLayoutParams { height += statusBarHeight }
binding.profileBannerGradient.updateLayoutParams { height += statusBarHeight }
binding.profileMenuButton.updateLayoutParams { topMargin += statusBarHeight }
- binding.profileActivityButton.updateLayoutParams { topMargin += statusBarHeight }
binding.profileBannerImage.setOnLongClickListener {
ImageViewDialog.newInstance(
this@ProfileActivity,
@@ -188,10 +181,11 @@ class ProfileActivity : AppCompatActivity() {
) :
FragmentStateAdapter(fragmentManager, lifecycle) {
- override fun getItemCount(): Int = 2
+ override fun getItemCount(): Int = 3
override fun createFragment(position: Int): Fragment = when (position) {
- 0 -> ProfileFragment.newInstance(user)
- 1 -> StatsFragment.newInstance(user)
+ 0 -> FeedFragment.newInstance(user.id, false)
+ 1 -> ProfileFragment.newInstance(user)
+ 2 -> StatsFragment.newInstance(user)
else -> ProfileFragment.newInstance(user)
}
}
diff --git a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt
index afb62d82..340c415f 100644
--- a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt
+++ b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt
@@ -32,7 +32,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-class ProfileFragment() : Fragment() {
+class ProfileFragment : Fragment() {
lateinit var binding: FragmentProfileBinding
private lateinit var activity: ProfileActivity
private lateinit var user: Query.UserProfile
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/ActivityActivity.kt b/app/src/main/java/ani/dantotsu/profile/activity/ActivityActivity.kt
deleted file mode 100644
index a9482820..00000000
--- a/app/src/main/java/ani/dantotsu/profile/activity/ActivityActivity.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-package ani.dantotsu.profile.activity
-
-import android.annotation.SuppressLint
-import android.os.Bundle
-import android.view.ViewGroup
-import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.updateLayoutParams
-import androidx.lifecycle.lifecycleScope
-import androidx.recyclerview.widget.LinearLayoutManager
-import ani.dantotsu.connections.anilist.Anilist
-import ani.dantotsu.connections.anilist.api.Activity
-import ani.dantotsu.databinding.ActivityFollowBinding
-import ani.dantotsu.initActivity
-import ani.dantotsu.statusBarHeight
-import ani.dantotsu.themes.ThemeManager
-import com.xwray.groupie.GroupieAdapter
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-
-class ActivityActivity : AppCompatActivity() {
- private lateinit var binding: ActivityFollowBinding
- private var adapter: GroupieAdapter = GroupieAdapter()
- private var activityList: List = emptyList()
-
- @SuppressLint("SetTextI18n")
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- ThemeManager(this).applyTheme()
- initActivity(this)
- binding = ActivityFollowBinding.inflate(layoutInflater)
- setContentView(binding.root)
-
- binding.listTitle.text = "Activity"
- binding.listToolbar.updateLayoutParams { topMargin = statusBarHeight }
- binding.listRecyclerView.adapter = adapter
- binding.listRecyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
- binding.followerGrid.visibility = ViewGroup.GONE
- binding.followerList.visibility = ViewGroup.GONE
- binding.listBack.setOnClickListener {
- onBackPressed()
- }
- binding.listProgressBar.visibility = ViewGroup.VISIBLE
- var userId: Int? = intent.getIntExtra("userId", -1)
- if (userId == -1) userId = null
- val global = intent.getBooleanExtra("global", false)
-
- 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
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt b/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt
index 5744c6c6..c69d5950 100644
--- a/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt
+++ b/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt
@@ -6,21 +6,29 @@ import android.view.View
import androidx.core.content.ContextCompat
import ani.dantotsu.R
import ani.dantotsu.buildMarkwon
+import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.api.Activity
import ani.dantotsu.databinding.ItemActivityBinding
import ani.dantotsu.loadImage
+import ani.dantotsu.snackString
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.request.RequestOptions
import com.xwray.groupie.viewbinding.BindableItem
import jp.wasabeef.glide.transformations.BlurTransformation
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
class ActivityItem(
private val activity: Activity,
- val clickCallback: (Int) -> Unit
-): BindableItem() {
+ val clickCallback: (Int, type: String) -> Unit
+) : BindableItem() {
private lateinit var binding: ItemActivityBinding
+
@SuppressLint("SetTextI18n")
override fun bind(viewBinding: ItemActivityBinding, position: Int) {
binding = viewBinding
@@ -28,24 +36,48 @@ class ActivityItem(
binding.activityUserName.text = activity.user?.name
binding.activityUserAvatar.loadImage(activity.user?.avatar?.medium)
binding.activityTime.text = ActivityItemBuilder.getDateTime(activity.createdAt)
- val color = if (activity.isLiked == true)
- ContextCompat.getColor(binding.root.context, R.color.yt_red)
- else
- ContextCompat.getColor(binding.root.context, R.color.bg_opp)
- binding.activityFavorite.setColorFilter(color)
- binding.commentRepliesContainer.visibility = if (activity.replyCount > 0) View.VISIBLE else View.GONE
+ 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.activityLike.setOnClickListener {
+ val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
+ scope.launch {
+ val res = Anilist.query.toggleLike(activity.id, "ACTIVITY")
+ withContext(Dispatchers.Main) {
+ if (res != null) {
+
+ if (activity.isLiked == true) {
+ activity.likeCount = activity.likeCount?.minus(1)
+ } else {
+ activity.likeCount = activity.likeCount?.plus(1)
+ }
+ binding.activityLikeCount.text = activity.likeCount.toString()
+ activity.isLiked = !activity.isLiked!!
+ binding.activityLike.setColorFilter(if (activity.isLiked == true) likeColor else notLikeColor)
+
+ } else {
+ snackString("Failed to like activity")
+ }
+ }
+ }
+ }
val context = binding.root.context
when (activity.typename) {
- "ListActivity" ->{
+ "ListActivity" -> {
binding.activityContent.visibility = View.GONE
binding.activityBannerContainer.visibility = View.VISIBLE
binding.activityMediaName.text = activity.media?.title?.userPreferred
- binding.activityText.text = "${activity.user!!.name} ${activity.status} ${activity.media!!.title!!.userPreferred}"
- binding.activityCover.loadImage(activity.media.coverImage?.medium)
- val banner = activity.media.bannerImage
+ binding.activityText.text =
+ """${activity.user!!.name} ${activity.status} ${activity.progress ?: ""}"""
+ binding.activityCover.loadImage(activity.media?.coverImage?.medium)
+ val banner = activity.media?.bannerImage
if (banner != null) {
if (!(context as android.app.Activity).isDestroyed) {
Glide.with(context as Context)
@@ -58,6 +90,7 @@ class ActivityItem(
binding.activityBannerImage.setImageResource(R.drawable.linear_gradient_bg)
}
}
+
"TextActivity" -> {
binding.activityBannerContainer.visibility = View.GONE
binding.activityContent.visibility = View.VISIBLE
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt b/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt
new file mode 100644
index 00000000..8513ceb2
--- /dev/null
+++ b/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt
@@ -0,0 +1,81 @@
+package ani.dantotsu.profile.activity
+
+import android.os.Bundle
+import android.view.ViewGroup
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.updateLayoutParams
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentManager
+import androidx.lifecycle.Lifecycle
+import androidx.viewpager2.adapter.FragmentStateAdapter
+import ani.dantotsu.R
+import ani.dantotsu.databinding.ActivityFeedBinding
+import ani.dantotsu.initActivity
+import ani.dantotsu.navBarHeight
+import ani.dantotsu.statusBarHeight
+import ani.dantotsu.themes.ThemeManager
+import nl.joery.animatedbottombar.AnimatedBottomBar
+
+class FeedActivity: AppCompatActivity() {
+ private lateinit var binding: ActivityFeedBinding
+ private var selected: Int = 0
+ private lateinit var navBar: AnimatedBottomBar
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ ThemeManager(this).applyTheme()
+ initActivity(this)
+ binding = ActivityFeedBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ navBar = binding.feedNavBar
+ navBar.updateLayoutParams { bottomMargin += navBarHeight }
+ val personalTab = navBar.createTab(R.drawable.ic_round_person_24, "Personal")
+ val globalTab = navBar.createTab(R.drawable.ic_globe_24, "Global")
+ navBar.addTab(personalTab)
+ navBar.addTab(globalTab)
+ binding.listTitle.text = "Activities"
+ binding.feedViewPager.updateLayoutParams {
+ bottomMargin += navBarHeight
+ topMargin += statusBarHeight
+ }
+ binding.listToolbar.updateLayoutParams { topMargin += statusBarHeight }
+ binding.feedViewPager.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle)
+ binding.feedViewPager.setCurrentItem(selected, false)
+ binding.feedViewPager.isUserInputEnabled = false
+ navBar.selectTabAt(selected)
+ navBar.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener {
+ override fun onTabSelected(
+ lastIndex: Int,
+ lastTab: AnimatedBottomBar.Tab?,
+ newIndex: Int,
+ newTab: AnimatedBottomBar.Tab
+ ) {
+ selected = newIndex
+ binding.feedViewPager.setCurrentItem(selected, true)
+ }
+ })
+ binding.listBack.setOnClickListener {
+ onBackPressed()
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ navBar.selectTabAt(selected)
+ }
+
+
+ private class ViewPagerAdapter(
+ fragmentManager: FragmentManager,
+ lifecycle: Lifecycle
+ ) : FragmentStateAdapter(fragmentManager, lifecycle) {
+ override fun getItemCount(): Int = 2
+
+ override fun createFragment(position: Int): Fragment {
+ return when (position) {
+ 0 -> FeedFragment.newInstance(null, false)
+ else -> FeedFragment.newInstance(null, true)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/FeedFragment.kt b/app/src/main/java/ani/dantotsu/profile/activity/FeedFragment.kt
new file mode 100644
index 00000000..f6751d53
--- /dev/null
+++ b/app/src/main/java/ani/dantotsu/profile/activity/FeedFragment.kt
@@ -0,0 +1,111 @@
+package ani.dantotsu.profile.activity
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.lifecycleScope
+import androidx.recyclerview.widget.LinearLayoutManager
+import ani.dantotsu.connections.anilist.Anilist
+import ani.dantotsu.connections.anilist.AnilistQueries
+import ani.dantotsu.connections.anilist.api.Activity
+import ani.dantotsu.databinding.FragmentFeedBinding
+import ani.dantotsu.logger
+import ani.dantotsu.profile.ProfileActivity
+import ani.dantotsu.snackString
+import com.xwray.groupie.GroupieAdapter
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+class FeedFragment : Fragment() {
+ private lateinit var binding: FragmentFeedBinding
+ private var adapter: GroupieAdapter = GroupieAdapter()
+ private var activityList: List = emptyList()
+ private lateinit var activity: androidx.activity.ComponentActivity
+ private var page: Int = 1
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ binding = FragmentFeedBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ activity = requireActivity()
+ binding.listRecyclerView.adapter = adapter
+ binding.listRecyclerView.layoutManager =
+ LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
+ binding.listProgressBar.visibility = ViewGroup.VISIBLE
+ var userId: Int? = 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
+ }
+ }
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ if (this::binding.isInitialized) {
+ binding.root.requestLayout()
+ }
+ }
+
+ companion object {
+ fun newInstance(userId: Int?, global: Boolean): FeedFragment {
+ val fragment = FeedFragment()
+ val args = Bundle()
+ args.putInt("userId", userId ?: -1)
+ args.putBoolean("global", global)
+ fragment.arguments = args
+ return fragment
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/NotificationActivity.kt b/app/src/main/java/ani/dantotsu/profile/activity/NotificationActivity.kt
index f699b274..881c9975 100644
--- a/app/src/main/java/ani/dantotsu/profile/activity/NotificationActivity.kt
+++ b/app/src/main/java/ani/dantotsu/profile/activity/NotificationActivity.kt
@@ -3,18 +3,23 @@ package ani.dantotsu.profile.activity
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
+import android.view.MotionEvent
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import ani.dantotsu.connections.anilist.Anilist
+import ani.dantotsu.connections.anilist.AnilistQueries
import ani.dantotsu.connections.anilist.api.Notification
import ani.dantotsu.databinding.ActivityFollowBinding
import ani.dantotsu.initActivity
import ani.dantotsu.media.MediaDetailsActivity
+import ani.dantotsu.navBarHeight
import ani.dantotsu.profile.ProfileActivity
+import ani.dantotsu.snackString
import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager
import com.xwray.groupie.GroupieAdapter
@@ -26,8 +31,9 @@ class NotificationActivity : AppCompatActivity() {
private lateinit var binding: ActivityFollowBinding
private var adapter: GroupieAdapter = GroupieAdapter()
private var notificationList: List = emptyList()
+ private var page: Int = 1
- @SuppressLint("SetTextI18n")
+ @SuppressLint("SetTextI18n", "ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ThemeManager(this).applyTheme()
@@ -36,6 +42,7 @@ class NotificationActivity : AppCompatActivity() {
setContentView(binding.root)
binding.listTitle.text = "Notifications"
binding.listToolbar.updateLayoutParams { topMargin = statusBarHeight }
+ binding.listFrameLayout.updateLayoutParams { bottomMargin = navBarHeight }
binding.listRecyclerView.adapter = adapter
binding.listRecyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
binding.followerGrid.visibility = ViewGroup.GONE
@@ -52,6 +59,30 @@ class NotificationActivity : AppCompatActivity() {
}
withContext(Dispatchers.Main){
binding.listProgressBar.visibility = ViewGroup.GONE
+ binding.listRecyclerView.setOnTouchListener { _, event ->
+ if (event?.action == MotionEvent.ACTION_UP) {
+ if (adapter.itemCount % AnilistQueries.ITEMS_PER_PAGE != 0) {
+ snackString("No more notifications")
+ } else if (!binding.listRecyclerView.canScrollVertically(1) && !binding.followRefresh.isVisible
+ && binding.listRecyclerView.adapter!!.itemCount != 0 &&
+ (binding.listRecyclerView.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() == (binding.listRecyclerView.adapter!!.itemCount - 1)
+ ) {
+ page++
+ binding.followRefresh.visibility = ViewGroup.VISIBLE
+ lifecycleScope.launch(Dispatchers.IO) {
+ val res = Anilist.query.getNotifications(Anilist.userid?:0, page)
+ withContext(Dispatchers.Main) {
+ res?.data?.page?.notifications?.let { notifications ->
+ notificationList += notifications
+ adapter.addAll(notifications.map { NotificationItem(it, ::onNotificationClick) })
+ }
+ binding.followRefresh.visibility = ViewGroup.GONE
+ }
+ }
+ }
+ }
+ false
+ }
}
}
}
diff --git a/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt b/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt
index 6638b151..b2aa43e6 100644
--- a/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt
+++ b/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt
@@ -25,6 +25,7 @@ import ani.dantotsu.incognitoNotification
import ani.dantotsu.loadImage
import ani.dantotsu.profile.activity.NotificationActivity
import ani.dantotsu.offline.OfflineFragment
+import ani.dantotsu.profile.activity.FeedActivity
import ani.dantotsu.setSafeOnClickListener
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
@@ -108,6 +109,11 @@ class SettingsDialogFragment : BottomSheetDialogFragment() {
dismiss()
}
+ binding.settingsActivity.setSafeOnClickListener {
+ startActivity(Intent(activity, FeedActivity::class.java))
+ dismiss()
+ }
+
binding.settingsNotification.setOnClickListener {
startActivity(Intent(activity, NotificationActivity::class.java))
dismiss()
diff --git a/app/src/main/res/drawable/ic_globe_24.xml b/app/src/main/res/drawable/ic_globe_24.xml
new file mode 100644
index 00000000..ff6e71b0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_globe_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_activity.xml b/app/src/main/res/layout/activity_feed.xml
similarity index 50%
rename from app/src/main/res/layout/activity_activity.xml
rename to app/src/main/res/layout/activity_feed.xml
index 584c5588..295a8a10 100644
--- a/app/src/main/res/layout/activity_activity.xml
+++ b/app/src/main/res/layout/activity_feed.xml
@@ -1,19 +1,13 @@
-
+
-
-
@@ -38,18 +32,38 @@
android:fontFamily="@font/poppins_bold"
android:gravity="center|start"
android:singleLine="true"
- android:text="Activity"
android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title"
android:textColor="?attr/colorOnBackground"
android:textSize="18sp"
- tools:ignore="HardcodedText" />
+ tools:text="Activities" />
+
-
-
\ No newline at end of file
+ android:layout_height="match_parent"
+ android:layout_marginBottom="72dp"
+ android:layout_marginTop="48dp"
+ tools:ignore="SpeakableTextPresentCheck" />
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_follow.xml b/app/src/main/res/layout/activity_follow.xml
index 59358670..9dfe9846 100644
--- a/app/src/main/res/layout/activity_follow.xml
+++ b/app/src/main/res/layout/activity_follow.xml
@@ -93,11 +93,26 @@
-
+ android:layout_height="wrap_content">
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml
index 1583039d..409e6860 100644
--- a/app/src/main/res/layout/activity_profile.xml
+++ b/app/src/main/res/layout/activity_profile.xml
@@ -20,6 +20,7 @@
-
-
-
+ android:layout_height="match_parent"
+ android:orientation="vertical">
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_activity.xml b/app/src/main/res/layout/item_activity.xml
index 361df9d2..a21d7e05 100644
--- a/app/src/main/res/layout/item_activity.xml
+++ b/app/src/main/res/layout/item_activity.xml
@@ -70,14 +70,14 @@
android:orientation="vertical">