会話ビューでエラーがあればトーストではなくカラム内部に表示する。

疑似アカウントのカラムはサーバからフィルタ設定を読まない。
カスタム絵文字描画時に画像のアスペクト比を維持する。
This commit is contained in:
tateisu 2018-08-05 03:07:55 +09:00
parent 881a9fda46
commit fc5933f573
11 changed files with 134 additions and 58 deletions

View File

@ -416,6 +416,7 @@ class Column(
internal var mInitialLoadingError : String = ""
internal var mRefreshLoadingError : String = ""
internal var mRefreshLoadingErrorTime : Long = 0L
internal var task_progress : String? = null
@ -1901,8 +1902,8 @@ class Column(
)
//
} else {
showToast(context, true, "TootContext parse failed.")
this.list_tmp = addOne(this.list_tmp, target_status)
this.list_tmp = addOne(this.list_tmp, TootMessageHolder(context.getString(R.string.toot_context_parse_failed)))
}
// カードを取得する
@ -2935,6 +2936,7 @@ class Column(
val error = result.error
if(error != null) {
mRefreshLoadingError = error
mRefreshLoadingErrorTime = SystemClock.elapsedRealtime()
fireShowContent(reason = "refresh error", changeList = ArrayList())
return
}
@ -3938,6 +3940,7 @@ class Column(
}
private fun loadFilter2(client : TootApiClient) : ArrayList<TootFilter>? {
if( access_info.isPseudo ) return null
val column_context = getFilterContext()
if(column_context == 0) return null
val result = client.request(PATH_FILTERS)
@ -3993,7 +3996,6 @@ class Column(
}
private fun onFiltersChanged2(filterList : ArrayList<TootFilter>) {
val newFilter = encodeFilterTree(filterList) ?: return
this.muted_word2 = newFilter
checkFiltersForListData(newFilter)

View File

@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.net.Uri
import android.os.AsyncTask
import android.os.SystemClock
import android.support.v4.view.ViewCompat
import android.text.Editable
import android.text.TextWatcher
@ -63,6 +64,8 @@ class ColumnViewHolder(
val heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
var lastRefreshError :String =""
var lastRefreshErrorShown :Long = 0L
}
var column : Column? = null
@ -420,15 +423,6 @@ class ColumnViewHolder(
val status_adapter = ItemListAdapter(activity, column, this, bSimpleList)
this.status_adapter = status_adapter
// status_adapter.header = when(column.column_type) {
// Column.TYPE_PROFILE -> ViewHolderHeaderProfile(activity, column, listView)
// Column.TYPE_SEARCH -> ViewHolderHeaderSearch(activity, column, listView, activity.getString(R.string.search_desc_mastodon_api))
// Column.TYPE_SEARCH_MSP -> ViewHolderHeaderSearch(activity, column, listView, getSearchDesc(R.raw.search_desc_msp_en, R.raw.search_desc_msp_ja))
// Column.TYPE_SEARCH_TS -> ViewHolderHeaderSearch(activity, column, listView, getSearchDesc(R.raw.search_desc_ts_en, R.raw.search_desc_ts_ja))
// Column.TYPE_INSTANCE_INFORMATION -> ViewHolderHeaderInstance(activity, column, listView)
// else -> null
// }
val isNotificationColumn = column.column_type == Column.TYPE_NOTIFICATIONS
// 添付メディアや正規表現のフィルタ
@ -1041,15 +1035,26 @@ class ColumnViewHolder(
if(! column.bRefreshLoading) {
refreshLayout.isRefreshing = false
val refreshError = column.mRefreshLoadingError
val refreshErrorTime = column.mRefreshLoadingErrorTime
if(refreshError.isNotEmpty()) {
showToast(activity, true, refreshError)
showRefreshError(refreshError,refreshErrorTime)
column.mRefreshLoadingError = ""
}
}
proc_restoreScrollPosition.run()
}
private fun showRefreshError(refreshError:String,refreshErrorTime:Long){
// 同じメッセージを連投しない
// if( refreshError == lastRefreshError && refreshErrorTime <= lastRefreshErrorShown + 300000L ){
// return
// }
lastRefreshError = refreshError
lastRefreshErrorShown = SystemClock.elapsedRealtime()
showToast(activity, true, refreshError)
}
private fun saveScrollPosition() {
val column = this.column
when {

View File

@ -6,6 +6,7 @@ import android.os.SystemClock
import android.support.v4.content.ContextCompat
import android.support.v4.view.ViewCompat
import android.support.v7.app.AlertDialog
import android.support.v7.widget.RecyclerView
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.Spanned
@ -44,6 +45,8 @@ internal class ItemViewHolder(
companion object {
private val log = LogCategory("ItemViewHolder")
}
val viewRoot : View
@ -187,7 +190,7 @@ internal class ItemViewHolder(
llTrendTag.setOnClickListener(this)
llTrendTag.setOnLongClickListener(this)
llFilter.setOnClickListener (this)
llFilter.setOnClickListener(this)
this.content_color_default = tvContent.textColors.defaultColor
@ -206,7 +209,7 @@ internal class ItemViewHolder(
tvTrendTagCount.textSize = activity.timeline_font_size_sp
tvFilterPhrase.textSize = activity.timeline_font_size_sp
}
if(! activity.notification_tl_font_size_sp.isNaN() ){
if(! activity.notification_tl_font_size_sp.isNaN()) {
tvBoosted.textSize = activity.notification_tl_font_size_sp
}
@ -243,6 +246,13 @@ internal class ItemViewHolder(
bSimpleList : Boolean,
item : TimelineItem
) {
// // LGT32で区切り線の下の余白が増えていく件の対策
// (this.viewRoot.layoutParams as? RecyclerView.LayoutParams)?.let {
// it.topMargin = 0
// it.bottomMargin = 0
// it.setDirtyInset()
// }
this.list_adapter = list_adapter
this.column = column
this.bSimpleList = bSimpleList
@ -251,7 +261,7 @@ internal class ItemViewHolder(
if(activity.timeline_font != null || activity.timeline_font_bold != null) {
val font_bold = activity.timeline_font_bold ?: activity.timeline_font
val font_normal = activity.timeline_font ?: activity.timeline_font_bold
val font_normal = activity.timeline_font ?: activity.timeline_font_bold
viewRoot.scan { v ->
try {
if(v is Button) {
@ -264,7 +274,7 @@ internal class ItemViewHolder(
v === tvTrendTagCount ||
v === tvTrendTagName ||
v === tvFilterPhrase -> font_bold
else ->font_normal
else -> font_normal
}
if(typeface != null) v.typeface = typeface
}
@ -416,7 +426,8 @@ internal class ItemViewHolder(
private fun showTrendTag(item : TootTrendTag) {
llTrendTag.visibility = View.VISIBLE
tvTrendTagName.text = "#${item.name}"
tvTrendTagDesc.text = activity.getString(R.string.people_talking, item.accountDaily,item.accountWeekly)
tvTrendTagDesc.text =
activity.getString(R.string.people_talking, item.accountDaily, item.accountWeekly)
tvTrendTagCount.text = "${item.countDaily}(${item.countWeekly})"
cvTrendTagHistory.setHistory(item.history)
}
@ -494,31 +505,31 @@ internal class ItemViewHolder(
btnSearchTag.text = domain_block.domain
}
private fun showFilter(filter : TootFilter){
private fun showFilter(filter : TootFilter) {
llFilter.visibility = View.VISIBLE
tvFilterPhrase.text = filter.phrase
val sb = StringBuffer()
//
sb.append( activity.getString(R.string.filter_context))
sb.append(activity.getString(R.string.filter_context))
.append(": ")
.append(filter.getContextNames(activity).joinToString("/"))
//
val flags = ArrayList<String>()
if( filter.irreversible ) flags.add(activity.getString(R.string.filter_irreversible))
if( filter.whole_word ) flags.add(activity.getString(R.string.filter_word_match))
if( flags.isNotEmpty() ){
if(filter.irreversible) flags.add(activity.getString(R.string.filter_irreversible))
if(filter.whole_word) flags.add(activity.getString(R.string.filter_word_match))
if(flags.isNotEmpty()) {
sb.append('\n')
.append( flags.joinToString(", "))
.append(flags.joinToString(", "))
}
//
if( filter.time_expires_at != 0L ){
if(filter.time_expires_at != 0L) {
sb.append('\n')
.append(activity.getString(R.string.filter_expires_at))
.append(": ")
.append( TootStatus.formatTime(activity,filter.time_expires_at,false))
.append(TootStatus.formatTime(activity, filter.time_expires_at, false))
}
tvFilterDetail.text = sb.toString()
}
@ -581,12 +592,12 @@ internal class ItemViewHolder(
}
private fun showStatus(activity : ActMain, status : TootStatus) {
if(status.filtered){
if(status.filtered) {
showMessageHolder(TootMessageHolder(activity.getString(R.string.filtered)))
return
}
this.status_showing = status
llStatus.visibility = View.VISIBLE
@ -1109,7 +1120,7 @@ internal class ItemViewHolder(
}
}
llFilter ->if(item is TootFilter) {
llFilter -> if(item is TootFilter) {
openFilterMenu(item)
}
@ -1441,22 +1452,22 @@ internal class ItemViewHolder(
private fun openFilterMenu(item : TootFilter) {
val ad = ActionsDialog()
ad.addAction(activity.getString(R.string.edit)){
ActKeywordFilter.open(activity,access_info,item.id)
ad.addAction(activity.getString(R.string.edit)) {
ActKeywordFilter.open(activity, access_info, item.id)
}
ad.addAction(activity.getString(R.string.delete)){
Action_Filter.delete(activity,access_info,item)
ad.addAction(activity.getString(R.string.delete)) {
Action_Filter.delete(activity, access_info, item)
}
ad.show(activity,activity.getString(R.string.filter_of,item.phrase))
ad.show(activity, activity.getString(R.string.filter_of, item.phrase))
}
/////////////////////////////////////////////////////////////////////
private fun inflate(ui : AnkoContext<Context>) = with(ui) {
verticalLayout {
// トップレベルのViewGroupのlparamsはイニシャライザ内部に置くしかないみたい
lparams(matchParent, wrapContent)
layoutParams = RecyclerView.LayoutParams(matchParent, wrapContent)
topPadding = dip(3)
bottomPadding = dip(3)
@ -2083,12 +2094,12 @@ internal class ItemViewHolder(
lparams(matchParent, wrapContent) {
}
minimumHeight = dip(40)
tvFilterPhrase = textView{
tvFilterPhrase = textView {
typeface = Typeface.DEFAULT_BOLD
}.lparams(matchParent, wrapContent)
tvFilterDetail = textView{
tvFilterDetail = textView {
textColor = Styler.getAttributeColor(context, R.attr.colorTimeSmall)
textSize = 12f // SP
}.lparams(matchParent, wrapContent)

View File

@ -508,8 +508,7 @@ object Action_User {
}
TootTaskRunner(activity).run(access_info, object : TootTask {
override fun background(client : TootApiClient) : TootApiResult? {
val result = client.request("/api/v1/suggestions/${who.id}",Request.Builder().delete())
return result
return client.request("/api/v1/suggestions/${who.id}",Request.Builder().delete())
}
override fun handleResult(result : TootApiResult?) {

View File

@ -41,7 +41,7 @@ class TootFilter( src: JSONObject) :TimelineItem() {
if( v !=null) n+= v.bit
}
}
return if(n==0) CONTEXT_ALL else n
return n
}
fun parseList(src:JSONArray?): ArrayList<TootFilter>{

View File

@ -105,15 +105,38 @@ class NetworkEmojiSpan internal constructor(private val url : String) : Replacem
log.e("draw: bitmap is null or recycled.")
return
}
val srcWidth = b.width
val srcHeight = b.height
if(srcWidth < 1 || srcHeight <1){
log.e("draw: bitmap size is too small.")
return
}
rect_src.set(0, 0, srcWidth, srcHeight )
// 絵文字の正方形のサイズ
val dstSize = scale_ratio * textPaint.textSize
// ベースラインから上下方向にずらすオフセット
val c_descent = dstSize * descent_ratio
val transY = baseline - dstSize + c_descent
val size = (0.5f + scale_ratio * textPaint.textSize).toInt()
val c_descent = (0.5f + size * descent_ratio).toInt()
val transY = baseline - size + c_descent
// 絵文字のアスペクト比から描画範囲の幅と高さを決める
val dstWidth:Float
val dstHeight:Float
val aspectSrc = srcWidth.toFloat() / srcHeight.toFloat()
if( aspectSrc >= 1f){
dstWidth = dstSize
dstHeight = dstSize /aspectSrc
}else{
dstHeight = dstSize
dstWidth = dstSize * aspectSrc
}
val dstX = (dstSize-dstWidth)/2f
val dstY = (dstSize-dstHeight)/2f
rect_dst.set(dstX,dstY,dstX+dstWidth,dstY+dstHeight)
canvas.save()
canvas.translate(x, transY.toFloat())
rect_src.set(0, 0, b.width, b.height)
rect_dst.set(0f, 0f, size.toFloat(), size.toFloat())
canvas.translate(x, transY)
canvas.drawBitmap(b, rect_src, rect_dst, mPaint)
canvas.restore()

View File

@ -4,10 +4,14 @@ import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.content.res.Resources
import android.graphics.Rect
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.support.v7.widget.RecyclerView
import android.text.Spannable
import android.text.SpannableString
import android.text.SpannableStringBuilder
@ -31,6 +35,7 @@ import java.util.regex.Pattern
import org.apache.commons.io.IOUtils
import org.json.JSONArray
import org.json.JSONObject
import java.lang.reflect.Field
import java.util.Locale
import java.util.LinkedList
@ -739,6 +744,28 @@ fun View.showKeyboard() {
}
}
fun getPrivateField( clazz: Class<*> ,name:String) : Field? {
return try{
clazz.getDeclaredField(name).apply{
isAccessible = true
}
}catch(_:Throwable){
null
}
}
private val RVLP_Clazz = RecyclerView.LayoutParams::class.java
private val RVLP_mDecorInsets = getPrivateField(RVLP_Clazz,"mDecorInsets")
private val RVLP_mInsetsDirty = getPrivateField(RVLP_Clazz,"mInsetsDirty")
fun RecyclerView.LayoutParams.setDirtyInset() {
val rect = (RVLP_mDecorInsets?.get(this) as? Rect) ?: return
if(rect.bottom != 0){
rect.set(0,0,0,0)
RVLP_mInsetsDirty?.setBoolean(this, true)
}
}
////////////////////////////////////////////////////////////////////
// context
@ -795,3 +822,4 @@ fun showToast(context : Context, bLong : Boolean, string_id : Int, vararg args :
fun showToast(context : Context, ex : Throwable, string_id : Int, vararg args : Any) {
Utils.showToastImpl(context, true, ex.withCaption(context.resources, string_id, *args))
}

View File

@ -10,19 +10,24 @@ import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.Styler
class ListDivider(context : Context) : RecyclerView.ItemDecoration() {
companion object {
var height : Int =0
var height : Int = 0
}
private val drawable : Drawable
init {
drawable = Styler.getAttributeDrawable(context, R.attr.colorSettingDivider)
height = (context.resources.displayMetrics.density * 1f +0.5f).toInt()
height = (context.resources.displayMetrics.density * 1f + 0.5f).toInt()
}
override fun getItemOffsets(outRect : Rect, view : View, parent : RecyclerView, state : RecyclerView.State) {
override fun getItemOffsets(
outRect : Rect,
view : View,
parent : RecyclerView,
state : RecyclerView.State
) {
outRect.set(0, 0, 0, height)
}
@ -39,5 +44,5 @@ class ListDivider(context : Context) : RecyclerView.ItemDecoration() {
drawable.draw(canvas)
}
}
}

View File

@ -728,6 +728,7 @@
<string name="scroll_top_from_column_strip">Scroll to top when tapping visible column in column strip</string>
<string name="delete_suggestion">Delete from follow suggestion…</string>
<string name="delete_succeeded_confirm">The user \"%1$s\" will be removed from follow suggestion. Are you sure?</string>
<string name="toot_context_parse_failed">conversation parse failed.</string>
<!--<string name="abc_action_bar_home_description">Revenir à l\'accueil</string>-->
<!--<string name="abc_action_bar_home_description_format">%1$s, %2$s</string>-->

View File

@ -1007,5 +1007,6 @@
<string name="scroll_top_from_column_strip">カラムストリップのタップで上端にスクロール</string>
<string name="delete_suggestion">フォロー推奨から削除…</string>
<string name="delete_succeeded_confirm">ユーザ \"%1$s\" はフォロー推奨から削除されます。よろしいですか?</string>
<string name="toot_context_parse_failed">会話データのデコードに失敗</string>
</resources>

View File

@ -714,4 +714,5 @@
<string name="scroll_top_from_column_strip">Scroll to top when tapping visible column in column strip</string>
<string name="delete_suggestion">Delete from follow suggestion…</string>
<string name="delete_succeeded_confirm">The user \"%1$s\" will be removed from follow suggestion. Are you sure?</string>
<string name="toot_context_parse_failed">conversation parse failed.</string>
</resources>