リアクションカラムに絵文字による絞り込み機能を追加
This commit is contained in:
parent
874411a536
commit
be0ee77ade
|
@ -207,7 +207,10 @@ object ColumnEncoder {
|
|||
dst[KEY_SEARCH_RESOLVE] = search_resolve
|
||||
}
|
||||
|
||||
ColumnType.SEARCH_MSP, ColumnType.SEARCH_TS, ColumnType.SEARCH_NOTESTOCK -> {
|
||||
ColumnType.REACTIONS,
|
||||
ColumnType.SEARCH_MSP,
|
||||
ColumnType.SEARCH_TS,
|
||||
ColumnType.SEARCH_NOTESTOCK -> {
|
||||
dst[KEY_SEARCH_QUERY] = search_query
|
||||
}
|
||||
|
||||
|
@ -328,10 +331,14 @@ object ColumnEncoder {
|
|||
search_resolve = src.optBoolean(KEY_SEARCH_RESOLVE, false)
|
||||
}
|
||||
|
||||
ColumnType.SEARCH_MSP, ColumnType.SEARCH_TS, ColumnType.SEARCH_NOTESTOCK -> search_query =
|
||||
src.optString(KEY_SEARCH_QUERY)
|
||||
ColumnType.REACTIONS,
|
||||
ColumnType.SEARCH_MSP,
|
||||
ColumnType.SEARCH_TS,
|
||||
ColumnType.SEARCH_NOTESTOCK ->
|
||||
search_query = src.optString(KEY_SEARCH_QUERY)
|
||||
|
||||
ColumnType.INSTANCE_INFORMATION -> instance_uri = src.optString(KEY_INSTANCE_URI)
|
||||
ColumnType.INSTANCE_INFORMATION ->
|
||||
instance_uri = src.optString(KEY_INSTANCE_URI)
|
||||
|
||||
ColumnType.PROFILE_DIRECTORY -> {
|
||||
instance_uri = src.optString(KEY_INSTANCE_URI)
|
||||
|
|
|
@ -705,6 +705,15 @@ fun Column.makeListTlUrl(): String {
|
|||
}
|
||||
}
|
||||
|
||||
fun Column.makeReactionsUrl(): String {
|
||||
if (isMisskey) error("misskey has no api to list your reactions.")
|
||||
val basePath = ApiPath.PATH_REACTIONS
|
||||
val list = TootReaction.decodeEmojiQuery(search_query)
|
||||
if (list.isEmpty()) return basePath
|
||||
val delm = if (basePath.contains("?")) "&" else "?"
|
||||
return "$basePath$delm${list.joinToString("&") { "emojis[]=${it.name.encodePercent()}" }}"
|
||||
}
|
||||
|
||||
fun Column.makeAntennaTlUrl(): String {
|
||||
return if (isMisskey) {
|
||||
"/api/antennas/notes"
|
||||
|
|
|
@ -700,18 +700,18 @@ enum class ColumnType(
|
|||
if (isMisskey) {
|
||||
TootApiResult("misskey has no api to list your reactions")
|
||||
} else {
|
||||
getStatusList(client, ApiPath.PATH_REACTIONS)
|
||||
getStatusList(client,column.makeReactionsUrl())
|
||||
}
|
||||
},
|
||||
|
||||
refresh = { client ->
|
||||
getStatusList(client, ApiPath.PATH_REACTIONS)
|
||||
getStatusList(client,column.makeReactionsUrl())
|
||||
},
|
||||
|
||||
gap = { client ->
|
||||
getStatusList(
|
||||
client,
|
||||
ApiPath.PATH_REACTIONS,
|
||||
column.makeReactionsUrl(),
|
||||
mastodonFilterByIdRange = false
|
||||
)
|
||||
},
|
||||
|
|
|
@ -14,6 +14,9 @@ import android.widget.*
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.flexbox.FlexWrap
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
import com.google.android.flexbox.JustifyContent
|
||||
import com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayout
|
||||
import com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayoutDirection
|
||||
import jp.juggler.subwaytooter.streaming.*
|
||||
|
@ -84,7 +87,10 @@ class ColumnViewHolder(
|
|||
|
||||
lateinit var btnSearch: ImageButton
|
||||
lateinit var btnSearchClear: ImageButton
|
||||
lateinit var btnEmojiAdd: ImageButton
|
||||
lateinit var etSearch: EditText
|
||||
lateinit var flEmoji: FlexboxLayout
|
||||
lateinit var tvEmojiDesc: TextView
|
||||
lateinit var cbResolve: CheckBox
|
||||
lateinit var etRegexFilter: EditText
|
||||
lateinit var tvRegexFilterError: TextView
|
||||
|
@ -168,6 +174,7 @@ class ColumnViewHolder(
|
|||
var bRefreshErrorWillShown = false
|
||||
|
||||
val extra_invalidator_list = ArrayList<NetworkEmojiInvalidator>()
|
||||
val emojiQueryInvalidatorList = ArrayList<NetworkEmojiInvalidator>()
|
||||
|
||||
val announcementContentInvalidator: NetworkEmojiInvalidator
|
||||
|
||||
|
@ -372,7 +379,6 @@ class ColumnViewHolder(
|
|||
// animator.supportsChangeAnimations = false
|
||||
// }
|
||||
|
||||
btnListAdd.setOnClickListener(this)
|
||||
|
||||
etListName.setOnEditorActionListener { _, actionId, _ ->
|
||||
var handled = false
|
||||
|
@ -383,54 +389,61 @@ class ColumnViewHolder(
|
|||
handled
|
||||
}
|
||||
|
||||
btnQuickFilterAll.setOnClickListener(this)
|
||||
btnQuickFilterMention.setOnClickListener(this)
|
||||
btnQuickFilterFavourite.setOnClickListener(this)
|
||||
btnQuickFilterBoost.setOnClickListener(this)
|
||||
btnQuickFilterFollow.setOnClickListener(this)
|
||||
btnQuickFilterPost.setOnClickListener(this)
|
||||
btnQuickFilterReaction.setOnClickListener(this)
|
||||
btnQuickFilterVote.setOnClickListener(this)
|
||||
|
||||
llColumnHeader.setOnClickListener(this)
|
||||
btnAnnouncements.setOnClickListener(this)
|
||||
btnColumnSetting.setOnClickListener(this)
|
||||
btnColumnReload.setOnClickListener(this)
|
||||
btnColumnClose.setOnClickListener(this)
|
||||
btnColumnClose.setOnLongClickListener(this)
|
||||
btnDeleteNotification.setOnClickListener(this)
|
||||
btnConfirmMail.setOnClickListener(this)
|
||||
|
||||
btnColor.setOnClickListener(this)
|
||||
btnLanguageFilter.setOnClickListener(this)
|
||||
|
||||
refreshLayout.setOnRefreshListener(this)
|
||||
refreshLayout.setDistanceToTriggerSync((0.5f + 20f * activity.density).toInt())
|
||||
|
||||
llRefreshError.setOnClickListener(this)
|
||||
arrayOf(
|
||||
btnAnnouncements,
|
||||
btnAnnouncementsNext,
|
||||
btnAnnouncementsPrev,
|
||||
btnColor,
|
||||
btnColumnClose,
|
||||
btnColumnReload,
|
||||
btnColumnSetting,
|
||||
btnConfirmMail,
|
||||
btnDeleteNotification,
|
||||
btnEmojiAdd,
|
||||
btnLanguageFilter,
|
||||
btnListAdd,
|
||||
btnQuickFilterAll,
|
||||
btnQuickFilterBoost,
|
||||
btnQuickFilterFavourite,
|
||||
btnQuickFilterFollow,
|
||||
btnQuickFilterMention,
|
||||
btnQuickFilterPost,
|
||||
btnQuickFilterReaction,
|
||||
btnQuickFilterVote,
|
||||
btnSearch,
|
||||
btnSearchClear,
|
||||
llColumnHeader,
|
||||
llRefreshError,
|
||||
|
||||
btnAnnouncementsPrev.setOnClickListener(this)
|
||||
btnAnnouncementsNext.setOnClickListener(this)
|
||||
).forEach { it.setOnClickListener(this) }
|
||||
|
||||
cbDontCloseColumn.setOnCheckedChangeListener(this)
|
||||
cbRemoteOnly.setOnCheckedChangeListener(this)
|
||||
cbWithAttachment.setOnCheckedChangeListener(this)
|
||||
cbWithHighlight.setOnCheckedChangeListener(this)
|
||||
cbDontShowBoost.setOnCheckedChangeListener(this)
|
||||
cbDontShowFollow.setOnCheckedChangeListener(this)
|
||||
cbDontShowFavourite.setOnCheckedChangeListener(this)
|
||||
cbDontShowReply.setOnCheckedChangeListener(this)
|
||||
cbDontShowReaction.setOnCheckedChangeListener(this)
|
||||
cbDontShowVote.setOnCheckedChangeListener(this)
|
||||
cbDontShowNormalToot.setOnCheckedChangeListener(this)
|
||||
cbDontShowNonPublicToot.setOnCheckedChangeListener(this)
|
||||
cbInstanceLocal.setOnCheckedChangeListener(this)
|
||||
cbDontStreaming.setOnCheckedChangeListener(this)
|
||||
cbDontAutoRefresh.setOnCheckedChangeListener(this)
|
||||
cbHideMediaDefault.setOnCheckedChangeListener(this)
|
||||
cbSystemNotificationNotRelated.setOnCheckedChangeListener(this)
|
||||
cbEnableSpeech.setOnCheckedChangeListener(this)
|
||||
cbOldApi.setOnCheckedChangeListener(this)
|
||||
|
||||
btnColumnClose.setOnLongClickListener(this)
|
||||
|
||||
arrayOf(
|
||||
cbDontAutoRefresh,
|
||||
cbDontCloseColumn,
|
||||
cbDontShowBoost,
|
||||
cbDontShowFavourite,
|
||||
cbDontShowFollow,
|
||||
cbDontShowNonPublicToot,
|
||||
cbDontShowNormalToot,
|
||||
cbDontShowReaction,
|
||||
cbDontShowReply,
|
||||
cbDontShowVote,
|
||||
cbDontStreaming,
|
||||
cbEnableSpeech,
|
||||
cbHideMediaDefault,
|
||||
cbInstanceLocal,
|
||||
cbOldApi,
|
||||
cbRemoteOnly,
|
||||
cbSystemNotificationNotRelated,
|
||||
cbWithAttachment,
|
||||
cbWithHighlight,
|
||||
).forEach { it.setOnCheckedChangeListener(this) }
|
||||
|
||||
if (Pref.bpMoveNotificationsQuickFilter(activity.pref)) {
|
||||
(svQuickFilter.parent as? ViewGroup)?.removeView(svQuickFilter)
|
||||
|
@ -455,6 +468,7 @@ class ColumnViewHolder(
|
|||
tvColumnContext.textSize = acctSize
|
||||
tvColumnStatus.textSize = acctSize
|
||||
tvColumnIndex.textSize = acctSize
|
||||
tvEmojiDesc.textSize = acctSize
|
||||
}
|
||||
|
||||
initLoadingTextView()
|
||||
|
@ -482,8 +496,6 @@ class ColumnViewHolder(
|
|||
btnColumnClose.layoutParams.height = wh
|
||||
btnColumnClose.setPaddingRelative(pad, pad, pad, pad)
|
||||
|
||||
btnSearch.setOnClickListener(this)
|
||||
btnSearchClear.setOnClickListener(this)
|
||||
etSearch.setOnEditorActionListener(TextView.OnEditorActionListener { _, actionId, _ ->
|
||||
if (!binding_busy) {
|
||||
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||
|
@ -1076,6 +1088,7 @@ class ColumnViewHolder(
|
|||
isBaselineAligned = false
|
||||
gravity = Gravity.CENTER
|
||||
|
||||
|
||||
etSearch = editText {
|
||||
id = View.generateViewId()
|
||||
imeOptions = EditorInfo.IME_ACTION_SEARCH
|
||||
|
@ -1086,6 +1099,25 @@ class ColumnViewHolder(
|
|||
weight = 1f
|
||||
}
|
||||
|
||||
flEmoji = flexboxLayout {
|
||||
flexWrap = FlexWrap.WRAP
|
||||
justifyContent = JustifyContent.FLEX_START
|
||||
}.lparams(0, wrapContent) {
|
||||
weight = 1f
|
||||
}
|
||||
|
||||
|
||||
btnEmojiAdd = imageButton {
|
||||
backgroundResource = R.drawable.btn_bg_transparent_round6dp
|
||||
contentDescription = context.getString(R.string.add)
|
||||
imageResource = R.drawable.ic_add
|
||||
imageTintList = ColorStateList.valueOf(
|
||||
context.attrColor(R.attr.colorVectorDrawable)
|
||||
)
|
||||
}.lparams(dip(40), dip(40)) {
|
||||
startMargin = dip(4)
|
||||
}
|
||||
|
||||
btnSearchClear = imageButton {
|
||||
backgroundResource = R.drawable.btn_bg_transparent_round6dp
|
||||
contentDescription = context.getString(R.string.clear)
|
||||
|
@ -1113,6 +1145,12 @@ class ColumnViewHolder(
|
|||
text = context.getString(R.string.resolve_non_local_account)
|
||||
}.lparams(wrapContent, wrapContent) // チェックボックスの余白はタッチ判定外
|
||||
|
||||
tvEmojiDesc = textView {
|
||||
text = context.getString(R.string.long_tap_to_delete)
|
||||
textColor = context.attrColor(R.attr.colorColumnHeaderPageNumber)
|
||||
textSize = 12f
|
||||
}.lparams(wrapContent, wrapContent)
|
||||
|
||||
} // end of search bar
|
||||
|
||||
llListList = linearLayout {
|
||||
|
|
|
@ -6,10 +6,7 @@ import jp.juggler.subwaytooter.action.Action_Account
|
|||
import jp.juggler.subwaytooter.action.Action_List
|
||||
import jp.juggler.subwaytooter.action.Action_Notification
|
||||
import jp.juggler.subwaytooter.api.entity.TootAnnouncement
|
||||
import jp.juggler.util.hideKeyboard
|
||||
import jp.juggler.util.isCheckedNoAnime
|
||||
import jp.juggler.util.showToast
|
||||
import jp.juggler.util.withCaption
|
||||
import jp.juggler.util.*
|
||||
import java.util.regex.Pattern
|
||||
|
||||
fun ColumnViewHolder.onListListUpdated() {
|
||||
|
@ -193,23 +190,28 @@ fun ColumnViewHolder.onClickImpl(v: View?) {
|
|||
etSearch.hideKeyboard()
|
||||
etSearch.setText(column.search_query)
|
||||
cbResolve.isCheckedNoAnime = column.search_resolve
|
||||
}else if(column.type == ColumnType.REACTIONS){
|
||||
updateReactionQueryView()
|
||||
}
|
||||
refreshLayout.isRefreshing = false
|
||||
column.startLoading()
|
||||
}
|
||||
|
||||
btnSearch -> {
|
||||
etSearch.hideKeyboard()
|
||||
column.search_query = etSearch.text.toString().trim { it <= ' ' }
|
||||
column.search_resolve = cbResolve.isChecked
|
||||
if( column.isSearchColumn){
|
||||
etSearch.hideKeyboard()
|
||||
column.search_query = etSearch.text.toString().trim { it <= ' ' }
|
||||
column.search_resolve = cbResolve.isChecked
|
||||
}
|
||||
activity.app_state.saveColumnList()
|
||||
column.startLoading()
|
||||
}
|
||||
|
||||
btnSearchClear -> {
|
||||
etSearch.setText("")
|
||||
column.search_query = ""
|
||||
column.search_resolve = cbResolve.isChecked
|
||||
etSearch.setText("")
|
||||
flEmoji.removeAllViews()
|
||||
activity.app_state.saveColumnList()
|
||||
column.startLoading()
|
||||
}
|
||||
|
@ -279,7 +281,10 @@ fun ColumnViewHolder.onClickImpl(v: View?) {
|
|||
|
||||
btnConfirmMail -> {
|
||||
Action_Account.resendConfirmMail(activity, column.access_info)
|
||||
}
|
||||
|
||||
btnEmojiAdd ->{
|
||||
addEmojiQuery()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,6 +139,16 @@ fun ColumnViewHolder.onPageCreate(column: Column, page_idx: Int, page_count: Int
|
|||
|
||||
|
||||
|
||||
for (invalidator in emojiQueryInvalidatorList) {
|
||||
invalidator.register(null)
|
||||
}
|
||||
emojiQueryInvalidatorList.clear()
|
||||
|
||||
for (invalidator in extra_invalidator_list) {
|
||||
invalidator.register(null)
|
||||
}
|
||||
extra_invalidator_list.clear()
|
||||
|
||||
cbDontCloseColumn.isCheckedNoAnime = column.dont_close
|
||||
cbRemoteOnly.isCheckedNoAnime = column.remote_only
|
||||
cbWithAttachment.isCheckedNoAnime = column.with_attachment
|
||||
|
@ -193,12 +203,34 @@ fun ColumnViewHolder.onPageCreate(column: Column, page_idx: Int, page_count: Int
|
|||
|
||||
btnDeleteNotification.vg(column.isNotificationColumn)
|
||||
|
||||
llSearch.vg(column.isSearchColumn)?.let {
|
||||
btnSearchClear.vg(Pref.bpShowSearchClear(activity.pref))
|
||||
when {
|
||||
column.isSearchColumn -> {
|
||||
llSearch.vg(true)
|
||||
|
||||
flEmoji.vg(false)
|
||||
tvEmojiDesc.vg(false)
|
||||
btnEmojiAdd.vg(false)
|
||||
|
||||
etSearch.vg(true)
|
||||
btnSearchClear.vg(Pref.bpShowSearchClear(activity.pref))
|
||||
cbResolve.vg(column.type == ColumnType.SEARCH)
|
||||
}
|
||||
column.type == ColumnType.REACTIONS -> {
|
||||
llSearch.vg(true)
|
||||
|
||||
flEmoji.vg(true)
|
||||
tvEmojiDesc.vg(true)
|
||||
btnEmojiAdd.vg(true)
|
||||
|
||||
etSearch.vg(false)
|
||||
btnSearchClear.vg(false)
|
||||
cbResolve.vg(false)
|
||||
}
|
||||
|
||||
else -> llSearch.vg(false)
|
||||
}
|
||||
|
||||
llListList.vg(column.type == ColumnType.LIST_LIST)
|
||||
cbResolve.vg(column.type == ColumnType.SEARCH)
|
||||
|
||||
llHashtagExtra.vg(column.hasHashtagExtra)
|
||||
etHashtagExtraAny.setText(column.hashtag_any)
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
package jp.juggler.subwaytooter
|
||||
|
||||
import android.widget.Button
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
import jp.juggler.subwaytooter.api.entity.TootReaction
|
||||
import jp.juggler.subwaytooter.dialog.EmojiPicker
|
||||
import jp.juggler.subwaytooter.emoji.CustomEmoji
|
||||
import jp.juggler.subwaytooter.emoji.UnicodeEmoji
|
||||
import jp.juggler.subwaytooter.util.DecodeOptions
|
||||
import jp.juggler.subwaytooter.util.NetworkEmojiInvalidator
|
||||
import jp.juggler.subwaytooter.util.minWidthCompat
|
||||
import jp.juggler.subwaytooter.util.startMargin
|
||||
import org.jetbrains.anko.allCaps
|
||||
|
||||
|
||||
|
||||
|
||||
fun ColumnViewHolder.addEmojiQuery(reaction:TootReaction? =null){
|
||||
val column = this.column?:return
|
||||
if(reaction==null){
|
||||
EmojiPicker(activity, column.access_info, closeOnSelected = true) { result ->
|
||||
val newReaction = when (val emoji = result.emoji) {
|
||||
is UnicodeEmoji -> TootReaction(name = emoji.unifiedCode)
|
||||
is CustomEmoji -> TootReaction(
|
||||
name=emoji.shortcode,
|
||||
url = emoji.url,
|
||||
static_url = emoji.static_url
|
||||
)
|
||||
}
|
||||
addEmojiQuery(newReaction)
|
||||
}.show()
|
||||
return
|
||||
}
|
||||
val list = TootReaction.decodeEmojiQuery(column.search_query).toMutableList()
|
||||
list.add(reaction)
|
||||
column.search_query = TootReaction. encodeEmojiQuery(list)
|
||||
updateReactionQueryView()
|
||||
activity.app_state.saveColumnList()
|
||||
}
|
||||
|
||||
private fun ColumnViewHolder.removeEmojiQuery(target:TootReaction?){
|
||||
target ?: return
|
||||
val list = TootReaction.decodeEmojiQuery(column?.search_query).filter { it.name != target.name }
|
||||
column?.search_query = TootReaction.encodeEmojiQuery(list)
|
||||
updateReactionQueryView()
|
||||
activity.app_state.saveColumnList()
|
||||
}
|
||||
|
||||
fun ColumnViewHolder.updateReactionQueryView() {
|
||||
val column = this.column ?: return
|
||||
|
||||
flEmoji.removeAllViews()
|
||||
|
||||
for (invalidator in emojiQueryInvalidatorList) {
|
||||
invalidator.register(null)
|
||||
}
|
||||
emojiQueryInvalidatorList.clear()
|
||||
|
||||
val options = DecodeOptions(
|
||||
activity,
|
||||
column.access_info,
|
||||
decodeEmoji = true,
|
||||
enlargeEmoji = 1.5f,
|
||||
enlargeCustomEmoji = 1.5f
|
||||
)
|
||||
|
||||
val act = this.activity // not Button(View).getActivity()
|
||||
|
||||
val buttonHeight = ActMain.boostButtonSize
|
||||
val marginBetween = (buttonHeight.toFloat() * 0.05f + 0.5f).toInt()
|
||||
|
||||
val paddingH = (buttonHeight.toFloat() * 0.1f + 0.5f).toInt()
|
||||
val paddingV = (buttonHeight.toFloat() * 0.1f + 0.5f).toInt()
|
||||
|
||||
val contentColor = column.getContentColor()
|
||||
|
||||
TootReaction.decodeEmojiQuery(column.search_query).forEachIndexed { index, reaction ->
|
||||
val ssb = reaction.toSpannableStringBuilder(options, status=null)
|
||||
|
||||
val b = Button(activity).apply {
|
||||
layoutParams = FlexboxLayout.LayoutParams(
|
||||
FlexboxLayout.LayoutParams.WRAP_CONTENT,
|
||||
buttonHeight
|
||||
).apply {
|
||||
if(index >0 ) startMargin = marginBetween
|
||||
}
|
||||
minWidthCompat = buttonHeight
|
||||
|
||||
background = ContextCompat.getDrawable(act,R.drawable.btn_bg_transparent_round6dp)
|
||||
|
||||
setTextColor(contentColor)
|
||||
setPadding(paddingH, paddingV, paddingH, paddingV)
|
||||
|
||||
text = ssb
|
||||
|
||||
allCaps = false
|
||||
tag = reaction
|
||||
|
||||
setOnLongClickListener {
|
||||
removeEmojiQuery(it.tag as? TootReaction)
|
||||
true
|
||||
}
|
||||
// カスタム絵文字の場合、アニメーション等のコールバックを処理する必要がある
|
||||
val invalidator = NetworkEmojiInvalidator(act.handler, this)
|
||||
invalidator.register(ssb)
|
||||
emojiQueryInvalidatorList.add(invalidator)
|
||||
}
|
||||
flEmoji.addView(b)
|
||||
}
|
||||
|
||||
}
|
|
@ -124,8 +124,6 @@ fun ItemViewHolder.makeReactionsView(status: TootStatus) {
|
|||
enlargeCustomEmoji = 1.5f
|
||||
)
|
||||
|
||||
var lastButton: View? = null
|
||||
|
||||
reactionSet?.forEachIndexed { index, reaction ->
|
||||
val ssb = reaction.toSpannableStringBuilder(options, status)
|
||||
.also { it.append(" ${reaction.count}") }
|
||||
|
@ -186,13 +184,8 @@ fun ItemViewHolder.makeReactionsView(status: TootStatus) {
|
|||
extra_invalidator_list.add(invalidator)
|
||||
}
|
||||
box.addView(b)
|
||||
lastButton = b
|
||||
}
|
||||
|
||||
lastButton
|
||||
?.layoutParams
|
||||
?.cast<ViewGroup.MarginLayoutParams>()
|
||||
?.endMargin = 0
|
||||
|
||||
llExtra.addView(box)
|
||||
}
|
||||
|
|
|
@ -268,7 +268,7 @@ class SideMenuAdapter(
|
|||
Action_Account.timeline(this, defaultInsertPosition, ColumnType.BOOKMARKS)
|
||||
},
|
||||
Item(icon = R.drawable.ic_face, title = R.string.fedibird_reactions) {
|
||||
Action_Account.getReactionableAccounts(this){ list->
|
||||
Action_Account.getReactionableAccounts(this,allowMisskey = false){ list->
|
||||
val columnType = ColumnType.REACTIONS
|
||||
AccountPicker.pick(
|
||||
this,
|
||||
|
|
|
@ -373,7 +373,11 @@ object Action_Account {
|
|||
}.show()
|
||||
}
|
||||
|
||||
fun getReactionableAccounts(activity:ActMain,block:(ArrayList<SavedAccount>)->Unit){
|
||||
fun getReactionableAccounts(
|
||||
activity:ActMain,
|
||||
allowMisskey:Boolean = true,
|
||||
block:(ArrayList<SavedAccount>)->Unit
|
||||
){
|
||||
TootTaskRunner(activity).run(object : TootTask {
|
||||
var list : List<SavedAccount>? = null
|
||||
override suspend fun background(client: TootApiClient): TootApiResult? {
|
||||
|
@ -381,7 +385,7 @@ object Action_Account {
|
|||
when {
|
||||
client.isApiCancelled -> false
|
||||
a.isPseudo -> false
|
||||
a.isMisskey -> true
|
||||
a.isMisskey -> allowMisskey
|
||||
else -> {
|
||||
val(ti,ri)=TootInstance.getEx(client,account=a)
|
||||
if(ti==null) {
|
||||
|
|
|
@ -1328,7 +1328,6 @@ object Action_Toot {
|
|||
} else {
|
||||
emoji.shortcode
|
||||
}
|
||||
else -> error("unknown emoji type")
|
||||
}
|
||||
addReaction(activity, column, status, newCode)
|
||||
}.show()
|
||||
|
|
|
@ -3,6 +3,7 @@ package jp.juggler.subwaytooter.api.entity
|
|||
import android.text.Spannable
|
||||
import android.text.SpannableStringBuilder
|
||||
import jp.juggler.subwaytooter.App1
|
||||
import jp.juggler.subwaytooter.ColumnViewHolder
|
||||
import jp.juggler.subwaytooter.Pref
|
||||
import jp.juggler.subwaytooter.emoji.CustomEmoji
|
||||
import jp.juggler.subwaytooter.span.NetworkEmojiSpan
|
||||
|
@ -33,7 +34,8 @@ class TootReaction(
|
|||
|
||||
// (fedibird絵文字リアクション) userストリームのemoji_reactionイベントで設定される。
|
||||
val status_id: EntityId? = null,
|
||||
) {
|
||||
|
||||
) {
|
||||
companion object {
|
||||
|
||||
fun appendDomain(name: String, domain: String?) =
|
||||
|
@ -94,32 +96,51 @@ class TootReaction(
|
|||
|
||||
val UNKNOWN = TootReaction(name = "?")
|
||||
|
||||
fun isUnicodeEmoji(code:String):Boolean =
|
||||
code.any{ it.code >= 0x7f}
|
||||
fun isUnicodeEmoji(code: String): Boolean =
|
||||
code.any { it.code >= 0x7f }
|
||||
|
||||
fun splitEmojiDomain(code:String):Pair<String?,String?>{
|
||||
fun splitEmojiDomain(code: String): Pair<String?, String?> {
|
||||
// unicode絵文字ならnull,nullを返す
|
||||
if( isUnicodeEmoji(code)) return Pair(null,null)
|
||||
if (isUnicodeEmoji(code)) return Pair(null, null)
|
||||
// Misskeyカスタム絵文字リアクションのコロンを除去
|
||||
val a = code.replace(":","")
|
||||
val a = code.replace(":", "")
|
||||
val idx = a.indexOf("@")
|
||||
return if(idx==-1) Pair(a,null) else Pair(a.substring(0,idx),a.substring(idx+1))
|
||||
return if (idx == -1) Pair(a, null) else Pair(a.substring(0, idx), a.substring(idx + 1))
|
||||
}
|
||||
|
||||
fun canReaction(
|
||||
access_info:SavedAccount,
|
||||
ti:TootInstance? =TootInstance.getCached(access_info.apiHost)
|
||||
access_info: SavedAccount,
|
||||
ti: TootInstance? = TootInstance.getCached(access_info.apiHost)
|
||||
) = when {
|
||||
access_info.isPseudo -> false
|
||||
access_info.isMisskey -> true
|
||||
else -> ti?.fedibird_capabilities?.contains("emoji_reaction") == true
|
||||
}
|
||||
|
||||
fun decodeEmojiQuery(jsonText: String?): List<TootReaction> =
|
||||
jsonText.notEmpty()?.let { src ->
|
||||
try {
|
||||
src.decodeJsonArray().objectList().map { parseFedibird(it) }
|
||||
} catch (ex: Throwable) {
|
||||
ColumnViewHolder.log.e(ex, "updateReactionQueryView: decode failed.")
|
||||
null
|
||||
}
|
||||
} ?: emptyList()
|
||||
|
||||
fun encodeEmojiQuery(src: List<TootReaction>): String =
|
||||
jsonArray {
|
||||
for (reaction in src) {
|
||||
add(reaction.jsonFedibird())
|
||||
}
|
||||
}.toString()
|
||||
|
||||
|
||||
}
|
||||
|
||||
private val isUnicodeEmoji: Boolean
|
||||
get()= isUnicodeEmoji(name)
|
||||
get() = isUnicodeEmoji(name)
|
||||
|
||||
fun splitEmojiDomain()=
|
||||
fun splitEmojiDomain() =
|
||||
splitEmojiDomain(name)
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
|
@ -177,7 +198,7 @@ class TootReaction(
|
|||
val cols = customCode.split("@", limit = 2)
|
||||
val key = cols.elementAtOrNull(0)
|
||||
val domain = cols.elementAtOrNull(1)
|
||||
if( key != null) {
|
||||
if (key != null) {
|
||||
if (domain == null || domain == "" || domain == "." || domain == accessInfo?.apDomain?.ascii) {
|
||||
// デコードオプションのアカウント情報と同じドメインの絵文字なら、
|
||||
// そのドメインの絵文字一覧を取得済みなら
|
||||
|
@ -207,6 +228,15 @@ class TootReaction(
|
|||
// unicode絵文字、もしくは :xxx: などのshortcode表現
|
||||
return EmojiDecoder.decodeEmoji(options, code)
|
||||
}
|
||||
|
||||
// リアクションカラムの絵文字絞り込み用
|
||||
fun jsonFedibird() = jsonObject {
|
||||
val (basename, domain) = splitEmojiDomain()
|
||||
put("name", basename ?: name)
|
||||
putNotNull("domain", domain)
|
||||
putNotNull("url", url)
|
||||
putNotNull("static_url", static_url)
|
||||
}
|
||||
}
|
||||
|
||||
class TootReactionSet(val isMisskey: Boolean) : LinkedList<TootReaction>() {
|
||||
|
|
|
@ -6,6 +6,7 @@ import com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayout
|
|||
import jp.juggler.subwaytooter.view.*
|
||||
import org.jetbrains.anko.custom.ankoView
|
||||
import androidx.appcompat.view.ContextThemeWrapper
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
import jp.juggler.subwaytooter.R
|
||||
|
||||
// Anko Layout中にカスタムビューを指定する為に拡張関数を定義する
|
||||
|
@ -40,3 +41,6 @@ inline fun ViewManager.recyclerView(init : RecyclerView.() -> Unit) : RecyclerVi
|
|||
}, theme = 0, init = init)
|
||||
}
|
||||
|
||||
inline fun ViewManager.flexboxLayout(init : FlexboxLayout.() -> Unit) : FlexboxLayout {
|
||||
return ankoView({ FlexboxLayout(it) }, theme = 0, init = init)
|
||||
}
|
||||
|
|
|
@ -1083,5 +1083,6 @@
|
|||
<string name="reactions">リアクション</string>
|
||||
<string name="cant_reaction_remote_custom_emoji">リモートのカスタム絵文字でリアクションできません %1$s</string>
|
||||
<string name="keep_reaction_space">リアクション表示用の空間を確保する</string>
|
||||
<string name="long_tap_to_delete">長押しで削除</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1097,4 +1097,5 @@
|
|||
<string name="reactions">Reactions</string>
|
||||
<string name="cant_reaction_remote_custom_emoji">can\'t reaction with remote custom emoji %1$s</string>
|
||||
<string name="keep_reaction_space">Keep Spacing for Reactions</string>
|
||||
<string name="long_tap_to_delete">long tap to delete</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue