Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MovieDetailsActivity: draw behind system bars, manually color app bar. #890

Merged
merged 1 commit into from
Dec 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Version 66
----------
*in development*

* 🔧 Appearance: draw behind navigation bar in movie details screen.

#### 66.0.3 🧪
*2022-12-10*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,24 @@ package com.battlelancer.seriesguide.movies.details
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import com.battlelancer.seriesguide.R
import com.battlelancer.seriesguide.ui.BaseMessageActivity
import com.readystatesoftware.systembartint.SystemBarTintManager
import com.uwetrottmann.androidutils.AndroidUtils
import com.battlelancer.seriesguide.util.ThemeUtils
import com.google.android.material.appbar.AppBarLayout

/**
* Hosts a [MovieDetailsFragment] displaying details about the movie defined by the given TMDb
* id intent extra.
*/
class MovieDetailsActivity : BaseMessageActivity() {

lateinit var systemBarTintManager: SystemBarTintManager

override fun getCustomTheme(): Int {
return R.style.Theme_SeriesGuide_DayNight_Immersive
}

override fun configureEdgeToEdge() {
// Do nothing.
}
lateinit var sgAppBarLayout: AppBarLayout

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// support transparent status bar
if (AndroidUtils.isMarshmallowOrHigher) {
findViewById<View>(android.R.id.content).systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
}

setContentView(R.layout.activity_movie)
ThemeUtils.configureForEdgeToEdge(findViewById(R.id.rootLayoutMovieActivity))
sgAppBarLayout = findViewById(R.id.sgAppBarLayout)
setupActionBar()

if (intent.extras == null) {
Expand All @@ -49,34 +33,12 @@ class MovieDetailsActivity : BaseMessageActivity() {
return
}

setupViews()

if (savedInstanceState == null) {
val f = MovieDetailsFragment.newInstance(tmdbId)
supportFragmentManager.beginTransaction().add(R.id.content_frame, f).commit()
}
}

private fun setupViews() {
// fix padding with translucent (K+)/transparent (M+) status bar
// warning: pre-M status bar not always translucent (e.g. Nexus 10)
// (using fitsSystemWindows would not work correctly with multiple views)
val systemBarTintManager = SystemBarTintManager(this)
.also { systemBarTintManager = it }
val config = systemBarTintManager.config
val insetTop = if (AndroidUtils.isMarshmallowOrHigher) {
config.statusBarHeight // transparent status bar
} else {
config.getPixelInsetTop(false) // translucent status bar
}
val actionBarToolbar = findViewById<ViewGroup>(R.id.sgToolbar)
val layoutParams = actionBarToolbar.layoutParams as MarginLayoutParams
layoutParams.setMargins(
layoutParams.leftMargin, layoutParams.topMargin + insetTop,
layoutParams.rightMargin, layoutParams.bottomMargin
)
}

override fun setupActionBar() {
super.setupActionBar()
val actionBar = supportActionBar
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import com.battlelancer.seriesguide.util.Metacritic
import com.battlelancer.seriesguide.util.ServiceUtils
import com.battlelancer.seriesguide.util.ShareUtils
import com.battlelancer.seriesguide.util.TextTools
import com.battlelancer.seriesguide.util.ThemeUtils
import com.battlelancer.seriesguide.util.TimeTools
import com.battlelancer.seriesguide.util.Utils
import com.battlelancer.seriesguide.util.ViewTools
Expand Down Expand Up @@ -88,6 +89,7 @@ class MovieDetailsFragment : Fragment(), MovieActionsContract {
private val model: MovieDetailsModel by viewModels {
MovieDetailsModelFactory(tmdbId, requireActivity().application)
}
private lateinit var scrollChangeListener: ToolbarScrollChangeListener

override fun onCreateView(
inflater: LayoutInflater,
Expand Down Expand Up @@ -185,28 +187,15 @@ class MovieDetailsFragment : Fragment(), MovieActionsContract {
}

private fun setupViews() {
// avoid overlap with status + action bar (adjust top margin)
// warning: pre-M status bar not always translucent (e.g. Nexus 10)
// (using fitsSystemWindows would not work correctly with multiple views)
val config = (activity as MovieDetailsActivity).systemBarTintManager.config
val pixelInsetTop = if (AndroidUtils.isMarshmallowOrHigher) {
config.statusBarHeight // full screen, status bar transparent
} else {
config.getPixelInsetTop(false) // status bar translucent
}

// action bar height is pre-set as top margin, add to it
val decorationHeightPx = pixelInsetTop + binding.contentContainerMovie.paddingTop
binding.contentContainerMovie.setPadding(0, decorationHeightPx, 0, 0)

// dual pane layout?
binding.contentContainerMovieRight?.setPadding(0, decorationHeightPx, 0, 0)

// show toolbar title and background when scrolling
val defaultPaddingPx = resources.getDimensionPixelSize(R.dimen.default_padding)
val scrollChangeListener = ToolbarScrollChangeListener(defaultPaddingPx, decorationHeightPx)
val defaultPaddingPx = resources.getDimensionPixelSize(R.dimen.large_padding)
val scrollChangeListener = ToolbarScrollChangeListener(defaultPaddingPx)
.also { scrollChangeListener = it }
binding.contentContainerMovie.setOnScrollChangeListener(scrollChangeListener)
binding.contentContainerMovieRight?.setOnScrollChangeListener(scrollChangeListener)

ThemeUtils.applyBottomPaddingForNavigationBar(binding.contentContainerMovie)
binding.contentContainerMovieRight?.let { ThemeUtils.applyBottomPaddingForNavigationBar(it) }
}

override fun onStart() {
Expand Down Expand Up @@ -504,19 +493,37 @@ class MovieDetailsFragment : Fragment(), MovieActionsContract {
val bitmap =
(binding.imageViewMoviePoster.drawable as BitmapDrawable).bitmap

val color = withContext(Dispatchers.Default) {
val (colorBackground, colorAppBarLifted) = withContext(Dispatchers.Default) {
val palette = try {
Palette.from(bitmap).generate()
} catch (e: Exception) {
Timber.e(e, "Failed to generate palette.")
null
}
palette
?.getVibrantColor(Color.WHITE)
?.let { ColorUtils.setAlphaComponent(it, 50) }
val vibrantColor = palette?.getVibrantColor(Color.WHITE)
Pair(
vibrantColor?.let { ColorUtils.setAlphaComponent(it, 50) },
vibrantColor?.let { ColorUtils.setAlphaComponent(it, 80) }
)
}

color?.let { binding.rootLayoutMovie.setBackgroundColor(it) }
colorBackground?.let {
// Color fragment background
binding.rootLayoutMovie.setBackgroundColor(it)

// Color app bar background
scrollChangeListener.appBarBackground = colorBackground
scrollChangeListener.appBarBackgroundLifted = colorAppBarLifted
sgAppBarLayout.apply {
background = ColorDrawable(
if (scrollChangeListener.showOverlay) {
colorAppBarLifted!!
} else {
colorBackground
}
)
}
}
}
}
})
Expand Down Expand Up @@ -764,14 +771,20 @@ class MovieDetailsFragment : Fragment(), MovieActionsContract {
}
}

private val sgAppBarLayout
get() = (activity as MovieDetailsActivity).sgAppBarLayout

private inner class ToolbarScrollChangeListener(
private val overlayThresholdPx: Int,
private val titleThresholdPx: Int
private val overlayThresholdPx: Int
) : NestedScrollView.OnScrollChangeListener {

var appBarBackground: Int? = null
var appBarBackgroundLifted: Int? = null

// we have determined by science that a capacity of 2 is good in our case :)
private val showOverlayMap: SparseArrayCompat<Boolean> = SparseArrayCompat(2)
private var showOverlay: Boolean = false
var showOverlay: Boolean = false
private set
private var showTitle: Boolean = false

override fun onScrollChange(
Expand All @@ -789,30 +802,30 @@ class MovieDetailsFragment : Fragment(), MovieActionsContract {
val shouldShowOverlay = shouldShowOverlayTemp

if (!showOverlay && shouldShowOverlay) {
val primaryColor = ContextCompat.getColor(
val drawableColor = appBarBackgroundLifted ?: ContextCompat.getColor(
v.context,
Utils.resolveAttributeToResourceId(
v.context.theme, R.attr.sgColorStatusBarOverlay
)
)
actionBar.setBackgroundDrawable(ColorDrawable(primaryColor))
sgAppBarLayout.background = ColorDrawable(drawableColor)
} else if (showOverlay && !shouldShowOverlay) {
actionBar.setBackgroundDrawable(null)
val drawableColor = appBarBackground ?: Color.TRANSPARENT
sgAppBarLayout.background = ColorDrawable(drawableColor)
}
showOverlay = shouldShowOverlay

// only main container should show/hide title
// Only show/hide title if main container displaying title is scrolled.
if (viewId == R.id.contentContainerMovie) {
val shouldShowTitle = scrollY > titleThresholdPx
if (!showTitle && shouldShowTitle) {
if (!showTitle && shouldShowOverlay) {
movieDetails?.tmdbMovie()?.let {
actionBar.title = it.title
actionBar.setDisplayShowTitleEnabled(true)
}
} else if (showTitle && !shouldShowTitle) {
} else if (showTitle && !shouldShowOverlay) {
actionBar.setDisplayShowTitleEnabled(false)
}
showTitle = shouldShowTitle
showTitle = shouldShowOverlay
}
}
}
Expand Down
36 changes: 16 additions & 20 deletions app/src/main/res/layout-w1024dp/fragment_movie.xml
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rootLayoutMovie"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.movies.MovieDetailsFragment"
tools:ignore="RtlHardcoded">

<!-- Parent used for fullscreen color background. -->
Expand All @@ -23,13 +22,11 @@
android:layout_height="wrap_content"
android:layout_gravity="center" />

<!-- Padding is adjusted in code based on translucent status bar. -->
<androidx.core.widget.NestedScrollView
android:id="@+id/contentContainerMovie"
android:layout_width="740dp"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingTop="?attr/actionBarSize">
android:clipToPadding="false">

<LinearLayout
android:layout_width="match_parent"
Expand All @@ -41,8 +38,8 @@
android:layout_width="370dp"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:paddingBottom="@dimen/default_padding"
android:paddingTop="@dimen/default_padding">
android:paddingTop="@dimen/large_padding"
android:paddingBottom="@dimen/large_padding">

<!-- Wrap in container to support reeeeally long movie titles. -->
<RelativeLayout
Expand All @@ -55,9 +52,9 @@
style="?attr/materialCardViewFilledStyle"
android:layout_width="@dimen/movie_poster_width_large"
android:layout_height="@dimen/movie_poster_height_large"
android:layout_marginBottom="@dimen/default_padding"
android:layout_marginLeft="@dimen/large_padding"
android:layout_marginRight="@dimen/default_padding"
android:layout_marginBottom="@dimen/default_padding"
android:foreground="?attr/selectableItemBackground">

<ImageView
Expand All @@ -66,8 +63,7 @@
android:layout_height="match_parent"
android:contentDescription="@null"
android:scaleType="centerCrop"
tools:src="#F44336"
tools:targetApi="lollipop" />
tools:src="#F44336" />

</com.google.android.material.card.MaterialCardView>

Expand All @@ -76,8 +72,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/default_padding"
android:layout_marginRight="@dimen/large_padding"
android:layout_marginTop="@dimen/inline_padding"
android:layout_marginRight="@dimen/large_padding"
android:layout_toRightOf="@id/frameLayoutMoviePoster"
android:background="?attr/selectableItemBackground"
android:focusable="true"
Expand Down Expand Up @@ -141,7 +137,9 @@

<RelativeLayout
android:layout_width="370dp"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:paddingTop="@dimen/large_padding"
android:paddingBottom="@dimen/large_padding">

<Button
android:id="@+id/buttonMovieLanguage"
Expand Down Expand Up @@ -208,10 +206,10 @@
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="@id/textMovieLastUpdated"
android:layout_marginBottom="@dimen/default_padding"
android:layout_marginLeft="@dimen/large_padding"
android:layout_marginRight="@dimen/large_padding"
android:layout_marginTop="@dimen/large_padding"
android:layout_marginRight="@dimen/large_padding"
android:layout_marginBottom="@dimen/default_padding"
android:background="?attr/sgColorDivider" />

<Button
Expand All @@ -229,10 +227,10 @@
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="@+id/buttonMovieComments"
android:layout_marginBottom="@dimen/default_padding"
android:layout_marginLeft="72dp"
android:layout_marginRight="@dimen/large_padding"
android:layout_marginTop="@dimen/default_padding"
android:layout_marginRight="@dimen/large_padding"
android:layout_marginBottom="@dimen/default_padding"
android:background="?attr/sgColorDivider" />

<LinearLayout
Expand All @@ -248,23 +246,21 @@

</androidx.core.widget.NestedScrollView>

<!-- Padding is adjusted in code based on translucent status bar. -->
<androidx.core.widget.NestedScrollView
android:id="@+id/contentContainerMovieRight"
android:layout_width="230dp"
android:layout_height="match_parent"
android:layout_marginLeft="740dp"
android:clipToPadding="false"
android:paddingTop="?attr/actionBarSize"
tools:ignore="InconsistentLayout">

<include
android:id="@+id/moviePeople"
layout="@layout/cast_and_crew"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/default_padding"
android:layout_marginBottom="@dimen/default_padding" />
android:layout_marginTop="@dimen/large_padding"
android:layout_marginBottom="@dimen/large_padding" />

</androidx.core.widget.NestedScrollView>

Expand Down
Loading