会話ビューでエラーがあればトーストではなくカラム内部に表示する。
疑似アカウントのカラムはサーバからフィルタ設定を読まない。 カスタム絵文字描画時に画像のアスペクト比を維持する。
This commit is contained in:
parent
881a9fda46
commit
fc5933f573
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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?) {
|
||||
|
|
|
@ -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>{
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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>-->
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue