build: change of package name

This commit is contained in:
antonio 2023-06-17 15:30:23 +02:00
parent 49afdbe4eb
commit b76a38cb30
274 changed files with 1981 additions and 2161 deletions

View file

@ -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
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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());
}
}

View 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("&#34;", "\"")
.replaceAll("&#39;", "'")
.replaceAll("&amp;", "'")
.replaceAll("<a\\s+([^>]+)>((?:.(?!</a>))*.)</a>", "");
}
return "";
}
public static String getReadableLyrics(String string) {
if (string != null) {
return string
.replaceAll("&#34;", "\"")
.replaceAll("&#39;", "'")
.replaceAll("&amp;", "'")
.replaceAll("&#xA;", "\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);
}
}

View 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()
}
}

View file

@ -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;
}
}