diff --git a/app/src/main/java/com/google/android/material/appbar/KotatsuAppBarLayout.kt b/app/src/main/java/com/google/android/material/appbar/KotatsuAppBarLayout.kt deleted file mode 100644 index cb2e1968b..000000000 --- a/app/src/main/java/com/google/android/material/appbar/KotatsuAppBarLayout.kt +++ /dev/null @@ -1,151 +0,0 @@ -package com.google.android.material.appbar - -import android.animation.AnimatorSet -import android.animation.ValueAnimator -import android.annotation.SuppressLint -import android.content.Context -import android.util.AttributeSet -import android.widget.TextView -import androidx.annotation.FloatRange -import com.google.android.material.animation.AnimationUtils -import com.google.android.material.appbar.AppBarLayout.OnOffsetChangedListener -import com.google.android.material.shape.MaterialShapeDrawable -import org.koitharu.kotatsu.R -import com.google.android.material.R as materialR - -/** - * [AppBarLayout] with our own lift state handler and custom title alpha. - * - * Inside this package to access some package-private methods. - */ -class KotatsuAppBarLayout @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null -) : AppBarLayout(context, attrs) { - - private var lifted = true - - private val toolbar by lazy { findViewById(R.id.toolbar) } - - @FloatRange(from = 0.0, to = 1.0) - var titleTextAlpha = 1F - set(value) { - field = value - titleTextView?.alpha = field - } - - private var titleTextView: TextView? = null - set(value) { - field = value - field?.alpha = titleTextAlpha - } - - private var animatorSet: AnimatorSet? = null - - private var statusBarForegroundAnimator: ValueAnimator? = null - private val offsetListener = OnOffsetChangedListener { appBarLayout, verticalOffset -> - // Show status bar foreground when offset - val foreground = (appBarLayout?.statusBarForeground as? MaterialShapeDrawable) ?: return@OnOffsetChangedListener - val start = foreground.alpha - val end = if (verticalOffset != 0) 255 else 0 - - statusBarForegroundAnimator?.cancel() - if (animatorSet?.isRunning == true) { - foreground.alpha = end - return@OnOffsetChangedListener - } - if (start != end) { - statusBarForegroundAnimator = ValueAnimator.ofInt(start, end).apply { - duration = resources.getInteger(materialR.integer.app_bar_elevation_anim_duration).toLong() - interpolator = AnimationUtils.LINEAR_INTERPOLATOR - addUpdateListener { - foreground.alpha = it.animatedValue as Int - } - start() - } - } - } - - var isTransparentWhenNotLifted = false - set(value) { - if (field != value) { - field = value - updateStates() - } - } - - override fun isLiftOnScroll(): Boolean = false - - override fun isLifted(): Boolean = lifted - - override fun setLifted(lifted: Boolean): Boolean { - return if (this.lifted != lifted) { - this.lifted = lifted - updateStates() - true - } else { - false - } - } - - override fun setLiftedState(lifted: Boolean, force: Boolean): Boolean = false - - override fun onAttachedToWindow() { - super.onAttachedToWindow() - addOnOffsetChangedListener(offsetListener) - toolbar.background.alpha = 0 // Use app bar background - } - - override fun onDetachedFromWindow() { - super.onDetachedFromWindow() - removeOnOffsetChangedListener(offsetListener) - } - - @SuppressLint("Recycle") - private fun updateStates() { - val animators = mutableListOf() - - val fromElevation = elevation - val toElevation = if (lifted) { - resources.getDimension(materialR.dimen.design_appbar_elevation) - } else { - 0F - } - if (fromElevation != toElevation) { - ValueAnimator.ofFloat(fromElevation, toElevation).apply { - addUpdateListener { - elevation = it.animatedValue as Float - (statusBarForeground as? MaterialShapeDrawable)?.elevation = it.animatedValue as Float - } - animators.add(this) - } - } - - val transparent = if (lifted) false else isTransparentWhenNotLifted - val fromAlpha = (background as? MaterialShapeDrawable)?.alpha ?: background.alpha - val toAlpha = if (transparent) 0 else 255 - if (fromAlpha != toAlpha) { - ValueAnimator.ofInt(fromAlpha, toAlpha).apply { - addUpdateListener { - val value = it.animatedValue as Int - background.alpha = value - } - animators.add(this) - } - } - - if (animators.isNotEmpty()) { - animatorSet?.cancel() - animatorSet = AnimatorSet().apply { - duration = resources.getInteger(materialR.integer.app_bar_elevation_anim_duration).toLong() - interpolator = AnimationUtils.LINEAR_INTERPOLATOR - playTogether(*animators.toTypedArray()) - start() - } - } - } - - init { - statusBarForeground = MaterialShapeDrawable.createWithElevationOverlay(context) - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/util/StatusBarDimHelper.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/util/StatusBarDimHelper.kt new file mode 100644 index 000000000..7a8bf28d4 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/util/StatusBarDimHelper.kt @@ -0,0 +1,42 @@ +package org.koitharu.kotatsu.base.ui.util + +import android.animation.ValueAnimator +import android.view.animation.AccelerateDecelerateInterpolator +import com.google.android.material.R as materialR +import com.google.android.material.appbar.AppBarLayout +import com.google.android.material.shape.MaterialShapeDrawable +import org.koitharu.kotatsu.utils.ext.getAnimationDuration + +class StatusBarDimHelper : AppBarLayout.OnOffsetChangedListener { + + private var animator: ValueAnimator? = null + private val interpolator = AccelerateDecelerateInterpolator() + + override fun onOffsetChanged(appBarLayout: AppBarLayout, verticalOffset: Int) { + val foreground = appBarLayout.statusBarForeground ?: return + val start = foreground.alpha + val collapsed = verticalOffset != 0 + val end = if (collapsed) 255 else 0 + animator?.cancel() + if (start == end) { + animator = null + return + } + animator = ValueAnimator.ofInt(start, end).apply { + duration = appBarLayout.context.getAnimationDuration(materialR.integer.app_bar_elevation_anim_duration) + interpolator = this@StatusBarDimHelper.interpolator + addUpdateListener { + foreground.alpha = it.animatedValue as Int + } + start() + } + } + + fun attachToAppBar(appBarLayout: AppBarLayout) { + appBarLayout.addOnOffsetChangedListener(this) + appBarLayout.statusBarForeground = + MaterialShapeDrawable.createWithElevationOverlay(appBarLayout.context).apply { + alpha = 0 + } + } +} diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/FadingSnackbar.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/FadingSnackbar.kt deleted file mode 100644 index 56c4a7d88..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/FadingSnackbar.kt +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2018 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.koitharu.kotatsu.base.ui.widgets - -import android.content.Context -import android.content.res.ColorStateList -import android.graphics.drawable.Drawable -import android.util.AttributeSet -import android.view.LayoutInflater -import android.widget.FrameLayout -import androidx.annotation.ColorInt -import androidx.annotation.StringRes -import androidx.core.graphics.drawable.DrawableCompat -import androidx.core.view.postDelayed -import com.google.android.material.color.MaterialColors -import com.google.android.material.shape.MaterialShapeDrawable -import com.google.android.material.shape.ShapeAppearanceModel -import com.google.android.material.snackbar.Snackbar -import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.databinding.FadingSnackbarLayoutBinding -import org.koitharu.kotatsu.utils.ext.getThemeColorStateList -import com.google.android.material.R as materialR - -private const val SHORT_DURATION_MS = 1_500L -private const val LONG_DURATION_MS = 2_750L - -/** - * A custom snackbar implementation allowing more control over placement and entry/exit animations. - * - * Xtimms: Well, my sufferings over the Snackbar in [DetailsActivity] will go away forever... Thanks, Google. - * - * https://github.com/google/iosched/blob/main/mobile/src/main/java/com/google/samples/apps/iosched/widget/FadingSnackbar.kt - */ -class FadingSnackbar @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0, -) : FrameLayout(context, attrs, defStyleAttr) { - - private val binding = FadingSnackbarLayoutBinding.inflate(LayoutInflater.from(context), this) - private val enterDuration = context.resources.getInteger(R.integer.config_defaultAnimTime).toLong() - private val exitDuration = context.resources.getInteger(android.R.integer.config_shortAnimTime).toLong() - - init { - binding.snackbarLayout.background = createThemedBackground() - } - - fun dismiss() { - if (visibility == VISIBLE && alpha == 1f) { - animate() - .alpha(0f) - .withEndAction { visibility = GONE } - .duration = exitDuration - } - } - - fun show( - messageText: CharSequence?, - @StringRes actionId: Int = 0, - duration: Int = Snackbar.LENGTH_SHORT, - onActionClick: (FadingSnackbar.() -> Unit)? = null, - onDismiss: (() -> Unit)? = null, - ) { - binding.snackbarText.text = messageText - if (actionId != 0) { - with(binding.snackbarAction) { - visibility = VISIBLE - text = context.getString(actionId) - setOnClickListener { - onActionClick?.invoke(this@FadingSnackbar) ?: dismiss() - } - } - } else { - binding.snackbarAction.visibility = GONE - } - alpha = 0f - visibility = VISIBLE - animate() - .alpha(1f) - .duration = enterDuration - if (duration == Snackbar.LENGTH_INDEFINITE) { - return - } - val durationMs = enterDuration + if (duration == Snackbar.LENGTH_LONG) LONG_DURATION_MS else SHORT_DURATION_MS - postDelayed(durationMs) { - dismiss() - onDismiss?.invoke() - } - } - - private fun createThemedBackground(): Drawable { - val backgroundColor = MaterialColors.layer(this, materialR.attr.colorSurface, materialR.attr.colorOnSurface, 1f) - val shapeAppearanceModel = ShapeAppearanceModel.builder( - context, - materialR.style.ShapeAppearance_Material3_Corner_ExtraSmall, - 0 - ).build() - val background = createMaterialShapeDrawableBackground( - backgroundColor, - shapeAppearanceModel, - ) - val backgroundTint = context.getThemeColorStateList(materialR.attr.colorSurfaceInverse) - return if (backgroundTint != null) { - val wrappedDrawable = DrawableCompat.wrap(background) - DrawableCompat.setTintList(wrappedDrawable, backgroundTint) - wrappedDrawable - } else { - DrawableCompat.wrap(background) - } - } - - private fun createMaterialShapeDrawableBackground( - @ColorInt backgroundColor: Int, - shapeAppearanceModel: ShapeAppearanceModel, - ): MaterialShapeDrawable { - val background = MaterialShapeDrawable(shapeAppearanceModel) - background.fillColor = ColorStateList.valueOf(backgroundColor) - return background - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/HideBottomNavigationOnScrollBehavior.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/HideBottomNavigationOnScrollBehavior.kt index b4f1df4e7..b1742420a 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/HideBottomNavigationOnScrollBehavior.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/HideBottomNavigationOnScrollBehavior.kt @@ -4,17 +4,14 @@ import android.animation.ValueAnimator import android.content.Context import android.util.AttributeSet import android.view.View -import android.view.ViewGroup import android.view.animation.DecelerateInterpolator -import androidx.appcompat.widget.Toolbar import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.ViewCompat import com.google.android.material.appbar.AppBarLayout import com.google.android.material.bottomnavigation.BottomNavigationView -import org.koitharu.kotatsu.utils.ext.animatorDurationScale -import org.koitharu.kotatsu.utils.ext.findChild +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.utils.ext.getAnimationDuration import org.koitharu.kotatsu.utils.ext.measureHeight -import kotlin.math.roundToLong class HideBottomNavigationOnScrollBehavior @JvmOverloads constructor( context: Context? = null, @@ -90,7 +87,7 @@ class HideBottomNavigationOnScrollBehavior @JvmOverloads constructor( offsetAnimator?.cancel() offsetAnimator = ValueAnimator().apply { interpolator = DecelerateInterpolator() - duration = (150 * child.context.animatorDurationScale).roundToLong() + duration = child.context.getAnimationDuration(R.integer.config_shorterAnimTime) addUpdateListener { child.translationY = it.animatedValue as Float } @@ -101,4 +98,4 @@ class HideBottomNavigationOnScrollBehavior @JvmOverloads constructor( ) offsetAnimator?.start() } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/KotatsuCoordinatorLayout.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/KotatsuCoordinatorLayout.kt deleted file mode 100644 index 8f7b0be10..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/KotatsuCoordinatorLayout.kt +++ /dev/null @@ -1,111 +0,0 @@ -package org.koitharu.kotatsu.base.ui.widgets - -import android.content.Context -import android.os.Parcel -import android.os.Parcelable -import android.util.AttributeSet -import android.view.View -import androidx.coordinatorlayout.widget.CoordinatorLayout -import androidx.core.view.doOnLayout -import androidx.customview.view.AbsSavedState -import com.google.android.material.appbar.AppBarLayout -import org.koitharu.kotatsu.utils.ext.findChild - -class KotatsuCoordinatorLayout @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = androidx.coordinatorlayout.R.attr.coordinatorLayoutStyle -) : CoordinatorLayout(context, attrs, defStyleAttr) { - - private var appBarLayout: AppBarLayout? = null - - /** - * If true, [AppBarLayout] child will be lifted on nested scroll. - */ - var isLiftAppBarOnScroll = true - - /** - * Internal check - */ - private val canLiftAppBarOnScroll - get() = isLiftAppBarOnScroll - - override fun onNestedScroll( - target: View, - dxConsumed: Int, - dyConsumed: Int, - dxUnconsumed: Int, - dyUnconsumed: Int, - type: Int, - consumed: IntArray - ) { - super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type, consumed) - if (canLiftAppBarOnScroll) { - appBarLayout?.isLifted = dyConsumed != 0 || dyUnconsumed >= 0 - } - } - - override fun onAttachedToWindow() { - super.onAttachedToWindow() - appBarLayout = findChild() - } - - override fun onDetachedFromWindow() { - super.onDetachedFromWindow() - appBarLayout = null - } - - override fun onSaveInstanceState(): Parcelable? { - val superState = super.onSaveInstanceState() - return if (superState != null) { - SavedState(superState).also { - it.appBarLifted = appBarLayout?.isLifted ?: false - } - } else { - superState - } - } - - override fun onRestoreInstanceState(state: Parcelable?) { - if (state is SavedState) { - super.onRestoreInstanceState(state.superState) - doOnLayout { - appBarLayout?.isLifted = state.appBarLifted - } - } else { - super.onRestoreInstanceState(state) - } - } - - internal class SavedState : AbsSavedState { - var appBarLifted = false - - constructor(superState: Parcelable) : super(superState) - - constructor(source: Parcel, loader: ClassLoader?) : super(source, loader) { - appBarLifted = source.readByte().toInt() == 1 - } - - override fun writeToParcel(out: Parcel, flags: Int) { - super.writeToParcel(out, flags) - out.writeByte((if (appBarLifted) 1 else 0).toByte()) - } - - companion object { - @JvmField - val CREATOR: Parcelable.ClassLoaderCreator = object : Parcelable.ClassLoaderCreator { - override fun createFromParcel(source: Parcel, loader: ClassLoader): SavedState { - return SavedState(source, loader) - } - - override fun createFromParcel(source: Parcel): SavedState { - return SavedState(source, null) - } - - override fun newArray(size: Int): Array { - return newArray(size) - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/KotatsuBottomNavigationView.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/SlidingBottomNavigationView.kt similarity index 54% rename from app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/KotatsuBottomNavigationView.kt rename to app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/SlidingBottomNavigationView.kt index 7ee897e80..bfbaf2f92 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/KotatsuBottomNavigationView.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/SlidingBottomNavigationView.kt @@ -8,46 +8,42 @@ import android.os.Parcel import android.os.Parcelable import android.util.AttributeSet import android.view.ViewPropertyAnimator +import androidx.annotation.AttrRes +import androidx.annotation.StyleRes import androidx.coordinatorlayout.widget.CoordinatorLayout -import androidx.core.view.doOnLayout -import androidx.core.view.updateLayoutParams -import androidx.customview.view.AbsSavedState import androidx.interpolator.view.animation.FastOutLinearInInterpolator import androidx.interpolator.view.animation.LinearOutSlowInInterpolator -import androidx.lifecycle.findViewTreeLifecycleOwner -import androidx.lifecycle.lifecycleScope +import com.google.android.material.R as materialR import com.google.android.material.bottomnavigation.BottomNavigationView import org.koitharu.kotatsu.utils.ext.applySystemAnimatorScale -import com.google.android.material.R as materialR +import org.koitharu.kotatsu.utils.ext.measureHeight + +private const val STATE_DOWN = 1 +private const val STATE_UP = 2 + +private const val SLIDE_UP_ANIMATION_DURATION = 225L +private const val SLIDE_DOWN_ANIMATION_DURATION = 175L -class KotatsuBottomNavigationView @JvmOverloads constructor( +class SlidingBottomNavigationView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = materialR.attr.bottomNavigationStyle, - defStyleRes: Int = materialR.style.Widget_Design_BottomNavigationView, -) : BottomNavigationView(context, attrs, defStyleAttr, defStyleRes) { + @AttrRes defStyleAttr: Int = materialR.attr.bottomNavigationStyle, + @StyleRes defStyleRes: Int = materialR.style.Widget_Design_BottomNavigationView, +) : BottomNavigationView(context, attrs, defStyleAttr, defStyleRes), + CoordinatorLayout.AttachedBehavior { private var currentAnimator: ViewPropertyAnimator? = null private var currentState = STATE_UP + private var behavior = HideBottomNavigationOnScrollBehavior() - init { - // Hide on scroll - doOnLayout { - findViewTreeLifecycleOwner()?.lifecycleScope?.let { - updateLayoutParams { - behavior = HideBottomNavigationOnScrollBehavior() - } - } - } + override fun getBehavior(): CoordinatorLayout.Behavior<*> { + return behavior } override fun onSaveInstanceState(): Parcelable { val superState = super.onSaveInstanceState() - return SavedState(superState).also { - it.currentState = currentState - it.translationY = translationY - } + return SavedState(superState, currentState, translationY) } override fun onRestoreInstanceState(state: Parcelable?) { @@ -62,14 +58,12 @@ class KotatsuBottomNavigationView @JvmOverloads constructor( override fun setTranslationY(translationY: Float) { // Disallow translation change when state down - if (currentState == STATE_DOWN) return - super.setTranslationY(translationY) + if (currentState != STATE_DOWN) { + super.setTranslationY(translationY) + } } - /** - * Shows this view up. - */ - fun slideUp() = post { + fun show() { currentAnimator?.cancel() clearAnimation() @@ -81,16 +75,17 @@ class KotatsuBottomNavigationView @JvmOverloads constructor( ) } - /** - * Hides this view down. [setTranslationY] won't work until [slideUp] is called. - */ - fun slideDown() = post { + fun hide() { currentAnimator?.cancel() clearAnimation() currentState = STATE_DOWN + val target = measureHeight() + if (target == 0) { + return + } animateTranslation( - height.toFloat(), + target.toFloat(), SLIDE_DOWN_ANIMATION_DURATION, FastOutLinearInInterpolator(), ) @@ -102,22 +97,26 @@ class KotatsuBottomNavigationView @JvmOverloads constructor( .setInterpolator(interpolator) .setDuration(duration) .applySystemAnimatorScale(context) - .setListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator?) { - currentAnimator = null - postInvalidate() - } - }, + .setListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator?) { + currentAnimator = null + postInvalidate() + } + }, ) } - internal class SavedState : AbsSavedState { + internal class SavedState : BaseSavedState { var currentState = STATE_UP var translationY = 0F - constructor(superState: Parcelable) : super(superState) + constructor(superState: Parcelable, currentState: Int, translationY: Float) : super(superState) { + this.currentState = currentState + this.translationY = translationY + } - constructor(source: Parcel, loader: ClassLoader?) : super(source, loader) { + constructor(source: Parcel) : super(source) { currentState = source.readInt() translationY = source.readFloat() } @@ -129,28 +128,14 @@ class KotatsuBottomNavigationView @JvmOverloads constructor( } companion object { + + @Suppress("unused") @JvmField - val CREATOR: Parcelable.ClassLoaderCreator = object : Parcelable.ClassLoaderCreator { - override fun createFromParcel(source: Parcel, loader: ClassLoader): SavedState { - return SavedState(source, loader) - } - - override fun createFromParcel(source: Parcel): SavedState { - return SavedState(source, null) - } - - override fun newArray(size: Int): Array { - return newArray(size) - } + val CREATOR: Parcelable.Creator = object : Parcelable.Creator { + override fun createFromParcel(`in`: Parcel) = SavedState(`in`) + + override fun newArray(size: Int): Array = arrayOfNulls(size) } } } - - companion object { - private const val STATE_DOWN = 1 - private const val STATE_UP = 2 - - private const val SLIDE_UP_ANIMATION_DURATION = 225L - private const val SLIDE_DOWN_ANIMATION_DURATION = 175L - } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/SquareLayout.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/SquareLayout.kt deleted file mode 100644 index 589d75382..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/SquareLayout.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.koitharu.kotatsu.base.ui.widgets - -import android.content.Context -import android.util.AttributeSet -import android.widget.FrameLayout - -class SquareLayout @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : FrameLayout(context, attrs, defStyleAttr) { - - public override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - super.onMeasure(widthMeasureSpec, widthMeasureSpec) - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/WindowInsetHolder.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/WindowInsetHolder.kt index 0d915dc4f..3279dfc06 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/WindowInsetHolder.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/WindowInsetHolder.kt @@ -1,6 +1,5 @@ package org.koitharu.kotatsu.base.ui.widgets -import android.annotation.SuppressLint import android.content.Context import android.util.AttributeSet import android.view.Gravity @@ -21,8 +20,7 @@ class WindowInsetHolder @JvmOverloads constructor( private var desiredHeight = 0 private var desiredWidth = 0 - @SuppressLint("RtlHardcoded") - override fun dispatchApplyWindowInsets(insets: WindowInsets): WindowInsets { + override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets { val barsInsets = WindowInsetsCompat.toWindowInsetsCompat(insets, this) .getInsets(WindowInsetsCompat.Type.systemBars()) val gravity = getLayoutGravity() @@ -41,24 +39,26 @@ class WindowInsetHolder @JvmOverloads constructor( desiredHeight = newHeight requestLayout() } - return super.dispatchApplyWindowInsets(insets) + return super.onApplyWindowInsets(insets) } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val widthMode = MeasureSpec.getMode(widthMeasureSpec) + val widthSize = MeasureSpec.getSize(widthMeasureSpec) val heightMode = MeasureSpec.getMode(heightMeasureSpec) - super.onMeasure( - if (desiredWidth == 0 || widthMode == MeasureSpec.EXACTLY) { - widthMeasureSpec - } else { - MeasureSpec.makeMeasureSpec(desiredWidth, widthMode) - }, - if (desiredHeight == 0 || heightMode == MeasureSpec.EXACTLY) { - heightMeasureSpec - } else { - MeasureSpec.makeMeasureSpec(desiredHeight, heightMode) - }, - ) + val heightSize = MeasureSpec.getSize(heightMeasureSpec) + + val width: Int = when (widthMode) { + MeasureSpec.EXACTLY -> widthSize + MeasureSpec.AT_MOST -> minOf(desiredWidth, widthSize) + else -> desiredWidth + } + val height = when (heightMode) { + MeasureSpec.EXACTLY -> heightSize + MeasureSpec.AT_MOST -> minOf(desiredHeight, heightSize) + else -> desiredHeight + } + setMeasuredDimension(width, height) } private fun getLayoutGravity(): Int { @@ -69,4 +69,4 @@ class WindowInsetHolder @JvmOverloads constructor( else -> Gravity.NO_GRAVITY } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt index 7bc70c836..1386851ec 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt @@ -201,16 +201,11 @@ abstract class MangaListFragment : } override fun onWindowInsetsChanged(insets: Insets) { - binding.root.updatePadding( - left = insets.left, - right = insets.right, - ) binding.recyclerView.updatePadding( bottom = insets.bottom, ) binding.recyclerView.fastScroller.updateLayoutParams { bottomMargin = insets.bottom - marginEnd = insets.end(binding.recyclerView) } if (activity is MainActivity) { val headerHeight = (activity as? AppBarOwner)?.appBar?.measureHeight() ?: insets.top diff --git a/app/src/main/java/org/koitharu/kotatsu/main/ui/BottomNavOwner.kt b/app/src/main/java/org/koitharu/kotatsu/main/ui/BottomNavOwner.kt index 3d254e8ee..02a9f3624 100644 --- a/app/src/main/java/org/koitharu/kotatsu/main/ui/BottomNavOwner.kt +++ b/app/src/main/java/org/koitharu/kotatsu/main/ui/BottomNavOwner.kt @@ -1,8 +1,8 @@ package org.koitharu.kotatsu.main.ui -import org.koitharu.kotatsu.base.ui.widgets.KotatsuBottomNavigationView +import org.koitharu.kotatsu.base.ui.widgets.SlidingBottomNavigationView interface BottomNavOwner { - val bottomNav: KotatsuBottomNavigationView? + val bottomNav: SlidingBottomNavigationView? } diff --git a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt index c9a73565f..2b309304f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt @@ -7,9 +7,9 @@ import android.view.View import android.view.ViewGroup.MarginLayoutParams import androidx.activity.result.ActivityResultCallback import androidx.activity.viewModels -import androidx.annotation.IdRes import androidx.appcompat.view.ActionMode import androidx.core.app.ActivityOptionsCompat +import androidx.core.content.ContextCompat import androidx.core.graphics.Insets import androidx.core.util.size import androidx.core.view.* @@ -21,7 +21,6 @@ import androidx.transition.TransitionManager import com.google.android.material.R as materialR import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout.LayoutParams.* -import com.google.android.material.navigation.NavigationBarView import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.Dispatchers @@ -29,11 +28,9 @@ import kotlinx.coroutines.withContext import kotlinx.coroutines.yield import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BaseActivity -import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner -import org.koitharu.kotatsu.base.ui.widgets.KotatsuBottomNavigationView +import org.koitharu.kotatsu.base.ui.widgets.SlidingBottomNavigationView import org.koitharu.kotatsu.databinding.ActivityMainBinding import org.koitharu.kotatsu.details.ui.DetailsActivity -import org.koitharu.kotatsu.explore.ui.ExploreFragment import org.koitharu.kotatsu.library.ui.LibraryFragment import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaSource @@ -46,14 +43,11 @@ import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionListener import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionViewModel import org.koitharu.kotatsu.settings.newsources.NewSourcesDialogFragment import org.koitharu.kotatsu.settings.onboard.OnboardDialogFragment -import org.koitharu.kotatsu.settings.tools.ToolsFragment import org.koitharu.kotatsu.suggestions.ui.SuggestionsWorker -import org.koitharu.kotatsu.tracker.ui.FeedFragment import org.koitharu.kotatsu.tracker.work.TrackWorker import org.koitharu.kotatsu.utils.VoiceInputContract import org.koitharu.kotatsu.utils.ext.* -private const val TAG_PRIMARY = "primary" private const val TAG_SEARCH = "search" @AndroidEntryPoint @@ -64,25 +58,23 @@ class MainActivity : View.OnClickListener, View.OnFocusChangeListener, SearchSuggestionListener, - NavigationBarView.OnItemSelectedListener, - NavigationBarView.OnItemReselectedListener { + MainNavigationDelegate.OnFragmentChangedListener { private val viewModel by viewModels() private val searchSuggestionViewModel by viewModels() private val voiceInputLauncher = registerForActivityResult(VoiceInputContract(), VoiceInputCallback()) - private lateinit var navBar: NavigationBarView + private lateinit var navigationDelegate: MainNavigationDelegate override val appBar: AppBarLayout get() = binding.appbar - override val bottomNav: KotatsuBottomNavigationView? + override val bottomNav: SlidingBottomNavigationView? get() = binding.bottomNav override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(ActivityMainBinding.inflate(layoutInflater)) - navBar = checkNotNull(bottomNav ?: binding.navRail) if (bottomNav != null) { ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets -> if (insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom > 0) { @@ -98,18 +90,17 @@ class MainActivity : onFocusChangeListener = this@MainActivity searchSuggestionListener = this@MainActivity } + window.statusBarColor = ContextCompat.getColor(this, R.color.dim_statusbar) - binding.root.isLiftAppBarOnScroll = false - navBar.setOnItemSelectedListener(this) - navBar.setOnItemReselectedListener(this) binding.fab?.setOnClickListener(this) binding.navRail?.headerView?.setOnClickListener(this) binding.searchView.isVoiceSearchEnabled = voiceInputLauncher.resolve(this, null) != null onBackPressedDispatcher.addCallback(ExitCallback(this, binding.container)) - supportFragmentManager.findFragmentByTag(TAG_PRIMARY)?.let { - if (it is LibraryFragment) binding.fab?.show() else binding.fab?.hide() - } ?: onNavigationItemSelected(navBar.selectedItemId) + navigationDelegate = MainNavigationDelegate(checkNotNull(bottomNav ?: binding.navRail), supportFragmentManager) + navigationDelegate.addOnFragmentChangedListener(this) + navigationDelegate.onCreate(savedInstanceState) + if (savedInstanceState == null) { onFirstStart() } @@ -123,17 +114,7 @@ class MainActivity : override fun onRestoreInstanceState(savedInstanceState: Bundle) { super.onRestoreInstanceState(savedInstanceState) - val isSearchOpened = isSearchOpened() - if (isSearchOpened) { - binding.toolbarCard.updateLayoutParams { - scrollFlags = SCROLL_FLAG_NO_SCROLL - } - binding.toolbarCard.background = null - binding.appbar.setBackgroundColor(getThemeColor(materialR.attr.colorSurfaceVariant)) - binding.appbar.updatePadding(left = 0, right = 0) - supportActionBar?.setHomeAsUpIndicator(materialR.drawable.abc_ic_ab_back_material) - } - adjustFabVisibility(isSearchOpened = isSearchOpened) + adjustSearchUI(isSearchOpened(), animate = false) } override fun onBackPressed() { @@ -149,8 +130,15 @@ class MainActivity : } } - override fun onNavigationItemSelected(item: MenuItem): Boolean { - return onNavigationItemSelected(item.itemId) + override fun onFragmentChanged(fragment: Fragment, fromUser: Boolean) { + if (fragment is LibraryFragment) { + binding.fab?.show() + } else { + binding.fab?.hide() + } + if (fromUser) { + binding.appbar.setExpanded(true) + } } override fun onOptionsItemSelected(item: MenuItem): Boolean { @@ -248,36 +236,9 @@ class MainActivity : showNav(true) } - private fun onNavigationItemSelected(@IdRes itemId: Int): Boolean { - when (itemId) { - R.id.nav_library -> { - setPrimaryFragment(LibraryFragment.newInstance()) - } - R.id.nav_explore -> { - setPrimaryFragment(ExploreFragment.newInstance()) - } - R.id.nav_feed -> { - setPrimaryFragment(FeedFragment.newInstance()) - } - R.id.nav_tools -> { - setPrimaryFragment(ToolsFragment.newInstance()) - } - else -> return false - } - appBar.setExpanded(true) - appBar.isLifted = false - return true - } - - override fun onNavigationItemReselected(item: MenuItem) { - val fragment = supportFragmentManager.findFragmentById(R.id.container) as? RecyclerViewOwner ?: return - val recyclerView = fragment.recyclerView - recyclerView.smoothScrollToPosition(0) - binding.appbar.isLifted = false - } - private fun onOpenReader(manga: Manga) { - val options = binding.fab?.let { + val fab = binding.fab ?: binding.navRail?.headerView + val options = fab?.let { scaleUpActivityOptionsOf(it).toBundle() } startActivity(ReaderActivity.newIntent(this, manga), options) @@ -292,17 +253,7 @@ class MainActivity : repeat(counters.size) { i -> val id = counters.keyAt(i) val counter = counters.valueAt(i) - if (counter == 0) { - navBar.getBadge(id)?.isVisible = false - } else { - val badge = navBar.getOrCreateBadge(id) - if (counter < 0) { - badge.clearNumber() - } else { - badge.number = counter - } - badge.isVisible = true - } + navigationDelegate.setCounter(id, counter) } } @@ -314,55 +265,28 @@ class MainActivity : adjustFabVisibility(isResumeEnabled = isEnabled) } - private fun setPrimaryFragment(fragment: Fragment) { - supportFragmentManager.beginTransaction() - .replace(R.id.container, fragment, TAG_PRIMARY) - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) - .commit() - adjustFabVisibility(topFragment = fragment) - } - private fun onSearchOpened() { - TransitionManager.beginDelayedTransition(binding.appbar) - binding.toolbarCard.updateLayoutParams { - scrollFlags = SCROLL_FLAG_NO_SCROLL - } - binding.toolbarCard.background = null - binding.appbar.isLifted = true - binding.appbar.updatePadding(left = 0, right = 0) - adjustFabVisibility(isSearchOpened = true) - supportActionBar?.setHomeAsUpIndicator(materialR.drawable.abc_ic_ab_back_material) - showNav(false) + adjustSearchUI(isOpened = true, animate = true) } private fun onSearchClosed() { binding.searchView.hideKeyboard() - TransitionManager.beginDelayedTransition(binding.appbar) - binding.toolbarCard.updateLayoutParams { - scrollFlags = SCROLL_FLAG_SCROLL or SCROLL_FLAG_ENTER_ALWAYS or SCROLL_FLAG_SNAP - } - binding.toolbarCard.setBackgroundResource(R.drawable.toolbar_background) - binding.appbar.isLifted = false - val padding = resources.getDimensionPixelOffset(R.dimen.margin_normal) - binding.appbar.updatePadding(left = padding, right = padding) - adjustFabVisibility(isSearchOpened = false) - supportActionBar?.setHomeAsUpIndicator(materialR.drawable.abc_ic_search_api_material) - showNav(true) + adjustSearchUI(isOpened = false, animate = true) } private fun showNav(visible: Boolean) { bottomNav?.run { if (visible) { - slideUp() + show() } else { - slideDown() + hide() } } binding.navRail?.isVisible = visible } private fun isSearchOpened(): Boolean { - return supportFragmentManager.findFragmentByTag(TAG_SEARCH)?.isVisible == true + return supportFragmentManager.findFragmentByTag(TAG_SEARCH) != null } private fun onFirstStart() { @@ -382,7 +306,7 @@ class MainActivity : private fun adjustFabVisibility( isResumeEnabled: Boolean = viewModel.isResumeEnabled.value == true, - topFragment: Fragment? = supportFragmentManager.findFragmentByTag(TAG_PRIMARY), + topFragment: Fragment? = navigationDelegate.primaryFragment, isSearchOpened: Boolean = isSearchOpened(), ) { val fab = binding.fab @@ -402,6 +326,31 @@ class MainActivity : } } + private fun adjustSearchUI(isOpened: Boolean, animate: Boolean) { + if (animate) { + TransitionManager.beginDelayedTransition(binding.appbar) + } + val appBarScrollFlags = if (isOpened) { + SCROLL_FLAG_NO_SCROLL + } else { + SCROLL_FLAG_SCROLL or SCROLL_FLAG_ENTER_ALWAYS or SCROLL_FLAG_SNAP + } + binding.toolbarCard.updateLayoutParams { scrollFlags = appBarScrollFlags } + binding.insetsHolder.updateLayoutParams { scrollFlags = appBarScrollFlags } + binding.toolbarCard.background = if (isOpened) { + null + } else { + ContextCompat.getDrawable(this, R.drawable.toolbar_background) + } + val padding = if (isOpened) 0 else resources.getDimensionPixelOffset(R.dimen.margin_normal) + binding.appbar.updatePadding(left = padding, right = padding) + adjustFabVisibility(isSearchOpened = isOpened) + supportActionBar?.setHomeAsUpIndicator( + if (isOpened) materialR.drawable.abc_ic_ab_back_material else materialR.drawable.abc_ic_search_api_material, + ) + showNav(!isOpened) + } + private inner class VoiceInputCallback : ActivityResultCallback { override fun onActivityResult(result: String?) { diff --git a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainNavigationDelegate.kt b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainNavigationDelegate.kt new file mode 100644 index 000000000..01e870565 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainNavigationDelegate.kt @@ -0,0 +1,102 @@ +package org.koitharu.kotatsu.main.ui + +import android.os.Bundle +import android.view.MenuItem +import androidx.annotation.IdRes +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentTransaction +import com.google.android.material.navigation.NavigationBarView +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner +import org.koitharu.kotatsu.explore.ui.ExploreFragment +import org.koitharu.kotatsu.library.ui.LibraryFragment +import org.koitharu.kotatsu.settings.tools.ToolsFragment +import org.koitharu.kotatsu.tracker.ui.FeedFragment +import java.util.* + +private const val TAG_PRIMARY = "primary" + +class MainNavigationDelegate( + private val navBar: NavigationBarView, + private val fragmentManager: FragmentManager, +) : NavigationBarView.OnItemSelectedListener, NavigationBarView.OnItemReselectedListener { + + private val listeners = LinkedList() + + val primaryFragment: Fragment? + get() = fragmentManager.findFragmentByTag(TAG_PRIMARY) + + init { + navBar.setOnItemSelectedListener(this) + navBar.setOnItemReselectedListener(this) + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + return onNavigationItemSelected(item.itemId) + } + + override fun onNavigationItemReselected(item: MenuItem) { + val fragment = fragmentManager.findFragmentByTag(TAG_PRIMARY) as? RecyclerViewOwner ?: return + val recyclerView = fragment.recyclerView + recyclerView.smoothScrollToPosition(0) + } + + fun onCreate(savedInstanceState: Bundle?) { + primaryFragment?.let { + onFragmentChanged(it, fromUser = false) + } ?: onNavigationItemSelected(navBar.selectedItemId) + } + + fun setCounter(@IdRes id: Int, counter: Int) { + if (counter == 0) { + navBar.getBadge(id)?.isVisible = false + } else { + val badge = navBar.getOrCreateBadge(id) + if (counter < 0) { + badge.clearNumber() + } else { + badge.number = counter + } + badge.isVisible = true + } + } + + fun addOnFragmentChangedListener(listener: OnFragmentChangedListener) { + listeners.add(listener) + } + + fun removeOnFragmentChangedListener(listener: OnFragmentChangedListener) { + listeners.remove(listener) + } + + private fun onNavigationItemSelected(@IdRes itemId: Int): Boolean { + setPrimaryFragment( + when (itemId) { + R.id.nav_library -> LibraryFragment.newInstance() + R.id.nav_explore -> ExploreFragment.newInstance() + R.id.nav_feed -> FeedFragment.newInstance() + R.id.nav_tools -> ToolsFragment.newInstance() + else -> return false + }, + ) + return true + } + + private fun setPrimaryFragment(fragment: Fragment) { + fragmentManager.beginTransaction() + .replace(R.id.container, fragment, TAG_PRIMARY) + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) + .commit() + onFragmentChanged(fragment, fromUser = true) + } + + private fun onFragmentChanged(fragment: Fragment, fromUser: Boolean) { + listeners.forEach { it.onFragmentChanged(fragment, fromUser) } + } + + interface OnFragmentChangedListener { + + fun onFragmentChanged(fragment: Fragment, fromUser: Boolean) + } +} diff --git a/app/src/main/java/org/koitharu/kotatsu/search/ui/multi/MultiSearchActivity.kt b/app/src/main/java/org/koitharu/kotatsu/search/ui/multi/MultiSearchActivity.kt index bdfb973ec..28cabbcbc 100644 --- a/app/src/main/java/org/koitharu/kotatsu/search/ui/multi/MultiSearchActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/search/ui/multi/MultiSearchActivity.kt @@ -7,6 +7,7 @@ import android.view.Menu import android.view.MenuItem import android.view.View import androidx.appcompat.view.ActionMode +import androidx.core.content.ContextCompat import androidx.core.graphics.Insets import androidx.core.view.updatePadding import coil.ImageLoader @@ -53,6 +54,7 @@ class MultiSearchActivity : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(ActivitySearchMultiBinding.inflate(layoutInflater)) + window.statusBarColor = ContextCompat.getColor(this, R.color.dim_statusbar) val itemCLickListener = object : OnListItemClickListener { override fun onItemClick(item: MultiSearchListModel, view: View) { diff --git a/app/src/main/res/layout-w600dp/activity_main.xml b/app/src/main/res/layout-w600dp/activity_main.xml index e85c414df..ac119b5ea 100644 --- a/app/src/main/res/layout-w600dp/activity_main.xml +++ b/app/src/main/res/layout-w600dp/activity_main.xml @@ -1,28 +1,51 @@ - - + + - + + + app:liftOnScroll="false"> + + + android:theme="@style/ThemeOverlay.Kotatsu.MainToolbar" + app:layout_scrollFlags="scroll|enterAlways|snap"> @@ -60,28 +84,8 @@ - - - - - + - + - \ No newline at end of file + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 12eb5358d..01c535da6 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,5 +1,5 @@ - - + android:stateListAnimator="@null" + app:liftOnScroll="false"> + + - + - - + diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index 7325cc62c..d536f3c51 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -1,11 +1,11 @@ - - - + - + diff --git a/app/src/main/res/layout/activity_search_multi.xml b/app/src/main/res/layout/activity_search_multi.xml index f41cbeef6..783cb6d61 100644 --- a/app/src/main/res/layout/activity_search_multi.xml +++ b/app/src/main/res/layout/activity_search_multi.xml @@ -1,16 +1,23 @@ - - + android:fitsSystemWindows="false" + app:elevation="0dp" + app:liftOnScroll="false"> + + - + - \ No newline at end of file + diff --git a/app/src/main/res/layout/navigation_rail_fab.xml b/app/src/main/res/layout/navigation_rail_fab.xml index a20a205c5..74caa5107 100644 --- a/app/src/main/res/layout/navigation_rail_fab.xml +++ b/app/src/main/res/layout/navigation_rail_fab.xml @@ -3,7 +3,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/railFab" - android:theme="@style/ThemeOverlay.Material3.FloatingActionButton.Tertiary" android:layout_width="wrap_content" android:layout_height="wrap_content" - app:srcCompat="@drawable/ic_read" /> \ No newline at end of file + android:contentDescription="@string/_continue" + app:srcCompat="@drawable/ic_read" /> diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index 1770ac971..d1a29d861 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -8,5 +8,6 @@ #66FFFFFF #29FFFFFF #1FFFFFFF + #99000000 - \ No newline at end of file + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index f4bae8418..27aaebfd4 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -18,8 +18,9 @@ #424242 #212121 #99000000 + #99FFFFFF #66000000 #29000000 #1F000000 - \ No newline at end of file + diff --git a/app/src/main/res/values/integers.xml b/app/src/main/res/values/integers.xml index 1676e5cbb..7cbbd343a 100644 --- a/app/src/main/res/values/integers.xml +++ b/app/src/main/res/values/integers.xml @@ -1,6 +1,7 @@ 300 + 150 50 3