diff --git a/app/src/main/java/com/keylesspalace/tusky/AboutActivity.kt b/app/src/main/java/com/keylesspalace/tusky/AboutActivity.kt index af012d301..93cb08478 100644 --- a/app/src/main/java/com/keylesspalace/tusky/AboutActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/AboutActivity.kt @@ -1,8 +1,5 @@ package com.keylesspalace.tusky -import android.content.ClipData -import android.content.ClipboardManager -import android.content.Context import android.content.Intent import android.os.Build import android.os.Bundle @@ -12,12 +9,12 @@ import android.text.method.LinkMovementMethod import android.text.style.URLSpan import android.text.util.Linkify import android.widget.TextView -import android.widget.Toast import androidx.annotation.StringRes import androidx.lifecycle.lifecycleScope import com.keylesspalace.tusky.components.instanceinfo.InstanceInfoRepository import com.keylesspalace.tusky.databinding.ActivityAboutBinding import com.keylesspalace.tusky.util.NoUnderlineURLSpan +import com.keylesspalace.tusky.util.copyToClipboard import com.keylesspalace.tusky.util.hide import com.keylesspalace.tusky.util.show import com.keylesspalace.tusky.util.startActivityWithSlideInAnimation @@ -91,13 +88,11 @@ class AboutActivity : BottomSheetActivity() { } binding.copyDeviceInfo.setOnClickListener { - val text = "${binding.versionTextView.text}\n\nDevice:\n\n${binding.deviceInfo.text}\n\nAccount:\n\n${binding.accountInfo.text}" - val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - val clip = ClipData.newPlainText("Tusky version information", text) - clipboard.setPrimaryClip(clip) - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) { - Toast.makeText(this, getString(R.string.about_copied), Toast.LENGTH_SHORT).show() - } + copyToClipboard( + "${binding.versionTextView.text}\n\nDevice:\n\n${binding.deviceInfo.text}\n\nAccount:\n\n${binding.accountInfo.text}", + getString(R.string.about_copied), + "Tusky version information", + ) } } } diff --git a/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt b/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt index 10bfffb5f..de142c62d 100644 --- a/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt @@ -19,8 +19,6 @@ import android.Manifest import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.app.DownloadManager -import android.content.ClipData -import android.content.ClipboardManager import android.content.Context import android.content.Intent import android.graphics.Bitmap @@ -53,6 +51,7 @@ import com.keylesspalace.tusky.fragment.ViewImageFragment import com.keylesspalace.tusky.fragment.ViewVideoFragment import com.keylesspalace.tusky.pager.ImagePagerAdapter import com.keylesspalace.tusky.pager.SingleImagePagerAdapter +import com.keylesspalace.tusky.util.copyToClipboard import com.keylesspalace.tusky.util.getParcelableArrayListExtraCompat import com.keylesspalace.tusky.util.getTemporaryMediaFilename import com.keylesspalace.tusky.util.startActivityWithSlideInAnimation @@ -253,9 +252,10 @@ class ViewMediaActivity : } private fun copyLink() { - val url = imageUrl ?: attachments!![binding.viewPager.currentItem].attachment.url - val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - clipboard.setPrimaryClip(ClipData.newPlainText(null, url)) + copyToClipboard( + imageUrl ?: attachments!![binding.viewPager.currentItem].attachment.url, + getString(R.string.url_copied), + ) } private fun shareMedia() { diff --git a/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt index c04bd6dc4..00605189e 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt @@ -16,8 +16,6 @@ package com.keylesspalace.tusky.components.account import android.animation.ArgbEvaluator -import android.content.ClipData -import android.content.ClipboardManager import android.content.Context import android.content.Intent import android.content.res.ColorStateList @@ -82,6 +80,7 @@ import com.keylesspalace.tusky.settings.PrefKeys import com.keylesspalace.tusky.util.Error import com.keylesspalace.tusky.util.Loading import com.keylesspalace.tusky.util.Success +import com.keylesspalace.tusky.util.copyToClipboard import com.keylesspalace.tusky.util.emojify import com.keylesspalace.tusky.util.getDomain import com.keylesspalace.tusky.util.hide @@ -484,15 +483,10 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide for (view in listOf(binding.accountUsernameTextView, binding.accountDisplayNameTextView)) { view.setOnLongClickListener { loadedAccount?.let { loadedAccount -> - val fullUsername = getFullUsername(loadedAccount) - val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - clipboard.setPrimaryClip(ClipData.newPlainText(null, fullUsername)) - Snackbar.make( - binding.root, + copyToClipboard( + getFullUsername(loadedAccount), getString(R.string.account_username_copied), - Snackbar.LENGTH_SHORT ) - .show() } true } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt index bd235c25b..0a843eec1 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt @@ -19,11 +19,13 @@ import at.connyduck.calladapter.networkresult.fold import com.google.android.material.snackbar.Snackbar import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.R +import com.keylesspalace.tusky.StatusListActivity import com.keylesspalace.tusky.components.compose.ComposeAutoCompleteAdapter import com.keylesspalace.tusky.databinding.ActivityFollowedTagsBinding import com.keylesspalace.tusky.interfaces.HashtagActionListener import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.settings.PrefKeys +import com.keylesspalace.tusky.util.copyToClipboard import com.keylesspalace.tusky.util.hide import com.keylesspalace.tusky.util.show import com.keylesspalace.tusky.util.viewBinding @@ -180,6 +182,17 @@ class FollowedTagsActivity : return viewModel.searchAutocompleteSuggestions(token) } + override fun viewTag(tagName: String) { + startActivity(StatusListActivity.newHashtagIntent(this, tagName)) + } + + override fun copyTagName(tagName: String) { + copyToClipboard( + "#$tagName", + getString(R.string.confirmation_hashtag_copied, tagName), + ) + } + companion object { const val TAG = "FollowedTagsActivity" } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsAdapter.kt index 211be5630..5df59a5a1 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsAdapter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsAdapter.kt @@ -27,7 +27,17 @@ class FollowedTagsAdapter( position: Int ) { viewModel.tags[position].let { tag -> - holder.itemView.findViewById(R.id.followed_tag).text = tag.name + holder.itemView.findViewById(R.id.followed_tag).apply { + text = tag.name + setOnClickListener { + actionListener.viewTag(tag.name) + } + setOnLongClickListener { + actionListener.copyTagName(tag.name) + true + } + } + holder.itemView.findViewById( R.id.followed_tag_unfollow ).setOnClickListener { diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt index 8bad5e629..85d7c406d 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt @@ -17,9 +17,6 @@ package com.keylesspalace.tusky.components.search.fragments import android.Manifest import android.app.DownloadManager -import android.content.ClipData -import android.content.ClipboardManager -import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.net.Uri @@ -60,6 +57,7 @@ import com.keylesspalace.tusky.settings.PrefKeys import com.keylesspalace.tusky.util.CardViewMode import com.keylesspalace.tusky.util.ListStatusAccessibilityDelegate import com.keylesspalace.tusky.util.StatusDisplayOptions +import com.keylesspalace.tusky.util.copyToClipboard import com.keylesspalace.tusky.util.openLink import com.keylesspalace.tusky.util.startActivityWithSlideInAnimation import com.keylesspalace.tusky.view.showMuteAccountDialog @@ -398,10 +396,7 @@ class SearchStatusesFragment : SearchFragment(), Status } R.id.status_copy_link -> { - val clipboard = requireActivity().getSystemService( - Context.CLIPBOARD_SERVICE - ) as ClipboardManager - clipboard.setPrimaryClip(ClipData.newPlainText(null, statusUrl)) + statusUrl?.let { requireActivity().copyToClipboard(it, getString(R.string.url_copied)) } return@setOnMenuItemClickListener true } diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt index 26529763a..203079604 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt @@ -16,8 +16,6 @@ package com.keylesspalace.tusky.fragment import android.Manifest import android.app.DownloadManager -import android.content.ClipData -import android.content.ClipboardManager import android.content.Context import android.content.DialogInterface import android.content.Intent @@ -59,6 +57,7 @@ import com.keylesspalace.tusky.entity.Translation import com.keylesspalace.tusky.interfaces.AccountSelectionListener import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.usecase.TimelineCases +import com.keylesspalace.tusky.util.copyToClipboard import com.keylesspalace.tusky.util.openLink import com.keylesspalace.tusky.util.parseAsMastodonHtml import com.keylesspalace.tusky.util.startActivityWithSlideInAnimation @@ -290,13 +289,7 @@ abstract class SFragment(@LayoutRes contentLayoutId: Int) : Fragment(contentLayo } R.id.status_copy_link -> { - ( - requireActivity().getSystemService( - Context.CLIPBOARD_SERVICE - ) as ClipboardManager - ).apply { - setPrimaryClip(ClipData.newPlainText(null, statusUrl)) - } + statusUrl?.let { requireActivity().copyToClipboard(it, getString(R.string.url_copied)) } return@setOnMenuItemClickListener true } diff --git a/app/src/main/java/com/keylesspalace/tusky/interfaces/HashtagActionListener.kt b/app/src/main/java/com/keylesspalace/tusky/interfaces/HashtagActionListener.kt index a223f268d..e617195c9 100644 --- a/app/src/main/java/com/keylesspalace/tusky/interfaces/HashtagActionListener.kt +++ b/app/src/main/java/com/keylesspalace/tusky/interfaces/HashtagActionListener.kt @@ -2,4 +2,6 @@ package com.keylesspalace.tusky.interfaces interface HashtagActionListener { fun unfollow(tagName: String, position: Int) + fun viewTag(tagName: String) + fun copyTagName(tagName: String) } diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ActivityExtensions.kt b/app/src/main/java/com/keylesspalace/tusky/util/ActivityExtensions.kt index 724ea69a4..a58f4f45a 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/ActivityExtensions.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/ActivityExtensions.kt @@ -3,8 +3,12 @@ package com.keylesspalace.tusky.util import android.app.Activity +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context import android.content.Intent import android.os.Build +import android.widget.Toast import androidx.activity.ComponentActivity import androidx.annotation.AnimRes import androidx.lifecycle.Lifecycle @@ -47,6 +51,14 @@ fun ComponentActivity.overrideActivityTransitionCompat( } } +fun Activity.copyToClipboard(text: CharSequence, popupText: CharSequence, clipboardLabel: CharSequence = "") { + val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + clipboard.setPrimaryClip(ClipData.newPlainText(clipboardLabel, text)) + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) { + Toast.makeText(this, popupText, Toast.LENGTH_SHORT).show() + } +} + object ActivityConstants { const val OVERRIDE_TRANSITION_OPEN = 0 const val OVERRIDE_TRANSITION_CLOSE = 1 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6e16daec4..36265cf5e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -222,12 +222,14 @@ Share account username to… Share media to… Username copied + Url copied Sent! User unblocked User unmuted %1$s unhidden #%1$s unfollowed + \'#%1$s\' copied Sending… Your reply is being sent.