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"