diff options
author | ByteHamster <info@bytehamster.com> | 2020-02-13 12:42:26 +0100 |
---|---|---|
committer | ByteHamster <info@bytehamster.com> | 2020-02-13 12:42:26 +0100 |
commit | b39dc02109721f97bded7267e00ca8a06e4d9798 (patch) | |
tree | b15ef5f4435c23211df2146246afeeeb4926837d /core/src | |
parent | fe632a4f9f5dd5aa9ed8e54f42aa1496ce08f480 (diff) | |
parent | f951d6362c4728a2378bb314d77f964010691e3c (diff) | |
download | AntennaPod-b39dc02109721f97bded7267e00ca8a06e4d9798.zip |
Merge remote-tracking branch 'upstream/develop' into player-screen-update
Diffstat (limited to 'core/src')
108 files changed, 922 insertions, 702 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java index f3dfdfdb6..08a531d17 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java @@ -6,81 +6,92 @@ import de.danoeh.antennapod.core.storage.PodDBAdapter; public abstract class Chapter extends FeedComponent { - /** Defines starting point in milliseconds. */ + /** Defines starting point in milliseconds. */ long start; - String title; - String link; - - Chapter() { - } - - Chapter(long start) { - super(); - this.start = start; - } - - Chapter(long start, String title, FeedItem item, String link) { - super(); - this.start = start; - this.title = title; - this.link = link; - } - - public static Chapter fromCursor(Cursor cursor, FeedItem item) { - int indexId = cursor.getColumnIndex(PodDBAdapter.KEY_ID); - int indexTitle = cursor.getColumnIndex(PodDBAdapter.KEY_TITLE); - int indexStart = cursor.getColumnIndex(PodDBAdapter.KEY_START); - int indexLink = cursor.getColumnIndex(PodDBAdapter.KEY_LINK); - int indexChapterType = cursor.getColumnIndex(PodDBAdapter.KEY_CHAPTER_TYPE); - - long id = cursor.getLong(indexId); - String title = cursor.getString(indexTitle); - long start = cursor.getLong(indexStart); - String link = cursor.getString(indexLink); - int chapterType = cursor.getInt(indexChapterType); - - Chapter chapter = null; - switch (chapterType) { - case SimpleChapter.CHAPTERTYPE_SIMPLECHAPTER: - chapter = new SimpleChapter(start, title, item, link); - break; - case ID3Chapter.CHAPTERTYPE_ID3CHAPTER: - chapter = new ID3Chapter(start, title, item, link); - break; - case VorbisCommentChapter.CHAPTERTYPE_VORBISCOMMENT_CHAPTER: - chapter = new VorbisCommentChapter(start, title, item, link); - break; - } - chapter.setId(id); - return chapter; - } - - - public abstract int getChapterType(); - - public long getStart() { - return start; - } - - public String getTitle() { - return title; - } - - public String getLink() { - return link; - } - - public void setStart(long start) { - this.start = start; - } - - public void setTitle(String title) { - this.title = title; - } - - public void setLink(String link) { - this.link = link; - } + String title; + String link; + String imageUrl; + + Chapter() { + } + + Chapter(long start) { + super(); + this.start = start; + } + + Chapter(long start, String title, String link, String imageUrl) { + super(); + this.start = start; + this.title = title; + this.link = link; + this.imageUrl = imageUrl; + } + + public static Chapter fromCursor(Cursor cursor) { + int indexId = cursor.getColumnIndex(PodDBAdapter.KEY_ID); + int indexTitle = cursor.getColumnIndex(PodDBAdapter.KEY_TITLE); + int indexStart = cursor.getColumnIndex(PodDBAdapter.KEY_START); + int indexLink = cursor.getColumnIndex(PodDBAdapter.KEY_LINK); + int indexImage = cursor.getColumnIndex(PodDBAdapter.KEY_IMAGE_URL); + int indexChapterType = cursor.getColumnIndex(PodDBAdapter.KEY_CHAPTER_TYPE); + + long id = cursor.getLong(indexId); + String title = cursor.getString(indexTitle); + long start = cursor.getLong(indexStart); + String link = cursor.getString(indexLink); + String imageUrl = cursor.getString(indexImage); + int chapterType = cursor.getInt(indexChapterType); + + Chapter chapter = null; + switch (chapterType) { + case SimpleChapter.CHAPTERTYPE_SIMPLECHAPTER: + chapter = new SimpleChapter(start, title, link, imageUrl); + break; + case ID3Chapter.CHAPTERTYPE_ID3CHAPTER: + chapter = new ID3Chapter(start, title, link, imageUrl); + break; + case VorbisCommentChapter.CHAPTERTYPE_VORBISCOMMENT_CHAPTER: + chapter = new VorbisCommentChapter(start, title, link, imageUrl); + break; + } + chapter.setId(id); + return chapter; + } + + public abstract int getChapterType(); + + public long getStart() { + return start; + } + + public String getTitle() { + return title; + } + + public String getLink() { + return link; + } + + public void setStart(long start) { + this.start = start; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setLink(String link) { + this.link = link; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } @Override public String getHumanReadableIdentifier() { diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/ID3Chapter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/ID3Chapter.java index f0ff03a93..b69d537fb 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/ID3Chapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/ID3Chapter.java @@ -1,36 +1,36 @@ package de.danoeh.antennapod.core.feed; public class ID3Chapter extends Chapter { - public static final int CHAPTERTYPE_ID3CHAPTER = 2; - - /** - * Identifies the chapter in its ID3 tag. This attribute does not have to be - * store in the DB and is only used for parsing. - */ - private String id3ID; - - public ID3Chapter(String id3ID, long start) { - super(start); - this.id3ID = id3ID; - } - - public ID3Chapter(long start, String title, FeedItem item, String link) { - super(start, title, item, link); - } - - @Override - public String toString() { - return "ID3Chapter [id3ID=" + id3ID + ", title=" + title + ", start=" - + start + ", url=" + link + "]"; - } - - @Override - public int getChapterType() { - return CHAPTERTYPE_ID3CHAPTER; - } - - public String getId3ID() { - return id3ID; - } + public static final int CHAPTERTYPE_ID3CHAPTER = 2; + + /** + * Identifies the chapter in its ID3 tag. This attribute does not have to be + * store in the DB and is only used for parsing. + */ + private String id3ID; + + public ID3Chapter(String id3ID, long start) { + super(start); + this.id3ID = id3ID; + } + + public ID3Chapter(long start, String title, String link, String imageUrl) { + super(start, title, link, imageUrl); + } + + @Override + public String toString() { + return "ID3Chapter [id3ID=" + id3ID + ", title=" + title + ", start=" + + start + ", url=" + link + "]"; + } + + @Override + public int getChapterType() { + return CHAPTERTYPE_ID3CHAPTER; + } + + public String getId3ID() { + return id3ID; + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/SimpleChapter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/SimpleChapter.java index 2dadd3ec8..45c71a014 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/SimpleChapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/SimpleChapter.java @@ -1,25 +1,14 @@ package de.danoeh.antennapod.core.feed; public class SimpleChapter extends Chapter { - public static final int CHAPTERTYPE_SIMPLECHAPTER = 0; - - public SimpleChapter(long start, String title, FeedItem item, String link) { - super(start, title, item, link); - } + public static final int CHAPTERTYPE_SIMPLECHAPTER = 0; - @Override - public int getChapterType() { - return CHAPTERTYPE_SIMPLECHAPTER; - } + public SimpleChapter(long start, String title, String link, String imageUrl) { + super(start, title, link, imageUrl); + } - public void updateFromOther(SimpleChapter other) { - super.updateFromOther(other); - start = other.start; - if (other.title != null) { - title = other.title; - } - if (other.link != null) { - link = other.link; - } - } + @Override + public int getChapterType() { + return CHAPTERTYPE_SIMPLECHAPTER; + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/VorbisCommentChapter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/VorbisCommentChapter.java index 5ab9868a6..eac50aed8 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/VorbisCommentChapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/VorbisCommentChapter.java @@ -5,105 +5,84 @@ import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.core.util.vorbiscommentreader.VorbisCommentReaderException; public class VorbisCommentChapter extends Chapter { - public static final int CHAPTERTYPE_VORBISCOMMENT_CHAPTER = 3; - - private static final int CHAPTERXXX_LENGTH = "chapterxxx".length(); - - private int vorbisCommentId; - - public VorbisCommentChapter(int vorbisCommentId) { - this.vorbisCommentId = vorbisCommentId; - } - - public VorbisCommentChapter(long start, String title, FeedItem item, - String link) { - super(start, title, item, link); - } - - @Override - public String toString() { - return "VorbisCommentChapter [id=" + id + ", title=" + title - + ", link=" + link + ", start=" + start + "]"; - } - - public static long getStartTimeFromValue(String value) - throws VorbisCommentReaderException { - String[] parts = value.split(":"); - if (parts.length >= 3) { - try { - long hours = TimeUnit.MILLISECONDS.convert( - Long.parseLong(parts[0]), TimeUnit.HOURS); - long minutes = TimeUnit.MILLISECONDS.convert( - Long.parseLong(parts[1]), TimeUnit.MINUTES); - if (parts[2].contains("-->")) { - parts[2] = parts[2].substring(0, parts[2].indexOf("-->")); - } - long seconds = TimeUnit.MILLISECONDS.convert( - ((long) Float.parseFloat(parts[2])), TimeUnit.SECONDS); - return hours + minutes + seconds; - } catch (NumberFormatException e) { - throw new VorbisCommentReaderException(e); - } - } else { - throw new VorbisCommentReaderException("Invalid time string"); - } - } - - /** - * Return the id of a vorbiscomment chapter from a string like CHAPTERxxx* - * - * @return the id of the chapter key or -1 if the id couldn't be read. - * @throws VorbisCommentReaderException - * */ - public static int getIDFromKey(String key) - throws VorbisCommentReaderException { - if (key.length() >= CHAPTERXXX_LENGTH) { // >= CHAPTERxxx - try { - String strId = key.substring(8, 10); - return Integer.parseInt(strId); - } catch (NumberFormatException e) { - throw new VorbisCommentReaderException(e); - } - } - throw new VorbisCommentReaderException("key is too short (" + key + ")"); - } - - /** - * Get the string that comes after 'CHAPTERxxx', for example 'name' or - * 'url'. - */ - public static String getAttributeTypeFromKey(String key) { - if (key.length() > CHAPTERXXX_LENGTH) { - return key.substring(CHAPTERXXX_LENGTH, key.length()); - } - return null; - } - - @Override - public int getChapterType() { - return CHAPTERTYPE_VORBISCOMMENT_CHAPTER; - } - - public void setTitle(String title) { - this.title = title; - } - - public void setLink(String link) { - this.link = link; - } - - public void setStart(long start) { - this.start = start; - } - - public int getVorbisCommentId() { - return vorbisCommentId; - } - - public void setVorbisCommentId(int vorbisCommentId) { - this.vorbisCommentId = vorbisCommentId; - } - - - + public static final int CHAPTERTYPE_VORBISCOMMENT_CHAPTER = 3; + + private static final int CHAPTERXXX_LENGTH = "chapterxxx".length(); + + private int vorbisCommentId; + + public VorbisCommentChapter(int vorbisCommentId) { + this.vorbisCommentId = vorbisCommentId; + } + + public VorbisCommentChapter(long start, String title, String link, String imageUrl) { + super(start, title, link, imageUrl); + } + + @Override + public String toString() { + return "VorbisCommentChapter [id=" + id + ", title=" + title + + ", link=" + link + ", start=" + start + "]"; + } + + public static long getStartTimeFromValue(String value) + throws VorbisCommentReaderException { + String[] parts = value.split(":"); + if (parts.length >= 3) { + try { + long hours = TimeUnit.MILLISECONDS.convert( + Long.parseLong(parts[0]), TimeUnit.HOURS); + long minutes = TimeUnit.MILLISECONDS.convert( + Long.parseLong(parts[1]), TimeUnit.MINUTES); + if (parts[2].contains("-->")) { + parts[2] = parts[2].substring(0, parts[2].indexOf("-->")); + } + long seconds = TimeUnit.MILLISECONDS.convert( + ((long) Float.parseFloat(parts[2])), TimeUnit.SECONDS); + return hours + minutes + seconds; + } catch (NumberFormatException e) { + throw new VorbisCommentReaderException(e); + } + } else { + throw new VorbisCommentReaderException("Invalid time string"); + } + } + + /** + * Return the id of a vorbiscomment chapter from a string like CHAPTERxxx* + * + * @return the id of the chapter key or -1 if the id couldn't be read. + * @throws VorbisCommentReaderException + * */ + public static int getIDFromKey(String key) throws VorbisCommentReaderException { + if (key.length() >= CHAPTERXXX_LENGTH) { // >= CHAPTERxxx + try { + String strId = key.substring(8, 10); + return Integer.parseInt(strId); + } catch (NumberFormatException e) { + throw new VorbisCommentReaderException(e); + } + } + throw new VorbisCommentReaderException("key is too short (" + key + ")"); + } + + /** + * Get the string that comes after 'CHAPTERxxx', for example 'name' or + * 'url'. + */ + public static String getAttributeTypeFromKey(String key) { + if (key.length() > CHAPTERXXX_LENGTH) { + return key.substring(CHAPTERXXX_LENGTH); + } + return null; + } + + @Override + public int getChapterType() { + return CHAPTERTYPE_VORBISCOMMENT_CHAPTER; + } + + public int getVorbisCommentId() { + return vorbisCommentId; + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java b/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java index b2c809e90..50511526f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java +++ b/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java @@ -11,10 +11,12 @@ import com.bumptech.glide.load.DecodeFormat; import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory; import com.bumptech.glide.module.AppGlideModule; +import de.danoeh.antennapod.core.util.EmbeddedChapterImage; import java.io.InputStream; import com.bumptech.glide.request.RequestOptions; import de.danoeh.antennapod.core.preferences.UserPreferences; +import java.nio.ByteBuffer; /** * {@see com.bumptech.glide.integration.okhttp.OkHttpGlideModule} @@ -32,5 +34,6 @@ public class ApGlideModule extends AppGlideModule { @Override public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) { registry.replace(String.class, InputStream.class, new ApOkHttpUrlLoader.Factory()); + registry.append(EmbeddedChapterImage.class, ByteBuffer.class, new ChapterImageModelLoader.Factory()); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java b/core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java new file mode 100644 index 000000000..bc0a06a07 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java @@ -0,0 +1,111 @@ +package de.danoeh.antennapod.core.glide; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.bumptech.glide.Priority; +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.Options; +import com.bumptech.glide.load.data.DataFetcher; +import com.bumptech.glide.load.model.ModelLoader; +import com.bumptech.glide.load.model.ModelLoaderFactory; +import com.bumptech.glide.load.model.MultiModelLoaderFactory; +import com.bumptech.glide.signature.ObjectKey; +import de.danoeh.antennapod.core.ClientConfig; +import de.danoeh.antennapod.core.feed.Chapter; +import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; +import de.danoeh.antennapod.core.util.EmbeddedChapterImage; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.nio.ByteBuffer; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.apache.commons.io.IOUtils; + +public final class ChapterImageModelLoader implements ModelLoader<EmbeddedChapterImage, ByteBuffer> { + + public static class Factory implements ModelLoaderFactory<EmbeddedChapterImage, ByteBuffer> { + @Override + public ModelLoader<EmbeddedChapterImage, ByteBuffer> build(MultiModelLoaderFactory unused) { + return new ChapterImageModelLoader(); + } + + @Override + public void teardown() { + // Do nothing. + } + } + + @Nullable + @Override + public LoadData<ByteBuffer> buildLoadData(EmbeddedChapterImage model, int width, int height, Options options) { + return new LoadData<>(new ObjectKey(model), new EmbeddedImageFetcher(model)); + } + + @Override + public boolean handles(EmbeddedChapterImage model) { + return true; + } + + static class EmbeddedImageFetcher implements DataFetcher<ByteBuffer> { + private final EmbeddedChapterImage image; + + public EmbeddedImageFetcher(EmbeddedChapterImage image) { + this.image = image; + } + + @Override + public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super ByteBuffer> callback) { + + BufferedInputStream stream = null; + try { + if (image.getMedia().localFileAvailable()) { + File localFile = new File(image.getMedia().getLocalMediaUrl()); + stream = new BufferedInputStream(new FileInputStream(localFile)); + stream.skip(image.getPosition()); + byte[] imageContent = new byte[image.getLength()]; + stream.read(imageContent, 0, image.getLength()); + callback.onDataReady(ByteBuffer.wrap(imageContent)); + } else { + Request.Builder httpReq = new Request.Builder(); + httpReq.header("User-Agent", ClientConfig.USER_AGENT); + // Skipping would download the whole file + httpReq.header("Range", "bytes=" + image.getPosition() + + "-" + (image.getPosition() + image.getLength())); + httpReq.url(image.getMedia().getStreamUrl()); + Response response = AntennapodHttpClient.getHttpClient().newCall(httpReq.build()).execute(); + if (!response.isSuccessful() || response.body() == null) { + throw new IOException("Invalid response: " + response.code() + " " + response.message()); + } + callback.onDataReady(ByteBuffer.wrap(response.body().bytes())); + } + } catch (IOException e) { + callback.onLoadFailed(e); + } finally { + IOUtils.closeQuietly(stream); + } + } + + @Override public void cleanup() { + // nothing to clean up + } + @Override public void cancel() { + // cannot cancel + } + + @NonNull + @Override + public Class<ByteBuffer> getDataClass() { + return ByteBuffer.class; + } + + @NonNull + @Override + public DataSource getDataSource() { + return DataSource.LOCAL; + } + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java b/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java index 3cc906b7f..d2d9e5947 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java +++ b/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java @@ -14,19 +14,15 @@ public class FastBlurTransformation extends BitmapTransformation { private static final String TAG = FastBlurTransformation.class.getSimpleName(); - private static final int STACK_BLUR_RADIUS = 1; - private static final int BLUR_IMAGE_WIDTH = 150; + private static final int STACK_BLUR_RADIUS = 5; public FastBlurTransformation() { super(); } @Override - protected Bitmap transform(BitmapPool pool, Bitmap source, - int outWidth, int outHeight) { - int targetWidth = BLUR_IMAGE_WIDTH; - int targetHeight = (int) (1.0 * outHeight * targetWidth / outWidth); - Bitmap resized = ThumbnailUtils.extractThumbnail(source, targetWidth, targetHeight); + protected Bitmap transform(BitmapPool pool, Bitmap source, int outWidth, int outHeight) { + Bitmap resized = ThumbnailUtils.extractThumbnail(source, outWidth / 3, outHeight / 3); Bitmap result = fastBlur(resized, STACK_BLUR_RADIUS); if (result == null) { Log.w(TAG, "result was null"); @@ -80,9 +76,9 @@ public class FastBlurTransformation extends BitmapTransformation { int wh = w * h; int div = radius + radius + 1; - int r[] = new int[wh]; - int g[] = new int[wh]; - int b[] = new int[wh]; + int[] r = new int[wh]; + int[] g = new int[wh]; + int[] b = new int[wh]; int rsum; int gsum; int bsum; @@ -93,11 +89,11 @@ public class FastBlurTransformation extends BitmapTransformation { int yp; int yi; int yw; - int vmin[] = new int[Math.max(w, h)]; + int[] vmin = new int[Math.max(w, h)]; int divsum = (div + 1) >> 1; divsum *= divsum; - int dv[] = new int[256 * divsum]; + int[] dv = new int[256 * divsum]; for (i = 0; i < 256 * divsum; i++) { dv[i] = (i / divsum); } @@ -225,8 +221,8 @@ public class FastBlurTransformation extends BitmapTransformation { yi = x; stackpointer = radius; for (y = 0; y < h; y++) { - // Preserve alpha channel: ( 0xff000000 & pix[yi] ) - pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum]; + // Set alpha to 1 + pix[yi] = 0xff000000 | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum]; rsum -= routsum; gsum -= goutsum; diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java b/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java index e6f2176f7..4562f1393 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java @@ -8,7 +8,6 @@ import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.graphics.Bitmap; -import android.os.Build; import android.os.Bundle; import android.os.IBinder; import androidx.annotation.NonNull; @@ -158,10 +157,10 @@ public class PlayerWidgetJobService extends SafeJobIntentService { } if (status == PlayerStatus.PLAYING) { - views.setImageViewResource(R.id.butPlay, R.drawable.ic_pause_white_24dp); + views.setImageViewResource(R.id.butPlay, R.drawable.ic_av_pause_white_48dp); views.setContentDescription(R.id.butPlay, getString(R.string.pause_label)); } else { - views.setImageViewResource(R.id.butPlay, R.drawable.ic_play_arrow_white_24dp); + views.setImageViewResource(R.id.butPlay, R.drawable.ic_av_play_white_48dp); views.setContentDescription(R.id.butPlay, getString(R.string.play_label)); } views.setOnClickPendingIntent(R.id.butPlay, createMediaButtonIntent()); @@ -177,7 +176,7 @@ public class PlayerWidgetJobService extends SafeJobIntentService { views.setViewVisibility(R.id.txtvTitle, View.GONE); views.setViewVisibility(R.id.txtNoPlaying, View.VISIBLE); views.setImageViewResource(R.id.imgvCover, R.mipmap.ic_launcher_foreground); - views.setImageViewResource(R.id.butPlay, R.drawable.ic_play_arrow_white_24dp); + views.setImageViewResource(R.id.butPlay, R.drawable.ic_av_play_white_48dp); } if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java index 4f4ee4721..e818f3072 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java @@ -795,9 +795,7 @@ public final class DBReader { } private static void loadChaptersOfFeedItem(PodDBAdapter adapter, FeedItem item) { - Cursor cursor = null; - try { - cursor = adapter.getSimpleChaptersOfFeedItemCursor(item); + try (Cursor cursor = adapter.getSimpleChaptersOfFeedItemCursor(item)) { int chaptersCount = cursor.getCount(); if (chaptersCount == 0) { item.setChapters(null); @@ -805,14 +803,7 @@ public final class DBReader { } item.setChapters(new ArrayList<>(chaptersCount)); while (cursor.moveToNext()) { - Chapter chapter = Chapter.fromCursor(cursor, item); - if (chapter != null) { - item.getChapters().add(chapter); - } - } - } finally { - if (cursor != null) { - cursor.close(); + item.getChapters().add(Chapter.fromCursor(cursor)); } } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java index 234ce8367..ee31c8cc4 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java @@ -95,7 +95,7 @@ class DBUpgrader { + " ADD COLUMN " + PodDBAdapter.KEY_PASSWORD + " TEXT"); db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS - + " ADD COLUMN " + PodDBAdapter.KEY_IMAGE + + " ADD COLUMN image" + " INTEGER"); } if (oldVersion <= 12) { @@ -280,13 +280,13 @@ class DBUpgrader { + " SELECT " + PodDBAdapter.KEY_DOWNLOAD_URL + " FROM " + PodDBAdapter.TABLE_NAME_FEED_IMAGES + " WHERE " + PodDBAdapter.TABLE_NAME_FEED_IMAGES + "." + PodDBAdapter.KEY_ID - + " = " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_IMAGE + ")"); + + " = " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + ".image)"); db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEEDS + " SET " + PodDBAdapter.KEY_IMAGE_URL + " = (" + " SELECT " + PodDBAdapter.KEY_DOWNLOAD_URL + " FROM " + PodDBAdapter.TABLE_NAME_FEED_IMAGES + " WHERE " + PodDBAdapter.TABLE_NAME_FEED_IMAGES + "." + PodDBAdapter.KEY_ID - + " = " + PodDBAdapter.TABLE_NAME_FEEDS + "." + PodDBAdapter.KEY_IMAGE + ")"); + + " = " + PodDBAdapter.TABLE_NAME_FEEDS + ".image)"); db.execSQL("DROP TABLE " + PodDBAdapter.TABLE_NAME_FEED_IMAGES); } @@ -301,6 +301,8 @@ class DBUpgrader { if (oldVersion < 1090000) { db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " + PodDBAdapter.KEY_FEED_VOLUME_ADAPTION + " INTEGER DEFAULT 0"); + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS + + " ADD COLUMN " + PodDBAdapter.KEY_IMAGE_URL + " TEXT DEFAULT NULL"); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java index 4e2588f22..af6a8ef81 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java @@ -69,7 +69,6 @@ public class PodDBAdapter { public static final String KEY_POSITION = "position"; public static final String KEY_SIZE = "filesize"; public static final String KEY_MIME_TYPE = "mime_type"; - public static final String KEY_IMAGE = "image"; public static final String KEY_IMAGE_URL = "image_url"; public static final String KEY_FEED = "feed"; public static final String KEY_MEDIA = "media"; @@ -183,7 +182,7 @@ public class PodDBAdapter { private static final String CREATE_TABLE_SIMPLECHAPTERS = "CREATE TABLE " + TABLE_NAME_SIMPLECHAPTERS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE + " TEXT," + KEY_START + " INTEGER," + KEY_FEEDITEM + " INTEGER," - + KEY_LINK + " TEXT," + KEY_CHAPTER_TYPE + " INTEGER)"; + + KEY_LINK + " TEXT," + KEY_IMAGE_URL + " TEXT," + KEY_CHAPTER_TYPE + " INTEGER)"; // SQL Statements for creating indexes static final String CREATE_INDEX_FEEDITEMS_FEED = "CREATE INDEX " @@ -674,6 +673,7 @@ public class PodDBAdapter { values.put(KEY_START, chapter.getStart()); values.put(KEY_FEEDITEM, item.getId()); values.put(KEY_LINK, chapter.getLink()); + values.put(KEY_IMAGE_URL, chapter.getImageUrl()); values.put(KEY_CHAPTER_TYPE, chapter.getChapterType()); if (chapter.getId() == 0) { chapter.setId(db.insert(TABLE_NAME_SIMPLECHAPTERS, null, values)); diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java index 45266569a..5761f37c8 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java @@ -22,12 +22,12 @@ public class NSSimpleChapters extends Namespace { private static final String START = "start"; private static final String TITLE = "title"; private static final String HREF = "href"; + private static final String IMAGE = "image"; @Override - public SyndElement handleElementStart(String localName, HandlerState state, - Attributes attributes) { + public SyndElement handleElementStart(String localName, HandlerState state, Attributes attributes) { FeedItem currentItem = state.getCurrentItem(); - if(currentItem != null) { + if (currentItem != null) { if (localName.equals(CHAPTERS)) { currentItem.setChapters(new ArrayList<>()); } else if (localName.equals(CHAPTER)) { @@ -35,7 +35,8 @@ public class NSSimpleChapters extends Namespace { long start = DateUtils.parseTimeString(attributes.getValue(START)); String title = attributes.getValue(TITLE); String link = attributes.getValue(HREF); - SimpleChapter chapter = new SimpleChapter(start, title, currentItem, link); + String imageUrl = attributes.getValue(IMAGE); + SimpleChapter chapter = new SimpleChapter(start, title, link, imageUrl); currentItem.getChapters().add(chapter); } catch (NumberFormatException e) { Log.e(TAG, "Unable to read chapter", e); diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java index 300e0038a..b75887154 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java @@ -4,6 +4,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import android.util.Log; +import java.util.zip.CheckedOutputStream; import org.apache.commons.io.IOUtils; import java.io.BufferedInputStream; @@ -23,6 +24,7 @@ import de.danoeh.antennapod.core.util.id3reader.ID3ReaderException; import de.danoeh.antennapod.core.util.playback.Playable; import de.danoeh.antennapod.core.util.vorbiscommentreader.VorbisCommentChapterReader; import de.danoeh.antennapod.core.util.vorbiscommentreader.VorbisCommentReaderException; +import org.apache.commons.io.input.CountingInputStream; /** * Utility class for getting chapter data from media files. @@ -34,24 +36,17 @@ public class ChapterUtils { private ChapterUtils() { } - @Nullable - public static Chapter getCurrentChapter(Playable media) { - if (media.getChapters() == null) { - return null; + public static int getCurrentChapterIndex(Playable media, int position) { + if (media == null || media.getChapters() == null || media.getChapters().size() == 0) { + return -1; } List<Chapter> chapters = media.getChapters(); - if (chapters == null) { - return null; - } - Chapter current = chapters.get(0); - for (Chapter sc : chapters) { - if (sc.getStart() > media.getPosition()) { - break; - } else { - current = sc; + for (int i = 0; i < chapters.size(); i++) { + if (chapters.get(i).getStart() > position) { + return i - 1; } } - return current; + return chapters.size() - 1; } public static void loadChaptersFromStreamUrl(Playable media) { @@ -82,13 +77,12 @@ public class ChapterUtils { return; } Log.d(TAG, "Reading id3 chapters from item " + p.getEpisodeTitle()); - InputStream in = null; + CountingInputStream in = null; try { URL url = new URL(p.getStreamUrl()); - - in = url.openStream(); + in = new CountingInputStream(url.openStream()); List<Chapter> chapters = readChaptersFrom(in); - if(!chapters.isEmpty()) { + if (!chapters.isEmpty()) { p.setChapters(chapters); } Log.i(TAG, "Chapters loaded"); @@ -114,9 +108,9 @@ public class ChapterUtils { return; } - InputStream in = null; + CountingInputStream in = null; try { - in = new BufferedInputStream(new FileInputStream(source)); + in = new CountingInputStream(new BufferedInputStream(new FileInputStream(source))); List<Chapter> chapters = readChaptersFrom(in); if (!chapters.isEmpty()) { p.setChapters(chapters); @@ -130,7 +124,7 @@ public class ChapterUtils { } @NonNull - private static List<Chapter> readChaptersFrom(InputStream in) throws IOException, ID3ReaderException { + private static List<Chapter> readChaptersFrom(CountingInputStream in) throws IOException, ID3ReaderException { ChapterReader reader = new ChapterReader(); reader.readInputStream(in); List<Chapter> chapters = reader.getChapters(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/EmbeddedChapterImage.java b/core/src/main/java/de/danoeh/antennapod/core/util/EmbeddedChapterImage.java new file mode 100644 index 000000000..deeba9238 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/util/EmbeddedChapterImage.java @@ -0,0 +1,73 @@ +package de.danoeh.antennapod.core.util; + +import android.text.TextUtils; +import de.danoeh.antennapod.core.util.playback.Playable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class EmbeddedChapterImage { + private static final Pattern EMBEDDED_IMAGE_MATCHER = Pattern.compile("embedded-image://(\\d+)/(\\d+)"); + + private final int position; + private final int length; + private final String imageUrl; + private final Playable media; + + public EmbeddedChapterImage(Playable media, String imageUrl) { + this.media = media; + this.imageUrl = imageUrl; + Matcher m = EMBEDDED_IMAGE_MATCHER.matcher(imageUrl); + if (m.find()) { + this.position = Integer.parseInt(m.group(1)); + this.length = Integer.parseInt(m.group(2)); + } else { + throw new IllegalArgumentException("Not an embedded chapter"); + } + } + + public static String makeUrl(int position, int length) { + return "embedded-image://" + position + "/" + length; + } + + public int getPosition() { + return position; + } + + public int getLength() { + return length; + } + + public Playable getMedia() { + return media; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + EmbeddedChapterImage that = (EmbeddedChapterImage) o; + return TextUtils.equals(imageUrl, that.imageUrl); + } + + @Override + public int hashCode() { + return imageUrl.hashCode(); + } + + private static boolean isEmbeddedChapterImage(String imageUrl) { + return EMBEDDED_IMAGE_MATCHER.matcher(imageUrl).matches(); + } + + public static Object getModelFor(Playable media, int chapter) { + String imageUrl = media.getChapters().get(chapter).getImageUrl(); + if (isEmbeddedChapterImage(imageUrl)) { + return new EmbeddedChapterImage(media, imageUrl); + } else { + return imageUrl; + } + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java index a3f747e09..ce3577a9e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ChapterReader.java @@ -1,124 +1,154 @@ package de.danoeh.antennapod.core.util.id3reader; +import android.text.TextUtils; import android.util.Log; import de.danoeh.antennapod.core.feed.Chapter; import de.danoeh.antennapod.core.feed.ID3Chapter; +import de.danoeh.antennapod.core.util.EmbeddedChapterImage; import de.danoeh.antennapod.core.util.id3reader.model.FrameHeader; import de.danoeh.antennapod.core.util.id3reader.model.TagHeader; import java.io.IOException; -import java.io.InputStream; import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; +import org.apache.commons.io.input.CountingInputStream; public class ChapterReader extends ID3Reader { private static final String TAG = "ID3ChapterReader"; - private static final String FRAME_ID_CHAPTER = "CHAP"; - private static final String FRAME_ID_TITLE = "TIT2"; + private static final String FRAME_ID_CHAPTER = "CHAP"; + private static final String FRAME_ID_TITLE = "TIT2"; private static final String FRAME_ID_LINK = "WXXX"; + private static final String FRAME_ID_PICTURE = "APIC"; + private static final int IMAGE_TYPE_COVER = 3; - private List<Chapter> chapters; - private ID3Chapter currentChapter; - - @Override - public int onStartTagHeader(TagHeader header) { - chapters = new ArrayList<>(); - Log.d(TAG, "header: " + header); - return ID3Reader.ACTION_DONT_SKIP; - } - - @Override - public int onStartFrameHeader(FrameHeader header, InputStream input) - throws IOException, ID3ReaderException { - Log.d(TAG, "header: " + header); - switch (header.getId()) { - case FRAME_ID_CHAPTER: - if (currentChapter != null) { - if (!hasId3Chapter(currentChapter)) { - chapters.add(currentChapter); - Log.d(TAG, "Found chapter: " + currentChapter); - currentChapter = null; - } - } - StringBuilder elementId = new StringBuilder(); - readISOString(elementId, input, Integer.MAX_VALUE); - char[] startTimeSource = readBytes(input, 4); - long startTime = ((int) startTimeSource[0] << 24) - | ((int) startTimeSource[1] << 16) - | ((int) startTimeSource[2] << 8) | startTimeSource[3]; - currentChapter = new ID3Chapter(elementId.toString(), startTime); - skipBytes(input, 12); - return ID3Reader.ACTION_DONT_SKIP; - case FRAME_ID_TITLE: - if (currentChapter != null && currentChapter.getTitle() == null) { - StringBuilder title = new StringBuilder(); - readString(title, input, header.getSize()); - currentChapter - .setTitle(title.toString()); - Log.d(TAG, "Found title: " + currentChapter.getTitle()); - - return ID3Reader.ACTION_DONT_SKIP; - } - break; - case FRAME_ID_LINK: - if (currentChapter != null) { - // skip description - int descriptionLength = readString(null, input, header.getSize()); - StringBuilder link = new StringBuilder(); - readISOString(link, input, header.getSize() - descriptionLength); - try { - String decodedLink = URLDecoder.decode(link.toString(), "UTF-8"); - currentChapter.setLink(decodedLink); - Log.d(TAG, "Found link: " + currentChapter.getLink()); - } catch (IllegalArgumentException iae) { - Log.w(TAG, "Bad URL found in ID3 data"); - } - - return ID3Reader.ACTION_DONT_SKIP; - } - break; - case "APIC": - Log.d(TAG, header.toString()); - break; - } - - return super.onStartFrameHeader(header, input); - } - - private boolean hasId3Chapter(ID3Chapter chapter) { - for (Chapter c : chapters) { - if (((ID3Chapter) c).getId3ID().equals(chapter.getId3ID())) { - return true; - } - } - return false; - } - - @Override - public void onEndTag() { - if (currentChapter != null) { - if (!hasId3Chapter(currentChapter)) { - chapters.add(currentChapter); - } - } - Log.d(TAG, "Reached end of tag"); - if (chapters != null) { - for (Chapter c : chapters) { - Log.d(TAG, "chapter: " + c); - } - } - } - - @Override - public void onNoTagHeaderFound() { - Log.d(TAG, "No tag header found"); - super.onNoTagHeaderFound(); - } - - public List<Chapter> getChapters() { - return chapters; - } + private List<Chapter> chapters; + private ID3Chapter currentChapter; + + @Override + public int onStartTagHeader(TagHeader header) { + chapters = new ArrayList<>(); + Log.d(TAG, "header: " + header); + return ID3Reader.ACTION_DONT_SKIP; + } + + @Override + public int onStartFrameHeader(FrameHeader header, CountingInputStream input) throws IOException, ID3ReaderException { + Log.d(TAG, "header: " + header); + switch (header.getId()) { + case FRAME_ID_CHAPTER: + if (currentChapter != null) { + if (!hasId3Chapter(currentChapter)) { + chapters.add(currentChapter); + Log.d(TAG, "Found chapter: " + currentChapter); + currentChapter = null; + } + } + StringBuilder elementId = new StringBuilder(); + readISOString(elementId, input, Integer.MAX_VALUE); + char[] startTimeSource = readChars(input, 4); + long startTime = ((int) startTimeSource[0] << 24) + | ((int) startTimeSource[1] << 16) + | ((int) startTimeSource[2] << 8) | startTimeSource[3]; + currentChapter = new ID3Chapter(elementId.toString(), startTime); + skipBytes(input, 12); + return ID3Reader.ACTION_DONT_SKIP; + case FRAME_ID_TITLE: + if (currentChapter != null && currentChapter.getTitle() == null) { + StringBuilder title = new StringBuilder(); + readString(title, input, header.getSize()); + currentChapter + .setTitle(title.toString()); + Log.d(TAG, "Found title: " + currentChapter.getTitle()); + + return ID3Reader.ACTION_DONT_SKIP; + } + break; + case FRAME_ID_LINK: + if (currentChapter != null) { + // skip description + int descriptionLength = readString(null, input, header.getSize()); + StringBuilder link = new StringBuilder(); + readISOString(link, input, header.getSize() - descriptionLength); + try { + String decodedLink = URLDecoder.decode(link.toString(), "UTF-8"); + currentChapter.setLink(decodedLink); + Log.d(TAG, "Found link: " + currentChapter.getLink()); + } catch (IllegalArgumentException iae) { + Log.w(TAG, "Bad URL found in ID3 data"); + } + + return ID3Reader.ACTION_DONT_SKIP; + } + break; + case FRAME_ID_PICTURE: + if (currentChapter != null) { + Log.d(TAG, header.toString()); + StringBuilder mime = new StringBuilder(); + int read = readString(mime, input, header.getSize()); + byte type = (byte) readChars(input, 1)[0]; + read++; + StringBuilder description = new StringBuilder(); + read += readISOString(description, input, header.getSize()); // Should use same encoding as mime + + Log.d(TAG, "Found apic: " + mime + "," + description); + if (mime.toString().equals("-->")) { + // Data contains a link to a picture + StringBuilder link = new StringBuilder(); + readISOString(link, input, header.getSize()); + Log.d(TAG, "link: " + link.toString()); + if (TextUtils.isEmpty(currentChapter.getImageUrl()) || type == IMAGE_TYPE_COVER) { + currentChapter.setImageUrl(link.toString()); + } + } else { + // Data contains the picture + int length = header.getSize() - read; + if (TextUtils.isEmpty(currentChapter.getImageUrl()) || type == IMAGE_TYPE_COVER) { + currentChapter.setImageUrl(EmbeddedChapterImage.makeUrl(input.getCount(), length)); + } + skipBytes(input, length); + } + return ID3Reader.ACTION_DONT_SKIP; + } + break; + } + + return super.onStartFrameHeader(header, input); + } + + private boolean hasId3Chapter(ID3Chapter chapter) { + for (Chapter c : chapters) { + if (((ID3Chapter) c).getId3ID().equals(chapter.getId3ID())) { + return true; + } + } + return false; + } + + @Override + public void onEndTag() { + if (currentChapter != null) { + if (!hasId3Chapter(currentChapter)) { + chapters.add(currentChapter); + } + } + Log.d(TAG, "Reached end of tag"); + if (chapters != null) { + for (Chapter c : chapters) { + Log.d(TAG, "chapter: " + c); + } + } + } + + @Override + public void onNoTagHeaderFound() { + Log.d(TAG, "No tag header found"); + super.onNoTagHeaderFound(); + } + + public List<Chapter> getChapters() { + return chapters; + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java index 3f5993700..dfc21a5f2 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java @@ -9,6 +9,7 @@ import java.nio.charset.Charset; import de.danoeh.antennapod.core.util.id3reader.model.FrameHeader; import de.danoeh.antennapod.core.util.id3reader.model.TagHeader; +import org.apache.commons.io.input.CountingInputStream; /** * Reads the ID3 Tag of a given file. In order to use this class, you should @@ -33,11 +34,10 @@ public class ID3Reader { ID3Reader() { } - public final void readInputStream(InputStream input) throws IOException, - ID3ReaderException { + public final void readInputStream(CountingInputStream input) throws IOException, ID3ReaderException { int rc; readerPosition = 0; - char[] tagHeaderSource = readBytes(input, HEADER_LENGTH); + char[] tagHeaderSource = readChars(input, HEADER_LENGTH); tagHeader = createTagHeader(tagHeaderSource); if (tagHeader == null) { onNoTagHeaderFound(); @@ -47,7 +47,7 @@ public class ID3Reader { onEndTag(); } else { while (readerPosition < tagHeader.getSize()) { - FrameHeader frameHeader = createFrameHeader(readBytes(input, HEADER_LENGTH)); + FrameHeader frameHeader = createFrameHeader(readChars(input, HEADER_LENGTH)); if (checkForNullString(frameHeader.getId())) { break; } @@ -84,11 +84,10 @@ public class ID3Reader { } /** - * Read a certain number of bytes from the given input stream. This method + * Read a certain number of chars from the given input stream. This method * changes the readerPosition-attribute. */ - char[] readBytes(InputStream input, int number) - throws IOException, ID3ReaderException { + char[] readChars(InputStream input, int number) throws IOException, ID3ReaderException { char[] header = new char[number]; for (int i = 0; i < number; i++) { int b = input.read(); @@ -168,7 +167,7 @@ public class ID3Reader { protected int readString(StringBuilder buffer, InputStream input, int max) throws IOException, ID3ReaderException { if (max > 0) { - char[] encoding = readBytes(input, 1); + char[] encoding = readChars(input, 1); max--; if (encoding[0] == ENCODING_UTF16_WITH_BOM || encoding[0] == ENCODING_UTF16_WITHOUT_BOM) { @@ -230,8 +229,7 @@ public class ID3Reader { return ACTION_SKIP; } - int onStartFrameHeader(FrameHeader header, InputStream input) - throws IOException, ID3ReaderException { + int onStartFrameHeader(FrameHeader header, CountingInputStream input) throws IOException, ID3ReaderException { return ACTION_SKIP; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java index cb22fbcc9..d9567e1e1 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java @@ -21,6 +21,7 @@ import android.widget.ImageButton; import android.widget.SeekBar; import android.widget.TextView; +import de.danoeh.antennapod.core.util.ThemeUtils; import java.util.concurrent.ScheduledThreadPoolExecutor; import de.danoeh.antennapod.core.R; @@ -397,12 +398,10 @@ public class PlaybackController { final CharSequence playText = activity.getString(R.string.play_label); final CharSequence pauseText = activity.getString(R.string.pause_label); - if (PlaybackService.getCurrentMediaType() == MediaType.AUDIO || - PlaybackService.isCasting()) { - TypedArray res = activity.obtainStyledAttributes(new int[]{ - R.attr.av_play_big, R.attr.av_pause_big}); - playResource = res.getResourceId(0, R.drawable.ic_play_arrow_grey600_36dp); - pauseResource = res.getResourceId(1, R.drawable.ic_pause_grey600_36dp); + if (PlaybackService.getCurrentMediaType() == MediaType.AUDIO || PlaybackService.isCasting()) { + TypedArray res = activity.obtainStyledAttributes(new int[]{ R.attr.av_play, R.attr.av_pause}); + playResource = res.getResourceId(0, R.drawable.ic_av_play_dark_48dp); + pauseResource = res.getResourceId(1, R.drawable.ic_av_pause_dark_48dp); res.recycle(); } else { playResource = R.drawable.ic_av_play_white_80dp; @@ -779,11 +778,8 @@ public class PlaybackController { .observeOn(AndroidSchedulers.mainThread()) .subscribe(media -> { if (media.getMediaType() == MediaType.AUDIO) { - TypedArray res = activity.obtainStyledAttributes(new int[]{ - de.danoeh.antennapod.core.R.attr.av_play_big}); getPlayButton().setImageResource( - res.getResourceId(0, de.danoeh.antennapod.core.R.drawable.ic_play_arrow_grey600_36dp)); - res.recycle(); + ThemeUtils.getDrawableFromAttr(activity, de.danoeh.antennapod.core.R.attr.av_play)); } else { getPlayButton().setImageResource(R.drawable.ic_av_play_white_80dp); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentChapterReader.java b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentChapterReader.java index 569ff3438..c4fe76780 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentChapterReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentChapterReader.java @@ -10,93 +10,91 @@ import de.danoeh.antennapod.core.feed.Chapter; import de.danoeh.antennapod.core.feed.VorbisCommentChapter; public class VorbisCommentChapterReader extends VorbisCommentReader { - private static final String TAG = "VorbisCommentChptrReadr"; - - private static final String CHAPTER_KEY = "chapter\\d\\d\\d.*"; - private static final String CHAPTER_ATTRIBUTE_TITLE = "name"; - private static final String CHAPTER_ATTRIBUTE_LINK = "url"; - - private List<Chapter> chapters; - - public VorbisCommentChapterReader() { - } - - @Override - public void onVorbisCommentFound() { - System.out.println("Vorbis comment found"); - } - - @Override - public void onVorbisCommentHeaderFound(VorbisCommentHeader header) { - chapters = new ArrayList<>(); - System.out.println(header.toString()); - } - - @Override - public boolean onContentVectorKey(String content) { - return content.matches(CHAPTER_KEY); - } - - @Override - public void onContentVectorValue(String key, String value) - throws VorbisCommentReaderException { - if (BuildConfig.DEBUG) - Log.d(TAG, "Key: " + key + ", value: " + value); - String attribute = VorbisCommentChapter.getAttributeTypeFromKey(key); - int id = VorbisCommentChapter.getIDFromKey(key); - Chapter chapter = getChapterById(id); - if (attribute == null) { - if (getChapterById(id) == null) { - // new chapter - long start = VorbisCommentChapter.getStartTimeFromValue(value); - chapter = new VorbisCommentChapter(id); - chapter.setStart(start); - chapters.add(chapter); - } else { - throw new VorbisCommentReaderException( - "Found chapter with duplicate ID (" + key + ", " - + value + ")"); - } - } else if (attribute.equals(CHAPTER_ATTRIBUTE_TITLE)) { - if (chapter != null) { - chapter.setTitle(value); - } - } else if (attribute.equals(CHAPTER_ATTRIBUTE_LINK)) { - if (chapter != null) { - chapter.setLink(value); - } - } - } - - @Override - public void onNoVorbisCommentFound() { - System.out.println("No vorbis comment found"); - } - - @Override - public void onEndOfComment() { - System.out.println("End of comment"); - for (Chapter c : chapters) { - System.out.println(c.toString()); - } - } - - @Override - public void onError(VorbisCommentReaderException exception) { - exception.printStackTrace(); - } - - private Chapter getChapterById(long id) { - for (Chapter c : chapters) { - if (((VorbisCommentChapter) c).getVorbisCommentId() == id) { - return c; - } - } - return null; - } - - public List<Chapter> getChapters() { - return chapters; - } + private static final String TAG = "VorbisCommentChptrReadr"; + + private static final String CHAPTER_KEY = "chapter\\d\\d\\d.*"; + private static final String CHAPTER_ATTRIBUTE_TITLE = "name"; + private static final String CHAPTER_ATTRIBUTE_LINK = "url"; + + private List<Chapter> chapters; + + public VorbisCommentChapterReader() { + } + + @Override + public void onVorbisCommentFound() { + System.out.println("Vorbis comment found"); + } + + @Override + public void onVorbisCommentHeaderFound(VorbisCommentHeader header) { + chapters = new ArrayList<>(); + System.out.println(header.toString()); + } + + @Override + public boolean onContentVectorKey(String content) { + return content.matches(CHAPTER_KEY); + } + + @Override + public void onContentVectorValue(String key, String value) throws VorbisCommentReaderException { + if (BuildConfig.DEBUG) { + Log.d(TAG, "Key: " + key + ", value: " + value); + } + String attribute = VorbisCommentChapter.getAttributeTypeFromKey(key); + int id = VorbisCommentChapter.getIDFromKey(key); + Chapter chapter = getChapterById(id); + if (attribute == null) { + if (getChapterById(id) == null) { + // new chapter + long start = VorbisCommentChapter.getStartTimeFromValue(value); + chapter = new VorbisCommentChapter(id); + chapter.setStart(start); + chapters.add(chapter); + } else { + throw new VorbisCommentReaderException("Found chapter with duplicate ID (" + key + ", " + value + ")"); + } + } else if (attribute.equals(CHAPTER_ATTRIBUTE_TITLE)) { + if (chapter != null) { + chapter.setTitle(value); + } + } else if (attribute.equals(CHAPTER_ATTRIBUTE_LINK)) { + if (chapter != null) { + chapter.setLink(value); + } + } + } + + @Override + public void onNoVorbisCommentFound() { + System.out.println("No vorbis comment found"); + } + + @Override + public void onEndOfComment() { + System.out.println("End of comment"); + for (Chapter c : chapters) { + System.out.println(c.toString()); + } + } + + @Override + public void onError(VorbisCommentReaderException exception) { + exception.printStackTrace(); + } + + private Chapter getChapterById(long id) { + for (Chapter c : chapters) { + if (((VorbisCommentChapter) c).getVorbisCommentId() == id) { + return c; + } + } + return null; + } + + public List<Chapter> getChapters() { + return chapters; + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReader.java b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReader.java index 55498afcb..e910e2be4 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/VorbisCommentReader.java @@ -1,5 +1,6 @@ package de.danoeh.antennapod.core.util.vorbiscommentreader; +import androidx.annotation.NonNull; import org.apache.commons.io.EndianUtils; import org.apache.commons.io.IOUtils; @@ -8,187 +9,158 @@ import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.charset.Charset; -import java.util.Arrays; - public abstract class VorbisCommentReader { - /** Length of first page in an ogg file in bytes. */ - private static final int FIRST_PAGE_LENGTH = 58; - private static final int SECOND_PAGE_MAX_LENGTH = 64 * 1024 * 1024; - private static final int PACKET_TYPE_IDENTIFICATION = 1; - private static final int PACKET_TYPE_COMMENT = 3; - - /** Called when Reader finds identification header. */ - protected abstract void onVorbisCommentFound(); - - protected abstract void onVorbisCommentHeaderFound(VorbisCommentHeader header); - - /** - * Is called every time the Reader finds a content vector. The handler - * should return true if it wants to handle the content vector. - */ - protected abstract boolean onContentVectorKey(String content); - - /** - * Is called if onContentVectorKey returned true for the key. - * - * @throws VorbisCommentReaderException - */ - protected abstract void onContentVectorValue(String key, String value) - throws VorbisCommentReaderException; - - protected abstract void onNoVorbisCommentFound(); - - protected abstract void onEndOfComment(); - - protected abstract void onError(VorbisCommentReaderException exception); - - public void readInputStream(InputStream input) - throws VorbisCommentReaderException { - try { - // look for identification header - if (findIdentificationHeader(input)) { - - onVorbisCommentFound(); - input = new OggInputStream(input); - if (findCommentHeader(input)) { - VorbisCommentHeader commentHeader = readCommentHeader(input); - if (commentHeader != null) { - onVorbisCommentHeaderFound(commentHeader); - for (int i = 0; i < commentHeader - .getUserCommentLength(); i++) { - try { - long vectorLength = EndianUtils - .readSwappedUnsignedInteger(input); - String key = readContentVectorKey(input, - vectorLength).toLowerCase(); - boolean readValue = onContentVectorKey(key); - if (readValue) { - String value = readUTF8String( - input, - (int) (vectorLength - key.length() - 1)); - onContentVectorValue(key, value); - } else { - IOUtils.skipFully(input, - vectorLength - key.length() - 1); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - onEndOfComment(); - } - - } else { - onError(new VorbisCommentReaderException( - "No comment header found")); - } - } else { - onNoVorbisCommentFound(); - } - } catch (IOException e) { - onError(new VorbisCommentReaderException(e)); - } - } - - private String readUTF8String(InputStream input, long length) - throws IOException { - byte[] buffer = new byte[(int) length]; - - IOUtils.readFully(input, buffer); - Charset charset = Charset.forName("UTF-8"); - return charset.newDecoder().decode(ByteBuffer.wrap(buffer)).toString(); - } - - /** - * Looks for an identification header in the first page of the file. If an - * identification header is found, it will be skipped completely and the - * method will return true, otherwise false. - * - * @throws IOException - */ - private boolean findIdentificationHeader(InputStream input) - throws IOException { - byte[] buffer = new byte[FIRST_PAGE_LENGTH]; - IOUtils.readFully(input, buffer); - int i; - for (i = 6; i < buffer.length; i++) { - if (buffer[i - 5] == 'v' && buffer[i - 4] == 'o' - && buffer[i - 3] == 'r' && buffer[i - 2] == 'b' - && buffer[i - 1] == 'i' && buffer[i] == 's' - && buffer[i - 6] == PACKET_TYPE_IDENTIFICATION) { - return true; - } - } - return false; - } - - private boolean findCommentHeader(InputStream input) throws IOException { - char[] buffer = new char["vorbis".length() + 1]; - for (int bytesRead = 0; bytesRead < SECOND_PAGE_MAX_LENGTH; bytesRead++) { - char c = (char) input.read(); - int dest = -1; - switch (c) { - case PACKET_TYPE_COMMENT: - dest = 0; - break; - case 'v': - dest = 1; - break; - case 'o': - dest = 2; - break; - case 'r': - dest = 3; - break; - case 'b': - dest = 4; - break; - case 'i': - dest = 5; - break; - case 's': - dest = 6; - break; - } - if (dest >= 0) { - buffer[dest] = c; - if (buffer[1] == 'v' && buffer[2] == 'o' && buffer[3] == 'r' - && buffer[4] == 'b' && buffer[5] == 'i' - && buffer[6] == 's' && buffer[0] == PACKET_TYPE_COMMENT) { - return true; - } - } else { - Arrays.fill(buffer, (char) 0); - } - } - return false; - } - - private VorbisCommentHeader readCommentHeader(InputStream input) - throws IOException, VorbisCommentReaderException { - try { - long vendorLength = EndianUtils.readSwappedUnsignedInteger(input); - String vendorName = readUTF8String(input, vendorLength); - long userCommentLength = EndianUtils - .readSwappedUnsignedInteger(input); - return new VorbisCommentHeader(vendorName, userCommentLength); - } catch (UnsupportedEncodingException e) { - throw new VorbisCommentReaderException(e); - } - } - - private String readContentVectorKey(InputStream input, long vectorLength) - throws IOException { - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < vectorLength; i++) { - char c = (char) input.read(); - if (c == '=') { - return builder.toString(); - } else { - builder.append(c); - } - } - return null; // no key found - } + /** Length of first page in an ogg file in bytes. */ + private static final int FIRST_OGG_PAGE_LENGTH = 58; + private static final int FIRST_OPUS_PAGE_LENGTH = 47; + private static final int SECOND_PAGE_MAX_LENGTH = 64 * 1024 * 1024; + private static final int PACKET_TYPE_IDENTIFICATION = 1; + private static final int PACKET_TYPE_COMMENT = 3; + + /** Called when Reader finds identification header. */ + protected abstract void onVorbisCommentFound(); + + protected abstract void onVorbisCommentHeaderFound(VorbisCommentHeader header); + + /** + * Is called every time the Reader finds a content vector. The handler + * should return true if it wants to handle the content vector. + */ + protected abstract boolean onContentVectorKey(String content); + + /** + * Is called if onContentVectorKey returned true for the key. + */ + protected abstract void onContentVectorValue(String key, String value) throws VorbisCommentReaderException; + + protected abstract void onNoVorbisCommentFound(); + + protected abstract void onEndOfComment(); + + protected abstract void onError(VorbisCommentReaderException exception); + + public void readInputStream(InputStream input) throws VorbisCommentReaderException { + try { + // look for identification header + if (findIdentificationHeader(input)) { + onVorbisCommentFound(); + input = new OggInputStream(input); + if (findCommentHeader(input)) { + VorbisCommentHeader commentHeader = readCommentHeader(input); + onVorbisCommentHeaderFound(commentHeader); + for (int i = 0; i < commentHeader.getUserCommentLength(); i++) { + readUserComment(input); + } + onEndOfComment(); + } else { + onError(new VorbisCommentReaderException("No comment header found")); + } + } else { + onNoVorbisCommentFound(); + } + } catch (IOException e) { + onError(new VorbisCommentReaderException(e)); + } + } + + private void readUserComment(InputStream input) throws VorbisCommentReaderException { + try { + long vectorLength = EndianUtils.readSwappedUnsignedInteger(input); + String key = readContentVectorKey(input, vectorLength).toLowerCase(); + boolean readValue = onContentVectorKey(key); + if (readValue) { + String value = readUtf8String(input, (int) (vectorLength - key.length() - 1)); + onContentVectorValue(key, value); + } else { + IOUtils.skipFully(input, vectorLength - key.length() - 1); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + private String readUtf8String(InputStream input, long length) throws IOException { + byte[] buffer = new byte[(int) length]; + IOUtils.readFully(input, buffer); + Charset charset = Charset.forName("UTF-8"); + return charset.newDecoder().decode(ByteBuffer.wrap(buffer)).toString(); + } + + /** + * Looks for an identification header in the first page of the file. If an + * identification header is found, it will be skipped completely and the + * method will return true, otherwise false. + */ + private boolean findIdentificationHeader(InputStream input) throws IOException { + byte[] buffer = new byte[FIRST_OPUS_PAGE_LENGTH]; + IOUtils.readFully(input, buffer); + final byte[] oggIdentificationHeader = new byte[]{ PACKET_TYPE_IDENTIFICATION, 'v', 'o', 'r', 'b', 'i', 's' }; + for (int i = 6; i < buffer.length; i++) { + if (bufferMatches(buffer, oggIdentificationHeader, i)) { + IOUtils.skip(input, FIRST_OGG_PAGE_LENGTH - FIRST_OPUS_PAGE_LENGTH); + return true; + } else if (bufferMatches(buffer, "OpusHead".getBytes(), i)) { + return true; + } + } + return false; + } + + private boolean findCommentHeader(InputStream input) throws IOException { + byte[] buffer = new byte[64]; // Enough space for some bytes. Used circularly. + final byte[] oggCommentHeader = new byte[]{ PACKET_TYPE_COMMENT, 'v', 'o', 'r', 'b', 'i', 's' }; + for (int bytesRead = 0; bytesRead < SECOND_PAGE_MAX_LENGTH; bytesRead++) { + buffer[bytesRead % buffer.length] = (byte) input.read(); + if (bufferMatches(buffer, oggCommentHeader, bytesRead)) { + return true; + } else if (bufferMatches(buffer, "OpusTags".getBytes(), bytesRead)) { + return true; + } + } + return false; + } + + /** + * Reads backwards in haystack, starting at position. Checks if the bytes match needle. + * Uses haystack circularly, so when reading at (-1), it reads at (length - 1). + */ + boolean bufferMatches(byte[] haystack, byte[] needle, int position) { + for (int i = 0; i < needle.length; i++) { + int posInHaystack = position - i; + while (posInHaystack < 0) { + posInHaystack += haystack.length; + } + posInHaystack = posInHaystack % haystack.length; + if (haystack[posInHaystack] != needle[needle.length - 1 - i]) { + return false; + } + } + return true; + } + + @NonNull + private VorbisCommentHeader readCommentHeader(InputStream input) throws IOException, VorbisCommentReaderException { + try { + long vendorLength = EndianUtils.readSwappedUnsignedInteger(input); + String vendorName = readUtf8String(input, vendorLength); + long userCommentLength = EndianUtils.readSwappedUnsignedInteger(input); + return new VorbisCommentHeader(vendorName, userCommentLength); + } catch (UnsupportedEncodingException e) { + throw new VorbisCommentReaderException(e); + } + } + + private String readContentVectorKey(InputStream input, long vectorLength) throws IOException { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < vectorLength; i++) { + char c = (char) input.read(); + if (c == '=') { + return builder.toString(); + } else { + builder.append(c); + } + } + return null; // no key found + } } diff --git a/core/src/main/res/drawable-hdpi/ic_fast_forward_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_fast_forward_grey600_24dp.png Binary files differdeleted file mode 100644 index df9e662c1..000000000 --- a/core/src/main/res/drawable-hdpi/ic_fast_forward_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_fast_forward_grey600_36dp.png b/core/src/main/res/drawable-hdpi/ic_fast_forward_grey600_36dp.png Binary files differdeleted file mode 100644 index 59ae40266..000000000 --- a/core/src/main/res/drawable-hdpi/ic_fast_forward_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_fast_forward_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_fast_forward_white_24dp.png Binary files differdeleted file mode 100644 index 2d61b31f1..000000000 --- a/core/src/main/res/drawable-hdpi/ic_fast_forward_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_fast_forward_white_36dp.png b/core/src/main/res/drawable-hdpi/ic_fast_forward_white_36dp.png Binary files differdeleted file mode 100644 index e5ae251d3..000000000 --- a/core/src/main/res/drawable-hdpi/ic_fast_forward_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_fast_rewind_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_fast_rewind_grey600_24dp.png Binary files differdeleted file mode 100644 index f661ca723..000000000 --- a/core/src/main/res/drawable-hdpi/ic_fast_rewind_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_fast_rewind_grey600_36dp.png b/core/src/main/res/drawable-hdpi/ic_fast_rewind_grey600_36dp.png Binary files differdeleted file mode 100644 index d36891a8d..000000000 --- a/core/src/main/res/drawable-hdpi/ic_fast_rewind_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_fast_rewind_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_fast_rewind_white_24dp.png Binary files differdeleted file mode 100644 index ab8b48ec3..000000000 --- a/core/src/main/res/drawable-hdpi/ic_fast_rewind_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_fast_rewind_white_36dp.png b/core/src/main/res/drawable-hdpi/ic_fast_rewind_white_36dp.png Binary files differdeleted file mode 100644 index 75796d7a9..000000000 --- a/core/src/main/res/drawable-hdpi/ic_fast_rewind_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_pause_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_pause_grey600_24dp.png Binary files differdeleted file mode 100644 index 7281f37e1..000000000 --- a/core/src/main/res/drawable-hdpi/ic_pause_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_pause_grey600_36dp.png b/core/src/main/res/drawable-hdpi/ic_pause_grey600_36dp.png Binary files differdeleted file mode 100644 index dde9bb25c..000000000 --- a/core/src/main/res/drawable-hdpi/ic_pause_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_pause_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_pause_white_24dp.png Binary files differdeleted file mode 100644 index 1701f34b0..000000000 --- a/core/src/main/res/drawable-hdpi/ic_pause_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_pause_white_36dp.png b/core/src/main/res/drawable-hdpi/ic_pause_white_36dp.png Binary files differdeleted file mode 100644 index 1d024393a..000000000 --- a/core/src/main/res/drawable-hdpi/ic_pause_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_play_arrow_grey600_24dp.png b/core/src/main/res/drawable-hdpi/ic_play_arrow_grey600_24dp.png Binary files differdeleted file mode 100644 index b540e4a63..000000000 --- a/core/src/main/res/drawable-hdpi/ic_play_arrow_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_play_arrow_grey600_36dp.png b/core/src/main/res/drawable-hdpi/ic_play_arrow_grey600_36dp.png Binary files differdeleted file mode 100644 index a12b921e4..000000000 --- a/core/src/main/res/drawable-hdpi/ic_play_arrow_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png b/core/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png Binary files differdeleted file mode 100644 index f77ad6b57..000000000 --- a/core/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_play_arrow_white_36dp.png b/core/src/main/res/drawable-hdpi/ic_play_arrow_white_36dp.png Binary files differdeleted file mode 100644 index 2b8e3513f..000000000 --- a/core/src/main/res/drawable-hdpi/ic_play_arrow_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_skip_grey600_36dp.png b/core/src/main/res/drawable-hdpi/ic_skip_grey600_36dp.png Binary files differdeleted file mode 100644 index 6e1dffc93..000000000 --- a/core/src/main/res/drawable-hdpi/ic_skip_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-hdpi/ic_skip_white_36dp.png b/core/src/main/res/drawable-hdpi/ic_skip_white_36dp.png Binary files differdeleted file mode 100644 index 760ec9987..000000000 --- a/core/src/main/res/drawable-hdpi/ic_skip_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_fast_forward_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_fast_forward_grey600_24dp.png Binary files differdeleted file mode 100644 index c67fc25f1..000000000 --- a/core/src/main/res/drawable-mdpi/ic_fast_forward_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_fast_forward_grey600_36dp.png b/core/src/main/res/drawable-mdpi/ic_fast_forward_grey600_36dp.png Binary files differdeleted file mode 100644 index df9e662c1..000000000 --- a/core/src/main/res/drawable-mdpi/ic_fast_forward_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_fast_forward_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_fast_forward_white_24dp.png Binary files differdeleted file mode 100644 index fceffcb7b..000000000 --- a/core/src/main/res/drawable-mdpi/ic_fast_forward_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_fast_forward_white_36dp.png b/core/src/main/res/drawable-mdpi/ic_fast_forward_white_36dp.png Binary files differdeleted file mode 100644 index 2d61b31f1..000000000 --- a/core/src/main/res/drawable-mdpi/ic_fast_forward_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_fast_rewind_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_fast_rewind_grey600_24dp.png Binary files differdeleted file mode 100644 index de04575da..000000000 --- a/core/src/main/res/drawable-mdpi/ic_fast_rewind_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_fast_rewind_grey600_36dp.png b/core/src/main/res/drawable-mdpi/ic_fast_rewind_grey600_36dp.png Binary files differdeleted file mode 100644 index f661ca723..000000000 --- a/core/src/main/res/drawable-mdpi/ic_fast_rewind_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_fast_rewind_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_fast_rewind_white_24dp.png Binary files differdeleted file mode 100644 index bfb476b4a..000000000 --- a/core/src/main/res/drawable-mdpi/ic_fast_rewind_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_fast_rewind_white_36dp.png b/core/src/main/res/drawable-mdpi/ic_fast_rewind_white_36dp.png Binary files differdeleted file mode 100644 index ab8b48ec3..000000000 --- a/core/src/main/res/drawable-mdpi/ic_fast_rewind_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_pause_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_pause_grey600_24dp.png Binary files differdeleted file mode 100644 index 126ee03ef..000000000 --- a/core/src/main/res/drawable-mdpi/ic_pause_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_pause_grey600_36dp.png b/core/src/main/res/drawable-mdpi/ic_pause_grey600_36dp.png Binary files differdeleted file mode 100644 index 7281f37e1..000000000 --- a/core/src/main/res/drawable-mdpi/ic_pause_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_pause_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_pause_white_24dp.png Binary files differdeleted file mode 100644 index 2272d478c..000000000 --- a/core/src/main/res/drawable-mdpi/ic_pause_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_pause_white_36dp.png b/core/src/main/res/drawable-mdpi/ic_pause_white_36dp.png Binary files differdeleted file mode 100644 index 1701f34b0..000000000 --- a/core/src/main/res/drawable-mdpi/ic_pause_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_play_arrow_grey600_24dp.png b/core/src/main/res/drawable-mdpi/ic_play_arrow_grey600_24dp.png Binary files differdeleted file mode 100644 index 9c8f2c555..000000000 --- a/core/src/main/res/drawable-mdpi/ic_play_arrow_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_play_arrow_grey600_36dp.png b/core/src/main/res/drawable-mdpi/ic_play_arrow_grey600_36dp.png Binary files differdeleted file mode 100644 index b540e4a63..000000000 --- a/core/src/main/res/drawable-mdpi/ic_play_arrow_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_play_arrow_white_24dp.png b/core/src/main/res/drawable-mdpi/ic_play_arrow_white_24dp.png Binary files differdeleted file mode 100644 index 172c211ab..000000000 --- a/core/src/main/res/drawable-mdpi/ic_play_arrow_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_play_arrow_white_36dp.png b/core/src/main/res/drawable-mdpi/ic_play_arrow_white_36dp.png Binary files differdeleted file mode 100644 index f77ad6b57..000000000 --- a/core/src/main/res/drawable-mdpi/ic_play_arrow_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_skip_grey600_36dp.png b/core/src/main/res/drawable-mdpi/ic_skip_grey600_36dp.png Binary files differdeleted file mode 100644 index 229eeca47..000000000 --- a/core/src/main/res/drawable-mdpi/ic_skip_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-mdpi/ic_skip_white_36dp.png b/core/src/main/res/drawable-mdpi/ic_skip_white_36dp.png Binary files differdeleted file mode 100644 index 9032328d4..000000000 --- a/core/src/main/res/drawable-mdpi/ic_skip_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_fast_forward_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_fast_forward_grey600_24dp.png Binary files differdeleted file mode 100644 index 6f8b42221..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_fast_forward_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_fast_forward_grey600_36dp.png b/core/src/main/res/drawable-xhdpi/ic_fast_forward_grey600_36dp.png Binary files differdeleted file mode 100644 index 521f7490b..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_fast_forward_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_fast_forward_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_fast_forward_white_24dp.png Binary files differdeleted file mode 100644 index 2b34fb82d..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_fast_forward_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_fast_forward_white_36dp.png b/core/src/main/res/drawable-xhdpi/ic_fast_forward_white_36dp.png Binary files differdeleted file mode 100644 index 2d9a7e3c9..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_fast_forward_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_fast_rewind_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_fast_rewind_grey600_24dp.png Binary files differdeleted file mode 100644 index 9468020b7..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_fast_rewind_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_fast_rewind_grey600_36dp.png b/core/src/main/res/drawable-xhdpi/ic_fast_rewind_grey600_36dp.png Binary files differdeleted file mode 100644 index ea5493251..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_fast_rewind_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_fast_rewind_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_fast_rewind_white_24dp.png Binary files differdeleted file mode 100644 index f4182f174..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_fast_rewind_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_fast_rewind_white_36dp.png b/core/src/main/res/drawable-xhdpi/ic_fast_rewind_white_36dp.png Binary files differdeleted file mode 100644 index de9ec1d90..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_fast_rewind_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_pause_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_pause_grey600_24dp.png Binary files differdeleted file mode 100644 index 6708b4161..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_pause_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_pause_grey600_36dp.png b/core/src/main/res/drawable-xhdpi/ic_pause_grey600_36dp.png Binary files differdeleted file mode 100644 index aeb13ebc4..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_pause_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png Binary files differdeleted file mode 100644 index f49aed757..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_pause_white_36dp.png b/core/src/main/res/drawable-xhdpi/ic_pause_white_36dp.png Binary files differdeleted file mode 100644 index 7192ad487..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_pause_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_play_arrow_grey600_24dp.png b/core/src/main/res/drawable-xhdpi/ic_play_arrow_grey600_24dp.png Binary files differdeleted file mode 100644 index 6874b8236..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_play_arrow_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_play_arrow_grey600_36dp.png b/core/src/main/res/drawable-xhdpi/ic_play_arrow_grey600_36dp.png Binary files differdeleted file mode 100644 index dabd252ee..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_play_arrow_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png b/core/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png Binary files differdeleted file mode 100644 index 5b0110454..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_play_arrow_white_36dp.png b/core/src/main/res/drawable-xhdpi/ic_play_arrow_white_36dp.png Binary files differdeleted file mode 100644 index fff3e1f56..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_play_arrow_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_skip_grey600_36dp.png b/core/src/main/res/drawable-xhdpi/ic_skip_grey600_36dp.png Binary files differdeleted file mode 100644 index 31aa09ca2..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_skip_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xhdpi/ic_skip_white_36dp.png b/core/src/main/res/drawable-xhdpi/ic_skip_white_36dp.png Binary files differdeleted file mode 100644 index e664f607c..000000000 --- a/core/src/main/res/drawable-xhdpi/ic_skip_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_fast_forward_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_fast_forward_grey600_24dp.png Binary files differdeleted file mode 100644 index 521f7490b..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_fast_forward_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_fast_forward_grey600_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_fast_forward_grey600_36dp.png Binary files differdeleted file mode 100644 index 644645c8b..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_fast_forward_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_fast_forward_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_fast_forward_white_24dp.png Binary files differdeleted file mode 100644 index 2d9a7e3c9..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_fast_forward_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_fast_forward_white_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_fast_forward_white_36dp.png Binary files differdeleted file mode 100644 index 76c94c3ba..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_fast_forward_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_fast_rewind_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_fast_rewind_grey600_24dp.png Binary files differdeleted file mode 100644 index ea5493251..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_fast_rewind_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_fast_rewind_grey600_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_fast_rewind_grey600_36dp.png Binary files differdeleted file mode 100644 index 831fda2ab..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_fast_rewind_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_fast_rewind_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_fast_rewind_white_24dp.png Binary files differdeleted file mode 100644 index de9ec1d90..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_fast_rewind_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_fast_rewind_white_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_fast_rewind_white_36dp.png Binary files differdeleted file mode 100644 index 8e11ac89e..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_fast_rewind_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_pause_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_pause_grey600_24dp.png Binary files differdeleted file mode 100644 index aeb13ebc4..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_pause_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_pause_grey600_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_pause_grey600_36dp.png Binary files differdeleted file mode 100644 index 8753d9c50..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_pause_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png Binary files differdeleted file mode 100644 index 7192ad487..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_pause_white_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_pause_white_36dp.png Binary files differdeleted file mode 100644 index fb63ddc5a..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_pause_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_play_arrow_grey600_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_play_arrow_grey600_24dp.png Binary files differdeleted file mode 100644 index dabd252ee..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_play_arrow_grey600_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_play_arrow_grey600_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_play_arrow_grey600_36dp.png Binary files differdeleted file mode 100644 index 9fcf99558..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_play_arrow_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png b/core/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png Binary files differdeleted file mode 100644 index fff3e1f56..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_play_arrow_white_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_play_arrow_white_36dp.png Binary files differdeleted file mode 100644 index 9b31e2d19..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_play_arrow_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_skip_grey600_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_skip_grey600_36dp.png Binary files differdeleted file mode 100644 index 75a4a9545..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_skip_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxhdpi/ic_skip_white_36dp.png b/core/src/main/res/drawable-xxhdpi/ic_skip_white_36dp.png Binary files differdeleted file mode 100644 index a31299c81..000000000 --- a/core/src/main/res/drawable-xxhdpi/ic_skip_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxxhdpi/ic_skip_grey600_36dp.png b/core/src/main/res/drawable-xxxhdpi/ic_skip_grey600_36dp.png Binary files differdeleted file mode 100644 index b599c2207..000000000 --- a/core/src/main/res/drawable-xxxhdpi/ic_skip_grey600_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable-xxxhdpi/ic_skip_white_36dp.png b/core/src/main/res/drawable-xxxhdpi/ic_skip_white_36dp.png Binary files differdeleted file mode 100644 index a0dd670c3..000000000 --- a/core/src/main/res/drawable-xxxhdpi/ic_skip_white_36dp.png +++ /dev/null diff --git a/core/src/main/res/drawable/ic_av_fast_forward_dark_48dp.xml b/core/src/main/res/drawable/ic_av_fast_forward_dark_48dp.xml new file mode 100644 index 000000000..cf0faa33e --- /dev/null +++ b/core/src/main/res/drawable/ic_av_fast_forward_dark_48dp.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path android:fillColor="#FF757575" android:pathData="M4,18l8.5,-6L4,6v12zM13,6v12l8.5,-6L13,6z"/> +</vector> diff --git a/core/src/main/res/drawable/ic_av_fast_forward_white_48dp.xml b/core/src/main/res/drawable/ic_av_fast_forward_white_48dp.xml new file mode 100644 index 000000000..aca5bcf29 --- /dev/null +++ b/core/src/main/res/drawable/ic_av_fast_forward_white_48dp.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path android:fillColor="#FFFFFFFF" android:pathData="M4,18l8.5,-6L4,6v12zM13,6v12l8.5,-6L13,6z"/> +</vector> diff --git a/core/src/main/res/drawable/ic_av_fast_rewind_dark_48dp.xml b/core/src/main/res/drawable/ic_av_fast_rewind_dark_48dp.xml new file mode 100644 index 000000000..47d1189cb --- /dev/null +++ b/core/src/main/res/drawable/ic_av_fast_rewind_dark_48dp.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path android:fillColor="#FF757575" android:pathData="M11,18L11,6l-8.5,6 8.5,6zM11.5,12l8.5,6L20,6l-8.5,6z"/> +</vector> diff --git a/core/src/main/res/drawable/ic_av_fast_rewind_white_48dp.xml b/core/src/main/res/drawable/ic_av_fast_rewind_white_48dp.xml new file mode 100644 index 000000000..ba2b8ae4f --- /dev/null +++ b/core/src/main/res/drawable/ic_av_fast_rewind_white_48dp.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path android:fillColor="#FFFFFFFF" android:pathData="M11,18L11,6l-8.5,6 8.5,6zM11.5,12l8.5,6L20,6l-8.5,6z"/> +</vector> diff --git a/core/src/main/res/drawable/ic_av_pause_dark_48dp.xml b/core/src/main/res/drawable/ic_av_pause_dark_48dp.xml new file mode 100644 index 000000000..61fdd4b5b --- /dev/null +++ b/core/src/main/res/drawable/ic_av_pause_dark_48dp.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path android:fillColor="#FF757575" android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/> +</vector> diff --git a/core/src/main/res/drawable/ic_av_pause_white_48dp.xml b/core/src/main/res/drawable/ic_av_pause_white_48dp.xml new file mode 100644 index 000000000..3512563ec --- /dev/null +++ b/core/src/main/res/drawable/ic_av_pause_white_48dp.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path android:fillColor="#FFFFFFFF" android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/> +</vector> diff --git a/core/src/main/res/drawable/ic_av_play_dark_24dp.xml b/core/src/main/res/drawable/ic_av_play_dark_24dp.xml new file mode 100644 index 000000000..5bc12c0e1 --- /dev/null +++ b/core/src/main/res/drawable/ic_av_play_dark_24dp.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path android:fillColor="#FF757575" android:pathData="M8,5v14l11,-7z"/> +</vector> diff --git a/core/src/main/res/drawable/ic_av_play_dark_48dp.xml b/core/src/main/res/drawable/ic_av_play_dark_48dp.xml new file mode 100644 index 000000000..dbe5e7104 --- /dev/null +++ b/core/src/main/res/drawable/ic_av_play_dark_48dp.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path android:fillColor="#FF757575" android:pathData="M8,5v14l11,-7z"/> +</vector> diff --git a/core/src/main/res/drawable/ic_av_play_white_24dp.xml b/core/src/main/res/drawable/ic_av_play_white_24dp.xml new file mode 100644 index 000000000..0e896a8d4 --- /dev/null +++ b/core/src/main/res/drawable/ic_av_play_white_24dp.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path android:fillColor="#FFFFFFFF" android:pathData="M8,5v14l11,-7z"/> +</vector> diff --git a/core/src/main/res/drawable/ic_av_play_white_48dp.xml b/core/src/main/res/drawable/ic_av_play_white_48dp.xml new file mode 100644 index 000000000..bf94a000b --- /dev/null +++ b/core/src/main/res/drawable/ic_av_play_white_48dp.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path android:fillColor="#FFFFFFFF" android:pathData="M8,5v14l11,-7z"/> +</vector> diff --git a/core/src/main/res/drawable/ic_av_skip_dark_48dp.xml b/core/src/main/res/drawable/ic_av_skip_dark_48dp.xml new file mode 100644 index 000000000..2552f8d73 --- /dev/null +++ b/core/src/main/res/drawable/ic_av_skip_dark_48dp.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path android:fillColor="#FF757575" android:pathData="M6,18l8.5,-6L6,6v12zM16,6v12h2V6h-2z"/> +</vector> diff --git a/core/src/main/res/drawable/ic_av_skip_white_48dp.xml b/core/src/main/res/drawable/ic_av_skip_white_48dp.xml new file mode 100644 index 000000000..7e0073e88 --- /dev/null +++ b/core/src/main/res/drawable/ic_av_skip_white_48dp.xml @@ -0,0 +1,7 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + <path android:fillColor="#FFFFFFFF" android:pathData="M6,18l8.5,-6L6,6v12zM16,6v12h2V6h-2z"/> +</vector> diff --git a/core/src/main/res/layout/player_widget.xml b/core/src/main/res/layout/player_widget.xml index 5f49fb7ef..b0e5e0fd8 100644 --- a/core/src/main/res/layout/player_widget.xml +++ b/core/src/main/res/layout/player_widget.xml @@ -19,8 +19,10 @@ android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:layout_margin="12dp" - android:background="@android:color/transparent" - android:src="@drawable/ic_play_arrow_white_24dp" /> + android:background="?android:attr/selectableItemBackground" + android:scaleType="fitCenter" + android:padding="8dp" + android:src="@drawable/ic_av_play_white_24dp" /> <LinearLayout android:id="@+id/layout_left" diff --git a/core/src/main/res/values/attrs.xml b/core/src/main/res/values/attrs.xml index 77dd1fe47..44c79567c 100644 --- a/core/src/main/res/values/attrs.xml +++ b/core/src/main/res/values/attrs.xml @@ -9,6 +9,7 @@ <attr name="av_fast_forward" format="reference"/> <attr name="av_pause" format="reference"/> <attr name="av_play" format="reference"/> + <attr name="av_skip" format="reference"/> <attr name="av_speed" format="reference"/> <attr name="av_rewind" format="reference"/> <attr name="content_discard" format="reference"/> @@ -32,11 +33,7 @@ <attr name="dragview_float_background" format="reference"/> <attr name="ic_new" format="reference"/> <attr name="ic_history" format="reference"/> - <attr name="av_play_big" format="reference"/> - <attr name="av_pause_big" format="reference"/> - <attr name="av_ff_big" format="reference"/> - <attr name="av_rew_big" format="reference"/> - <attr name="av_skip_big" format="reference"/> + <attr name="ic_settings_playback" format="reference"/> <attr name="ic_settings" format="reference"/> <attr name="ic_lock_open" format="reference"/> <attr name="ic_lock_closed" format="reference"/> diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml index 33b736089..f6c31f652 100644 --- a/core/src/main/res/values/styles.xml +++ b/core/src/main/res/values/styles.xml @@ -20,12 +20,13 @@ <item name="action_search">@drawable/ic_search_grey600_24dp</item> <item name="action_stream">@drawable/ic_stream_grey600</item> <item name="av_download">@drawable/ic_file_download_grey600_24dp</item> - <item name="av_fast_forward">@drawable/ic_fast_forward_grey600_24dp</item> - <item name="av_pause">@drawable/ic_pause_grey600_24dp</item> - <item name="av_play">@drawable/ic_play_arrow_grey600_24dp</item> + <item name="av_pause">@drawable/ic_av_pause_dark_48dp</item> + <item name="av_play">@drawable/ic_av_play_dark_48dp</item> + <item name="av_rewind">@drawable/ic_av_fast_rewind_dark_48dp</item> + <item name="av_fast_forward">@drawable/ic_av_fast_forward_dark_48dp</item> + <item name="av_skip">@drawable/ic_av_skip_dark_48dp</item> <item name="av_speed">@drawable/ic_playback_speed_dark_48dp</item> <item name="ic_settings_speed">@drawable/ic_playback_speed_dark_24dp</item> - <item name="av_rewind">@drawable/ic_fast_rewind_grey600_24dp</item> <item name="content_discard">@drawable/ic_delete_grey600_24dp</item> <item name="content_new">@drawable/ic_add_grey600_24dp</item> <item name="content_remove_from_queue">@drawable/ic_remove_grey600</item> @@ -49,11 +50,7 @@ <item name="ic_new">@drawable/ic_new_releases_grey600_24dp</item> <item name="ic_history">@drawable/ic_history_grey600_24dp</item> <item name="ic_folder">@drawable/ic_folder_grey600_24dp</item> - <item name="av_play_big">@drawable/ic_play_arrow_grey600_36dp</item> - <item name="av_pause_big">@drawable/ic_pause_grey600_36dp</item> - <item name="av_ff_big">@drawable/ic_fast_forward_grey600_36dp</item> - <item name="av_rew_big">@drawable/ic_fast_rewind_grey600_36dp</item> - <item name="av_skip_big">@drawable/ic_skip_grey600_36dp</item> + <item name="ic_settings_playback">@drawable/ic_av_play_dark_24dp</item> <item name="ic_fav">@drawable/ic_star_border_grey600_24dp</item> <item name="ic_unfav">@drawable/ic_star_grey600_24dp</item> <item name="ic_settings">@drawable/ic_settings_grey600_24dp</item> @@ -108,12 +105,13 @@ <item name="action_search">@drawable/ic_search_white_24dp</item> <item name="action_stream">@drawable/ic_stream_white</item> <item name="av_download">@drawable/ic_file_download_white_24dp</item> - <item name="av_fast_forward">@drawable/ic_fast_forward_white_24dp</item> - <item name="av_pause">@drawable/ic_pause_white_24dp</item> - <item name="av_play">@drawable/ic_play_arrow_white_24dp</item> + <item name="av_rewind">@drawable/ic_av_fast_rewind_white_48dp</item> + <item name="av_fast_forward">@drawable/ic_av_fast_forward_white_48dp</item> + <item name="av_pause">@drawable/ic_av_pause_white_48dp</item> + <item name="av_play">@drawable/ic_av_play_white_48dp</item> + <item name="av_skip">@drawable/ic_av_skip_white_48dp</item> <item name="av_speed">@drawable/ic_playback_speed_white_48dp</item> <item name="ic_settings_speed">@drawable/ic_playback_speed_white_24dp</item> - <item name="av_rewind">@drawable/ic_fast_rewind_white_24dp</item> <item name="content_discard">@drawable/ic_delete_white_24dp</item> <item name="content_new">@drawable/ic_add_white_24dp</item> <item name="content_remove_from_queue">@drawable/ic_remove_white</item> @@ -137,11 +135,7 @@ <item name="ic_new">@drawable/ic_new_releases_white_24dp</item> <item name="ic_history">@drawable/ic_history_white_24dp</item> <item name="ic_folder">@drawable/ic_folder_white_24dp</item> - <item name="av_play_big">@drawable/ic_play_arrow_white_36dp</item> - <item name="av_pause_big">@drawable/ic_pause_white_36dp</item> - <item name="av_ff_big">@drawable/ic_fast_forward_white_36dp</item> - <item name="av_rew_big">@drawable/ic_fast_rewind_white_36dp</item> - <item name="av_skip_big">@drawable/ic_skip_white_36dp</item> + <item name="ic_settings_playback">@drawable/ic_av_play_white_24dp</item> <item name="ic_fav">@drawable/ic_star_border_white_24dp</item> <item name="ic_unfav">@drawable/ic_star_white_24dp</item> <item name="ic_settings">@drawable/ic_settings_white_24dp</item> |