redesigned compose account picker, fixed #301

This commit is contained in:
Mariotaku Lee 2017-03-28 21:27:08 +08:00
parent 3d219368cd
commit 256a3233a5
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
8 changed files with 367 additions and 158 deletions

View File

@ -1,23 +0,0 @@
package android.support.v7.widget;
import android.content.Context;
import android.support.v7.widget.android.support.v7.view.menu.TwidereActionMenuItemView;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by mariotaku on 16/3/18.
*/
public class TwidereActionMenuView extends ActionMenuView {
public TwidereActionMenuView(Context context) {
super(context);
}
public TwidereActionMenuView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public View createActionMenuView(Context context, AttributeSet attrs) {
return new TwidereActionMenuItemView(context, attrs);
}
}

View File

@ -0,0 +1,16 @@
package android.support.v7.widget
import android.content.Context
import android.support.v7.widget.android.support.v7.view.menu.TwidereActionMenuItemView
import android.util.AttributeSet
import android.view.View
/**
* Created by mariotaku on 16/3/18.
*/
class TwidereActionMenuView(context: Context, attrs: AttributeSet? = null) : ActionMenuView(context, attrs) {
fun createActionMenuView(context: Context, attrs: AttributeSet): View {
return TwidereActionMenuItemView(context, attrs)
}
}

View File

@ -20,6 +20,8 @@
package org.mariotaku.twidere.activity
import android.accounts.AccountManager
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.app.Activity
import android.app.Dialog
import android.content.ActivityNotFoundException
@ -39,7 +41,6 @@ import android.support.v4.app.DialogFragment
import android.support.v7.app.AlertDialog
import android.support.v7.view.SupportMenuInflater
import android.support.v7.widget.ActionMenuView.OnMenuItemClickListener
import android.support.v7.widget.DefaultItemAnimator
import android.support.v7.widget.FixedLinearLayoutManager
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
@ -54,6 +55,8 @@ import android.util.Log
import android.view.*
import android.view.View.OnClickListener
import android.view.View.OnLongClickListener
import android.view.animation.DecelerateInterpolator
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import com.bumptech.glide.Glide
@ -98,6 +101,8 @@ import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.EditTextEnterHandler.EnterListener
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
import org.mariotaku.twidere.util.premium.ExtraFeaturesService
import org.mariotaku.twidere.util.view.ViewAnimator
import org.mariotaku.twidere.util.view.ViewProperties
import org.mariotaku.twidere.view.CheckableLinearLayout
import org.mariotaku.twidere.view.ExtendedRecyclerView
import org.mariotaku.twidere.view.ShapedImageView
@ -121,6 +126,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
lateinit var locationManager: LocationManager
private lateinit var itemTouchHelper: ItemTouchHelper
private lateinit var bottomMenuAnimator: ViewAnimator
private val supportMenuInflater by lazy { SupportMenuInflater(this) }
private var currentTask: AsyncTask<Any, Any, *>? = null
@ -161,6 +167,9 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
nameFirst = preferences[nameFirstKey]
setContentView(R.layout.activity_compose)
bottomMenuAnimator = ViewAnimator()
bottomMenuAnimator.setupViews()
mediaPreviewAdapter = MediaPreviewAdapter(this, Glide.with(this))
mediaPreviewAdapter.listener = object : MediaPreviewAdapter.Listener {
override fun onEditClick(position: Int, holder: MediaPreviewViewHolder) {
@ -192,7 +201,6 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
val defaultAccountIds = accountDetails.map(AccountDetails::key).toTypedArray()
menuBar.setOnMenuItemClickListener(this)
setupEditText()
accountSelectorContainer.setOnClickListener(this)
accountSelectorButton.setOnClickListener(this)
replyLabel.setOnClickListener(this)
locationSwitch.max = LOCATION_OPTIONS.size
@ -244,10 +252,11 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
}
accountSelector.layoutManager = FixedLinearLayoutManager(this).apply {
orientation = LinearLayoutManager.VERTICAL
stackFromEnd = true
orientation = LinearLayoutManager.HORIZONTAL
reverseLayout = false
stackFromEnd = false
}
accountSelector.itemAnimator = DefaultItemAnimator()
// accountSelector.itemAnimator = DefaultItemAnimator()
accountsAdapter = AccountIconsAdapter(this).apply {
setAccounts(accountDetails)
}
@ -322,6 +331,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
updateUpdateStatusIcon()
textChanged = false
bottomMenuAnimator.showView(composeMenu, false)
updateAttachedMediaView()
}
@ -461,9 +471,6 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
updateStatus -> {
confirmAndUpdateStatus()
}
accountSelectorContainer -> {
isAccountSelectorVisible = false
}
accountSelectorButton -> {
isAccountSelectorVisible = !isAccountSelectorVisible
}
@ -475,9 +482,10 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
}
private var isAccountSelectorVisible: Boolean
get() = accountSelectorContainer.visibility == View.VISIBLE
get() = bottomMenuAnimator.currentChild == accountSelector
set(visible) {
accountSelectorContainer.visibility = if (visible) View.VISIBLE else View.GONE
bottomMenuAnimator.showView(if (visible) accountSelector else composeMenu, true)
displaySelectedAccountsIcon()
}
private fun confirmAndUpdateStatus() {
@ -655,27 +663,56 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
return draftUri
}
fun setSelectedAccounts(vararg accounts: AccountDetails) {
if (accounts.size == 1) {
accountsCount.setText(null)
val account = accounts[0]
val profileImageStyle = preferences[profileImageStyleKey]
Glide.with(this).loadProfileImage(this, account, profileImageStyle).into(accountProfileImage)
accountProfileImage.setBorderColor(account.color)
} else {
accountsCount.setText(accounts.size.toString())
//TODO cancel image load
accountProfileImage.setImageDrawable(null)
accountProfileImage.setBorderColors(*Utils.getAccountColors(accounts))
}
}
override fun onActionModeStarted(mode: ActionMode) {
super.onActionModeStarted(mode)
ThemeUtils.applyColorFilterToMenuIcon(mode.menu, ThemeUtils.getContrastActionBarItemColor(this),
0, 0, Mode.MULTIPLY)
}
private fun displaySelectedAccountsIcon() {
val accounts = accountsAdapter.selectedAccounts
val account = accounts.singleOrNull()
val displayDoneIcon = isAccountSelectorVisible
if (account != null) {
accountsCount.setText(null)
if (displayDoneIcon) {
Glide.clear(accountProfileImage)
accountProfileImage.setColorFilter(ThemeUtils.getColorFromAttribute(this,
android.R.attr.colorForeground, 0))
accountProfileImage.scaleType = ImageView.ScaleType.CENTER_INSIDE
accountProfileImage.setImageResource(R.drawable.ic_action_confirm)
} else {
accountProfileImage.clearColorFilter()
accountProfileImage.scaleType = ImageView.ScaleType.CENTER_CROP
Glide.with(this).loadProfileImage(this, account, accountProfileImage.style)
.into(accountProfileImage)
}
accountProfileImage.setBorderColor(account.color)
} else {
accountsCount.setText(accounts.size.toString())
Glide.clear(accountProfileImage)
if (displayDoneIcon) {
accountProfileImage.setImageResource(R.drawable.ic_action_confirm)
accountProfileImage.scaleType = ImageView.ScaleType.CENTER_INSIDE
} else {
accountProfileImage.setImageDrawable(null)
}
accountProfileImage.setBorderColors(*Utils.getAccountColors(accounts))
}
if (displayDoneIcon) {
accountsCount.visibility = View.GONE
} else {
accountsCount.visibility = View.VISIBLE
}
}
private fun updateViewStyle() {
accountProfileImage.style = preferences[profileImageStyleKey]
}
@ -1138,8 +1175,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
}
private fun notifyAccountSelectionChanged() {
displaySelectedAccountsIcon()
val accounts = accountsAdapter.selectedAccounts
setSelectedAccounts(*accounts)
if (ArrayUtils.isEmpty(accounts)) {
editText.accountKey = Utils.getDefaultAccountKey(this)
} else {
@ -1429,6 +1466,46 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
}
}
private fun ViewAnimator.setupViews() {
fun AnimatorSet.setup() {
interpolator = DecelerateInterpolator()
duration = 250
}
addView(accountSelector) { view ->
inAnimator = AnimatorSet().also { set ->
set.playTogether(
ObjectAnimator.ofFloat(view, ViewProperties.TRANSLATION_X_RELATIVE, -1f, 0f),
ObjectAnimator.ofFloat(view, View.ALPHA, 0f, 1f)
)
set.setup()
}
outAnimator = AnimatorSet().also { set ->
set.playTogether(
ObjectAnimator.ofFloat(view, ViewProperties.TRANSLATION_X_RELATIVE, 0f, -1f),
ObjectAnimator.ofFloat(view, View.ALPHA, 1f, 0f)
)
set.setup()
}
}
addView(composeMenu) { view ->
inAnimator = AnimatorSet().also { set ->
set.playTogether(
ObjectAnimator.ofFloat(view, ViewProperties.TRANSLATION_X_RELATIVE, 1f, 0f),
ObjectAnimator.ofFloat(view, View.ALPHA, 0f, 1f)
)
set.setup()
}
outAnimator = AnimatorSet().also { set ->
set.playTogether(
ObjectAnimator.ofFloat(view, ViewProperties.TRANSLATION_X_RELATIVE, 0f, 1f),
ObjectAnimator.ofFloat(view, View.ALPHA, 1f, 0f)
)
set.setup()
}
}
}
internal class ComposeLocationListener(activity: ComposeActivity) : LocationListener {
private val activityRef = WeakReference(activity)
@ -1452,7 +1529,6 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
internal class AccountIconViewHolder(val adapter: AccountIconsAdapter, itemView: View) : ViewHolder(itemView), OnClickListener {
private val iconView = itemView.findViewById(android.R.id.icon) as ShapedImageView
private val nameView = itemView.findViewById(android.R.id.text1) as TextView
init {
itemView.setOnClickListener(this)
@ -1460,11 +1536,9 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
fun showAccount(adapter: AccountIconsAdapter, account: AccountDetails, isSelected: Boolean) {
itemView.alpha = if (isSelected) 1f else 0.33f
(itemView as CheckableLinearLayout).isChecked = isSelected
val context = adapter.context
adapter.requestManager.loadProfileImage(context, account, adapter.profileImageStyle).into(iconView)
iconView.setBorderColor(account.color)
nameView.text = if (adapter.isNameFirst) account.user.name else "@" + account.user.screen_name
}
override fun onClick(v: View) {
@ -1598,11 +1672,10 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
internal class DiscardTweetTask(activity: ComposeActivity) : AsyncTask<Any, Any, Unit>() {
val activityRef: WeakReference<ComposeActivity>
private val activityRef = WeakReference(activity)
private val media: List<ParcelableMediaUpdate>
init {
this.activityRef = WeakReference(activity)
this.media = activity.mediaList
}
@ -1858,3 +1931,4 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
}
}
}

View File

@ -19,12 +19,19 @@
package org.mariotaku.twidere.extension
import android.view.View
import android.widget.ViewAnimator
/**
* Created by mariotaku on 2017/3/24.
*/
var ViewAnimator.currentChild: View?
get() = getChildAt(displayedChild)
set(value) {
displayedChild = indexOfChild(value)
}
var ViewAnimator.displayedChildId: Int
get() = getChildAt(displayedChild).id
set(value) {

View File

@ -0,0 +1,111 @@
/*
* 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.util.view
import android.animation.Animator
import android.view.View
/**
* Created by mariotaku on 2017/3/28.
*/
class ViewAnimator {
private val managedViews = HashMap<View, Config>()
private var currentInAnimator: Animator? = null
private var currentOutAnimator: Animator? = null
var currentChild: View? = null
private set
fun addView(view: View, config: Config.(View) -> Unit) {
managedViews[view] = Config().apply { config(view) }
}
fun showView(view: View?, animate: Boolean) {
currentInAnimator?.cancel()
currentOutAnimator?.cancel()
val oldView = currentChild
currentOutAnimator = managedViews[oldView]?.outAnimator?.also { animator ->
animator.addListener(object : SimpleAnimatorListener() {
override fun onAnimationEnd(animation: Animator) {
oldView?.visibility = View.GONE
animator.removeListener(this)
}
override fun onAnimationCancel(animation: Animator) {
animator.removeListener(this)
}
})
if (animate) {
animator.start()
} else {
animator.end()
}
}
val newView = view
currentInAnimator = managedViews[newView]?.inAnimator?.also { animator ->
animator.addListener(object : SimpleAnimatorListener() {
override fun onAnimationEnd(animation: Animator) {
animator.removeListener(this)
}
override fun onAnimationCancel(animation: Animator) {
animator.removeListener(this)
}
override fun onAnimationStart(animation: Animator) {
newView?.visibility = View.VISIBLE
}
})
if (animate) {
animator.start()
} else {
animator.end()
}
}
currentChild = view
}
class Config {
var inAnimator: Animator? = null
var outAnimator: Animator? = null
}
internal abstract class SimpleAnimatorListener : Animator.AnimatorListener {
override fun onAnimationRepeat(animation: Animator) {
}
override fun onAnimationEnd(animation: Animator) {
}
override fun onAnimationCancel(animation: Animator) {
}
override fun onAnimationStart(animation: Animator) {
}
}
}

View File

@ -0,0 +1,37 @@
/*
* 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.util.view
import android.util.FloatProperty
import android.view.View
object ViewProperties {
val TRANSLATION_X_RELATIVE = object : FloatProperty<View>("xRelative") {
override fun setValue(obj: View, value: Float) {
obj.translationX = value * obj.width
}
override fun get(obj: View): Float {
return obj.translationX / obj.width
}
}
}

View File

@ -132,26 +132,6 @@
</LinearLayout>
</ScrollView>
<FrameLayout
android:id="@+id/accountSelectorContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignBottom="@+id/editTextContainer"
android:layout_alignEnd="@+id/editTextContainer"
android:layout_alignLeft="@+id/editTextContainer"
android:layout_alignRight="@+id/editTextContainer"
android:layout_alignStart="@+id/editTextContainer"
android:layout_alignTop="@+id/editTextContainer"
android:visibility="gone">
<org.mariotaku.twidere.view.ExtendedRecyclerView
android:id="@+id/accountSelector"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:overScrollMode="never"/>
</FrameLayout>
</RelativeLayout>
<View
@ -166,6 +146,89 @@
android:background="?android:panelColorBackground"
android:baselineAligned="false">
<org.mariotaku.twidere.view.ExtendedRecyclerView
android:id="@+id/accountSelector"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_toEndOf="@+id/accountSelectorButton"
android:layout_toRightOf="@id/accountSelectorButton"
android:clickable="true"
android:overScrollMode="never"
android:visibility="gone"
tools:listitem="@layout/adapter_item_compose_account"/>
<RelativeLayout
android:id="@+id/composeMenu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_toEndOf="@+id/accountSelectorButton"
android:layout_toRightOf="@id/accountSelectorButton"
android:clickable="true"
android:visibility="visible">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/updateStatus"
android:layout_toStartOf="@+id/updateStatus"
android:overScrollMode="never"
android:scrollbars="none">
<android.support.v7.widget.TwidereActionMenuView
android:id="@+id/menuBar"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="@null"/>
</HorizontalScrollView>
<LinearLayout
android:id="@+id/updateStatus"
style="?actionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:contentDescription="@string/action_send"
android:gravity="center"
android:orientation="horizontal"
android:paddingBottom="@dimen/element_spacing_normal"
android:paddingEnd="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_large"
android:paddingRight="@dimen/element_spacing_normal"
android:paddingStart="@dimen/element_spacing_large"
android:paddingTop="@dimen/element_spacing_normal">
<org.mariotaku.twidere.view.StatusTextCountView
android:id="@+id/statusTextCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:minWidth="@dimen/element_size_small"
android:textAppearance="?android:textAppearanceSmall"
tools:text="140"/>
<org.mariotaku.twidere.view.IconActionView
android:id="@+id/updateStatusIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/action_send"
android:cropToPadding="false"
android:padding="@dimen/element_spacing_xsmall"
android:scaleType="centerCrop"
android:src="@drawable/ic_action_send"
app:iabColor="?android:textColorSecondary"
tools:tint="?android:textColorSecondary"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/accountSelectorButton"
style="?actionButtonStyle"
@ -214,61 +277,5 @@
</RelativeLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toEndOf="@+id/accountSelectorButton"
android:layout_toLeftOf="@+id/updateStatus"
android:layout_toRightOf="@+id/accountSelectorButton"
android:layout_toStartOf="@+id/updateStatus"
android:scrollbars="none">
<android.support.v7.widget.TwidereActionMenuView
android:id="@+id/menuBar"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="@null"/>
</FrameLayout>
<LinearLayout
android:id="@+id/updateStatus"
style="?actionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:contentDescription="@string/action_send"
android:gravity="center"
android:orientation="horizontal"
android:paddingBottom="@dimen/element_spacing_normal"
android:paddingEnd="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_large"
android:paddingRight="@dimen/element_spacing_normal"
android:paddingStart="@dimen/element_spacing_large"
android:paddingTop="@dimen/element_spacing_normal">
<org.mariotaku.twidere.view.StatusTextCountView
android:id="@+id/statusTextCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:minWidth="@dimen/element_size_small"
android:textAppearance="?android:textAppearanceSmall"
tools:text="140"/>
<org.mariotaku.twidere.view.IconActionView
android:id="@+id/updateStatusIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/action_send"
android:cropToPadding="false"
android:padding="@dimen/element_spacing_xsmall"
android:scaleType="centerCrop"
android:src="@drawable/ic_action_send"
app:iabColor="?android:textColorSecondary"
tools:tint="?android:textColorSecondary"/>
</LinearLayout>
</RelativeLayout>
</LinearLayout>

View File

@ -19,42 +19,22 @@
<org.mariotaku.twidere.view.CheckableLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tool="http://schemas.android.com/tools"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="?actionBarSize"
android:layout_height="match_parent"
android:clipToPadding="false"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="@dimen/element_spacing_msmall">
android:padding="@dimen/element_spacing_msmall"
tools:layout_height="?actionBarSize">
<org.mariotaku.twidere.view.ProfileImageView
android:id="@android:id/icon"
style="?profileImageStyleLarge"
android:layout_width="@dimen/element_size_normal"
android:layout_height="@dimen/element_size_normal"
style="?profileImageStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:sivBorder="true"
app:sivBorderWidth="@dimen/line_width_compose_account_profile_image"
app:sivElevation="@dimen/elevation_card"/>
tools:src="@drawable/ic_profile_image_twidere"/>
<android.support.v7.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/element_spacing_msmall"
android:layout_marginStart="@dimen/element_spacing_msmall"
app:cardBackgroundColor="?android:colorBackground"
app:cardElevation="@dimen/elevation_card"
app:contentPadding="@dimen/element_spacing_msmall">
<org.mariotaku.twidere.view.FixedTextView
android:id="@android:id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"
tool:text="Name"/>
</android.support.v7.widget.CardView>
</org.mariotaku.twidere.view.CheckableLinearLayout>