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)))
}
@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
fun swipingLeftStopsAtProfile() {
onView(withId(R.id.main_activity_main_linear_layout))

View File

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

View File

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

View File

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

View File

@ -108,16 +108,21 @@ class NotificationsFragment : FeedFragment<Notification, NotificationsFragment.N
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 = Intent(context, PostActivity::class.java)
intent.putExtra(Status.POST_TAG, notification.status)
intent = openPostFromNotifcation(notification)
}
Notification.NotificationType.reblog-> {
Toast.makeText(context,"Can't see shares yet, sorry!", Toast.LENGTH_SHORT).show()
return
intent = openPostFromNotifcation(notification)
}
Notification.NotificationType.follow -> {
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.Drawable
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -27,13 +28,14 @@ import retrofit2.Call
open class PostsFeedFragment : FeedFragment<Status, PostViewHolder>() {
lateinit var picRequest: RequestBuilder<Drawable>
lateinit var domain : String
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = super.onCreateView(inflater, container, savedInstanceState)
domain = preferences.getString("domain", "")!!
//RequestBuilder that is re-used for every image
picRequest = Glide.with(this)
.asDrawable().fitCenter()
@ -106,7 +108,7 @@ open class PostsFeedFragment : FeedFragment<Status, PostViewHolder>() {
holder.postPic.maxHeight = metrics.heightPixels
//Setup the post layout
post.setupPost(holder.postView, picRequest, postsFeedFragment)
post.setupPost(holder.postView, picRequest, this@PostsFeedFragment, domain, false)
//Set the special HTML text
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 commentIn : LinearLayout = postView.findViewById(R.id.commentIn)
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
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.net.Uri
import android.provider.MediaStore
import android.text.Spanned
import android.text.method.LinkMovementMethod
import android.util.Log
import android.view.View
import android.view.View.GONE
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.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.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
@ -32,6 +25,7 @@ import com.h.pixeldroid.ImageFragment
import com.h.pixeldroid.R
import com.h.pixeldroid.api.PixelfedAPI
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.ImageConverter
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.unLikePostCall
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.postPicture
import kotlinx.android.synthetic.main.post_fragment.view.postTabs
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.
@ -96,6 +93,7 @@ data class Status(
companion object {
const val POST_TAG = "postTag"
const val POST_FRAG_TAG = "postFragTag"
const val DOMAIN_TAG = "domainTag"
}
fun getPostUrl() : String? = media_attachments?.getOrNull(0)?.url
@ -132,6 +130,31 @@ data class Status(
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) {
//Check whether or not we need to activate the viewPager
if(media_attachments?.size == 1) {
@ -174,7 +197,9 @@ data class Status(
fun setupPost(
rootView: View,
request: RequestBuilder<Drawable>,
homeFragment: Fragment
homeFragment: Fragment,
domain : String,
isActivity : Boolean
) {
//Setup username as a button that opens the profile
val username = rootView.findViewById<TextView>(R.id.username)
@ -194,6 +219,11 @@ data class Status(
nshares.text = this.getNShares()
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
ImageConverter.setRoundImageFromURL(
rootView,

View File

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

View File

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

View File

@ -24,20 +24,30 @@
android:id="@+id/profilePic"
android:layout_width="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"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/username"
android:id="@+id/username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
app:layout_constraintBottom_toBottomOf="@+id/profilePic"
app:layout_constraintStart_toEndOf="@+id/profilePic"
app:layout_constraintTop_toTopOf="@+id/profilePic"/>
<TextView
android:id="@+id/postDomain"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:textColor="#b3b3b3"
app:layout_constraintBottom_toBottomOf="@+id/profilePic"
app:layout_constraintStart_toEndOf="@+id/profilePic"
app:layout_constraintTop_toTopOf="@+id/profilePic"
tools:text="Account" />
app:layout_constraintStart_toEndOf="@+id/username"
app:layout_constraintTop_toTopOf="@+id/profilePic"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/postConstraint"
@ -174,17 +184,27 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hyphenationFrequency="full"
app:layout_constraintStart_toStartOf="@+id/usernameDesc"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+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." />
<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
android:id="@+id/commentIn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@+id/description"
app:layout_constraintTop_toBottomOf="@+id/postDate"
tools:layout_editor_absoluteX="10dp">
<com.google.android.material.textfield.TextInputLayout