PixelDroid-App-Android/app/src/main/java/com/h/pixeldroid/fragments/feeds/NotificationsFragment.kt

218 lines
8.7 KiB
Kotlin
Raw Normal View History

package com.h.pixeldroid.fragments.feeds
import android.content.Context
import android.content.Intent
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
2020-04-03 09:11:57 +02:00
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.ListPreloader
import com.bumptech.glide.RequestBuilder
import com.bumptech.glide.integration.recyclerview.RecyclerViewPreloader
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.util.ViewPreloadSizeProvider
import com.h.pixeldroid.PostActivity
import com.h.pixeldroid.ProfileActivity
import com.h.pixeldroid.R
import com.h.pixeldroid.objects.Account
import com.h.pixeldroid.objects.Notification
import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.utils.HtmlUtils.Companion.parseHTMLText
import kotlinx.android.synthetic.main.fragment_notifications.view.*
2020-04-03 09:11:57 +02:00
import retrofit2.Call
/**
* A fragment representing a list of Items.
*/
class NotificationsFragment : FeedFragment<Notification, NotificationsFragment.NotificationsRecyclerViewAdapter.ViewHolder>() {
lateinit var profilePicRequest: RequestBuilder<Drawable>
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = super.onCreateView(inflater, container, savedInstanceState)
2020-04-02 22:16:03 +02:00
//RequestBuilder that is re-used for every image
profilePicRequest = Glide.with(this)
.asDrawable().apply(RequestOptions().circleCrop())
.placeholder(R.drawable.ic_default_user)
adapter = NotificationsRecyclerViewAdapter()
list.adapter = adapter
2020-04-02 22:16:03 +02:00
//Make Glide be aware of the recyclerview and pre-load images
val sizeProvider: ListPreloader.PreloadSizeProvider<Notification> = ViewPreloadSizeProvider()
val preloader: RecyclerViewPreloader<Notification> = RecyclerViewPreloader(
Glide.with(this), adapter as NotificationsFragment.NotificationsRecyclerViewAdapter, sizeProvider, 4
)
list.addOnScrollListener(preloader)
return view
}
Commenting & seeing comments on a post ( issues: #37 #77 ) (#87) Comment and like buttons added + a few UI tweaks * WIP posts * WIP posts * trying to add images * trying to add images * Got posts working and linked them to the profile * added tests for Post * layout changes * moved a test file * refactoring * refactoring * removed wrong annotation in unit test * removed an import that was breaking the build * removed tests that broke from merge, will override with master * added UI test for the post activity * WIP posts * WIP posts * trying to add images * trying to add images * Got posts working and linked them to the profile * layout changes * refactoring * refactoring * WIP posts * WIP posts * trying to add images * trying to add images * Got posts working and linked them to the profile * added tests for Post * layout changes * moved a test file * refactoring * refactoring * removed wrong annotation in unit test * removed an import that was breaking the build * removed tests that broke from merge, will override with master * fixed merging errors * trying my best to merge * removed drawable definition in activity_post.xml * Started converting Post to a fragment * got a working feed * WI * removed non-valid test * rebase on other branch * moved the feed to the home page * Add tests * delete test for now * Adapt test to changes (no more profile from drawer) * Add unit test for api * Add test for profile, refactor to allow testing, add exception to security policy to allow tests * Adapt test to new situation * Fix typo due to change * refactor somewhat * added a feed test * WIP posts * trying to add images * WIP posts * trying to add images * Got posts working and linked them to the profile * added tests for Post * layout changes * moved a test file * refactoring * refactoring * WIP posts * WIP posts * trying to add images * trying to add images * Got posts working and linked them to the profile * added tests for Post * layout changes * moved a test file * refactoring * refactoring * removed wrong annotation in unit test * removed an import that was breaking the build * removed tests that broke from merge, will override with master * added UI test for the post activity * WIP posts * trying to add images * WIP posts * trying to add images * Got posts working and linked them to the profile * added tests for Post * layout changes * moved a test file * refactoring * refactoring * WIP posts * WIP posts * trying to add images * trying to add images * Got posts working and linked them to the profile * added tests for Post * layout changes * moved a test file * refactoring * refactoring * removed wrong annotation in unit test * removed an import that was breaking the build * removed tests that broke from merge, will override with master * added UI test for the post activity * fixed merging errors * trying my best to merge * removed drawable definition in activity_post.xml * Started converting Post to a fragment * got a working feed * WI * removed non-valid test * WIP posts * WIP posts * trying to add images * trying to add images * Got posts working and linked them to the profile * added tests for Post * layout changes * moved a test file * WIP posts * WIP posts * trying to add images * trying to add images * Got posts working and linked them to the profile * added tests for Post * layout changes * moved a test file * refactoring * refactoring * refactoring * refactoring * removed wrong annotation in unit test * WIP posts * WIP posts * WIP posts * WIP posts * trying to add images * trying to add images * trying to add images * trying to add images * Got posts working and linked them to the profile * Got posts working and linked them to the profile * added tests for Post * layout changes * layout changes * moved a test file * refactoring * refactoring * refactoring * refactoring * removed wrong annotation in unit test * removed an import that was breaking the build * removed an import that was breaking the build * removed tests that broke from merge, will override with master * removed tests that broke from merge, will override with master * added UI test for the post activity * fixed merging errors * trying my best to merge * removed drawable definition in activity_post.xml * Started converting Post to a fragment * got a working feed * WI * removed non-valid test * rebase on other branch * moved the feed to the home page * added a feed test * added a working feed test * fixed broken test * merged with master * added a max height for images and made profile pictures round * Added a default image for the post * created a PostActivity to look a single posts * fixed buggy postActivity * Complete overhall of the feed UI * removed test that didn't please Travis * removed legacy test * changed feedAdapter init location (outside of network callback) * changed the feed from public timeline to home timeline * Refactored myProfile page * Converted profile picture to round image * restored feed test * I can like a post, but unlike is still a WIP * Liking kind of works now and added tests * fixed an error, now we can unlike as well * fixed travis constraint error * Display user's posts on profile page * moved test to Mock server tests * fixed test * last resort debugging * Changed fixed size of profile posts * last resort debugging * last resort debugging * last resort debugging * made post_activity profilepic round * Total refactor of profile posts * still have a weird bug with the comments: input is always null (WIP) * still trying to fix coments * removed annoying side margins in the home feed * trying to fix comments * fixed null comment * converted all posts back to statuses and got rid of post * Refactored recycler view * Merged with my-profile * Posts displayed on profile page * Added links to profile activity where needed * fixed comment posting * finished implementing comments, but api is buggy so none are visible * removed useless space in profile page * fixed ci config bug * trying to trigger ci hook (github was down last time) * updated tests with master tests * added tests for the comments * added tests for the comments * added first() matcher to fix comment test * still trying to fix comment tests' null progress bar * getting rid of that null progress bar * added comment test * fixed merge error * added like button test * added more post tests * took pr coments into account * added back an old test * added mockServer response for comment test and fixed comment null pointer bug * changed notification UI to better separate notifications * added mockserver response for likes and corrected like toggling error * added a test for posting comments * fixed typo in test * a gift for code climate * refactored stuff * fixed broken imports * comment refactored as xml Co-authored-by: Matthieu <61561059+Wv5twkFEKh54vo4tta9yu7dHa3@users.noreply.github.com> Co-authored-by: mjaillot <marie.jaillot@epfl.ch>
2020-04-11 12:55:06 +02:00
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
content = makeContent()
content.observe(viewLifecycleOwner,
Observer { c ->
adapter.submitList(c)
//after a refresh is done we need to stop the pull to refresh spinner
swipeRefreshLayout.isRefreshing = false
})
}
2020-04-03 09:11:57 +02:00
private fun makeContent(): LiveData<PagedList<Notification>> {
fun makeInitialCall(requestedLoadSize: Int): Call<List<Notification>> {
return pixelfedAPI
.notifications("Bearer $accessToken", limit="$requestedLoadSize")
2020-04-03 09:11:57 +02:00
}
fun makeAfterCall(requestedLoadSize: Int, key: String): Call<List<Notification>> {
return pixelfedAPI
.notifications("Bearer $accessToken", max_id=key, limit="$requestedLoadSize")
}
2020-04-03 09:11:57 +02:00
val config: PagedList.Config = PagedList.Config.Builder().setPageSize(10).build()
val dataSource = FeedDataSource(::makeInitialCall, ::makeAfterCall)
factory = FeedDataSourceFactory(dataSource)
2020-04-03 09:11:57 +02:00
return LivePagedListBuilder(factory, config).build()
}
/**
* [RecyclerView.Adapter] that can display a [Notification]
*/
inner class NotificationsRecyclerViewAdapter: FeedsRecyclerViewAdapter<Notification, NotificationsRecyclerViewAdapter.ViewHolder>(),
ListPreloader.PreloadModelProvider<Notification> {
private val mOnClickListener: View.OnClickListener
init {
mOnClickListener = View.OnClickListener { v ->
val notification = v.tag as Notification
openActivity(notification)
}
}
private fun openPostFromNotifcation(notification: Notification) : Intent {
val intent = Intent(context, PostActivity::class.java)
intent.putExtra(Status.POST_TAG, notification.status)
return intent
}
private fun openActivity(notification: Notification){
val intent: Intent
when (notification.type){
Notification.NotificationType.mention, Notification.NotificationType.favourite-> {
intent = openPostFromNotifcation(notification)
}
Notification.NotificationType.reblog-> {
intent = openPostFromNotifcation(notification)
}
Notification.NotificationType.follow -> {
intent = Intent(context, ProfileActivity::class.java)
intent.putExtra(Account.ACCOUNT_TAG, notification.account)
}
}
context.startActivity(intent)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.fragment_notifications, parent, false)
context = view.context
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val notification = getItem(position) ?: return
profilePicRequest.load(notification.account.avatar_static).into(holder.avatar)
val previewUrl = notification.status?.media_attachments?.getOrNull(0)?.preview_url
if(!previewUrl.isNullOrBlank()){
Glide.with(holder.mView).load(previewUrl)
.placeholder(R.drawable.ic_picture_fallback).into(holder.photoThumbnail)
} else{
holder.photoThumbnail.visibility = View.GONE
}
setNotificationType(notification.type, notification.account.username, holder.notificationType)
//Convert HTML to clickable text
holder.postDescription.text =
parseHTMLText(
notification.status?.content ?: "",
notification.status?.mentions,
pixelfedAPI,
context,
"Bearer $accessToken"
)
with(holder.mView) {
tag = notification
setOnClickListener(mOnClickListener)
}
}
private fun setNotificationType(type: Notification.NotificationType, username: String,
textView: TextView
){
val context = textView.context
val (format: String, drawable: Drawable?) = when(type) {
Notification.NotificationType.follow -> {
setNotificationTypeTextView(context, R.string.followed_notification, R.drawable.ic_follow)
}
Notification.NotificationType.mention -> {
setNotificationTypeTextView(context, R.string.mention_notification, R.drawable.ic_apenstaart)
}
Notification.NotificationType.reblog -> {
setNotificationTypeTextView(context, R.string.shared_notification, R.drawable.ic_reblog_blue)
}
Notification.NotificationType.favourite -> {
setNotificationTypeTextView(context, R.string.liked_notification, R.drawable.ic_like_full)
}
}
textView.text = format.format(username)
textView.setCompoundDrawablesWithIntrinsicBounds(
drawable,null,null,null
)
}
private fun setNotificationTypeTextView(context: Context, format: Int, drawable: Int): Pair<String, Drawable?> {
return Pair(context.getString(format), context.getDrawable(drawable))
}
inner class ViewHolder(val mView: View) : RecyclerView.ViewHolder(mView) {
val notificationType: TextView = mView.notification_type
val postDescription: TextView = mView.notification_post_description
val avatar: ImageView = mView.notification_avatar
val photoThumbnail: ImageView = mView.notification_photo_thumbnail
}
override fun getPreloadItems(position: Int): MutableList<Notification> {
val notification = getItem(position) ?: return mutableListOf()
return mutableListOf(notification)
}
override fun getPreloadRequestBuilder(item: Notification): RequestBuilder<*>? {
return profilePicRequest.load(item.account.avatar_static)
}
}
}