367 lines
14 KiB
Kotlin
367 lines
14 KiB
Kotlin
package org.pixeldroid.app.profile
|
|
|
|
import android.content.Intent
|
|
import android.os.Bundle
|
|
import android.text.method.LinkMovementMethod
|
|
import android.util.Log
|
|
import android.view.LayoutInflater
|
|
import android.view.View
|
|
import android.view.ViewGroup
|
|
import android.widget.ImageView
|
|
import android.widget.Toast
|
|
import androidx.appcompat.app.AlertDialog
|
|
import androidx.core.content.ContextCompat
|
|
import androidx.fragment.app.Fragment
|
|
import androidx.lifecycle.lifecycleScope
|
|
import androidx.recyclerview.widget.RecyclerView
|
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
|
import com.bumptech.glide.Glide
|
|
import com.bumptech.glide.request.RequestOptions
|
|
import com.google.android.material.snackbar.Snackbar
|
|
import com.google.android.material.tabs.TabLayout
|
|
import com.google.android.material.tabs.TabLayoutMediator
|
|
import kotlinx.coroutines.launch
|
|
import org.pixeldroid.app.R
|
|
import org.pixeldroid.app.databinding.ActivityProfileBinding
|
|
import org.pixeldroid.app.databinding.FragmentProfilePostsBinding
|
|
import org.pixeldroid.app.posts.PostActivity
|
|
import org.pixeldroid.app.posts.parseHTMLText
|
|
import org.pixeldroid.app.utils.*
|
|
import org.pixeldroid.app.utils.api.PixelfedAPI
|
|
import org.pixeldroid.app.utils.api.objects.Account
|
|
import org.pixeldroid.app.utils.api.objects.Attachment
|
|
import org.pixeldroid.app.utils.api.objects.Status
|
|
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
|
|
import retrofit2.HttpException
|
|
import java.io.IOException
|
|
|
|
class ProfileActivity : BaseThemedWithBarActivity() {
|
|
|
|
private lateinit var domain : String
|
|
private lateinit var accountId : String
|
|
private lateinit var binding: ActivityProfileBinding
|
|
|
|
private var user: UserDatabaseEntity? = null
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
binding = ActivityProfileBinding.inflate(layoutInflater)
|
|
setContentView(binding.root)
|
|
|
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
|
|
|
user = db.userDao().getActiveUser()
|
|
|
|
domain = user?.instance_uri.orEmpty()
|
|
|
|
// Set profile according to given account
|
|
val account = intent.getSerializableExtra(Account.ACCOUNT_TAG) as Account?
|
|
accountId = account?.id ?: user!!.user_id
|
|
|
|
val tabs = createProfileTabs(account)
|
|
setupTabs(tabs)
|
|
setContent(account)
|
|
}
|
|
|
|
private fun createProfileTabs(account: Account?): Array<Fragment>{
|
|
|
|
val profileFeedFragment = ProfileFeedFragment()
|
|
profileFeedFragment.arguments = Bundle().apply {
|
|
putSerializable(Account.ACCOUNT_TAG, account)
|
|
putSerializable(ProfileFeedFragment.PROFILE_GRID, false)
|
|
putSerializable(ProfileFeedFragment.BOOKMARKS, false)
|
|
}
|
|
|
|
val profileGridFragment = ProfileFeedFragment()
|
|
profileGridFragment.arguments = Bundle().apply {
|
|
putSerializable(Account.ACCOUNT_TAG, account)
|
|
putSerializable(ProfileFeedFragment.PROFILE_GRID, true)
|
|
putSerializable(ProfileFeedFragment.BOOKMARKS, false)
|
|
}
|
|
|
|
val profileCollectionsFragment = ProfileFeedFragment()
|
|
profileCollectionsFragment.arguments = Bundle().apply {
|
|
putSerializable(Account.ACCOUNT_TAG, account)
|
|
putSerializable(ProfileFeedFragment.PROFILE_GRID, true)
|
|
putSerializable(ProfileFeedFragment.BOOKMARKS, false)
|
|
putSerializable(ProfileFeedFragment.COLLECTIONS, true)
|
|
}
|
|
|
|
val returnArray: Array<Fragment> = arrayOf(
|
|
profileGridFragment,
|
|
profileFeedFragment,
|
|
profileCollectionsFragment
|
|
)
|
|
|
|
// If we are viewing our own account, show bookmarks
|
|
if(account == null || account.id == user?.user_id) {
|
|
val profileBookmarksFragment = ProfileFeedFragment()
|
|
profileBookmarksFragment.arguments = Bundle().apply {
|
|
putSerializable(Account.ACCOUNT_TAG, account)
|
|
putSerializable(ProfileFeedFragment.PROFILE_GRID, true)
|
|
putSerializable(ProfileFeedFragment.BOOKMARKS, true)
|
|
}
|
|
return returnArray + profileBookmarksFragment
|
|
}
|
|
return returnArray
|
|
}
|
|
|
|
private fun setupTabs(
|
|
tabs: Array<Fragment>
|
|
){
|
|
binding.viewPager.adapter = object : FragmentStateAdapter(this) {
|
|
override fun createFragment(position: Int): Fragment {
|
|
return tabs[position]
|
|
}
|
|
|
|
override fun getItemCount(): Int {
|
|
return tabs.size
|
|
}
|
|
}
|
|
TabLayoutMediator(binding.profileTabs, binding.viewPager) { tab, position ->
|
|
tab.tabLabelVisibility = TabLayout.TAB_LABEL_VISIBILITY_UNLABELED
|
|
when (position) {
|
|
0 -> {
|
|
tab.setText(R.string.grid_view)
|
|
tab.setIcon(R.drawable.grid_on_black_24dp)
|
|
}
|
|
1 -> {
|
|
tab.setText(R.string.feed_view)
|
|
tab.setIcon(R.drawable.feed_view)
|
|
}
|
|
2 -> {
|
|
tab.setText(R.string.collections)
|
|
tab.setIcon(R.drawable.collections)
|
|
}
|
|
3 -> {
|
|
tab.setText(R.string.bookmarks)
|
|
tab.setIcon(R.drawable.bookmark)
|
|
}
|
|
}
|
|
}.attach()
|
|
}
|
|
|
|
|
|
private fun setContent(account: Account?) {
|
|
if(account != null) {
|
|
setViews(account)
|
|
} else {
|
|
supportActionBar?.setTitle(R.string.menu_account)
|
|
lifecycleScope.launchWhenResumed {
|
|
val api: PixelfedAPI = apiHolder.api ?: apiHolder.setToCurrentUser()
|
|
val myAccount: Account = try {
|
|
api.verifyCredentials()
|
|
} catch (exception: IOException) {
|
|
Log.e("ProfileActivity:", exception.toString())
|
|
Toast.makeText(
|
|
applicationContext, "Could not get your profile",
|
|
Toast.LENGTH_SHORT
|
|
).show()
|
|
return@launchWhenResumed
|
|
} catch (exception: HttpException) {
|
|
Toast.makeText(
|
|
applicationContext, "Could not get your profile",
|
|
Toast.LENGTH_SHORT
|
|
).show()
|
|
return@launchWhenResumed
|
|
}
|
|
setViews(myAccount)
|
|
}
|
|
}
|
|
|
|
if(account != null && account.id != user?.user_id) {
|
|
//if we aren't viewing our own account, activate follow button
|
|
activateFollow(account)
|
|
} else {
|
|
//if we *are* viewing our own account, activate the edit button
|
|
activateEditButton()
|
|
}
|
|
|
|
// On click open followers list
|
|
binding.nbFollowersTextView.setOnClickListener{ onClickFollowers(account) }
|
|
// On click open followers list
|
|
binding.nbFollowingTextView.setOnClickListener{ onClickFollowing(account) }
|
|
}
|
|
|
|
/**
|
|
* Populate profile page with user's data
|
|
*/
|
|
private fun setViews(account: Account) {
|
|
val profilePicture = binding.profilePictureImageView
|
|
setProfileImageFromURL(
|
|
View(applicationContext),
|
|
account.anyAvatar(),
|
|
profilePicture
|
|
)
|
|
|
|
binding.descriptionTextView.text = parseHTMLText(
|
|
account.note ?: "", emptyList(), apiHolder,
|
|
binding.descriptionTextView.context,
|
|
lifecycleScope
|
|
)
|
|
// This is so that the clicks in the text (eg #, @) work.
|
|
binding.descriptionTextView.movementMethod = LinkMovementMethod.getInstance();
|
|
|
|
val displayName = account.getDisplayName()
|
|
|
|
binding.accountNameTextView.text = displayName
|
|
|
|
supportActionBar?.title = displayName
|
|
if(displayName != "@${account.acct}") {
|
|
supportActionBar?.subtitle = "@${account.acct}"
|
|
}
|
|
|
|
binding.nbPostsTextView.text = resources.getQuantityString(
|
|
R.plurals.nb_posts,
|
|
account.statuses_count ?: 0,
|
|
account.statuses_count ?: 0
|
|
)
|
|
|
|
binding.nbFollowersTextView.text = resources.getQuantityString(
|
|
R.plurals.nb_followers,
|
|
account.followers_count ?: 0,
|
|
account.followers_count ?: 0
|
|
)
|
|
|
|
binding.nbFollowingTextView.text = resources.getQuantityString(
|
|
R.plurals.nb_following,
|
|
account.following_count ?: 0,
|
|
account.following_count ?: 0
|
|
)
|
|
}
|
|
|
|
private fun onClickEditButton() {
|
|
val intent = Intent(this, EditProfileActivity::class.java)
|
|
ContextCompat.startActivity(this, intent, null)
|
|
}
|
|
|
|
private fun onClickFollowers(account: Account?) {
|
|
val intent = Intent(this, FollowsActivity::class.java)
|
|
intent.putExtra(Account.FOLLOWERS_TAG, true)
|
|
intent.putExtra(Account.ACCOUNT_TAG, account)
|
|
|
|
ContextCompat.startActivity(this, intent, null)
|
|
}
|
|
|
|
private fun onClickFollowing(account: Account?) {
|
|
val intent = Intent(this, FollowsActivity::class.java)
|
|
intent.putExtra(Account.FOLLOWERS_TAG, false)
|
|
intent.putExtra(Account.ACCOUNT_TAG, account)
|
|
|
|
ContextCompat.startActivity(this, intent, null)
|
|
}
|
|
|
|
private fun activateEditButton() {
|
|
// Edit button redirects to Pixelfed's "edit account" page
|
|
binding.editButton.apply {
|
|
visibility = View.VISIBLE
|
|
setOnClickListener{ onClickEditButton() }
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set up follow button
|
|
*/
|
|
private fun activateFollow(account: Account) {
|
|
// Get relationship between the two users (credential and this) and set followButton accordingly
|
|
lifecycleScope.launch {
|
|
try {
|
|
val api: PixelfedAPI = apiHolder.api ?: apiHolder.setToCurrentUser()
|
|
val relationship = api.checkRelationships(
|
|
listOf(account.id.orEmpty())
|
|
).firstOrNull()
|
|
|
|
if(relationship != null){
|
|
if (relationship.following == true || relationship.requested == true) {
|
|
setOnClickUnfollow(account, relationship.requested == true)
|
|
} else {
|
|
setOnClickFollow(account)
|
|
}
|
|
binding.followButton.visibility = View.VISIBLE
|
|
}
|
|
} catch (exception: IOException) {
|
|
Log.e("FOLLOW ERROR", exception.toString())
|
|
Toast.makeText(
|
|
applicationContext, getString(R.string.follow_status_failed),
|
|
Toast.LENGTH_SHORT
|
|
).show()
|
|
} catch (exception: HttpException) {
|
|
Toast.makeText(
|
|
applicationContext, getString(R.string.follow_button_failed),
|
|
Toast.LENGTH_SHORT
|
|
).show()
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun setOnClickFollow(account: Account) {
|
|
binding.followButton.apply {
|
|
setText(R.string.follow)
|
|
setOnClickListener {
|
|
lifecycleScope.launchWhenResumed {
|
|
try {
|
|
val api: PixelfedAPI = apiHolder.api ?: apiHolder.setToCurrentUser()
|
|
val rel = api.follow(account.id.orEmpty())
|
|
if(rel.following == true) setOnClickUnfollow(account, rel.requested == true)
|
|
else setOnClickFollow(account)
|
|
} catch (exception: IOException) {
|
|
Log.e("FOLLOW ERROR", exception.toString())
|
|
Toast.makeText(
|
|
applicationContext, getString(R.string.follow_error),
|
|
Toast.LENGTH_SHORT
|
|
).show()
|
|
} catch (exception: HttpException) {
|
|
Toast.makeText(
|
|
applicationContext, getString(R.string.follow_error),
|
|
Toast.LENGTH_SHORT
|
|
).show()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun setOnClickUnfollow(account: Account, requested: Boolean) {
|
|
binding.followButton.apply {
|
|
if(account.locked == true && requested) {
|
|
setText(R.string.follow_requested)
|
|
} else setText(R.string.unfollow)
|
|
|
|
|
|
fun unfollow() {
|
|
lifecycleScope.launchWhenResumed {
|
|
try {
|
|
val api: PixelfedAPI = apiHolder.api ?: apiHolder.setToCurrentUser()
|
|
val rel = api.unfollow(account.id.orEmpty())
|
|
if(rel.following == false && rel.requested == false) setOnClickFollow(account)
|
|
else setOnClickUnfollow(account, rel.requested == true)
|
|
} catch (exception: IOException) {
|
|
Log.e("FOLLOW ERROR", exception.toString())
|
|
Toast.makeText(
|
|
applicationContext, getString(R.string.unfollow_error),
|
|
Toast.LENGTH_SHORT
|
|
).show()
|
|
} catch (exception: HttpException) {
|
|
Toast.makeText(
|
|
applicationContext, getString(R.string.unfollow_error),
|
|
Toast.LENGTH_SHORT
|
|
).show()
|
|
}
|
|
}
|
|
}
|
|
|
|
setOnClickListener {
|
|
if(account.locked == true && requested){
|
|
AlertDialog.Builder(context)
|
|
.setMessage(R.string.dialog_message_cancel_follow_request)
|
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
|
unfollow()
|
|
}
|
|
.setNegativeButton(android.R.string.cancel){_, _ -> }
|
|
.show()
|
|
} else unfollow()
|
|
}
|
|
}
|
|
}
|
|
}
|