improved user fragment layout

This commit is contained in:
Mariotaku Lee 2017-10-26 20:25:44 +08:00
parent a3547e82a0
commit 0ec9096a9d
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
11 changed files with 327 additions and 175 deletions

View File

@ -345,9 +345,10 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
this[EXTRA_REQUEST_TOKEN_SECRET] = requestToken.oauthTokenSecret
})
activity.startActivityForResult(intent, REQUEST_BROWSER_TWITTER_SIGN_IN)
}.failUi {
}.failUi { exception ->
val activity = weakThis.get() ?: return@failUi
// TODO show error message
Toast.makeText(activity, exception.getErrorMessage(activity), Toast.LENGTH_LONG).show()
DebugLog.w(tr = exception)
}.alwaysUi {
executeAfterFragmentResumed {
it.supportFragmentManager.dismissDialogFragment("get_request_token")

View File

@ -20,10 +20,10 @@
package org.mariotaku.twidere.extension.model
import android.annotation.SuppressLint
import android.graphics.drawable.Drawable
import android.text.Spannable
import android.text.Spanned
import android.text.style.URLSpan
import android.widget.TextView
import com.bumptech.glide.RequestManager
import org.mariotaku.twidere.model.CustomEmoji
import org.mariotaku.twidere.model.SpanItem
@ -36,7 +36,7 @@ val SpanItem.length: Int get() = end - start
@SuppressLint("SwitchIntDef")
fun Array<SpanItem>.applyTo(spannable: Spannable, emojis: Map<String, CustomEmoji>?,
requestManager: RequestManager, callback: Drawable.Callback) {
requestManager: RequestManager, textView: TextView) {
forEach { span ->
when (span.type) {
SpanItem.SpanType.HIDE -> {
@ -54,7 +54,7 @@ fun Array<SpanItem>.applyTo(spannable: Spannable, emojis: Map<String, CustomEmoj
SpanItem.SpanType.EMOJI -> {
val shortCode = span.link ?: return@forEach
val emoji = emojis?.get(shortCode) ?: return@forEach
spannable.setSpan(CustomEmojiSpan(emoji.url, requestManager, callback), span.start,
spannable.setSpan(CustomEmojiSpan(emoji.url, requestManager, textView), span.start,
span.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
else -> {

View File

@ -22,24 +22,19 @@ package org.mariotaku.twidere.fragment
import android.accounts.AccountManager
import android.animation.ArgbEvaluator
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.graphics.Color
import android.graphics.Outline
import android.graphics.PorterDuff
import android.graphics.Rect
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.net.Uri
import android.nfc.NdefMessage
import android.nfc.NdefRecord
import android.nfc.NfcAdapter.CreateNdefMessageCallback
import android.os.Build
import android.os.Bundle
import android.os.Parcelable
import android.support.annotation.ColorRes
@ -118,8 +113,8 @@ import org.mariotaku.twidere.fragment.timeline.AbsTimelineFragment
import org.mariotaku.twidere.fragment.timeline.FavoritesTimelineFragment
import org.mariotaku.twidere.fragment.timeline.UserMediaTimelineFragment
import org.mariotaku.twidere.fragment.timeline.UserTimelineFragment
import org.mariotaku.twidere.graphic.ActionBarColorDrawable
import org.mariotaku.twidere.graphic.ActionIconDrawable
import org.mariotaku.twidere.graphic.drawable.userprofile.ActionBarDrawable
import org.mariotaku.twidere.loader.ParcelableUserLoader
import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.event.FriendshipTaskEvent
@ -637,7 +632,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
profileBanner.onSizeChangedListener = this
profileBannerSpace.setOnTouchListener(this)
profileNameBackground.setBackgroundColor(cardBackgroundColor)
profileHeaderBackground.setBackgroundColor(cardBackgroundColor)
toolbarTabs.setBackgroundColor(cardBackgroundColor)
actionBarBackground = ActionBarDrawable(ResourcesCompat.getDrawable(activity.resources,
@ -1301,8 +1296,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
location.setLinkTextColor(optimalAccentColor)
url.setLinkTextColor(optimalAccentColor)
profileBanner.setBackgroundColor(color)
toolbarTabs.setBackgroundColor(primaryColor)
}
private fun setupBaseActionBar() {
@ -1370,11 +1363,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
private fun updateScrollOffset(offset: Int) {
val spaceHeight = profileBannerSpace.height
val factor = (if (spaceHeight == 0) 0f else offset / spaceHeight.toFloat()).coerceIn(0f, 1f)
profileBannerContainer.translationY = (-offset).toFloat()
profileBanner.translationY = (offset / 2).toFloat()
if (profileBirthdayStub == null) {
profileBirthdayBanner.translationY = (offset / 2).toFloat()
}
val activity = activity as BaseActivity
@ -1386,7 +1374,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
val stackedTabColor = primaryColor
val profileContentHeight = profileNameBackground.height.toFloat()
val profileContentHeight = profileHeaderBackground.height.toFloat()
val tabOutlineAlphaFactor: Float
if (offset - spaceHeight > 0) {
tabOutlineAlphaFactor = 1f - ((offset - spaceHeight) / profileContentHeight).coerceIn(0f, 1f)
@ -1514,70 +1502,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
}
}
private class ActionBarDrawable(shadow: Drawable) : LayerDrawable(arrayOf(shadow, ActionBarColorDrawable.create(true))) {
private val shadowDrawable = getDrawable(0)
private val colorDrawable = getDrawable(1) as ColorDrawable
private var alphaValue: Int = 0
var factor: Float = 0f
set(value) {
field = value
updateValue()
}
var color: Int = 0
set(value) {
field = value
colorDrawable.color = value
updateValue()
}
var outlineAlphaFactor: Float = 0f
set(value) {
field = value
updateValue()
}
init {
alpha = 0xFF
updateValue()
}
override fun setAlpha(alpha: Int) {
alphaValue = alpha
updateValue()
}
override fun getAlpha(): Int {
return alphaValue
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
override fun getOutline(outline: Outline) {
colorDrawable.getOutline(outline)
outline.alpha = factor * outlineAlphaFactor * 0.99f
}
override fun getIntrinsicWidth(): Int {
return colorDrawable.intrinsicWidth
}
override fun getIntrinsicHeight(): Int {
return colorDrawable.intrinsicHeight
}
private fun updateValue() {
val shadowAlpha = Math.round(alpha * (1 - factor).coerceIn(0f, 1f))
shadowDrawable.alpha = shadowAlpha
val hasColor = color != 0
val colorAlpha = if (hasColor) Math.round(alpha * factor.coerceIn(0f, 1f)) else 0
colorDrawable.alpha = colorAlpha
invalidateSelf()
}
}
internal class UserRelationshipLoader(
context: Context,

View File

@ -0,0 +1,92 @@
/*
* 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.graphic.drawable.userprofile
import android.annotation.TargetApi
import android.graphics.Outline
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.os.Build
import org.mariotaku.twidere.graphic.ActionBarColorDrawable
internal class ActionBarDrawable(shadow: Drawable) : LayerDrawable(arrayOf(shadow, ActionBarColorDrawable.create(true))) {
private val shadowDrawable = getDrawable(0)
private val colorDrawable = getDrawable(1) as ColorDrawable
private var alphaValue: Int = 0
var factor: Float = 0f
set(value) {
field = value
updateValue()
}
var color: Int = 0
set(value) {
field = value
colorDrawable.color = value
updateValue()
}
var outlineAlphaFactor: Float = 0f
set(value) {
field = value
updateValue()
}
init {
alpha = 0xFF
updateValue()
}
override fun setAlpha(alpha: Int) {
alphaValue = alpha
updateValue()
}
override fun getAlpha(): Int {
return alphaValue
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
override fun getOutline(outline: Outline) {
colorDrawable.getOutline(outline)
outline.alpha = factor * outlineAlphaFactor * 0.99f
}
override fun getIntrinsicWidth(): Int {
return colorDrawable.intrinsicWidth
}
override fun getIntrinsicHeight(): Int {
return colorDrawable.intrinsicHeight
}
private fun updateValue() {
val shadowAlpha = Math.round(alpha * (1 - factor).coerceIn(0f, 1f))
shadowDrawable.alpha = shadowAlpha
val hasColor = color != 0
val colorAlpha = if (hasColor) Math.round(alpha * factor.coerceIn(0f, 1f)) else 0
colorDrawable.alpha = colorAlpha
invalidateSelf()
}
}

View File

@ -19,77 +19,89 @@
package org.mariotaku.twidere.text.style
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import android.graphics.drawable.Animatable
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.support.v4.widget.CircularProgressDrawable
import android.text.style.DynamicDrawableSpan
import android.text.style.ReplacementSpan
import android.widget.TextView
import com.bumptech.glide.RequestManager
import com.bumptech.glide.load.resource.drawable.GlideDrawable
import com.bumptech.glide.request.animation.GlideAnimation
import com.bumptech.glide.request.target.BaseTarget
import com.bumptech.glide.request.target.SizeReadyCallback
import org.mariotaku.twidere.R
import org.mariotaku.twidere.graphic.DrawableWrapper
import java.lang.ref.WeakReference
class CustomEmojiSpan(
val uri: String,
requestManager: RequestManager,
callback: Drawable.Callback
) : DynamicDrawableSpan(DynamicDrawableSpan.ALIGN_BASELINE) {
val textView: TextView,
val alignBaseline: Boolean = false
) : ReplacementSpan() {
private val textSize = (callback as TextView).textSize.toInt()
private val textSize = textView.textSize.toInt()
private val emojiDrawable = EmojiDrawable(textSize)
private val emojiDirtyBounds = Rect()
private val target = GlideTarget()
private val target = GlideTarget(textSize)
init {
emojiDrawable.callback = callback
requestManager.load(uri)
.placeholder(CircularProgressDrawable((callback as TextView).context))
.asBitmap()
.placeholder(R.mipmap.ic_emoji_loading)
.error(R.mipmap.ic_emoji_error)
.fitCenter()
.dontAnimate()
.into(target)
}
override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int,
fm: Paint.FontMetricsInt?): Int {
return textSize
}
override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int, x: Float, top: Int,
y: Int, bottom: Int, paint: Paint) {
val b = target.drawable ?: return
canvas.save()
var transY = bottom - emojiDrawable.bounds.bottom
if (verticalAlignment == ALIGN_BASELINE) {
var transY = bottom - b.bounds.bottom
if (alignBaseline) {
transY -= paint.fontMetricsInt.descent
}
emojiDrawable.copyBounds(emojiDirtyBounds)
emojiDirtyBounds.offsetTo(x.toInt(), transY)
super.draw(canvas, text, start, end, x, top, y, bottom, paint)
canvas.translate(x, transY.toFloat())
b.setBounds(0, 0, textSize, textSize)
b.draw(canvas)
canvas.restore()
}
override fun getDrawable(): Drawable = emojiDrawable
private inner class GlideTarget(
val textSize: Int
) : BaseTarget<Bitmap>() {
fun verify(who: Drawable): Boolean = who === emojiDrawable
var drawable: Drawable?
get() = drawableRef?.get()
private set(value) {
drawableRef = if (value != null) WeakReference(value) else null
textView.invalidate()
}
private inner class GlideTarget : BaseTarget<GlideDrawable>() {
private var drawableRef: WeakReference<Drawable>? = null
override fun onResourceReady(resource: GlideDrawable, glideAnimation: GlideAnimation<in GlideDrawable>) {
resource.setLoopCount(GlideDrawable.LOOP_FOREVER)
emojiDrawable.setDrawable(resource)
override fun onResourceReady(resource: Bitmap, glideAnimation: GlideAnimation<in Bitmap>) {
drawable = BitmapDrawable(textView.resources, resource)
}
override fun onLoadCleared(placeholder: Drawable?) {
emojiDrawable.setDrawable(placeholder)
drawable = placeholder
}
override fun onLoadStarted(placeholder: Drawable?) {
emojiDrawable.setDrawable(placeholder)
drawable = placeholder
}
override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
emojiDrawable.setDrawable(errorDrawable)
drawable = errorDrawable
}
override fun getSize(cb: SizeReadyCallback) {
@ -98,20 +110,4 @@ class CustomEmojiSpan(
}
private inner class EmojiDrawable(val textSize: Int) : DrawableWrapper() {
override fun getDirtyBounds(): Rect {
return emojiDirtyBounds
}
fun setDrawable(drawable: Drawable?) {
wrapped = drawable
drawable?.setBounds(0, 0, textSize, textSize)
setBounds(0, 0, textSize, textSize)
if (drawable is Animatable) {
drawable.start()
}
}
}
}

View File

@ -21,9 +21,7 @@ package org.mariotaku.twidere.view
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.drawable.Drawable
import android.text.Spannable
import android.text.Spanned
import android.text.method.BaseMovementMethod
import android.text.method.MovementMethod
import android.text.style.ClickableSpan
@ -32,7 +30,6 @@ import android.view.MotionEvent
import android.widget.TextView
import org.mariotaku.chameleon.view.ChameleonTextView
import org.mariotaku.twidere.extension.setupEmojiFactory
import org.mariotaku.twidere.text.style.CustomEmojiSpan
import java.lang.ref.WeakReference
/**
@ -90,16 +87,6 @@ class TimelineContentTextView(
}
}
override fun verifyDrawable(who: Drawable): Boolean {
val result = super.verifyDrawable(who)
if (result) return true
val spanned = text as? Spanned ?: return false
val spans = spanned.getSpans(0, length(), CustomEmojiSpan::class.java)
return spans.any {
it.verify(who)
}
}
internal class InternalMovementMethod : BaseMovementMethod() {
private var targetSpan: WeakReference<ClickableSpan?>? = null

View File

@ -19,20 +19,40 @@
package org.mariotaku.twidere.view.behavior.userprofile
import android.annotation.SuppressLint
import android.content.Context
import android.support.design.widget.AccessorHeaderBehavior
import android.support.design.widget.CoordinatorLayout
import android.support.v4.math.MathUtils
import android.support.graphics.drawable.ArgbEvaluator
import android.util.AttributeSet
import android.view.View
import kotlinx.android.synthetic.main.fragment_user.view.*
import kotlinx.android.synthetic.main.header_user.view.*
import org.mariotaku.chameleon.Chameleon
import org.mariotaku.chameleon.ChameleonUtils
import org.mariotaku.kpreferences.get
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.themeBackgroundAlphaKey
import org.mariotaku.twidere.constant.themeBackgroundOptionKey
import org.mariotaku.twidere.extension.view.measureChildIgnoringInsets
import org.mariotaku.twidere.graphic.drawable.userprofile.ActionBarDrawable
import org.mariotaku.twidere.util.ThemeUtils
import org.mariotaku.twidere.util.dagger.DependencyHolder
internal class HeaderBehavior(context: Context, attrs: AttributeSet? = null) : AccessorHeaderBehavior<View>(context, attrs) {
var offsetDelta: Int = 0
private set
private val cardBackgroundColor: Int
private var tabItemIsDark: Int = 0
init {
val preferences = DependencyHolder.get(context).preferences
cardBackgroundColor = ThemeUtils.getCardBackgroundColor(context,
preferences[themeBackgroundOptionKey], preferences[themeBackgroundAlphaKey])
}
override fun onMeasureChild(parent: CoordinatorLayout, child: View,
parentWidthMeasureSpec: Int, widthUsed: Int, parentHeightMeasureSpec: Int,
heightUsed: Int): Boolean {
@ -40,6 +60,12 @@ internal class HeaderBehavior(context: Context, attrs: AttributeSet? = null) : A
parentHeightMeasureSpec, heightUsed)
}
override fun onLayoutChild(parent: CoordinatorLayout, child: View, layoutDirection: Int): Boolean {
val result = super.onLayoutChild(parent, child, layoutDirection)
updateTabColor(parent, child, topAndBottomOffset)
return result
}
override fun layoutChild(parent: CoordinatorLayout, child: View, layoutDirection: Int) {
child.layout(0, 0, child.measuredWidth, child.measuredHeight)
}
@ -62,38 +88,19 @@ internal class HeaderBehavior(context: Context, attrs: AttributeSet? = null) : A
val curOffset = topBottomOffsetForScrollingSibling
var consumed = 0
var newOffset = newOffset
if (minOffset != 0 && curOffset >= minOffset && curOffset <= maxOffset) {
// If we have some scrolling range, and we're currently within the min and max
// offsets, calculate a new offset
newOffset = MathUtils.clamp(newOffset, minOffset, maxOffset)
if (curOffset != newOffset) {
val interpolatedOffset = if (header.hasChildWithInterpolator)
interpolateOffset(header, newOffset)
else
newOffset
val offsetChanged = setTopAndBottomOffset(interpolatedOffset)
val clampedOffset = newOffset.coerceIn(minOffset, maxOffset)
if (curOffset != clampedOffset) {
topAndBottomOffset = clampedOffset
updateTabColor(parent, header, clampedOffset)
// Update how much dy we have consumed
consumed = curOffset - newOffset
consumed = curOffset - clampedOffset
// Update the stored sibling offset
offsetDelta = newOffset - interpolatedOffset
offsetDelta = clampedOffset - clampedOffset
if (!offsetChanged && header.hasChildWithInterpolator) {
// If the offset hasn't changed and we're using an interpolated scroll
// then we need to keep any dependent views updated. CoL will do this for
// us when we move, but we need to do it manually when we don't (as an
// interpolated scroll may finish early).
parent.dispatchDependentViewsChanged(header)
}
// Dispatch the updates to any listeners
// header.dispatchOffsetUpdates(topAndBottomOffset)
// Update the AppBarLayout's drawable state (for any elevation changes)
// updateAppBarLayoutDrawableState(parent, header, newOffset,
// if (newOffset < curOffset) -1 else 1, false)
}
} else {
// Reset the offset delta
@ -103,13 +110,42 @@ internal class HeaderBehavior(context: Context, attrs: AttributeSet? = null) : A
return consumed
}
override fun canDragView(view: View) = true
@SuppressLint("RestrictedApi")
private fun updateTabColor(parent: CoordinatorLayout, header: View, offset: Int) {
val actionBarBackground = parent.toolbar.background as? ActionBarDrawable ?: return
val profileHeaderBackground = parent.profileHeaderBackground
private fun interpolateOffset(header: View, offset: Int): Int {
return offset
val toolbarBottom = parent.toolbar.bottom
val headerBackgroundOffset = offset + profileHeaderBackground.top
val factor = ((toolbarBottom - headerBackgroundOffset) / profileHeaderBackground.height.toFloat()).coerceIn(0f, 1f)
val toolbarTabs = header.toolbarTabs
val colorPrimary = actionBarBackground.color
val currentTabColor = ArgbEvaluator.getInstance().evaluate(factor,
cardBackgroundColor, colorPrimary) as Int
toolbarTabs.setBackgroundColor(currentTabColor)
val tabItemIsDark = if (ThemeUtils.isLightColor(currentTabColor)) 1 else -1
if (this.tabItemIsDark != tabItemIsDark) {
val context = parent.context
val activity = ChameleonUtils.getActivity(context)
val tabContrastColor = ThemeUtils.getColorDependent(currentTabColor)
toolbarTabs.setIconColor(tabContrastColor)
toolbarTabs.setLabelColor(tabContrastColor)
val theme = Chameleon.getOverrideTheme(context, activity)
if (theme.isToolbarColored) {
toolbarTabs.setStripColor(tabContrastColor)
} else {
toolbarTabs.setStripColor(ThemeUtils.getOptimalAccentColor(colorPrimary, tabContrastColor))
}
toolbarTabs.updateAppearance()
}
this.tabItemIsDark = tabItemIsDark
}
private val View.hasChildWithInterpolator: Boolean
get() = false
override fun canDragView(view: View) = true
}

View File

@ -0,0 +1,75 @@
/*
* 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.view.behavior.userprofile
import android.annotation.SuppressLint
import android.content.Context
import android.support.design.widget.CoordinatorLayout
import android.support.design.widget.lastWindowInsetsCompat
import android.support.graphics.drawable.ArgbEvaluator
import android.util.AttributeSet
import android.view.View
import android.view.Window
import kotlinx.android.synthetic.main.fragment_user.view.*
import org.mariotaku.chameleon.ChameleonUtils
import org.mariotaku.twidere.R
import org.mariotaku.twidere.graphic.drawable.userprofile.ActionBarDrawable
import org.mariotaku.twidere.util.ThemeUtils
import org.mariotaku.twidere.util.support.WindowSupport
internal class StatusBarBehavior(context: Context, attrs: AttributeSet? = null) : CoordinatorLayout.Behavior<View>(context, attrs) {
private val window: Window = ChameleonUtils.getActivity(context)!!.window
private var lightStatusBar: Int = 0
override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
return dependency.id == R.id.profileHeader
}
override fun onLayoutChild(parent: CoordinatorLayout, child: View, layoutDirection: Int): Boolean {
val lastInsets = parent.lastWindowInsetsCompat ?: return true
val height = lastInsets.systemWindowInsetTop
child.layout(0, 0, child.measuredWidth, height)
return true
}
@SuppressLint("RestrictedApi")
override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
if (child.height == 0) return true
val actionBarBackground = parent.toolbar.background as? ActionBarDrawable ?: return true
val bannerContainer = parent.profileBannerContainer
val bannerBottom = dependency.top + bannerContainer.height
val currentOffset = bannerBottom - child.bottom
val maxOffset = (bannerContainer.height - child.bottom).toFloat()
val factor = (1 - currentOffset / maxOffset).coerceIn(0f, 1f)
val primaryColorDark = ChameleonUtils.darkenColor(actionBarBackground.color)
val statusBarColor = ArgbEvaluator.getInstance().evaluate(factor, 0xA0000000.toInt(),
ChameleonUtils.darkenColor(primaryColorDark))
child.setBackgroundColor(statusBarColor as Int)
val lightStatusBar = if (ThemeUtils.isLightColor(statusBarColor)) 1 else -1
if (this.lightStatusBar != lightStatusBar) {
WindowSupport.setLightStatusBar(window, lightStatusBar == 1)
}
this.lightStatusBar = lightStatusBar
return true
}
}

View File

@ -19,11 +19,47 @@
package org.mariotaku.twidere.view.behavior.userprofile
import android.annotation.SuppressLint
import android.content.Context
import android.support.design.widget.CoordinatorLayout
import android.support.graphics.drawable.ArgbEvaluator
import android.support.v7.widget.Toolbar
import android.util.AttributeSet
import android.view.View
import kotlinx.android.synthetic.main.fragment_user.view.*
import org.mariotaku.twidere.R
import org.mariotaku.twidere.graphic.drawable.userprofile.ActionBarDrawable
import org.mariotaku.twidere.util.ThemeUtils
internal class ToolbarBehavior(context: Context?, attrs: AttributeSet? = null) : CoordinatorLayout.Behavior<Toolbar>(context, attrs) {
private val actionBarShadowColor: Int = 0xA0000000.toInt()
private var actionItemIsDark: Int = 0
override fun layoutDependsOn(parent: CoordinatorLayout, child: Toolbar, dependency: View): Boolean {
return dependency.id == R.id.profileHeader
}
@SuppressLint("RestrictedApi")
override fun onDependentViewChanged(parent: CoordinatorLayout, child: Toolbar, dependency: View): Boolean {
val actionBarBackground = child.background as? ActionBarDrawable ?: return false
val bannerContainer = parent.profileBannerContainer
val bannerBottom = dependency.top + bannerContainer.height
val currentOffset = bannerBottom - child.bottom
val maxOffset = (bannerContainer.height - child.bottom).toFloat()
val factor = (1 - currentOffset / maxOffset).coerceIn(0f, 1f)
actionBarBackground.factor = factor
actionBarBackground.outlineAlphaFactor = factor
val colorPrimary = actionBarBackground.color
val currentActionBarColor = ArgbEvaluator.getInstance().evaluate(factor, actionBarShadowColor,
colorPrimary) as Int
val actionItemIsDark = if (ThemeUtils.isLightColor(currentActionBarColor)) 1 else -1
if (this.actionItemIsDark != actionItemIsDark) {
ThemeUtils.applyToolbarItemColor(parent.context, child, currentActionBarColor)
}
this.actionItemIsDark = actionItemIsDark
return true
}
}

View File

@ -117,7 +117,12 @@
</FrameLayout>
<!-- Don't change view order, since this view consumes window insets-->
<View
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="org.mariotaku.twidere.view.behavior.userprofile.StatusBarBehavior"
tools:layout_height="25dp"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"

View File

@ -39,7 +39,7 @@
app:layout_constraintTop_toTopOf="parent"/>
<View
android:id="@+id/profileNameBackground"
android:id="@+id/profileHeaderBackground"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="@+id/countsContainer"