feat: activity view
This commit is contained in:
parent
55ad8dccad
commit
856deb7755
16 changed files with 945 additions and 6 deletions
|
@ -139,6 +139,9 @@
|
|||
<activity
|
||||
android:name=".settings.SettingsAboutActivity"
|
||||
android:parentActivityName=".MainActivity" />
|
||||
<activity
|
||||
android:name=".home.StatusActivity"
|
||||
android:parentActivityName=".MainActivity" />
|
||||
<activity
|
||||
android:name=".settings.SettingsAccountActivity"
|
||||
android:parentActivityName=".MainActivity" />
|
||||
|
|
|
@ -1637,7 +1637,13 @@ Page(page:$page,perPage:50) {
|
|||
force = true
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getStatus(
|
||||
): FeedResponse? {
|
||||
return executeQuery<FeedResponse>(
|
||||
"""{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<Media> {
|
||||
val res = executeQuery<Query.MediaListCollection>(
|
||||
"""{MediaListCollection(userId:$id,type:ANIME){lists{name entries{media{id,isFavourite,title{userPreferred,romaji}coverImage{medium}nextAiringEpisode{timeUntilAiring}}}}}}""",
|
||||
|
|
|
@ -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<ArrayList<User>> =
|
||||
MutableLiveData<ArrayList<User>>(null)
|
||||
|
||||
fun getUserStatus(): LiveData<ArrayList<User>> = 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()
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -69,7 +69,7 @@ data class User(
|
|||
// The user's previously used names.
|
||||
// @SerialName("previousNames") var previousNames: List<UserPreviousName>?,
|
||||
|
||||
)
|
||||
): java.io.Serializable
|
||||
|
||||
@Serializable
|
||||
data class UserOptions(
|
||||
|
|
|
@ -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<Boolean> =
|
||||
PrefManager.getVal(PrefName.HomeLayoutShow)
|
||||
runBlocking {
|
||||
model.initUserStatus()
|
||||
model.initHomePage()
|
||||
}
|
||||
(array.indices).forEach { i ->
|
||||
|
|
73
app/src/main/java/ani/dantotsu/home/StatusActivity.kt
Normal file
73
app/src/main/java/ani/dantotsu/home/StatusActivity.kt
Normal file
|
@ -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<Activity>
|
||||
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<ViewGroup.MarginLayoutParams> {
|
||||
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()
|
||||
}
|
||||
|
||||
}
|
53
app/src/main/java/ani/dantotsu/home/UserStatus.kt
Normal file
53
app/src/main/java/ani/dantotsu/home/UserStatus.kt
Normal file
|
@ -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<User>) :
|
||||
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
|
||||
}
|
413
app/src/main/java/ani/dantotsu/home/status/Stories.kt
Normal file
413
app/src/main/java/ani/dantotsu/home/status/Stories.kt
Normal file
|
@ -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<StoryItem>
|
||||
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<StoryItem>, activity: FragmentActivity) {
|
||||
this.storiesList = storiesList
|
||||
this.activ = activity
|
||||
addLoadingViews(storiesList)
|
||||
}
|
||||
|
||||
private fun addLoadingViews(storiesList: List<StoryItem>) {
|
||||
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<ProgressBar>("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<ProgressBar>("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<ProgressBar>(tag).id
|
||||
}
|
||||
|
||||
private fun secondsToMillis(seconds: String): Long {
|
||||
return (seconds.toLongOrNull() ?: 3).times(1000)
|
||||
}
|
||||
|
||||
private fun resetProgressBar(storyIndex: Int) {
|
||||
val currentProgressBar = findViewWithTag<ProgressBar>("story${storyIndex}")
|
||||
val lastProgressBar = findViewWithTag<ProgressBar>("story${storyIndex - 1}")
|
||||
currentProgressBar?.let {
|
||||
it.progress = 0
|
||||
}
|
||||
lastProgressBar?.let {
|
||||
it.progress = 0
|
||||
}
|
||||
}
|
||||
|
||||
private fun completeProgressBar(storyIndex: Int) {
|
||||
val lastProgressBar = findViewWithTag<ProgressBar>("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<User>()
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
20
app/src/main/java/ani/dantotsu/home/status/data/StoryItem.kt
Normal file
20
app/src/main/java/ani/dantotsu/home/status/data/StoryItem.kt
Normal file
|
@ -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<User>? = null,
|
||||
var isLiked : Boolean = false
|
||||
)
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package ani.dantotsu.home.status.listener
|
||||
|
||||
interface StoriesCallback {
|
||||
|
||||
fun onStoriesEnd()
|
||||
}
|
|
@ -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<Activity> = mutableListOf(),
|
||||
) : java.io.Serializable {
|
||||
companion object {
|
||||
private const val serialVersionUID: Long = 1
|
||||
|
|
13
app/src/main/res/layout/activity_status.xml
Normal file
13
app/src/main/res/layout/activity_status.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<ani.dantotsu.home.status.Stories
|
||||
android:id="@+id/stories"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -309,7 +309,50 @@
|
|||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/homeUserStatusContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/homeUserStatus"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:padding="8dp"
|
||||
android:text="@string/social"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="100dp">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/homeUserStatusProgressBar"
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="90dp" />
|
||||
|
||||
<ani.dantotsu.FadingEdgeRecyclerView
|
||||
android:id="@+id/homeUserStatusRecyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:requiresFadingEdge="horizontal"
|
||||
tools:itemCount="4"
|
||||
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_user_status"
|
||||
tools:orientation="horizontal" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/homeContinueWatchingContainer"
|
||||
android:layout_width="match_parent"
|
||||
|
|
210
app/src/main/res/layout/fragment_status.xml
Normal file
210
app/src/main/res/layout/fragment_status.xml
Normal file
|
@ -0,0 +1,210 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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"
|
||||
tools:ignore="ContentDescription">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/contentImageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/leftTouchPanel"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintWidth_percent="0.5" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/rightTouchPanel"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintWidth_percent="0.5" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
tools:ignore="MissingConstraints">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/progressBarContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginTop="10dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/statusUserContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/statusUserAvatarContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:layout_margin="12dp"
|
||||
android:backgroundTint="@color/transparent"
|
||||
app:cardCornerRadius="64dp"
|
||||
app:strokeColor="@color/transparent">
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/statusUserAvatar"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="center"
|
||||
app:srcCompat="@drawable/ic_round_add_circle_24"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck"
|
||||
tools:tint="@color/bg_black_50" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/statusUserName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:ellipsize="end"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:paddingTop="1dp"
|
||||
android:paddingBottom="0dp"
|
||||
android:singleLine="true"
|
||||
android:text="Username"
|
||||
android:textSize="16sp"
|
||||
tools:ignore="HardcodedText,RtlSymmetry" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:alpha="0.6"
|
||||
android:fontFamily="@font/poppins_semi_bold"
|
||||
android:text="•"
|
||||
android:textSize="18sp"
|
||||
tools:ignore="HardcodedText,RtlSymmetry" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/statusUserTime"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_weight="1"
|
||||
android:alpha="0.6"
|
||||
android:fontFamily="@font/poppins_semi_bold"
|
||||
android:text="Time"
|
||||
android:textSize="14sp"
|
||||
tools:ignore="HardcodedText,RtlSymmetry" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:orientation="vertical"
|
||||
tools:ignore="UseCompoundDrawables">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/activityLike"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_round_favorite_24"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/activityLikeCount"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:fontFamily="@font/poppins_semi_bold"
|
||||
android:textSize="15sp"
|
||||
tools:text="12" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/itemCompactCard"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:translationZ="8dp"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="4dp"
|
||||
android:layout_marginBottom="124dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/coverImage"
|
||||
android:layout_width="172dp"
|
||||
android:layout_height="256dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:transitionName="mediaCover"
|
||||
app:shapeAppearanceOverlay="@style/roundedImageView"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck"
|
||||
tools:srcCompat="@tools:sample/backgrounds/scenic" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:layout_marginTop="124dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:backgroundTint="@color/transparent"
|
||||
app:cardCornerRadius="124dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/itemCompactCard"
|
||||
app:strokeColor="@color/transparent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/infoText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorSurfaceVariant"
|
||||
android:ellipsize="marquee"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:fontFamily="@font/poppins_semi_bold"
|
||||
android:lineSpacingExtra="-8sp"
|
||||
android:maxLines="3"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/bg_opp"
|
||||
android:textSize="24dp"
|
||||
android:transitionName="mediaTitle"
|
||||
tools:ignore="SpUsage"
|
||||
tools:text="@string/slogan" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/androidStoriesLoadingView"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
37
app/src/main/res/layout/item_user_status.xml
Normal file
37
app/src/main/res/layout/item_user_status.xml
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout 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="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/profileUserAvatarContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:backgroundTint="@color/bg_white"
|
||||
app:cardCornerRadius="124dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/profileUserAvatar"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
tools:ignore="ContentDescription,ImageContrastCheck"
|
||||
tools:tint="@color/transparent" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/profileUserName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal|center_vertical"
|
||||
android:ellipsize="end"
|
||||
android:text="@string/username"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
Loading…
Add table
Add a link
Reference in a new issue