widgets: add widget layout preview
Add a layout preview to the Android 12 widget metadata. I'm holding off on implementing a drawable until the widgets are completely finalized.
This commit is contained in:
parent
8551e90884
commit
49db7e0741
11 changed files with 54 additions and 29 deletions
|
|
@ -369,6 +369,9 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac
|
||||||
onLoopUpdate(playbackManager.loopMode)
|
onLoopUpdate(playbackManager.loopMode)
|
||||||
onSongUpdate(playbackManager.song)
|
onSongUpdate(playbackManager.song)
|
||||||
onSeek(playbackManager.position)
|
onSeek(playbackManager.position)
|
||||||
|
|
||||||
|
// Notify other classes that rely on this service to also update.
|
||||||
|
widgets.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -495,9 +498,11 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseWidget.ACTION_WIDGET_UPDATE -> widgets.initWidget(
|
BaseWidget.ACTION_WIDGET_UPDATE -> {
|
||||||
intent.getIntExtra(BaseWidget.ACTION_WIDGET_UPDATE, -1)
|
widgets.initWidget(
|
||||||
)
|
intent.getIntExtra(BaseWidget.KEY_WIDGET_TYPE, -1)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -155,8 +155,8 @@ enum class SortMode(@DrawableRes val iconRes: Int) {
|
||||||
val list = mutableListOf<Song>()
|
val list = mutableListOf<Song>()
|
||||||
|
|
||||||
songs.groupBy { it.album }.entries.sortedWith(compareByDescending { it.key.year }).forEach { entry ->
|
songs.groupBy { it.album }.entries.sortedWith(compareByDescending { it.key.year }).forEach { entry ->
|
||||||
list.addAll(entry.value.sortedWith(compareBy { it.track }))
|
list.addAll(entry.value.sortedWith(compareBy { it.track }))
|
||||||
}
|
}
|
||||||
|
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,6 @@ abstract class BaseWidget : AppWidgetProvider() {
|
||||||
* Update the widget based on the playback state.
|
* Update the widget based on the playback state.
|
||||||
*/
|
*/
|
||||||
fun update(context: Context, playbackManager: PlaybackStateManager) {
|
fun update(context: Context, playbackManager: PlaybackStateManager) {
|
||||||
logD("Dispatching playback state update")
|
|
||||||
|
|
||||||
val manager = AppWidgetManager.getInstance(context)
|
val manager = AppWidgetManager.getInstance(context)
|
||||||
|
|
||||||
// View updates are often async due to image loading, so only push the views
|
// View updates are often async due to image loading, so only push the views
|
||||||
|
|
@ -57,10 +55,10 @@ abstract class BaseWidget : AppWidgetProvider() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stop this widget, reverting it to its default state.
|
* Revert this widget to its default view
|
||||||
*/
|
*/
|
||||||
fun stop(context: Context) {
|
fun reset(context: Context) {
|
||||||
logD("Stopping widget")
|
logD("Resetting widget")
|
||||||
|
|
||||||
val manager = AppWidgetManager.getInstance(context)
|
val manager = AppWidgetManager.getInstance(context)
|
||||||
manager.applyViews(context, defaultViews(context))
|
manager.applyViews(context, defaultViews(context))
|
||||||
|
|
@ -71,10 +69,10 @@ abstract class BaseWidget : AppWidgetProvider() {
|
||||||
appWidgetManager: AppWidgetManager,
|
appWidgetManager: AppWidgetManager,
|
||||||
appWidgetIds: IntArray
|
appWidgetIds: IntArray
|
||||||
) {
|
) {
|
||||||
appWidgetManager.applyViews(context, defaultViews(context))
|
|
||||||
|
|
||||||
logD("Sending update intent to PlaybackService")
|
logD("Sending update intent to PlaybackService")
|
||||||
|
|
||||||
|
appWidgetManager.applyViews(context, defaultViews(context))
|
||||||
|
|
||||||
val intent = Intent(ACTION_WIDGET_UPDATE)
|
val intent = Intent(ACTION_WIDGET_UPDATE)
|
||||||
.putExtra(KEY_WIDGET_TYPE, type)
|
.putExtra(KEY_WIDGET_TYPE, type)
|
||||||
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
|
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ class MinimalWidgetProvider : BaseWidget() {
|
||||||
val song = playbackManager.song
|
val song = playbackManager.song
|
||||||
|
|
||||||
if (song != null) {
|
if (song != null) {
|
||||||
logD("updating view to ${song.name}")
|
logD("Updating view to ${song.name}")
|
||||||
|
|
||||||
val views = createViews(context, R.layout.widget_minimal)
|
val views = createViews(context, R.layout.widget_minimal)
|
||||||
|
|
||||||
|
|
@ -88,6 +88,8 @@ class MinimalWidgetProvider : BaseWidget() {
|
||||||
onDone(views)
|
onDone(views)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
logD("No song playing, reverting to default view")
|
||||||
|
|
||||||
onDone(defaultViews(context))
|
onDone(defaultViews(context))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,44 @@
|
||||||
package org.oxycblt.auxio.widgets
|
package org.oxycblt.auxio.widgets
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import org.oxycblt.auxio.logD
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||||
|
|
||||||
class WidgetController(private val context: Context) : PlaybackStateManager.Callback {
|
class WidgetController(private val context: Context) : PlaybackStateManager.Callback {
|
||||||
private val manager = PlaybackStateManager.getInstance()
|
private val playbackManager = PlaybackStateManager.getInstance()
|
||||||
private val minimal = MinimalWidgetProvider()
|
private val minimal = MinimalWidgetProvider()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
manager.addCallback(this)
|
playbackManager.addCallback(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun initWidget(type: Int) {
|
fun initWidget(type: Int) {
|
||||||
|
logD("Updating new widget $type")
|
||||||
|
|
||||||
when (type) {
|
when (type) {
|
||||||
MinimalWidgetProvider.TYPE -> minimal.update(context, manager)
|
MinimalWidgetProvider.TYPE -> minimal.update(context, playbackManager)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun update() {
|
||||||
|
logD("Updating all widgets")
|
||||||
|
|
||||||
|
minimal.update(context, playbackManager)
|
||||||
|
}
|
||||||
|
|
||||||
fun release() {
|
fun release() {
|
||||||
minimal.stop(context)
|
logD("Resetting widgets")
|
||||||
manager.removeCallback(this)
|
|
||||||
|
minimal.reset(context)
|
||||||
|
playbackManager.removeCallback(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSongUpdate(song: Song?) {
|
override fun onSongUpdate(song: Song?) {
|
||||||
minimal.update(context, manager)
|
minimal.update(context, playbackManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPlayingUpdate(isPlaying: Boolean) {
|
override fun onPlayingUpdate(isPlaying: Boolean) {
|
||||||
minimal.update(context, manager)
|
minimal.update(context, playbackManager)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
7
app/src/main/res/drawable-v31/ui_rounded_cutout.xml
Normal file
7
app/src/main/res/drawable-v31/ui_rounded_cutout.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
|
||||||
|
<corners android:radius="@android:dimen/system_app_widget_inner_radius" />
|
||||||
|
|
||||||
|
</shape>
|
||||||
|
|
@ -15,13 +15,13 @@
|
||||||
android:background="?attr/colorSurface"
|
android:background="?attr/colorSurface"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
tools:ignore="contentDescription"
|
tools:ignore="contentDescription"
|
||||||
tools:src="@drawable/ic_song" />
|
android:src="@drawable/ic_song" />
|
||||||
|
|
||||||
<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_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:background="?android:attr/colorBackground"
|
android:background="?attr/colorSurface"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="@dimen/spacing_medium">
|
android:padding="@dimen/spacing_medium">
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
tools:text="Song Name" />
|
android:text="@string/placeholder_widget_song" />
|
||||||
|
|
||||||
<android.widget.TextView
|
<android.widget.TextView
|
||||||
android:id="@+id/widget_artist"
|
android:id="@+id/widget_artist"
|
||||||
|
|
@ -46,13 +46,12 @@
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
tools:text="Artist Name" />
|
android:text="@string/placeholder_widget_artist" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:layout_marginTop="@dimen/spacing_small"
|
||||||
android:layout_marginTop="@dimen/spacing_medium"
|
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
android:id="@android:id/background"
|
android:id="@android:id/background"
|
||||||
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:theme="@style/Theme.Widget">
|
android:theme="@style/Theme.Widget">
|
||||||
|
|
||||||
<android.widget.ImageView
|
<android.widget.ImageView
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,7 @@
|
||||||
<LinearLayout
|
<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_small">
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Can't use a normal unbounded ripple here since it causes a weird bug
|
Can't use a normal unbounded ripple here since it causes a weird bug
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools"
|
<resources xmlns:tools="http://schemas.android.com/tools"
|
||||||
tools:ignore="MissingTranslation">
|
tools:ignore="MissingTranslation">
|
||||||
|
|
||||||
<!-- Info namespace | App labels -->
|
<!-- Info namespace | App labels -->
|
||||||
<string name="info_app_desc">A simple, rational music player for android.</string>
|
<string name="info_app_desc">A simple, rational music player for android.</string>
|
||||||
<string name="info_channel_name">Music Playback</string>
|
<string name="info_channel_name">Music Playback</string>
|
||||||
|
|
@ -137,6 +138,8 @@
|
||||||
<string name="placeholder_album">Unknown Album</string>
|
<string name="placeholder_album">Unknown Album</string>
|
||||||
<string name="placeholder_no_date">No Date</string>
|
<string name="placeholder_no_date">No Date</string>
|
||||||
<string name="placeholder_playback">No music playing</string>
|
<string name="placeholder_playback">No music playing</string>
|
||||||
|
<string name="placeholder_widget_song">Song Name</string>
|
||||||
|
<string name="placeholder_widget_artist">Artist Name</string>
|
||||||
|
|
||||||
<!-- Color Label namespace | Accent names -->
|
<!-- Color Label namespace | Accent names -->
|
||||||
<string name="color_label_red">Red</string>
|
<string name="color_label_red">Red</string>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
android:targetCellHeight="2"
|
android:targetCellHeight="2"
|
||||||
android:minResizeWidth="110dp"
|
android:minResizeWidth="110dp"
|
||||||
android:minResizeHeight="110dp"
|
android:minResizeHeight="110dp"
|
||||||
|
android:previewLayout="@layout/widget_minimal"
|
||||||
android:resizeMode="horizontal|vertical"
|
android:resizeMode="horizontal|vertical"
|
||||||
android:updatePeriodMillis="0"
|
android:updatePeriodMillis="0"
|
||||||
android:widgetCategory="home_screen">
|
android:widgetCategory="home_screen">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue