1
0
mirror of https://github.com/tateisu/SubwayTooter synced 2025-02-10 09:00:36 +01:00

アカウントIDのコピー

This commit is contained in:
tateisu 2019-01-10 03:40:27 +09:00
parent f2b0849f01
commit 0ba187e545
7 changed files with 127 additions and 91 deletions

View File

@ -797,7 +797,6 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
} }
internal fun copy(url : String) { internal fun copy(url : String) {
val cm = getSystemService(CLIPBOARD_SERVICE) as? ClipboardManager val cm = getSystemService(CLIPBOARD_SERVICE) as? ClipboardManager
?: throw NotImplementedError("missing ClipboardManager system service") ?: throw NotImplementedError("missing ClipboardManager system service")

View File

@ -1,8 +1,6 @@
package jp.juggler.subwaytooter package jp.juggler.subwaytooter
import android.app.SearchManager import android.app.SearchManager
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
@ -14,6 +12,7 @@ import jp.juggler.subwaytooter.table.MutedWord
import jp.juggler.subwaytooter.table.SavedAccount import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.util.DecodeOptions import jp.juggler.subwaytooter.util.DecodeOptions
import jp.juggler.util.LogCategory import jp.juggler.util.LogCategory
import jp.juggler.util.copyToClipboard
import jp.juggler.util.showToast import jp.juggler.util.showToast
import java.util.* import java.util.*
@ -278,7 +277,7 @@ class ActText : AppCompatActivity(), View.OnClickListener {
override fun onClick(v : View) { override fun onClick(v : View) {
when(v.id) { when(v.id) {
R.id.btnCopy -> copy() R.id.btnCopy -> selection.copyToClipboard(this)
R.id.btnSearch -> search() R.id.btnSearch -> search()
@ -294,27 +293,6 @@ class ActText : AppCompatActivity(), View.OnClickListener {
} }
} }
private fun copy() {
try {
// Gets a handle to the clipboard service.
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
?: throw NotImplementedError("missing ClipboardManager system service")
// Creates a new text clip to put on the clipboard
val clip = ClipData.newPlainText("text", selection)
// Set the clipboard's primary clip.
clipboard.primaryClip = clip
showToast(this, false, R.string.copy_complete)
} catch(ex : Throwable) {
log.trace(ex)
showToast(this, ex, "copy failed.")
}
}
private fun send() { private fun send() {
try { try {

View File

@ -62,60 +62,61 @@ internal class DlgContextMenu(
dialog.setCancelable(true) dialog.setCancelable(true)
dialog.setCanceledOnTouchOutside(true) dialog.setCanceledOnTouchOutside(true)
val llStatus = viewRoot.findViewById<View>(R.id.llStatus) val llStatus : View = viewRoot.findViewById(R.id.llStatus)
val btnStatusWebPage = viewRoot.findViewById<View>(R.id.btnStatusWebPage) val btnStatusWebPage : View = viewRoot.findViewById(R.id.btnStatusWebPage)
val btnText = viewRoot.findViewById<View>(R.id.btnText) val btnText : View = viewRoot.findViewById(R.id.btnText)
val btnFavouriteAnotherAccount = val btnFavouriteAnotherAccount : View =
viewRoot.findViewById<View>(R.id.btnFavouriteAnotherAccount) viewRoot.findViewById(R.id.btnFavouriteAnotherAccount)
val btnBoostAnotherAccount = viewRoot.findViewById<View>(R.id.btnBoostAnotherAccount) val btnBoostAnotherAccount : View = viewRoot.findViewById(R.id.btnBoostAnotherAccount)
val btnReactionAnotherAccount = viewRoot.findViewById<View>(R.id.btnReactionAnotherAccount) val btnReactionAnotherAccount : View = viewRoot.findViewById(R.id.btnReactionAnotherAccount)
val btnReplyAnotherAccount = viewRoot.findViewById<View>(R.id.btnReplyAnotherAccount) val btnReplyAnotherAccount : View = viewRoot.findViewById(R.id.btnReplyAnotherAccount)
val btnQuotedRenote = viewRoot.findViewById<View>(R.id.btnQuotedRenote) val btnQuotedRenote : View = viewRoot.findViewById(R.id.btnQuotedRenote)
val btnDelete = viewRoot.findViewById<View>(R.id.btnDelete) val btnDelete : View = viewRoot.findViewById(R.id.btnDelete)
val btnRedraft = viewRoot.findViewById<View>(R.id.btnRedraft) val btnRedraft : View = viewRoot.findViewById(R.id.btnRedraft)
val btnReport = viewRoot.findViewById<View>(R.id.btnReport) val btnReport : View = viewRoot.findViewById(R.id.btnReport)
val btnMuteApp = viewRoot.findViewById<Button>(R.id.btnMuteApp) val btnMuteApp : Button = viewRoot.findViewById(R.id.btnMuteApp)
val llAccountActionBar = viewRoot.findViewById<View>(R.id.llAccountActionBar) val llAccountActionBar : View = viewRoot.findViewById(R.id.llAccountActionBar)
val btnFollow = viewRoot.findViewById<ImageView>(R.id.btnFollow) val btnFollow : ImageView = viewRoot.findViewById(R.id.btnFollow)
val btnMute = viewRoot.findViewById<ImageView>(R.id.btnMute) val btnMute : ImageView = viewRoot.findViewById(R.id.btnMute)
val btnBlock = viewRoot.findViewById<ImageView>(R.id.btnBlock) val btnBlock : ImageView = viewRoot.findViewById(R.id.btnBlock)
val btnProfile = viewRoot.findViewById<View>(R.id.btnProfile) val btnProfile : View = viewRoot.findViewById(R.id.btnProfile)
val btnSendMessage = viewRoot.findViewById<View>(R.id.btnSendMessage) val btnSendMessage : View = viewRoot.findViewById(R.id.btnSendMessage)
val btnAccountWebPage = viewRoot.findViewById<View>(R.id.btnAccountWebPage) val btnAccountWebPage : View = viewRoot.findViewById(R.id.btnAccountWebPage)
val btnFollowRequestOK = viewRoot.findViewById<View>(R.id.btnFollowRequestOK) val btnFollowRequestOK : View = viewRoot.findViewById(R.id.btnFollowRequestOK)
val btnFollowRequestNG = viewRoot.findViewById<View>(R.id.btnFollowRequestNG) val btnFollowRequestNG : View = viewRoot.findViewById(R.id.btnFollowRequestNG)
val btnDeleteSuggestion = viewRoot.findViewById<View>(R.id.btnDeleteSuggestion) val btnDeleteSuggestion : View = viewRoot.findViewById(R.id.btnDeleteSuggestion)
val btnFollowFromAnotherAccount = val btnFollowFromAnotherAccount : View =
viewRoot.findViewById<View>(R.id.btnFollowFromAnotherAccount) viewRoot.findViewById(R.id.btnFollowFromAnotherAccount)
val btnSendMessageFromAnotherAccount = val btnSendMessageFromAnotherAccount : View =
viewRoot.findViewById<View>(R.id.btnSendMessageFromAnotherAccount) viewRoot.findViewById(R.id.btnSendMessageFromAnotherAccount)
val btnOpenProfileFromAnotherAccount = val btnOpenProfileFromAnotherAccount : View =
viewRoot.findViewById<View>(R.id.btnOpenProfileFromAnotherAccount) viewRoot.findViewById(R.id.btnOpenProfileFromAnotherAccount)
val btnDomainBlock = viewRoot.findViewById<Button>(R.id.btnDomainBlock) val btnDomainBlock : Button = viewRoot.findViewById(R.id.btnDomainBlock)
val btnInstanceInformation = viewRoot.findViewById<Button>(R.id.btnInstanceInformation) val btnInstanceInformation : Button = viewRoot.findViewById(R.id.btnInstanceInformation)
val ivFollowedBy = viewRoot.findViewById<ImageView>(R.id.ivFollowedBy) val ivFollowedBy : ImageView = viewRoot.findViewById(R.id.ivFollowedBy)
val btnOpenTimeline = viewRoot.findViewById<Button>(R.id.btnOpenTimeline) val btnOpenTimeline : Button = viewRoot.findViewById(R.id.btnOpenTimeline)
val btnConversationAnotherAccount = val btnConversationAnotherAccount : View =
viewRoot.findViewById<View>(R.id.btnConversationAnotherAccount) viewRoot.findViewById(R.id.btnConversationAnotherAccount)
val btnAvatarImage = viewRoot.findViewById<View>(R.id.btnAvatarImage) val btnAvatarImage : View = viewRoot.findViewById(R.id.btnAvatarImage)
val llNotification = viewRoot.findViewById<View>(R.id.llNotification) val llNotification : View = viewRoot.findViewById(R.id.llNotification)
val btnNotificationDelete = viewRoot.findViewById<View>(R.id.btnNotificationDelete) val btnNotificationDelete : View = viewRoot.findViewById(R.id.btnNotificationDelete)
val btnConversationMute = viewRoot.findViewById<Button>(R.id.btnConversationMute) val btnConversationMute : Button = viewRoot.findViewById(R.id.btnConversationMute)
val btnHideBoost = viewRoot.findViewById<View>(R.id.btnHideBoost) val btnHideBoost : View = viewRoot.findViewById(R.id.btnHideBoost)
val btnShowBoost = viewRoot.findViewById<View>(R.id.btnShowBoost) val btnShowBoost : View = viewRoot.findViewById(R.id.btnShowBoost)
val btnHideFavourite = viewRoot.findViewById<View>(R.id.btnHideFavourite) val btnHideFavourite : View = viewRoot.findViewById(R.id.btnHideFavourite)
val btnShowFavourite = viewRoot.findViewById<View>(R.id.btnShowFavourite) val btnShowFavourite : View = viewRoot.findViewById(R.id.btnShowFavourite)
val btnListMemberAddRemove = viewRoot.findViewById<View>(R.id.btnListMemberAddRemove) val btnListMemberAddRemove : View = viewRoot.findViewById(R.id.btnListMemberAddRemove)
val btnEndorse : Button = viewRoot.findViewById(R.id.btnEndorse) val btnEndorse : Button = viewRoot.findViewById(R.id.btnEndorse)
val btnAroundAccountTL = viewRoot.findViewById<View>(R.id.btnAroundAccountTL) val btnAroundAccountTL : View = viewRoot.findViewById(R.id.btnAroundAccountTL)
val btnAroundLTL = viewRoot.findViewById<View>(R.id.btnAroundLTL) val btnAroundLTL : View = viewRoot.findViewById(R.id.btnAroundLTL)
val btnAroundFTL = viewRoot.findViewById<View>(R.id.btnAroundFTL) val btnAroundFTL : View = viewRoot.findViewById(R.id.btnAroundFTL)
val btnCopyAccountId : Button = viewRoot.findViewById(R.id.btnCopyAccountId)
val llLinks : LinearLayout = viewRoot.findViewById(R.id.llLinks) val llLinks : LinearLayout = viewRoot.findViewById(R.id.llLinks)
@ -160,6 +161,7 @@ internal class DlgContextMenu(
btnInstanceInformation.setOnClickListener(this) btnInstanceInformation.setOnClickListener(this)
btnDomainBlock.setOnClickListener(this) btnDomainBlock.setOnClickListener(this)
btnEndorse.setOnClickListener(this) btnEndorse.setOnClickListener(this)
btnCopyAccountId.setOnClickListener(this)
viewRoot.findViewById<View>(R.id.btnQuoteUrlStatus).setOnClickListener(this) viewRoot.findViewById<View>(R.id.btnQuoteUrlStatus).setOnClickListener(this)
viewRoot.findViewById<View>(R.id.btnQuoteUrlAccount).setOnClickListener(this) viewRoot.findViewById<View>(R.id.btnQuoteUrlAccount).setOnClickListener(this)
@ -186,24 +188,30 @@ internal class DlgContextMenu(
} else { } else {
val status_by_me = access_info.isMe(status.account) val status_by_me = access_info.isMe(status.account)
if(Pref.bpLinksInContextMenu(activity.pref) && contentTextView != null){ if(Pref.bpLinksInContextMenu(activity.pref) && contentTextView != null) {
var insPos = 0 var insPos = 0
fun addLinkButton(span : MyClickableSpan,caption : String){ fun addLinkButton(span : MyClickableSpan, caption : String) {
val b = Button(activity) val b = Button(activity)
val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT) val lp = LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
b.layoutParams = lp b.layoutParams = lp
ViewCompat.setBackground(b, ContextCompat.getDrawable(activity,R.drawable.btn_bg_transparent)) ViewCompat.setBackground(
b,
ContextCompat.getDrawable(activity, R.drawable.btn_bg_transparent)
)
b.gravity = Gravity.START or Gravity.CENTER_VERTICAL b.gravity = Gravity.START or Gravity.CENTER_VERTICAL
b.minHeight = (activity.density *32f + 0.5f).toInt() b.minHeight = (activity.density * 32f + 0.5f).toInt()
b.minimumHeight = (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_lr = (activity.density * 8f + 0.5f).toInt()
val pad_tb = (activity.density *4f + 0.5f).toInt() val pad_tb = (activity.density * 4f + 0.5f).toInt()
b.setPaddingRelative(pad_lr,pad_tb,pad_lr,pad_tb) b.setPaddingRelative(pad_lr, pad_tb, pad_lr, pad_tb)
b.text = caption b.text = caption
b.allCaps = false b.allCaps = false
b.setOnClickListener{ b.setOnClickListener {
try { try {
dialog.dismiss() dialog.dismiss()
} catch(ignored : Throwable) { } catch(ignored : Throwable) {
@ -211,23 +219,23 @@ internal class DlgContextMenu(
} }
span.onClick(contentTextView) span.onClick(contentTextView)
} }
llLinks.addView(b,insPos++) llLinks.addView(b, insPos ++)
} }
val dc = status.decoded_content val dc = status.decoded_content
for( tag in dc.getSpans(0,dc.length,MyClickableSpan::class.java) ){ for(tag in dc.getSpans(0, dc.length, MyClickableSpan::class.java)) {
val start = dc.getSpanStart(tag) val start = dc.getSpanStart(tag)
val end = dc.getSpanEnd(tag) val end = dc.getSpanEnd(tag)
val href = tag ?.url ?:continue val href = tag?.url ?: continue
val caption = dc.substring(start,end) val caption = dc.substring(start, end)
val head = caption[0] val head = caption[0]
if(head=='@' || head == '#') if(head == '@' || head == '#')
addLinkButton(tag, caption) addLinkButton(tag, caption)
else else
addLinkButton(tag, href) addLinkButton(tag, href)
} }
} }
vg(llLinks,llLinks.childCount > 1) vg(llLinks, llLinks.childCount > 1)
btnDelete.visibility = if(status_by_me) View.VISIBLE else View.GONE btnDelete.visibility = if(status_by_me) View.VISIBLE else View.GONE
btnRedraft.visibility = if(status_by_me) View.VISIBLE else View.GONE btnRedraft.visibility = if(status_by_me) View.VISIBLE else View.GONE
@ -346,6 +354,7 @@ internal class DlgContextMenu(
if(who == null) { if(who == null) {
btnInstanceInformation.visibility = View.GONE btnInstanceInformation.visibility = View.GONE
btnDomainBlock.visibility = View.GONE btnDomainBlock.visibility = View.GONE
btnCopyAccountId.visibility = View.GONE
} else { } else {
val who_host = who.host val who_host = who.host
btnInstanceInformation.visibility = View.VISIBLE btnInstanceInformation.visibility = View.VISIBLE
@ -359,6 +368,9 @@ internal class DlgContextMenu(
btnDomainBlock.visibility = View.VISIBLE btnDomainBlock.visibility = View.VISIBLE
btnDomainBlock.text = activity.getString(R.string.block_domain_that, who_host) btnDomainBlock.text = activity.getString(R.string.block_domain_that, who_host)
} }
btnCopyAccountId.visibility = View.VISIBLE
btnCopyAccountId.text = activity.getString(R.string.copy_account_id, who.id.toString() )
} }
viewRoot.findViewById<View>(R.id.btnAccountText).setOnClickListener(this) viewRoot.findViewById<View>(R.id.btnAccountText).setOnClickListener(this)
@ -742,6 +754,7 @@ internal class DlgContextMenu(
Column.TYPE_FEDERATED_AROUND Column.TYPE_FEDERATED_AROUND
) )
R.id.btnCopyAccountId -> who.id.toString().copyToClipboard(activity)
} }
} }

View File

@ -1,5 +1,7 @@
package jp.juggler.util package jp.juggler.util
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.Color import android.graphics.Color
@ -13,8 +15,13 @@ import android.os.SystemClock
import android.support.v4.content.ContextCompat import android.support.v4.content.ContextCompat
import android.util.SparseArray import android.util.SparseArray
import android.widget.ImageView import android.widget.ImageView
import jp.juggler.subwaytooter.R
import java.util.* import java.util.*
object UiUtils{
val log = LogCategory("UiUtils")
}
// colorARGB.applyAlphaMultiplier(0.5f) でalpha値が半分になったARGB値を得る // colorARGB.applyAlphaMultiplier(0.5f) でalpha値が半分になったARGB値を得る
fun Int.applyAlphaMultiplier(alphaMultiplier : Float? = null) : Int { fun Int.applyAlphaMultiplier(alphaMultiplier : Float? = null) : Int {
return if(alphaMultiplier == null) { return if(alphaMultiplier == null) {
@ -241,3 +248,24 @@ fun setIconAttr(
alphaMultiplier alphaMultiplier
) )
} }
fun CharSequence.copyToClipboard(context:Context) {
try {
// Gets a handle to the clipboard service.
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
?: throw NotImplementedError("missing ClipboardManager system service")
// Creates a new text clip to put on the clipboard
val clip = ClipData.newPlainText("text", this)
// Set the clipboard's primary clip.
clipboard.primaryClip = clip
showToast(context, false, R.string.copy_complete)
} catch(ex : Throwable) {
UiUtils.log.trace(ex)
showToast(context, ex, "copy failed.")
}
}

View File

@ -758,6 +758,22 @@
android:textAllCaps="false" android:textAllCaps="false"
/> />
<Button
android:id="@+id/btnCopyAccountId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/btn_bg_transparent"
android:gravity="start|center_vertical"
android:minHeight="32dp"
android:paddingBottom="4dp"
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:paddingTop="4dp"
android:textAllCaps="false"
/>
<Button <Button
android:id="@+id/btnAccountQrCode" android:id="@+id/btnAccountQrCode"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -846,5 +846,6 @@
<string name="show_links_in_context_menu">本文中のリンクをコンテキストメニューに表示する</string> <string name="show_links_in_context_menu">本文中のリンクをコンテキストメニューに表示する</string>
<string name="scheduled_status_requires_mastodon_2_7_0">予約投稿はマストドン2.7.0以降で使えます</string> <string name="scheduled_status_requires_mastodon_2_7_0">予約投稿はマストドン2.7.0以降で使えます</string>
<string name="move_notifications_quick_filter_to_column_setting">通知カラムのクイックフィルタをカラム設定内部に表示する(アプリ再起動が必要)</string> <string name="move_notifications_quick_filter_to_column_setting">通知カラムのクイックフィルタをカラム設定内部に表示する(アプリ再起動が必要)</string>
<string name="copy_account_id">アカウントID %1$s をコピー</string>
</resources> </resources>

View File

@ -867,5 +867,6 @@
<string name="show_links_in_context_menu">Show links in context menu</string> <string name="show_links_in_context_menu">Show links in context menu</string>
<string name="scheduled_status_requires_mastodon_2_7_0">Scheduled status requires Mastodon 2.7.0 or later.</string> <string name="scheduled_status_requires_mastodon_2_7_0">Scheduled status requires Mastodon 2.7.0 or later.</string>
<string name="move_notifications_quick_filter_to_column_setting">Show notifications quick filter in column setting (app restart required)</string> <string name="move_notifications_quick_filter_to_column_setting">Show notifications quick filter in column setting (app restart required)</string>
<string name="copy_account_id">Copy account ID %1$s</string>
</resources> </resources>