1
0
mirror of https://github.com/tateisu/SubwayTooter synced 2025-01-29 18:19:22 +01:00

profile field のverified_atがあれば表示する

This commit is contained in:
tateisu 2018-10-09 15:39:05 +09:00
parent 28c1db12e8
commit 0176f18ef5
6 changed files with 167 additions and 95 deletions

View File

@ -892,7 +892,7 @@ class ActAccountSetting
val text = decodeOptionsNoCustomEmoji.decodeEmoji(
when {
i >= fields.size -> ""
else -> fields[i].first
else -> fields[i].name
}
)
et.setText(text)
@ -905,7 +905,7 @@ class ActAccountSetting
val text = decodeOptions.decodeEmoji(
when {
i >= fields.size -> ""
else -> fields[i].second
else -> fields[i].value
}
)
et.setText(text)
@ -921,7 +921,7 @@ class ActAccountSetting
val text = decodeOptionsNoCustomEmoji.decodeEmoji(
when {
fields == null || i >= fields.size -> ""
else -> fields[i].first
else -> fields[i].name
}
)
et.setText(text)
@ -934,7 +934,7 @@ class ActAccountSetting
val text = decodeOptions.decodeHTML(
when {
fields == null || i >= fields.size -> ""
else -> fields[i].second
else -> fields[i].value
}
)
et.text = text

View File

@ -27,6 +27,7 @@ import jp.juggler.subwaytooter.api.entity.*
import jp.juggler.subwaytooter.dialog.ActionsDialog
import jp.juggler.subwaytooter.dialog.DlgConfirm
import jp.juggler.subwaytooter.span.EmojiImageSpan
import jp.juggler.subwaytooter.span.NetworkEmojiSpan
import jp.juggler.subwaytooter.table.*
import jp.juggler.subwaytooter.util.*
import jp.juggler.subwaytooter.view.*
@ -449,12 +450,45 @@ internal class ItemViewHolder(
private fun showConversationIcons(accounts : ArrayList<TootAccountRef>) {
if(accounts.isEmpty()) return
// 消えてしまったりちらついたりするので保留
// 絵文字スパンにしてもやはり消えたりちらついたりする。なんでだ。
// val density = llExtra.resources.displayMetrics.density
// val wh = (activity.avatarIconSize * 0.75f + 0.5f).toInt()
// val me = (density * 3f + 0.5f).toInt()
// val mt = (density * 3f + 0.5f).toInt()
//
// val lp = LinearLayout.LayoutParams(
// LinearLayout.LayoutParams.MATCH_PARENT,
// LinearLayout.LayoutParams.WRAP_CONTENT
// )
// lp.topMargin = mt
//
// val b = MyTextView(activity)
// b.layoutParams = lp
// b.isAllCaps = false
// llExtra.addView(b)
//
// val sb = SpannableStringBuilder()
// val invalidator = NetworkEmojiInvalidator(activity.handler, b)
// extra_invalidator_list.add(invalidator)
// for(ar in accounts) {
// val a = ar.get()
// val url = access_info.supplyBaseUrl(a.avatar_static)
// if(url?.isNotEmpty() == true) {
// if(sb.isNotEmpty()) sb.append(' ')
// val start = sb.length
// sb.append(a.acct)
// val end = sb.length
// sb.setSpan(
// NetworkEmojiSpan(url)
// , start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
// )
// }
// }
// b.text = sb
// invalidator.register(sb)
// 消えてしまったりちらついたりするので保留
//
// val llIconBar = FlexboxLayout(activity)
// val boxLp = LinearLayout.LayoutParams(
// LinearLayout.LayoutParams.MATCH_PARENT,

View File

@ -1,9 +1,11 @@
package jp.juggler.subwaytooter
import android.graphics.Color
import android.graphics.Typeface
import android.support.v4.view.ViewCompat
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.style.ForegroundColorSpan
import android.view.View
import android.widget.*
import jp.juggler.emoji.EmojiMap201709
@ -273,7 +275,7 @@ internal class ViewHolderHeaderProfile(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
val nameText = decodeOptionsNoCustomEmoji.decodeEmoji(item.first)
val nameText = decodeOptionsNoCustomEmoji.decodeEmoji(item.name)
val nameInvalidator = NetworkEmojiInvalidator(activity.handler, nameView)
nameInvalidator.register(nameText)
@ -291,7 +293,23 @@ internal class ViewHolderHeaderProfile(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
val valueText = decodeOptions.decodeHTML(item.second)
val valueText = decodeOptions.decodeHTML(item.value)
if(item.verified_at > 0L){
valueText.append('\n')
val start = valueText.length
valueText.append( activity.getString(R.string.verified_at))
valueText.append( ": ")
valueText.append(TootStatus.formatTime(activity,item.verified_at,false))
val end = valueText.length
valueText.setSpan(
ForegroundColorSpan(Color.BLACK or 0x7fbc99)
,start,end,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
val valueInvalidator = NetworkEmojiInvalidator(activity.handler, valueView)
valueInvalidator.register(valueText)
@ -301,6 +319,11 @@ internal class ViewHolderHeaderProfile(
valueView.setTextColor(c)
valueView.typeface = valueTypeface
valueView.movementMethod = MyLinkMovementMethod
if(item.verified_at > 0L){
valueView.setBackgroundColor(0x337fbc99)
}
llFields.addView(valueView)
}

View File

@ -15,6 +15,105 @@ import java.util.regex.Pattern
open class TootAccount(parser : TootParser, src : JSONObject) {
class Field(
val name :String,
val value :String,
val verified_at: Long // 0L if not verified
)
companion object {
private val log = LogCategory("TootAccount")
internal val reWhitespace:Pattern = Pattern.compile("[\\s\\t\\x0d\\x0a]+")
// host, user ,(instance)
internal val reAccountUrl :Pattern =
Pattern.compile("\\Ahttps://([A-Za-z0-9._-]+)/@([A-Za-z0-9_]+(?:@[A-Za-z0-9._-]+)?)(?:\\z|[?#])")
fun getAcctFromUrl(url:String):String?{
val m = reAccountUrl.matcher(url)
return if(m.find()){
val host = m.group(1)
val user = m.group(2).unescapeUri()
val instance = m.groupOrNull(3)?.unescapeUri()
if( instance?.isNotEmpty() == true){
"$user@$instance"
}else{
"$user@$host"
}
}else{
null
}
}
private fun parseSource(src : JSONObject?) : Source? {
src ?: return null
return try {
Source(src)
} catch(ex : Throwable) {
log.trace(ex)
log.e("parseSource failed.")
null
}
}
// Tootsearch用。URLやUriを使ってアカウントのインスタンス名を調べる
fun findHostFromUrl(acct : String?, accessHost : String?, url : String?) : String? {
// acctから調べる
if(acct != null) {
val pos = acct.indexOf('@')
if(pos != - 1) {
val host = acct.substring(pos + 1)
if(host.isNotEmpty()) return host.toLowerCase()
}
}
// accessHostから調べる
if(accessHost != null) {
return accessHost
}
// URLから調べる
if(url != null) {
try {
// たぶんどんなURLでもauthorityの部分にホスト名が来るだろう(慢心)
val host = Uri.parse(url).authority
if( host?.isNotEmpty() == true){
return host.toLowerCase()
}
log.e("findHostFromUrl: can't parse host from URL $url")
} catch(ex : Throwable) {
log.e(ex, "findHostFromUrl: can't parse host from URL $url")
}
}
return null
}
fun parseFields(src : JSONArray?) : ArrayList<Field>? {
src ?: return null
val dst = ArrayList<Field>()
for(i in 0 until src.length()) {
val item = src.optJSONObject(i) ?: continue
val name = item.parseString("name") ?: continue
val value = item.parseString("value") ?: continue
val svVerifiedAt = item.parseString("verified_at")
val verifiedAt = when(svVerifiedAt){
null -> 0L
else-> TootStatus.parseTime(svVerifiedAt)
}
dst.add( Field(name,value,verifiedAt))
}
return if(dst.isEmpty()) {
null
} else {
dst
}
}
}
//URL of the user's profile page (can be remote)
// https://mastodon.juggler.jp/@tateisu
// 疑似アカウントではnullになります
@ -76,7 +175,7 @@ open class TootAccount(parser : TootParser, src : JSONObject) {
val moved : TootAccount?
get() = movedRef?.get()
val fields : ArrayList<Pair<String, String>>?
val fields : ArrayList<Field>?
val custom_emojis : java.util.HashMap<String, CustomEmoji>?
@ -274,7 +373,7 @@ open class TootAccount(parser : TootParser, src : JSONObject) {
val note : String?
// 2.4.0 から?
val fields : ArrayList<Pair<String, String>>?
val fields : ArrayList<Field>?
init {
this.privacy = src.parseString("privacy")
@ -301,92 +400,6 @@ open class TootAccount(parser : TootParser, src : JSONObject) {
).decodeEmoji(sv)
}
companion object {
private val log = LogCategory("TootAccount")
internal val reWhitespace:Pattern = Pattern.compile("[\\s\\t\\x0d\\x0a]+")
// host, user ,(instance)
internal val reAccountUrl :Pattern =
Pattern.compile("\\Ahttps://([A-Za-z0-9._-]+)/@([A-Za-z0-9_]+(?:@[A-Za-z0-9._-]+)?)(?:\\z|[?#])")
fun getAcctFromUrl(url:String):String?{
val m = reAccountUrl.matcher(url)
return if(m.find()){
val host = m.group(1)
val user = m.group(2).unescapeUri()
val instance = m.groupOrNull(3)?.unescapeUri()
if( instance?.isNotEmpty() == true){
"$user@$instance"
}else{
"$user@$host"
}
}else{
null
}
}
private fun parseSource(src : JSONObject?) : Source? {
src ?: return null
return try {
Source(src)
} catch(ex : Throwable) {
log.trace(ex)
log.e("parseSource failed.")
null
}
}
// Tootsearch用。URLやUriを使ってアカウントのインスタンス名を調べる
fun findHostFromUrl(acct : String?, accessHost : String?, url : String?) : String? {
// acctから調べる
if(acct != null) {
val pos = acct.indexOf('@')
if(pos != - 1) {
val host = acct.substring(pos + 1)
if(host.isNotEmpty()) return host.toLowerCase()
}
}
// accessHostから調べる
if(accessHost != null) {
return accessHost
}
// URLから調べる
if(url != null) {
try {
// たぶんどんなURLでもauthorityの部分にホスト名が来るだろう(慢心)
val host = Uri.parse(url).authority
if( host?.isNotEmpty() == true){
return host.toLowerCase()
}
log.e("findHostFromUrl: can't parse host from URL $url")
} catch(ex : Throwable) {
log.e(ex, "findHostFromUrl: can't parse host from URL $url")
}
}
return null
}
fun parseFields(src : JSONArray?) : ArrayList<Pair<String, String>>? {
src ?: return null
val dst = ArrayList<Pair<String, String>>()
for(i in 0 until src.length()) {
val item = src.optJSONObject(i) ?: continue
val k = item.parseString("name") ?: continue
val v = item.parseString("value") ?: continue
dst.add(Pair(k, v))
}
return if(dst.isEmpty()) {
null
} else {
dst
}
}
}
var _orderId : EntityId? = null

View File

@ -773,5 +773,6 @@
<string name="account_tl_around_toot">周辺のアカウントTL… (Mastodon2.6以降)</string>
<string name="account_tl_around">…周辺のアカウントTL</string>
<string name="account_tl_around_of">%1$s周辺のアカウントTL</string>
<string name="verified_at">検証時刻</string>
</resources>

View File

@ -792,5 +792,6 @@
<string name="account_tl_around_toot">Account TL around this toot… (Mastodon 2.6)</string>
<string name="account_tl_around">Account timeline around …</string>
<string name="account_tl_around_of">Account timeline around %1$s</string>
<string name="verified_at">verified at</string>
</resources>