Implement identity proof api (#1597)
* implement identity proof api * fix warnings in AccountActivity * fix createClickableText method * improve error handling * use combineOptionalLiveData to simplify code
This commit is contained in:
parent
c253f6b23b
commit
c44dd455b4
7 changed files with 95 additions and 21 deletions
|
@ -19,8 +19,7 @@ import android.animation.ArgbEvaluator
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.*
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
|
@ -52,6 +51,8 @@ import com.keylesspalace.tusky.components.compose.ComposeActivity
|
|||
import com.keylesspalace.tusky.components.report.ReportActivity
|
||||
import com.keylesspalace.tusky.di.ViewModelFactory
|
||||
import com.keylesspalace.tusky.entity.Account
|
||||
import com.keylesspalace.tusky.entity.Field
|
||||
import com.keylesspalace.tusky.entity.IdentityProof
|
||||
import com.keylesspalace.tusky.entity.Relationship
|
||||
import com.keylesspalace.tusky.interfaces.ActionButtonActivity
|
||||
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||
|
@ -118,7 +119,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
|||
viewModel = ViewModelProviders.of(this, viewModelFactory)[AccountViewModel::class.java]
|
||||
|
||||
// Obtain information to fill out the profile.
|
||||
viewModel.setAccountInfo(intent.getStringExtra(KEY_ACCOUNT_ID))
|
||||
viewModel.setAccountInfo(intent.getStringExtra(KEY_ACCOUNT_ID)!!)
|
||||
|
||||
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
animateAvatar = sharedPrefs.getBoolean("animateGifAvatars", false)
|
||||
|
@ -350,6 +351,11 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
|||
}
|
||||
|
||||
})
|
||||
viewModel.accountFieldData.observe(this, Observer<List<Either<IdentityProof, Field>>> {
|
||||
accountFieldAdapter.fields = it
|
||||
accountFieldAdapter.notifyDataSetChanged()
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -378,7 +384,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
|||
val emojifiedNote = CustomEmojiHelper.emojifyText(account.note, account.emojis, accountNoteTextView)
|
||||
LinkHelper.setClickableText(accountNoteTextView, emojifiedNote, null, this)
|
||||
|
||||
accountFieldAdapter.fields = account.fields ?: emptyList()
|
||||
// accountFieldAdapter.fields = account.fields ?: emptyList()
|
||||
accountFieldAdapter.emojis = account.emojis ?: emptyList()
|
||||
accountFieldAdapter.notifyDataSetChanged()
|
||||
|
||||
|
@ -472,7 +478,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
|
|||
// this is necessary because API 19 can't handle vector compound drawables
|
||||
val movedIcon = ContextCompat.getDrawable(this, R.drawable.ic_briefcase)?.mutate()
|
||||
val textColor = ThemeUtils.getColor(this, android.R.attr.textColorTertiary)
|
||||
movedIcon?.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
|
||||
movedIcon?.colorFilter = PorterDuffColorFilter(textColor, PorterDuff.Mode.SRC_IN)
|
||||
|
||||
accountMovedText.setCompoundDrawablesRelativeWithIntrinsicBounds(movedIcon, null, null, null)
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
package com.keylesspalace.tusky.adapter
|
||||
|
||||
import android.text.method.LinkMovementMethod
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
|
@ -23,15 +24,17 @@ import android.widget.TextView
|
|||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.entity.Emoji
|
||||
import com.keylesspalace.tusky.entity.Field
|
||||
import com.keylesspalace.tusky.entity.IdentityProof
|
||||
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper
|
||||
import com.keylesspalace.tusky.util.Either
|
||||
import com.keylesspalace.tusky.util.LinkHelper
|
||||
import kotlinx.android.synthetic.main.item_account_field.view.*
|
||||
|
||||
class AccountFieldAdapter(private val linkListener: LinkListener) : RecyclerView.Adapter<AccountFieldAdapter.ViewHolder>() {
|
||||
|
||||
var emojis: List<Emoji> = emptyList()
|
||||
var fields: List<Field> = emptyList()
|
||||
var fields: List<Either<IdentityProof, Field>> = emptyList()
|
||||
|
||||
override fun getItemCount() = fields.size
|
||||
|
||||
|
@ -41,18 +44,30 @@ class AccountFieldAdapter(private val linkListener: LinkListener) : RecyclerView
|
|||
}
|
||||
|
||||
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
|
||||
val field = fields[position]
|
||||
val proofOrField = fields[position]
|
||||
|
||||
val emojifiedName = CustomEmojiHelper.emojifyString(field.name, emojis, viewHolder.nameTextView)
|
||||
viewHolder.nameTextView.text = emojifiedName
|
||||
if(proofOrField.isLeft()) {
|
||||
val identityProof = proofOrField.asLeft()
|
||||
|
||||
val emojifiedValue = CustomEmojiHelper.emojifyText(field.value, emojis, viewHolder.valueTextView)
|
||||
LinkHelper.setClickableText(viewHolder.valueTextView, emojifiedValue, null, linkListener)
|
||||
viewHolder.nameTextView.text = identityProof.provider
|
||||
viewHolder.valueTextView.text = LinkHelper.createClickableText(identityProof.username, identityProof.profileUrl)
|
||||
|
||||
viewHolder.valueTextView.movementMethod = LinkMovementMethod.getInstance()
|
||||
|
||||
if(field.verifiedAt != null) {
|
||||
viewHolder.valueTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_check_circle, 0)
|
||||
} else {
|
||||
viewHolder.valueTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0 )
|
||||
val field = proofOrField.asRight()
|
||||
val emojifiedName = CustomEmojiHelper.emojifyString(field.name, emojis, viewHolder.nameTextView)
|
||||
viewHolder.nameTextView.text = emojifiedName
|
||||
|
||||
val emojifiedValue = CustomEmojiHelper.emojifyText(field.value, emojis, viewHolder.valueTextView)
|
||||
LinkHelper.setClickableText(viewHolder.valueTextView, emojifiedValue, null, linkListener)
|
||||
|
||||
if(field.verifiedAt != null) {
|
||||
viewHolder.valueTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_check_circle, 0)
|
||||
} else {
|
||||
viewHolder.valueTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0 )
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -115,10 +115,7 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
|||
timestampInfo.append(" • ");
|
||||
|
||||
if (app.getWebsite() != null) {
|
||||
URLSpan span = new CustomURLSpan(app.getWebsite());
|
||||
|
||||
SpannableStringBuilder text = new SpannableStringBuilder(app.getName());
|
||||
text.setSpan(span, 0, app.getName().length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
CharSequence text = LinkHelper.createClickableText(app.getName(), app.getWebsite());
|
||||
timestampInfo.append(text);
|
||||
timestampInfo.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package com.keylesspalace.tusky.entity
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class IdentityProof(
|
||||
val provider: String,
|
||||
@SerializedName("provider_username") val username: String,
|
||||
@SerializedName("profile_url") val profileUrl: String
|
||||
)
|
|
@ -318,6 +318,11 @@ interface MastodonApi {
|
|||
@Query("id[]") accountIds: List<String>
|
||||
): Call<List<Relationship>>
|
||||
|
||||
@GET("api/v1/accounts/{id}/identity_proofs")
|
||||
fun identityProofs(
|
||||
@Path("id") accountId: String
|
||||
): Call<List<IdentityProof>>
|
||||
|
||||
@GET("api/v1/blocks")
|
||||
fun blocks(
|
||||
@Query("max_id") maxId: String?
|
||||
|
|
|
@ -179,6 +179,14 @@ public class LinkHelper {
|
|||
view.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
}
|
||||
|
||||
public static CharSequence createClickableText(String text, String link) {
|
||||
URLSpan span = new CustomURLSpan(link);
|
||||
|
||||
SpannableStringBuilder clickableText = new SpannableStringBuilder(text);
|
||||
clickableText.setSpan(span, 0, text.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
return clickableText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a link, depending on the settings, either in the browser or in a custom tab
|
||||
*
|
||||
|
|
|
@ -6,12 +6,11 @@ import androidx.lifecycle.ViewModel
|
|||
import com.keylesspalace.tusky.appstore.*
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.entity.Account
|
||||
import com.keylesspalace.tusky.entity.Field
|
||||
import com.keylesspalace.tusky.entity.IdentityProof
|
||||
import com.keylesspalace.tusky.entity.Relationship
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.util.Error
|
||||
import com.keylesspalace.tusky.util.Loading
|
||||
import com.keylesspalace.tusky.util.Resource
|
||||
import com.keylesspalace.tusky.util.Success
|
||||
import com.keylesspalace.tusky.util.*
|
||||
import io.reactivex.disposables.Disposable
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
|
@ -27,6 +26,14 @@ class AccountViewModel @Inject constructor(
|
|||
val accountData = MutableLiveData<Resource<Account>>()
|
||||
val relationshipData = MutableLiveData<Resource<Relationship>>()
|
||||
|
||||
private val identityProofData = MutableLiveData<List<IdentityProof>>()
|
||||
|
||||
val accountFieldData = combineOptionalLiveData(accountData, identityProofData) { accountRes, identityProofs ->
|
||||
identityProofs.orEmpty().map { Either.Left<IdentityProof, Field>(it) }
|
||||
.plus(accountRes?.data?.fields.orEmpty().map { Either.Right<IdentityProof, Field>(it) })
|
||||
}
|
||||
|
||||
|
||||
private val callList: MutableList<Call<*>> = mutableListOf()
|
||||
private val disposable: Disposable = eventHub.events
|
||||
.subscribe { event ->
|
||||
|
@ -60,6 +67,7 @@ class AccountViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onFailure(call: Call<Account>, t: Throwable) {
|
||||
Log.w(TAG, "failed obtaining account", t)
|
||||
accountData.postValue(Error())
|
||||
isDataLoading = false
|
||||
isRefreshing.postValue(false)
|
||||
|
@ -90,6 +98,7 @@ class AccountViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onFailure(call: Call<List<Relationship>>, t: Throwable) {
|
||||
Log.w(TAG, "failed obtaining relationships", t)
|
||||
relationshipData.postValue(Error())
|
||||
}
|
||||
})
|
||||
|
@ -98,6 +107,30 @@ class AccountViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun obtainIdentityProof(reload: Boolean = false) {
|
||||
if (identityProofData.value == null || reload) {
|
||||
|
||||
val call = mastodonApi.identityProofs(accountId)
|
||||
call.enqueue(object : Callback<List<IdentityProof>> {
|
||||
override fun onResponse(call: Call<List<IdentityProof>>,
|
||||
response: Response<List<IdentityProof>>) {
|
||||
val proofs = response.body()
|
||||
if (response.isSuccessful && proofs != null ) {
|
||||
identityProofData.postValue(proofs)
|
||||
} else {
|
||||
identityProofData.postValue(emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<List<IdentityProof>>, t: Throwable) {
|
||||
Log.w(TAG, "failed obtaining identity proofs", t)
|
||||
}
|
||||
})
|
||||
|
||||
callList.add(call)
|
||||
}
|
||||
}
|
||||
|
||||
fun changeFollowState() {
|
||||
val relationship = relationshipData.value?.data
|
||||
if (relationship?.following == true || relationship?.requested == true) {
|
||||
|
@ -227,6 +260,7 @@ class AccountViewModel @Inject constructor(
|
|||
return
|
||||
accountId.let {
|
||||
obtainAccount(isReload)
|
||||
obtainIdentityProof()
|
||||
if (!isSelf)
|
||||
obtainRelationship(isReload)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue