widgets: add 1x3/1x4 widget

Add a 1x3/1x4 widget that displays the cover and controls

Also requires another widget type that just displays controls to
accomodate landscape devices.

Resolves #420.
This commit is contained in:
Alexander Capehart 2024-01-15 20:47:21 -07:00
parent 195498879a
commit 881df0fc02
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
19 changed files with 451 additions and 151 deletions

View file

@ -6,6 +6,7 @@
- Gapless playback is now used whenever possible
- Added "Remember pause" setting that makes remain paused when skipping
or editing queue
- Added 1x4 and 1x3 widget forms
#### What's Improved
- The playback state is now saved more often, improving persistence

View file

@ -167,6 +167,7 @@ constructor(
*
* @param song [Queue.currentSong]
* @param cover A pre-loaded album cover [Bitmap] for [song].
* @param cover A pre-loaded album cover [Bitmap] for [song], with rounded corners.
* @param isPlaying [PlaybackStateManager.playerState]
* @param repeatMode [PlaybackStateManager.repeatMode]
* @param isShuffled [Queue.isShuffled]

View file

@ -91,11 +91,14 @@ class WidgetProvider : AppWidgetProvider() {
// the widget elements, plus some leeway for text sizing.
val views =
mapOf(
SizeF(180f, 100f) to newThinLayout(context, uiSettings, state),
SizeF(180f, 152f) to newSmallLayout(context, uiSettings, state),
SizeF(272f, 152f) to newWideLayout(context, uiSettings, state),
SizeF(180f, 272f) to newMediumLayout(context, uiSettings, state),
SizeF(272f, 272f) to newLargeLayout(context, uiSettings, state))
SizeF(180f, 48f) to newThinStickLayout(context, state),
SizeF(304f, 48f) to newWideStickLayout(context, state),
SizeF(180f, 100f) to newThinWaferLayout(context, uiSettings, state),
SizeF(304f, 100f) to newWideWaferLayout(context, uiSettings, state),
SizeF(180f, 152f) to newThinDockedLayout(context, uiSettings, state),
SizeF(304f, 152f) to newWideDockedLayout(context, uiSettings, state),
SizeF(180f, 272f) to newThinPaneLayout(context, uiSettings, state),
SizeF(304f, 272f) to newWidePaneLayout(context, uiSettings, state))
// Manually update AppWidgetManager with the new views.
val awm = AppWidgetManager.getInstance(context)
@ -139,60 +142,78 @@ class WidgetProvider : AppWidgetProvider() {
private fun newDefaultLayout(context: Context) =
newRemoteViews(context, R.layout.widget_default)
private fun newThinLayout(
private fun newThinStickLayout(context: Context, state: WidgetComponent.PlaybackState) =
newRemoteViews(context, R.layout.widget_stick_thin).setupTimelineControls(context, state)
private fun newWideStickLayout(context: Context, state: WidgetComponent.PlaybackState) =
newRemoteViews(context, R.layout.widget_stick_wide).setupFullControls(context, state)
private fun newThinWaferLayout(
context: Context,
uiSettings: UISettings,
state: WidgetComponent.PlaybackState
) =
newRemoteViews(context, R.layout.widget_thin)
newRemoteViews(context, R.layout.widget_wafer_thin)
.setupBackground(
uiSettings,
)
.setupPlaybackState(context, state)
.setupCover(context, state.takeIf { canDisplayWaferCover(uiSettings) })
.setupTimelineControls(context, state)
private fun newSmallLayout(
private fun newWideWaferLayout(
context: Context,
uiSettings: UISettings,
state: WidgetComponent.PlaybackState
) =
newRemoteViews(context, R.layout.widget_small)
newRemoteViews(context, R.layout.widget_wafer_wide)
.setupBackground(
uiSettings,
)
.setupCover(context, state.takeIf { canDisplayWaferCover(uiSettings) })
.setupFullControls(context, state)
private fun newThinDockedLayout(
context: Context,
uiSettings: UISettings,
state: WidgetComponent.PlaybackState
) =
newRemoteViews(context, R.layout.widget_docked_thin)
.setupBar(
uiSettings,
)
.setupCover(context, state)
.setupTimelineControls(context, state)
private fun newMediumLayout(
private fun newWideDockedLayout(
context: Context,
uiSettings: UISettings,
state: WidgetComponent.PlaybackState
) =
newRemoteViews(context, R.layout.widget_medium)
.setupBackground(
uiSettings,
)
.setupPlaybackState(context, state)
.setupTimelineControls(context, state)
private fun newWideLayout(
context: Context,
uiSettings: UISettings,
state: WidgetComponent.PlaybackState
) =
newRemoteViews(context, R.layout.widget_wide)
newRemoteViews(context, R.layout.widget_docked_wide)
.setupBar(
uiSettings,
)
.setupCover(context, state)
.setupFullControls(context, state)
private fun newLargeLayout(
private fun newThinPaneLayout(
context: Context,
uiSettings: UISettings,
state: WidgetComponent.PlaybackState
) =
newRemoteViews(context, R.layout.widget_large)
newRemoteViews(context, R.layout.widget_pane_thin)
.setupBackground(
uiSettings,
)
.setupPlaybackState(context, state)
.setupTimelineControls(context, state)
private fun newWidePaneLayout(
context: Context,
uiSettings: UISettings,
state: WidgetComponent.PlaybackState
) =
newRemoteViews(context, R.layout.widget_pane_wide)
.setupBackground(
uiSettings,
)
@ -246,8 +267,14 @@ class WidgetProvider : AppWidgetProvider() {
*/
private fun RemoteViews.setupCover(
context: Context,
state: WidgetComponent.PlaybackState
state: WidgetComponent.PlaybackState?
): RemoteViews {
if (state == null) {
setImageViewBitmap(R.id.widget_cover, null)
setContentDescription(R.id.widget_cover, null)
return this
}
if (state.cover != null) {
setImageViewBitmap(R.id.widget_cover, state.cover)
setContentDescription(
@ -388,6 +415,18 @@ class WidgetProvider : AppWidgetProvider() {
return this
}
private fun useRoundedRemoteViews(uiSettings: UISettings) =
uiSettings.roundMode || Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
private fun canDisplayWaferCover(uiSettings: UISettings) =
// We cannot display album covers in the wafer-style widget when round mode is enabled
// below Android 12, as:
// - We cannot rely on system widget corner clipping, like on Android 12+
// - We cannot manually clip the widget ourselves due to broken clipToOutline support
// - We cannot determine the exact widget height that would allow us to clip the loaded
// image itself
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S || !uiSettings.roundMode
companion object {
/**
* Broadcast when [WidgetProvider] desires to update it's widget with new information.

View file

@ -28,7 +28,6 @@ import androidx.annotation.DrawableRes
import androidx.annotation.IdRes
import androidx.annotation.LayoutRes
import kotlin.math.sqrt
import org.oxycblt.auxio.ui.UISettings
import org.oxycblt.auxio.util.isLandscape
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.newMainPendingIntent
@ -139,13 +138,3 @@ fun AppWidgetManager.updateAppWidgetCompat(
}
}
}
/**
* Returns whether rounded UI elements are appropriate for the widget, either based on the current
* settings or if the widget has to fit in aesthetically with other widgets.
*
* @param [uiSettings] [UISettings] required to obtain round mode configuration.
* @return true if to use round mode, false otherwise.
*/
fun useRoundedRemoteViews(uiSettings: UISettings) =
uiSettings.roundMode || Build.VERSION.SDK_INT >= Build.VERSION_CODES.S

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?attr/colorSurface" />
<corners android:radius="@android:dimen/system_app_widget_background_radius" />
</shape>

View file

@ -6,8 +6,15 @@
android:viewportHeight="24">
<path
android:fillColor="?attr/colorSurfaceInverse"
android:pathData="M12,16.5Q13.875,16.5 15.188,15.188Q16.5,13.875 16.5,12Q16.5,10.125 15.188,8.812Q13.875,7.5 12,7.5Q10.125,7.5 8.812,8.812Q7.5,10.125 7.5,12Q7.5,13.875 8.812,15.188Q10.125,16.5 12,16.5ZM12,13Q11.575,13 11.288,12.712Q11,12.425 11,12Q11,11.575 11.288,11.287Q11.575,11 12,11Q12.425,11 12.713,11.287Q13,11.575 13,12Q13,12.425 12.713,12.712Q12.425,13 12,13ZM12,22Q9.925,22 8.1,21.212Q6.275,20.425 4.925,19.075Q3.575,17.725 2.788,15.9Q2,14.075 2,12Q2,9.925 2.788,8.1Q3.575,6.275 4.925,4.925Q6.275,3.575 8.1,2.787Q9.925,2 12,2Q14.075,2 15.9,2.787Q17.725,3.575 19.075,4.925Q20.425,6.275 21.212,8.1Q22,9.925 22,12Q22,14.075 21.212,15.9Q20.425,17.725 19.075,19.075Q17.725,20.425 15.9,21.212Q14.075,22 12,22ZM12,20Q15.35,20 17.675,17.675Q20,15.35 20,12Q20,8.65 17.675,6.325Q15.35,4 12,4Q8.65,4 6.325,6.325Q4,8.65 4,12Q4,15.35 6.325,17.675Q8.65,20 12,20ZM12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Z" />
<path
android:fillColor="?attr/colorOnSurfaceInverse"
android:pathData="M 11.999784 1.9998779 A 10 9.999999 0 0 1 22.000208 11.999784 C 22.000208 10.616452 21.737475 9.3164294 21.212142 8.099764 C 20.687476 6.8830985 19.974804 5.8247631 19.074805 4.924764 C 18.174806 4.0247649 17.11647 3.3122428 15.899805 2.78691 C 14.683139 2.2622439 13.383116 1.9998779 11.999784 1.9998779 z M 11.999784 1.9998779 C 10.616452 1.9998779 9.3164294 2.2622439 8.099764 2.78691 C 6.8830985 3.3122428 5.8247631 4.0247649 4.924764 4.924764 C 4.0247649 5.8247631 3.3126097 6.8830985 2.7879435 8.099764 C 2.2626107 9.3164294 1.9998779 10.616452 1.9998779 11.999784 A 10 9.999999 0 0 1 11.999784 1.9998779 z M 1.9998779 11.999784 C 1.9998779 13.383116 2.2626107 14.683139 2.7879435 15.899805 C 3.3126097 17.11647 4.0247649 18.174806 4.924764 19.074805 C 5.8247631 19.974804 6.8830985 20.687476 8.099764 21.212142 C 9.3164294 21.737475 10.616452 22.000208 11.999784 22.000208 A 10 9.999999 0 0 1 1.9998779 11.999784 z M 11.999784 22.000208 C 13.383116 22.000208 14.683139 21.737475 15.899805 21.212142 C 17.11647 20.687476 18.174806 19.974804 19.074805 19.074805 C 19.974804 18.174806 20.687476 17.11647 21.212142 15.899805 C 21.737475 14.683139 22.000208 13.383116 22.000208 11.999784 A 10 9.999999 0 0 1 11.999784 22.000208 z M 11.999784 3.9997559 C 9.7664532 3.9997559 7.8751938 4.7751969 6.3251953 6.3251953 C 4.7751969 7.8751938 3.9997559 9.7664532 3.9997559 11.999784 C 3.9997559 14.233115 4.7751969 16.124892 6.3251953 17.67489 C 7.8751938 19.224889 9.7664532 19.999813 11.999784 19.999813 C 14.233115 19.999813 16.124892 19.224889 17.67489 17.67489 C 19.224889 16.124892 19.999813 14.233115 19.999813 11.999784 C 19.999813 9.7664532 19.224889 7.8751938 17.67489 6.3251953 C 16.124892 4.7751969 14.233115 3.9997559 11.999784 3.9997559 z M 11.999784 7.4998006 C 13.249783 7.4998006 14.312888 7.9371994 15.18822 8.8118652 C 16.062886 9.6871977 16.499768 10.749786 16.499768 11.999784 C 16.499768 13.249783 16.062886 14.312888 15.18822 15.18822 C 14.312888 16.062886 13.249783 16.499768 11.999784 16.499768 C 10.749786 16.499768 9.6871977 16.062886 8.8118652 15.18822 C 7.9371994 14.312888 7.4998006 13.249783 7.4998006 11.999784 C 7.4998006 10.749786 7.9371994 9.6871977 8.8118652 8.8118652 C 9.6871977 7.9371994 10.749786 7.4998006 11.999784 7.4998006 z M 11.999784 10.999845 C 11.716451 10.999845 11.479533 11.095833 11.2882 11.287166 C 11.0962 11.479166 10.999845 11.716451 10.999845 11.999784 C 10.999845 12.283117 11.0962 12.520552 11.2882 12.711886 C 11.479533 12.903885 11.716451 13.00024 11.999784 13.00024 C 12.283117 13.00024 12.520919 12.903885 12.712919 12.711886 C 12.904252 12.520552 13.00024 12.283117 13.00024 11.999784 C 13.00024 11.716451 12.904252 11.479166 12.712919 11.287166 C 12.520919 11.095833 12.283117 10.999845 11.999784 10.999845 z " />
android:pathData="M 2.6000008,9.3143836e-7 H 21.399999 c 1.4404,0 2.6,1.15959996856164 2.6,2.59999986856164 V 21.399999 c 0,1.4404 -1.1596,2.6 -2.6,2.6 H 2.6000008 c -1.4403999,0 -2.59999986856164,-1.1596 -2.59999986856164,-2.6 V 2.6000008 C 9.3143836e-7,1.1596009 1.1596009,9.3143836e-7 2.6000008,9.3143836e-7 Z" />
<group
android:scaleX="0.5"
android:scaleY="0.5"
android:translateX="6"
android:translateY="6">
<path
android:fillColor="@android:color/white"
android:pathData="M10,21Q8.35,21 7.175,19.825Q6,18.65 6,17Q6,15.35 7.175,14.175Q8.35,13 10,13Q10.575,13 11.062,13.137Q11.55,13.275 12,13.55V3H18V7H14V17Q14,18.65 12.825,19.825Q11.65,21 10,21Z" />
</group>
</vector>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="?attr/colorSurface" />
</shape>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?attr/colorSurface" />
<corners android:radius="@dimen/spacing_mid_medium" />
</shape>

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@android:id/background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:orientation="horizontal"
android:theme="@style/Theme.Auxio.Widget">
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/ui_widget_rectangle_button_bg">
<android.widget.ImageButton
android:id="@+id/widget_skip_prev"
style="@style/Widget.Auxio.MaterialButton.AppWidget"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/desc_skip_prev"
android:src="@drawable/ic_skip_prev_24" />
</FrameLayout>
<android.widget.ImageButton
android:id="@+id/widget_play_pause"
style="@style/Widget.Auxio.MaterialButton.AppWidget.PlayPause"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:contentDescription="@string/desc_play_pause"
android:src="@drawable/ic_play_24" />
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/ui_widget_rectangle_button_bg">
<android.widget.ImageButton
android:id="@+id/widget_skip_next"
style="@style/Widget.Auxio.MaterialButton.AppWidget"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/desc_skip_next"
android:src="@drawable/ic_skip_next_24" />
</FrameLayout>
</LinearLayout>

View file

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@android:id/background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:orientation="horizontal"
android:theme="@style/Theme.Auxio.Widget">
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/ui_widget_rectangle_button_bg">
<android.widget.ImageButton
android:id="@+id/widget_repeat"
style="@style/Widget.Auxio.MaterialButton.AppWidget"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/desc_change_repeat"
android:src="@drawable/ic_repeat_off_24" />
</FrameLayout>
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/ui_widget_rectangle_button_bg">
<android.widget.ImageButton
android:id="@+id/widget_skip_prev"
style="@style/Widget.Auxio.MaterialButton.AppWidget"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/desc_skip_prev"
android:src="@drawable/ic_skip_prev_24" />
</FrameLayout>
<android.widget.ImageButton
android:id="@+id/widget_play_pause"
style="@style/Widget.Auxio.MaterialButton.AppWidget.PlayPause"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:contentDescription="@string/desc_play_pause"
android:src="@drawable/ic_play_24" />
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/ui_widget_rectangle_button_bg">
<android.widget.ImageButton
android:id="@+id/widget_skip_next"
style="@style/Widget.Auxio.MaterialButton.AppWidget"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/desc_skip_next"
android:src="@drawable/ic_skip_next_24" />
</FrameLayout>
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/ui_widget_rectangle_button_bg">
<android.widget.ImageButton
android:id="@+id/widget_shuffle"
style="@style/Widget.Auxio.MaterialButton.AppWidget"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/desc_shuffle"
android:src="@drawable/ic_shuffle_off_24" />
</FrameLayout>
</LinearLayout>

View file

@ -1,106 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@android:id/background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/ui_widget_bg_system"
android:backgroundTint="?attr/colorSurface"
android:baselineAligned="false"
android:orientation="horizontal"
android:theme="@style/Theme.Auxio.Widget">
<!--
Wrapping the 1:1 ImageView hack in a LinearLayout allows the view to measure greedily
without squishing the controls.
-->
<android.widget.RelativeLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<!--
See widget_small.xml for an explanation for the ImageView setup.
-->
<android.widget.ImageView
android:id="@+id/widget_aspect_ratio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="@drawable/ui_remote_aspect_ratio"
android:visibility="invisible"
tools:ignore="ContentDescription" />
<android.widget.ImageView
android:id="@+id/widget_cover"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_alignStart="@id/widget_aspect_ratio"
android:layout_alignTop="@id/widget_aspect_ratio"
android:layout_alignEnd="@id/widget_aspect_ratio"
android:layout_alignBottom="@id/widget_aspect_ratio"
android:src="@drawable/ic_remote_default_cover_24"
tools:ignore="ContentDescription" />
</android.widget.RelativeLayout>
<android.widget.LinearLayout
android:id="@+id/widget_panel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_medium"
android:layout_weight="2"
android:orientation="horizontal">
<android.widget.LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_weight="1"
android:orientation="vertical">
<android.widget.TextView
android:id="@+id/widget_song"
style="@style/Widget.Auxio.TextView.Primary.AppWidget"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Song name" />
<android.widget.TextView
android:id="@+id/widget_artist"
style="@style/Widget.Auxio.TextView.Secondary.AppWidget"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Artist name" />
</android.widget.LinearLayout>
<android.widget.ImageButton
android:id="@+id/widget_play_pause"
style="@style/Widget.Auxio.MaterialButton.AppWidget.PlayPause"
android:layout_width="@dimen/size_btn"
android:layout_height="@dimen/size_btn"
android:contentDescription="@string/desc_play_pause"
android:src="@drawable/ic_play_24" />
</android.widget.LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@android:id/background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/ui_widget_bg_system"
android:backgroundTint="?attr/colorSurface"
android:baselineAligned="false"
android:orientation="horizontal"
android:theme="@style/Theme.Auxio.Widget">
<!--
Wrapping the 1:1 ImageView hack in a LinearLayout allows the view to measure greedily
without squishing the controls.
-->
<android.widget.ImageView
android:id="@+id/widget_cover"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:ignore="ContentDescription" />
<android.widget.LinearLayout
android:id="@+id/widget_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="@dimen/spacing_mid_medium"
android:orientation="horizontal">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ui_widget_circle_button_bg">
<android.widget.ImageButton
android:id="@+id/widget_skip_prev"
style="@style/Widget.Auxio.MaterialButton.AppWidget"
android:layout_width="@dimen/size_btn"
android:layout_height="@dimen/size_btn"
android:contentDescription="@string/desc_skip_prev"
android:src="@drawable/ic_skip_prev_24" />
</FrameLayout>
<android.widget.ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<android.widget.ImageButton
android:id="@+id/widget_play_pause"
style="@style/Widget.Auxio.MaterialButton.AppWidget.PlayPause"
android:layout_width="@dimen/size_btn"
android:layout_height="@dimen/size_btn"
android:contentDescription="@string/desc_play_pause"
android:src="@drawable/ic_play_24" />
<android.widget.ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ui_widget_circle_button_bg">
<android.widget.ImageButton
android:id="@+id/widget_skip_next"
style="@style/Widget.Auxio.MaterialButton.AppWidget"
android:layout_width="@dimen/size_btn"
android:layout_height="@dimen/size_btn"
android:contentDescription="@string/desc_skip_next"
android:src="@drawable/ic_skip_next_24" />
</FrameLayout>
</android.widget.LinearLayout>
</FrameLayout>

View file

@ -0,0 +1,128 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@android:id/background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/ui_widget_bg_system"
android:backgroundTint="?attr/colorSurface"
android:baselineAligned="false"
android:orientation="horizontal"
android:theme="@style/Theme.Auxio.Widget">
<!--
Wrapping the 1:1 ImageView hack in a LinearLayout allows the view to measure greedily
without squishing the controls.
-->
<android.widget.ImageView
android:id="@+id/widget_cover"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:ignore="ContentDescription" />
<android.widget.LinearLayout
android:id="@+id/widget_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="@dimen/spacing_mid_medium"
android:orientation="horizontal">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ui_widget_circle_button_bg">
<android.widget.ImageButton
android:id="@+id/widget_repeat"
style="@style/Widget.Auxio.MaterialButton.AppWidget"
android:layout_width="@dimen/size_btn"
android:layout_height="@dimen/size_btn"
android:contentDescription="@string/desc_change_repeat"
android:src="@drawable/ic_repeat_off_24" />
</FrameLayout>
<android.widget.ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ui_widget_circle_button_bg">
<android.widget.ImageButton
android:id="@+id/widget_skip_prev"
style="@style/Widget.Auxio.MaterialButton.AppWidget"
android:layout_width="@dimen/size_btn"
android:layout_height="@dimen/size_btn"
android:contentDescription="@string/desc_skip_prev"
android:src="@drawable/ic_skip_prev_24" />
</FrameLayout>
<android.widget.ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<android.widget.ImageButton
android:id="@+id/widget_play_pause"
style="@style/Widget.Auxio.MaterialButton.AppWidget.PlayPause"
android:layout_width="@dimen/size_btn"
android:layout_height="@dimen/size_btn"
android:contentDescription="@string/desc_play_pause"
android:src="@drawable/ic_play_24" />
<android.widget.ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ui_widget_circle_button_bg">
<android.widget.ImageButton
android:id="@+id/widget_skip_next"
style="@style/Widget.Auxio.MaterialButton.AppWidget"
android:layout_width="@dimen/size_btn"
android:layout_height="@dimen/size_btn"
android:contentDescription="@string/desc_skip_next"
android:src="@drawable/ic_skip_next_24" />
</FrameLayout>
<android.widget.ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ui_widget_circle_button_bg">
<android.widget.ImageButton
android:id="@+id/widget_shuffle"
style="@style/Widget.Auxio.MaterialButton.AppWidget"
android:layout_width="@dimen/size_btn"
android:layout_height="@dimen/size_btn"
android:contentDescription="@string/desc_shuffle"
android:src="@drawable/ic_shuffle_off_24" />
</FrameLayout>
</android.widget.LinearLayout>
</FrameLayout>

View file

@ -4,10 +4,10 @@
android:initialLayout="@layout/widget_default"
android:minWidth="@dimen/widget_def_width"
android:minHeight="@dimen/widget_def_height"
android:minResizeHeight="0dp"
android:minResizeWidth="@dimen/widget_def_width"
android:minResizeHeight="@dimen/widget_def_height"
android:previewImage="@drawable/ui_widget_preview"
android:previewLayout="@layout/widget_small"
android:previewLayout="@layout/widget_docked_thin"
android:resizeMode="horizontal|vertical"
android:targetCellWidth="3"
android:targetCellHeight="2"

View file

@ -3,8 +3,8 @@
android:initialLayout="@layout/widget_default"
android:minWidth="@dimen/widget_def_width"
android:minHeight="@dimen/widget_def_height"
android:minResizeHeight="0dp"
android:minResizeWidth="@dimen/widget_def_width"
android:minResizeHeight="@dimen/widget_def_height"
android:previewImage="@drawable/ui_widget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="0"