widgets: re-add 2x2 widgets

Re-add 2x2 widgets. They were originally removed due to strange layouts
in landscape mode, but that has now been fixed with a new "tiny" layout
meant for that specific edge case. Also rename the widget forms to more
sensible names and make the small (previously minimal) widget be
text-only again.
This commit is contained in:
OxygenCobalt 2021-10-28 19:46:00 -06:00
parent df49e2765f
commit 4f4f6654c0
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
10 changed files with 150 additions and 101 deletions

View file

@ -43,7 +43,7 @@ private fun createViews(
private fun RemoteViews.applyMeta(context: Context, state: WidgetState) { private fun RemoteViews.applyMeta(context: Context, state: WidgetState) {
setTextViewText(R.id.widget_song, state.song.name) setTextViewText(R.id.widget_song, state.song.name)
setTextViewText(R.id.widget_artist, state.song.album.artist.name) setTextViewText(R.id.widget_artist, state.song.album.artist.resolvedName)
if (state.albumArt != null) { if (state.albumArt != null) {
setImageViewBitmap(R.id.widget_cover, state.albumArt) setImageViewBitmap(R.id.widget_cover, state.albumArt)
@ -92,15 +92,15 @@ fun createDefaultWidget(context: Context): RemoteViews {
return createViews(context, R.layout.widget_default) return createViews(context, R.layout.widget_default)
} }
fun createCompactWidget(context: Context, state: WidgetState): RemoteViews { fun createTinyWidget(context: Context, state: WidgetState): RemoteViews {
val views = createViews(context, R.layout.widget_compact) val views = createViews(context, R.layout.widget_tiny)
views.applyMeta(context, state) views.applyMeta(context, state)
views.applyControls(context, state) views.applyControls(context, state)
return views return views
} }
fun createMinimalWidget(context: Context, state: WidgetState): RemoteViews { fun createWideWidget(context: Context, state: WidgetState): RemoteViews {
val views = createViews(context, R.layout.widget_minimal) val views = createViews(context, R.layout.widget_wide)
views.applyMeta(context, state) views.applyMeta(context, state)
views.applyControls(context, state) views.applyControls(context, state)
return views return views
@ -113,8 +113,15 @@ fun createSmallWidget(context: Context, state: WidgetState): RemoteViews {
return views return views
} }
fun createFullWidget(context: Context, state: WidgetState): RemoteViews { fun createMediumWidget(context: Context, state: WidgetState): RemoteViews {
val views = createViews(context, R.layout.widget_full) val views = createViews(context, R.layout.widget_medium)
views.applyMeta(context, state)
views.applyControls(context, state)
return views
}
fun createLargeWidget(context: Context, state: WidgetState): RemoteViews {
val views = createViews(context, R.layout.widget_large)
views.applyMeta(context, state) views.applyMeta(context, state)
views.applyControls(context, state) views.applyControls(context, state)

View file

@ -46,10 +46,11 @@ import org.oxycblt.auxio.util.logD
* packing what could be considered multiple widgets into a single responsive widget. All types * packing what could be considered multiple widgets into a single responsive widget. All types
* are listed below: * are listed below:
* *
* - Full: Large widgets will show cover art and all controls * - Large widgets will show cover art and all controls
* - Small: Tall and thin widgets will show cover art and three controls * - Tall and thin widgets will show cover art and three controls
* - Compact: Wide and short widgets will show cover art and all controls in a compact manner * - Wide and short widgets will show cover art and all controls in a compact manner
* - Minimal: Small widgets will only show cover art and three controls * - Small widgets will only show text and three controls
* - Tiny widgets [e.g landscape mode] will show cover art, text, and a play/pause control.
* *
* There are some minor problems with this implementation [notably UI jittering when the widget * There are some minor problems with this implementation [notably UI jittering when the widget
* picks a new layout below Android 12], but this is tolerable. It may be improved in the future. * picks a new layout below Android 12], but this is tolerable. It may be improved in the future.
@ -80,10 +81,11 @@ class WidgetProvider : AppWidgetProvider() {
// Map each widget form to the cells where it would look at least okay. // Map each widget form to the cells where it would look at least okay.
val views = mapOf( val views = mapOf(
SizeF(180f, 152f) to createMinimalWidget(context, state), SizeF(180f, 100f) to createTinyWidget(context, state),
SizeF(272f, 152f) to createCompactWidget(context, state), SizeF(180f, 152f) to createSmallWidget(context, state),
SizeF(180f, 270f) to createSmallWidget(context, state), SizeF(272f, 152f) to createWideWidget(context, state),
SizeF(272f, 270f) to createFullWidget(context, state) SizeF(180f, 270f) to createMediumWidget(context, state),
SizeF(272f, 270f) to createLargeWidget(context, state)
) )
appWidgetManager.applyViewsCompat(context, views) appWidgetManager.applyViewsCompat(context, views)

View file

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@android:id/background"
android:background="?attr/colorSurface"
android:theme="@style/Theme.Widget"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--
We can't use ConstraintLayout on widgets due to RemoteView limitations, but
for this widget form to work, we need to get the cover to preserve it's aspect
ratio. So, we use a fixed-size 1000x1000 drawable and then align the cover view
to that so that the bounds will scale properly.
This is easily one of the worst layout hacks I've done, but it seems to work.
-->
<ImageView
android:id="@+id/widget_aspect_ratio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:layout_marginTop="@dimen/spacing_medium"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_above="@+id/widget_panel"
android:src="@drawable/ui_widget_aspect_ratio"
android:visibility="invisible"
tools:ignore="ContentDescription" />
<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_song"
tools:ignore="ContentDescription" />
<android.widget.LinearLayout
android:id="@+id/widget_panel"
style="@style/Widget.Auxio.AppWidget.Panel"
android:layout_alignParentBottom="true"
android:layout_gravity="center">
<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"
android:text="@string/def_widget_song" />
<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"
android:text="@string/def_widget_artist" />
<android.widget.LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_medium"
android:orientation="horizontal">
<android.widget.ImageButton
android:id="@+id/widget_skip_prev"
style="@style/Widget.Auxio.Button.AppWidget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:contentDescription="@string/desc_skip_prev"
android:src="@drawable/ic_skip_prev" />
<android.widget.ImageButton
android:id="@+id/widget_play_pause"
style="@style/Widget.Auxio.Button.AppWidget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:contentDescription="@string/desc_play_pause"
android:src="@drawable/ic_play" />
<android.widget.ImageButton
android:id="@+id/widget_skip_next"
style="@style/Widget.Auxio.Button.AppWidget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:contentDescription="@string/desc_skip_next"
android:src="@drawable/ic_skip_next" />
</android.widget.LinearLayout>
</android.widget.LinearLayout>
</RelativeLayout>

View file

@ -1,53 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@android:id/background" android:id="@android:id/background"
android:background="?attr/colorSurface"
android:theme="@style/Theme.Widget"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:background="?attr/colorSurface"
android:gravity="center_vertical"
android:orientation="vertical"
android:theme="@style/Theme.Widget">
<!-- <android.widget.LinearLayout style="@style/Widget.Auxio.AppWidget.Panel">
We can't use ConstraintLayout on widgets due to RemoteView limitations, but
for this widget form to work, we need to get the cover to preserve it's aspect
ratio. So, we use a fixed-size 1000x1000 drawable and then align the cover view
to that so that the bounds will scale properly.
This is easily one of the worst layout hacks I've done, but it seems to work.
-->
<ImageView
android:id="@+id/widget_aspect_ratio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:layout_marginTop="@dimen/spacing_medium"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_above="@+id/widget_panel"
android:src="@drawable/ui_widget_aspect_ratio"
android:visibility="invisible"
tools:ignore="ContentDescription" />
<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_song"
tools:ignore="ContentDescription" />
<android.widget.LinearLayout
android:id="@+id/widget_panel"
style="@style/Widget.Auxio.AppWidget.Panel"
android:layout_alignParentBottom="true"
android:layout_gravity="center">
<android.widget.TextView <android.widget.TextView
android:id="@+id/widget_song" android:id="@+id/widget_song"
@ -66,8 +27,7 @@
<android.widget.LinearLayout <android.widget.LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_medium" android:layout_marginTop="@dimen/spacing_medium">
android:orientation="horizontal">
<android.widget.ImageButton <android.widget.ImageButton
android:id="@+id/widget_skip_prev" android:id="@+id/widget_skip_prev"
@ -99,6 +59,5 @@
</android.widget.LinearLayout> </android.widget.LinearLayout>
</android.widget.LinearLayout> </android.widget.LinearLayout>
</RelativeLayout>
</LinearLayout>

View file

@ -8,11 +8,12 @@
android:background="?attr/colorSurface" android:background="?attr/colorSurface"
android:theme="@style/Theme.Widget"> android:theme="@style/Theme.Widget">
<android.widget.LinearLayout style="@style/Widget.Auxio.AppWidget.Panel">
<LinearLayout <LinearLayout
style="@style/Widget.Auxio.AppWidget.Panel"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"> android:orientation="horizontal">
<ImageView <ImageView
@ -24,9 +25,9 @@
android:src="@drawable/ic_song" /> android:src="@drawable/ic_song" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="vertical"> android:orientation="vertical">
<android.widget.TextView <android.widget.TextView
@ -44,42 +45,18 @@
android:text="@string/def_widget_artist" /> android:text="@string/def_widget_artist" />
</LinearLayout> </LinearLayout>
</LinearLayout>
<android.widget.LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_medium">
<android.widget.ImageButton
android:id="@+id/widget_skip_prev"
style="@style/Widget.Auxio.Button.AppWidget"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/desc_skip_prev"
android:src="@drawable/ic_skip_prev" />
<android.widget.ImageButton <android.widget.ImageButton
android:id="@+id/widget_play_pause" android:id="@+id/widget_play_pause"
style="@style/Widget.Auxio.Button.AppWidget" style="@style/Widget.Auxio.Button.AppWidget"
android:layout_weight="1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minHeight="@dimen/size_btn_small"
android:minWidth="@dimen/size_btn_small"
android:contentDescription="@string/desc_play_pause" android:contentDescription="@string/desc_play_pause"
android:src="@drawable/ic_play" /> android:src="@drawable/sel_playing_state" />
<android.widget.ImageButton
android:id="@+id/widget_skip_next"
style="@style/Widget.Auxio.Button.AppWidget"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/desc_skip_next"
android:src="@drawable/ic_skip_next" />
</android.widget.LinearLayout> </LinearLayout>
</android.widget.LinearLayout>
</LinearLayout> </LinearLayout>

View file

@ -43,7 +43,7 @@
<dimen name="popup_padding_end">28dp</dimen> <dimen name="popup_padding_end">28dp</dimen>
<dimen name="widget_width_min">176dp</dimen> <dimen name="widget_width_min">176dp</dimen>
<dimen name="widget_height_min">180dp</dimen> <dimen name="widget_height_min">110dp</dimen>
<dimen name="widget_width_def">@dimen/widget_width_min</dimen> <dimen name="widget_width_def">@dimen/widget_width_min</dimen>
<dimen name="widget_height_def">180dp</dimen> <dimen name="widget_height_def">180dp</dimen>
</resources> </resources>

View file

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/info_widget_desc" android:description="@string/info_widget_desc"
android:initialLayout="@layout/widget_minimal" android:initialLayout="@layout/widget_medium"
android:minResizeWidth="@dimen/widget_width_min" android:minResizeWidth="@dimen/widget_width_min"
android:minResizeHeight="@dimen/widget_height_min" android:minResizeHeight="@dimen/widget_height_min"
android:previewLayout="@layout/widget_minimal" android:previewLayout="@layout/widget_medium"
android:previewImage="@drawable/ui_widget_preview" android:previewImage="@drawable/ui_widget_preview"
android:resizeMode="horizontal|vertical" android:resizeMode="horizontal|vertical"
android:minWidth="@dimen/widget_width_def" android:minWidth="@dimen/widget_width_def"

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/widget_minimal" android:initialLayout="@layout/widget_medium"
android:minWidth="@dimen/widget_width_min" android:minWidth="@dimen/widget_width_min"
android:minHeight="@dimen/widget_height_min" android:minHeight="@dimen/widget_height_min"
android:minResizeWidth="@dimen/widget_width_def" android:minResizeWidth="@dimen/widget_width_def"