mirror of
https://github.com/antebudimir/tempus.git
synced 2026-01-01 09:53:33 +00:00
build: change of package name
This commit is contained in:
parent
49afdbe4eb
commit
b76a38cb30
274 changed files with 1981 additions and 2161 deletions
|
|
@ -0,0 +1,77 @@
|
|||
package com.cappielloantonio.tempo.util
|
||||
|
||||
object Constants {
|
||||
const val SHARED_PREF_KEY = "play-shared-preferences"
|
||||
|
||||
const val ITEM_POSITION = "ITEM_POSITION"
|
||||
|
||||
const val TRACK_OBJECT = "TRACK_OBJECT"
|
||||
const val TRACKS_OBJECT = "TRACKS_OBJECT"
|
||||
const val ALBUM_OBJECT = "ALBUM_OBJECT"
|
||||
const val ARTIST_OBJECT = "ARTIST_OBJECT"
|
||||
const val GENRE_OBJECT = "GENRE_OBJECT"
|
||||
const val PLAYLIST_OBJECT = "PLAYLIST_OBJECT"
|
||||
const val PODCAST_OBJECT = "PODCAST_OBJECT"
|
||||
const val PODCAST_CHANNEL_OBJECT = "PODCAST_CHANNEL_OBJECT"
|
||||
const val INTERNET_RADIO_STATION_OBJECT = "INTERNET_RADIO_STATION_OBJECT"
|
||||
const val MUSIC_FOLDER_OBJECT = "MUSIC_FOLDER_OBJECT"
|
||||
const val MUSIC_DIRECTORY_OBJECT = "MUSIC_DIRECTORY_OBJECT"
|
||||
const val MUSIC_INDEX_OBJECT = "MUSIC_DIRECTORY_OBJECT"
|
||||
|
||||
const val ALBUM_RECENTLY_PLAYED = "ALBUM_RECENTLY_PLAYED"
|
||||
const val ALBUM_MOST_PLAYED = "ALBUM_MOST_PLAYED"
|
||||
const val ALBUM_RECENTLY_ADDED = "ALBUM_RECENTLY_ADDED"
|
||||
const val ALBUM_DOWNLOADED = "ALBUM_DOWNLOADED"
|
||||
const val ALBUM_STARRED = "ALBUM_STARRED"
|
||||
const val ALBUM_FROM_ARTIST = "ALBUM_FROM_ARTIST"
|
||||
const val ALBUM_NEW_RELEASES = "ALBUM_NEW_RELEASES"
|
||||
const val ALBUM_ORDER_BY_NAME = "ALBUM_ORDER_BY_NAME"
|
||||
const val ALBUM_ORDER_BY_ARTIST = "ALBUM_ORDER_BY_ARTIST"
|
||||
const val ALBUM_ORDER_BY_YEAR = "ALBUM_ORDER_BY_YEAR"
|
||||
const val ALBUM_ORDER_BY_RANDOM = "ALBUM_ORDER_BY_RANDOM"
|
||||
|
||||
const val ARTIST_DOWNLOADED = "ARTIST_DOWNLOADED"
|
||||
const val ARTIST_STARRED = "ARTIST_STARRED"
|
||||
const val ARTIST_ORDER_BY_NAME = "ARTIST_ORDER_BY_NAME"
|
||||
const val ARTIST_ORDER_BY_RANDOM = "ARTIST_ORDER_BY_RANDOM"
|
||||
|
||||
const val GENRE_ORDER_BY_NAME = "GENRE_ORDER_BY_NAME"
|
||||
const val GENRE_ORDER_BY_RANDOM = "GENRE_ORDER_BY_RANDOM"
|
||||
|
||||
const val PLAYLIST_ALL = "ALL"
|
||||
const val PLAYLIST_DOWNLOADED = "DOWNLOADED"
|
||||
const val PLAYLIST_ORDER_BY_NAME = "ORDER_BY_NAME"
|
||||
const val PLAYLIST_ORDER_BY_RANDOM = "ORDER_BY_RANDOM"
|
||||
|
||||
const val MEDIA_TYPE_MUSIC = "music"
|
||||
const val MEDIA_TYPE_PODCAST = "podcast"
|
||||
const val MEDIA_TYPE_AUDIOBOOK = "audiobook"
|
||||
const val MEDIA_TYPE_VIDEO = "video"
|
||||
const val MEDIA_TYPE_RADIO = "radio"
|
||||
|
||||
const val MEDIA_PLAYBACK_SPEED_080 = 0.8f
|
||||
const val MEDIA_PLAYBACK_SPEED_100 = 1.0f
|
||||
const val MEDIA_PLAYBACK_SPEED_125 = 1.25f
|
||||
const val MEDIA_PLAYBACK_SPEED_150 = 1.50f
|
||||
const val MEDIA_PLAYBACK_SPEED_175 = 1.75f
|
||||
const val MEDIA_PLAYBACK_SPEED_200 = 2.0f
|
||||
|
||||
const val MEDIA_RECENTLY_PLAYED = "MEDIA_RECENTLY_PLAYED"
|
||||
const val MEDIA_MOST_PLAYED = "MEDIA_MOST_PLAYED"
|
||||
const val MEDIA_RECENTLY_ADDED = "MEDIA_RECENTLY_ADDED"
|
||||
const val MEDIA_BY_GENRE = "MEDIA_BY_GENRE"
|
||||
const val MEDIA_BY_GENRES = "MEDIA_BY_GENRES"
|
||||
const val MEDIA_BY_ARTIST = "MEDIA_BY_ARTIST"
|
||||
const val MEDIA_BY_YEAR = "MEDIA_BY_YEAR"
|
||||
const val MEDIA_STARRED = "MEDIA_STARRED"
|
||||
const val MEDIA_DOWNLOADED = "MEDIA_DOWNLOADED"
|
||||
const val MEDIA_FROM_ALBUM = "MEDIA_FROM_ALBUM"
|
||||
const val MEDIA_MIX = "MEDIA_MIX"
|
||||
const val MEDIA_CHRONOLOGY = "MEDIA_CHRONOLOGY"
|
||||
const val MEDIA_BEST_OF = "MEDIA_BEST_OF"
|
||||
|
||||
const val DOWNLOAD_URI = "rest/download"
|
||||
|
||||
const val PLAYABLE_MEDIA_LIMIT = 100
|
||||
const val PRE_PLAYABLE_MEDIA = 15
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
package com.cappielloantonio.tempo.util;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.database.DatabaseProvider;
|
||||
import androidx.media3.database.StandaloneDatabaseProvider;
|
||||
import androidx.media3.datasource.DataSource;
|
||||
import androidx.media3.datasource.DefaultDataSource;
|
||||
import androidx.media3.datasource.DefaultHttpDataSource;
|
||||
import androidx.media3.datasource.cache.Cache;
|
||||
import androidx.media3.datasource.cache.CacheDataSource;
|
||||
import androidx.media3.datasource.cache.NoOpCacheEvictor;
|
||||
import androidx.media3.datasource.cache.SimpleCache;
|
||||
import androidx.media3.exoplayer.DefaultRenderersFactory;
|
||||
import androidx.media3.exoplayer.RenderersFactory;
|
||||
import androidx.media3.exoplayer.offline.DownloadManager;
|
||||
import androidx.media3.exoplayer.offline.DownloadNotificationHelper;
|
||||
|
||||
import com.cappielloantonio.tempo.service.DownloaderManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.CookieHandler;
|
||||
import java.net.CookieManager;
|
||||
import java.net.CookiePolicy;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@UnstableApi
|
||||
public final class DownloadUtil {
|
||||
|
||||
public static final String DOWNLOAD_NOTIFICATION_CHANNEL_ID = "download_channel";
|
||||
|
||||
private static final String DOWNLOAD_CONTENT_DIRECTORY = "downloads";
|
||||
|
||||
private static DataSource.Factory dataSourceFactory;
|
||||
private static DataSource.Factory httpDataSourceFactory;
|
||||
private static DatabaseProvider databaseProvider;
|
||||
private static File downloadDirectory;
|
||||
private static Cache downloadCache;
|
||||
private static DownloadManager downloadManager;
|
||||
private static DownloaderManager downloaderManager;
|
||||
private static DownloadNotificationHelper downloadNotificationHelper;
|
||||
|
||||
public static boolean useExtensionRenderers() {
|
||||
// return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static RenderersFactory buildRenderersFactory(Context context, boolean preferExtensionRenderer) {
|
||||
@DefaultRenderersFactory.ExtensionRendererMode int extensionRendererMode =
|
||||
useExtensionRenderers()
|
||||
? (preferExtensionRenderer ? DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER : DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON)
|
||||
: DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF;
|
||||
|
||||
return new DefaultRenderersFactory(context.getApplicationContext()).setExtensionRendererMode(extensionRendererMode);
|
||||
}
|
||||
|
||||
public static synchronized DataSource.Factory getHttpDataSourceFactory() {
|
||||
if (httpDataSourceFactory == null) {
|
||||
CookieManager cookieManager = new CookieManager();
|
||||
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);
|
||||
CookieHandler.setDefault(cookieManager);
|
||||
httpDataSourceFactory = new DefaultHttpDataSource.Factory();
|
||||
}
|
||||
|
||||
return httpDataSourceFactory;
|
||||
}
|
||||
|
||||
public static synchronized DataSource.Factory getDataSourceFactory(Context context) {
|
||||
if (dataSourceFactory == null) {
|
||||
context = context.getApplicationContext();
|
||||
DefaultDataSource.Factory upstreamFactory = new DefaultDataSource.Factory(context, getHttpDataSourceFactory());
|
||||
dataSourceFactory = buildReadOnlyCacheDataSource(upstreamFactory, getDownloadCache(context));
|
||||
}
|
||||
|
||||
return dataSourceFactory;
|
||||
}
|
||||
|
||||
public static synchronized DownloadNotificationHelper getDownloadNotificationHelper(Context context) {
|
||||
if (downloadNotificationHelper == null) {
|
||||
downloadNotificationHelper = new DownloadNotificationHelper(context, DOWNLOAD_NOTIFICATION_CHANNEL_ID);
|
||||
}
|
||||
|
||||
return downloadNotificationHelper;
|
||||
}
|
||||
|
||||
public static synchronized DownloadManager getDownloadManager(Context context) {
|
||||
ensureDownloadManagerInitialized(context);
|
||||
return downloadManager;
|
||||
}
|
||||
|
||||
public static synchronized DownloaderManager getDownloadTracker(Context context) {
|
||||
ensureDownloadManagerInitialized(context);
|
||||
return downloaderManager;
|
||||
}
|
||||
|
||||
private static synchronized Cache getDownloadCache(Context context) {
|
||||
if (downloadCache == null) {
|
||||
File downloadContentDirectory = new File(getDownloadDirectory(context), DOWNLOAD_CONTENT_DIRECTORY);
|
||||
downloadCache = new SimpleCache(downloadContentDirectory, new NoOpCacheEvictor(), getDatabaseProvider(context));
|
||||
}
|
||||
|
||||
return downloadCache;
|
||||
}
|
||||
|
||||
private static synchronized void ensureDownloadManagerInitialized(Context context) {
|
||||
if (downloadManager == null) {
|
||||
downloadManager = new DownloadManager(
|
||||
context,
|
||||
getDatabaseProvider(context),
|
||||
getDownloadCache(context),
|
||||
getHttpDataSourceFactory(),
|
||||
Executors.newFixedThreadPool(6)
|
||||
);
|
||||
|
||||
downloaderManager = new DownloaderManager(context, getHttpDataSourceFactory(), downloadManager);
|
||||
}
|
||||
}
|
||||
|
||||
private static synchronized DatabaseProvider getDatabaseProvider(Context context) {
|
||||
if (databaseProvider == null) {
|
||||
databaseProvider = new StandaloneDatabaseProvider(context);
|
||||
}
|
||||
|
||||
return databaseProvider;
|
||||
}
|
||||
|
||||
private static synchronized File getDownloadDirectory(Context context) {
|
||||
if (downloadDirectory == null) {
|
||||
downloadDirectory = context.getExternalFilesDir(null);
|
||||
if (downloadDirectory == null) {
|
||||
downloadDirectory = context.getFilesDir();
|
||||
}
|
||||
}
|
||||
|
||||
return downloadDirectory;
|
||||
}
|
||||
|
||||
private static CacheDataSource.Factory buildReadOnlyCacheDataSource(DataSource.Factory upstreamFactory, Cache cache) {
|
||||
return new CacheDataSource.Factory()
|
||||
.setCache(cache)
|
||||
.setUpstreamDataSourceFactory(upstreamFactory)
|
||||
.setCacheWriteDataSinkFactory(null)
|
||||
.setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.cappielloantonio.tempo.util;
|
||||
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
|
||||
import com.cappielloantonio.tempo.subsonic.models.Artist;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Index;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Indexes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@OptIn(markerClass = UnstableApi.class)
|
||||
public class IndexUtil {
|
||||
public static List<Artist> getArtist(Indexes indexes) {
|
||||
if (indexes.getIndices() == null) return Collections.emptyList();
|
||||
|
||||
ArrayList<Artist> toReturn = new ArrayList<>();
|
||||
|
||||
for (Index index : indexes.getIndices()) {
|
||||
if (index.getArtists() != null) {
|
||||
toReturn.addAll(index.getArtists());
|
||||
}
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
package com.cappielloantonio.tempo.util;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.MediaMetadata;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
|
||||
import com.cappielloantonio.tempo.App;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.subsonic.models.InternetRadioStation;
|
||||
import com.cappielloantonio.tempo.subsonic.models.PodcastEpisode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@OptIn(markerClass = UnstableApi.class)
|
||||
public class MappingUtil {
|
||||
public static List<MediaItem> mapMediaItems(List<Child> items) {
|
||||
ArrayList<MediaItem> mediaItems = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
mediaItems.add(mapMediaItem(items.get(i)));
|
||||
}
|
||||
|
||||
return mediaItems;
|
||||
}
|
||||
|
||||
public static MediaItem mapMediaItem(Child media) {
|
||||
Uri uri = getUri(media);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("id", media.getId());
|
||||
bundle.putString("parentId", media.getParentId());
|
||||
bundle.putBoolean("isDir", media.isDir());
|
||||
bundle.putString("title", media.getTitle());
|
||||
bundle.putString("album", media.getAlbum());
|
||||
bundle.putString("artist", media.getArtist());
|
||||
bundle.putInt("track", media.getTrack() != null ? media.getTrack() : 0);
|
||||
bundle.putInt("year", media.getYear() != null ? media.getYear() : 0);
|
||||
bundle.putString("genre", media.getGenre());
|
||||
bundle.putString("coverArtId", media.getCoverArtId());
|
||||
bundle.putLong("size", media.getSize() != null ? media.getSize() : 0);
|
||||
bundle.putString("contentType", media.getContentType());
|
||||
bundle.putString("suffix", media.getSuffix());
|
||||
bundle.putString("transcodedContentType", media.getTranscodedContentType());
|
||||
bundle.putString("transcodedSuffix", media.getTranscodedSuffix());
|
||||
bundle.putInt("duration", media.getDuration() != null ? media.getDuration() : 0);
|
||||
bundle.putInt("bitrate", media.getBitrate() != null ? media.getBitrate() : 0);
|
||||
bundle.putString("path", media.getPath());
|
||||
bundle.putBoolean("isVideo", media.isVideo());
|
||||
bundle.putInt("userRating", media.getUserRating() != null ? media.getUserRating() : 0);
|
||||
bundle.putDouble("averageRating", media.getAverageRating() != null ? media.getAverageRating() : 0);
|
||||
bundle.putLong("playCount", media.getPlayCount() != null ? media.getTrack() : 0);
|
||||
bundle.putInt("discNumber", media.getDiscNumber() != null ? media.getTrack() : 0);
|
||||
bundle.putLong("created", media.getCreated() != null ? media.getCreated().getTime() : 0);
|
||||
bundle.putLong("starred", media.getStarred() != null ? media.getStarred().getTime() : 0);
|
||||
bundle.putString("albumId", media.getAlbumId());
|
||||
bundle.putString("artistId", media.getArtistId());
|
||||
bundle.putString("type", media.getType());
|
||||
bundle.putLong("bookmarkPosition", media.getBookmarkPosition() != null ? media.getBookmarkPosition() : 0);
|
||||
bundle.putInt("originalWidth", media.getOriginalWidth() != null ? media.getOriginalWidth() : 0);
|
||||
bundle.putInt("originalHeight", media.getOriginalHeight() != null ? media.getOriginalHeight() : 0);
|
||||
bundle.putString("uri", uri.toString());
|
||||
|
||||
return new MediaItem.Builder()
|
||||
.setMediaId(media.getId())
|
||||
.setMediaMetadata(
|
||||
new MediaMetadata.Builder()
|
||||
.setTitle(MusicUtil.getReadableString(media.getTitle()))
|
||||
.setTrackNumber(media.getTrack())
|
||||
.setDiscNumber(media.getDiscNumber())
|
||||
.setReleaseYear(media.getYear())
|
||||
.setAlbumTitle(MusicUtil.getReadableString(media.getAlbum()))
|
||||
.setArtist(MusicUtil.getReadableString(media.getArtist()))
|
||||
.setExtras(bundle)
|
||||
.build()
|
||||
)
|
||||
.setRequestMetadata(
|
||||
new MediaItem.RequestMetadata.Builder()
|
||||
.setMediaUri(uri)
|
||||
.setExtras(bundle)
|
||||
.build()
|
||||
)
|
||||
.setMimeType(MimeTypes.BASE_TYPE_AUDIO)
|
||||
.setUri(uri)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static List<MediaItem> mapDownloads(List<Child> items) {
|
||||
ArrayList<MediaItem> downloads = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
downloads.add(mapDownload(items.get(i)));
|
||||
}
|
||||
|
||||
return downloads;
|
||||
}
|
||||
|
||||
public static MediaItem mapDownload(Child media) {
|
||||
return new MediaItem.Builder()
|
||||
.setMediaId(media.getId())
|
||||
.setMediaMetadata(
|
||||
new MediaMetadata.Builder()
|
||||
.setTitle(MusicUtil.getReadableString(media.getTitle()))
|
||||
.setTrackNumber(media.getTrack())
|
||||
.setDiscNumber(media.getDiscNumber())
|
||||
.setReleaseYear(media.getYear())
|
||||
.setAlbumTitle(MusicUtil.getReadableString(media.getAlbum()))
|
||||
.setArtist(MusicUtil.getReadableString(media.getArtist()))
|
||||
.build()
|
||||
)
|
||||
.setRequestMetadata(
|
||||
new MediaItem.RequestMetadata.Builder()
|
||||
.setMediaUri(MusicUtil.getDownloadUri(media.getId()))
|
||||
.build()
|
||||
)
|
||||
.setMimeType(MimeTypes.BASE_TYPE_AUDIO)
|
||||
.setUri(MusicUtil.getDownloadUri(media.getId()))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static MediaItem mapInternetRadioStation(InternetRadioStation internetRadioStation) {
|
||||
Uri uri = Uri.parse(internetRadioStation.getStreamUrl());
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("id", internetRadioStation.getId());
|
||||
bundle.putString("title", internetRadioStation.getName());
|
||||
bundle.putString("artist", uri.toString());
|
||||
bundle.putString("uri", uri.toString());
|
||||
bundle.putString("type", Constants.MEDIA_TYPE_RADIO);
|
||||
|
||||
return new MediaItem.Builder()
|
||||
.setMediaId(internetRadioStation.getId())
|
||||
.setMediaMetadata(
|
||||
new MediaMetadata.Builder()
|
||||
.setTitle(internetRadioStation.getName())
|
||||
.setArtist(internetRadioStation.getStreamUrl())
|
||||
.setExtras(bundle)
|
||||
.build()
|
||||
)
|
||||
.setRequestMetadata(
|
||||
new MediaItem.RequestMetadata.Builder()
|
||||
.setMediaUri(uri)
|
||||
.setExtras(bundle)
|
||||
.build()
|
||||
)
|
||||
.setMimeType(MimeTypes.BASE_TYPE_AUDIO)
|
||||
.setUri(uri)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static MediaItem mapMediaItem(PodcastEpisode podcastEpisode) {
|
||||
Uri uri = getUri(podcastEpisode);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("id", podcastEpisode.getId());
|
||||
bundle.putString("parentId", podcastEpisode.getParentId());
|
||||
bundle.putBoolean("isDir", podcastEpisode.isDir());
|
||||
bundle.putString("title", podcastEpisode.getTitle());
|
||||
bundle.putString("album", podcastEpisode.getAlbum());
|
||||
bundle.putString("artist", podcastEpisode.getArtist());
|
||||
bundle.putInt("track", podcastEpisode.getTrack() != null ? podcastEpisode.getTrack() : 0);
|
||||
bundle.putInt("year", podcastEpisode.getYear() != null ? podcastEpisode.getYear() : 0);
|
||||
bundle.putString("genre", podcastEpisode.getGenre());
|
||||
bundle.putString("coverArtId", podcastEpisode.getCoverArtId());
|
||||
bundle.putLong("size", podcastEpisode.getSize() != null ? podcastEpisode.getSize() : 0);
|
||||
bundle.putString("contentType", podcastEpisode.getContentType());
|
||||
bundle.putString("suffix", podcastEpisode.getSuffix());
|
||||
bundle.putString("transcodedContentType", podcastEpisode.getTranscodedContentType());
|
||||
bundle.putString("transcodedSuffix", podcastEpisode.getTranscodedSuffix());
|
||||
bundle.putInt("duration", podcastEpisode.getDuration() != null ? podcastEpisode.getDuration() : 0);
|
||||
bundle.putInt("bitrate", podcastEpisode.getBitrate() != null ? podcastEpisode.getBitrate() : 0);
|
||||
bundle.putString("path", podcastEpisode.getPath());
|
||||
bundle.putBoolean("isVideo", podcastEpisode.isVideo());
|
||||
bundle.putInt("userRating", podcastEpisode.getUserRating() != null ? podcastEpisode.getUserRating() : 0);
|
||||
bundle.putDouble("averageRating", podcastEpisode.getAverageRating() != null ? podcastEpisode.getAverageRating() : 0);
|
||||
bundle.putLong("playCount", podcastEpisode.getPlayCount() != null ? podcastEpisode.getTrack() : 0);
|
||||
bundle.putInt("discNumber", podcastEpisode.getDiscNumber() != null ? podcastEpisode.getTrack() : 0);
|
||||
bundle.putLong("created", podcastEpisode.getCreated() != null ? podcastEpisode.getCreated().getTime() : 0);
|
||||
bundle.putLong("starred", podcastEpisode.getStarred() != null ? podcastEpisode.getStarred().getTime() : 0);
|
||||
bundle.putString("albumId", podcastEpisode.getAlbumId());
|
||||
bundle.putString("artistId", podcastEpisode.getArtistId());
|
||||
bundle.putString("type", podcastEpisode.getType());
|
||||
bundle.putLong("bookmarkPosition", podcastEpisode.getBookmarkPosition() != null ? podcastEpisode.getBookmarkPosition() : 0);
|
||||
bundle.putInt("originalWidth", podcastEpisode.getOriginalWidth() != null ? podcastEpisode.getOriginalWidth() : 0);
|
||||
bundle.putInt("originalHeight", podcastEpisode.getOriginalHeight() != null ? podcastEpisode.getOriginalHeight() : 0);
|
||||
bundle.putString("uri", uri.toString());
|
||||
|
||||
return new MediaItem.Builder()
|
||||
.setMediaId(podcastEpisode.getId())
|
||||
.setMediaMetadata(
|
||||
new MediaMetadata.Builder()
|
||||
.setTitle(MusicUtil.getReadableString(podcastEpisode.getTitle()))
|
||||
.setTrackNumber(podcastEpisode.getTrack())
|
||||
.setDiscNumber(podcastEpisode.getDiscNumber())
|
||||
.setReleaseYear(podcastEpisode.getYear())
|
||||
.setAlbumTitle(MusicUtil.getReadableString(podcastEpisode.getAlbum()))
|
||||
.setArtist(MusicUtil.getReadableString(podcastEpisode.getArtist()))
|
||||
.setExtras(bundle)
|
||||
.build()
|
||||
)
|
||||
.setRequestMetadata(
|
||||
new MediaItem.RequestMetadata.Builder()
|
||||
.setMediaUri(uri)
|
||||
.setExtras(bundle)
|
||||
.build()
|
||||
)
|
||||
.setMimeType(MimeTypes.BASE_TYPE_AUDIO)
|
||||
.setUri(uri)
|
||||
.build();
|
||||
}
|
||||
|
||||
private static Uri getUri(Child media) {
|
||||
return DownloadUtil.getDownloadTracker(App.getContext()).isDownloaded(media.getId())
|
||||
? MusicUtil.getDownloadUri(media.getId())
|
||||
: MusicUtil.getStreamUri(media.getId());
|
||||
}
|
||||
|
||||
private static Uri getUri(PodcastEpisode podcastEpisode) {
|
||||
return DownloadUtil.getDownloadTracker(App.getContext()).isDownloaded(podcastEpisode.getId())
|
||||
? MusicUtil.getDownloadUri(podcastEpisode.getId())
|
||||
: MusicUtil.getStreamUri(podcastEpisode.getId());
|
||||
}
|
||||
}
|
||||
214
app/src/main/java/com/cappielloantonio/tempo/util/MusicUtil.java
Normal file
214
app/src/main/java/com/cappielloantonio/tempo/util/MusicUtil.java
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
package com.cappielloantonio.tempo.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.Uri;
|
||||
import android.text.Html;
|
||||
import android.util.Log;
|
||||
|
||||
import com.cappielloantonio.tempo.App;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MusicUtil {
|
||||
private static final String TAG = "MusicUtil";
|
||||
|
||||
public static Uri getStreamUri(String id) {
|
||||
Map<String, String> params = App.getSubsonicClientInstance(false).getParams();
|
||||
|
||||
StringBuilder uri = new StringBuilder();
|
||||
|
||||
uri.append(App.getSubsonicClientInstance(false).getUrl());
|
||||
uri.append("stream");
|
||||
|
||||
if (params.containsKey("u") && params.get("u") != null)
|
||||
uri.append("?u=").append(params.get("u"));
|
||||
if (params.containsKey("p") && params.get("p") != null)
|
||||
uri.append("&p=").append(params.get("p"));
|
||||
if (params.containsKey("s") && params.get("s") != null)
|
||||
uri.append("&s=").append(params.get("s"));
|
||||
if (params.containsKey("t") && params.get("t") != null)
|
||||
uri.append("&t=").append(params.get("t"));
|
||||
if (params.containsKey("v") && params.get("v") != null)
|
||||
uri.append("&v=").append(params.get("v"));
|
||||
if (params.containsKey("c") && params.get("c") != null)
|
||||
uri.append("&c=").append(params.get("c"));
|
||||
|
||||
uri.append("&maxBitRate=").append(getBitratePreference());
|
||||
uri.append("&format=").append(getTranscodingFormatPreference());
|
||||
uri.append("&id=").append(id);
|
||||
|
||||
Log.d(TAG, "getStreamUri: " + uri);
|
||||
|
||||
return Uri.parse(uri.toString());
|
||||
}
|
||||
|
||||
public static Uri getDownloadUri(String id) {
|
||||
Map<String, String> params = App.getSubsonicClientInstance(false).getParams();
|
||||
|
||||
StringBuilder uri = new StringBuilder();
|
||||
|
||||
uri.append(App.getSubsonicClientInstance(false).getUrl());
|
||||
uri.append("download");
|
||||
|
||||
if (params.containsKey("u") && params.get("u") != null)
|
||||
uri.append("?u=").append(params.get("u"));
|
||||
if (params.containsKey("p") && params.get("p") != null)
|
||||
uri.append("&p=").append(params.get("p"));
|
||||
if (params.containsKey("s") && params.get("s") != null)
|
||||
uri.append("&s=").append(params.get("s"));
|
||||
if (params.containsKey("t") && params.get("t") != null)
|
||||
uri.append("&t=").append(params.get("t"));
|
||||
if (params.containsKey("v") && params.get("v") != null)
|
||||
uri.append("&v=").append(params.get("v"));
|
||||
if (params.containsKey("c") && params.get("c") != null)
|
||||
uri.append("&c=").append(params.get("c"));
|
||||
|
||||
uri.append("&id=").append(id);
|
||||
|
||||
Log.d(TAG, "getDownloadUri: " + uri);
|
||||
|
||||
return Uri.parse(uri.toString());
|
||||
}
|
||||
|
||||
public static String getReadableDurationString(long duration, boolean millis) {
|
||||
long minutes;
|
||||
long seconds;
|
||||
|
||||
if (millis) {
|
||||
minutes = (duration / 1000) / 60;
|
||||
seconds = (duration / 1000) % 60;
|
||||
} else {
|
||||
minutes = duration / 60;
|
||||
seconds = duration % 60;
|
||||
}
|
||||
|
||||
if (minutes < 60) {
|
||||
return String.format(Locale.getDefault(), "%01d:%02d", minutes, seconds);
|
||||
} else {
|
||||
long hours = minutes / 60;
|
||||
minutes = minutes % 60;
|
||||
return String.format(Locale.getDefault(), "%d:%02d:%02d", hours, minutes, seconds);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getReadablePodcastDurationString(long duration) {
|
||||
long minutes = duration / 60;
|
||||
|
||||
if (minutes < 60) {
|
||||
return String.format(Locale.getDefault(), "%01d min", minutes);
|
||||
} else {
|
||||
long hours = minutes / 60;
|
||||
minutes = minutes % 60;
|
||||
return String.format(Locale.getDefault(), "%d h %02d min", hours, minutes);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getReadableString(String string) {
|
||||
if (string != null) {
|
||||
return Html.fromHtml(string, Html.FROM_HTML_MODE_COMPACT).toString();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String forceReadableString(String string) {
|
||||
if (string != null) {
|
||||
return getReadableString(string)
|
||||
.replaceAll(""", "\"")
|
||||
.replaceAll("'", "'")
|
||||
.replaceAll("&", "'")
|
||||
.replaceAll("<a\\s+([^>]+)>((?:.(?!</a>))*.)</a>", "");
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String getReadableLyrics(String string) {
|
||||
if (string != null) {
|
||||
return string
|
||||
.replaceAll(""", "\"")
|
||||
.replaceAll("'", "'")
|
||||
.replaceAll("&", "'")
|
||||
.replaceAll("
", "\n");
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static List<String> getReadableStrings(List<String> strings) {
|
||||
List<String> readableStrings = new ArrayList<>();
|
||||
|
||||
if (strings.size() > 0) {
|
||||
for (String string : strings) {
|
||||
if (string != null) {
|
||||
readableStrings.add(Html.fromHtml(string, Html.FROM_HTML_MODE_COMPACT).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return readableStrings;
|
||||
}
|
||||
|
||||
public static String passwordHexEncoding(String plainPassword) {
|
||||
return "enc:" + plainPassword.chars().mapToObj(Integer::toHexString).collect(Collectors.joining());
|
||||
}
|
||||
|
||||
public static String getBitratePreference() {
|
||||
Network network = getConnectivityManager().getActiveNetwork();
|
||||
NetworkCapabilities networkCapabilities = getConnectivityManager().getNetworkCapabilities(network);
|
||||
String audioTranscodeFormat = getTranscodingFormatPreference();
|
||||
|
||||
if (audioTranscodeFormat.equals("raw") || network == null || networkCapabilities == null)
|
||||
return "0";
|
||||
|
||||
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
|
||||
return Preferences.getMaxBitrateWifi();
|
||||
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
|
||||
return Preferences.getMaxBitrateMobile();
|
||||
} else {
|
||||
return Preferences.getMaxBitrateWifi();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getTranscodingFormatPreference() {
|
||||
Network network = getConnectivityManager().getActiveNetwork();
|
||||
NetworkCapabilities networkCapabilities = getConnectivityManager().getNetworkCapabilities(network);
|
||||
|
||||
if (network == null || networkCapabilities == null) return "raw";
|
||||
|
||||
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
|
||||
return Preferences.getAudioTranscodeFormatWifi();
|
||||
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
|
||||
return Preferences.getAudioTranscodeFormatMobile();
|
||||
} else {
|
||||
return Preferences.getAudioTranscodeFormatWifi();
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Child> limitPlayableMedia(List<Child> toLimit, int position) {
|
||||
if (!toLimit.isEmpty() && toLimit.size() > Constants.PLAYABLE_MEDIA_LIMIT) {
|
||||
int from = position < Constants.PRE_PLAYABLE_MEDIA ? 0 : position - Constants.PRE_PLAYABLE_MEDIA;
|
||||
int to = Math.min(from + Constants.PLAYABLE_MEDIA_LIMIT, toLimit.size());
|
||||
|
||||
return toLimit.subList(from, to);
|
||||
}
|
||||
|
||||
return toLimit;
|
||||
}
|
||||
|
||||
public static int getPlayableMediaPosition(int initialPosition) {
|
||||
return initialPosition > Constants.PLAYABLE_MEDIA_LIMIT ? Constants.PRE_PLAYABLE_MEDIA : initialPosition;
|
||||
}
|
||||
|
||||
private static ConnectivityManager getConnectivityManager() {
|
||||
return (ConnectivityManager) App.getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
}
|
||||
}
|
||||
232
app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt
Normal file
232
app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
package com.cappielloantonio.tempo.util
|
||||
|
||||
import com.cappielloantonio.tempo.App
|
||||
|
||||
object Preferences {
|
||||
const val THEME = "theme"
|
||||
private const val SERVER = "server"
|
||||
private const val USER = "user"
|
||||
private const val PASSWORD = "password"
|
||||
private const val TOKEN = "token"
|
||||
private const val SALT = "salt"
|
||||
private const val LOW_SECURITY = "low_security"
|
||||
private const val SERVER_ID = "server_id"
|
||||
private const val PLAYBACK_SPEED = "playback_speed"
|
||||
private const val SKIP_SILENCE = "skip_silence"
|
||||
private const val IMAGE_CACHE_SIZE = "image_cache_size"
|
||||
private const val IMAGE_SIZE = "image_size"
|
||||
private const val MAX_BITRATE_WIFI = "max_bitrate_wifi"
|
||||
private const val MAX_BITRATE_MOBILE = "max_bitrate_mobile"
|
||||
private const val AUDIO_TRANSCODE_FORMAT_WIFI = "audio_transcode_format_wifi"
|
||||
private const val AUDIO_TRANSCODE_FORMAT_MOBILE = "audio_transcode_format_mobile"
|
||||
private const val WIFI_ONLY = "wifi_only"
|
||||
private const val DATA_SAVING_MODE = "data_saving_mode"
|
||||
private const val SERVER_UNREACHABLE = "server_unreachable"
|
||||
private const val SYNC_STARRED_TRACKS_FOR_OFFLINE_USE = "sync_starred_tracks_for_offline_use"
|
||||
private const val QUEUE_SYNCING = "queue_syncing"
|
||||
private const val QUEUE_SYNCING_COUNTDOWN = "queue_syncing_countdown"
|
||||
private const val ROUNDED_CORNER = "rounded_corner"
|
||||
private const val ROUNDED_CORNER_SIZE = "rounded_corner_size"
|
||||
private const val PODCAST_SECTION_VISIBILITY = "podcast_section_visibility"
|
||||
private const val RADIO_SECTION_VISIBILITY = "radio_section_visibility"
|
||||
|
||||
@JvmStatic
|
||||
fun getServer(): String? {
|
||||
return App.getInstance().preferences.getString(SERVER, null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setServer(server: String?) {
|
||||
App.getInstance().preferences.edit().putString(SERVER, server).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getUser(): String? {
|
||||
return App.getInstance().preferences.getString(USER, null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setUser(user: String?) {
|
||||
App.getInstance().preferences.edit().putString(USER, user).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getPassword(): String? {
|
||||
return App.getInstance().preferences.getString(PASSWORD, null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setPassword(password: String?) {
|
||||
App.getInstance().preferences.edit().putString(PASSWORD, password).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getToken(): String? {
|
||||
return App.getInstance().preferences.getString(TOKEN, null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setToken(token: String?) {
|
||||
App.getInstance().preferences.edit().putString(TOKEN, token).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getSalt(): String? {
|
||||
return App.getInstance().preferences.getString(SALT, null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setSalt(salt: String?) {
|
||||
App.getInstance().preferences.edit().putString(SALT, salt).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isLowScurity(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(LOW_SECURITY, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setLowSecurity(isLowSecurity: Boolean) {
|
||||
App.getInstance().preferences.edit().putBoolean(LOW_SECURITY, isLowSecurity).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getServerId(): String? {
|
||||
return App.getInstance().preferences.getString(SERVER_ID, null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setServerId(serverId: String?) {
|
||||
App.getInstance().preferences.edit().putString(SERVER_ID, serverId).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getPlaybackSpeed(): Float {
|
||||
return App.getInstance().preferences.getFloat(PLAYBACK_SPEED, 1f)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setPlaybackSpeed(playbackSpeed: Float) {
|
||||
App.getInstance().preferences.edit().putFloat(PLAYBACK_SPEED, playbackSpeed).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isSkipSilenceMode(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(SKIP_SILENCE, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setSkipSilenceMode(isSkipSilenceMode: Boolean) {
|
||||
App.getInstance().preferences.edit().putBoolean(SKIP_SILENCE, isSkipSilenceMode).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getImageCacheSize(): Int {
|
||||
return App.getInstance().preferences.getString(IMAGE_CACHE_SIZE, "500")!!.toInt()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getImageSize(): Int {
|
||||
return App.getInstance().preferences.getString(IMAGE_SIZE, "-1")!!.toInt()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getMaxBitrateWifi(): String {
|
||||
return App.getInstance().preferences.getString(MAX_BITRATE_WIFI, "0")!!
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getMaxBitrateMobile(): String {
|
||||
return App.getInstance().preferences.getString(MAX_BITRATE_MOBILE, "0")!!
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getAudioTranscodeFormatWifi(): String {
|
||||
return App.getInstance().preferences.getString(AUDIO_TRANSCODE_FORMAT_WIFI, "raw")!!
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getAudioTranscodeFormatMobile(): String {
|
||||
return App.getInstance().preferences.getString(AUDIO_TRANSCODE_FORMAT_MOBILE, "raw")!!
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isWifiOnly(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(WIFI_ONLY, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isDataSavingMode(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(DATA_SAVING_MODE, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setDataSavingMode(isDataSavingModeEnabled: Boolean) {
|
||||
App.getInstance().preferences.edit().putBoolean(DATA_SAVING_MODE, isDataSavingModeEnabled)
|
||||
.apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isStarredSyncEnabled(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(SYNC_STARRED_TRACKS_FOR_OFFLINE_USE, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setStarredSyncEnabled(isStarredSyncEnabled: Boolean) {
|
||||
App.getInstance().preferences.edit().putBoolean(
|
||||
SYNC_STARRED_TRACKS_FOR_OFFLINE_USE, isStarredSyncEnabled
|
||||
).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showServerUnreachableDialog(): Boolean {
|
||||
return App.getInstance().preferences.getLong(
|
||||
SERVER_UNREACHABLE, 0
|
||||
) + 360000 < System.currentTimeMillis()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setServerUnreachableDatetime(datetime: Long) {
|
||||
App.getInstance().preferences.edit().putLong(SERVER_UNREACHABLE, datetime).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isSyncronizationEnabled(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(QUEUE_SYNCING, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getSyncCountdownTimer(): Int {
|
||||
return App.getInstance().preferences.getString(QUEUE_SYNCING_COUNTDOWN, "5")!!.toInt()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isCornerRoundingEnabled(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(ROUNDED_CORNER, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getRoundedCornerSize(): Int {
|
||||
return App.getInstance().preferences.getString(ROUNDED_CORNER_SIZE, "12")!!.toInt()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isPodcastSectionVisible(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(PODCAST_SECTION_VISIBILITY, true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setPodcastSectionHidden() {
|
||||
App.getInstance().preferences.edit().putBoolean(PODCAST_SECTION_VISIBILITY, false).apply()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isRadioSectionVisible(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(RADIO_SECTION_VISIBILITY, true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setRadioSectionHidden() {
|
||||
App.getInstance().preferences.edit().putBoolean(RADIO_SECTION_VISIBILITY, false).apply()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.cappielloantonio.tempo.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.InsetDrawable;
|
||||
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GoogleApiAvailability;
|
||||
|
||||
public class UIUtil {
|
||||
public static int getSpanCount(int itemCount, int maxSpan) {
|
||||
int itemSize = itemCount == 0 ? 1 : itemCount;
|
||||
|
||||
if (itemSize / maxSpan > 0) {
|
||||
return maxSpan;
|
||||
} else {
|
||||
return itemSize % maxSpan;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isCastApiAvailable(Context context) {
|
||||
return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS;
|
||||
}
|
||||
|
||||
public static DividerItemDecoration getDividerItemDecoration(Context context) {
|
||||
int[] ATTRS = new int[]{android.R.attr.listDivider};
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(ATTRS);
|
||||
Drawable divider = a.getDrawable(0);
|
||||
InsetDrawable insetDivider = new InsetDrawable(divider, 42, 0, 42, 42);
|
||||
a.recycle();
|
||||
|
||||
DividerItemDecoration itemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL);
|
||||
itemDecoration.setDrawable(insetDivider);
|
||||
|
||||
return itemDecoration;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue