A few UI tweaks (#126)

* added timestamp and 'from domain' for people who aren't on our domain

* added abbreviated timestamp for feed posts

* changed timestamp text color

* added share notification clicking

* fixed search

* Fixed broken test

* refactored notification clicks a bit

* fixed accounts in test
This commit is contained in:
Andrew Dobis 2020-05-01 10:39:25 +02:00 committed by GitHub
parent db594bbda2
commit 600813baaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 129 additions and 38 deletions

View File

@ -247,6 +247,22 @@ class MockedServerTest {
onView(withText("Dante")).check(matches(withId(R.id.accountNameTextView))) onView(withText("Dante")).check(matches(withId(R.id.accountNameTextView)))
} }
@Test
fun clickNotificationRePost() {
ActivityScenario.launch(MainActivity::class.java).onActivity{
a -> a.findViewById<TabLayout>(R.id.tabs).getTabAt(3)?.select()
}
Thread.sleep(1000)
onView(withId(R.id.view_pager)).perform(ViewActions.swipeUp()).perform(ViewActions.swipeDown())
Thread.sleep(1000)
onView(withText("Clement shared your post")).perform(ViewActions.click())
Thread.sleep(1000)
onView(first(withText("Andrea"))).check(matches(withId(R.id.username)))
}
@Test @Test
fun swipingLeftStopsAtProfile() { fun swipingLeftStopsAtProfile() {
onView(withId(R.id.main_activity_main_linear_layout)) onView(withId(R.id.main_activity_main_linear_layout))

View File

@ -64,7 +64,8 @@ class PostTest {
id = "12", id = "12",
account = Account( account = Account(
id = "12", id = "12",
username = "douze" username = "douze",
url = "https://pixelfed.de/douze"
), ),
media_attachments = listOf(attachment) media_attachments = listOf(attachment)
) )
@ -94,7 +95,8 @@ class PostTest {
id = "12", id = "12",
account = Account( account = Account(
id = "12", id = "12",
username = "douze" username = "douze",
url = "https://pixelfed.de/douze"
), ),
media_attachments = listOf(attachment1, attachment2) media_attachments = listOf(attachment1, attachment2)
) )
@ -121,7 +123,8 @@ class PostTest {
id = "12", id = "12",
account = Account( account = Account(
id = "12", id = "12",
username = "douze" username = "douze",
url = "https://pixelfed.de/douze"
), ),
media_attachments = listOf(attachment) media_attachments = listOf(attachment)
) )
@ -149,7 +152,8 @@ class PostTest {
id = "12", id = "12",
account = Account( account = Account(
id = "12", id = "12",
username = "douze" username = "douze",
url = "https://pixelfed.de/douze"
), ),
media_attachments = listOf(attachment1, attachment2) media_attachments = listOf(attachment1, attachment2)
) )

View File

@ -1,13 +1,16 @@
package com.h.pixeldroid package com.h.pixeldroid
import android.content.Context
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.h.pixeldroid.fragments.PostFragment import com.h.pixeldroid.fragments.PostFragment
import com.h.pixeldroid.objects.Status import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.objects.Status.Companion.DOMAIN_TAG
import com.h.pixeldroid.objects.Status.Companion.POST_TAG import com.h.pixeldroid.objects.Status.Companion.POST_TAG
class PostActivity : AppCompatActivity() { class PostActivity : AppCompatActivity() {
lateinit var postFragment : PostFragment lateinit var postFragment : PostFragment
lateinit var domain : String
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -15,9 +18,14 @@ class PostActivity : AppCompatActivity() {
val status = intent.getSerializableExtra(POST_TAG) as Status? val status = intent.getSerializableExtra(POST_TAG) as Status?
domain = getSharedPreferences(
"${BuildConfig.APPLICATION_ID}.pref", Context.MODE_PRIVATE
).getString("domain", "")!!
postFragment = PostFragment() postFragment = PostFragment()
val arguments = Bundle() val arguments = Bundle()
arguments.putSerializable(POST_TAG, status) arguments.putSerializable(POST_TAG, status)
arguments.putString(DOMAIN_TAG, domain)
postFragment.arguments = arguments postFragment.arguments = arguments
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()

View File

@ -14,6 +14,7 @@ import com.h.pixeldroid.R
import com.h.pixeldroid.api.PixelfedAPI import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.fragments.feeds.PostViewHolder import com.h.pixeldroid.fragments.feeds.PostViewHolder
import com.h.pixeldroid.objects.Status import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.objects.Status.Companion.DOMAIN_TAG
import com.h.pixeldroid.objects.Status.Companion.POST_TAG import com.h.pixeldroid.objects.Status.Companion.POST_TAG
@ -24,12 +25,13 @@ class PostFragment : Fragment() {
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
val status = arguments?.getSerializable(POST_TAG) as Status? val status = arguments?.getSerializable(POST_TAG) as Status?
val domain = arguments?.getString(DOMAIN_TAG)!!
val root = inflater.inflate(R.layout.post_fragment, container, false) val root = inflater.inflate(R.layout.post_fragment, container, false)
val picRequest = Glide.with(this) val picRequest = Glide.with(this)
.asDrawable().fitCenter() .asDrawable().fitCenter()
.placeholder(ColorDrawable(Color.GRAY)) .placeholder(ColorDrawable(Color.GRAY))
status?.setupPost(root, picRequest, this) status?.setupPost(root, picRequest, this, domain, true)
//Setup arguments needed for the onclicklisteners //Setup arguments needed for the onclicklisteners
val holder = PostViewHolder(root, requireContext()) val holder = PostViewHolder(root, requireContext())

View File

@ -108,16 +108,21 @@ class NotificationsFragment : FeedFragment<Notification, NotificationsFragment.N
openActivity(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){ private fun openActivity(notification: Notification){
val intent: Intent val intent: Intent
when (notification.type){ when (notification.type){
Notification.NotificationType.mention, Notification.NotificationType.favourite-> { Notification.NotificationType.mention, Notification.NotificationType.favourite-> {
intent = Intent(context, PostActivity::class.java) intent = openPostFromNotifcation(notification)
intent.putExtra(Status.POST_TAG, notification.status)
} }
Notification.NotificationType.reblog-> { Notification.NotificationType.reblog-> {
Toast.makeText(context,"Can't see shares yet, sorry!", Toast.LENGTH_SHORT).show() intent = openPostFromNotifcation(notification)
return
} }
Notification.NotificationType.follow -> { Notification.NotificationType.follow -> {
intent = Intent(context, ProfileActivity::class.java) intent = Intent(context, ProfileActivity::class.java)

View File

@ -4,6 +4,7 @@ import android.graphics.Color
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -27,13 +28,14 @@ import retrofit2.Call
open class PostsFeedFragment : FeedFragment<Status, PostViewHolder>() { open class PostsFeedFragment : FeedFragment<Status, PostViewHolder>() {
lateinit var picRequest: RequestBuilder<Drawable> lateinit var picRequest: RequestBuilder<Drawable>
lateinit var domain : String
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
val view = super.onCreateView(inflater, container, savedInstanceState) val view = super.onCreateView(inflater, container, savedInstanceState)
domain = preferences.getString("domain", "")!!
//RequestBuilder that is re-used for every image //RequestBuilder that is re-used for every image
picRequest = Glide.with(this) picRequest = Glide.with(this)
.asDrawable().fitCenter() .asDrawable().fitCenter()
@ -106,7 +108,7 @@ open class PostsFeedFragment : FeedFragment<Status, PostViewHolder>() {
holder.postPic.maxHeight = metrics.heightPixels holder.postPic.maxHeight = metrics.heightPixels
//Setup the post layout //Setup the post layout
post.setupPost(holder.postView, picRequest, postsFeedFragment) post.setupPost(holder.postView, picRequest, this@PostsFeedFragment, domain, false)
//Set the special HTML text //Set the special HTML text
post.setDescription(holder.postView, api, credential) post.setDescription(holder.postView, api, credential)
@ -157,4 +159,6 @@ class PostViewHolder(val postView: View, val context: android.content.Context) :
val commentCont : LinearLayout = postView.findViewById(R.id.commentContainer) val commentCont : LinearLayout = postView.findViewById(R.id.commentContainer)
val commentIn : LinearLayout = postView.findViewById(R.id.commentIn) val commentIn : LinearLayout = postView.findViewById(R.id.commentIn)
val viewComment : TextView = postView.findViewById(R.id.ViewComments) val viewComment : TextView = postView.findViewById(R.id.ViewComments)
val postDate : TextView = postView.findViewById(R.id.postDate)
val postDomain : TextView = postView.findViewById(R.id.postDomain)
} }

View File

@ -1,28 +1,21 @@
package com.h.pixeldroid.objects package com.h.pixeldroid.objects
import android.content.ContentValues
import android.content.Context import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Typeface import android.graphics.Typeface
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.net.Uri
import android.provider.MediaStore
import android.text.Spanned import android.text.Spanned
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.view.View.GONE import android.view.View.GONE
import android.view.View.VISIBLE import android.view.View.VISIBLE
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.PopupMenu
import android.widget.TextView
import android.widget.Toast
import androidx.core.content.ContextCompat.startActivity
import androidx.core.text.toSpanned import androidx.core.text.toSpanned
import androidx.core.view.drawToBitmap import android.widget.TextView
import android.widget.LinearLayout
import android.widget.Toast
import android.widget.PopupMenu
import android.widget.ImageView
import android.widget.FrameLayout
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
@ -32,6 +25,7 @@ import com.h.pixeldroid.ImageFragment
import com.h.pixeldroid.R import com.h.pixeldroid.R
import com.h.pixeldroid.api.PixelfedAPI import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.fragments.feeds.PostViewHolder import com.h.pixeldroid.fragments.feeds.PostViewHolder
import com.h.pixeldroid.utils.HtmlUtils.Companion.getDomain
import com.h.pixeldroid.utils.HtmlUtils.Companion.parseHTMLText import com.h.pixeldroid.utils.HtmlUtils.Companion.parseHTMLText
import com.h.pixeldroid.utils.ImageConverter import com.h.pixeldroid.utils.ImageConverter
import com.h.pixeldroid.utils.ImageUtils.Companion.downloadImage import com.h.pixeldroid.utils.ImageUtils.Companion.downloadImage
@ -42,14 +36,17 @@ import com.h.pixeldroid.utils.PostUtils.Companion.retrieveComments
import com.h.pixeldroid.utils.PostUtils.Companion.toggleCommentInput import com.h.pixeldroid.utils.PostUtils.Companion.toggleCommentInput
import com.h.pixeldroid.utils.PostUtils.Companion.unLikePostCall import com.h.pixeldroid.utils.PostUtils.Companion.unLikePostCall
import com.h.pixeldroid.utils.PostUtils.Companion.undoReblogPost import com.h.pixeldroid.utils.PostUtils.Companion.undoReblogPost
import kotlinx.android.synthetic.main.post_fragment.view.postDate
import kotlinx.android.synthetic.main.post_fragment.view.postDomain
import java.io.Serializable
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Date
import kotlin.collections.ArrayList
import kotlinx.android.synthetic.main.post_fragment.view.postPager import kotlinx.android.synthetic.main.post_fragment.view.postPager
import kotlinx.android.synthetic.main.post_fragment.view.postPicture import kotlinx.android.synthetic.main.post_fragment.view.postPicture
import kotlinx.android.synthetic.main.post_fragment.view.postTabs import kotlinx.android.synthetic.main.post_fragment.view.postTabs
import kotlinx.android.synthetic.main.post_fragment.view.profilePic import kotlinx.android.synthetic.main.post_fragment.view.profilePic
import retrofit2.http.Url
import java.io.OutputStream
import java.io.Serializable
import java.net.URL
/* /*
Represents a status posted by an account. Represents a status posted by an account.
@ -96,6 +93,7 @@ data class Status(
companion object { companion object {
const val POST_TAG = "postTag" const val POST_TAG = "postTag"
const val POST_FRAG_TAG = "postFragTag" const val POST_FRAG_TAG = "postFragTag"
const val DOMAIN_TAG = "domainTag"
} }
fun getPostUrl() : String? = media_attachments?.getOrNull(0)?.url fun getPostUrl() : String? = media_attachments?.getOrNull(0)?.url
@ -132,6 +130,31 @@ data class Status(
return "$nShares Shares" return "$nShares Shares"
} }
private fun ISO8601toDate(dateString : String, textView: TextView, isActivity: Boolean) {
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.'000000Z'")
val now = Date().time
try {
val date: Date = format.parse(dateString)!!
val then = date.time
val formattedDate = android.text.format.DateUtils
.getRelativeTimeSpanString(then, now,
android.text.format.DateUtils.SECOND_IN_MILLIS,
android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE)
textView.text = if(isActivity) "Posted on $date"
else "$formattedDate"
} catch (e: ParseException) {
e.printStackTrace()
}
}
private fun getStatusDomain(domain : String) : String {
val accountDomain = getDomain(account.url)
return if(getDomain(domain) == accountDomain) ""
else " from $accountDomain"
}
private fun setupPostPics(rootView: View, request: RequestBuilder<Drawable>, homeFragment: Fragment) { private fun setupPostPics(rootView: View, request: RequestBuilder<Drawable>, homeFragment: Fragment) {
//Check whether or not we need to activate the viewPager //Check whether or not we need to activate the viewPager
if(media_attachments?.size == 1) { if(media_attachments?.size == 1) {
@ -174,7 +197,9 @@ data class Status(
fun setupPost( fun setupPost(
rootView: View, rootView: View,
request: RequestBuilder<Drawable>, request: RequestBuilder<Drawable>,
homeFragment: Fragment homeFragment: Fragment,
domain : String,
isActivity : Boolean
) { ) {
//Setup username as a button that opens the profile //Setup username as a button that opens the profile
val username = rootView.findViewById<TextView>(R.id.username) val username = rootView.findViewById<TextView>(R.id.username)
@ -194,6 +219,11 @@ data class Status(
nshares.text = this.getNShares() nshares.text = this.getNShares()
nshares.setTypeface(null, Typeface.BOLD) nshares.setTypeface(null, Typeface.BOLD)
//Convert the date to a readable string
ISO8601toDate(created_at, rootView.postDate, isActivity)
rootView.postDomain.text = getStatusDomain(domain)
//Setup images //Setup images
ImageConverter.setRoundImageFromURL( ImageConverter.setRoundImageFromURL(
rootView, rootView,

View File

@ -32,7 +32,7 @@ class HtmlUtils {
return result.trim().toSpanned() return result.trim().toSpanned()
} }
private fun getDomain(urlString: String?): String { public fun getDomain(urlString: String?): String {
val uri: URI val uri: URI
try { try {
uri = URI(urlString!!) uri = URI(urlString!!)

View File

@ -10,6 +10,7 @@
android:id="@+id/search" android:id="@+id/search"
android:layout_width="250dp" android:layout_width="250dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="10dp"
android:gravity="center" android:gravity="center"
android:hint="Search" android:hint="Search"
app:errorEnabled="true" app:errorEnabled="true"
@ -42,6 +43,7 @@
android:id="@+id/searchButton" android:id="@+id/searchButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="20dp"
android:text="Search" android:text="Search"
app:layout_constraintBottom_toBottomOf="@+id/search" app:layout_constraintBottom_toBottomOf="@+id/search"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

View File

@ -24,7 +24,9 @@
android:id="@+id/profilePic" android:id="@+id/profilePic"
android:layout_width="50dp" android:layout_width="50dp"
android:layout_height="50dp" android:layout_height="50dp"
android:layout_margin="10dp" android:layout_marginTop="10dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:src="@drawable/ic_default_user" android:src="@drawable/ic_default_user"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
@ -36,8 +38,16 @@
android:layout_marginStart="12dp" android:layout_marginStart="12dp"
app:layout_constraintBottom_toBottomOf="@+id/profilePic" app:layout_constraintBottom_toBottomOf="@+id/profilePic"
app:layout_constraintStart_toEndOf="@+id/profilePic" app:layout_constraintStart_toEndOf="@+id/profilePic"
app:layout_constraintTop_toTopOf="@+id/profilePic" app:layout_constraintTop_toTopOf="@+id/profilePic"/>
tools:text="Account" />
<TextView
android:id="@+id/postDomain"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#b3b3b3"
app:layout_constraintBottom_toBottomOf="@+id/profilePic"
app:layout_constraintStart_toEndOf="@+id/username"
app:layout_constraintTop_toTopOf="@+id/profilePic"/>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/postConstraint" android:id="@+id/postConstraint"
@ -174,17 +184,27 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hyphenationFrequency="full" android:hyphenationFrequency="full"
app:layout_constraintStart_toStartOf="@+id/usernameDesc"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/usernameDesc"
app:layout_constraintTop_toBottomOf="@+id/usernameDesc" app:layout_constraintTop_toBottomOf="@+id/usernameDesc"
tools:text="This is a description, describing stuff.\nIt contains multiple lines, and that's okay. It's also got some really long lines, and we love it for it." /> tools:text="This is a description, describing stuff.\nIt contains multiple lines, and that's okay. It's also got some really long lines, and we love it for it." />
<TextView
android:id="@+id/postDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:textColor="#b3b3b3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/description"
tools:text="time" />
<LinearLayout <LinearLayout
android:id="@+id/commentIn" android:id="@+id/commentIn"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@+id/description" app:layout_constraintTop_toBottomOf="@+id/postDate"
tools:layout_editor_absoluteX="10dp"> tools:layout_editor_absoluteX="10dp">
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout