This commit is contained in:
Mariotaku Lee 2017-09-11 22:20:45 +08:00
parent f4ec5dd81d
commit cd11d92118
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
8 changed files with 119 additions and 57 deletions

View File

@ -37,13 +37,13 @@ import org.apache.commons.cli.*
import org.json.JSONArray
import org.json.JSONObject
import org.mariotaku.ktextension.subArray
import org.mariotaku.twidere.exception.NoAccountException
import org.mariotaku.twidere.extension.model.updateDetails
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.util.DataStoreUtils
import org.mariotaku.twidere.util.JsonSerializer
import org.mariotaku.twidere.util.Utils
import java.io.InputStream
import java.io.OutputStream
import java.nio.ByteBuffer
@ -174,7 +174,7 @@ class AccountsDumperPlugin(val context: Context) : DumperPlugin {
val am = AccountManager.get(context)
val docContext = try {
am.docContext(args[0])
} catch (e: Utils.NoAccountException) {
} catch (e: NoAccountException) {
throw DumpException("Account not found")
}
if (args.size == 1) {
@ -196,7 +196,7 @@ class AccountsDumperPlugin(val context: Context) : DumperPlugin {
val am = AccountManager.get(context)
val docContext = try {
am.docContext(args[0])
} catch (e: Utils.NoAccountException) {
} catch (e: NoAccountException) {
throw DumpException("Account not found")
}
val value = args[2]
@ -219,7 +219,7 @@ class AccountsDumperPlugin(val context: Context) : DumperPlugin {
val am = AccountManager.get(context)
val docContext = try {
am.docContext(args[0])
} catch (e: Utils.NoAccountException) {
} catch (e: NoAccountException) {
throw DumpException("Account not found")
}
val value = args[2]
@ -308,7 +308,7 @@ class AccountsDumperPlugin(val context: Context) : DumperPlugin {
private fun AccountManager.docContext(forKey: String): DocumentContext {
val accountKey = UserKey.valueOf(forKey)
val details = AccountUtils.getAccountDetails(this, accountKey, true) ?: throw Utils.NoAccountException()
val details = AccountUtils.getAccountDetails(this, accountKey, true) ?: throw NoAccountException()
val configuration = Configuration.builder()
.jsonProvider(JsonOrgJsonProvider())
.mappingProvider(AsIsMappingProvider())

View File

@ -95,7 +95,7 @@ class AccountSelectorActivity : BaseActivity(), OnItemClickListener {
val oauthOnly = isOAuthOnly
val accountHost = accountHost
val accountType = accountType
addAll(allAccountDetails.filter {
val matchedAccounts = allAccountDetails.filter {
if (extraKeys != null) {
return@filter extraKeys.contains(it.key)
}
@ -104,14 +104,15 @@ class AccountSelectorActivity : BaseActivity(), OnItemClickListener {
}
if (USER_TYPE_TWITTER_COM == accountHost) {
if (it.key.host != null && it.type != AccountType.TWITTER) return@filter false
} else if (accountHost != null) {
} else if (accountHost != null && accountType == AccountType.MASTODON) {
if (accountHost != it.key.host) return@filter false
}
if (accountType != null) {
if (accountType != it.type) return@filter false
}
return@filter true
})
}
addAll(matchedAccounts)
}
accountsList.choiceMode = if (isSingleSelection) ListView.CHOICE_MODE_NONE else ListView.CHOICE_MODE_MULTIPLE
if (isSingleSelection) {

View File

@ -49,6 +49,7 @@ import org.mariotaku.twidere.R
import org.mariotaku.twidere.activity.iface.IControlBarActivity
import org.mariotaku.twidere.activity.iface.IControlBarActivity.ControlBarShowHideHelper
import org.mariotaku.twidere.constant.*
import org.mariotaku.twidere.exception.NoAccountException
import org.mariotaku.twidere.fragment.*
import org.mariotaku.twidere.fragment.filter.FiltersFragment
import org.mariotaku.twidere.fragment.filter.FiltersImportBlocksFragment
@ -119,13 +120,16 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowInsetsCallback, IControl
finish()
return
}
} catch (e: Utils.NoAccountException) {
} catch (e: NoAccountException) {
val selectIntent = Intent(this, AccountSelectorActivity::class.java)
val accountHost: String? = intent.getStringExtra(EXTRA_ACCOUNT_HOST) ?:
uri.getQueryParameter(QUERY_PARAM_ACCOUNT_HOST) ?: e.accountHost
val accountType: String? = intent.getStringExtra(EXTRA_ACCOUNT_TYPE) ?:
uri.getQueryParameter(QUERY_PARAM_ACCOUNT_TYPE) ?: e.accountType
selectIntent.putExtra(EXTRA_SINGLE_SELECTION, true)
selectIntent.putExtra(EXTRA_SELECT_ONLY_ITEM_AUTOMATICALLY, true)
selectIntent.putExtra(EXTRA_ACCOUNT_HOST, accountHost)
selectIntent.putExtra(EXTRA_ACCOUNT_TYPE, accountType)
selectIntent.putExtra(EXTRA_START_INTENT, intent)
startActivity(selectIntent)
finish()
@ -546,7 +550,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowInsetsCallback, IControl
fab.contentDescription = info.title
}
@Throws(Utils.NoAccountException::class)
@Throws(NoAccountException::class)
private fun createFragmentForIntent(context: Context, linkId: Int, intent: Intent): Fragment? {
intent.setExtrasClassLoader(classLoader)
val extras = intent.extras
@ -564,6 +568,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowInsetsCallback, IControl
}
var userHost: String? = null
var accountType: String? = null
var accountRequired = true
when (linkId) {
LINK_ID_ACCOUNTS -> {
@ -616,6 +621,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowInsetsCallback, IControl
if (paramUserKey != null) {
userHost = paramUserKey.host
}
accountType = uri.getQueryParameter(QUERY_PARAM_ACCOUNT_TYPE)
}
LINK_ID_USER_LIST_MEMBERSHIPS -> {
fragment = UserListMembershipsFragment()
@ -908,8 +914,9 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowInsetsCallback, IControl
}
if (accountRequired && accountKey == null) {
val exception = Utils.NoAccountException()
val exception = NoAccountException()
exception.accountHost = userHost
exception.accountType = accountType
throw exception
}
args.putParcelable(EXTRA_ACCOUNT_KEY, accountKey)

View File

@ -0,0 +1,22 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2017 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.exception
class NoAccountException(var accountHost: String? = null, var accountType: String? = null) : Exception()

View File

@ -80,6 +80,9 @@ fun View.hideIfEmpty(dependency: TextView, hideVisibility: Int = View.GONE) {
}
}
fun View.setVisible(visible: Boolean, hiddenVisibility: Int = View.GONE) {
visibility = if (visible) View.VISIBLE else hiddenVisibility
}
private fun offsetToRoot(view: View, rect: Rect) {
var parent = view.parent as? View
while (parent != null) {

View File

@ -94,8 +94,6 @@ import java.util.regex.Pattern
object Utils {
class NoAccountException(var accountHost: String? = null) : Exception()
private val PATTERN_XML_RESOURCE_IDENTIFIER = Pattern.compile("res/xml/([\\w_]+)\\.xml")
private val PATTERN_RESOURCE_IDENTIFIER = Pattern.compile("@([\\w_]+)/([\\w_]+)")

View File

@ -1,5 +1,6 @@
package org.mariotaku.twidere.view.holder
import android.support.annotation.DrawableRes
import android.support.v4.content.ContextCompat
import android.support.v4.widget.TextViewCompat
import android.support.v7.widget.RecyclerView
@ -27,6 +28,7 @@ import org.mariotaku.twidere.extension.model.applyTo
import org.mariotaku.twidere.extension.model.quoted_user_acct
import org.mariotaku.twidere.extension.model.retweeted_by_user_acct
import org.mariotaku.twidere.extension.model.user_acct
import org.mariotaku.twidere.extension.setVisible
import org.mariotaku.twidere.graphic.like.LikeAnimationDrawable
import org.mariotaku.twidere.model.ParcelableLocation
import org.mariotaku.twidere.model.ParcelableMedia
@ -36,8 +38,11 @@ import org.mariotaku.twidere.task.CreateFavoriteTask
import org.mariotaku.twidere.task.DestroyFavoriteTask
import org.mariotaku.twidere.task.RetweetStatusTask
import org.mariotaku.twidere.text.TwidereClickableSpan
import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.HtmlEscapeHelper.toPlainText
import org.mariotaku.twidere.util.HtmlSpanBuilder
import org.mariotaku.twidere.util.ThemeUtils
import org.mariotaku.twidere.util.UnitConvertUtils
import org.mariotaku.twidere.util.Utils
import org.mariotaku.twidere.util.Utils.getUserTypeIconRes
import org.mariotaku.twidere.view.ShapedImageView
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder
@ -162,13 +167,6 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
statusInfoLabel.visibility = View.VISIBLE
statusInfoIcon.visibility = View.VISIBLE
statusContentUpperSpace.visibility = View.GONE
} else if (TwitterCardUtils.isPoll(status)) {
statusInfoLabel.setText(R.string.label_poll)
statusInfoIcon.setImageResource(R.drawable.ic_activity_action_poll)
statusInfoLabel.visibility = View.VISIBLE
statusInfoIcon.visibility = View.VISIBLE
statusContentUpperSpace.visibility = View.GONE
} else if (status.retweet_id != null) {
val retweetedBy = colorNameManager.getDisplayName(status.retweeted_by_user_key!!,
@ -319,20 +317,19 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
itemContent.drawEnd()
}
val hasMediaLabel = mediaLabel.displayMediaLabel(status.card_name, status.media, status.location,
status.place_full_name, status.is_possibly_sensitive)
if (status.media.isNotNullOrEmpty()) {
mediaLabel.displayMediaLabel(status.card_name, status.media, status.location,
status.place_full_name, status.is_possibly_sensitive)
if (!adapter.sensitiveContentEnabled && status.is_possibly_sensitive) {
// Sensitive content, show label instead of media view
mediaLabel.visibility = View.VISIBLE
mediaLabel.contentDescription = status.media?.firstOrNull()?.alt_text
mediaLabel.setVisible(hasMediaLabel)
mediaPreview.visibility = View.GONE
} else if (!adapter.mediaPreviewEnabled) {
// Media preview disabled, just show label
mediaLabel.visibility = View.VISIBLE
mediaLabel.contentDescription = status.media?.firstOrNull()?.alt_text
mediaLabel.setVisible(hasMediaLabel)
mediaPreview.visibility = View.GONE
} else {
// Show media
@ -344,8 +341,8 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
mediaClickListener = this)
}
} else {
// No media, hide all related views
mediaLabel.visibility = View.GONE
// No media, hide media preview
mediaLabel.setVisible(hasMediaLabel)
mediaPreview.visibility = View.GONE
}
@ -438,36 +435,37 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
}
private fun displayQuotedMedia(requestManager: RequestManager, status: ParcelableStatus) {
if (status.quoted_media?.isNotEmpty() ?: false) {
quotedMediaLabel.displayMediaLabel(null, status.quoted_media, null, null,
status.is_possibly_sensitive)
val hasMediaLabel = quotedMediaLabel.displayMediaLabel(null, status.quoted_media,
null, null, status.is_possibly_sensitive)
if (status.quoted_media.isNotNullOrEmpty()) {
if (!adapter.sensitiveContentEnabled && status.is_possibly_sensitive) {
quotedMediaLabel.setVisible(hasMediaLabel)
// Sensitive content, show label instead of media view
quotedMediaPreview.visibility = View.GONE
quotedMediaLabel.visibility = View.VISIBLE
} else if (!adapter.mediaPreviewEnabled) {
quotedMediaLabel.setVisible(hasMediaLabel)
// Media preview disabled, just show label
quotedMediaPreview.visibility = View.GONE
quotedMediaLabel.visibility = View.VISIBLE
} else if (status.media.isNotNullOrEmpty()) {
quotedMediaLabel.setVisible(hasMediaLabel)
// Already displaying media, show label only
quotedMediaPreview.visibility = View.GONE
quotedMediaLabel.visibility = View.VISIBLE
} else {
quotedMediaLabel.visibility = View.GONE
// Show media
quotedMediaPreview.visibility = View.VISIBLE
quotedMediaLabel.visibility = View.GONE
quotedMediaPreview.displayMedia(requestManager = requestManager,
media = status.quoted_media, accountKey = status.account_key,
mediaClickListener = this)
}
} else {
quotedMediaLabel.setVisible(hasMediaLabel)
// No media, hide all related views
quotedMediaPreview.visibility = View.GONE
quotedMediaLabel.visibility = View.GONE
}
}
@ -605,35 +603,51 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
}
private fun TextView.displayMediaLabel(cardName: String?, media: Array<ParcelableMedia?>?,
location: ParcelableLocation?, placeFullName: String?,
sensitive: Boolean) {
location: ParcelableLocation?, placeFullName: String?, sensitive: Boolean): Boolean {
var result = false
if (sensitive) {
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(this, R.drawable.ic_label_warning, 0, 0, 0)
setLabelIcon(R.drawable.ic_label_warning)
setText(R.string.label_sensitive_content)
result = true
} else if (media != null && media.isNotEmpty()) {
val type = media.type
if (type in videoTypes) {
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(this, R.drawable.ic_label_video, 0, 0, 0)
setText(R.string.label_video)
} else if (media.size > 1) {
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(this, R.drawable.ic_label_gallery, 0, 0, 0)
setText(R.string.label_photos)
} else {
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(this, R.drawable.ic_label_gallery, 0, 0, 0)
setText(R.string.label_photo)
when {
type in videoTypes -> {
setLabelIcon(R.drawable.ic_label_video)
setText(R.string.label_video)
}
media.size > 1 -> {
setLabelIcon(R.drawable.ic_label_gallery)
setText(R.string.label_photos)
}
else -> {
setLabelIcon(R.drawable.ic_label_gallery)
setText(R.string.label_photo)
}
}
result = true
} else if (cardName != null) {
if (cardName.startsWith("poll")) {
setLabelIcon(R.drawable.ic_label_poll)
setText(R.string.label_poll)
result = true
}
} else {
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(this, R.drawable.ic_label_gallery, 0, 0, 0)
setText(R.string.label_media)
}
refreshDrawableState()
return result
}
private val Array<ParcelableMedia?>.type: Int get() {
forEach { if (it != null) return it.type }
return 0
private fun TextView.setLabelIcon(@DrawableRes icon: Int) {
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(this, icon, 0,
0, 0)
}
private val Array<ParcelableMedia?>.type: Int
get() {
forEach { if (it != null) return it.type }
return 0
}
private fun hasVideo(media: Array<ParcelableMedia?>?): Boolean {
if (media == null) return false
return media.any { item ->
@ -673,8 +687,12 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
listener.onItemActionClick(holder, R.id.favorite, position)
}
holder.mediaLabel -> {
val firstMedia = holder.adapter.getStatus(position).media?.firstOrNull() ?: return
listener.onMediaClick(holder, v, firstMedia, position)
val firstMedia = holder.adapter.getStatus(position).media?.firstOrNull()
if (firstMedia != null) {
listener.onMediaClick(holder, v, firstMedia, position)
} else {
listener.onStatusClick(holder, position)
}
}
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
<title>ic_label_poll-mdpi</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Action-Icons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="ic_label_poll-mdpi">
<polygon id="Shape" points="2 2 22 2 22 22 2 22"></polygon>
<path d="M9.63512195,8.453125 L9.63512195,11.71875 C9.63512195,11.9583333 9.54926829,12.1640625 9.37756098,12.3359375 C9.20585366,12.5078125 8.99772358,12.59375 8.75317073,12.59375 C8.50861789,12.59375 8.3004878,12.5078125 8.12878049,12.3359375 C7.95707317,12.1640625 7.87121951,11.9583333 7.87121951,11.71875 L7.87121951,8.453125 C7.87121951,8.21354167 7.95707317,8.00520833 8.12878049,7.828125 C8.3004878,7.65104167 8.50861789,7.5625 8.75317073,7.5625 C8.99772358,7.5625 9.20585366,7.65104167 9.37756098,7.828125 C9.54926829,8.00520833 9.63512195,8.21354167 9.63512195,8.453125 L9.63512195,8.453125 Z M16.1443902,8.453125 L16.1443902,13.484375 C16.1443902,13.734375 16.0585366,13.9453125 15.8868293,14.1171875 C15.715122,14.2890625 15.5069919,14.375 15.262439,14.375 C15.0178862,14.375 14.8097561,14.2890625 14.6380488,14.1171875 C14.4663415,13.9453125 14.3804878,13.734375 14.3804878,13.484375 L14.3804878,8.453125 C14.3804878,8.21354167 14.4663415,8.00520833 14.6380488,7.828125 C14.8097561,7.65104167 15.0178862,7.5625 15.262439,7.5625 C15.5069919,7.5625 15.715122,7.65104167 15.8868293,7.828125 C16.0585366,8.00520833 16.1443902,8.21354167 16.1443902,8.453125 L16.1443902,8.453125 Z M12.897561,8.453125 L12.897561,15.859375 C12.897561,16.0989583 12.8091057,16.3072917 12.6321951,16.484375 C12.4552846,16.6614583 12.2471545,16.75 12.0078049,16.75 C11.7684553,16.75 11.5603252,16.6614583 11.3834146,16.484375 C11.2065041,16.3072917 11.1180488,16.0989583 11.1180488,15.859375 L11.1180488,8.453125 C11.1180488,8.21354167 11.2065041,8.00520833 11.3834146,7.828125 C11.5603252,7.65104167 11.7684553,7.5625 12.0078049,7.5625 C12.2471545,7.5625 12.4552846,7.65104167 12.6321951,7.828125 C12.8091057,8.00520833 12.897561,8.21354167 12.897561,8.453125 L12.897561,8.453125 Z M7.01268293,20 L17.0029268,20 C17.8354472,20 18.5430894,19.7083333 19.1258537,19.125 C19.7086179,18.5416667 20,17.8333333 20,17 L20,7 C20,6.16666667 19.7086179,5.45833333 19.1258537,4.875 C18.5430894,4.29166667 17.8354472,4 17.0029268,4 L7.01268293,4 C6.1801626,4 5.4699187,4.29166667 4.88195122,4.875 C4.29398374,5.45833333 4,6.16666667 4,7 L4,17 C4,17.8333333 4.29398374,18.5416667 4.88195122,19.125 C5.4699187,19.7083333 6.1801626,20 7.01268293,20 L7.01268293,20 Z" id="Shape" fill="#FFFFFF" transform="translate(12.000000, 12.000000) scale(1, -1) translate(-12.000000, -12.000000) "></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB