diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActPost.kt b/app/src/main/java/jp/juggler/subwaytooter/ActPost.kt index 434bb32e..c81aafd4 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ActPost.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/ActPost.kt @@ -332,7 +332,7 @@ class ActPost : AppCompatActivity(), View.OnClickListener, PostAttachment.Callba // 画像のURL val uri : Uri? = data?.data ?: uriCameraImage if(uri != null) { - val type = contentResolver.getType(uri) + val type :String? = contentResolver.getType(uri) 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) { 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) return } else if(! acceptable_mime_types.contains(mime_type)) { diff --git a/app/src/main/java/jp/juggler/subwaytooter/Column.kt b/app/src/main/java/jp/juggler/subwaytooter/Column.kt index 5a649f74..6338fcd2 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/Column.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/Column.kt @@ -633,44 +633,34 @@ class Column( return getIconAttrId(access_info.acct, type) } - interface StatusEntryCallback { - fun onIterate(account : SavedAccount, status : TootStatus) : Boolean - } - // ブーストやお気に入りの更新に使う。ステータスを列挙する。 fun findStatus( target_instance : String, 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)) { - - var bChanged = false - - val status_proc = { status : TootStatus -> + if(! access_info.host.equals(target_instance, ignoreCase = true)) return + + var bChanged = false + + fun procStatus(status : TootStatus?) { + if(status != null) { if(target_status_id == status.id) { - if(callback.onIterate(access_info, status)) { - bChanged = true - } + if(callback(access_info, status)) bChanged = true } - val reblog = 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) + procStatus(status.reblog) } } + + 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) { list_data.clear() list_data.addAll(tmp_list) - fireShowContent(reason="removeAccountInTimeline") + fireShowContent(reason = "removeAccountInTimeline") } } @@ -716,7 +706,7 @@ class Column( if(tmp_list.size != list_data.size) { list_data.clear() list_data.addAll(tmp_list) - fireShowContent(reason="removeFromMuteList") + fireShowContent(reason = "removeFromMuteList") } } } @@ -734,7 +724,7 @@ class Column( if(tmp_list.size != list_data.size) { list_data.clear() list_data.addAll(tmp_list) - fireShowContent(reason="removeFromBlockList") + fireShowContent(reason = "removeFromBlockList") } } @@ -754,11 +744,11 @@ class Column( if(tmp_list.size != list_data.size) { list_data.clear() list_data.addAll(tmp_list) - fireShowContent(reason="removeFollowRequest 1") + fireShowContent(reason = "removeFollowRequest 1") } } else { // 他のカラムでもフォロー状態の表示更新が必要 - fireShowContent(reason="removeFollowRequest 2",reset=true) + fireRebindAdapterItems() } } @@ -783,7 +773,7 @@ class Column( if(tmp_list.size != list_data.size) { list_data.clear() list_data.addAll(tmp_list) - fireShowContent(reason="removeStatus") + fireShowContent(reason = "removeStatus") } } @@ -796,10 +786,10 @@ class Column( bInitialLoading = false max_id = "" since_id = "" - + list_data.clear() duplicate_map.clear() - fireShowContent(reason="removeNotifications",reset=true) + fireShowContent(reason = "removeNotifications", reset = true) PollingWorker.queueNotificationCleared(context, access_info.db_id) } @@ -820,7 +810,7 @@ class Column( if(tmp_list.size != list_data.size) { list_data.clear() list_data.addAll(tmp_list) - fireShowContent(reason="removeNotificationOne") + fireShowContent(reason = "removeNotificationOne") } } @@ -844,7 +834,7 @@ class Column( if(tmp_list.size != list_data.size) { list_data.clear() list_data.addAll(tmp_list) - fireShowContent(reason="onMuteAppUpdated") + fireShowContent(reason = "onMuteAppUpdated") } } @@ -880,7 +870,7 @@ class Column( if(tmp_list.size != list_data.size) { list_data.clear() list_data.addAll(tmp_list) - fireShowContent(reason="onDomainBlockChanged") + fireShowContent(reason = "onDomainBlockChanged") } } @@ -945,14 +935,14 @@ class Column( } internal fun fireShowContent( - reason:String, + reason : String, changeList : List? = null, reset : Boolean = false ) { if(! Utils.isMainThread) { throw RuntimeException("fireShowContent: not on main thread.") } - viewHolder?.showContent(reason,changeList,reset) + viewHolder?.showContent(reason, changeList, reset) } internal fun fireShowColumnHeader() { @@ -983,7 +973,6 @@ class Column( viewHolder?.rebindAdapterItems() } - private fun cancelLastTask() { if(last_task != null) { last_task?.cancel(true) @@ -1288,7 +1277,7 @@ class Column( duplicate_map.clear() list_data.clear() - fireShowContent(reason="loading start",reset=true) + fireShowContent(reason = "loading start", reset = true) val task = @SuppressLint("StaticFieldLeak") object : AsyncTask() { @@ -1518,7 +1507,7 @@ class Column( Utils.runOnMainThread { if(isCancelled) return@runOnMainThread task_progress = s - fireShowContent(reason="loading progress",changeList = ArrayList()) + fireShowContent(reason = "loading progress", changeList = ArrayList()) } } }) @@ -1817,7 +1806,7 @@ class Column( resumeStreaming(false) } - fireShowContent(reason="loading updated",reset=true) + fireShowContent(reason = "loading updated", reset = true) // 初期ロードの直後は先頭に移動する viewHolder?.scrollToTop() @@ -2436,7 +2425,7 @@ class Column( Utils.runOnMainThread { if(isCancelled) return@runOnMainThread 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 if(error != null) { mRefreshLoadingError = error - fireShowContent(reason="refresh error",changeList = ArrayList()) + fireShowContent(reason = "refresh error", changeList = ArrayList()) return } val list_new = duplicate_map.filterDuplicate(list_tmp) - if(list_new.isEmpty() ) { - fireShowContent(reason="refresh list_new is empty",changeList = ArrayList()) + if(list_new.isEmpty()) { + fireShowContent( + reason = "refresh list_new is empty", + changeList = ArrayList() + ) return } @@ -2630,9 +2622,15 @@ class Column( val added = list_new.size 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) - fireShowContent(reason="refresh updated bottom",changeList = changeList) + fireShowContent(reason = "refresh updated bottom", changeList = changeList) // 新着が少しだけ見えるようにスクロール位置を移動する if(sp != null) { @@ -2652,7 +2650,7 @@ class Column( // 投稿後のリフレッシュなら当該投稿の位置を探す var status_index = - 1 - for( i in 0 until added){ + for(i in 0 until added) { val o = list_new[i] if(o is TootStatus && o.id == posted_status_id) { 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) - 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) { // 投稿後にその投稿にスクロールする @@ -2949,7 +2948,7 @@ class Column( Utils.runOnMainThread { if(isCancelled) return@runOnMainThread 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 if(error != null) { mRefreshLoadingError = error - fireShowContent(reason="gap error",changeList = ArrayList()) + fireShowContent(reason = "gap error", changeList = ArrayList()) return } val position = list_data.indexOf(gap) if(position == - 1) { log.d("gap not found..") - fireShowContent(reason="gap not found",changeList = ArrayList()) + fireShowContent(reason = "gap not found", changeList = ArrayList()) return } val list_tmp = this.list_tmp if(list_tmp == null) { - fireShowContent(reason="gap list_tmp is null",changeList = ArrayList()) + fireShowContent(reason = "gap list_tmp is null", changeList = ArrayList()) return } // 0個でもギャップを消すために以下の処理を続ける - val list_new = duplicate_map.filterDuplicate(list_tmp) // idx番目の要素がListViewのtopから何ピクセル下にあるか @@ -3088,11 +3086,11 @@ class Column( list_data.addAll(position, list_new) val changeList = ArrayList() - changeList.add(AdapterChange( AdapterChangeType.RangeRemove,position)) - if( added > 0 ){ - changeList.add(AdapterChange(AdapterChangeType.RangeInsert,position,added)) + changeList.add(AdapterChange(AdapterChangeType.RangeRemove, position)) + if(added > 0) { + changeList.add(AdapterChange(AdapterChangeType.RangeInsert, position, added)) } - fireShowContent(reason="gap updated",changeList = changeList) + fireShowContent(reason = "gap updated", changeList = changeList) if(holder != null) { if(restore_idx >= 0) { @@ -3215,7 +3213,7 @@ class Column( startRefresh(true, false, - 1L, - 1) } else if(isSearchColumn) { // 検索カラムはリフレッシュもストリーミングもないが、表示開始のタイミングでリストの再描画を行いたい - fireShowContent(reason="Column onStart isSearchColumn",reset=true) + fireShowContent(reason = "Column onStart isSearchColumn", reset = true) } else { // ギャップつきでストリーミング開始 log.d("onStart: start streaming with gap.") @@ -3342,7 +3340,7 @@ class Column( if(item is Long) { if("delete" == event_type) { - removeStatus(access_info, item ) + removeStatus(access_info, item) } return } else if(item is TimelineItem) { @@ -3465,9 +3463,9 @@ class Column( } 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) - fireShowContent(reason="mergeStreamingMessage",changeList = changeList) + fireShowContent(reason = "mergeStreamingMessage", changeList = changeList) if(holder != null) { if(holder_sp == null) { @@ -3475,7 +3473,6 @@ class Column( log.d("mergeStreamingMessage: has VH. missing scroll position.") viewHolder?.scrollToTop() - } else if(holder_sp.adapterIndex == 0 && holder_sp.offset == 0) { // スクロール位置が先頭なら先頭にする log.d( @@ -3483,7 +3480,7 @@ class Column( , holder_sp.adapterIndex , holder_sp.offset ) - holder.setScrollPosition(ScrollPosition(0,0)) + holder.setScrollPosition(ScrollPosition(0, 0)) } else if(restore_idx < - 1) { // 可視範囲の検出に失敗 log.d("mergeStreamingMessage: has VH. can't find visible range.") @@ -3504,5 +3501,4 @@ class Column( } } - } diff --git a/app/src/main/java/jp/juggler/subwaytooter/ItemListAdapter.kt b/app/src/main/java/jp/juggler/subwaytooter/ItemListAdapter.kt index 95b0453a..89162b66 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ItemListAdapter.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/ItemListAdapter.kt @@ -156,7 +156,7 @@ internal class ItemListAdapter( new_list.addAll(column.list_data) when { - // 変更リストが指定された場合はヘッダ部分とリスト要素を通知する + // 変更リストが指定された場合はヘッダ部分と変更部分を通知する changeList != null -> { log.d("notifyChange: changeList=${changeList.size},reason=$reason") diff --git a/app/src/main/java/jp/juggler/subwaytooter/action/Action_Toot.kt b/app/src/main/java/jp/juggler/subwaytooter/action/Action_Toot.kt index 6ca81b94..2d27d318 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/action/Action_Toot.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/action/Action_Toot.kt @@ -152,15 +152,18 @@ object Action_Toot { for(column in App1.getAppState(activity).column_list) { - column.findStatus(access_info.host, new_status.id, object : Column.StatusEntryCallback { - 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.favourited = new_status.favourited - } - return true + column.findStatus(access_info.host, new_status.id){ account,status -> + + // 同タンス別アカウントでもカウントは変化する + status.favourites_count = new_status.favourites_count + + if(access_info.acct == account.acct ) { + // 同アカウントならfav状態を変化させる + status.favourited = new_status.favourited } - }) + + true + } } if(callback != null) callback() @@ -328,15 +331,17 @@ object Action_Toot { } for(column in App1.getAppState(activity).column_list) { - column.findStatus(access_info.host, new_status.id, object : Column.StatusEntryCallback { - 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.reblogged = new_status.reblogged - } - return true + column.findStatus(access_info.host, new_status.id){ account, status -> + + // 同タンス別アカウントでもカウントは変化する + status.reblogs_count = new_status.reblogs_count + + if(access_info.acct == account.acct ) { + // 同アカウントならreblog状態を変化させる + status.reblogged = new_status.reblogged } - }) + true + } } if(callback != null) callback() } @@ -621,13 +626,15 @@ object Action_Toot { // cancelled. } - new_status != null -> for(column in App1.getAppState(activity).column_list) { - column.findStatus(access_info.host, new_status.id, object : Column.StatusEntryCallback { - override fun onIterate(account : SavedAccount, status : TootStatus) : Boolean { - status.pinned = bSet - return true + new_status != null ->{ + for(column in App1.getAppState(activity).column_list) { + if( access_info.acct == column.access_info.acct){ + column.findStatus(access_info.host, new_status.id){_,status-> + status.pinned = bSet + true + } } - }) + } } else -> Utils.showToast(activity, true, result.error) } @@ -745,14 +752,12 @@ object Action_Toot { val ls = local_status if(ls != null) { for(column in App1.getAppState(activity).column_list) { - column.findStatus(access_info.host, ls.id, object : Column.StatusEntryCallback { - override fun onIterate(account : SavedAccount, status : TootStatus) : Boolean { - if(access_info.acct.equals(account.acct, ignoreCase = true)) { - status.muted = bMute - } - return true + if(access_info.acct == column.access_info.acct ) { + column.findStatus(access_info.host, ls.id) { _, status -> + status.muted = bMute + true } - }) + } } Utils.showToast(activity, true, if(bMute) R.string.mute_succeeded else R.string.unmute_succeeded) } else { diff --git a/app/src/main/java/jp/juggler/subwaytooter/util/EmojiDecoder.kt b/app/src/main/java/jp/juggler/subwaytooter/util/EmojiDecoder.kt index 33d5472f..d3c80755 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/util/EmojiDecoder.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/util/EmojiDecoder.kt @@ -12,10 +12,12 @@ import java.util.ArrayList import jp.juggler.subwaytooter.App1 import jp.juggler.subwaytooter.Pref +import jp.juggler.subwaytooter.R import jp.juggler.subwaytooter.span.EmojiImageSpan import jp.juggler.subwaytooter.span.HighlightSpan import jp.juggler.subwaytooter.span.NetworkEmojiSpan import jp.juggler.subwaytooter.table.HighlightWord +import java.util.regex.Pattern 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( context : Context, s : String, options : DecodeOptions ) : 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) + } + } })