Added handling of multiple images in a post (#111)

* Changed Post interaction icons and added click feedback

* added reblog and unreblog api implementations

* Use fancy animated buttons

* WIP reposter

* WIP reblog button

* renamed ViewHolder => PostViewHolder

* activated reblogger in feed

* added custom html parser, still need to fix clickable links

* added parsed HTML in notifications

* fixed mention click

* added tests for reblog and clickable mentions

* adapted unit tests to work with new html parser

* changed incoherent comment

* made hashtags slightly less useless

* removed unit test that were no longer valid

* removed useless test

* trying to fix tests

* fixing tests

* trying to improve coverage a little

* removed unused code to improve coverage

* changed cast to type converter

* added failure responses to help coverage

* added mock server response for reblogging

* fixed broken json

* trying to fix a broken test

* added handling of multiple images in a post

* Tweak tests

* Typo in test

* Add scrolls to make tests pass on small screens

* fixed old JSON in mockserver

* fixed linter issue

* merged with master again

* added test for albums

Co-authored-by: Matthieu <61561059+Wv5twkFEKh54vo4tta9yu7dHa3@users.noreply.github.com>
This commit is contained in:
Andrew Dobis 2020-04-23 18:49:32 +02:00 committed by GitHub
parent 8265ac2d62
commit 2339fb0967
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 209 additions and 21 deletions

View File

@ -144,6 +144,21 @@ class MockedServerTest {
onView(withId(R.id.list)).check(matches(isDisplayed()))
}
@Test
fun clickingTabOnAlbumShowsNextPhoto() {
ActivityScenario.launch(MainActivity::class.java).onActivity {
a -> run {
//Wait for the feed to load
Thread.sleep(1000)
//Pick the second photo
a.findViewById<TabLayout>(R.id.postTabs).getTabAt(1)?.select()
}
}
//Check that the tabs are shown
onView(first(withId(R.id.postTabs))).check(matches(isDisplayed()))
}
@Test
fun clickingLikeButtonWorks() {
ActivityScenario.launch(MainActivity::class.java)

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,73 @@
package com.h.pixeldroid
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.RequestBuilder
import com.h.pixeldroid.utils.ImageConverter
import kotlinx.android.synthetic.main.post_fragment.view.*
import java.io.Serializable
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val IMG_URL = "imgurl"
private const val RQST_BLDR = "rqstbldr"
/**
* A simple [Fragment] subclass.
* Use the [ImageFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class ImageFragment : Fragment() {
private lateinit var imgUrl: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
imgUrl = it.getString(IMG_URL)!!
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_image, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//Load the image into to view
val imageView : ImageView = view.findViewById(R.id.imageImageView)!!
val picRequest = Glide.with(this)
.asDrawable().fitCenter()
.placeholder(ColorDrawable(Color.GRAY))
picRequest.load(imgUrl).into(imageView)
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param imageUrl the url of the image we want to create a fragment for
* @return A new instance of fragment ImageFragment.
*/
@JvmStatic
fun newInstance(imageUrl: String) =
ImageFragment().apply {
arguments = Bundle().apply {
putString(IMG_URL, imageUrl)
}
}
}
}

View File

@ -30,7 +30,7 @@ class PostFragment : Fragment() {
.asDrawable().fitCenter()
.placeholder(ColorDrawable(Color.GRAY))
status?.setupPost(root, picRequest, root.postPicture, root.profilePic)
status?.setupPost(root, picRequest, this)
//Setup arguments needed for the onclicklisteners
val holder = PostViewHolder(root, requireContext())

View File

@ -39,7 +39,7 @@ class HomeFragment : FeedFragment<Status, PostViewHolder>() {
.asDrawable().fitCenter()
.placeholder(ColorDrawable(Color.GRAY))
adapter = HomeRecyclerViewAdapter()
adapter = HomeRecyclerViewAdapter(this)
list.adapter = adapter
@ -82,7 +82,7 @@ class HomeFragment : FeedFragment<Status, PostViewHolder>() {
/**
* [RecyclerView.Adapter] that can display a list of Statuses
*/
inner class HomeRecyclerViewAdapter
inner class HomeRecyclerViewAdapter(private val homeFragment: HomeFragment)
: FeedsRecyclerViewAdapter<Status, PostViewHolder>() {
private val api = pixelfedAPI
private val credential = "Bearer $accessToken"
@ -104,7 +104,7 @@ class HomeFragment : FeedFragment<Status, PostViewHolder>() {
holder.postPic.maxHeight = metrics.heightPixels
//Setup the post layout
post.setupPost(holder.postView, picRequest, holder.postPic, holder.profilePic)
post.setupPost(holder.postView, picRequest, homeFragment)
//Set the special HTML text
post.setDescription(holder.postView, api, credential)

View File

@ -3,18 +3,21 @@ package com.h.pixeldroid.objects
import android.content.Context
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.os.Build
import android.text.Html
import android.text.Spanned
import android.text.method.LinkMovementMethod
import android.util.Log
import android.view.View
import android.widget.ImageView
import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.core.text.toSpanned
import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.bumptech.glide.RequestBuilder
import com.google.android.material.tabs.TabLayoutMediator
import com.h.pixeldroid.ImageFragment
import com.h.pixeldroid.R
import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.fragments.feeds.PostViewHolder
@ -27,6 +30,9 @@ import com.h.pixeldroid.utils.PostUtils.Companion.retrieveComments
import com.h.pixeldroid.utils.PostUtils.Companion.toggleCommentInput
import com.h.pixeldroid.utils.PostUtils.Companion.unLikePostCall
import com.h.pixeldroid.utils.PostUtils.Companion.undoReblogPost
import kotlinx.android.synthetic.main.post_fragment.view.*
import java.io.Serializable
/*
@ -93,11 +99,11 @@ data class Status(
}
fun getUsername() : CharSequence {
var name = account?.display_name
var name = account.display_name
if (name.isEmpty()) {
name = account?.username
name = account.username
}
return name!!
return name
}
fun getNLikes() : CharSequence {
@ -110,11 +116,49 @@ data class Status(
return "$nShares Shares"
}
private fun setupPostPics(rootView: View, request: RequestBuilder<Drawable>, homeFragment: Fragment) {
//Check whether or not we need to activate the viewPager
if(media_attachments?.size == 1) {
rootView.postPicture.visibility = VISIBLE
rootView.postPager.visibility = GONE
rootView.postTabs.visibility = GONE
request.load(this.getPostUrl()).into(rootView.postPicture)
} else if(media_attachments?.size!! > 1) {
//Only show the viewPager and tabs
rootView.postPicture.visibility = GONE
rootView.postPager.visibility = VISIBLE
rootView.postTabs.visibility = VISIBLE
val tabs : ArrayList<ImageFragment> = ArrayList()
//Fill the tabs with each mediaAttachment
for(media in media_attachments) {
tabs.add(ImageFragment.newInstance(media.url))
}
setupTabs(tabs, rootView, homeFragment)
}
}
private fun setupTabs(tabs: ArrayList<ImageFragment>, rootView: View, homeFragment: Fragment) {
//Attach the given tabs to the view pager
rootView.postPager.adapter = object : FragmentStateAdapter(homeFragment) {
override fun createFragment(position: Int): Fragment {
return tabs[position]
}
override fun getItemCount(): Int {
return media_attachments?.size ?: 0
}
}
TabLayoutMediator(rootView.postTabs, rootView.postPager) { tab, _ ->
tab.icon = rootView.context.getDrawable(R.drawable.ic_dot_blue_12dp)
}.attach()
}
fun setupPost(
rootView: View,
request: RequestBuilder<Drawable>,
postPic: ImageView,
profilePic: ImageView
homeFragment: Fragment
) {
//Setup username as a button that opens the profile
val username = rootView.findViewById<TextView>(R.id.username)
@ -135,13 +179,13 @@ data class Status(
nshares.setTypeface(null, Typeface.BOLD)
//Setup images
request.load(this.getPostUrl()).into(postPic)
setupPostPics(rootView, request, homeFragment)
ImageConverter.setRoundImageFromURL(
rootView,
this.getProfilePicUrl(),
profilePic
rootView.profilePic
)
profilePic.setOnClickListener { account.openProfile(rootView.context) }
rootView.profilePic.setOnClickListener { account.openProfile(rootView.context) }
//Set comment initial visibility
rootView.findViewById<LinearLayout>(R.id.commentIn).visibility = View.GONE

View File

@ -0,0 +1,5 @@
<vector android:height="12dp" android:tint="#003DFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="12dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#010101" android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#003DFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#010101" android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"/>
</vector>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".ImageFragment">
<ImageView
android:id="@+id/imageImageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"/>
</FrameLayout>

View File

@ -39,14 +39,44 @@
app:layout_constraintTop_toTopOf="@+id/profilePic"
tools:text="Account" />
<ImageView
android:id="@+id/postPicture"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/postConstraint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:adjustViewBounds="true"
app:layout_constraintTop_toBottomOf="@+id/profilePic"
tools:src="@color/browser_actions_bg_grey"/>
app:layout_constraintTop_toBottomOf="@+id/profilePic">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/postPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</androidx.viewpager2.widget.ViewPager2>
<com.google.android.material.tabs.TabLayout
android:id="@+id/postTabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/postPager"
app:tabMode="auto">
</com.google.android.material.tabs.TabLayout>
<ImageView
android:id="@+id/postPicture"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@color/browser_actions_bg_grey"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView
android:id="@+id/commenter"
@ -78,7 +108,7 @@
app:layout_constraintEnd_toStartOf="@id/commenter"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="@id/profilePic"
app:layout_constraintTop_toBottomOf="@id/postPicture"/>
app:layout_constraintTop_toBottomOf="@id/postConstraint"/>
<at.connyduck.sparkbutton.SparkButton
android:id="@+id/reblogger"