v269。リアクションの表示と追加
This commit is contained in:
parent
80e6242f58
commit
4d9c9068d7
|
@ -12,8 +12,8 @@ android {
|
|||
minSdkVersion 21
|
||||
targetSdkVersion 27
|
||||
|
||||
versionCode 268
|
||||
versionName "2.6.8"
|
||||
versionCode 269
|
||||
versionName "2.6.9"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
// https://stackoverflow.com/questions/47791227/java-lang-illegalstateexception-dex-archives-setting-dex-extension-only-for
|
||||
|
|
|
@ -15,6 +15,9 @@ import android.view.Gravity
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
import com.google.android.flexbox.AlignItems
|
||||
import com.google.android.flexbox.FlexWrap
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
import jp.juggler.subwaytooter.action.*
|
||||
|
||||
import java.util.ArrayList
|
||||
|
@ -46,7 +49,6 @@ internal class ItemViewHolder(
|
|||
companion object {
|
||||
private val log = LogCategory("ItemViewHolder")
|
||||
|
||||
|
||||
}
|
||||
|
||||
val viewRoot : View
|
||||
|
@ -597,7 +599,12 @@ internal class ItemViewHolder(
|
|||
llStatus.visibility = View.VISIBLE
|
||||
|
||||
if(status.conversation_main) {
|
||||
this.viewRoot.setBackgroundColor( (Styler.getAttributeColor(activity,R.attr.colorImageButtonAccent) and 0xffffff ) or 0x20000000)
|
||||
this.viewRoot.setBackgroundColor(
|
||||
(Styler.getAttributeColor(
|
||||
activity,
|
||||
R.attr.colorImageButtonAccent
|
||||
) and 0xffffff) or 0x20000000
|
||||
)
|
||||
}
|
||||
|
||||
showStatusTime(activity, tvTime, who = status.account, status = status)
|
||||
|
@ -726,6 +733,8 @@ internal class ItemViewHolder(
|
|||
setMedia(ivMedia4, status, media_attachments, 3)
|
||||
}
|
||||
|
||||
makeReactionsView(status.reactionCounts)
|
||||
|
||||
buttons_for_status?.bind(status, (item as? TootNotification))
|
||||
|
||||
val application = status.application
|
||||
|
@ -805,11 +814,18 @@ internal class ItemViewHolder(
|
|||
}
|
||||
|
||||
// visibility
|
||||
val visIconAttrId = Styler.getVisibilityIconAttr(access_info.isMisskey,status.visibility)
|
||||
val visIconAttrId =
|
||||
Styler.getVisibilityIconAttr(access_info.isMisskey, status.visibility)
|
||||
if(R.attr.ic_public != visIconAttrId) {
|
||||
if(sb.isNotEmpty()) sb.append('\u200B')
|
||||
val start = sb.length
|
||||
sb.append(Styler.getVisibilityString(activity,access_info.isMisskey,status.visibility))
|
||||
sb.append(
|
||||
Styler.getVisibilityString(
|
||||
activity,
|
||||
access_info.isMisskey,
|
||||
status.visibility
|
||||
)
|
||||
)
|
||||
val end = sb.length
|
||||
val iconResId = Styler.getAttributeResourceId(activity, visIconAttrId)
|
||||
sb.setSpan(
|
||||
|
@ -1009,8 +1025,19 @@ internal class ItemViewHolder(
|
|||
|
||||
ivThumbnail -> status_account?.let { whoRef ->
|
||||
when {
|
||||
access_info.isMisskey -> Action_User.profileLocal(activity, pos, access_info, whoRef.get())
|
||||
access_info.isPseudo -> DlgContextMenu(activity, column, whoRef, null, notification).show()
|
||||
access_info.isMisskey -> Action_User.profileLocal(
|
||||
activity,
|
||||
pos,
|
||||
access_info,
|
||||
whoRef.get()
|
||||
)
|
||||
access_info.isPseudo -> DlgContextMenu(
|
||||
activity,
|
||||
column,
|
||||
whoRef,
|
||||
null,
|
||||
notification
|
||||
).show()
|
||||
else -> Action_User.profileLocal(activity, pos, access_info, whoRef.get())
|
||||
}
|
||||
}
|
||||
|
@ -1362,6 +1389,148 @@ internal class ItemViewHolder(
|
|||
|
||||
}
|
||||
|
||||
private fun makeReactionsView(reactionsCount : HashMap<String, Int>?) {
|
||||
|
||||
if( ! access_info.isMisskey) return
|
||||
|
||||
// reactionsCount?:return
|
||||
// MisskeyReaction.values().find {
|
||||
// val c = reactionsCount[it.shortcode]
|
||||
// c != null && c > 0
|
||||
// } ?: return
|
||||
|
||||
|
||||
|
||||
val density = activity.resources.displayMetrics.density
|
||||
val compoundPadding = (density * 0.5f + 0.5f).toInt()
|
||||
val endMargin = (density * 3f + 0.5f).toInt()
|
||||
val paddingHorizontal = (density * 4f + 0.5f).toInt()
|
||||
val btnHeight = (density * 40f + 0.5f).toInt()
|
||||
|
||||
val box = FlexboxLayout(activity)
|
||||
val boxLp = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
box.layoutParams = boxLp
|
||||
boxLp.topMargin = (0.5f + density * 3f).toInt()
|
||||
box.flexWrap = FlexWrap.WRAP
|
||||
box.alignItems = AlignItems.FLEX_START
|
||||
|
||||
// +ボタン
|
||||
run{
|
||||
val b = ImageButton(activity)
|
||||
val blp = FlexboxLayout.LayoutParams(
|
||||
btnHeight,
|
||||
btnHeight
|
||||
)
|
||||
b.layoutParams = blp
|
||||
blp.endMargin = endMargin
|
||||
b.background = ContextCompat.getDrawable(
|
||||
activity,
|
||||
R.drawable.btn_bg_transparent
|
||||
)
|
||||
b.minimumWidth = (density * 40f + 0.5f).toInt()
|
||||
b.contentDescription = activity.getString(R.string.reaction_add)
|
||||
b.imageResource = Styler.getAttributeResourceId(activity,R.attr.ic_add)
|
||||
b.padding= paddingHorizontal
|
||||
b.setOnClickListener{ addReaction(status_showing,null) }
|
||||
box.addView(b)
|
||||
}
|
||||
var lastButton : Button? = null
|
||||
for(mr in MisskeyReaction.values()) {
|
||||
val count = reactionsCount?.get(mr.shortcode)
|
||||
if(count == null || count <= 0) continue
|
||||
val b = Button(activity)
|
||||
val blp = FlexboxLayout.LayoutParams(
|
||||
FlexboxLayout.LayoutParams.WRAP_CONTENT,
|
||||
btnHeight
|
||||
)
|
||||
b.layoutParams = blp
|
||||
blp.endMargin = endMargin
|
||||
b.background = ContextCompat.getDrawable(
|
||||
activity,
|
||||
R.drawable.btn_bg_transparent
|
||||
)
|
||||
b.minWidthCompat = (density * 40f + 0.5f).toInt()
|
||||
b.text = count.toString()
|
||||
b.compoundDrawablePadding = compoundPadding
|
||||
b.padding= paddingHorizontal
|
||||
b.tag = mr.shortcode
|
||||
b.setOnClickListener{addReaction(status_showing,it.tag as? String) }
|
||||
val d = ContextCompat.getDrawable(activity, mr.drawableId)
|
||||
b.setCompoundDrawablesRelativeWithIntrinsicBounds(d, null, null, null)
|
||||
box.addView(b)
|
||||
lastButton = b
|
||||
}
|
||||
|
||||
if( lastButton != null ){
|
||||
val lp = lastButton.layoutParams
|
||||
if( lp is ViewGroup.MarginLayoutParams){
|
||||
lp.endMargin = 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
llExtra.addView(box)
|
||||
}
|
||||
|
||||
private fun addReaction(status:TootStatus?,code : String?) {
|
||||
status?:return
|
||||
|
||||
if( access_info.isPseudo || !access_info.isMisskey) return
|
||||
|
||||
if(code == null ){
|
||||
val ad = ActionsDialog()
|
||||
for( mr in MisskeyReaction.values()){
|
||||
val code= mr.shortcode
|
||||
val sb = SpannableStringBuilder()
|
||||
.appendDrawableIcon(activity,mr.drawableId," ")
|
||||
.append(' ')
|
||||
.append(mr.shortcode)
|
||||
ad.addAction(sb){
|
||||
addReaction(status,code)
|
||||
}
|
||||
}
|
||||
ad.show(activity)
|
||||
return
|
||||
}
|
||||
|
||||
TootTaskRunner(activity,progress_style = TootTaskRunner.PROGRESS_NONE).run(access_info,object :TootTask{
|
||||
override fun background(client : TootApiClient) : TootApiResult? {
|
||||
val params = access_info.putMisskeyApiToken(JSONObject())
|
||||
.put("noteId",status.id.toString())
|
||||
.put("reaction",code)
|
||||
val result = client.request("/api/notes/reactions/create",params.toPostRequestBuilder())
|
||||
// 成功すると204 no content
|
||||
return result
|
||||
}
|
||||
|
||||
override fun handleResult(result : TootApiResult?) {
|
||||
result?: return
|
||||
|
||||
val error = result.error
|
||||
if( error!=null){
|
||||
showToast(activity,false,error)
|
||||
return
|
||||
}
|
||||
|
||||
if( (result.response?.code()?:-1) in 200 until 300 ){
|
||||
if( status.reactionCounts == null ){
|
||||
status.reactionCounts = HashMap()
|
||||
}
|
||||
val count = status.reactionCounts?.get(code) ?: 0
|
||||
status.reactionCounts?.put(code,count+1)
|
||||
// 1個だけ描画更新するのではなく、TLにある複数の要素をまとめて更新する
|
||||
list_adapter.notifyChange(reason = "addReaction complete", reset = true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
private fun makeEnqueteChoiceView(
|
||||
enquete : NicoEnquete,
|
||||
now : Long,
|
||||
|
|
|
@ -291,7 +291,7 @@ fun SpannableStringBuilder.appendColorShadeIcon(
|
|||
context:Context,
|
||||
drawable_id:Int,
|
||||
text:String
|
||||
){
|
||||
):SpannableStringBuilder{
|
||||
val start = this.length
|
||||
this.append(text)
|
||||
val end = this.length
|
||||
|
@ -301,4 +301,22 @@ fun SpannableStringBuilder.appendColorShadeIcon(
|
|||
end,
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
return this
|
||||
}
|
||||
|
||||
fun SpannableStringBuilder.appendDrawableIcon(
|
||||
context:Context,
|
||||
drawable_id:Int,
|
||||
text:String
|
||||
):SpannableStringBuilder{
|
||||
val start = this.length
|
||||
this.append(text)
|
||||
val end = this.length
|
||||
this.setSpan(
|
||||
EmojiImageSpan(context, drawable_id),
|
||||
start,
|
||||
end,
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
return this
|
||||
}
|
||||
|
|
|
@ -1,24 +1,28 @@
|
|||
//package jp.juggler.subwaytooter.api.entity
|
||||
//
|
||||
//enum class MisskeyReaction(val name:String,val drawableId:Int){
|
||||
//
|
||||
//
|
||||
// Like("like"),
|
||||
// Love("love"),
|
||||
// Laugh("laugh"),
|
||||
// Hmm("hmm"),
|
||||
// Surprise("surprise"),
|
||||
// Congrats("congrats"),
|
||||
// Angry("angry"),
|
||||
// Confused("confused"),
|
||||
// Rip("rip"),
|
||||
// Pudding("pudding") ;
|
||||
//
|
||||
// companion object {
|
||||
// val map: HashMap<String,MisskeyReaction> by lazy {
|
||||
// HashMap<String,MisskeyReaction>().apply {
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
package jp.juggler.subwaytooter.api.entity
|
||||
|
||||
import jp.juggler.subwaytooter.R
|
||||
|
||||
enum class MisskeyReaction(val shortcode:String,val drawableId:Int){
|
||||
|
||||
|
||||
Like("like", R.drawable.emj_1f44d),
|
||||
Love("love",R.drawable.emj_2665),
|
||||
Laugh("laugh",R.drawable.emj_1f606),
|
||||
Hmm("hmm", R.drawable.emj_1f914),
|
||||
Surprise("surprise",R.drawable.emj_1f62e),
|
||||
Congrats("congrats",R.drawable.emj_1f389),
|
||||
Angry("angry",R.drawable.emj_1f4a2),
|
||||
Confused("confused",R.drawable.emj_1f625),
|
||||
Rip("rip", R.drawable.emj_1f607),
|
||||
Pudding("pudding", R.drawable.emj_1f36e) ;
|
||||
|
||||
companion object {
|
||||
val shortcodeMap: HashMap<String,MisskeyReaction> by lazy {
|
||||
HashMap<String,MisskeyReaction>().apply {
|
||||
for( e in MisskeyReaction.values()){
|
||||
put( e.shortcode,e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -140,6 +140,8 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() {
|
|||
|
||||
var viaMobile : Boolean = false
|
||||
|
||||
var reactionCounts : HashMap<String, Int>? = null
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// 以下はentityから取得したデータではなく、アプリ内部で使う
|
||||
|
||||
|
@ -223,7 +225,6 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() {
|
|||
|
||||
// "mentionedRemoteUsers" -> "[{"uri":"https:\/\/mastodon.juggler.jp\/users\/tateisu","username":"tateisu","host":"mastodon.juggler.jp"}]"
|
||||
|
||||
|
||||
this.tags = parseMisskeyTags(src.optJSONArray("tags"))
|
||||
|
||||
this.application = parseItem(::TootApplication, parser, src.optJSONObject("app"), log)
|
||||
|
@ -286,11 +287,12 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() {
|
|||
src.optJSONObject("poll")
|
||||
)
|
||||
|
||||
this.reactionCounts = parseReactionCounts(src.optJSONObject("reactionCounts"))
|
||||
|
||||
this.reblog = parser.status(src.optJSONObject("renote"))
|
||||
|
||||
} else {
|
||||
misskeyVisibleIds = null
|
||||
|
||||
this.uri = src.parseString("uri") // MSPだとuriは提供されない
|
||||
this.url = src.parseString("url") // 頻繁にnullになる
|
||||
this.created_at = src.parseString("created_at")
|
||||
|
@ -437,20 +439,6 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun parseMisskeyTags(src : JSONArray?) : ArrayList<TootTag>? {
|
||||
var rv : ArrayList<TootTag>? = null
|
||||
if(src != null) {
|
||||
for(i in 0 until src.length()) {
|
||||
val sv = src.optString(i, null)
|
||||
if(sv?.isNotEmpty() == true) {
|
||||
if(rv == null) rv = ArrayList()
|
||||
rv.add(TootTag(name = sv))
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// ユーティリティ
|
||||
|
||||
|
@ -698,6 +686,33 @@ class TootStatus(parser : TootParser, src : JSONObject) : TimelineItem() {
|
|||
return rv
|
||||
}
|
||||
|
||||
private fun parseReactionCounts(src : JSONObject?) : HashMap<String, Int>? {
|
||||
var rv : HashMap<String, Int>? = null
|
||||
if(src != null) {
|
||||
for(key in src.keys()) {
|
||||
val v = src.parseInt(key) ?: continue
|
||||
MisskeyReaction.shortcodeMap[key] ?: continue
|
||||
if(rv == null) rv = HashMap()
|
||||
rv[key] = v
|
||||
}
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
private fun parseMisskeyTags(src : JSONArray?) : ArrayList<TootTag>? {
|
||||
var rv : ArrayList<TootTag>? = null
|
||||
if(src != null) {
|
||||
for(i in 0 until src.length()) {
|
||||
val sv = src.optString(i, null)
|
||||
if(sv?.isNotEmpty() == true) {
|
||||
if(rv == null) rv = ArrayList()
|
||||
rv.add(TootTag(name = sv))
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
private fun validHost(host : String?) : String? {
|
||||
return if(host != null && host.isNotEmpty() && host != "?") host else null
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ class ActionsDialog {
|
|||
return this
|
||||
}
|
||||
|
||||
fun show(context : Context, title : CharSequence?) : ActionsDialog {
|
||||
fun show(context : Context, title : CharSequence? = null ) : ActionsDialog {
|
||||
val caption_list = arrayOfNulls<CharSequence>(action_list.size)
|
||||
var i = 0
|
||||
val ie = caption_list.size
|
||||
|
|
|
@ -748,6 +748,7 @@
|
|||
<string name="visibility_home">Home</string>
|
||||
<string name="visibility_followers">Followers</string>
|
||||
<string name="vote_count_text">%1$d votes</string>
|
||||
<string name="reaction_add">Add reaction</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>-->
|
||||
|
|
|
@ -1026,6 +1026,7 @@
|
|||
<string name="misskey">Misskey</string>
|
||||
<string name="visibility_home">ホーム</string>
|
||||
<string name="visibility_followers">フォロワー</string>
|
||||
<string name="vote_count_text">%1$d votes</string>
|
||||
<string name="vote_count_text">%1$d票</string>
|
||||
<string name="reaction_add">リアクションの追加</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -734,4 +734,5 @@
|
|||
<string name="visibility_home">Home</string>
|
||||
<string name="visibility_followers">Followers</string>
|
||||
<string name="vote_count_text">%1$d votes</string>
|
||||
<string name="reaction_add">Add reaction</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue