Added support for landscape mode.

This commit is contained in:
Antoine POPINEAU 2019-11-05 21:23:29 +01:00
parent cac32332e0
commit 0cb4bda212
No known key found for this signature in database
GPG Key ID: A78AC64694F84063
13 changed files with 809 additions and 71 deletions

View File

@ -13,7 +13,6 @@
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:screenOrientation="portrait"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
@ -35,6 +34,7 @@
<activity <activity
android:name="com.github.apognu.otter.activities.LoginActivity" android:name="com.github.apognu.otter.activities.LoginActivity"
android:configChanges="screenSize|orientation"
android:launchMode="singleInstance" /> android:launchMode="singleInstance" />
<activity android:name="com.github.apognu.otter.activities.MainActivity" /> <activity android:name="com.github.apognu.otter.activities.MainActivity" />
<activity <activity

View File

@ -5,19 +5,21 @@ import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.content.res.Configuration
import android.graphics.Bitmap
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.util.DisplayMetrics
import android.view.MenuItem import android.view.*
import android.view.View
import android.view.ViewGroup
import android.view.animation.AccelerateDecelerateInterpolator import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.SeekBar import android.widget.SeekBar
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.graphics.drawable.toDrawable
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import com.github.apognu.otter.R import com.github.apognu.otter.R
import com.github.apognu.otter.fragments.BrowseFragment import com.github.apognu.otter.fragments.BrowseFragment
import com.github.apognu.otter.fragments.LandscapeQueueFragment
import com.github.apognu.otter.fragments.QueueFragment import com.github.apognu.otter.fragments.QueueFragment
import com.github.apognu.otter.playback.MediaControlsManager import com.github.apognu.otter.playback.MediaControlsManager
import com.github.apognu.otter.playback.PlayerService import com.github.apognu.otter.playback.PlayerService
@ -34,6 +36,7 @@ import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
enum class ResultCode(val code: Int) { enum class ResultCode(val code: Int) {
@ -101,6 +104,10 @@ class MainActivity : AppCompatActivity() {
} }
} }
}) })
landscape_queue?.let {
supportFragmentManager.beginTransaction().replace(R.id.landscape_queue, LandscapeQueueFragment()).commit()
}
} }
override fun onBackPressed() { override fun onBackPressed() {
@ -155,6 +162,10 @@ class MainActivity : AppCompatActivity() {
} }
} }
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
}
private fun launchFragment(fragment: Fragment) { private fun launchFragment(fragment: Fragment) {
supportFragmentManager.fragments.lastOrNull()?.also { oldFragment -> supportFragmentManager.fragments.lastOrNull()?.also { oldFragment ->
oldFragment.enterTransition = null oldFragment.enterTransition = null
@ -206,6 +217,12 @@ class MainActivity : AppCompatActivity() {
it.bottomMargin = it.bottomMargin / 2 it.bottomMargin = it.bottomMargin / 2
} }
landscape_queue?.let { landscape_queue ->
(landscape_queue.layoutParams as? ViewGroup.MarginLayoutParams)?.let {
it.bottomMargin = it.bottomMargin / 2
}
}
now_playing.animate() now_playing.animate()
.alpha(0.0f) .alpha(0.0f)
.setDuration(400) .setDuration(400)
@ -233,6 +250,12 @@ class MainActivity : AppCompatActivity() {
(container.layoutParams as? ViewGroup.MarginLayoutParams)?.let { (container.layoutParams as? ViewGroup.MarginLayoutParams)?.let {
it.bottomMargin = it.bottomMargin * 2 it.bottomMargin = it.bottomMargin * 2
} }
landscape_queue?.let { landscape_queue ->
(landscape_queue.layoutParams as? ViewGroup.MarginLayoutParams)?.let {
it.bottomMargin = it.bottomMargin * 2
}
}
} }
now_playing_title.text = track.title now_playing_title.text = track.title
@ -251,33 +274,60 @@ class MainActivity : AppCompatActivity() {
.centerCrop() .centerCrop()
.into(now_playing_cover) .into(now_playing_cover)
Picasso.get() now_playing_details_cover?.let { now_playing_details_cover ->
.maybeLoad(maybeNormalizeUrl(track.album.cover.original)) Picasso.get()
.fit() .maybeLoad(maybeNormalizeUrl(track.album.cover.original))
.centerCrop() .fit()
.into(now_playing_details_cover) .centerCrop()
.into(now_playing_details_cover)
}
favoriteCheckRepository.fetch().untilNetwork(IO) { favorites, _, _ -> if (now_playing_details_cover == null) {
GlobalScope.launch(Main) { GlobalScope.launch(IO) {
track.favorite = favorites.contains(track.id) val width = DisplayMetrics().apply {
windowManager.defaultDisplay.getMetrics(this)
}.widthPixels
when (track.favorite) { val backgroundCover = Picasso.get()
true -> now_playing_details_favorite.setColorFilter(getColor(R.color.colorFavorite)) .maybeLoad(maybeNormalizeUrl(track.album.cover.original))
false -> now_playing_details_favorite.setColorFilter(getColor(R.color.controlForeground)) .get()
.run { Bitmap.createScaledBitmap(this, width, width, false).toDrawable(resources) }
.apply {
alpha = 20
gravity = Gravity.CENTER
}
withContext(Main) {
now_playing_details.background = backgroundCover
} }
} }
} }
now_playing_details_favorite.setOnClickListener { now_playing_details_favorite?.let { now_playing_details_favorite ->
when (track.favorite) { favoriteCheckRepository.fetch().untilNetwork(IO) { favorites, _, _ ->
true -> { GlobalScope.launch(Main) {
favoriteRepository.deleteFavorite(track.id) track.favorite = favorites.contains(track.id)
now_playing_details_favorite.setColorFilter(getColor(R.color.controlForeground))
}
false -> { when (track.favorite) {
favoriteRepository.addFavorite(track.id) true -> now_playing_details_favorite.setColorFilter(getColor(R.color.colorFavorite))
now_playing_details_favorite.setColorFilter(getColor(R.color.colorFavorite)) false -> now_playing_details_favorite.setColorFilter(getColor(R.color.controlForeground))
}
}
}
}
now_playing_details_favorite?.let { now_playing_details_favorite ->
now_playing_details_favorite.setOnClickListener {
when (track.favorite) {
true -> {
favoriteRepository.deleteFavorite(track.id)
now_playing_details_favorite.setColorFilter(getColor(R.color.controlForeground))
}
false -> {
favoriteRepository.addFavorite(track.id)
now_playing_details_favorite.setColorFilter(getColor(R.color.colorFavorite))
}
} }
} }

View File

@ -1,8 +1,12 @@
package com.github.apognu.otter.fragments package com.github.apognu.otter.fragments
import android.graphics.Bitmap
import android.os.Bundle import android.os.Bundle
import android.util.DisplayMetrics
import android.view.Gravity
import android.view.View import android.view.View
import android.view.animation.AccelerateDecelerateInterpolator import android.view.animation.AccelerateDecelerateInterpolator
import androidx.core.graphics.drawable.toDrawable
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.transition.Fade import androidx.transition.Fade
@ -14,6 +18,12 @@ import com.github.apognu.otter.repositories.AlbumsRepository
import com.github.apognu.otter.utils.* import com.github.apognu.otter.utils.*
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.fragment_albums.* import kotlinx.android.synthetic.main.fragment_albums.*
import kotlinx.android.synthetic.main.partial_now_playing.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.math.min
class AlbumsFragment : FunkwhaleFragment<Album, AlbumsAdapter>() { class AlbumsFragment : FunkwhaleFragment<Album, AlbumsAdapter>() {
override val viewRes = R.layout.fragment_albums override val viewRes = R.layout.fragment_albums
@ -51,12 +61,38 @@ class AlbumsFragment : FunkwhaleFragment<Album, AlbumsAdapter>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
Picasso.get() cover?.let { cover ->
.maybeLoad(maybeNormalizeUrl(artistArt)) Picasso.get()
.noFade() .maybeLoad(maybeNormalizeUrl(artistArt))
.fit() .noFade()
.centerCrop() .fit()
.into(cover) .centerCrop()
.into(cover)
}
cover_background?.let {
activity?.let { activity ->
GlobalScope.launch(Dispatchers.IO) {
val width = DisplayMetrics().apply {
activity.windowManager.defaultDisplay.getMetrics(this)
}.widthPixels
val backgroundCover = Picasso.get()
.maybeLoad(maybeNormalizeUrl(artistArt))
.get()
.run { Bitmap.createScaledBitmap(this, width, width, false) }
.run { Bitmap.createBitmap(this, 0, 0, width, cover_background.height).toDrawable(resources) }
.apply {
alpha = 20
gravity = Gravity.CENTER
}
withContext(Dispatchers.Main) {
cover_background.background = backgroundCover
}
}
}
}
artist.text = artistName artist.text = artistName
} }

View File

@ -0,0 +1,75 @@
package com.github.apognu.otter.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.apognu.otter.R
import com.github.apognu.otter.adapters.TracksAdapter
import com.github.apognu.otter.utils.*
import kotlinx.android.synthetic.main.partial_queue.*
import kotlinx.android.synthetic.main.partial_queue.view.*
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
class LandscapeQueueFragment : Fragment() {
private var adapter: TracksAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
watchEventBus()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.partial_queue, container, false).apply {
adapter = TracksAdapter(context, fromQueue = true).also {
queue.layoutManager = LinearLayoutManager(context)
queue.adapter = it
}
}
}
override fun onResume() {
super.onResume()
queue?.visibility = View.GONE
placeholder?.visibility = View.VISIBLE
refresh()
}
private fun refresh() {
GlobalScope.launch(Main) {
RequestBus.send(Request.GetQueue).wait<Response.Queue>()?.let { response ->
adapter?.let {
it.data = response.queue.toMutableList()
it.notifyDataSetChanged()
if (it.data.isEmpty()) {
queue?.visibility = View.GONE
placeholder?.visibility = View.VISIBLE
} else {
queue?.visibility = View.VISIBLE
placeholder?.visibility = View.GONE
}
}
}
}
}
private fun watchEventBus() {
GlobalScope.launch(Main) {
EventBus.get().collect { message ->
when (message) {
is Event.TrackPlayed -> refresh()
is Event.QueueChanged -> refresh()
}
}
}
}
}

View File

@ -15,6 +15,8 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kotlinx.android.synthetic.main.fragment_queue.* import kotlinx.android.synthetic.main.fragment_queue.*
import kotlinx.android.synthetic.main.fragment_queue.view.* import kotlinx.android.synthetic.main.fragment_queue.view.*
import kotlinx.android.synthetic.main.partial_queue.*
import kotlinx.android.synthetic.main.partial_queue.view.*
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
@ -50,6 +52,10 @@ class QueueFragment : BottomSheetDialogFragment() {
adapter = TracksAdapter(context, FavoriteListener(), fromQueue = true).also { adapter = TracksAdapter(context, FavoriteListener(), fromQueue = true).also {
queue.layoutManager = LinearLayoutManager(context) queue.layoutManager = LinearLayoutManager(context)
queue.adapter = it queue.adapter = it
adapter = TracksAdapter(context, fromQueue = true).also {
included.queue.layoutManager = LinearLayoutManager(context)
included.queue.adapter = it
}
} }
} }
} }
@ -57,7 +63,7 @@ class QueueFragment : BottomSheetDialogFragment() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
queue?.visibility = View.GONE included.queue?.visibility = View.GONE
placeholder?.visibility = View.VISIBLE placeholder?.visibility = View.VISIBLE
refresh() refresh()
@ -66,16 +72,18 @@ class QueueFragment : BottomSheetDialogFragment() {
private fun refresh() { private fun refresh() {
GlobalScope.launch(Main) { GlobalScope.launch(Main) {
RequestBus.send(Request.GetQueue).wait<Response.Queue>()?.let { response -> RequestBus.send(Request.GetQueue).wait<Response.Queue>()?.let { response ->
adapter?.let { included?.let {
it.data = response.queue.toMutableList() adapter?.let {
it.notifyDataSetChanged() it.data = response.queue.toMutableList()
it.notifyDataSetChanged()
if (it.data.isEmpty()) { if (it.data.isEmpty()) {
queue?.visibility = View.GONE included.queue?.visibility = View.GONE
placeholder?.visibility = View.VISIBLE placeholder?.visibility = View.VISIBLE
} else { } else {
queue?.visibility = View.VISIBLE included.queue?.visibility = View.VISIBLE
placeholder?.visibility = View.GONE placeholder?.visibility = View.GONE
}
} }
} }
} }

View File

@ -25,8 +25,6 @@ object AppContext {
fun init(context: Activity) { fun init(context: Activity) {
setupNotificationChannels(context) setupNotificationChannels(context)
context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
// CastContext.getSharedInstance(context) // CastContext.getSharedInstance(context)
FuelManager.instance.addResponseInterceptor { next -> FuelManager.instance.addResponseInterceptor { next ->

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginBottom="?attr/actionBarSize"
android:layout_weight="1"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<FrameLayout
android:id="@+id/landscape_queue"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginBottom="?attr/actionBarSize"
android:layout_weight="1"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</LinearLayout>
<com.github.apognu.otter.views.NowPlayingView
android:id="@+id/now_playing"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="bottom"
android:layout_margin="8dp"
android:alpha="0"
android:visibility="gone"
app:cardCornerRadius="8dp"
app:cardElevation="12dp"
app:layout_dodgeInsetEdges="bottom"
tools:alpha="1"
tools:visibility="visible">
<include layout="@layout/partial_now_playing" />
</com.github.apognu.otter.views.NowPlayingView>
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:theme="@style/AppTheme.AppBar"
app:backgroundTint="@color/colorPrimary"
app:layout_insetEdge="bottom"
app:navigationIcon="@drawable/ottericon"
tools:menu="@menu/toolbar" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swiper"
style="@style/AppTheme.Fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
android:clipChildren="false"
android:clipToPadding="false">
<androidx.core.widget.NestedScrollView
android:id="@+id/scroller"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
android:elevation="1dp">
<LinearLayout
android:id="@+id/cover_background"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:text="@string/albums"
android:textAllCaps="true"
android:textSize="14sp" />
<TextView
android:id="@+id/artist"
style="@style/AppTheme.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
tools:text="Muse" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/albums"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
tools:itemCount="10"
tools:listitem="@layout/row_album" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@ -0,0 +1,209 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swiper"
style="@style/AppTheme.Fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:transitionGroup="true">
<androidx.core.widget.NestedScrollView
android:id="@+id/scroller"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
android:elevation="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/cover"
android:layout_width="match_parent"
android:layout_height="100dp"
android:contentDescription="@string/alt_album_cover"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0"
tools:src="@tools:sample/avatars"
tools:visibility="invisible" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/covers"
android:layout_width="match_parent"
android:layout_height="250dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0"
tools:visibility="visible">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent=".50" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent=".50" />
<com.github.apognu.otter.views.SquareImageView
android:id="@+id/cover_top_left"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
android:src="@drawable/cover"
app:layout_constraintBottom_toBottomOf="@id/vertical"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="@id/horizontal"
app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/avatars" />
<com.github.apognu.otter.views.SquareImageView
android:id="@+id/cover_top_right"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
android:src="@drawable/cover"
app:layout_constraintBottom_toBottomOf="@id/vertical"
app:layout_constraintLeft_toLeftOf="@id/horizontal"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/avatars" />
<com.github.apognu.otter.views.SquareImageView
android:id="@+id/cover_bottom_left"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
android:src="@drawable/cover"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="@id/horizontal"
app:layout_constraintTop_toTopOf="@id/vertical"
tools:src="@tools:sample/avatars" />
<com.github.apognu.otter.views.SquareImageView
android:id="@+id/cover_bottom_right"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
android:src="@drawable/cover"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="@id/horizontal"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/vertical"
tools:src="@tools:sample/avatars" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/colorPrimary"
android:elevation="10dp"
android:text="@string/playback_shuffle"
android:textColor="@android:color/white"
app:icon="@drawable/play"
app:iconTint="@android:color/white"
app:layout_constraintBottom_toBottomOf="@id/cover"
app:layout_constraintLeft_toLeftOf="@id/cover"
app:layout_constraintRight_toRightOf="@id/cover"
app:layout_constraintTop_toBottomOf="@id/cover" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/artist"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:textAllCaps="true"
android:textSize="14sp"
tools:text="Muse" />
<TextView
android:id="@+id/title"
style="@style/AppTheme.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
tools:text="Absolution" />
</LinearLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/queue"
style="@style/AppTheme.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:text="@string/playback_queue"
app:icon="@drawable/add" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/tracks"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:itemCount="10"
tools:listitem="@layout/row_track" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@ -0,0 +1,193 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/now_playing_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/summary"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:orientation="vertical">
<ProgressBar
android:id="@+id/now_playing_progress"
style="@android:style/Widget.Material.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-6dp"
android:layout_marginBottom="-6dp"
android:progress="40"
android:progressTint="@color/colorPrimary" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<FrameLayout
android:layout_width="?attr/actionBarSize"
android:layout_height="?attr/actionBarSize"
android:layout_marginEnd="16dp">
<com.github.apognu.otter.views.SquareImageView
android:id="@+id/now_playing_cover"
android:layout_width="?attr/actionBarSize"
android:layout_height="?attr/actionBarSize"
tools:src="@tools:sample/avatars" />
<ProgressBar
android:id="@+id/now_playing_buffering"
android:layout_width="?attr/actionBarSize"
android:layout_height="?attr/actionBarSize"
android:indeterminate="true"
android:indeterminateTint="@color/controlForeground"
android:visibility="gone" />
</FrameLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="2"
android:orientation="vertical">
<TextView
android:id="@+id/now_playing_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/itemTitle"
tools:text="Supermassive Black Hole" />
<TextView
android:id="@+id/now_playing_album"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Muse" />
</LinearLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/now_playing_toggle"
style="@style/AppTheme.OutlinedButton"
android:layout_width="?attr/actionBarSize"
android:layout_height="match_parent"
app:icon="@drawable/play" />
<ImageButton
android:id="@+id/now_playing_next"
style="@style/IconButton"
android:layout_width="?attr/actionBarSize"
android:layout_height="match_parent"
android:contentDescription="@string/control_next"
android:src="@drawable/next" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/now_playing_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/now_playing_details_controls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:orientation="vertical"
android:paddingTop="32dp">
<TextView
android:id="@+id/now_playing_details_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/itemTitle"
android:textSize="18sp"
tools:text="Supermassive Black Hole" />
<TextView
android:id="@+id/now_playing_details_artist"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Muse" />
<SeekBar
android:id="@+id/now_playing_details_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:max="100"
android:progressBackgroundTint="#cacaca"
android:progressTint="@color/controlForeground"
android:thumbTint="@color/controlForeground" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<TextView
android:id="@+id/now_playing_details_progress_current"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView
android:id="@+id/now_playing_details_progress_duration"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAlignment="textEnd" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_marginBottom="16dp"
android:gravity="center"
android:orientation="horizontal">
<ImageButton
android:id="@+id/now_playing_details_previous"
style="@style/IconButton"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginEnd="16dp"
android:contentDescription="@string/control_previous"
android:src="@drawable/previous" />
<com.google.android.material.button.MaterialButton
android:id="@+id/now_playing_details_toggle"
style="@style/AppTheme.OutlinedButton"
android:layout_width="64dp"
android:layout_height="64dp"
app:cornerRadius="64dp"
app:icon="@drawable/play"
app:iconSize="32dp" />
<ImageButton
android:id="@+id/now_playing_details_next"
style="@style/IconButton"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="16dp"
android:contentDescription="@string/control_next"
android:src="@drawable/next" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
@ -14,33 +13,9 @@
app:cardCornerRadius="16dp" app:cardCornerRadius="16dp"
app:cardElevation="4dp"> app:cardElevation="4dp">
<FrameLayout <include
android:layout_width="match_parent" android:id="@+id/included"
android:layout_height="wrap_content"> layout="@layout/partial_queue" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/queue"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:itemCount="10"
tools:listitem="@layout/row_track" />
<TextView
android:id="@+id/placeholder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="64dp"
android:layout_marginBottom="64dp"
android:drawableTop="@drawable/ottericon"
android:drawablePadding="16dp"
android:drawableTint="#525252"
android:text="@string/playback_queue_empty"
android:textAlignment="center"
android:visibility="gone"
tools:visibility="visible" />
</FrameLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>

View File

@ -0,0 +1,29 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@layout/fragment_queue">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/queue"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:itemCount="10"
tools:listitem="@layout/row_track" />
<TextView
android:id="@+id/placeholder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="64dp"
android:layout_marginBottom="64dp"
android:drawableTop="@drawable/ottericon"
android:drawablePadding="16dp"
android:drawableTint="#525252"
android:text="@string/playback_queue_empty"
android:textAlignment="center"
android:visibility="gone"
tools:visibility="visible" />
</FrameLayout>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/cast"
android:iconTint="@android:color/white"
android:title="@string/toolbar_cast"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="ifRoom" />
<item
android:id="@+id/nav_search"
android:icon="@drawable/search"
android:title="@string/toolbar_search"
app:showAsAction="ifRoom" />
<item
android:id="@+id/settings"
android:icon="@drawable/settings"
android:iconTint="@android:color/white"
android:title="@string/title_settings"
app:showAsAction="never" />
</menu>