Twidere-App-Android-Twitter.../twidere/src/main/kotlin/org/mariotaku/twidere/util/MenuUtils.kt

450 lines
20 KiB
Kotlin
Raw Normal View History

2016-07-02 05:54:53 +02:00
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util
2016-12-04 04:58:03 +01:00
import android.accounts.AccountManager
2016-07-02 05:54:53 +02:00
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
2017-04-12 10:17:20 +02:00
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.graphics.PorterDuff
import android.os.Parcelable
2020-01-26 08:35:15 +01:00
import androidx.annotation.UiThread
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.core.content.ContextCompat
import androidx.core.view.MenuItemCompat
import androidx.appcompat.widget.ShareActionProvider
2016-07-02 05:54:53 +02:00
import android.util.Log
import android.view.ContextMenu
import android.view.Menu
import android.view.MenuItem
2017-04-20 14:04:37 +02:00
import android.widget.Toast
import org.mariotaku.kpreferences.get
2017-02-28 03:17:20 +01:00
import org.mariotaku.ktextension.Bundle
import org.mariotaku.ktextension.set
2017-05-17 09:36:59 +02:00
import org.mariotaku.ktextension.setActionIcon
2017-04-12 10:17:20 +02:00
import org.mariotaku.ktextension.setItemAvailability
2017-05-17 09:36:59 +02:00
import org.mariotaku.microblog.library.mastodon.annotation.StatusVisibility
import org.mariotaku.twidere.Constants.*
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.R
import org.mariotaku.twidere.activity.AccountSelectorActivity
2017-04-12 10:17:20 +02:00
import org.mariotaku.twidere.activity.BaseActivity
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.activity.ColorPickerDialogActivity
2017-04-21 11:23:55 +02:00
import org.mariotaku.twidere.app.TwidereApplication
2017-04-12 10:17:20 +02:00
import org.mariotaku.twidere.constant.favoriteConfirmationKey
import org.mariotaku.twidere.constant.iWantMyStarsBackKey
import org.mariotaku.twidere.constant.nameFirstKey
import org.mariotaku.twidere.extension.model.isOfficial
import org.mariotaku.twidere.fragment.AbsStatusesFragment
import org.mariotaku.twidere.fragment.AddStatusFilterDialogFragment
import org.mariotaku.twidere.fragment.BaseFragment
import org.mariotaku.twidere.fragment.SetUserNicknameDialogFragment
import org.mariotaku.twidere.fragment.status.*
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.graphic.ActionIconDrawable
import org.mariotaku.twidere.graphic.PaddingDrawable
import org.mariotaku.twidere.menu.FavoriteItemProvider
import org.mariotaku.twidere.menu.SupportStatusShareProvider
2016-12-04 04:58:03 +01:00
import org.mariotaku.twidere.model.AccountDetails
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.model.ParcelableStatus
2016-12-04 04:58:03 +01:00
import org.mariotaku.twidere.model.util.AccountUtils
2017-02-07 15:55:36 +01:00
import org.mariotaku.twidere.task.CreateFavoriteTask
import org.mariotaku.twidere.task.DestroyFavoriteTask
import org.mariotaku.twidere.task.RetweetStatusTask
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.util.menu.TwidereMenuInfo
import java.io.IOException
2020-06-09 00:50:51 +02:00
import kotlin.math.roundToInt
2016-07-02 05:54:53 +02:00
/**
* Created by mariotaku on 15/4/12.
*/
2016-07-04 03:31:17 +02:00
object MenuUtils {
2016-07-02 05:54:53 +02:00
2017-04-11 16:22:50 +02:00
fun addIntentToMenu(context: Context, menu: Menu, queryIntent: Intent,
2017-02-28 03:17:20 +01:00
groupId: Int = Menu.NONE) {
2016-07-04 03:31:17 +02:00
val pm = context.packageManager
val res = context.resources
val density = res.displayMetrics.density
2020-06-09 00:50:51 +02:00
val padding = (density * 4).roundToInt()
2016-07-04 03:31:17 +02:00
val activities = pm.queryIntentActivities(queryIntent, 0)
for (info in activities) {
val intent = Intent(queryIntent)
val icon = info.loadIcon(pm)
intent.setClassName(info.activityInfo.packageName, info.activityInfo.name)
val item = menu.add(groupId, Menu.NONE, Menu.NONE, info.loadLabel(pm))
item.intent = intent
val iw = icon.intrinsicWidth
val ih = icon.intrinsicHeight
if (iw > 0 && ih > 0) {
val iconWithPadding = PaddingDrawable(icon, padding)
iconWithPadding.setBounds(0, 0, iw, ih)
item.icon = iconWithPadding
} else {
item.icon = icon
2016-07-02 05:54:53 +02:00
}
}
2016-07-04 03:31:17 +02:00
}
2016-07-02 05:54:53 +02:00
2017-04-12 10:17:20 +02:00
fun setupForStatus(context: Context, menu: Menu, preferences: SharedPreferences,
twitter: AsyncTwitterWrapper, manager: UserColorNameManager, status: ParcelableStatus) {
2016-12-04 04:58:03 +01:00
val account = AccountUtils.getAccountDetails(AccountManager.get(context),
2016-12-15 06:11:32 +01:00
status.account_key, true) ?: return
2017-04-12 10:17:20 +02:00
setupForStatus(context, menu, preferences, twitter, manager, status, account)
2016-07-04 03:31:17 +02:00
}
2016-07-02 05:54:53 +02:00
2016-07-04 03:31:17 +02:00
@UiThread
2017-04-12 10:17:20 +02:00
fun setupForStatus(context: Context, menu: Menu, preferences: SharedPreferences,
twitter: AsyncTwitterWrapper, manager: UserColorNameManager, status: ParcelableStatus,
details: AccountDetails) {
2016-07-04 03:31:17 +02:00
if (menu is ContextMenu) {
2017-04-12 10:17:20 +02:00
val displayName = manager.getDisplayName(status.user_key, status.user_name,
status.user_screen_name, preferences[nameFirstKey])
menu.setHeaderTitle(context.getString(R.string.status_menu_title_format, displayName,
2016-07-04 03:31:17 +02:00
status.text_unescaped))
}
val retweetHighlight = ContextCompat.getColor(context, R.color.highlight_retweet)
val favoriteHighlight = ContextCompat.getColor(context, R.color.highlight_favorite)
val likeHighlight = ContextCompat.getColor(context, R.color.highlight_like)
2020-06-09 01:09:31 +02:00
val isMyRetweet: Boolean =
2020-06-09 02:21:48 +02:00
when {
RetweetStatusTask.isCreatingRetweet(status.account_key, status.id) -> {
true
}
twitter.isDestroyingStatus(status.account_key, status.id) -> {
false
}
else -> {
status.retweeted || Utils.isMyRetweet(status)
}
}
val isMyStatus = Utils.isMyStatus(status)
menu.setItemAvailability(R.id.delete, isMyStatus)
if (isMyStatus) {
val isPinned = status.is_pinned_status
menu.setItemAvailability(R.id.pin, !isPinned)
menu.setItemAvailability(R.id.unpin, isPinned)
} else {
menu.setItemAvailability(R.id.pin, false)
menu.setItemAvailability(R.id.unpin, false)
2016-07-04 03:31:17 +02:00
}
val retweet = menu.findItem(R.id.retweet)
if (retweet != null) {
2017-05-17 09:36:59 +02:00
when (status.extras?.visibility) {
StatusVisibility.PRIVATE -> {
retweet.setActionIcon(context, R.drawable.ic_action_lock)
}
StatusVisibility.DIRECT -> {
retweet.setActionIcon(context, R.drawable.ic_action_message)
retweet.setIcon(R.drawable.ic_action_message)
}
else -> {
retweet.setActionIcon(context, R.drawable.ic_action_retweet)
}
}
2016-12-28 08:30:50 +01:00
retweet.setTitle(if (isMyRetweet) R.string.action_cancel_retweet else R.string.action_retweet)
2017-05-17 09:36:59 +02:00
ActionIconDrawable.setMenuHighlight(retweet, TwidereMenuInfo(isMyRetweet, retweetHighlight))
2016-07-04 03:31:17 +02:00
}
val favorite = menu.findItem(R.id.favorite)
if (favorite != null) {
2020-06-09 01:09:31 +02:00
val isFavorite: Boolean =
2020-06-09 02:21:48 +02:00
when {
CreateFavoriteTask.isCreatingFavorite(status.account_key, status.id) -> {
true
}
DestroyFavoriteTask.isDestroyingFavorite(status.account_key, status.id) -> {
false
}
else -> {
status.is_favorite
}
}
2016-07-04 03:31:17 +02:00
val provider = MenuItemCompat.getActionProvider(favorite)
2017-04-12 10:17:20 +02:00
val useStar = preferences[iWantMyStarsBackKey]
2016-07-04 03:31:17 +02:00
if (provider is FavoriteItemProvider) {
provider.setIsFavorite(favorite, isFavorite)
} else {
if (useStar) {
2017-05-17 09:36:59 +02:00
favorite.setActionIcon(context, R.drawable.ic_action_star)
2016-07-04 03:31:17 +02:00
ActionIconDrawable.setMenuHighlight(favorite, TwidereMenuInfo(isFavorite, favoriteHighlight))
2016-07-02 05:54:53 +02:00
} else {
2016-07-04 03:31:17 +02:00
ActionIconDrawable.setMenuHighlight(favorite, TwidereMenuInfo(isFavorite, likeHighlight))
2016-07-02 05:54:53 +02:00
}
}
2016-07-04 03:31:17 +02:00
if (useStar) {
2016-12-26 17:26:09 +01:00
favorite.setTitle(if (isFavorite) R.string.action_unfavorite else R.string.action_favorite)
2016-07-02 05:54:53 +02:00
} else {
2016-12-26 17:26:09 +01:00
favorite.setTitle(if (isFavorite) R.string.action_undo_like else R.string.action_like)
2016-07-02 05:54:53 +02:00
}
2016-07-04 03:31:17 +02:00
}
val translate = menu.findItem(R.id.translate)
if (translate != null) {
val isOfficialKey = details.isOfficial(context)
menu.setItemAvailability(R.id.translate, isOfficialKey)
}
val linkAvailable = LinkCreator.hasWebLink(status)
menu.setItemAvailability(R.id.copy_url, linkAvailable)
menu.setItemAvailability(R.id.open_in_browser, linkAvailable)
menu.removeGroup(MENU_GROUP_STATUS_EXTENSION)
addIntentToMenuForExtension(context, menu, MENU_GROUP_STATUS_EXTENSION,
INTENT_ACTION_EXTENSION_OPEN_STATUS, EXTRA_STATUS, EXTRA_STATUS_JSON, status)
2016-07-04 03:31:17 +02:00
val shareItem = menu.findItem(R.id.share)
val shareProvider = MenuItemCompat.getActionProvider(shareItem)
2020-06-09 02:21:48 +02:00
when {
shareProvider is SupportStatusShareProvider -> {
shareProvider.status = status
}
shareProvider is ShareActionProvider -> {
val shareIntent = Utils.createStatusShareIntent(context, status)
shareProvider.setShareIntent(shareIntent)
}
shareItem.hasSubMenu() -> {
val shareSubMenu = shareItem.subMenu
val shareIntent = Utils.createStatusShareIntent(context, status)
shareSubMenu.removeGroup(MENU_GROUP_STATUS_SHARE)
addIntentToMenu(context, shareSubMenu, shareIntent, MENU_GROUP_STATUS_SHARE)
}
else -> {
val shareIntent = Utils.createStatusShareIntent(context, status)
val chooserIntent = Intent.createChooser(shareIntent, context.getString(R.string.share_status))
shareItem.intent = chooserIntent
}
2016-07-02 05:54:53 +02:00
}
2016-07-04 03:31:17 +02:00
}
2017-04-12 10:17:20 +02:00
fun handleStatusClick(context: Context, fragment: Fragment?, fm: FragmentManager,
2020-01-26 08:35:15 +01:00
preferences: SharedPreferences, colorNameManager: UserColorNameManager,
twitter: AsyncTwitterWrapper, status: ParcelableStatus, item: MenuItem): Boolean {
2016-07-04 03:31:17 +02:00
when (item.itemId) {
R.id.copy -> {
if (ClipboardUtils.setText(context, status.text_plain)) {
2017-04-20 14:04:37 +02:00
Toast.makeText(context, R.string.text_copied, Toast.LENGTH_SHORT).show()
2016-07-02 05:54:53 +02:00
}
2016-07-04 03:31:17 +02:00
}
R.id.retweet -> {
2020-06-09 02:21:48 +02:00
when {
fragment is BaseFragment -> {
fragment.executeAfterFragmentResumed {
RetweetQuoteDialogFragment.show(it.childFragmentManager, status.account_key,
2017-04-12 10:17:20 +02:00
status.id, status)
2020-06-09 02:21:48 +02:00
}
2017-04-12 10:17:20 +02:00
}
2020-06-09 02:21:48 +02:00
context is BaseActivity -> {
context.executeAfterFragmentResumed {
RetweetQuoteDialogFragment.show(it.supportFragmentManager, status.account_key,
2017-04-12 10:17:20 +02:00
status.id, status)
2020-06-09 02:21:48 +02:00
}
2017-04-12 10:17:20 +02:00
}
2020-06-09 02:21:48 +02:00
else -> {
RetweetQuoteDialogFragment.show(fm, status.account_key,
2017-04-12 10:17:20 +02:00
status.id, status)
2020-06-09 02:21:48 +02:00
}
2016-07-02 05:54:53 +02:00
}
2016-07-04 03:31:17 +02:00
}
R.id.quote -> {
val intent = Intent(INTENT_ACTION_QUOTE)
intent.putExtra(EXTRA_STATUS, status)
context.startActivity(intent)
}
R.id.reply -> {
val intent = Intent(INTENT_ACTION_REPLY)
intent.putExtra(EXTRA_STATUS, status)
context.startActivity(intent)
}
R.id.favorite -> {
2017-04-12 10:17:20 +02:00
if (preferences[favoriteConfirmationKey]) {
2020-06-09 02:21:48 +02:00
when {
fragment is BaseFragment -> {
fragment.executeAfterFragmentResumed {
FavoriteConfirmDialogFragment.show(it.childFragmentManager,
2017-04-12 10:17:20 +02:00
status.account_key, status.id, status)
2020-06-09 02:21:48 +02:00
}
2017-04-12 10:17:20 +02:00
}
2020-06-09 02:21:48 +02:00
context is BaseActivity -> {
context.executeAfterFragmentResumed {
FavoriteConfirmDialogFragment.show(it.supportFragmentManager,
2017-04-12 10:17:20 +02:00
status.account_key, status.id, status)
2020-06-09 02:21:48 +02:00
}
2017-04-12 10:17:20 +02:00
}
2020-06-09 02:21:48 +02:00
else -> {
FavoriteConfirmDialogFragment.show(fm, status.account_key, status.id,
2017-04-12 10:17:20 +02:00
status)
2020-06-09 02:21:48 +02:00
}
2017-04-12 10:17:20 +02:00
}
} else if (status.is_favorite) {
2016-07-04 03:31:17 +02:00
twitter.destroyFavoriteAsync(status.account_key, status.id)
} else {
val provider = MenuItemCompat.getActionProvider(item)
if (provider is FavoriteItemProvider) {
provider.invokeItem(item,
AbsStatusesFragment.DefaultOnLikedListener(twitter, status))
2016-07-02 05:54:53 +02:00
} else {
2017-02-07 15:55:36 +01:00
twitter.createFavoriteAsync(status.account_key, status)
2016-07-02 05:54:53 +02:00
}
}
2016-07-04 03:31:17 +02:00
}
R.id.delete -> {
DestroyStatusDialogFragment.show(fm, status)
}
R.id.pin -> {
PinStatusDialogFragment.show(fm, status)
}
R.id.unpin -> {
UnpinStatusDialogFragment.show(fm, status)
}
2016-07-04 03:31:17 +02:00
R.id.add_to_filter -> {
AddStatusFilterDialogFragment.show(fm, status)
}
R.id.set_color -> {
val intent = Intent(context, ColorPickerDialogActivity::class.java)
val color = colorNameManager.getUserColor(status.user_key)
if (color != 0) {
intent.putExtra(EXTRA_COLOR, color)
2016-07-02 05:54:53 +02:00
}
2016-07-04 03:31:17 +02:00
intent.putExtra(EXTRA_CLEAR_BUTTON, color != 0)
intent.putExtra(EXTRA_ALPHA_SLIDER, false)
if (fragment != null) {
fragment.startActivityForResult(intent, REQUEST_SET_COLOR)
} else if (context is Activity) {
context.startActivityForResult(intent, REQUEST_SET_COLOR)
2016-07-02 05:54:53 +02:00
}
2016-07-04 03:31:17 +02:00
}
R.id.clear_nickname -> {
colorNameManager.clearUserNickname(status.user_key)
}
R.id.set_nickname -> {
val nick = colorNameManager.getUserNickname(status.user_key)
val df = SetUserNicknameDialogFragment.create(status.user_key, nick)
df.show(fm, SetUserNicknameDialogFragment.FRAGMENT_TAG)
2016-07-04 03:31:17 +02:00
}
R.id.open_with_account -> {
val intent = Intent(INTENT_ACTION_SELECT_ACCOUNT)
intent.setClass(context, AccountSelectorActivity::class.java)
intent.putExtra(EXTRA_SINGLE_SELECTION, true)
intent.putExtra(EXTRA_ACCOUNT_HOST, status.user_key.host)
if (fragment != null) {
fragment.startActivityForResult(intent, REQUEST_SELECT_ACCOUNT)
} else if (context is Activity) {
context.startActivityForResult(intent, REQUEST_SELECT_ACCOUNT)
2016-07-02 05:54:53 +02:00
}
2016-07-04 03:31:17 +02:00
}
R.id.open_in_browser -> {
val uri = LinkCreator.getStatusWebLink(status) ?: return true
2016-07-04 03:31:17 +02:00
val intent = Intent(Intent.ACTION_VIEW, uri)
intent.addCategory(Intent.CATEGORY_BROWSABLE)
intent.`package` = IntentUtils.getDefaultBrowserPackage(context, uri, true)
try {
context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
intent.`package` = null
2016-12-28 08:30:50 +01:00
context.startActivity(Intent.createChooser(intent, context.getString(R.string.action_open_in_browser)))
2016-07-02 05:54:53 +02:00
}
2016-12-01 11:08:38 +01:00
}
R.id.copy_url -> {
val uri = LinkCreator.getStatusWebLink(status) ?: return true
2016-12-01 11:08:38 +01:00
ClipboardUtils.setText(context, uri.toString())
2017-04-20 14:04:37 +02:00
Toast.makeText(context, R.string.message_toast_link_copied_to_clipboard,
Toast.LENGTH_SHORT).show()
2016-07-04 03:31:17 +02:00
}
2017-02-28 03:17:20 +01:00
R.id.mute_users -> {
val df = MuteStatusUsersDialogFragment()
df.arguments = Bundle {
this[EXTRA_STATUS] = status
}
df.show(fm, "mute_users_selector")
}
R.id.block_users -> {
val df = BlockStatusUsersDialogFragment()
df.arguments = Bundle {
this[EXTRA_STATUS] = status
}
df.show(fm, "block_users_selector")
}
2016-07-04 03:31:17 +02:00
else -> {
if (item.intent != null) {
2016-07-02 05:54:53 +02:00
try {
2016-07-04 03:31:17 +02:00
context.startActivity(item.intent)
2016-07-02 05:54:53 +02:00
} catch (e: ActivityNotFoundException) {
2016-07-04 03:31:17 +02:00
Log.w(LOGTAG, e)
return false
2016-07-02 05:54:53 +02:00
}
}
}
}
2016-07-04 03:31:17 +02:00
return true
2016-07-02 05:54:53 +02:00
}
2017-04-12 10:17:20 +02:00
fun addIntentToMenuForExtension(context: Context, menu: Menu, groupId: Int, action: String,
parcelableKey: String, jsonKey: String, obj: Parcelable) {
val pm = context.packageManager
val res = context.resources
val density = res.displayMetrics.density
2020-06-09 00:50:51 +02:00
val padding = (density * 4).roundToInt()
val queryIntent = Intent(action)
2017-04-21 11:23:55 +02:00
queryIntent.setExtrasClassLoader(TwidereApplication::class.java.classLoader)
val activities = pm.queryIntentActivities(queryIntent, PackageManager.GET_META_DATA)
val parcelableJson = try {
2017-04-12 10:17:20 +02:00
JsonSerializer.serialize(obj)
} catch (e: IOException) {
null
}
for (info in activities) {
val intent = Intent(queryIntent)
if (Utils.isExtensionUseJSON(info) && parcelableJson != null) {
2017-04-12 10:17:20 +02:00
intent.putExtra(jsonKey, parcelableJson)
} else {
2017-04-12 10:17:20 +02:00
intent.putExtra(parcelableKey, obj)
}
intent.setClassName(info.activityInfo.packageName, info.activityInfo.name)
val item = menu.add(groupId, Menu.NONE, Menu.NONE, info.loadLabel(pm))
item.intent = intent
val metaDataDrawable = Utils.getMetadataDrawable(pm, info.activityInfo, METADATA_KEY_EXTENSION_ICON)
val actionIconColor = ThemeUtils.getThemeForegroundColor(context)
if (metaDataDrawable != null) {
metaDataDrawable.mutate()
metaDataDrawable.setColorFilter(actionIconColor, PorterDuff.Mode.SRC_ATOP)
item.icon = metaDataDrawable
} else {
val icon = info.loadIcon(pm)
val iw = icon.intrinsicWidth
val ih = icon.intrinsicHeight
if (iw > 0 && ih > 0) {
val iconWithPadding = PaddingDrawable(icon, padding)
iconWithPadding.setBounds(0, 0, iw, ih)
item.icon = iconWithPadding
} else {
item.icon = icon
}
}
}
}
2016-07-02 05:54:53 +02:00
}
2017-05-17 09:36:59 +02:00