DataBinding migration

This commit is contained in:
Mariotaku Lee 2018-08-02 17:23:20 +08:00
parent b27ec2ce4e
commit 2a49bd731f
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
9 changed files with 90 additions and 114 deletions

View File

@ -6,7 +6,7 @@ buildscript {
maven { url 'https://plugins.gradle.org/m2/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.2'
classpath 'com.android.tools.build:gradle:3.1.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
@ -35,7 +35,7 @@ allprojects {
subprojects {
buildscript {
ext {
kotlinVersion = '1.2.41'
kotlinVersion = '1.2.51'
pluginVersions = [
AndroidSvgDrawable: '3.0.0',
PlayServices : '3.1.1',

View File

@ -45,6 +45,7 @@ import org.mariotaku.twidere.annotation.PreviewStyle
import org.mariotaku.twidere.annotation.TimelineStyle
import org.mariotaku.twidere.constant.*
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_DISPLAY_SENSITIVE_CONTENTS
import org.mariotaku.twidere.databinding.ItemStatusBinding
import org.mariotaku.twidere.exception.UnsupportedCountIndexException
import org.mariotaku.twidere.model.ItemCounts
import org.mariotaku.twidere.model.ObjectId
@ -449,8 +450,8 @@ class ParcelableStatusesAdapter(
return holder
}
TimelineStyle.PLAIN -> {
val view = inflater.inflate(StatusViewHolder.layoutResource, parent, false)
val holder = StatusViewHolder(adapter, view, viewType)
val binding = ItemStatusBinding.inflate(inflater, parent, false)
val holder = StatusViewHolder(adapter, binding, viewType)
holder.setupViewOptions(adapter)
return holder
}

View File

@ -0,0 +1,18 @@
package org.mariotaku.twidere.extension.databinding
import android.databinding.BindingAdapter
import org.mariotaku.twidere.util.UnitConvertUtils
import org.mariotaku.twidere.view.LabeledImageButton
@BindingAdapter("properCount", "pluralRes", "zeroRes", requireAll = true)
fun LabeledImageButton.displayProperCount(count: Long, pluralRes: Int, zeroRes: Int) {
if (count > 0) {
val properCount = UnitConvertUtils.calculateProperCount(count)
text = properCount
contentDescription = context.resources.getQuantityString(pluralRes,
count.toInt(), properCount)
} else {
text = null
contentDescription = context.getString(zeroRes)
}
}

View File

@ -40,6 +40,7 @@ import org.mariotaku.ktextension.weak
import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.DummyItemAdapter
import org.mariotaku.twidere.databinding.ItemStatusBinding
import org.mariotaku.twidere.extension.*
import org.mariotaku.twidere.extension.model.api.toParcelable
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
@ -48,7 +49,6 @@ import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.ModelCreationConfig
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.view.holder.status.StatusViewHolder
abstract class AbsStatusDialogFragment : BaseDialogFragment() {
@ -67,7 +67,7 @@ abstract class AbsStatusDialogFragment : BaseDialogFragment() {
private lateinit var adapter: DummyItemAdapter
final override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = Builder(context!!)
val builder = AlertDialog.Builder(context!!)
val accountKey = this.accountKey
builder.setupAlertDialog()
@ -87,16 +87,15 @@ abstract class AbsStatusDialogFragment : BaseDialogFragment() {
return@onShow
}
val weakThis by weak(this)
val weakHolder by weak(StatusViewHolder(adapter = adapter, itemView = it.itemContent).apply {
setupViewOptions(adapter)
})
val binding = ItemStatusBinding.bind(it.itemContent)
val weakBinding by weak(binding)
val extraStatus = status
if (extraStatus != null) {
showStatus(weakHolder!!, extraStatus, details, savedInstanceState)
showStatus(binding, extraStatus, details, savedInstanceState)
} else promiseOnUi {
weakThis?.showProgress()
} and AbsStatusDialogFragment.showStatus(context, details, statusId).successUi { status ->
val holder = weakHolder ?: return@successUi
val holder = weakBinding ?: return@successUi
weakThis?.showStatus(holder, status, details, savedInstanceState)
}.failUi {
val fragment = weakThis?.takeIf { it.dialog != null } ?: return@failUi
@ -116,7 +115,7 @@ abstract class AbsStatusDialogFragment : BaseDialogFragment() {
currentDialog.getButton(BUTTON_NEUTRAL)?.isEnabled = false
}
private fun showStatus(holder: StatusViewHolder, status: ParcelableStatus,
private fun showStatus(holder: ItemStatusBinding, status: ParcelableStatus,
details: AccountDetails, savedInstanceState: Bundle?) {
status.apply {
if (account_key != details.key) {
@ -132,7 +131,7 @@ abstract class AbsStatusDialogFragment : BaseDialogFragment() {
currentDialog.itemContent.visibility = View.VISIBLE
currentDialog.loadProgress.visibility = View.GONE
currentDialog.itemContent.isFocusable = false
holder.display(status = status, displayInReplyTo = false)
holder.status = status
currentDialog.onStatusLoaded(details, status, savedInstanceState)
}

View File

@ -22,24 +22,22 @@ package org.mariotaku.twidere.preference
import android.content.Context
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.databinding.DataBindingUtil
import android.support.v7.preference.Preference
import android.support.v7.preference.PreferenceViewHolder
import android.support.v7.widget.RecyclerView
import android.util.AttributeSet
import com.bumptech.glide.Glide
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.SHARED_PREFERENCES_NAME
import org.mariotaku.twidere.adapter.DummyItemAdapter
import org.mariotaku.twidere.graphic.like.LikeAnimationDrawable
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder
import org.mariotaku.twidere.view.holder.status.StatusViewHolder
import org.mariotaku.twidere.databinding.ItemStatusBinding
class CardPreviewPreference(
context: Context,
attrs: AttributeSet? = null
) : Preference(context, attrs), OnSharedPreferenceChangeListener {
private var holder: StatusViewHolder? = null
private lateinit var binding: ItemStatusBinding
private val adapter: DummyItemAdapter = DummyItemAdapter(context, requestManager = Glide.with(context))
init {
@ -51,25 +49,16 @@ class CardPreviewPreference(
override fun onSharedPreferenceChanged(preferences: SharedPreferences, key: String) {
adapter.updateOptions()
holder = null
notifyChanged()
}
override fun onBindViewHolder(holder: PreferenceViewHolder) {
if (this.holder == null) {
this.holder = StatusViewHolder(adapter, holder.itemView).apply {
setStatusClickListener(object : IStatusViewHolder.StatusClickListener {
override fun onItemActionClick(holder: RecyclerView.ViewHolder, id: Int, position: Int) {
if (id == R.id.favorite) {
(holder as StatusViewHolder).playLikeAnimation(LikeAnimationDrawable.OnLikedListener { false })
}
}
})
}
if (!this::binding.isInitialized) {
val widget = holder.findViewById(R.id.itemContent)
binding = DataBindingUtil.getBinding(widget) ?: ItemStatusBinding.bind(widget)
}
this.holder?.let {
it.setupViewOptions(adapter)
it.preview()
binding.favorite.setOnClickListener {
// (holder as StatusViewHolder).playLikeAnimation(LikeAnimationDrawable.OnLikedListener { false })
}
super.onBindViewHolder(holder)
}

View File

@ -20,9 +20,12 @@
package org.mariotaku.twidere.view
import android.content.Context
import android.databinding.BindingMethod
import android.databinding.BindingMethods
import android.os.Handler
import android.os.HandlerThread
import android.os.SystemClock
import android.support.v4.view.ViewCompat
import android.support.v7.widget.AppCompatTextView
import android.text.Spannable
import android.text.SpannableString
@ -35,6 +38,9 @@ import org.mariotaku.twidere.util.Utils.formatSameDayTime
import java.lang.ref.WeakReference
import java.util.concurrent.TimeUnit
@BindingMethods(
BindingMethod(type = ShortTimeView::class, attribute = "time", method = "setTime")
)
class ShortTimeView(
context: Context,
attrs: AttributeSet? = null
@ -43,7 +49,7 @@ class ShortTimeView(
private val ticker = TickerRunnable(this)
private val invalidateTimeRunnable = Runnable {
if (!isAttachedToWindow) return@Runnable
if (!ViewCompat.isAttachedToWindow(this)) return@Runnable
val time = this.time
if (time < 0) return@Runnable
val label = getTimeLabel(context, time, showAbsoluteTime)

View File

@ -35,9 +35,7 @@ import android.view.View.OnClickListener
import android.view.View.OnLongClickListener
import android.widget.ImageView
import android.widget.TextView
import kotlinx.android.synthetic.main.list_item_status.view.*
import org.mariotaku.ktextension.applyFontFamily
import org.mariotaku.ktextension.hideIfEmpty
import org.mariotaku.ktextension.spannable
import org.mariotaku.microblog.library.annotation.mastodon.StatusVisibility
import org.mariotaku.twidere.Constants.*
@ -45,6 +43,7 @@ import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter
import org.mariotaku.twidere.constant.RecyclerViewTypes
import org.mariotaku.twidere.constant.SharedPreferenceConstants.VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE
import org.mariotaku.twidere.databinding.ItemStatusBinding
import org.mariotaku.twidere.extension.inflate
import org.mariotaku.twidere.extension.model.displayInfo
import org.mariotaku.twidere.extension.model.retweeted_by_user_acct
@ -67,7 +66,6 @@ import org.mariotaku.twidere.text.TwidereClickableSpan
import org.mariotaku.twidere.text.style.PlaceholderLineSpan
import org.mariotaku.twidere.util.HtmlEscapeHelper.toPlainText
import org.mariotaku.twidere.util.HtmlSpanBuilder
import org.mariotaku.twidere.util.UnitConvertUtils
import org.mariotaku.twidere.util.UriCreator
import org.mariotaku.twidere.util.UserColorNameManager
import org.mariotaku.twidere.util.Utils.getUserTypeIconRes
@ -78,23 +76,23 @@ import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder
/**
* [ViewHolder] class for standard status list item
*/
class StatusViewHolder(var adapter: IStatusesAdapter, itemView: View, subtype: Int = 0) : ViewHolder(itemView), IStatusViewHolder {
class StatusViewHolder(var adapter: IStatusesAdapter, val binding: ItemStatusBinding, subtype: Int = 0) : ViewHolder(binding.root), IStatusViewHolder {
override val profileImageView: ProfileImageView = itemView.profileImage
override val profileTypeView: ImageView = itemView.profileType
override val profileImageView: ProfileImageView = binding.profileImage
override val profileTypeView: ImageView = binding.profileType
private val itemContent = itemView.itemContent
private val textView = itemView.text
private val nameView = itemView.name
private val itemMenu = itemView.itemMenu
private val statusInfoLabel = itemView.statusInfoLabel
private val statusInfoIcon = itemView.statusInfoIcon
private val timeView = itemView.time
private val replyButton = itemView.reply
private val retweetButton = itemView.retweet
private val favoriteButton = itemView.favorite
private val itemActionsGroup = itemView.itemActionsGroup
private val attachmentContainer = itemView.attachmentContainer
private val itemContent = binding.itemContent
private val textView = binding.text
private val nameView = binding.name
private val itemMenu = binding.itemMenu
private val statusInfoLabel = binding.statusInfoLabel
private val statusInfoIcon = binding.statusInfoIcon
private val timeView = binding.time
private val replyButton = binding.reply
private val retweetButton = binding.retweet
private val favoriteButton = binding.favorite
private val itemActionsGroup = binding.itemActionsGroup
private val attachmentContainer = binding.attachmentContainer
private val eventHandler = EventHandler()
@ -183,11 +181,15 @@ class StatusViewHolder(var adapter: IStatusesAdapter, itemView: View, subtype: I
}
override fun display(status: ParcelableStatus, displayInReplyTo: Boolean, displayPinned: Boolean) {
val context = itemView.context
val display = status.displayInfo(context)
binding.status = status
if (status is PlaceholderObject) {
placeholder()
return
}
val context = itemView.context
val formatter = BidiFormatterSingleton.get()
val colorNameManager = UserColorNameManager.get(context)
val showCardActions = isCardActionsShown
@ -199,10 +201,6 @@ class StatusViewHolder(var adapter: IStatusesAdapter, itemView: View, subtype: I
itemActionsGroup.setVisible(showCardActions)
val replyCount = status.reply_count
val retweetCount = status.retweet_count
val favoriteCount = status.favorite_count
if (displayPinned && status.is_pinned_status) {
statusInfoLabel.setText(R.string.pinned_status)
statusInfoIcon.setImageResource(R.drawable.ic_activity_action_pinned)
@ -231,7 +229,6 @@ class StatusViewHolder(var adapter: IStatusesAdapter, itemView: View, subtype: I
statusInfoIcon.visibility = View.GONE
}
val display = status.displayInfo(context)
val userColor = display.userColor
if (status.is_retweet) {
@ -245,19 +242,12 @@ class StatusViewHolder(var adapter: IStatusesAdapter, itemView: View, subtype: I
itemContent.drawStart(userColor)
}
timeView.time = if (status.is_retweet) {
status.retweet_timestamp
} else {
status.timestamp
}
nameView.placeholder = false
nameView.name = colorNameManager.getUserNickname(status.user_key, status.user_name)
nameView.screenName = "@${status.user_acct}"
if (adapter.profileImageEnabled) {
profileImageView.visibility = View.VISIBLE
profileImageView.profileImage = status.user_profile_image_url
profileTypeView.setImageResource(getUserTypeIconRes(status.user_is_verified, status.user_is_protected))
profileTypeView.visibility = View.VISIBLE
@ -275,18 +265,6 @@ class StatusViewHolder(var adapter: IStatusesAdapter, itemView: View, subtype: I
}
textView.spannable = display.text
textView.hideIfEmpty()
if (replyCount > 0) {
val properCount = UnitConvertUtils.calculateProperCount(replyCount)
replyButton.text = properCount
replyButton.contentDescription = context.resources.getQuantityString(R.plurals.N_replies_abbrev,
replyCount.toInt(), properCount)
} else {
replyButton.text = null
replyButton.contentDescription = context.getString(R.string.action_reply)
}
replyButton.drawable?.mutate()
when (status.extras?.visibility) {
@ -304,43 +282,10 @@ class StatusViewHolder(var adapter: IStatusesAdapter, itemView: View, subtype: I
retweetButton.isActivated = isRetweetIconActivated(status)
if (retweetCount > 0) {
val properCount = UnitConvertUtils.calculateProperCount(retweetCount)
retweetButton.text = properCount
retweetButton.contentDescription = context.resources.getQuantityString(R.plurals.N_retweets_abbrev,
retweetCount.toInt(), properCount)
} else {
retweetButton.text = null
retweetButton.contentDescription = context.getString(R.string.action_retweet)
}
favoriteButton.isActivated = isFavoriteIconActivated(status)
if (favoriteCount > 0) {
val properCount = UnitConvertUtils.calculateProperCount(favoriteCount)
favoriteButton.text = properCount
if (adapter.useStarsForLikes) {
favoriteButton.contentDescription = context.resources.getQuantityString(R.plurals.N_favorites_abbrev,
favoriteCount.toInt(), properCount)
} else {
favoriteButton.contentDescription = context.resources.getQuantityString(R.plurals.N_likes_abbrev,
favoriteCount.toInt(), properCount)
}
} else {
favoriteButton.text = null
if (adapter.useStarsForLikes) {
favoriteButton.contentDescription = context.getString(R.string.action_favorite)
} else {
favoriteButton.contentDescription = context.getString(R.string.action_like)
}
}
nameView.updateText(formatter)
itemView.contentDescription = display.contentDescription
profileImageView.contentDescription = display.profileImageContentDescription
attachmentContainer.setVisible(attachmentHolder != null)
attachmentHolder?.display(status)
}

View File

@ -19,8 +19,7 @@
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -32,7 +31,7 @@
android:paddingRight="@dimen/element_spacing_large"
android:paddingTop="@dimen/element_spacing_normal">
<include layout="@layout/list_item_status"/>
<include layout="@layout/item_status" />
<FrameLayout
android:id="@+id/loadProgress"
@ -43,7 +42,7 @@
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
android:layout_gravity="center" />
</FrameLayout>
</FrameLayout>

View File

@ -23,11 +23,17 @@
<data>
<import type="org.mariotaku.twidere.R" />
<import type="org.mariotaku.twidere.model.ParcelableStatus" />
<variable
name="status"
type="ParcelableStatus" />
type="org.mariotaku.twidere.model.ParcelableStatus" />
<variable
name="useFavorite"
type="boolean" />
</data>
<org.mariotaku.twidere.view.ColorLabelConstraintLayout
@ -37,6 +43,7 @@
android:background="?selectableItemBackground"
android:clipChildren="false"
android:clipToPadding="false"
android:contentDescription="@{status.display.contentDescription}"
android:focusable="true"
android:paddingLeft="8dp"
android:paddingRight="8dp"
@ -75,6 +82,7 @@
style="?profileImageStyle"
android:layout_width="@dimen/icon_size_status_profile_image"
android:layout_height="@dimen/icon_size_status_profile_image"
android:contentDescription="@{status.display.profileImageContentDescription}"
android:scaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/name"
@ -125,6 +133,7 @@
android:textAppearance="?android:textAppearanceSmall"
app:layout_constraintBaseline_toBaselineOf="@+id/name"
app:layout_constraintEnd_toEndOf="parent"
bind:time="@{status.is_retweet ? status.retweet_timestamp : status.timestamp}"
tools:text="42 mins ago"
tools:textSize="@dimen/text_size_extra_small" />
@ -134,6 +143,7 @@
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/element_spacing_small"
android:layout_marginTop="@dimen/element_spacing_small"
android:text="@{status.display.text}"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"
android:visibility="visible"
@ -177,6 +187,9 @@
app:layout_constraintTop_toBottomOf="@+id/attachmentContainer"
app:srcCompat="@drawable/ic_action_reply"
app:tint="?android:textColorSecondary"
bind:pluralRes="@{R.plurals.N_replies_abbrev}"
bind:properCount="@{status.reply_count}"
bind:zeroRes="@{R.string.action_reply}"
tools:text="255" />
<org.mariotaku.twidere.view.LabeledImageButton
@ -198,6 +211,9 @@
app:layout_constraintTop_toBottomOf="@+id/attachmentContainer"
app:srcCompat="@drawable/ic_action_retweet"
app:tint="@color/btn_tint_retweet_stateful"
bind:pluralRes="@{R.plurals.N_retweets_abbrev}"
bind:properCount="@{status.retweet_count}"
bind:zeroRes="@{R.string.action_retweet}"
tools:text="255" />
<org.mariotaku.twidere.view.LabeledImageButton
@ -219,6 +235,9 @@
app:layout_constraintTop_toBottomOf="@+id/attachmentContainer"
app:srcCompat="@drawable/ic_action_heart"
app:tint="@color/btn_tint_like_stateful"
bind:pluralRes="@{useFavorite ? R.plurals.N_favorites_abbrev : R.plurals.N_likes_abbrev}"
bind:properCount="@{status.favorite_count}"
bind:zeroRes="@{useFavorite ? R.string.action_favorite : R.string.action_like}"
tools:text="255" />
<android.support.v7.widget.AppCompatImageButton