diff --git a/app/build.gradle b/app/build.gradle index a3e59cc66..1835989ee 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,6 +99,8 @@ dependencies { // Material implementation "com.google.android.material:material:1.4.0" + implementation 'me.zhanghai.android.fastscroll:library:1.1.7' + // --- DEBUG --- // Lint diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt b/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt index 8bf4036fc..7eaab084e 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/Forms.kt @@ -41,7 +41,12 @@ private fun createViews( return views } -private fun RemoteViews.applyState(context: Context, state: WidgetState) { +private fun RemoteViews.applyMeta(context: Context, state: WidgetState) { + setTextViewText(R.id.widget_song, state.song.name) + setTextViewText(R.id.widget_artist, state.song.album.artist.name) +} + +fun RemoteViews.applyControls(context: Context, state: WidgetState) { setOnClickPendingIntent( R.id.widget_skip_prev, context.newBroadcastIntent( @@ -63,9 +68,6 @@ private fun RemoteViews.applyState(context: Context, state: WidgetState) { ) ) - setTextViewText(R.id.widget_song, state.song.name) - setTextViewText(R.id.widget_artist, state.song.album.artist.name) - setImageViewResource( R.id.widget_play_pause, if (state.isPlaying) { @@ -74,7 +76,9 @@ private fun RemoteViews.applyState(context: Context, state: WidgetState) { R.drawable.ic_play } ) +} +fun RemoteViews.applyCover(context: Context, state: WidgetState) { if (state.albumArt != null) { setImageViewBitmap(R.id.widget_cover, state.albumArt) setContentDescription( @@ -90,15 +94,32 @@ fun createDefaultWidget(context: Context): RemoteViews { return createViews(context, R.layout.widget_default) } +fun createMiniWidget(context: Context, state: WidgetState): RemoteViews { + val views = createViews(context, R.layout.widget_mini) + views.applyMeta(context, state) + return views +} + +fun createCompactWidget(context: Context, state: WidgetState): RemoteViews { + val views = createViews(context, R.layout.widget_compact) + views.applyMeta(context, state) + views.applyCover(context, state) + return views +} + fun createSmallWidget(context: Context, state: WidgetState): RemoteViews { val views = createViews(context, R.layout.widget_small) - views.applyState(context, state) + views.applyMeta(context, state) + views.applyCover(context, state) + views.applyControls(context, state) return views } fun createFullWidget(context: Context, state: WidgetState): RemoteViews { val views = createViews(context, R.layout.widget_full) - views.applyState(context, state) + views.applyMeta(context, state) + views.applyCover(context, state) + views.applyControls(context, state) views.setOnClickPendingIntent( R.id.widget_loop, diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt index da3933872..1a167c66f 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt @@ -38,10 +38,13 @@ import org.oxycblt.auxio.ui.isLandscape * Auxio's one and only appwidget. This widget follows a more unorthodox approach, effectively * packing what could be considered 3 or 4 widgets into a single responsive widget. More specifically: * + * - For widgets 2x1 or lower, show a text-only view with no controls + * - For widgets Wx1 or lower, show a compact view with no controls. * - For widgets Wx2 or higher, show an expanded view with album art and basic controls * - For widgets 4x2 or higher, show a complete view with all playback controls * - * Other widget variants might be added if there is sufficient demand. + * 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. * * For more specific details about these sub-widgets, see Forms.kt. */ @@ -68,9 +71,13 @@ class WidgetProvider : AppWidgetProvider() { ) // Map each widget form to the cells where it would look at least okay. + // The large widgets are 140 instead of 110 so that they're backwards compatible + // with the old widget size reporting val views = mapOf( - SizeF(180f, 110f) to createSmallWidget(context, state), - SizeF(250f, 110f) to createFullWidget(context, state) + SizeF(180f, 40f) to createMiniWidget(context, state), + SizeF(250f, 40f) to createCompactWidget(context, state), + SizeF(180f, 140f) to createSmallWidget(context, state), + SizeF(250f, 140f) to createFullWidget(context, state) ) appWidgetManager.applyViewsCompat(context, views) @@ -138,8 +145,8 @@ class WidgetProvider : AppWidgetProvider() { updateAppWidget(name, RemoteViews(views)) } else { // Otherwise, we try our best to backport the responsive behavior to older versions. - // This is mostly a guess based on RemoteView's documentation. It may be improved when - // Android 12's source is released. + // This is mostly a guess based on RemoteView's documentation. It seems to work well + // on most launchers. It may be improved when Android 12's source is released. // Each widget has independent dimensions, so we iterate through them all // and do this for each. @@ -168,8 +175,8 @@ class WidgetProvider : AppWidgetProvider() { height = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT) } - height += padW - width += padH + height += padH + width += padW logD("Assuming true widget dimens are ${width}x$height") diff --git a/app/src/main/res/drawable/ui_widget_aspect_ratio.xml b/app/src/main/res/drawable/ui_widget_aspect_ratio.xml new file mode 100644 index 000000000..4eb6d9199 --- /dev/null +++ b/app/src/main/res/drawable/ui_widget_aspect_ratio.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/widget_compact.xml b/app/src/main/res/layout/widget_compact.xml new file mode 100644 index 000000000..92907f1f1 --- /dev/null +++ b/app/src/main/res/layout/widget_compact.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/widget_mini.xml b/app/src/main/res/layout/widget_mini.xml new file mode 100644 index 000000000..108f15978 --- /dev/null +++ b/app/src/main/res/layout/widget_mini.xml @@ -0,0 +1,26 @@ + + + + + + + + + diff --git a/app/src/main/res/xml-v31/widget_info.xml b/app/src/main/res/xml-v31/widget_info.xml index 76612407c..963846a3d 100644 --- a/app/src/main/res/xml-v31/widget_info.xml +++ b/app/src/main/res/xml-v31/widget_info.xml @@ -3,10 +3,10 @@ android:description="@string/info_widget_desc" android:initialLayout="@layout/widget_small" android:minResizeWidth="180dp" - android:minResizeHeight="110dp" + android:minResizeHeight="40dp" android:previewLayout="@layout/widget_small" android:resizeMode="horizontal|vertical" - android:targetCellWidth="3" - android:targetCellHeight="2" + android:minWidth="180dp" + android:minHeight="110dp" android:updatePeriodMillis="0" android:widgetCategory="home_screen" /> \ No newline at end of file diff --git a/app/src/main/res/xml/widget_info.xml b/app/src/main/res/xml/widget_info.xml index f74fde98b..828a11bae 100644 --- a/app/src/main/res/xml/widget_info.xml +++ b/app/src/main/res/xml/widget_info.xml @@ -4,7 +4,7 @@ android:minWidth="180dp" android:minHeight="110dp" android:minResizeWidth="180dp" - android:minResizeHeight="110dp" + android:minResizeHeight="40dp" android:previewImage="@drawable/ui_widget_preview" android:resizeMode="horizontal|vertical" android:updatePeriodMillis="0"