SubwayTooter-Android-App/app/src/main/java/jp/juggler/subwaytooter/DlgContextMenu.kt

1141 lines
34 KiB
Kotlin

package jp.juggler.subwaytooter
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.res.ColorStateList
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.*
import androidx.appcompat.app.AlertDialog
import androidx.core.app.ShareCompat
import androidx.core.content.ContextCompat
import jp.juggler.subwaytooter.action.*
import jp.juggler.subwaytooter.api.entity.*
import jp.juggler.subwaytooter.dialog.DlgListMember
import jp.juggler.subwaytooter.dialog.DlgQRCode
import jp.juggler.subwaytooter.span.MyClickableSpan
import jp.juggler.subwaytooter.table.FavMute
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.table.UserRelation
import jp.juggler.subwaytooter.util.*
import jp.juggler.util.*
import org.jetbrains.anko.allCaps
import org.jetbrains.anko.backgroundDrawable
import java.util.*
@SuppressLint("InflateParams")
internal class DlgContextMenu(
val activity : ActMain,
private val column : Column,
private val whoRef : TootAccountRef?,
private val status : TootStatus?,
private val notification : TootNotification? = null,
private val contentTextView : TextView? = null
) : View.OnClickListener, View.OnLongClickListener {
companion object {
private val log = LogCategory("DlgContextMenu")
}
private val access_info : SavedAccount
private val relation : UserRelation
private val dialog : Dialog
private val viewRoot = activity.layoutInflater.inflate(R.layout.dlg_context_menu, null, false)
private val btnCrossAccountActionsForStatus : Button =
viewRoot.findViewById(R.id.btnCrossAccountActionsForStatus)
private val llCrossAccountActionsForStatus : View =
viewRoot.findViewById(R.id.llCrossAccountActionsForStatus)
private val btnCrossAccountActionsForAccount : Button =
viewRoot.findViewById(R.id.btnCrossAccountActionsForAccount)
private val llCrossAccountActionsForAccount : View =
viewRoot.findViewById(R.id.llCrossAccountActionsForAccount)
private val btnAroundThisToot : Button =
viewRoot.findViewById(R.id.btnAroundThisToot)
private val llAroundThisToot : View =
viewRoot.findViewById(R.id.llAroundThisToot)
private val btnYourToot : Button =
viewRoot.findViewById(R.id.btnYourToot)
private val llYourToot : View =
viewRoot.findViewById(R.id.llYourToot)
private val btnStatusExtraAction : Button =
viewRoot.findViewById(R.id.btnStatusExtraAction)
private val llStatusExtraAction : View =
viewRoot.findViewById(R.id.llStatusExtraAction)
private val btnAccountExtraAction : Button =
viewRoot.findViewById(R.id.btnAccountExtraAction)
private val llAccountExtraAction : View =
viewRoot.findViewById(R.id.llAccountExtraAction)
private val btnPostNotification : Button = viewRoot.findViewById(R.id.btnPostNotification)
init {
this.access_info = column.access_info
val columnType = column.type
val who = whoRef?.get()
val status = this.status
this.relation = when {
who == null -> UserRelation()
access_info.isPseudo -> UserRelation.loadPseudo(access_info.getFullAcct(who))
else -> UserRelation.load(access_info.db_id, who.id)
}
this.dialog = Dialog(activity)
dialog.setContentView(viewRoot)
dialog.setCancelable(true)
dialog.setCanceledOnTouchOutside(true)
val llStatus : View = viewRoot.findViewById(R.id.llStatus)
val btnStatusWebPage : View = viewRoot.findViewById(R.id.btnStatusWebPage)
val btnText : View = viewRoot.findViewById(R.id.btnText)
val btnFavouriteAnotherAccount : View =
viewRoot.findViewById(R.id.btnFavouriteAnotherAccount)
val btnBookmarkAnotherAccount : View =
viewRoot.findViewById(R.id.btnBookmarkAnotherAccount)
val btnBoostAnotherAccount : View = viewRoot.findViewById(R.id.btnBoostAnotherAccount)
val btnReactionAnotherAccount : View = viewRoot.findViewById(R.id.btnReactionAnotherAccount)
val btnReplyAnotherAccount : View = viewRoot.findViewById(R.id.btnReplyAnotherAccount)
val btnQuoteToot : View = viewRoot.findViewById(R.id.btnQuoteToot)
val btnQuoteTootBT : View = viewRoot.findViewById(R.id.btnQuoteTootBT)
val btnDelete : View = viewRoot.findViewById(R.id.btnDelete)
val btnRedraft : View = viewRoot.findViewById(R.id.btnRedraft)
val btnReportStatus : View = viewRoot.findViewById(R.id.btnReportStatus)
val btnReportUser : View = viewRoot.findViewById(R.id.btnReportUser)
val btnMuteApp : Button = viewRoot.findViewById(R.id.btnMuteApp)
val llAccountActionBar : View = viewRoot.findViewById(R.id.llAccountActionBar)
val btnFollow : ImageButton = viewRoot.findViewById(R.id.btnFollow)
val btnMute : ImageView = viewRoot.findViewById(R.id.btnMute)
val btnBlock : ImageView = viewRoot.findViewById(R.id.btnBlock)
val btnProfile : View = viewRoot.findViewById(R.id.btnProfile)
val btnSendMessage : View = viewRoot.findViewById(R.id.btnSendMessage)
val btnAccountWebPage : View = viewRoot.findViewById(R.id.btnAccountWebPage)
val btnFollowRequestOK : View = viewRoot.findViewById(R.id.btnFollowRequestOK)
val btnFollowRequestNG : View = viewRoot.findViewById(R.id.btnFollowRequestNG)
val btnDeleteSuggestion : View = viewRoot.findViewById(R.id.btnDeleteSuggestion)
val btnFollowFromAnotherAccount : View =
viewRoot.findViewById(R.id.btnFollowFromAnotherAccount)
val btnSendMessageFromAnotherAccount : View =
viewRoot.findViewById(R.id.btnSendMessageFromAnotherAccount)
val btnOpenProfileFromAnotherAccount : View =
viewRoot.findViewById(R.id.btnOpenProfileFromAnotherAccount)
val btnDomainBlock : Button = viewRoot.findViewById(R.id.btnDomainBlock)
val btnInstanceInformation : Button = viewRoot.findViewById(R.id.btnInstanceInformation)
val btnProfileDirectory : Button = viewRoot.findViewById(R.id.btnProfileDirectory)
val ivFollowedBy : ImageView = viewRoot.findViewById(R.id.ivFollowedBy)
val btnOpenTimeline : Button = viewRoot.findViewById(R.id.btnOpenTimeline)
val btnConversationAnotherAccount : View =
viewRoot.findViewById(R.id.btnConversationAnotherAccount)
val btnAvatarImage : View = viewRoot.findViewById(R.id.btnAvatarImage)
val llNotification : View = viewRoot.findViewById(R.id.llNotification)
val btnNotificationDelete : View = viewRoot.findViewById(R.id.btnNotificationDelete)
val btnConversationMute : Button = viewRoot.findViewById(R.id.btnConversationMute)
val btnHideBoost : View = viewRoot.findViewById(R.id.btnHideBoost)
val btnShowBoost : View = viewRoot.findViewById(R.id.btnShowBoost)
val btnHideFavourite : View = viewRoot.findViewById(R.id.btnHideFavourite)
val btnShowFavourite : View = viewRoot.findViewById(R.id.btnShowFavourite)
val btnListMemberAddRemove : View = viewRoot.findViewById(R.id.btnListMemberAddRemove)
val btnEndorse : Button = viewRoot.findViewById(R.id.btnEndorse)
val btnAroundAccountTL : View = viewRoot.findViewById(R.id.btnAroundAccountTL)
val btnAroundLTL : View = viewRoot.findViewById(R.id.btnAroundLTL)
val btnAroundFTL : View = viewRoot.findViewById(R.id.btnAroundFTL)
val btnCopyAccountId : Button = viewRoot.findViewById(R.id.btnCopyAccountId)
val btnOpenAccountInAdminWebUi : Button =
viewRoot.findViewById(R.id.btnOpenAccountInAdminWebUi)
val btnOpenInstanceInAdminWebUi : Button =
viewRoot.findViewById(R.id.btnOpenInstanceInAdminWebUi)
val btnBoostWithVisibility : Button = viewRoot.findViewById(R.id.btnBoostWithVisibility)
val llLinks : LinearLayout = viewRoot.findViewById(R.id.llLinks)
val btnNotificationFrom : Button = viewRoot.findViewById(R.id.btnNotificationFrom)
val btnProfilePin = viewRoot.findViewById<View>(R.id.btnProfilePin)
val btnProfileUnpin = viewRoot.findViewById<View>(R.id.btnProfileUnpin)
val btnBoostedBy = viewRoot.findViewById<View>(R.id.btnBoostedBy)
val btnFavouritedBy = viewRoot.findViewById<View>(R.id.btnFavouritedBy)
val btnDomainTimeline = viewRoot.findViewById<View>(R.id.btnDomainTimeline)
arrayOf(
btnNotificationFrom,
btnAroundAccountTL,
btnAroundLTL,
btnAroundFTL,
btnStatusWebPage,
btnText,
btnFavouriteAnotherAccount,
btnBookmarkAnotherAccount,
btnBoostAnotherAccount,
btnReactionAnotherAccount,
btnReplyAnotherAccount,
btnQuoteToot,
btnQuoteTootBT,
btnReportStatus,
btnReportUser,
btnMuteApp,
btnDelete,
btnRedraft,
btnFollow,
btnMute,
btnBlock,
btnProfile,
btnSendMessage,
btnAccountWebPage,
btnFollowRequestOK,
btnFollowRequestNG,
btnDeleteSuggestion,
btnFollowFromAnotherAccount,
btnSendMessageFromAnotherAccount,
btnOpenProfileFromAnotherAccount,
btnOpenTimeline,
btnConversationAnotherAccount,
btnAvatarImage,
btnNotificationDelete,
btnConversationMute,
btnHideBoost,
btnShowBoost,
btnHideFavourite,
btnShowFavourite,
btnListMemberAddRemove,
btnInstanceInformation,
btnProfileDirectory,
btnDomainBlock,
btnEndorse,
btnCopyAccountId,
btnOpenAccountInAdminWebUi,
btnOpenInstanceInAdminWebUi,
btnBoostWithVisibility,
btnProfilePin,
btnProfileUnpin,
btnBoostedBy,
btnFavouritedBy,
btnDomainTimeline,
btnPostNotification,
viewRoot.findViewById(R.id.btnQuoteUrlStatus),
viewRoot.findViewById(R.id.btnTranslate),
viewRoot.findViewById(R.id.btnQuoteUrlAccount),
viewRoot.findViewById(R.id.btnShareUrlStatus),
viewRoot.findViewById(R.id.btnShareUrlAccount),
viewRoot.findViewById(R.id.btnQuoteName)
).forEach {
it.setOnClickListener(this@DlgContextMenu)
}
arrayOf(
btnFollow,
btnProfile,
btnMute,
btnBlock,
btnSendMessage
).forEach {
it.setOnLongClickListener(this)
}
val account_list = SavedAccount.loadAccountList(activity)
// final ArrayList< SavedAccount > account_list_non_pseudo_same_instance = new ArrayList<>();
val account_list_non_pseudo = ArrayList<SavedAccount>()
for(a in account_list) {
if(! a.isPseudo) {
account_list_non_pseudo.add(a)
// if( a.host.equalsIgnoreCase( access_info.host ) ){
// account_list_non_pseudo_same_instance.add( a );
// }
}
}
if(status == null) {
llStatus.visibility = View.GONE
llLinks.visibility = View.GONE
} else {
val status_by_me = access_info.isMe(status.account)
if(Pref.bpLinksInContextMenu(activity.pref) && contentTextView != null) {
var insPos = 0
fun addLinkButton(span : MyClickableSpan, caption : String) {
val b = Button(activity)
val lp = LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
b.layoutParams = lp
b.backgroundDrawable =
ContextCompat.getDrawable(activity, R.drawable.btn_bg_transparent_round6dp)
b.gravity = Gravity.START or Gravity.CENTER_VERTICAL
b.minHeight = (activity.density * 32f + 0.5f).toInt()
b.minimumHeight = (activity.density * 32f + 0.5f).toInt()
val pad_lr = (activity.density * 8f + 0.5f).toInt()
val pad_tb = (activity.density * 4f + 0.5f).toInt()
b.setPaddingRelative(pad_lr, pad_tb, pad_lr, pad_tb)
b.text = caption
b.allCaps = false
b.setOnClickListener {
dialog.dismissSafe()
span.onClick(contentTextView)
}
llLinks.addView(b, insPos ++)
}
val dc = status.decoded_content
for(span in dc.getSpans(0, dc.length, MyClickableSpan::class.java)) {
val caption = span.linkInfo.text
when(caption.firstOrNull()) {
'@', '#' -> addLinkButton(span, caption)
else -> addLinkButton(span, span.linkInfo.url)
}
}
}
llLinks.vg(llLinks.childCount > 1)
btnYourToot.vg(status_by_me)
btnQuoteTootBT.vg(status.reblogParent != null)
btnBoostWithVisibility.vg(! access_info.isPseudo && ! access_info.isMisskey)
btnReportStatus.vg(! (status_by_me || access_info.isPseudo))
val application_name = status.application?.name
if(status_by_me || application_name == null || application_name.isEmpty()) {
btnMuteApp.visibility = View.GONE
} else {
btnMuteApp.text = activity.getString(R.string.mute_app_of, application_name)
}
val canPin = status.canPin(access_info)
btnProfileUnpin.vg(canPin && status.pinned)
btnProfilePin.vg(canPin && ! status.pinned)
}
val bShowConversationMute = when {
status == null -> false
access_info.isMe(status.account) -> true
notification != null && TootNotification.TYPE_MENTION == notification.type -> true
else -> false
}
val muted = status?.muted ?: false
btnConversationMute.vg(bShowConversationMute)
?.setText(
if(muted)
R.string.unmute_this_conversation
else R.string.mute_this_conversation
)
llNotification.vg(notification != null)
val colorButtonAccent =
Pref.ipButtonFollowingColor(activity.pref).notZero()
?: activity.getAttributeColor(R.attr.colorImageButtonAccent)
val colorButtonError =
Pref.ipButtonFollowRequestColor(activity.pref).notZero()
?: activity.getAttributeColor(R.attr.colorRegexFilterError)
val colorButtonNormal =
activity.getAttributeColor(R.attr.colorImageButton)
fun showRelation(relation : UserRelation) {
// 被フォロー状態
// Styler.setFollowIconとは異なり細かい状態を表示しない
ivFollowedBy.vg(relation.followed_by)
// フォロー状態
// Styler.setFollowIconとは異なりミュートやブロックを表示しない
btnFollow.setImageResource(
when {
relation.getRequested(who) -> R.drawable.ic_follow_wait
relation.getFollowing(who) -> R.drawable.ic_follow_cross
else -> R.drawable.ic_follow_plus
}
)
btnFollow.imageTintList = ColorStateList.valueOf(
when {
relation.getRequested(who) -> colorButtonError
relation.getFollowing(who) -> colorButtonAccent
else -> colorButtonNormal
}
)
// ミュート状態
btnMute.imageTintList = ColorStateList.valueOf(
when(relation.muting) {
true -> colorButtonAccent
else -> colorButtonNormal
}
)
// ブロック状態
btnBlock.imageTintList = ColorStateList.valueOf(
when(relation.blocking) {
true -> colorButtonAccent
else -> colorButtonNormal
}
)
}
if(access_info.isPseudo) {
// 疑似アカミュートができたのでアカウントアクションを表示する
showRelation(UserRelation())
llAccountActionBar.visibility = View.VISIBLE
ivFollowedBy.vg(false)
btnFollow.setImageResource(R.drawable.ic_follow_plus)
btnFollow.imageTintList =
ColorStateList.valueOf(activity.getAttributeColor(R.attr.colorImageButton))
btnNotificationFrom.visibility = View.GONE
} else {
showRelation(relation)
}
val whoApiHost = getUserApiHost()
val whoApDomain = getUserApDomain()
viewRoot.findViewById<View>(R.id.llInstance)
.vg(whoApiHost.isValid)
?.let {
val tvInstanceActions : TextView = viewRoot.findViewById(R.id.tvInstanceActions)
tvInstanceActions.text =
activity.getString(R.string.instance_actions_for, whoApDomain.pretty)
// 疑似アカウントではドメインブロックできない
// 自ドメインはブロックできない
btnDomainBlock.vg(
! (access_info.isPseudo || access_info.matchHost(whoApiHost))
)
btnDomainTimeline.vg(
Pref.bpEnableDomainTimeline(activity.pref) &&
! access_info.isPseudo &&
! access_info.isMisskey
)
}
if(who == null) {
btnCopyAccountId.visibility = View.GONE
btnOpenAccountInAdminWebUi.visibility = View.GONE
btnOpenInstanceInAdminWebUi.visibility = View.GONE
btnReportUser.visibility = View.GONE
} else {
btnCopyAccountId.visibility = View.VISIBLE
btnCopyAccountId.text = activity.getString(R.string.copy_account_id, who.id.toString())
btnOpenAccountInAdminWebUi.vg(! access_info.isPseudo)
btnOpenInstanceInAdminWebUi.vg(! access_info.isPseudo)
btnReportUser.vg(! (access_info.isPseudo || access_info.isMe(who)))
btnPostNotification.vg(! access_info.isPseudo && access_info.isMastodon && relation.following)
?.let {
it.text = when(relation.notifying) {
true -> activity.getString(R.string.stop_notify_posts_from_this_user)
else -> activity.getString(R.string.notify_posts_from_this_user)
}
}
}
viewRoot.findViewById<View>(R.id.btnAccountText).setOnClickListener(this)
if(access_info.isPseudo) {
btnProfile.visibility = View.GONE
btnSendMessage.visibility = View.GONE
btnEndorse.visibility = View.GONE
}
btnEndorse.text = when(relation.endorsed) {
false -> activity.getString(R.string.endorse_set)
else -> activity.getString(R.string.endorse_unset)
}
if(columnType != ColumnType.FOLLOW_REQUESTS) {
btnFollowRequestOK.visibility = View.GONE
btnFollowRequestNG.visibility = View.GONE
}
if(columnType != ColumnType.FOLLOW_SUGGESTION) {
btnDeleteSuggestion.visibility = View.GONE
}
if(account_list_non_pseudo.isEmpty()) {
btnFollowFromAnotherAccount.visibility = View.GONE
btnSendMessageFromAnotherAccount.visibility = View.GONE
}
viewRoot.findViewById<View>(R.id.btnNickname).setOnClickListener(this)
viewRoot.findViewById<View>(R.id.btnCancel).setOnClickListener(this)
viewRoot.findViewById<View>(R.id.btnAccountQrCode).setOnClickListener(this)
if(access_info.isPseudo
|| who == null
|| ! relation.getFollowing(who)
|| relation.following_reblogs == UserRelation.REBLOG_UNKNOWN) {
btnHideBoost.visibility = View.GONE
btnShowBoost.visibility = View.GONE
} else if(relation.following_reblogs == UserRelation.REBLOG_SHOW) {
btnHideBoost.visibility = View.VISIBLE
btnShowBoost.visibility = View.GONE
} else {
btnHideBoost.visibility = View.GONE
btnShowBoost.visibility = View.VISIBLE
}
when {
who == null -> {
btnHideFavourite.visibility = View.GONE
btnShowFavourite.visibility = View.GONE
}
FavMute.contains(access_info.getFullAcct(who)) -> {
btnHideFavourite.visibility = View.GONE
btnShowFavourite.visibility = View.VISIBLE
}
else -> {
btnHideFavourite.visibility = View.VISIBLE
btnShowFavourite.visibility = View.GONE
}
}
btnListMemberAddRemove.visibility = View.VISIBLE
updateGroup(btnCrossAccountActionsForStatus, llCrossAccountActionsForStatus)
updateGroup(btnCrossAccountActionsForAccount, llCrossAccountActionsForAccount)
updateGroup(btnAroundThisToot, llAroundThisToot)
updateGroup(btnYourToot, llYourToot)
updateGroup(btnStatusExtraAction, llStatusExtraAction)
updateGroup(btnAccountExtraAction, llAccountExtraAction)
}
fun show() {
val window = dialog.window
if(window != null) {
val lp = window.attributes
lp.width = (0.5f + 280f * activity.density).toInt()
lp.height = WindowManager.LayoutParams.WRAP_CONTENT
window.attributes = lp
}
dialog.show()
}
private fun getUserApiHost() : Host =
when(val who_host = whoRef?.get()?.apiHost) {
Host.UNKNOWN -> Host.parse(column.instance_uri)
Host.EMPTY, null -> access_info.apiHost
else -> who_host
}
private fun getUserApDomain() : Host =
when(val who_host = whoRef?.get()?.apDomain) {
Host.UNKNOWN -> Host.parse(column.instance_uri)
Host.EMPTY, null -> access_info.apDomain
else -> who_host
}
private fun updateGroup(btn : Button, group : View, toggle : Boolean = false) {
if(btn.visibility != View.VISIBLE) {
group.vg(false)
return
}
when {
Pref.bpAlwaysExpandContextMenuItems(activity.pref) -> {
group.vg(true)
btn.background = null
}
toggle -> group.vg(group.visibility != View.VISIBLE)
else -> btn.setOnClickListener(this)
}
val iconId = if(group.visibility == View.VISIBLE) {
R.drawable.ic_arrow_drop_up
} else {
R.drawable.ic_arrow_drop_down
}
val iconColor = activity.getAttributeColor(R.attr.colorTimeSmall)
val drawable = createColoredDrawable(activity, iconId, iconColor, 1f)
btn.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null)
}
override fun onClick(v : View) {
// ダイアログを閉じない操作
when(v.id) {
R.id.btnCrossAccountActionsForStatus ->
return updateGroup(
btnCrossAccountActionsForStatus,
llCrossAccountActionsForStatus,
toggle = true
)
R.id.btnCrossAccountActionsForAccount ->
return updateGroup(
btnCrossAccountActionsForAccount,
llCrossAccountActionsForAccount,
toggle = true
)
R.id.btnAroundThisToot ->
return updateGroup(
btnAroundThisToot,
llAroundThisToot,
toggle = true
)
R.id.btnYourToot ->
return updateGroup(
btnYourToot,
llYourToot,
toggle = true
)
R.id.btnStatusExtraAction ->
return updateGroup(
btnStatusExtraAction,
llStatusExtraAction,
toggle = true
)
R.id.btnAccountExtraAction ->
return updateGroup(
btnAccountExtraAction,
llAccountExtraAction,
toggle = true
)
}
dialog.dismissSafe()
val pos = activity.nextPosition(column)
val whoRef = this.whoRef
val who = whoRef?.get()
if(whoRef != null && who != null) {
when(v.id) {
R.id.btnReportStatus -> if(status is TootStatus) {
Action_User.reportForm(activity, access_info, who, status)
}
R.id.btnReportUser ->
Action_User.reportForm(activity, access_info, who)
R.id.btnFollow ->
when {
access_info.isPseudo -> Action_Follow.followFromAnotherAccount(
activity,
pos,
access_info,
who
)
access_info.isMisskey && relation.getRequested(who) && ! relation.getFollowing(
who
) -> Action_Follow.deleteFollowRequest(
activity, pos, access_info, whoRef,
callback = activity.cancel_follow_request_complete_callback
)
else -> {
val bSet = ! (relation.getRequested(who) || relation.getFollowing(who))
Action_Follow.follow(
activity, pos, access_info, whoRef,
bFollow = bSet,
callback = when(bSet) {
true -> activity.follow_complete_callback
else -> activity.unfollow_complete_callback
}
)
}
}
R.id.btnAccountText ->
ActText.open(activity, ActMain.REQUEST_CODE_TEXT, access_info, who)
R.id.btnMute -> when {
relation.muting -> Action_User.mute(
activity,
access_info,
who,
access_info,
bMute = false
)
else -> Action_User.muteConfirm(activity, access_info, who, access_info)
}
R.id.btnBlock -> when {
relation.blocking -> Action_User.block(
activity,
access_info,
who,
access_info,
false
)
else -> Action_User.blockConfirm(activity, access_info, who, access_info)
}
R.id.btnProfile ->
Action_User.profileLocal(activity, pos, access_info, who)
R.id.btnSendMessage ->
Action_User.mention(activity, access_info, who)
R.id.btnAccountWebPage -> who.url?.let { url ->
activity.openCustomTabOrBrowser(url)
}
R.id.btnFollowRequestOK ->
Action_Follow.authorizeFollowRequest(activity, access_info, whoRef, true)
R.id.btnDeleteSuggestion ->
Action_User.deleteSuggestion(activity, access_info, who)
R.id.btnFollowRequestNG ->
Action_Follow.authorizeFollowRequest(activity, access_info, whoRef, false)
R.id.btnFollowFromAnotherAccount ->
Action_Follow.followFromAnotherAccount(activity, pos, access_info, who)
R.id.btnSendMessageFromAnotherAccount ->
Action_User.mentionFromAnotherAccount(activity, access_info, who)
R.id.btnOpenProfileFromAnotherAccount ->
Action_User.profileFromAnotherAccount(activity, pos, access_info, who)
R.id.btnNickname ->
ActNickname.open(
activity,
access_info.getFullAcct(who),
true,
ActMain.REQUEST_CODE_NICKNAME
)
R.id.btnAccountQrCode ->
DlgQRCode.open(
activity,
whoRef.decoded_display_name,
who.getUserUrl()
)
R.id.btnDomainBlock ->
if(access_info.isPseudo) {
// 疑似アカウントではドメインブロックできない
activity.showToast(false, R.string.domain_block_from_pseudo)
return
} else {
val whoApDomain = who.apDomain
// 自分のドメインではブロックできない
if(access_info.matchHost(whoApDomain)) {
activity.showToast(false, R.string.domain_block_from_local)
return
}
AlertDialog.Builder(activity)
.setMessage(
activity.getString(
R.string.confirm_block_domain,
whoApDomain
)
)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok) { _, _ ->
Action_Instance.blockDomain(
activity,
access_info,
whoApDomain,
true
)
}
.show()
}
R.id.btnOpenTimeline -> {
who.apiHost.valid()?.let {
Action_Instance.timelineLocal(activity, pos, it)
}
}
R.id.btnDomainTimeline -> {
who.apiHost.valid()?.let {
Action_Instance.timelineDomain(activity, pos, access_info, it)
}
}
R.id.btnAvatarImage -> {
val url = if(! who.avatar.isNullOrEmpty()) who.avatar else who.avatar_static
activity.openCustomTab(url)
// XXX: 設定によっては内蔵メディアビューアで開けないか?
}
R.id.btnQuoteName -> {
var sv = who.display_name
try {
val fmt = Pref.spQuoteNameFormat(activity.pref)
if(fmt.contains("%1\$s")) {
sv = String.format(fmt, sv)
}
} catch(ex : Throwable) {
log.trace(ex)
}
Action_Account.openPost(activity, sv)
}
R.id.btnHideBoost ->
Action_User.showBoosts(activity, access_info, who, false)
R.id.btnShowBoost ->
Action_User.showBoosts(activity, access_info, who, true)
R.id.btnHideFavourite -> {
val acct = access_info.getFullAcct(who)
FavMute.save(acct)
activity.showToast(false, R.string.changed)
for(column in activity.app_state.column_list) {
column.onHideFavouriteNotification(acct)
}
}
R.id.btnShowFavourite -> {
FavMute.delete(access_info.getFullAcct(who))
activity.showToast(false, R.string.changed)
}
R.id.btnListMemberAddRemove ->
DlgListMember(activity, who, access_info).show()
R.id.btnInstanceInformation -> {
Action_Instance.information(activity, pos, getUserApiHost())
}
R.id.btnProfileDirectory -> {
Action_Instance.profileDirectoryFromInstanceInformation(
activity,
column,
getUserApiHost()
)
}
R.id.btnEndorse -> Action_Account.endorse(
activity,
access_info,
who,
! relation.endorsed
)
R.id.btnAroundAccountTL -> Action_Instance.timelinePublicAround(
activity,
access_info,
pos,
who.apiHost,
status,
ColumnType.ACCOUNT_AROUND, allowPseudo = false
)
R.id.btnAroundLTL -> Action_Instance.timelinePublicAround(
activity,
access_info,
pos,
who.apiHost,
status,
ColumnType.LOCAL_AROUND
)
R.id.btnAroundFTL -> Action_Instance.timelinePublicAround(
activity,
access_info,
pos,
who.apiHost,
status,
ColumnType.FEDERATED_AROUND
)
R.id.btnCopyAccountId -> who.id.toString().copyToClipboard(activity)
R.id.btnOpenAccountInAdminWebUi ->
activity.openBrowser(
"https://${access_info.apiHost.ascii}/admin/accounts/${who.id}"
)
R.id.btnOpenInstanceInAdminWebUi ->
activity.openBrowser(
"https://${access_info.apiHost.ascii}/admin/instances/${who.apDomain.ascii}"
)
R.id.btnBoostWithVisibility -> {
val status = this.status ?: return
val list = if(access_info.isMisskey) {
arrayOf(
TootVisibility.Public,
TootVisibility.UnlistedHome,
TootVisibility.PrivateFollowers,
TootVisibility.LocalPublic,
TootVisibility.LocalHome,
TootVisibility.LocalFollowers,
TootVisibility.DirectSpecified,
TootVisibility.DirectPrivate
)
} else {
arrayOf(
TootVisibility.Public,
TootVisibility.UnlistedHome,
TootVisibility.PrivateFollowers
)
}
val caption_list = list
.map { Styler.getVisibilityCaption(activity, access_info.isMisskey, it) }
.toTypedArray()
AlertDialog.Builder(activity)
.setTitle(R.string.choose_visibility)
.setItems(caption_list) { _, which ->
if(which in list.indices) {
Action_Toot.boost(
activity,
access_info,
status,
access_info.getFullAcct(status.account),
NOT_CROSS_ACCOUNT,
visibility = list[which],
callback =activity.boost_complete_callback,
)
}
}
.setNegativeButton(R.string.cancel, null)
.show()
}
R.id.btnNotificationFrom -> {
if(access_info.isMisskey) {
activity.showToast(false, R.string.misskey_account_not_supported)
} else {
access_info.getFullAcct(who).validFull()?.let {
activity.addColumn(
pos,
access_info,
ColumnType.NOTIFICATION_FROM_ACCT,
it
)
}
}
}
R.id.btnPostNotification ->
if(! access_info.isPseudo && access_info.isMastodon && relation.following) {
val toggle = ! relation.notifying
Action_User.statusNotification(activity, access_info, who.id, toggle)
}
}
}
when(v.id) {
R.id.btnStatusWebPage ->
activity.openCustomTabOrBrowser(status?.url)
R.id.btnText -> if(status != null) {
ActText.open(activity, ActMain.REQUEST_CODE_TEXT, access_info, status)
}
R.id.btnFavouriteAnotherAccount -> Action_Toot.favouriteFromAnotherAccount(
activity,
access_info,
status
)
R.id.btnBookmarkAnotherAccount -> Action_Toot.bookmarkFromAnotherAccount(
activity,
access_info,
status
)
R.id.btnBoostAnotherAccount -> Action_Toot.boostFromAnotherAccount(
activity,
access_info,
status
)
R.id.btnReactionAnotherAccount -> Action_Toot.reactionFromAnotherAccount(
activity,
access_info,
status
)
R.id.btnReplyAnotherAccount -> Action_Toot.replyFromAnotherAccount(
activity,
access_info,
status
)
R.id.btnQuoteToot -> Action_Toot.replyFromAnotherAccount(
activity,
access_info,
status,
quote = true
)
R.id.btnQuoteTootBT -> Action_Toot.replyFromAnotherAccount(
activity,
access_info,
status?.reblogParent,
quote = true
)
R.id.btnConversationAnotherAccount -> status?.let { status ->
Action_Toot.conversationOtherInstance(activity, pos, status)
}
R.id.btnDelete -> status?.let { status ->
AlertDialog.Builder(activity)
.setMessage(activity.getString(R.string.confirm_delete_status))
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok) { _, _ ->
Action_Toot.delete(
activity,
access_info,
status.id
)
}
.show()
}
R.id.btnRedraft -> status?.let { status ->
Action_Toot.redraft(activity, access_info, status)
}
R.id.btnMuteApp -> status?.application?.let {
Action_App.muteApp(activity, it)
}
R.id.btnBoostedBy -> status?.let {
activity.addColumn(false, pos, access_info, ColumnType.BOOSTED_BY, it.id)
}
R.id.btnFavouritedBy -> status?.let {
activity.addColumn(false, pos, access_info, ColumnType.FAVOURITED_BY, it.id)
}
R.id.btnCancel -> dialog.cancel()
R.id.btnTranslate -> CustomShare.invoke(
activity,
access_info,
status,
CustomShareTarget.Translate
)
R.id.btnQuoteUrlStatus -> status?.url?.let { url ->
if(url.isNotEmpty()) Action_Account.openPost(activity, url)
}
R.id.btnQuoteUrlAccount -> who?.url?.let { url ->
if(url.isNotEmpty()) Action_Account.openPost(activity, url)
}
R.id.btnShareUrlStatus -> status?.url?.let { url ->
if(url.isNotEmpty()) shareText(activity, url)
}
R.id.btnShareUrlAccount -> who?.url?.let { url ->
if(url.isNotEmpty()) shareText(activity, url)
}
R.id.btnNotificationDelete -> notification?.let { notification ->
Action_Notification.deleteOne(activity, access_info, notification)
}
R.id.btnConversationMute -> status?.let { status ->
Action_Toot.muteConversation(activity, access_info, status)
}
R.id.btnProfilePin -> status?.let { status ->
Action_Toot.pin(activity, access_info, status, true)
}
R.id.btnProfileUnpin -> status?.let { status ->
Action_Toot.pin(activity, access_info, status, false)
}
}
}
private fun shareText(activity : ActMain, text : String) {
ShareCompat.IntentBuilder.from(activity)
.setText(text)
.setType("text/plain")
.startChooser()
}
override fun onLongClick(v : View) : Boolean {
val whoRef = this.whoRef
val who = whoRef?.get()
when(v.id) {
R.id.btnFollow -> {
dialog.dismissSafe()
Action_Follow.followFromAnotherAccount(
activity,
activity.nextPosition(column),
access_info,
who
)
return true
}
R.id.btnProfile -> {
dialog.dismissSafe()
Action_User.profileFromAnotherAccount(
activity,
activity.nextPosition(column),
access_info,
who
)
return true
}
R.id.btnSendMessage -> {
dialog.dismissSafe()
Action_User.mentionFromAnotherAccount(activity, access_info, who)
return true
}
R.id.btnMute -> if(who != null) {
Action_User.muteFromAnotherAccount(activity, who, access_info)
return true
}
R.id.btnBlock -> if(who != null) {
Action_User.blockFromAnotherAccount(activity, who, access_info)
return true
}
}
return false
}
}