クラッシュレポート対応。リファクタ。

This commit is contained in:
tateisu 2018-01-21 01:59:38 +09:00
parent 4ab6f78121
commit ecb7b1bc75
5 changed files with 116 additions and 105 deletions

View File

@ -332,7 +332,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
// 画像のURL // 画像のURL
val uri : Uri? = data?.data ?: uriCameraImage val uri : Uri? = data?.data ?: uriCameraImage
if(uri != null) { if(uri != null) {
val type = contentResolver.getType(uri) val type :String? = contentResolver.getType(uri)
addAttachment(uri, type) addAttachment(uri, type)
} }
} }
@ -1254,7 +1254,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
} }
} }
@SuppressLint("StaticFieldLeak") private fun addAttachment(uri : Uri, mime_type : String) { @SuppressLint("StaticFieldLeak") private fun addAttachment(uri : Uri, mime_type : String?) {
if(attachment_list.size >= 4) { if(attachment_list.size >= 4) {
Utils.showToast(this, false, R.string.attachment_too_many) Utils.showToast(this, false, R.string.attachment_too_many)
@ -1268,7 +1268,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba
} }
if(mime_type.isEmpty()) { if(mime_type?.isEmpty() != false) {
Utils.showToast(this, false, R.string.mime_type_missing) Utils.showToast(this, false, R.string.mime_type_missing)
return return
} else if(! acceptable_mime_types.contains(mime_type)) { } else if(! acceptable_mime_types.contains(mime_type)) {

View File

@ -633,44 +633,34 @@ class Column(
return getIconAttrId(access_info.acct, type) return getIconAttrId(access_info.acct, type)
} }
interface StatusEntryCallback {
fun onIterate(account : SavedAccount, status : TootStatus) : Boolean
}
// ブーストやお気に入りの更新に使う。ステータスを列挙する。 // ブーストやお気に入りの更新に使う。ステータスを列挙する。
fun findStatus( fun findStatus(
target_instance : String, target_instance : String,
target_status_id : Long, target_status_id : Long,
callback : StatusEntryCallback callback : (account : SavedAccount, status : TootStatus) -> Boolean
// callback return true if rebind view required
) { ) {
if(access_info.host.equals(target_instance, ignoreCase = true)) { if(! access_info.host.equals(target_instance, ignoreCase = true)) return
var bChanged = false var bChanged = false
val status_proc = { status : TootStatus -> fun procStatus(status : TootStatus?) {
if(status != null) {
if(target_status_id == status.id) { if(target_status_id == status.id) {
if(callback.onIterate(access_info, status)) { if(callback(access_info, status)) bChanged = true
bChanged = true
}
} }
val reblog = status.reblog procStatus(status.reblog)
if(reblog != null && target_status_id == reblog.id) {
if(callback.onIterate(access_info, reblog)) {
bChanged = true
}
}
}
for(data in list_data) {
when(data) {
is TootNotification -> data.status?.let(status_proc)
is TootStatus -> status_proc(data)
}
}
if(bChanged) {
fireShowContent(reason="findStatus",reset=true)
} }
} }
for(data in list_data) {
when(data) {
is TootNotification -> procStatus(data.status)
is TootStatus -> procStatus(data)
}
}
if(bChanged) fireRebindAdapterItems()
} }
// ミュート、ブロックが成功した時に呼ばれる // ミュート、ブロックが成功した時に呼ばれる
@ -698,7 +688,7 @@ class Column(
if(tmp_list.size != list_data.size) { if(tmp_list.size != list_data.size) {
list_data.clear() list_data.clear()
list_data.addAll(tmp_list) list_data.addAll(tmp_list)
fireShowContent(reason="removeAccountInTimeline") fireShowContent(reason = "removeAccountInTimeline")
} }
} }
@ -716,7 +706,7 @@ class Column(
if(tmp_list.size != list_data.size) { if(tmp_list.size != list_data.size) {
list_data.clear() list_data.clear()
list_data.addAll(tmp_list) list_data.addAll(tmp_list)
fireShowContent(reason="removeFromMuteList") fireShowContent(reason = "removeFromMuteList")
} }
} }
} }
@ -734,7 +724,7 @@ class Column(
if(tmp_list.size != list_data.size) { if(tmp_list.size != list_data.size) {
list_data.clear() list_data.clear()
list_data.addAll(tmp_list) list_data.addAll(tmp_list)
fireShowContent(reason="removeFromBlockList") fireShowContent(reason = "removeFromBlockList")
} }
} }
@ -754,11 +744,11 @@ class Column(
if(tmp_list.size != list_data.size) { if(tmp_list.size != list_data.size) {
list_data.clear() list_data.clear()
list_data.addAll(tmp_list) list_data.addAll(tmp_list)
fireShowContent(reason="removeFollowRequest 1") fireShowContent(reason = "removeFollowRequest 1")
} }
} else { } else {
// 他のカラムでもフォロー状態の表示更新が必要 // 他のカラムでもフォロー状態の表示更新が必要
fireShowContent(reason="removeFollowRequest 2",reset=true) fireRebindAdapterItems()
} }
} }
@ -783,7 +773,7 @@ class Column(
if(tmp_list.size != list_data.size) { if(tmp_list.size != list_data.size) {
list_data.clear() list_data.clear()
list_data.addAll(tmp_list) list_data.addAll(tmp_list)
fireShowContent(reason="removeStatus") fireShowContent(reason = "removeStatus")
} }
} }
@ -796,10 +786,10 @@ class Column(
bInitialLoading = false bInitialLoading = false
max_id = "" max_id = ""
since_id = "" since_id = ""
list_data.clear() list_data.clear()
duplicate_map.clear() duplicate_map.clear()
fireShowContent(reason="removeNotifications",reset=true) fireShowContent(reason = "removeNotifications", reset = true)
PollingWorker.queueNotificationCleared(context, access_info.db_id) PollingWorker.queueNotificationCleared(context, access_info.db_id)
} }
@ -820,7 +810,7 @@ class Column(
if(tmp_list.size != list_data.size) { if(tmp_list.size != list_data.size) {
list_data.clear() list_data.clear()
list_data.addAll(tmp_list) list_data.addAll(tmp_list)
fireShowContent(reason="removeNotificationOne") fireShowContent(reason = "removeNotificationOne")
} }
} }
@ -844,7 +834,7 @@ class Column(
if(tmp_list.size != list_data.size) { if(tmp_list.size != list_data.size) {
list_data.clear() list_data.clear()
list_data.addAll(tmp_list) list_data.addAll(tmp_list)
fireShowContent(reason="onMuteAppUpdated") fireShowContent(reason = "onMuteAppUpdated")
} }
} }
@ -880,7 +870,7 @@ class Column(
if(tmp_list.size != list_data.size) { if(tmp_list.size != list_data.size) {
list_data.clear() list_data.clear()
list_data.addAll(tmp_list) list_data.addAll(tmp_list)
fireShowContent(reason="onDomainBlockChanged") fireShowContent(reason = "onDomainBlockChanged")
} }
} }
@ -945,14 +935,14 @@ class Column(
} }
internal fun fireShowContent( internal fun fireShowContent(
reason:String, reason : String,
changeList : List<AdapterChange>? = null, changeList : List<AdapterChange>? = null,
reset : Boolean = false reset : Boolean = false
) { ) {
if(! Utils.isMainThread) { if(! Utils.isMainThread) {
throw RuntimeException("fireShowContent: not on main thread.") throw RuntimeException("fireShowContent: not on main thread.")
} }
viewHolder?.showContent(reason,changeList,reset) viewHolder?.showContent(reason, changeList, reset)
} }
internal fun fireShowColumnHeader() { internal fun fireShowColumnHeader() {
@ -983,7 +973,6 @@ class Column(
viewHolder?.rebindAdapterItems() viewHolder?.rebindAdapterItems()
} }
private fun cancelLastTask() { private fun cancelLastTask() {
if(last_task != null) { if(last_task != null) {
last_task?.cancel(true) last_task?.cancel(true)
@ -1288,7 +1277,7 @@ class Column(
duplicate_map.clear() duplicate_map.clear()
list_data.clear() list_data.clear()
fireShowContent(reason="loading start",reset=true) fireShowContent(reason = "loading start", reset = true)
val task = @SuppressLint("StaticFieldLeak") val task = @SuppressLint("StaticFieldLeak")
object : AsyncTask<Void, Void, TootApiResult?>() { object : AsyncTask<Void, Void, TootApiResult?>() {
@ -1518,7 +1507,7 @@ class Column(
Utils.runOnMainThread { Utils.runOnMainThread {
if(isCancelled) return@runOnMainThread if(isCancelled) return@runOnMainThread
task_progress = s task_progress = s
fireShowContent(reason="loading progress",changeList = ArrayList()) fireShowContent(reason = "loading progress", changeList = ArrayList())
} }
} }
}) })
@ -1817,7 +1806,7 @@ class Column(
resumeStreaming(false) resumeStreaming(false)
} }
fireShowContent(reason="loading updated",reset=true) fireShowContent(reason = "loading updated", reset = true)
// 初期ロードの直後は先頭に移動する // 初期ロードの直後は先頭に移動する
viewHolder?.scrollToTop() viewHolder?.scrollToTop()
@ -2436,7 +2425,7 @@ class Column(
Utils.runOnMainThread { Utils.runOnMainThread {
if(isCancelled) return@runOnMainThread if(isCancelled) return@runOnMainThread
task_progress = s task_progress = s
fireShowContent(reason="refresh progress",changeList = ArrayList()) fireShowContent(reason = "refresh progress", changeList = ArrayList())
} }
} }
}) })
@ -2610,13 +2599,16 @@ class Column(
val error = result.error val error = result.error
if(error != null) { if(error != null) {
mRefreshLoadingError = error mRefreshLoadingError = error
fireShowContent(reason="refresh error",changeList = ArrayList()) fireShowContent(reason = "refresh error", changeList = ArrayList())
return return
} }
val list_new = duplicate_map.filterDuplicate(list_tmp) val list_new = duplicate_map.filterDuplicate(list_tmp)
if(list_new.isEmpty() ) { if(list_new.isEmpty()) {
fireShowContent(reason="refresh list_new is empty",changeList = ArrayList()) fireShowContent(
reason = "refresh list_new is empty",
changeList = ArrayList()
)
return return
} }
@ -2630,9 +2622,15 @@ class Column(
val added = list_new.size val added = list_new.size
if(bBottom) { if(bBottom) {
val changeList = listOf(AdapterChange(AdapterChangeType.RangeInsert,list_data.size,added)) val changeList = listOf(
AdapterChange(
AdapterChangeType.RangeInsert,
list_data.size,
added
)
)
list_data.addAll(list_new) list_data.addAll(list_new)
fireShowContent(reason="refresh updated bottom",changeList = changeList) fireShowContent(reason = "refresh updated bottom", changeList = changeList)
// 新着が少しだけ見えるようにスクロール位置を移動する // 新着が少しだけ見えるようにスクロール位置を移動する
if(sp != null) { if(sp != null) {
@ -2652,7 +2650,7 @@ class Column(
// 投稿後のリフレッシュなら当該投稿の位置を探す // 投稿後のリフレッシュなら当該投稿の位置を探す
var status_index = - 1 var status_index = - 1
for( i in 0 until added){ for(i in 0 until added) {
val o = list_new[i] val o = list_new[i]
if(o is TootStatus && o.id == posted_status_id) { if(o is TootStatus && o.id == posted_status_id) {
status_index = i status_index = i
@ -2660,9 +2658,10 @@ class Column(
} }
} }
val changeList = listOf(AdapterChange(AdapterChangeType.RangeInsert,0,added)) val changeList =
listOf(AdapterChange(AdapterChangeType.RangeInsert, 0, added))
list_data.addAll(0, list_new) list_data.addAll(0, list_new)
fireShowContent(reason="refresh updated head",changeList=changeList) fireShowContent(reason = "refresh updated head", changeList = changeList)
if(status_index >= 0 && refresh_after_toot == Pref.RAT_REFRESH_SCROLL) { if(status_index >= 0 && refresh_after_toot == Pref.RAT_REFRESH_SCROLL) {
// 投稿後にその投稿にスクロールする // 投稿後にその投稿にスクロールする
@ -2949,7 +2948,7 @@ class Column(
Utils.runOnMainThread { Utils.runOnMainThread {
if(isCancelled) return@runOnMainThread if(isCancelled) return@runOnMainThread
task_progress = s task_progress = s
fireShowContent(reason="gap progress",changeList = ArrayList()) fireShowContent(reason = "gap progress", changeList = ArrayList())
} }
} }
}) })
@ -3044,26 +3043,25 @@ class Column(
val error = result.error val error = result.error
if(error != null) { if(error != null) {
mRefreshLoadingError = error mRefreshLoadingError = error
fireShowContent(reason="gap error",changeList = ArrayList()) fireShowContent(reason = "gap error", changeList = ArrayList())
return return
} }
val position = list_data.indexOf(gap) val position = list_data.indexOf(gap)
if(position == - 1) { if(position == - 1) {
log.d("gap not found..") log.d("gap not found..")
fireShowContent(reason="gap not found",changeList = ArrayList()) fireShowContent(reason = "gap not found", changeList = ArrayList())
return return
} }
val list_tmp = this.list_tmp val list_tmp = this.list_tmp
if(list_tmp == null) { if(list_tmp == null) {
fireShowContent(reason="gap list_tmp is null",changeList = ArrayList()) fireShowContent(reason = "gap list_tmp is null", changeList = ArrayList())
return return
} }
// 0個でもギャップを消すために以下の処理を続ける // 0個でもギャップを消すために以下の処理を続ける
val list_new = duplicate_map.filterDuplicate(list_tmp) val list_new = duplicate_map.filterDuplicate(list_tmp)
// idx番目の要素がListViewのtopから何ピクセル下にあるか // idx番目の要素がListViewのtopから何ピクセル下にあるか
@ -3088,11 +3086,11 @@ class Column(
list_data.addAll(position, list_new) list_data.addAll(position, list_new)
val changeList = ArrayList<AdapterChange>() val changeList = ArrayList<AdapterChange>()
changeList.add(AdapterChange( AdapterChangeType.RangeRemove,position)) changeList.add(AdapterChange(AdapterChangeType.RangeRemove, position))
if( added > 0 ){ if(added > 0) {
changeList.add(AdapterChange(AdapterChangeType.RangeInsert,position,added)) changeList.add(AdapterChange(AdapterChangeType.RangeInsert, position, added))
} }
fireShowContent(reason="gap updated",changeList = changeList) fireShowContent(reason = "gap updated", changeList = changeList)
if(holder != null) { if(holder != null) {
if(restore_idx >= 0) { if(restore_idx >= 0) {
@ -3215,7 +3213,7 @@ class Column(
startRefresh(true, false, - 1L, - 1) startRefresh(true, false, - 1L, - 1)
} else if(isSearchColumn) { } else if(isSearchColumn) {
// 検索カラムはリフレッシュもストリーミングもないが、表示開始のタイミングでリストの再描画を行いたい // 検索カラムはリフレッシュもストリーミングもないが、表示開始のタイミングでリストの再描画を行いたい
fireShowContent(reason="Column onStart isSearchColumn",reset=true) fireShowContent(reason = "Column onStart isSearchColumn", reset = true)
} else { } else {
// ギャップつきでストリーミング開始 // ギャップつきでストリーミング開始
log.d("onStart: start streaming with gap.") log.d("onStart: start streaming with gap.")
@ -3342,7 +3340,7 @@ class Column(
if(item is Long) { if(item is Long) {
if("delete" == event_type) { if("delete" == event_type) {
removeStatus(access_info, item ) removeStatus(access_info, item)
} }
return return
} else if(item is TimelineItem) { } else if(item is TimelineItem) {
@ -3465,9 +3463,9 @@ class Column(
} }
val added = list_new.size val added = list_new.size
val changeList = listOf(AdapterChange(AdapterChangeType.RangeInsert,0,added)) val changeList = listOf(AdapterChange(AdapterChangeType.RangeInsert, 0, added))
list_data.addAll(0, list_new) list_data.addAll(0, list_new)
fireShowContent(reason="mergeStreamingMessage",changeList = changeList) fireShowContent(reason = "mergeStreamingMessage", changeList = changeList)
if(holder != null) { if(holder != null) {
if(holder_sp == null) { if(holder_sp == null) {
@ -3475,7 +3473,6 @@ class Column(
log.d("mergeStreamingMessage: has VH. missing scroll position.") log.d("mergeStreamingMessage: has VH. missing scroll position.")
viewHolder?.scrollToTop() viewHolder?.scrollToTop()
} else if(holder_sp.adapterIndex == 0 && holder_sp.offset == 0) { } else if(holder_sp.adapterIndex == 0 && holder_sp.offset == 0) {
// スクロール位置が先頭なら先頭にする // スクロール位置が先頭なら先頭にする
log.d( log.d(
@ -3483,7 +3480,7 @@ class Column(
, holder_sp.adapterIndex , holder_sp.adapterIndex
, holder_sp.offset , holder_sp.offset
) )
holder.setScrollPosition(ScrollPosition(0,0)) holder.setScrollPosition(ScrollPosition(0, 0))
} else if(restore_idx < - 1) { } else if(restore_idx < - 1) {
// 可視範囲の検出に失敗 // 可視範囲の検出に失敗
log.d("mergeStreamingMessage: has VH. can't find visible range.") log.d("mergeStreamingMessage: has VH. can't find visible range.")
@ -3504,5 +3501,4 @@ class Column(
} }
} }
} }

View File

@ -156,7 +156,7 @@ internal class ItemListAdapter(
new_list.addAll(column.list_data) new_list.addAll(column.list_data)
when { when {
// 変更リストが指定された場合はヘッダ部分とリスト要素を通知する // 変更リストが指定された場合はヘッダ部分と変更部分を通知する
changeList != null -> { changeList != null -> {
log.d("notifyChange: changeList=${changeList.size},reason=$reason") log.d("notifyChange: changeList=${changeList.size},reason=$reason")

View File

@ -152,15 +152,18 @@ object Action_Toot {
for(column in App1.getAppState(activity).column_list) { for(column in App1.getAppState(activity).column_list) {
column.findStatus(access_info.host, new_status.id, object : Column.StatusEntryCallback { column.findStatus(access_info.host, new_status.id){ account,status ->
override fun onIterate(account : SavedAccount, status : TootStatus) : Boolean {
status.favourites_count = new_status.favourites_count // 同タンス別アカウントでもカウントは変化する
if(access_info.acct.equals(account.acct, ignoreCase = true)) { status.favourites_count = new_status.favourites_count
status.favourited = new_status.favourited
} if(access_info.acct == account.acct ) {
return true // 同アカウントならfav状態を変化させる
status.favourited = new_status.favourited
} }
})
true
}
} }
if(callback != null) callback() if(callback != null) callback()
@ -328,15 +331,17 @@ object Action_Toot {
} }
for(column in App1.getAppState(activity).column_list) { for(column in App1.getAppState(activity).column_list) {
column.findStatus(access_info.host, new_status.id, object : Column.StatusEntryCallback { column.findStatus(access_info.host, new_status.id){ account, status ->
override fun onIterate(account : SavedAccount, status : TootStatus) : Boolean {
status.reblogs_count = new_status.reblogs_count // 同タンス別アカウントでもカウントは変化する
if(access_info.acct.equals(account.acct, ignoreCase = true)) { status.reblogs_count = new_status.reblogs_count
status.reblogged = new_status.reblogged
} if(access_info.acct == account.acct ) {
return true // 同アカウントならreblog状態を変化させる
status.reblogged = new_status.reblogged
} }
}) true
}
} }
if(callback != null) callback() if(callback != null) callback()
} }
@ -621,13 +626,15 @@ object Action_Toot {
// cancelled. // cancelled.
} }
new_status != null -> for(column in App1.getAppState(activity).column_list) { new_status != null ->{
column.findStatus(access_info.host, new_status.id, object : Column.StatusEntryCallback { for(column in App1.getAppState(activity).column_list) {
override fun onIterate(account : SavedAccount, status : TootStatus) : Boolean { if( access_info.acct == column.access_info.acct){
status.pinned = bSet column.findStatus(access_info.host, new_status.id){_,status->
return true status.pinned = bSet
true
}
} }
}) }
} }
else -> Utils.showToast(activity, true, result.error) else -> Utils.showToast(activity, true, result.error)
} }
@ -745,14 +752,12 @@ object Action_Toot {
val ls = local_status val ls = local_status
if(ls != null) { if(ls != null) {
for(column in App1.getAppState(activity).column_list) { for(column in App1.getAppState(activity).column_list) {
column.findStatus(access_info.host, ls.id, object : Column.StatusEntryCallback { if(access_info.acct == column.access_info.acct ) {
override fun onIterate(account : SavedAccount, status : TootStatus) : Boolean { column.findStatus(access_info.host, ls.id) { _, status ->
if(access_info.acct.equals(account.acct, ignoreCase = true)) { status.muted = bMute
status.muted = bMute true
}
return true
} }
}) }
} }
Utils.showToast(activity, true, if(bMute) R.string.mute_succeeded else R.string.unmute_succeeded) Utils.showToast(activity, true, if(bMute) R.string.mute_succeeded else R.string.unmute_succeeded)
} else { } else {

View File

@ -12,10 +12,12 @@ import java.util.ArrayList
import jp.juggler.subwaytooter.App1 import jp.juggler.subwaytooter.App1
import jp.juggler.subwaytooter.Pref import jp.juggler.subwaytooter.Pref
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.span.EmojiImageSpan import jp.juggler.subwaytooter.span.EmojiImageSpan
import jp.juggler.subwaytooter.span.HighlightSpan import jp.juggler.subwaytooter.span.HighlightSpan
import jp.juggler.subwaytooter.span.NetworkEmojiSpan import jp.juggler.subwaytooter.span.NetworkEmojiSpan
import jp.juggler.subwaytooter.table.HighlightWord import jp.juggler.subwaytooter.table.HighlightWord
import java.util.regex.Pattern
object EmojiDecoder { object EmojiDecoder {
@ -228,6 +230,9 @@ object EmojiDecoder {
} }
} }
private val reNicoru = Pattern.compile("\\Anicoru\\d*\\z", Pattern.CASE_INSENSITIVE)
private val reHohoemi = Pattern.compile("\\Ahohoemi\\d*\\z", Pattern.CASE_INSENSITIVE)
fun decodeEmoji( fun decodeEmoji(
context : Context, s : String, options : DecodeOptions context : Context, s : String, options : DecodeOptions
) : Spannable { ) : Spannable {
@ -271,7 +276,12 @@ object EmojiDecoder {
} }
} }
builder.addUnicodeString(part) when {
reHohoemi.matcher(name).find() -> builder.addImageSpan(part, R.drawable.emoji_hohoemi)
reNicoru.matcher(name).find() -> builder.addImageSpan(part, R.drawable.emoji_nicoru)
else -> builder.addUnicodeString(part)
}
} }
}) })