fix(widget): refine layouts and progress UX across sizes

Compact (4×1)
- Reduce root vertical padding so the 4×1 cell yields ~56dp of content height.
- Make album art a true square (50×50dp) and center vertically; keeps edges
  clear of rounded corners.
- Tighten timing block: 2dp progress bar; 10sp labels with no extra font
  padding; prevents elapsed/total text from slipping below the background.
- Wrap album art in a 50×50dp FrameLayout with a new 6dp-radius background
  drawable; soft corners while remaining visually smaller than the widget body.
- Mirror the same structure in the preview layout so Studio preview matches
  on-device rendering.
  (app/src/main/res/layout/widget_layout_compact.xml,
   app/src/main/res/drawable/widget_album_art_bg.xml)

Large Short (4×2)
- Wrap album art in a fixed 90dp square container and enforce a true square
  crop via centerCrop.
- Tighten vertical spacing: thinner progress bar, closer timing row, controls
  shifted down for better balance.
- Keep album/timing text to the left of the controls but retune spacing so the
  stack stays fully inside the widget bounds.

Large (4×3 and up)
- Restructure to a vertical stack: header row (album art + text), full-width
  progress bar, timing row, primary controls, then secondary controls.
- Lock album art to a 150dp square; progress bar spans the widget beneath the
  header to match the new visual hierarchy.

Based-on: cd28ee0764
Co-authored-by: The Firehawk <firehawk@opayq.net>
Co-Authored-By: Mücahit Kaya <kaya-mucahit@outlook.com>
Co-Authored-By: Firehawk <firehawk@opayq.net>
This commit is contained in:
mucahit-kaya 2025-09-20 21:13:23 +02:00
parent b79cfa4af0
commit 35af1f9038
17 changed files with 964 additions and 149 deletions

View file

@ -4,6 +4,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.util.Log;
import androidx.media3.common.Player;
import androidx.media3.session.MediaController;
import androidx.media3.session.SessionToken;
@ -34,7 +35,23 @@ public final class WidgetActions {
case WidgetProvider.ACT_PREV:
c.seekToPrevious();
break;
case WidgetProvider.ACT_TOGGLE_SHUFFLE:
c.setShuffleModeEnabled(!c.getShuffleModeEnabled());
break;
case WidgetProvider.ACT_CYCLE_REPEAT:
int repeatMode = c.getRepeatMode();
int nextMode;
if (repeatMode == Player.REPEAT_MODE_OFF) {
nextMode = Player.REPEAT_MODE_ALL;
} else if (repeatMode == Player.REPEAT_MODE_ALL) {
nextMode = Player.REPEAT_MODE_ONE;
} else {
nextMode = Player.REPEAT_MODE_OFF;
}
c.setRepeatMode(nextMode);
break;
}
WidgetUpdateManager.refreshFromController(ctx);
c.release();
} catch (ExecutionException | InterruptedException e) {
Log.e("TempoWidget", "dispatch failed", e);

View file

@ -18,6 +18,8 @@ public class WidgetProvider extends AppWidgetProvider {
public static final String ACT_PLAY_PAUSE = "tempo.widget.PLAY_PAUSE";
public static final String ACT_NEXT = "tempo.widget.NEXT";
public static final String ACT_PREV = "tempo.widget.PREV";
public static final String ACT_TOGGLE_SHUFFLE = "tempo.widget.SHUFFLE";
public static final String ACT_CYCLE_REPEAT = "tempo.widget.REPEAT";
@Override public void onUpdate(Context ctx, AppWidgetManager mgr, int[] ids) {
for (int id : ids) {
@ -31,7 +33,8 @@ public class WidgetProvider extends AppWidgetProvider {
super.onReceive(ctx, intent);
String a = intent.getAction();
Log.d(TAG, "onReceive action=" + a);
if (ACT_PLAY_PAUSE.equals(a) || ACT_NEXT.equals(a) || ACT_PREV.equals(a)) {
if (ACT_PLAY_PAUSE.equals(a) || ACT_NEXT.equals(a) || ACT_PREV.equals(a)
|| ACT_TOGGLE_SHUFFLE.equals(a) || ACT_CYCLE_REPEAT.equals(a)) {
WidgetActions.dispatchToMediaSession(ctx, a);
} else if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(a)) {
WidgetUpdateManager.refreshFromController(ctx);
@ -69,10 +72,24 @@ public class WidgetProvider extends AppWidgetProvider {
new Intent(ctx, WidgetProvider4x1.class).setAction(ACT_PREV),
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
);
PendingIntent shuffle = PendingIntent.getBroadcast(
ctx,
requestCodeBase + 3,
new Intent(ctx, WidgetProvider4x1.class).setAction(ACT_TOGGLE_SHUFFLE),
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
);
PendingIntent repeat = PendingIntent.getBroadcast(
ctx,
requestCodeBase + 4,
new Intent(ctx, WidgetProvider4x1.class).setAction(ACT_CYCLE_REPEAT),
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
);
rv.setOnClickPendingIntent(R.id.btn_play_pause, playPause);
rv.setOnClickPendingIntent(R.id.btn_next, next);
rv.setOnClickPendingIntent(R.id.btn_prev, prev);
rv.setOnClickPendingIntent(R.id.btn_shuffle, shuffle);
rv.setOnClickPendingIntent(R.id.btn_repeat, repeat);
PendingIntent launch = TaskStackBuilder.create(ctx)
.addNextIntentWithParentStack(new Intent(ctx, MainActivity.class))

View file

@ -24,20 +24,24 @@ public final class WidgetUpdateManager {
public static void updateFromState(Context ctx,
String title,
String artist,
String album,
Bitmap art,
boolean playing,
boolean shuffleEnabled,
int repeatMode,
long positionMs,
long durationMs) {
if (TextUtils.isEmpty(title)) title = ctx.getString(R.string.widget_not_playing);
if (TextUtils.isEmpty(artist)) artist = ctx.getString(R.string.widget_placeholder_subtitle);
if (TextUtils.isEmpty(album)) album = "";
final TimingInfo timing = createTimingInfo(positionMs, durationMs);
AppWidgetManager mgr = AppWidgetManager.getInstance(ctx);
int[] ids = mgr.getAppWidgetIds(new ComponentName(ctx, WidgetProvider4x1.class));
for (int id : ids) {
android.widget.RemoteViews rv = choosePopulate(ctx, title, artist, art, playing,
timing.elapsedText, timing.totalText, timing.progress, id);
android.widget.RemoteViews rv = choosePopulate(ctx, title, artist, album, art, playing,
timing.elapsedText, timing.totalText, timing.progress, shuffleEnabled, repeatMode, id);
WidgetProvider.attachIntents(ctx, rv, id);
mgr.updateAppWidget(id, rv);
}
@ -56,14 +60,20 @@ public final class WidgetUpdateManager {
public static void updateFromState(Context ctx,
String title,
String artist,
String album,
String coverArtId,
boolean playing,
boolean shuffleEnabled,
int repeatMode,
long positionMs,
long durationMs) {
final Context appCtx = ctx.getApplicationContext();
final String t = TextUtils.isEmpty(title) ? appCtx.getString(R.string.widget_not_playing) : title;
final String a = TextUtils.isEmpty(artist) ? appCtx.getString(R.string.widget_placeholder_subtitle) : artist;
final String alb = !TextUtils.isEmpty(album) ? album : "";
final boolean p = playing;
final boolean sh = shuffleEnabled;
final int rep = repeatMode;
final TimingInfo timing = createTimingInfo(positionMs, durationMs);
if (!TextUtils.isEmpty(coverArtId)) {
@ -76,8 +86,8 @@ public final class WidgetUpdateManager {
AppWidgetManager mgr = AppWidgetManager.getInstance(appCtx);
int[] ids = mgr.getAppWidgetIds(new ComponentName(appCtx, WidgetProvider4x1.class));
for (int id : ids) {
android.widget.RemoteViews rv = choosePopulate(appCtx, t, a, resource, p,
timing.elapsedText, timing.totalText, timing.progress, id);
android.widget.RemoteViews rv = choosePopulate(appCtx, t, a, alb, resource, p,
timing.elapsedText, timing.totalText, timing.progress, sh, rep, id);
WidgetProvider.attachIntents(appCtx, rv, id);
mgr.updateAppWidget(id, rv);
}
@ -87,8 +97,8 @@ public final class WidgetUpdateManager {
AppWidgetManager mgr = AppWidgetManager.getInstance(appCtx);
int[] ids = mgr.getAppWidgetIds(new ComponentName(appCtx, WidgetProvider4x1.class));
for (int id : ids) {
android.widget.RemoteViews rv = choosePopulate(appCtx, t, a, null, p,
timing.elapsedText, timing.totalText, timing.progress, id);
android.widget.RemoteViews rv = choosePopulate(appCtx, t, a, alb, null, p,
timing.elapsedText, timing.totalText, timing.progress, sh, rep, id);
WidgetProvider.attachIntents(appCtx, rv, id);
mgr.updateAppWidget(id, rv);
}
@ -99,8 +109,8 @@ public final class WidgetUpdateManager {
AppWidgetManager mgr = AppWidgetManager.getInstance(appCtx);
int[] ids = mgr.getAppWidgetIds(new ComponentName(appCtx, WidgetProvider4x1.class));
for (int id : ids) {
android.widget.RemoteViews rv = choosePopulate(appCtx, t, a, null, p,
timing.elapsedText, timing.totalText, timing.progress, id);
android.widget.RemoteViews rv = choosePopulate(appCtx, t, a, alb, null, p,
timing.elapsedText, timing.totalText, timing.progress, sh, rep, id);
WidgetProvider.attachIntents(appCtx, rv, id);
mgr.updateAppWidget(id, rv);
}
@ -116,13 +126,15 @@ public final class WidgetUpdateManager {
if (!future.isDone()) return;
MediaController c = future.get();
androidx.media3.common.MediaItem mi = c.getCurrentMediaItem();
String title = null, artist = null, coverId = null;
String title = null, artist = null, album = null, coverId = null;
if (mi != null && mi.mediaMetadata != null) {
if (mi.mediaMetadata.title != null) title = mi.mediaMetadata.title.toString();
if (mi.mediaMetadata.artist != null) artist = mi.mediaMetadata.artist.toString();
if (mi.mediaMetadata.albumTitle != null) album = mi.mediaMetadata.albumTitle.toString();
if (mi.mediaMetadata.extras != null) {
if (title == null) title = mi.mediaMetadata.extras.getString("title");
if (artist == null) artist = mi.mediaMetadata.extras.getString("artist");
if (album == null) album = mi.mediaMetadata.extras.getString("album");
coverId = mi.mediaMetadata.extras.getString("coverArtId");
}
}
@ -133,8 +145,11 @@ public final class WidgetUpdateManager {
updateFromState(appCtx,
title != null ? title : appCtx.getString(R.string.widget_not_playing),
artist != null ? artist : appCtx.getString(R.string.widget_placeholder_subtitle),
album,
coverId,
c.isPlaying(),
c.getShuffleModeEnabled(),
c.getRepeatMode(),
position,
duration);
c.release();
@ -174,31 +189,68 @@ public final class WidgetUpdateManager {
}
public static android.widget.RemoteViews chooseBuild(Context ctx, int appWidgetId) {
if (isLarge(ctx, appWidgetId)) return WidgetViewsFactory.buildLarge(ctx);
return WidgetViewsFactory.buildCompact(ctx);
LayoutSize size = resolveLayoutSize(ctx, appWidgetId);
switch (size) {
case MEDIUM:
return WidgetViewsFactory.buildMedium(ctx);
case LARGE:
return WidgetViewsFactory.buildLarge(ctx);
case EXPANDED:
return WidgetViewsFactory.buildExpanded(ctx);
case COMPACT:
default:
return WidgetViewsFactory.buildCompact(ctx);
}
}
private static android.widget.RemoteViews choosePopulate(Context ctx,
String title,
String artist,
String album,
Bitmap art,
boolean playing,
String elapsedText,
String totalText,
int progress,
boolean shuffleEnabled,
int repeatMode,
int appWidgetId) {
if (isLarge(ctx, appWidgetId)) {
return WidgetViewsFactory.populateLarge(ctx, title, artist, art, playing, elapsedText, totalText, progress);
LayoutSize size = resolveLayoutSize(ctx, appWidgetId);
switch (size) {
case MEDIUM:
return WidgetViewsFactory.populateMedium(ctx, title, artist, album, art, playing,
elapsedText, totalText, progress, shuffleEnabled, repeatMode);
case LARGE:
return WidgetViewsFactory.populateLarge(ctx, title, artist, album, art, playing,
elapsedText, totalText, progress, shuffleEnabled, repeatMode);
case EXPANDED:
return WidgetViewsFactory.populateExpanded(ctx, title, artist, album, art, playing,
elapsedText, totalText, progress, shuffleEnabled, repeatMode);
case COMPACT:
default:
return WidgetViewsFactory.populateCompact(ctx, title, artist, album, art, playing,
elapsedText, totalText, progress, shuffleEnabled, repeatMode);
}
return WidgetViewsFactory.populate(ctx, title, artist, art, playing, elapsedText, totalText, progress);
}
private static boolean isLarge(Context ctx, int appWidgetId) {
private static LayoutSize resolveLayoutSize(Context ctx, int appWidgetId) {
AppWidgetManager mgr = AppWidgetManager.getInstance(ctx);
android.os.Bundle opts = mgr.getAppWidgetOptions(appWidgetId);
int minH = opts != null ? opts.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) : 0;
int threshold = ctx.getResources().getInteger(com.cappielloantonio.tempo.R.integer.widget_large_min_height_dp);
return minH >= threshold; // dp threshold for 2-row height
int expandedThreshold = ctx.getResources().getInteger(R.integer.widget_expanded_min_height_dp);
int largeThreshold = ctx.getResources().getInteger(R.integer.widget_large_min_height_dp);
int mediumThreshold = ctx.getResources().getInteger(R.integer.widget_medium_min_height_dp);
if (minH >= expandedThreshold) return LayoutSize.EXPANDED;
if (minH >= largeThreshold) return LayoutSize.LARGE;
if (minH >= mediumThreshold) return LayoutSize.MEDIUM;
return LayoutSize.COMPACT;
}
private enum LayoutSize {
COMPACT,
MEDIUM,
LARGE,
EXPANDED
}
private static final class TimingInfo {

View file

@ -2,76 +2,168 @@ package com.cappielloantonio.tempo.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.View;
import android.widget.RemoteViews;
import androidx.core.content.ContextCompat;
import androidx.media3.common.Player;
import com.cappielloantonio.tempo.R;
public final class WidgetViewsFactory {
static final int PROGRESS_MAX = 1000;
private static final float ALBUM_ART_CORNER_RADIUS_DP = 6f;
private WidgetViewsFactory() {}
public static RemoteViews buildCompact(Context ctx) {
return build(ctx, R.layout.widget_layout_compact);
return build(ctx, R.layout.widget_layout_compact, false, false);
}
public static RemoteViews buildMedium(Context ctx) {
return build(ctx, R.layout.widget_layout_medium, false, false);
}
public static RemoteViews buildLarge(Context ctx) {
return build(ctx, R.layout.widget_layout_large);
return build(ctx, R.layout.widget_layout_large_short, true, true);
}
public static RemoteViews buildExpanded(Context ctx) {
return build(ctx, R.layout.widget_layout_large, true, true);
}
private static RemoteViews build(Context ctx, int layoutRes) {
private static RemoteViews build(Context ctx,
int layoutRes,
boolean showAlbum,
boolean showSecondaryControls) {
RemoteViews rv = new RemoteViews(ctx.getPackageName(), layoutRes);
rv.setTextViewText(R.id.title, ctx.getString(R.string.widget_not_playing));
rv.setTextViewText(R.id.subtitle, ctx.getString(R.string.widget_placeholder_subtitle));
rv.setTextViewText(R.id.album, "");
rv.setViewVisibility(R.id.album, showAlbum ? View.INVISIBLE : View.GONE);
rv.setTextViewText(R.id.time_elapsed, ctx.getString(R.string.widget_time_elapsed_placeholder));
rv.setTextViewText(R.id.time_total, ctx.getString(R.string.widget_time_duration_placeholder));
rv.setProgressBar(R.id.progress, PROGRESS_MAX, 0, false);
rv.setImageViewResource(R.id.btn_play_pause, R.drawable.ic_play);
// Show Tempo logo when nothing is playing
rv.setImageViewResource(R.id.album_art, R.drawable.ic_splash_logo);
applySecondaryControlsDefaults(ctx, rv, showSecondaryControls);
return rv;
}
public static RemoteViews populate(Context ctx,
String title,
String subtitle,
Bitmap art,
boolean playing,
String elapsedText,
String totalText,
int progress) {
return populateWithLayout(ctx, title, subtitle, art, playing, elapsedText, totalText, progress, R.layout.widget_layout_compact);
private static void applySecondaryControlsDefaults(Context ctx,
RemoteViews rv,
boolean show) {
int visibility = show ? View.VISIBLE : View.GONE;
rv.setViewVisibility(R.id.controls_secondary, visibility);
rv.setViewVisibility(R.id.btn_shuffle, visibility);
rv.setViewVisibility(R.id.btn_repeat, visibility);
if (show) {
int defaultColor = ContextCompat.getColor(ctx, R.color.widget_icon_tint);
rv.setImageViewResource(R.id.btn_shuffle, R.drawable.ic_shuffle);
rv.setImageViewResource(R.id.btn_repeat, R.drawable.ic_repeat);
rv.setInt(R.id.btn_shuffle, "setColorFilter", defaultColor);
rv.setInt(R.id.btn_repeat, "setColorFilter", defaultColor);
}
}
public static RemoteViews populateCompact(Context ctx,
String title,
String subtitle,
String album,
Bitmap art,
boolean playing,
String elapsedText,
String totalText,
int progress,
boolean shuffleEnabled,
int repeatMode) {
return populateWithLayout(ctx, title, subtitle, album, art, playing, elapsedText, totalText,
progress, R.layout.widget_layout_compact, false, false, shuffleEnabled, repeatMode);
}
public static RemoteViews populateMedium(Context ctx,
String title,
String subtitle,
String album,
Bitmap art,
boolean playing,
String elapsedText,
String totalText,
int progress,
boolean shuffleEnabled,
int repeatMode) {
return populateWithLayout(ctx, title, subtitle, album, art, playing, elapsedText, totalText,
progress, R.layout.widget_layout_medium, true, true, shuffleEnabled, repeatMode);
}
public static RemoteViews populateLarge(Context ctx,
String title,
String subtitle,
Bitmap art,
boolean playing,
String elapsedText,
String totalText,
int progress) {
return populateWithLayout(ctx, title, subtitle, art, playing, elapsedText, totalText, progress, R.layout.widget_layout_large);
String title,
String subtitle,
String album,
Bitmap art,
boolean playing,
String elapsedText,
String totalText,
int progress,
boolean shuffleEnabled,
int repeatMode) {
return populateWithLayout(ctx, title, subtitle, album, art, playing, elapsedText, totalText,
progress, R.layout.widget_layout_large_short, true, true, shuffleEnabled, repeatMode);
}
public static RemoteViews populateExpanded(Context ctx,
String title,
String subtitle,
String album,
Bitmap art,
boolean playing,
String elapsedText,
String totalText,
int progress,
boolean shuffleEnabled,
int repeatMode) {
return populateWithLayout(ctx, title, subtitle, album, art, playing, elapsedText, totalText,
progress, R.layout.widget_layout_large, true, true, shuffleEnabled, repeatMode);
}
private static RemoteViews populateWithLayout(Context ctx,
String title,
String subtitle,
Bitmap art,
boolean playing,
String elapsedText,
String totalText,
int progress,
int layoutRes) {
String subtitle,
String album,
Bitmap art,
boolean playing,
String elapsedText,
String totalText,
int progress,
int layoutRes,
boolean showAlbum,
boolean showSecondaryControls,
boolean shuffleEnabled,
int repeatMode) {
RemoteViews rv = new RemoteViews(ctx.getPackageName(), layoutRes);
rv.setTextViewText(R.id.title, title);
rv.setTextViewText(R.id.subtitle, subtitle);
if (art != null) {
rv.setImageViewBitmap(R.id.album_art, art);
if (showAlbum && !TextUtils.isEmpty(album)) {
rv.setTextViewText(R.id.album, album);
rv.setViewVisibility(R.id.album, View.VISIBLE);
} else {
rv.setTextViewText(R.id.album, "");
rv.setViewVisibility(R.id.album, View.GONE);
}
if (art != null) {
Bitmap rounded = maybeRoundBitmap(ctx, art);
rv.setImageViewBitmap(R.id.album_art, rounded != null ? rounded : art);
} else {
// Fallback to app logo when art is missing
rv.setImageViewResource(R.id.album_art, R.drawable.ic_splash_logo);
}
@ -93,6 +185,67 @@ public final class WidgetViewsFactory {
rv.setTextViewText(R.id.time_total, total);
rv.setProgressBar(R.id.progress, PROGRESS_MAX, safeProgress, false);
applySecondaryControls(ctx, rv, showSecondaryControls, shuffleEnabled, repeatMode);
return rv;
}
private static Bitmap maybeRoundBitmap(Context ctx, Bitmap source) {
if (source == null || source.isRecycled()) {
return null;
}
try {
int width = source.getWidth();
int height = source.getHeight();
if (width <= 0 || height <= 0) {
return null;
}
Bitmap output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
float radiusPx = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
ALBUM_ART_CORNER_RADIUS_DP,
ctx.getResources().getDisplayMetrics());
float maxRadius = Math.min(width, height) / 2f;
float safeRadius = Math.min(radiusPx, maxRadius);
canvas.drawRoundRect(new RectF(0f, 0f, width, height), safeRadius, safeRadius, paint);
return output;
} catch (RuntimeException | OutOfMemoryError e) {
android.util.Log.w("TempoWidget", "Failed to round album art", e);
return null;
}
}
private static void applySecondaryControls(Context ctx,
RemoteViews rv,
boolean show,
boolean shuffleEnabled,
int repeatMode) {
if (!show) {
rv.setViewVisibility(R.id.controls_secondary, View.GONE);
rv.setViewVisibility(R.id.btn_shuffle, View.GONE);
rv.setViewVisibility(R.id.btn_repeat, View.GONE);
return;
}
int inactiveColor = ContextCompat.getColor(ctx, R.color.widget_icon_tint);
int activeColor = ContextCompat.getColor(ctx, R.color.widget_icon_tint_active);
rv.setViewVisibility(R.id.controls_secondary, View.VISIBLE);
rv.setViewVisibility(R.id.btn_shuffle, View.VISIBLE);
rv.setViewVisibility(R.id.btn_repeat, View.VISIBLE);
rv.setImageViewResource(R.id.btn_shuffle, R.drawable.ic_shuffle);
rv.setImageViewResource(R.id.btn_repeat,
repeatMode == Player.REPEAT_MODE_ONE ? R.drawable.ic_repeat_one : R.drawable.ic_repeat);
rv.setInt(R.id.btn_shuffle, "setColorFilter", shuffleEnabled ? activeColor : inactiveColor);
rv.setInt(R.id.btn_repeat, "setColorFilter",
repeatMode == Player.REPEAT_MODE_OFF ? inactiveColor : activeColor);
}
}

View file

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/titleTextColor"
android:pathData="M7,7h10v3l4,-4 -4,-4v3L5,5v6h2L7,7zM17,17H7v-3l-4,4 4,4v-3h12v-6h-2v4z" />
<path
android:fillColor="@color/titleTextColor"
android:pathData="M12,9h-2v2h1v6h2V9h-1z" />
</vector>

View file

@ -3,13 +3,17 @@
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="64dp"
android:padding="8dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:background="@drawable/widget_bg">
<ImageView
android:id="@+id/album_art"
android:layout_width="56dp"
android:layout_height="match_parent"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:scaleType="centerCrop"
android:contentDescription="@string/widget_content_desc_album_art"/>
@ -32,6 +36,8 @@
android:textStyle="bold"
android:textSize="14sp"
android:textColor="@color/widget_title"
android:includeFontPadding="false"
android:freezesText="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
@ -41,15 +47,30 @@
android:ellipsize="end"
android:textSize="12sp"
android:textColor="@color/widget_subtitle"
android:includeFontPadding="false"
android:freezesText="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/album"
android:maxLines="1"
android:ellipsize="end"
android:textSize="11sp"
android:textColor="@color/widget_subtitle"
android:includeFontPadding="false"
android:freezesText="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:visibility="gone"/>
<ProgressBar
android:id="@+id/progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="4dp"
android:layout_marginTop="4dp"
android:layout_height="2dp"
android:layout_marginTop="2dp"
android:indeterminate="false"
android:max="1000"
android:progress="0"
@ -70,7 +91,8 @@
android:layout_weight="1"
android:text="@string/widget_time_elapsed_placeholder"
android:textColor="@color/widget_subtitle"
android:textSize="11sp"/>
android:textSize="10sp"
android:includeFontPadding="false"/>
<TextView
android:id="@+id/time_total"
@ -80,7 +102,37 @@
android:gravity="end"
android:text="@string/widget_time_duration_placeholder"
android:textColor="@color/widget_subtitle"
android:textSize="11sp"/>
android:textSize="10sp"
android:includeFontPadding="false"/>
</LinearLayout>
<LinearLayout
android:id="@+id/controls_secondary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_marginTop="4dp"
android:visibility="gone">
<ImageButton
android:id="@+id/btn_shuffle"
android:layout_width="36dp"
android:layout_height="36dp"
android:background="@android:color/transparent"
android:contentDescription="@string/widget_content_desc_shuffle"
android:src="@drawable/ic_shuffle"
android:tint="@color/widget_icon_tint"/>
<ImageButton
android:id="@+id/btn_repeat"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginStart="4dp"
android:background="@android:color/transparent"
android:contentDescription="@string/widget_content_desc_repeat"
android:src="@drawable/ic_repeat"
android:tint="@color/widget_icon_tint"/>
</LinearLayout>
</LinearLayout>
@ -93,22 +145,28 @@
android:layout_width="wrap_content"
android:layout_height="match_parent">
<ImageButton android:id="@+id/btn_prev"
android:layout_width="48dp" android:layout_height="48dp"
<ImageButton
android:id="@+id/btn_prev"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="@android:color/transparent"
android:src="@drawable/ic_skip_previous"
android:contentDescription="@string/widget_content_desc_prev"
android:tint="@color/widget_icon_tint"/>
<ImageButton android:id="@+id/btn_play_pause"
android:layout_width="48dp" android:layout_height="48dp"
<ImageButton
android:id="@+id/btn_play_pause"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="@android:color/transparent"
android:src="@drawable/ic_play"
android:contentDescription="@string/widget_content_desc_play_pause"
android:tint="@color/widget_icon_tint"/>
<ImageButton android:id="@+id/btn_next"
android:layout_width="48dp" android:layout_height="48dp"
<ImageButton
android:id="@+id/btn_next"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="@android:color/transparent"
android:src="@drawable/ic_skip_next"
android:contentDescription="@string/widget_content_desc_next"

View file

@ -1,117 +1,189 @@
<?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"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="112dp"
android:padding="12dp"
android:layout_height="match_parent"
android:minHeight="200dp"
android:orientation="vertical"
android:padding="16dp"
android:background="@drawable/widget_bg">
<ImageView
android:id="@+id/album_art"
android:layout_width="96dp"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:contentDescription="@string/widget_content_desc_album_art"/>
<LinearLayout
android:id="@+id/texts"
android:orientation="vertical"
android:layout_toRightOf="@id/album_art"
android:layout_toEndOf="@id/album_art"
android:layout_toLeftOf="@id/controls"
android:layout_toStartOf="@id/controls"
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="12dp">
android:orientation="horizontal"
android:baselineAligned="false">
<TextView
android:id="@+id/title"
android:maxLines="2"
android:ellipsize="end"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/widget_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/subtitle"
android:maxLines="1"
android:ellipsize="end"
android:textSize="13sp"
android:textColor="@color/widget_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ProgressBar
android:id="@+id/progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="4dp"
android:layout_marginTop="6dp"
android:indeterminate="false"
android:max="1000"
android:progress="0"
android:progressBackgroundTint="@color/widget_subtitle"
android:progressTint="@color/widget_icon_tint"/>
<ImageView
android:id="@+id/album_art"
android:layout_width="150dp"
android:layout_height="150dp"
android:scaleType="centerCrop"
android:contentDescription="@string/widget_content_desc_album_art" />
<LinearLayout
android:id="@+id/timing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:orientation="horizontal">
android:id="@+id/text_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center_vertical">
<TextView
android:id="@+id/time_elapsed"
android:layout_width="0dp"
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/widget_time_elapsed_placeholder"
android:textColor="@color/widget_subtitle"
android:textSize="12sp"/>
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:textStyle="bold"
android:textSize="18sp"
android:textColor="@color/widget_title"
android:includeFontPadding="false"
android:freezesText="true" />
<TextView
android:id="@+id/time_total"
android:layout_width="0dp"
android:id="@+id/subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:text="@string/widget_time_duration_placeholder"
android:layout_marginTop="6dp"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:textSize="14sp"
android:textColor="@color/widget_subtitle"
android:textSize="12sp"/>
android:includeFontPadding="false"
android:freezesText="true" />
<TextView
android:id="@+id/album"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:textSize="13sp"
android:textColor="@color/widget_subtitle"
android:includeFontPadding="false"
android:freezesText="true"
android:visibility="invisible" />
</LinearLayout>
</LinearLayout>
<ProgressBar
android:id="@+id/progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="6dp"
android:layout_marginTop="16dp"
android:indeterminate="false"
android:max="1000"
android:progress="0"
android:progressBackgroundTint="@color/widget_subtitle"
android:progressTint="@color/widget_icon_tint" />
<LinearLayout
android:id="@+id/timing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:orientation="horizontal">
<TextView
android:id="@+id/time_elapsed"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/widget_time_elapsed_placeholder"
android:textColor="@color/widget_subtitle"
android:textSize="12sp" />
<TextView
android:id="@+id/time_total"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:text="@string/widget_time_duration_placeholder"
android:textColor="@color/widget_subtitle"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/controls"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginBottom="4dp"
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="match_parent">
android:orientation="horizontal">
<ImageButton android:id="@+id/btn_prev"
android:layout_width="44dp" android:layout_height="44dp"
<ImageButton
android:id="@+id/btn_prev"
android:layout_width="0dp"
android:layout_height="52dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:src="@drawable/ic_skip_previous"
android:contentDescription="@string/widget_content_desc_prev"
android:tint="@color/widget_icon_tint"/>
android:src="@drawable/ic_skip_previous"
android:tint="@color/widget_icon_tint" />
<ImageButton android:id="@+id/btn_play_pause"
android:layout_width="48dp" android:layout_height="48dp"
<ImageButton
android:id="@+id/btn_play_pause"
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:src="@drawable/ic_play"
android:contentDescription="@string/widget_content_desc_play_pause"
android:tint="@color/widget_icon_tint"/>
android:src="@drawable/ic_play"
android:tint="@color/widget_icon_tint" />
<ImageButton android:id="@+id/btn_next"
android:layout_width="44dp" android:layout_height="44dp"
<ImageButton
android:id="@+id/btn_next"
android:layout_width="0dp"
android:layout_height="52dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:src="@drawable/ic_skip_next"
android:contentDescription="@string/widget_content_desc_next"
android:tint="@color/widget_icon_tint"/>
android:src="@drawable/ic_skip_next"
android:tint="@color/widget_icon_tint" />
</LinearLayout>
</RelativeLayout>
<LinearLayout
android:id="@+id/controls_secondary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<ImageButton
android:id="@+id/btn_shuffle"
android:layout_width="0dp"
android:layout_height="44dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:contentDescription="@string/widget_content_desc_shuffle"
android:src="@drawable/ic_shuffle"
android:tint="@color/widget_icon_tint" />
<ImageButton
android:id="@+id/btn_repeat"
android:layout_width="0dp"
android:layout_height="44dp"
android:layout_marginStart="6dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:contentDescription="@string/widget_content_desc_repeat"
android:src="@drawable/ic_repeat"
android:tint="@color/widget_icon_tint" />
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,198 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="172dp"
android:padding="16dp"
android:orientation="vertical"
android:background="@drawable/widget_bg">
<LinearLayout
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:baselineAligned="false"
android:gravity="center_vertical">
<FrameLayout
android:id="@+id/album_art_container"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_gravity="center_vertical">
<ImageView
android:id="@+id/album_art"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:contentDescription="@string/widget_content_desc_album_art" />
</FrameLayout>
<LinearLayout
android:id="@+id/text_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center_vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:textStyle="bold"
android:textSize="18sp"
android:textColor="@color/widget_title"
android:includeFontPadding="false"
android:freezesText="true" />
<TextView
android:id="@+id/subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:textSize="14sp"
android:textColor="@color/widget_subtitle"
android:includeFontPadding="false"
android:freezesText="true" />
<TextView
android:id="@+id/album"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:textSize="13sp"
android:textColor="@color/widget_subtitle"
android:includeFontPadding="false"
android:freezesText="true"
android:visibility="invisible" />
</LinearLayout>
</LinearLayout>
<ProgressBar
android:id="@+id/progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="6dp"
android:layout_marginTop="12dp"
android:indeterminate="false"
android:max="1000"
android:progress="0"
android:progressBackgroundTint="@color/widget_subtitle"
android:progressTint="@color/widget_icon_tint" />
<LinearLayout
android:id="@+id/timing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:orientation="horizontal">
<TextView
android:id="@+id/time_elapsed"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/widget_time_elapsed_placeholder"
android:textColor="@color/widget_subtitle"
android:textSize="12sp" />
<TextView
android:id="@+id/time_total"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:text="@string/widget_time_duration_placeholder"
android:textColor="@color/widget_subtitle"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/controls_secondary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<ImageButton
android:id="@+id/btn_shuffle"
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:contentDescription="@string/widget_content_desc_shuffle"
android:src="@drawable/ic_shuffle"
android:tint="@color/widget_icon_tint" />
<LinearLayout
android:id="@+id/controls"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:layout_weight="3"
android:gravity="center"
android:orientation="horizontal">
<ImageButton
android:id="@+id/btn_prev"
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:contentDescription="@string/widget_content_desc_prev"
android:src="@drawable/ic_skip_previous"
android:tint="@color/widget_icon_tint" />
<ImageButton
android:id="@+id/btn_play_pause"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:contentDescription="@string/widget_content_desc_play_pause"
android:src="@drawable/ic_play"
android:tint="@color/widget_icon_tint" />
<ImageButton
android:id="@+id/btn_next"
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:contentDescription="@string/widget_content_desc_next"
android:src="@drawable/ic_skip_next"
android:tint="@color/widget_icon_tint" />
</LinearLayout>
<ImageButton
android:id="@+id/btn_repeat"
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:contentDescription="@string/widget_content_desc_repeat"
android:src="@drawable/ic_repeat"
android:tint="@color/widget_icon_tint" />
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,216 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="120dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingTop="8dp"
android:paddingBottom="12dp"
android:orientation="horizontal"
android:baselineAligned="false"
android:background="@drawable/widget_bg">
<FrameLayout
android:id="@+id/album_art_container"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center_vertical">
<ImageView
android:id="@+id/album_art"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:contentDescription="@string/widget_content_desc_album_art" />
</FrameLayout>
<LinearLayout
android:id="@+id/content"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="12dp"
android:layout_weight="1"
android:orientation="vertical"
android:weightSum="1">
<LinearLayout
android:id="@+id/text_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/widget_title"
android:includeFontPadding="false"
android:freezesText="true" />
<LinearLayout
android:id="@+id/subtitle_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:baselineAligned="false">
<TextView
android:id="@+id/subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:textSize="13sp"
android:textColor="@color/widget_subtitle"
android:includeFontPadding="false"
android:freezesText="true" />
<TextView
android:id="@+id/album"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:gravity="end"
android:textAlignment="viewEnd"
android:textSize="12sp"
android:textColor="@color/widget_subtitle"
android:includeFontPadding="false"
android:freezesText="true"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
<ProgressBar
android:id="@+id/progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_marginTop="4dp"
android:indeterminate="false"
android:max="1000"
android:progress="0"
android:progressBackgroundTint="@color/widget_subtitle"
android:progressTint="@color/widget_icon_tint" />
<LinearLayout
android:id="@+id/timing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:orientation="horizontal">
<TextView
android:id="@+id/time_elapsed"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/widget_time_elapsed_placeholder"
android:textColor="@color/widget_subtitle"
android:textSize="10sp" />
<TextView
android:id="@+id/time_total"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:text="@string/widget_time_duration_placeholder"
android:textColor="@color/widget_subtitle"
android:textSize="10sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/controls_secondary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:gravity="center"
android:orientation="horizontal">
<ImageButton
android:id="@+id/btn_shuffle"
android:layout_width="0dp"
android:layout_height="32dp"
android:layout_marginEnd="1dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:contentDescription="@string/widget_content_desc_shuffle"
android:src="@drawable/ic_shuffle"
android:tint="@color/widget_icon_tint" />
<LinearLayout
android:id="@+id/controls"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:gravity="center"
android:orientation="horizontal">
<ImageButton
android:id="@+id/btn_prev"
android:layout_width="0dp"
android:layout_height="32dp"
android:layout_marginStart="1dp"
android:layout_marginEnd="1dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:contentDescription="@string/widget_content_desc_prev"
android:src="@drawable/ic_skip_previous"
android:tint="@color/widget_icon_tint" />
<ImageButton
android:id="@+id/btn_play_pause"
android:layout_width="0dp"
android:layout_height="34dp"
android:layout_marginStart="1dp"
android:layout_marginEnd="1dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:contentDescription="@string/widget_content_desc_play_pause"
android:src="@drawable/ic_play"
android:tint="@color/widget_icon_tint" />
<ImageButton
android:id="@+id/btn_next"
android:layout_width="0dp"
android:layout_height="32dp"
android:layout_marginStart="1dp"
android:layout_marginEnd="1dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:contentDescription="@string/widget_content_desc_next"
android:src="@drawable/ic_skip_next"
android:tint="@color/widget_icon_tint" />
</LinearLayout>
<ImageButton
android:id="@+id/btn_repeat"
android:layout_width="0dp"
android:layout_height="32dp"
android:layout_marginStart="1dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:contentDescription="@string/widget_content_desc_repeat"
android:src="@drawable/ic_repeat"
android:tint="@color/widget_icon_tint" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View file

@ -11,8 +11,9 @@
<ImageView
android:id="@+id/album_art"
android:layout_width="56dp"
android:layout_height="match_parent"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:scaleType="centerCrop"
android:src="@drawable/ic_splash_logo"
android:contentDescription="@string/widget_content_desc_album_art"/>
@ -79,4 +80,3 @@
android:contentDescription="@string/widget_content_desc_next"/>
</LinearLayout>
</RelativeLayout>

View file

@ -5,4 +5,5 @@
<color name="widget_title">#DE000000</color>
<color name="widget_subtitle">#99000000</color>
<color name="widget_icon_tint">#DE000000</color>
<color name="widget_icon_tint_active">#FF6750A4</color>
</resources>

View file

@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="widget_large_min_height_dp">100</integer>
<integer name="widget_medium_min_height_dp">100</integer>
<integer name="widget_large_min_height_dp">160</integer>
<integer name="widget_expanded_min_height_dp">220</integer>
</resources>

View file

@ -448,6 +448,8 @@
<string name="widget_content_desc_play_pause">Play or pause</string>
<string name="widget_content_desc_next">Next track</string>
<string name="widget_content_desc_prev">Previous track</string>
<string name="widget_content_desc_shuffle">Toggle shuffle</string>
<string name="widget_content_desc_repeat">Change repeat mode</string>
<plurals name="home_sync_starred_albums_count">
<item quantity="one">%d album to sync</item>
<item quantity="other">%d albums to sync</item>

View file

@ -416,6 +416,8 @@ class MediaService : MediaLibraryService() {
?: mi?.mediaMetadata?.extras?.getString("title")
val artist = mi?.mediaMetadata?.artist?.toString()
?: mi?.mediaMetadata?.extras?.getString("artist")
val album = mi?.mediaMetadata?.albumTitle?.toString()
?: mi?.mediaMetadata?.extras?.getString("album")
val coverId = mi?.mediaMetadata?.extras?.getString("coverArtId")
val position = player.currentPosition.takeIf { it != C.TIME_UNSET } ?: 0L
val duration = player.duration.takeIf { it != C.TIME_UNSET } ?: 0L
@ -423,8 +425,11 @@ class MediaService : MediaLibraryService() {
this,
title ?: "",
artist ?: "",
album ?: "",
coverId,
player.isPlaying,
player.shuffleModeEnabled,
player.repeatMode,
position,
duration
)

View file

@ -262,6 +262,8 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
?: mi?.mediaMetadata?.extras?.getString("title")
val artist = mi?.mediaMetadata?.artist?.toString()
?: mi?.mediaMetadata?.extras?.getString("artist")
val album = mi?.mediaMetadata?.albumTitle?.toString()
?: mi?.mediaMetadata?.extras?.getString("album")
val coverId = mi?.mediaMetadata?.extras?.getString("coverArtId")
val position = player.currentPosition.takeIf { it != C.TIME_UNSET } ?: 0L
@ -270,8 +272,11 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
this,
title ?: "",
artist ?: "",
album ?: "",
coverId,
player.isPlaying,
player.shuffleModeEnabled,
player.repeatMode,
position,
duration
)

View file

@ -262,6 +262,8 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
?: mi?.mediaMetadata?.extras?.getString("title")
val artist = mi?.mediaMetadata?.artist?.toString()
?: mi?.mediaMetadata?.extras?.getString("artist")
val album = mi?.mediaMetadata?.albumTitle?.toString()
?: mi?.mediaMetadata?.extras?.getString("album")
val coverId = mi?.mediaMetadata?.extras?.getString("coverArtId")
val position = player.currentPosition.takeIf { it != C.TIME_UNSET } ?: 0L
val duration = player.duration.takeIf { it != C.TIME_UNSET } ?: 0L
@ -269,8 +271,11 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
this,
title ?: "",
artist ?: "",
album ?: "",
coverId,
player.isPlaying,
player.shuffleModeEnabled,
player.repeatMode,
position,
duration
)