diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 203d7307..85d3b9c6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -139,6 +139,9 @@
+
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 b39aeebc..5c4e1b1c 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
@@ -1637,7 +1637,13 @@ Page(page:$page,perPage:50) {
force = true
)
}
-
+ suspend fun getStatus(
+ ): FeedResponse? {
+ return executeQuery(
+ """{Page(page:1,perPage:50){activities(isFollowing: true, type:MEDIA_LIST,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{extraLarge 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 likeCount 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}}}}}}""",
+ force = true
+ )
+ }
suspend fun getUpcomingAnime(id: String): List {
val res = executeQuery(
"""{MediaListCollection(userId:$id,type:ANIME){lists{name entries{media{id,isFavourite,title{userPreferred,romaji}coverImage{medium}nextAiringEpisode{timeUntilAiring}}}}}}""",
diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistViewModel.kt b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistViewModel.kt
index 11d5cda1..9874ce50 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistViewModel.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistViewModel.kt
@@ -11,6 +11,8 @@ import ani.dantotsu.connections.discord.Discord
import ani.dantotsu.connections.mal.MAL
import ani.dantotsu.media.Media
import ani.dantotsu.others.AppUpdater
+import ani.dantotsu.profile.User
+import ani.dantotsu.profile.activity.ActivityItemBuilder
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
@@ -100,6 +102,35 @@ class AnilistHomeViewModel : ViewModel() {
res["plannedManga"]?.let { mangaPlanned.postValue(it) }
res["recommendations"]?.let { recommendation.postValue(it) }
}
+ private val userStatus: MutableLiveData> =
+ MutableLiveData>(null)
+
+ fun getUserStatus(): LiveData> = userStatus
+
+ suspend fun initUserStatus() {
+ Anilist.query.getStatus()?.data?.page?.activities?.let { activities ->
+ val groupedActivities = activities
+ .filterNot { it.userId == Anilist.userid }
+ .sortedByDescending { ActivityItemBuilder.getDateTime(it.createdAt) }
+ .groupBy { it.userId }
+ val userList = groupedActivities.mapNotNull { (_, activities) ->
+ val user = activities.firstOrNull()?.user
+ user?.let {
+ User(
+ it.id,
+ it.name ?: "",
+ it.avatar?.medium,
+ it.bannerImage,
+ activity = activities
+ )
+ }
+ }.toMutableList()
+ userList.sortByDescending { user ->
+ user.activity.maxByOrNull { it.createdAt }?.createdAt
+ }
+ userStatus.postValue(ArrayList(userList))
+ }
+ }
suspend fun loadMain(context: FragmentActivity) {
Anilist.getSavedToken()
diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/api/Media.kt b/app/src/main/java/ani/dantotsu/connections/anilist/api/Media.kt
index da2a989e..471b130d 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/api/Media.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/api/Media.kt
@@ -174,7 +174,7 @@ data class Media(
// Notes for site moderators
@SerialName("modNotes") var modNotes: String?,
-)
+) : java.io.Serializable
@Serializable
data class MediaTitle(
@@ -189,7 +189,7 @@ data class MediaTitle(
// The currently authenticated users preferred title language. Default romaji for non-authenticated
@SerialName("userPreferred") var userPreferred: String,
-)
+): java.io.Serializable
@Serializable
enum class MediaType {
diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/api/User.kt b/app/src/main/java/ani/dantotsu/connections/anilist/api/User.kt
index f6668fc4..9117c144 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/api/User.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/api/User.kt
@@ -69,7 +69,7 @@ data class User(
// The user's previously used names.
// @SerialName("previousNames") var previousNames: List?,
-)
+): java.io.Serializable
@Serializable
data class UserOptions(
diff --git a/app/src/main/java/ani/dantotsu/home/HomeFragment.kt b/app/src/main/java/ani/dantotsu/home/HomeFragment.kt
index 20a5d163..a496d80e 100644
--- a/app/src/main/java/ani/dantotsu/home/HomeFragment.kt
+++ b/app/src/main/java/ani/dantotsu/home/HomeFragment.kt
@@ -314,10 +314,37 @@ class HomeFragment : Fragment() {
binding.homeRecommendedEmpty,
binding.homeRecommended
)
+ binding.homeUserStatusContainer.visibility = View.VISIBLE
+ binding.homeUserStatusProgressBar.visibility = View.VISIBLE
+ binding.homeUserStatusRecyclerView.visibility = View.GONE
+ binding.homeUserStatus.visibility = View.INVISIBLE
+ model.getUserStatus().observe(viewLifecycleOwner) {
+ binding.homeUserStatusRecyclerView.visibility = View.GONE
+ if (it != null) {
+ if (it.isNotEmpty()) {
+ binding.homeUserStatusRecyclerView.adapter = UserStatus(it)
+ binding.homeUserStatusRecyclerView.layoutManager = LinearLayoutManager(
+ requireContext(),
+ LinearLayoutManager.HORIZONTAL,
+ false
+ )
+ binding.homeUserStatusRecyclerView.visibility = View.VISIBLE
+ binding.homeUserStatusRecyclerView.layoutAnimation =
+ LayoutAnimationController(setSlideIn(), 0.25f)
+
+ } else {
+ binding.homeUserStatusContainer.visibility = View.GONE
+ }
+ binding.homeUserStatus.visibility = View.VISIBLE
+ binding.homeUserStatus.startAnimation(setSlideUp())
+ binding.homeUserStatusProgressBar.visibility = View.GONE
+ }
+ }
binding.homeUserAvatarContainer.startAnimation(setSlideUp())
- model.empty.observe(viewLifecycleOwner) {
+ model.empty.observe(viewLifecycleOwner)
+ {
binding.homeDantotsuContainer.visibility = if (it == true) View.VISIBLE else View.GONE
(binding.homeDantotsuIcon.drawable as Animatable).start()
binding.homeDantotsuContainer.startAnimation(setSlideUp())
@@ -348,7 +375,8 @@ class HomeFragment : Fragment() {
)
val live = Refresh.activity.getOrPut(1) { MutableLiveData(false) }
- live.observe(viewLifecycleOwner) {
+ live.observe(viewLifecycleOwner)
+ {
if (it) {
scope.launch {
withContext(Dispatchers.IO) {
@@ -362,6 +390,7 @@ class HomeFragment : Fragment() {
val homeLayoutShow: List =
PrefManager.getVal(PrefName.HomeLayoutShow)
runBlocking {
+ model.initUserStatus()
model.initHomePage()
}
(array.indices).forEach { i ->
diff --git a/app/src/main/java/ani/dantotsu/home/StatusActivity.kt b/app/src/main/java/ani/dantotsu/home/StatusActivity.kt
new file mode 100644
index 00000000..cee888f2
--- /dev/null
+++ b/app/src/main/java/ani/dantotsu/home/StatusActivity.kt
@@ -0,0 +1,73 @@
+package ani.dantotsu.home
+
+import android.os.Bundle
+import android.view.ViewGroup
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.updateLayoutParams
+import ani.dantotsu.connections.anilist.api.Activity
+import ani.dantotsu.databinding.ActivityStatusBinding
+import ani.dantotsu.initActivity
+import ani.dantotsu.others.getSerialized
+import ani.dantotsu.themes.ThemeManager
+import ani.dantotsu.home.status.data.StoryItem
+import ani.dantotsu.home.status.listener.StoriesCallback
+import ani.dantotsu.navBarHeight
+import ani.dantotsu.profile.activity.ActivityItemBuilder
+import ani.dantotsu.statusBarHeight
+
+class StatusActivity : AppCompatActivity(), StoriesCallback {
+ private lateinit var activity: List
+ private lateinit var binding: ActivityStatusBinding
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ ThemeManager(this).applyTheme()
+ initActivity(this)
+ binding = ActivityStatusBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ activity = intent.getSerialized("activity")!!
+ binding.root.updateLayoutParams {
+ topMargin = statusBarHeight
+ bottomMargin = navBarHeight
+ }
+ val storiesList = activity.map { StoryItem(
+ id = it.userId,
+ activityId = it.id,
+ mediaId = it.media?.id,
+ userName = it.user?.name,
+ userAvatar = it.user?.avatar?.large,
+ time = ActivityItemBuilder.getDateTime(it.createdAt),
+ info = "${it.user!!.name} ${it.status} ${
+ it.progress
+ ?: it.media?.title?.userPreferred
+ }",
+ cover = it.media?.coverImage?.extraLarge,
+ banner = it.media?.bannerImage ?: it.media?.coverImage?.extraLarge,
+ likes = it.likeCount ?: 0,
+ likedBy = it.likes,
+ isLiked = it.isLiked == true
+ ) }
+ binding.stories.setStoriesList(storiesList, this)
+ }
+
+ override fun onPause() {
+ super.onPause()
+ binding.stories.pause()
+ }
+ override fun onResume() {
+ super.onResume()
+ binding.stories.resume()
+ }
+
+ override fun onWindowFocusChanged(hasFocus: Boolean) {
+ super.onWindowFocusChanged(hasFocus)
+ if (hasFocus) {
+ binding.stories.resume()
+ } else {
+ binding.stories.pause()
+ }
+ }
+ override fun onStoriesEnd() {
+ finish()
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/home/UserStatus.kt b/app/src/main/java/ani/dantotsu/home/UserStatus.kt
new file mode 100644
index 00000000..61351bde
--- /dev/null
+++ b/app/src/main/java/ani/dantotsu/home/UserStatus.kt
@@ -0,0 +1,53 @@
+package ani.dantotsu.home
+
+import android.content.Intent
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.core.content.ContextCompat
+import androidx.recyclerview.widget.RecyclerView
+import ani.dantotsu.databinding.ItemUserStatusBinding
+import ani.dantotsu.loadImage
+import ani.dantotsu.profile.User
+import ani.dantotsu.setAnimation
+import java.io.Serializable
+
+class UserStatus(private val user: ArrayList) :
+ RecyclerView.Adapter< UserStatus.UsersViewHolder>() {
+
+ inner class UsersViewHolder(val binding: ItemUserStatusBinding) :
+ RecyclerView.ViewHolder(binding.root) {
+ init {
+ itemView.setOnClickListener {
+ ContextCompat.startActivity(
+ itemView.context,
+ Intent(
+ itemView.context,
+ StatusActivity::class.java
+ ).putExtra("activity", user[bindingAdapterPosition].activity as Serializable),
+ null
+ )
+ }
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UsersViewHolder {
+ return UsersViewHolder(
+ ItemUserStatusBinding.inflate(
+ LayoutInflater.from(parent.context),
+ parent,
+ false
+ )
+ )
+ }
+
+ override fun onBindViewHolder(holder: UsersViewHolder, position: Int) {
+ val b = holder.binding
+ setAnimation(b.root.context, b.root)
+ val user = user[position]
+ b.profileUserAvatar.loadImage(user.pfp)
+ b.profileUserName.text = user.name
+
+ }
+
+ override fun getItemCount(): Int = user.size
+}
diff --git a/app/src/main/java/ani/dantotsu/home/status/Stories.kt b/app/src/main/java/ani/dantotsu/home/status/Stories.kt
new file mode 100644
index 00000000..bb6c5095
--- /dev/null
+++ b/app/src/main/java/ani/dantotsu/home/status/Stories.kt
@@ -0,0 +1,413 @@
+package ani.dantotsu.home.status
+
+import android.animation.Animator
+import android.animation.ObjectAnimator
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.graphics.Rect
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.MotionEvent
+import android.view.View
+import android.view.animation.LinearInterpolator
+import android.widget.FrameLayout
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.ProgressBar
+import android.widget.TextView
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.FragmentActivity
+import androidx.webkit.internal.ApiFeature.T
+import ani.dantotsu.R
+import ani.dantotsu.blurImage
+import ani.dantotsu.connections.anilist.Anilist
+import ani.dantotsu.home.status.data.StoryItem
+import ani.dantotsu.home.status.listener.StoriesCallback
+import ani.dantotsu.loadImage
+import ani.dantotsu.media.MediaDetailsActivity
+import ani.dantotsu.profile.ProfileActivity
+import ani.dantotsu.profile.User
+import ani.dantotsu.profile.UsersDialogFragment
+import ani.dantotsu.snackString
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.util.Calendar
+
+
+class Stories @JvmOverloads
+constructor(
+ context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
+) : ConstraintLayout(context, attrs, defStyleAttr), View.OnTouchListener {
+
+ private lateinit var storiesList: List
+ private lateinit var activ: FragmentActivity
+ private lateinit var loadingViewLayout: ConstraintLayout
+ private lateinit var leftTouchPanel: FrameLayout
+ private lateinit var rightTouchPanel: FrameLayout
+ private lateinit var statusUserContainer: LinearLayout
+ private lateinit var imageContentView: ImageView
+ private lateinit var loadingView: ProgressBar
+ private lateinit var activityLikeCount: TextView
+ private lateinit var activityLike: ImageView
+ private lateinit var userName: TextView
+ private lateinit var userAvatar: ImageView
+ private lateinit var time: TextView
+ private lateinit var infoText: TextView
+ private lateinit var coverImage: ImageView
+ private var storyDuration: String = "4"
+ private lateinit var animation: ObjectAnimator
+ private var storyIndex: Int = 1
+ private var userClicked: Boolean = false
+ private lateinit var storiesListener: StoriesCallback
+ private var oldStoryItem = StoryItem()
+
+ init {
+ initLayout()
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ private fun initLayout() {
+ val inflater: LayoutInflater = LayoutInflater.from(context)
+ val view = inflater.inflate(R.layout.fragment_status, this, false)
+ addView(view)
+
+ if (context is StoriesCallback)
+ storiesListener = context as StoriesCallback
+
+
+ loadingViewLayout = findViewById(R.id.progressBarContainer)
+ leftTouchPanel = findViewById(R.id.leftTouchPanel)
+ rightTouchPanel = findViewById(R.id.rightTouchPanel)
+ imageContentView = findViewById(R.id.contentImageView)
+ statusUserContainer = findViewById(R.id.statusUserContainer)
+ loadingView = findViewById(R.id.androidStoriesLoadingView)
+ coverImage = findViewById(R.id.coverImage)
+ userName = findViewById(R.id.statusUserName)
+ userAvatar = findViewById(R.id.statusUserAvatar)
+ time = findViewById(R.id.statusUserTime)
+ infoText = findViewById(R.id.infoText)
+ activityLikeCount = findViewById(R.id.activityLikeCount)
+ activityLike = findViewById(R.id.activityLike)
+
+ leftTouchPanel.setOnTouchListener(this)
+ rightTouchPanel.setOnTouchListener(this)
+
+ }
+
+
+ fun setStoriesList(storiesList: List, activity: FragmentActivity) {
+ this.storiesList = storiesList
+ this.activ = activity
+ addLoadingViews(storiesList)
+ }
+
+ private fun addLoadingViews(storiesList: List) {
+ var idCounter = 1
+ for (story in storiesList) {
+ val progressBar = ProgressBar(context, null, android.R.attr.progressBarStyleHorizontal)
+ progressBar.visibility = View.VISIBLE
+ progressBar.id = idCounter
+ progressBar.tag = "story${idCounter++}"
+ val params = LayoutParams(0, LayoutParams.WRAP_CONTENT)
+ params.marginEnd = 5
+ params.marginStart = 5
+ loadingViewLayout.addView(progressBar, params)
+ }
+
+ val constraintSet = ConstraintSet()
+ constraintSet.clone(loadingViewLayout)
+
+ var counter = storiesList.size
+ for (story in storiesList) {
+ val progressBar = findViewWithTag("story${counter}")
+ if (progressBar != null) {
+ if (storiesList.size > 1) {
+ when (counter) {
+ storiesList.size -> {
+ constraintSet.connect(
+ getId("story${counter}"),
+ ConstraintSet.END,
+ LayoutParams.PARENT_ID,
+ ConstraintSet.END
+ )
+ constraintSet.connect(
+ getId("story${counter}"),
+ ConstraintSet.TOP,
+ LayoutParams.PARENT_ID,
+ ConstraintSet.TOP
+ )
+ constraintSet.connect(
+ getId("story${counter}"),
+ ConstraintSet.START,
+ getId("story${counter - 1}"),
+ ConstraintSet.END
+ )
+ }
+
+ 1 -> {
+ constraintSet.connect(
+ getId("story${counter}"),
+ ConstraintSet.TOP,
+ LayoutParams.PARENT_ID,
+ ConstraintSet.TOP
+ )
+ constraintSet.connect(
+ getId("story${counter}"),
+ ConstraintSet.START,
+ LayoutParams.PARENT_ID,
+ ConstraintSet.START
+ )
+ constraintSet.connect(
+ getId("story${counter}"),
+ ConstraintSet.END,
+ getId("story${counter + 1}"),
+ ConstraintSet.START
+ )
+ }
+
+ else -> {
+ constraintSet.connect(
+ getId("story${counter}"),
+ ConstraintSet.TOP,
+ LayoutParams.PARENT_ID,
+ ConstraintSet.TOP
+ )
+ constraintSet.connect(
+ getId("story${counter}"),
+ ConstraintSet.START,
+ getId("story${counter - 1}"),
+ ConstraintSet.END
+ )
+ constraintSet.connect(
+ getId("story${counter}"),
+ ConstraintSet.END,
+ getId("story${counter + 1}"),
+ ConstraintSet.START
+ )
+ }
+ }
+ } else {
+ constraintSet.connect(
+ getId("story${counter}"),
+ ConstraintSet.END,
+ LayoutParams.PARENT_ID,
+ ConstraintSet.END
+ )
+ constraintSet.connect(
+ getId("story${counter}"),
+ ConstraintSet.TOP,
+ LayoutParams.PARENT_ID,
+ ConstraintSet.TOP
+ )
+ constraintSet.connect(
+ getId("story${counter}"),
+ ConstraintSet.START,
+ LayoutParams.PARENT_ID,
+ ConstraintSet.START
+ )
+ }
+ }
+ counter--
+ }
+ constraintSet.applyTo(loadingViewLayout)
+ startShowContent()
+ }
+
+ private fun startShowContent() {
+ showStory()
+ }
+
+ private fun showStory() {
+ val progressBar = findViewWithTag("story${storyIndex}")
+ loadingView.visibility = View.VISIBLE
+ animation = ObjectAnimator.ofInt(progressBar, "progress", 0, 100)
+ animation.duration = secondsToMillis(storyDuration)
+ animation.interpolator = LinearInterpolator()
+ animation.addListener(object : Animator.AnimatorListener {
+ override fun onAnimationStart(animator: Animator) {
+ }
+
+ override fun onAnimationEnd(animator: Animator) {
+ if (storyIndex - 1 <= storiesList.size) {
+ if (userClicked) {
+ userClicked = false
+ } else {
+ if (storyIndex < storiesList.size) {
+ storyIndex += 1
+ showStory()
+ } else {
+ // on stories end
+ loadingView.visibility = View.GONE
+ onStoriesCompleted()
+ }
+ }
+ } else {
+ // on stories end
+ loadingView.visibility = View.GONE
+ onStoriesCompleted()
+ }
+ }
+
+ override fun onAnimationCancel(animator: Animator) {
+ progressBar.progress = 100
+ }
+
+ override fun onAnimationRepeat(animator: Animator) {}
+ })
+ loadStory(storiesList[storyIndex - 1])
+ }
+
+ private fun getId(tag: String): Int {
+ return findViewWithTag(tag).id
+ }
+
+ private fun secondsToMillis(seconds: String): Long {
+ return (seconds.toLongOrNull() ?: 3).times(1000)
+ }
+
+ private fun resetProgressBar(storyIndex: Int) {
+ val currentProgressBar = findViewWithTag("story${storyIndex}")
+ val lastProgressBar = findViewWithTag("story${storyIndex - 1}")
+ currentProgressBar?.let {
+ it.progress = 0
+ }
+ lastProgressBar?.let {
+ it.progress = 0
+ }
+ }
+
+ private fun completeProgressBar(storyIndex: Int) {
+ val lastProgressBar = findViewWithTag("story${storyIndex}")
+ lastProgressBar?.let {
+ it.progress = 100
+ }
+ }
+
+
+ private var startClickTime = 0L
+ override fun onTouch(view: View?, event: MotionEvent?): Boolean {
+ val maxClickDuration = 200
+ when (event?.action) {
+ MotionEvent.ACTION_DOWN -> {
+ startClickTime = Calendar.getInstance().timeInMillis
+ animation.pause()
+ }
+
+ MotionEvent.ACTION_UP -> {
+ val clickDuration = Calendar.getInstance().timeInMillis - startClickTime
+ if (clickDuration < maxClickDuration) {
+ //click occurred
+ view?.let {
+ if (it.id == R.id.leftTouchPanel) {
+ leftPanelTouch()
+ } else if (it.id == R.id.rightTouchPanel) {
+ rightPanelTouch()
+ }
+ }
+ } else {
+ //hold click occurred
+ animation.resume()
+ }
+ }
+ }
+ return true
+ }
+
+ private fun rightPanelTouch() {
+ if (storyIndex == storiesList.size) {
+ completeProgressBar(storyIndex)
+ onStoriesCompleted()
+ return
+ }
+ userClicked = true
+ animation.end()
+ if (storyIndex < storiesList.size)
+ storyIndex += 1
+ showStory()
+ }
+
+ private fun leftPanelTouch() {
+ userClicked = true
+ animation.end()
+ resetProgressBar(storyIndex)
+ if (storyIndex > 1)
+ storyIndex -= 1
+ showStory()
+ }
+
+ private fun onStoriesCompleted() {
+ if (::storiesListener.isInitialized)
+ storiesListener.onStoriesEnd()
+ }
+ fun pause() {
+ animation.pause()
+ }
+ fun resume() {
+ animation.resume()
+ }
+ private fun loadStory(story: StoryItem) {
+ loadingView.visibility = View.GONE
+ animation.start()
+ blurImage(imageContentView, story.banner)
+ userAvatar.loadImage(story.userAvatar)
+ coverImage.loadImage(story.cover)
+ userName.text = story.userName
+ time.text = story.time
+ infoText.text = story.info
+ statusUserContainer.setOnClickListener {
+ ContextCompat.startActivity(context, Intent(context, ProfileActivity::class.java).putExtra("userId", story.id), null)
+ }
+ coverImage.setOnClickListener{
+ ContextCompat.startActivity(context, Intent(context, MediaDetailsActivity::class.java).putExtra("mediaId", story.mediaId), null)
+ }
+ val likeColor = ContextCompat.getColor(context, R.color.yt_red)
+ val notLikeColor = ContextCompat.getColor(context, R.color.bg_opp)
+ activityLikeCount.text = story.likes.toString()
+ activityLike.setColorFilter(if (story.isLiked) likeColor else notLikeColor)
+ activityLike.setOnClickListener {
+ val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
+ scope.launch {
+ val res = Anilist.query.toggleLike(story.activityId!!, "ACTIVITY")
+ withContext(Dispatchers.Main) {
+ if (res != null) {
+
+ if (story.isLiked) {
+ story.likes = story.likes.minus(1)
+ } else {
+ story.likes = story.likes.plus(1)
+ }
+ activityLikeCount.text = (story.likes ?: 0).toString()
+ story.isLiked = !story.isLiked
+ activityLike.setColorFilter(if (story.isLiked) likeColor else notLikeColor)
+
+ } else {
+ snackString("Failed to like activity")
+ }
+ }
+ }
+ }
+ val userList = arrayListOf()
+ story.likedBy?.forEach { i ->
+ userList.add(User(i.id, i.name.toString(), i.avatar?.medium, i.bannerImage))
+ }
+
+ activityLike.setOnLongClickListener {
+ UsersDialogFragment().apply {
+ userList(userList)
+ show(activ.supportFragmentManager, "dialog")
+ }
+ true
+ }
+ oldStoryItem = story
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/home/status/data/StoryItem.kt b/app/src/main/java/ani/dantotsu/home/status/data/StoryItem.kt
new file mode 100644
index 00000000..04fd93a1
--- /dev/null
+++ b/app/src/main/java/ani/dantotsu/home/status/data/StoryItem.kt
@@ -0,0 +1,20 @@
+package ani.dantotsu.home.status.data
+
+import ani.dantotsu.connections.anilist.api.User
+
+data class StoryItem(
+ val id : Int? = null,
+ val activityId : Int? = null,
+ val mediaId: Int? = null,
+ val userName: String? = null,
+ val userAvatar: String? = null,
+ val time: String? = null,
+ val info: String? = null,
+ val cover: String? = null,
+ val banner: String? = null,
+ var likes : Int = 0,
+ val likedBy: List? = null,
+ var isLiked : Boolean = false
+)
+
+
diff --git a/app/src/main/java/ani/dantotsu/home/status/listener/StoriesCallback.kt b/app/src/main/java/ani/dantotsu/home/status/listener/StoriesCallback.kt
new file mode 100644
index 00000000..0ba0251b
--- /dev/null
+++ b/app/src/main/java/ani/dantotsu/home/status/listener/StoriesCallback.kt
@@ -0,0 +1,6 @@
+package ani.dantotsu.home.status.listener
+
+interface StoriesCallback {
+
+ fun onStoriesEnd()
+}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/profile/User.kt b/app/src/main/java/ani/dantotsu/profile/User.kt
index a16c3329..3b231060 100644
--- a/app/src/main/java/ani/dantotsu/profile/User.kt
+++ b/app/src/main/java/ani/dantotsu/profile/User.kt
@@ -1,5 +1,6 @@
package ani.dantotsu.profile
+import ani.dantotsu.connections.anilist.api.Activity
import kotlinx.serialization.Serializable
@Serializable
@@ -14,6 +15,7 @@ data class User(
val progress: Int? = null,
val totalEpisodes: Int? = null,
val nextAiringEpisode: Int? = null,
+ val activity: List = mutableListOf(),
) : java.io.Serializable {
companion object {
private const val serialVersionUID: Long = 1
diff --git a/app/src/main/res/layout/activity_status.xml b/app/src/main/res/layout/activity_status.xml
new file mode 100644
index 00000000..e26c5708
--- /dev/null
+++ b/app/src/main/res/layout/activity_status.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index 0204115b..a23d4581 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -309,7 +309,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_user_status.xml b/app/src/main/res/layout/item_user_status.xml
new file mode 100644
index 00000000..d1fd06aa
--- /dev/null
+++ b/app/src/main/res/layout/item_user_status.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file