change application id for release

This commit is contained in:
dkanada 2020-05-09 04:43:09 +09:00
commit 9d08253655
159 changed files with 801 additions and 801 deletions

View file

@ -0,0 +1,125 @@
package com.dkanada.gramophone.util;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class CalendarUtil {
private static final long MS_PER_MINUTE = 60 * 1000;
private static final long MS_PER_DAY = 24 * 60 * MS_PER_MINUTE;
private Calendar calendar;
public CalendarUtil() {
this.calendar = Calendar.getInstance();
}
/**
* Returns the time elapsed so far today in milliseconds.
*
* @return Time elapsed today in milliseconds.
*/
public long getElapsedToday() {
// Time elapsed so far today
return (calendar.get(Calendar.HOUR_OF_DAY) * 60
+ calendar.get(Calendar.MINUTE)) * MS_PER_MINUTE
+ calendar.get(Calendar.SECOND) * 1000
+ calendar.get(Calendar.MILLISECOND);
}
/**
* Returns the time elapsed so far last N days in milliseconds.
*
* @return Time elapsed since N days in milliseconds.
*/
public long getElapsedDays(int numDays) {
long elapsed = getElapsedToday();
elapsed += numDays * MS_PER_DAY;
return elapsed;
}
/**
* Returns the time elapsed so far this week in milliseconds.
*
* @return Time elapsed this week in milliseconds.
*/
public long getElapsedWeek() {
// Today + days passed this week
long elapsed = getElapsedToday();
final int passedWeekdays = calendar.get(Calendar.DAY_OF_WEEK) - 1 - calendar.getFirstDayOfWeek();
if (passedWeekdays > 0) {
elapsed += passedWeekdays * MS_PER_DAY;
}
return elapsed;
}
/**
* Returns the time elapsed so far this month in milliseconds.
*
* @return Time elapsed this month in milliseconds.
*/
public long getElapsedMonth() {
// Today and the rest of this month
return getElapsedToday() + ((calendar.get(Calendar.DAY_OF_MONTH) - 1) * MS_PER_DAY);
}
/**
* Returns the time elapsed so far this month and the last numMonths months in milliseconds.
*
* @param numMonths Additional number of months prior to the current month to calculate.
* @return Time elapsed this month and the last numMonths months in milliseconds.
*/
public long getElapsedMonths(int numMonths) {
// Today and the rest of this month
long elapsed = getElapsedMonth();
// Previous numMonths months
int month = calendar.get(Calendar.MONTH);
int year = calendar.get(Calendar.YEAR);
for (int i = 0; i < numMonths; i++) {
month--;
if (month < Calendar.JANUARY) {
month = Calendar.DECEMBER;
year--;
}
elapsed += getDaysInMonth(year, month) * MS_PER_DAY;
}
return elapsed;
}
/**
* Returns the time elapsed so far this year in milliseconds.
*
* @return Time elapsed this year in milliseconds.
*/
public long getElapsedYear() {
// Today + rest of this month + previous months until January
long elapsed = getElapsedMonth();
int month = calendar.get(Calendar.MONTH) - 1;
int year = calendar.get(Calendar.YEAR);
while (month > Calendar.JANUARY) {
elapsed += getDaysInMonth(year, month) * MS_PER_DAY;
month--;
}
return elapsed;
}
/**
* Gets the number of days for the given month in the given year.
*
* @param year The year.
* @param month The month (1 - 12).
* @return The days in that month/year.
*/
private int getDaysInMonth(int year, int month) {
final Calendar monthCal = new GregorianCalendar(calendar.get(Calendar.YEAR), month, 1);
return monthCal.getActualMaximum(Calendar.DAY_OF_MONTH);
}
}

View file

@ -0,0 +1,120 @@
package com.dkanada.gramophone.util;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build;
import androidx.annotation.AttrRes;
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
import java.io.InputStream;
import com.kabouzeid.appthemehelper.util.TintHelper;
public class ImageUtil {
public static int calculateInSampleSize(int width, int height, int reqWidth) {
// setting reqWidth matching to desired 1:1 ratio and screen-size
if (width < height) {
reqWidth = (height / width) * reqWidth;
} else {
reqWidth = (width / height) * reqWidth;
}
int inSampleSize = 1;
if (height > reqWidth || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqWidth
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap resizeBitmap(@NonNull Bitmap src, int maxForSmallerSize) {
int width = src.getWidth();
int height = src.getHeight();
final int dstWidth;
final int dstHeight;
if (width < height) {
if (maxForSmallerSize >= width) {
return src;
}
float ratio = (float) height / width;
dstWidth = maxForSmallerSize;
dstHeight = Math.round(maxForSmallerSize * ratio);
} else {
if (maxForSmallerSize >= height) {
return src;
}
float ratio = (float) width / height;
dstWidth = Math.round(maxForSmallerSize * ratio);
dstHeight = maxForSmallerSize;
}
return Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);
}
public static Bitmap createBitmap(Drawable drawable) {
return createBitmap(drawable, 1f);
}
public static Bitmap createBitmap(Drawable drawable, float sizeMultiplier) {
Bitmap bitmap = Bitmap.createBitmap((int) (drawable.getIntrinsicWidth() * sizeMultiplier), (int) (drawable.getIntrinsicHeight() * sizeMultiplier), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bitmap);
drawable.setBounds(0, 0, c.getWidth(), c.getHeight());
drawable.draw(c);
return bitmap;
}
public static Drawable getVectorDrawable(@NonNull Resources res, @DrawableRes int resId, @Nullable Resources.Theme theme) {
if (Build.VERSION.SDK_INT >= 21) {
return res.getDrawable(resId, theme);
}
return VectorDrawableCompat.create(res, resId, theme);
}
public static Drawable getTintedVectorDrawable(@NonNull Resources res, @DrawableRes int resId, @Nullable Resources.Theme theme, @ColorInt int color) {
return TintHelper.createTintedDrawable(getVectorDrawable(res, resId, theme), color);
}
public static Drawable getTintedVectorDrawable(@NonNull Context context, @DrawableRes int id, @ColorInt int color) {
return TintHelper.createTintedDrawable(getVectorDrawable(context.getResources(), id, context.getTheme()), color);
}
public static Drawable getVectorDrawable(@NonNull Context context, @DrawableRes int id) {
return getVectorDrawable(context.getResources(), id, context.getTheme());
}
public static Drawable resolveDrawable(@NonNull Context context, @AttrRes int drawableAttr) {
TypedArray a = context.obtainStyledAttributes(new int[]{drawableAttr});
Drawable drawable = a.getDrawable(0);
a.recycle();
return drawable;
}
public static Bitmap resize(InputStream stream, int scaledWidth, int scaledHeight) {
final Bitmap bitmap = BitmapFactory.decodeStream(stream);
return Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, true);
}
}

View file

@ -0,0 +1,162 @@
package com.dkanada.gramophone.util;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import android.widget.Toast;
import com.dkanada.gramophone.App;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.model.Album;
import com.dkanada.gramophone.model.Artist;
import com.dkanada.gramophone.model.Genre;
import com.dkanada.gramophone.model.Playlist;
import com.dkanada.gramophone.model.Song;
import org.jellyfin.apiclient.interaction.Response;
import org.jellyfin.apiclient.model.dto.UserItemDataDto;
import java.util.List;
import java.util.Locale;
public class MusicUtil {
public static Uri getSongFileUri(Song song) {
return Uri.parse(App.getApiClient().getApiUrl() + "/Audio/" + song.id + "/stream?static=true");
}
@NonNull
public static Intent createShareSongFileIntent(@NonNull final Song song, Context context) {
try {
return new Intent();
} catch (IllegalArgumentException e) {
e.printStackTrace();
Toast.makeText(context, R.string.error_share_file, Toast.LENGTH_SHORT).show();
return new Intent();
}
}
@NonNull
public static String getArtistInfoString(@NonNull final Context context, @NonNull final Artist artist) {
return artist.genres.size() != 0 ? artist.genres.get(0).name : artist.id;
}
@NonNull
public static String getAlbumInfoString(@NonNull final Context context, @NonNull final Album album) {
return album.artistName;
}
@NonNull
public static String getSongInfoString(@NonNull final Song song) {
return song.albumName;
}
@NonNull
public static String getGenreInfoString(@NonNull final Context context, @NonNull final Genre genre) {
int songCount = genre.songCount;
return MusicUtil.getSongCountString(context, songCount);
}
@NonNull
public static String getPlaylistInfoString(@NonNull final Context context, @NonNull List<Song> songs) {
final long duration = getTotalDuration(context, songs);
return MusicUtil.buildInfoString(
MusicUtil.getSongCountString(context, songs.size()),
MusicUtil.getReadableDurationString(duration)
);
}
@NonNull
public static String getSongCountString(@NonNull final Context context, int songCount) {
final String songString = songCount == 1 ? context.getResources().getString(R.string.song) : context.getResources().getString(R.string.songs);
return songCount + " " + songString;
}
@NonNull
public static String getAlbumCountString(@NonNull final Context context, int albumCount) {
final String albumString = albumCount == 1 ? context.getResources().getString(R.string.album) : context.getResources().getString(R.string.albums);
return albumCount + " " + albumString;
}
@NonNull
public static String getYearString(int year) {
return year > 0 ? String.valueOf(year) : "-";
}
public static long getTotalDuration(@NonNull final Context context, @NonNull List<Song> songs) {
long duration = 0;
for (int i = 0; i < songs.size(); i++) {
duration += songs.get(i).duration;
}
return duration;
}
public static String getReadableDurationString(long songDurationMillis) {
long minutes = (songDurationMillis / 1000) / 60;
long seconds = (songDurationMillis / 1000) % 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);
}
}
@NonNull
public static String buildInfoString(@Nullable final String one, @Nullable final String two) {
// skip empty strings
if (TextUtils.isEmpty(one)) {
return TextUtils.isEmpty(two) ? "" : two;
}
if (TextUtils.isEmpty(two)) {
return TextUtils.isEmpty(one) ? "" : one;
}
return one + "" + two;
}
// iTunes uses for example 1002 for track 2 CD1 or 3011 for track 11 CD3.
// this method converts those values to normal track numbers
public static int getFixedTrackNumber(int trackNumberToFix) {
return trackNumberToFix % 1000;
}
public static void toggleFavorite(@NonNull final Context context, @NonNull final Song song) {
song.favorite = !song.favorite;
String user = App.getApiClient().getCurrentUserId();
App.getApiClient().UpdateFavoriteStatusAsync(song.id, user, song.favorite, new Response<UserItemDataDto>() {
@Override
public void onResponse(UserItemDataDto data) {
song.favorite = data.getIsFavorite();
}
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
}
);
}
@NonNull
public static String getSectionName(@Nullable String musicMediaTitle) {
if (TextUtils.isEmpty(musicMediaTitle)) return "";
musicMediaTitle = musicMediaTitle.trim().toLowerCase();
if (musicMediaTitle.startsWith("the ")) {
musicMediaTitle = musicMediaTitle.substring(4);
} else if (musicMediaTitle.startsWith("a ")) {
musicMediaTitle = musicMediaTitle.substring(2);
}
if (musicMediaTitle.isEmpty()) return "";
return String.valueOf(musicMediaTitle.charAt(0)).toUpperCase();
}
}

View file

@ -0,0 +1,58 @@
package com.dkanada.gramophone.util;
import android.app.Activity;
import android.content.Intent;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityOptionsCompat;
import androidx.core.util.Pair;
import com.dkanada.gramophone.model.Album;
import com.dkanada.gramophone.model.Artist;
import com.dkanada.gramophone.model.Genre;
import com.dkanada.gramophone.model.Playlist;
import com.dkanada.gramophone.model.Song;
import com.dkanada.gramophone.ui.activities.AlbumDetailActivity;
import com.dkanada.gramophone.ui.activities.ArtistDetailActivity;
import com.dkanada.gramophone.ui.activities.GenreDetailActivity;
import com.dkanada.gramophone.ui.activities.PlaylistDetailActivity;
public class NavigationUtil {
public static void goToArtist(@NonNull final Activity activity, final Artist artist, @Nullable Pair... sharedElements) {
final Intent intent = new Intent(activity, ArtistDetailActivity.class);
intent.putExtra(ArtistDetailActivity.EXTRA_ARTIST, artist);
startActivitySharedElements(activity, intent, sharedElements);
}
public static void goToAlbum(@NonNull final Activity activity, final Album album, @Nullable Pair... sharedElements) {
final Intent intent = new Intent(activity, AlbumDetailActivity.class);
intent.putExtra(AlbumDetailActivity.EXTRA_ALBUM, album);
startActivitySharedElements(activity, intent, sharedElements);
}
public static void goToGenre(@NonNull final Activity activity, final Genre genre, @Nullable Pair... sharedElements) {
final Intent intent = new Intent(activity, GenreDetailActivity.class);
intent.putExtra(GenreDetailActivity.EXTRA_GENRE, genre);
startActivitySharedElements(activity, intent, sharedElements);
}
public static void goToPlaylist(@NonNull final Activity activity, final Playlist playlist, @Nullable Pair... sharedElements) {
final Intent intent = new Intent(activity, PlaylistDetailActivity.class);
intent.putExtra(PlaylistDetailActivity.EXTRA_PLAYLIST, playlist);
startActivitySharedElements(activity, intent, sharedElements);
}
public static void startActivitySharedElements(@NonNull final Activity activity, Intent intent, @Nullable Pair... sharedElements) {
if (sharedElements != null && sharedElements.length > 0) {
// noinspection unchecked
activity.startActivity(intent, ActivityOptionsCompat.makeSceneTransitionAnimation(activity, sharedElements).toBundle());
} else {
activity.startActivity(intent);
}
}
}

View file

@ -0,0 +1,103 @@
package com.dkanada.gramophone.util;
import com.dkanada.gramophone.App;
import com.dkanada.gramophone.interfaces.MediaCallback;
import com.dkanada.gramophone.model.Playlist;
import com.dkanada.gramophone.model.PlaylistSong;
import com.dkanada.gramophone.model.Song;
import org.jellyfin.apiclient.interaction.EmptyResponse;
import org.jellyfin.apiclient.interaction.Response;
import org.jellyfin.apiclient.model.dto.BaseItemDto;
import org.jellyfin.apiclient.model.playlists.PlaylistCreationRequest;
import org.jellyfin.apiclient.model.playlists.PlaylistItemQuery;
import org.jellyfin.apiclient.model.querying.ItemsResult;
import java.util.ArrayList;
import java.util.List;
public class PlaylistUtil {
public static void getPlaylist(PlaylistItemQuery query, MediaCallback callback) {
query.setUserId(App.getApiClient().getCurrentUserId());
query.setLimit(100);
App.getApiClient().GetPlaylistItems(query, new Response<ItemsResult>() {
@Override
public void onResponse(ItemsResult result) {
List<PlaylistSong> songs = new ArrayList<>();
for (BaseItemDto itemDto : result.getItems()) {
songs.add(new PlaylistSong(itemDto, query.getId()));
}
callback.onLoadMedia(songs);
}
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
});
}
public static void createPlaylist(final String name, final List<Song> songs) {
ArrayList<String> ids = new ArrayList<>();
for (Song song : songs) {
ids.add(song.id);
}
PlaylistCreationRequest request = new PlaylistCreationRequest();
request.setUserId(App.getApiClient().getCurrentUserId());
request.setName(name);
if (ids.size() != 0) request.setItemIdList(ids);
App.getApiClient().CreatePlaylist(request, new Response<>());
}
public static void deletePlaylist(final List<Playlist> playlists) {
for (Playlist playlist : playlists) {
App.getApiClient().DeleteItem(playlist.id, new EmptyResponse());
}
}
public static void addItems(final List<Song> songs, final String playlist) {
String[] ids = new String[songs.size()];
for (int i = 0; i < songs.size(); i++) {
ids[i] = songs.get(i).id;
}
String user = App.getApiClient().getCurrentUserId();
App.getApiClient().AddToPlaylist(playlist, ids, user, new EmptyResponse());
}
public static void deleteItems(final List<PlaylistSong> songs, final String playlist) {
String[] ids = new String[songs.size()];
for (int i = 0; i < songs.size(); i++) {
ids[i] = songs.get(i).indexId;
}
App.getApiClient().RemoveFromPlaylist(playlist, ids, new EmptyResponse());
}
public static void moveItem(final String playlist, final PlaylistSong song, int to) {
App.getApiClient().MoveItem(playlist, song.indexId, to, new EmptyResponse());
}
public static void renamePlaylist(final String playlist, final String name) {
String user = App.getApiClient().getCurrentUserId();
App.getApiClient().GetItemAsync(playlist, user, new Response<BaseItemDto>() {
@Override
public void onResponse(BaseItemDto itemDto) {
itemDto.setName(name);
renamePlaylistInner(itemDto);
}
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
});
}
public static void renamePlaylistInner(final BaseItemDto itemDto) {
// TODO at some point this should become metadata utilities
App.getApiClient().UpdateItem(itemDto.getId(), itemDto, new EmptyResponse());
}
}

View file

@ -0,0 +1,392 @@
package com.dkanada.gramophone.util;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import androidx.annotation.StyleRes;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.helper.sort.SortMethod;
import com.dkanada.gramophone.helper.sort.SortOrder;
import com.dkanada.gramophone.model.CategoryInfo;
import com.dkanada.gramophone.ui.fragments.player.NowPlayingScreen;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
public final class PreferenceUtil {
public static final String LIBRARY_CATEGORIES = "library_categories";
public static final String REMEMBER_LAST_TAB = "remember_last_tab";
public static final String LAST_TAB = "last_tab";
public static final String NOW_PLAYING_SCREEN = "now_playing_screen";
public static final String ALBUM_SORT_METHOD = "album_sort_method";
public static final String SONG_SORT_METHOD = "song_sort_method";
public static final String ALBUM_SORT_ORDER = "album_sort_order";
public static final String SONG_SORT_ORDER = "song_sort_order";
public static final String ALBUM_GRID_SIZE = "album_grid_size";
public static final String ALBUM_GRID_SIZE_LAND = "album_grid_size_land";
public static final String SONG_GRID_SIZE = "song_grid_size";
public static final String SONG_GRID_SIZE_LAND = "song_grid_size_land";
public static final String ARTIST_GRID_SIZE = "artist_grid_size";
public static final String ARTIST_GRID_SIZE_LAND = "artist_grid_size_land";
public static final String ALBUM_COLORED_FOOTERS = "album_colored_footers";
public static final String SONG_COLORED_FOOTERS = "song_colored_footers";
public static final String ARTIST_COLORED_FOOTERS = "artist_colored_footers";
public static final String ALBUM_ARTIST_COLORED_FOOTERS = "album_artist_colored_footers";
public static final String COLORED_NOTIFICATION = "colored_notification";
public static final String CLASSIC_NOTIFICATION = "classic_notification";
public static final String GENERAL_THEME = "general_theme";
public static final String COLORED_SHORTCUTS = "colored_shortcuts";
public static final String AUDIO_DUCKING = "audio_ducking";
public static final String GAPLESS_PLAYBACK = "gapless_playback";
public static final String REMEMBER_SHUFFLE = "remember_shuffle";
public static final String SHOW_ALBUM_COVER = "show_album_cover";
public static final String BLUR_ALBUM_COVER = "blur_album_cover";
public static final String SLEEP_TIMER_LAST_VALUE = "sleep_timer_last_value";
public static final String SLEEP_TIMER_ELAPSED_REALTIME = "sleep_timer_elapsed_real_time";
public static final String SLEEP_TIMER_FINISH_SONG = "sleep_timer_finish_music";
private static PreferenceUtil sInstance;
private final SharedPreferences mPreferences;
private PreferenceUtil(final Context context) {
mPreferences = PreferenceManager.getDefaultSharedPreferences(context);
}
public static PreferenceUtil getInstance(final Context context) {
if (sInstance == null) {
sInstance = new PreferenceUtil(context.getApplicationContext());
}
return sInstance;
}
public void registerOnSharedPreferenceChangedListener(SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener) {
mPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
}
public void unregisterOnSharedPreferenceChangedListener(SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener) {
mPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
}
@StyleRes
public int getGeneralTheme() {
return getThemeResFromPrefValue(mPreferences.getString(GENERAL_THEME, "dark"));
}
@StyleRes
public static int getThemeResFromPrefValue(String themePrefValue) {
switch (themePrefValue) {
case "light":
return R.style.Theme_Phonograph_Light;
case "black":
return R.style.Theme_Phonograph_Black;
case "dark":
default:
return R.style.Theme_Phonograph;
}
}
public final boolean getRememberLastTab() {
return mPreferences.getBoolean(REMEMBER_LAST_TAB, true);
}
public final int getLastTab() {
return mPreferences.getInt(LAST_TAB, 0);
}
public void setLastTab(final int value) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putInt(LAST_TAB, value);
editor.apply();
}
public final NowPlayingScreen getNowPlayingScreen() {
int id = mPreferences.getInt(NOW_PLAYING_SCREEN, 0);
for (NowPlayingScreen nowPlayingScreen : NowPlayingScreen.values()) {
if (nowPlayingScreen.id == id) return nowPlayingScreen;
}
return NowPlayingScreen.CARD;
}
public void setNowPlayingScreen(NowPlayingScreen nowPlayingScreen) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putInt(NOW_PLAYING_SCREEN, nowPlayingScreen.id);
editor.apply();
}
public final boolean getColoredNotification() {
return mPreferences.getBoolean(COLORED_NOTIFICATION, true);
}
public void setColoredNotification(final boolean value) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putBoolean(COLORED_NOTIFICATION, value);
editor.apply();
}
public final boolean getClassicNotification() {
return mPreferences.getBoolean(CLASSIC_NOTIFICATION, true);
}
public void setClassicNotification(final boolean value) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putBoolean(CLASSIC_NOTIFICATION, value);
editor.apply();
}
public final boolean getColoredShortcuts() {
return mPreferences.getBoolean(COLORED_SHORTCUTS, true);
}
public void setColoredShortcuts(final boolean value) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putBoolean(COLORED_SHORTCUTS, value);
editor.apply();
}
public final boolean getAudioDucking() {
return mPreferences.getBoolean(AUDIO_DUCKING, true);
}
public final boolean getGaplessPlayback() {
return mPreferences.getBoolean(GAPLESS_PLAYBACK, true);
}
public final boolean getRememberShuffle() {
return mPreferences.getBoolean(REMEMBER_SHUFFLE, true);
}
public final boolean getShowAlbumCover() {
return mPreferences.getBoolean(SHOW_ALBUM_COVER, true);
}
public final boolean getBlurAlbumCover() {
return mPreferences.getBoolean(BLUR_ALBUM_COVER, true);
}
public final String getAlbumSortOrder() {
return mPreferences.getString(ALBUM_SORT_ORDER, SortOrder.DESCENDING);
}
public void setAlbumSortOrder(final String sortOrder) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putString(ALBUM_SORT_ORDER, sortOrder);
editor.commit();
}
public final String getSongSortOrder() {
return mPreferences.getString(SONG_SORT_ORDER, SortOrder.DESCENDING);
}
public void setSongSortOrder(final String sortOrder) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putString(SONG_SORT_ORDER, sortOrder);
editor.commit();
}
public final String getAlbumSortMethod() {
return mPreferences.getString(ALBUM_SORT_METHOD, SortMethod.NAME);
}
public void setAlbumSortMethod(final String sortMethod) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putString(ALBUM_SORT_METHOD, sortMethod);
editor.commit();
}
public final String getSongSortMethod() {
return mPreferences.getString(SONG_SORT_METHOD, SortMethod.NAME);
}
public void setSongSortMethod(final String sortMethod) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putString(SONG_SORT_METHOD, sortMethod);
editor.commit();
}
public int getLastSleepTimerValue() {
return mPreferences.getInt(SLEEP_TIMER_LAST_VALUE, 30);
}
public void setLastSleepTimerValue(final int value) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putInt(SLEEP_TIMER_LAST_VALUE, value);
editor.apply();
}
public long getNextSleepTimerElapsedRealTime() {
return mPreferences.getLong(SLEEP_TIMER_ELAPSED_REALTIME, -1);
}
public void setNextSleepTimerElapsedRealtime(final long value) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putLong(SLEEP_TIMER_ELAPSED_REALTIME, value);
editor.apply();
}
public boolean getSleepTimerFinishMusic() {
return mPreferences.getBoolean(SLEEP_TIMER_FINISH_SONG, false);
}
public void setSleepTimerFinishMusic(final boolean value) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putBoolean(SLEEP_TIMER_FINISH_SONG, value);
editor.apply();
}
public final int getAlbumGridSize(Context context) {
return mPreferences.getInt(ALBUM_GRID_SIZE, context.getResources().getInteger(R.integer.default_grid_columns));
}
public void setAlbumGridSize(final int gridSize) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putInt(ALBUM_GRID_SIZE, gridSize);
editor.apply();
}
public final int getSongGridSize(Context context) {
return mPreferences.getInt(SONG_GRID_SIZE, context.getResources().getInteger(R.integer.default_list_columns));
}
public void setSongGridSize(final int gridSize) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putInt(SONG_GRID_SIZE, gridSize);
editor.apply();
}
public final int getArtistGridSize(Context context) {
return mPreferences.getInt(ARTIST_GRID_SIZE, context.getResources().getInteger(R.integer.default_list_columns));
}
public void setArtistGridSize(final int gridSize) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putInt(ARTIST_GRID_SIZE, gridSize);
editor.apply();
}
public final int getAlbumGridSizeLand(Context context) {
return mPreferences.getInt(ALBUM_GRID_SIZE_LAND, context.getResources().getInteger(R.integer.default_grid_columns_land));
}
public void setAlbumGridSizeLand(final int gridSize) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putInt(ALBUM_GRID_SIZE_LAND, gridSize);
editor.apply();
}
public final int getSongGridSizeLand(Context context) {
return mPreferences.getInt(SONG_GRID_SIZE_LAND, context.getResources().getInteger(R.integer.default_list_columns_land));
}
public void setSongGridSizeLand(final int gridSize) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putInt(SONG_GRID_SIZE_LAND, gridSize);
editor.apply();
}
public final int getArtistGridSizeLand(Context context) {
return mPreferences.getInt(ARTIST_GRID_SIZE_LAND, context.getResources().getInteger(R.integer.default_list_columns_land));
}
public void setArtistGridSizeLand(final int gridSize) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putInt(ARTIST_GRID_SIZE_LAND, gridSize);
editor.apply();
}
public final boolean getAlbumColoredFooters() {
return mPreferences.getBoolean(ALBUM_COLORED_FOOTERS, true);
}
public void setAlbumColoredFooters(final boolean value) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putBoolean(ALBUM_COLORED_FOOTERS, value);
editor.apply();
}
public final boolean getAlbumArtistColoredFooters() {
return mPreferences.getBoolean(ALBUM_ARTIST_COLORED_FOOTERS, true);
}
public void setAlbumArtistColoredFooters(final boolean value) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putBoolean(ALBUM_ARTIST_COLORED_FOOTERS, value);
editor.apply();
}
public final boolean getSongColoredFooters() {
return mPreferences.getBoolean(SONG_COLORED_FOOTERS, true);
}
public void setSongColoredFooters(final boolean value) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putBoolean(SONG_COLORED_FOOTERS, value);
editor.apply();
}
public final boolean getArtistColoredFooters() {
return mPreferences.getBoolean(ARTIST_COLORED_FOOTERS, true);
}
public void setArtistColoredFooters(final boolean value) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putBoolean(ARTIST_COLORED_FOOTERS, value);
editor.apply();
}
public List<CategoryInfo> getLibraryCategories() {
String data = mPreferences.getString(LIBRARY_CATEGORIES, null);
if (data != null) {
Gson gson = new Gson();
Type collectionType = new TypeToken<List<CategoryInfo>>() {
}.getType();
try {
return gson.fromJson(data, collectionType);
} catch (JsonSyntaxException e) {
e.printStackTrace();
}
}
return getDefaultLibraryCategories();
}
public void setLibraryCategories(List<CategoryInfo> categories) {
Gson gson = new Gson();
Type collectionType = new TypeToken<List<CategoryInfo>>() {}.getType();
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putString(LIBRARY_CATEGORIES, gson.toJson(categories, collectionType));
editor.apply();
}
public List<CategoryInfo> getDefaultLibraryCategories() {
List<CategoryInfo> defaultCategories = new ArrayList<>(5);
defaultCategories.add(new CategoryInfo(CategoryInfo.Category.SONGS, true));
defaultCategories.add(new CategoryInfo(CategoryInfo.Category.ALBUMS, true));
defaultCategories.add(new CategoryInfo(CategoryInfo.Category.ARTISTS, true));
defaultCategories.add(new CategoryInfo(CategoryInfo.Category.GENRES, true));
defaultCategories.add(new CategoryInfo(CategoryInfo.Category.PLAYLISTS, true));
return defaultCategories;
}
}

View file

@ -0,0 +1,220 @@
package com.dkanada.gramophone.util;
import com.dkanada.gramophone.App;
import com.dkanada.gramophone.helper.sort.SortMethod;
import com.dkanada.gramophone.interfaces.MediaCallback;
import com.dkanada.gramophone.model.Album;
import com.dkanada.gramophone.model.Artist;
import com.dkanada.gramophone.model.Genre;
import com.dkanada.gramophone.model.Playlist;
import com.dkanada.gramophone.model.Song;
import org.jellyfin.apiclient.interaction.Response;
import org.jellyfin.apiclient.model.dto.BaseItemDto;
import org.jellyfin.apiclient.model.dto.BaseItemType;
import org.jellyfin.apiclient.model.querying.ArtistsQuery;
import org.jellyfin.apiclient.model.querying.ItemFields;
import org.jellyfin.apiclient.model.querying.ItemQuery;
import org.jellyfin.apiclient.model.querying.ItemsByNameQuery;
import org.jellyfin.apiclient.model.querying.ItemsResult;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class QueryUtil {
public static BaseItemDto currentLibrary;
// TODO return BaseItemDto everywhere
// will simplify the code for the getPlaylists method
public static void getLibraries(MediaCallback callback) {
String id = App.getApiClient().getCurrentUserId();
App.getApiClient().GetUserViews(id, new Response<ItemsResult>() {
@Override
public void onResponse(ItemsResult result) {
List<BaseItemDto> libraries = new ArrayList<>();
libraries.addAll(Arrays.asList(result.getItems()));
callback.onLoadMedia(libraries);
}
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
});
}
public static void getPlaylists(MediaCallback callback) {
ItemQuery query = new ItemQuery();
query.setIncludeItemTypes(new String[]{"Playlist"});
query.setUserId(App.getApiClient().getCurrentUserId());
query.setLimit(100);
query.setRecursive(true);
if (currentLibrary != null && query.getParentId() == null) query.setParentId(currentLibrary.getId());
App.getApiClient().GetItemsAsync(query, new Response<ItemsResult>() {
@Override
public void onResponse(ItemsResult result) {
List<Playlist> playlists = new ArrayList<>();
for (BaseItemDto itemDto : result.getItems()) {
playlists.add(new Playlist(itemDto));
}
callback.onLoadMedia(playlists);
}
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
});
}
public static void getGenres(MediaCallback callback) {
ItemsByNameQuery query = new ItemsByNameQuery();
query.setUserId(App.getApiClient().getCurrentUserId());
query.setLimit(100);
query.setRecursive(true);
if (currentLibrary != null && query.getParentId() == null) query.setParentId(currentLibrary.getId());
App.getApiClient().GetGenresAsync(query, new Response<ItemsResult>() {
@Override
public void onResponse(ItemsResult result) {
List<Genre> genres = new ArrayList<>();
for (BaseItemDto itemDto : result.getItems()) {
genres.add(new Genre(itemDto));
}
callback.onLoadMedia(genres);
}
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
});
}
public static void getItems(ItemQuery query, MediaCallback callback) {
query.setIncludeItemTypes(new String[]{"MusicArtist", "MusicAlbum", "Audio"});
query.setUserId(App.getApiClient().getCurrentUserId());
query.setLimit(40);
query.setRecursive(true);
App.getApiClient().GetItemsAsync(query, new Response<ItemsResult>() {
@Override
public void onResponse(ItemsResult result) {
List<Object> items = new ArrayList<>();
for (BaseItemDto itemDto : result.getItems()) {
if (itemDto.getBaseItemType() == BaseItemType.MusicArtist) {
items.add(new Artist(itemDto));
} else if (itemDto.getBaseItemType() == BaseItemType.MusicAlbum) {
items.add(new Album(itemDto));
} else {
items.add(new Song(itemDto));
}
}
callback.onLoadMedia(items);
}
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
});
}
public static void getAlbums(ItemQuery query, MediaCallback callback) {
query.setIncludeItemTypes(new String[]{"MusicAlbum"});
query.setUserId(App.getApiClient().getCurrentUserId());
query.setLimit(100);
query.setRecursive(true);
applySortMethod(query, PreferenceUtil.getInstance(App.getInstance()).getAlbumSortMethod());
if (currentLibrary != null && query.getParentId() == null) query.setParentId(currentLibrary.getId());
App.getApiClient().GetItemsAsync(query, new Response<ItemsResult>() {
@Override
public void onResponse(ItemsResult result) {
List<Album> albums = new ArrayList<>();
for (BaseItemDto itemDto : result.getItems()) {
albums.add(new Album(itemDto));
}
callback.onLoadMedia(albums);
}
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
});
}
public static void getArtists(MediaCallback callback) {
ArtistsQuery query = new ArtistsQuery();
query.setFields(new ItemFields[]{ItemFields.Genres});
query.setUserId(App.getApiClient().getCurrentUserId());
query.setLimit(100);
query.setRecursive(true);
if (currentLibrary != null && query.getParentId() == null) query.setParentId(currentLibrary.getId());
App.getApiClient().GetAlbumArtistsAsync(query, new Response<ItemsResult>() {
@Override
public void onResponse(ItemsResult result) {
List<Artist> artists = new ArrayList<>();
for (BaseItemDto itemDto : result.getItems()) {
artists.add(new Artist(itemDto));
}
callback.onLoadMedia(artists);
}
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
});
}
public static void getSongs(ItemQuery query, MediaCallback callback) {
query.setIncludeItemTypes(new String[]{"Audio"});
query.setUserId(App.getApiClient().getCurrentUserId());
query.setLimit(100);
query.setRecursive(true);
applySortMethod(query, PreferenceUtil.getInstance(App.getInstance()).getSongSortMethod());
if (currentLibrary != null && query.getParentId() == null) query.setParentId(currentLibrary.getId());
App.getApiClient().GetItemsAsync(query, new Response<ItemsResult>() {
@Override
public void onResponse(ItemsResult result) {
List<Song> songs = new ArrayList<>();
for (BaseItemDto itemDto : result.getItems()) {
songs.add(new Song(itemDto));
}
callback.onLoadMedia(songs);
}
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
});
}
private static void applySortMethod(ItemQuery query, String method) {
switch (method) {
case SortMethod.NAME:
query.setSortBy(new String[]{"SortName"});
break;
case SortMethod.ALBUM:
query.setSortBy(new String[]{"Album"});
break;
case SortMethod.ARTIST:
query.setSortBy(new String[]{"AlbumArtist"});
break;
case SortMethod.YEAR:
query.setSortBy(new String[]{"ProductionYear"});
break;
case SortMethod.RANDOM:
query.setSortBy(new String[]{"Random"});
break;
}
}
}

View file

@ -0,0 +1,78 @@
package com.dkanada.gramophone.util;
import android.graphics.Bitmap;
import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import androidx.palette.graphics.Palette;
import com.kabouzeid.appthemehelper.util.ColorUtil;
import java.util.Collections;
import java.util.Comparator;
public class ThemeUtil {
@Nullable
public static Palette generatePalette(Bitmap bitmap) {
if (bitmap == null) return null;
return Palette.from(bitmap).generate();
}
@ColorInt
public static int getColor(@Nullable Palette palette, int fallback) {
if (palette != null) {
if (palette.getVibrantSwatch() != null) {
return palette.getVibrantSwatch().getRgb();
} else if (palette.getMutedSwatch() != null) {
return palette.getMutedSwatch().getRgb();
} else if (palette.getDarkVibrantSwatch() != null) {
return palette.getDarkVibrantSwatch().getRgb();
} else if (palette.getDarkMutedSwatch() != null) {
return palette.getDarkMutedSwatch().getRgb();
} else if (palette.getLightVibrantSwatch() != null) {
return palette.getLightVibrantSwatch().getRgb();
} else if (palette.getLightMutedSwatch() != null) {
return palette.getLightMutedSwatch().getRgb();
} else if (!palette.getSwatches().isEmpty()) {
return Collections.max(palette.getSwatches(), SwatchComparator.getInstance()).getRgb();
}
}
return fallback;
}
private static class SwatchComparator implements Comparator<Palette.Swatch> {
private static SwatchComparator sInstance;
static SwatchComparator getInstance() {
if (sInstance == null) {
sInstance = new SwatchComparator();
}
return sInstance;
}
@Override
public int compare(Palette.Swatch lhs, Palette.Swatch rhs) {
return lhs.getPopulation() - rhs.getPopulation();
}
}
@ColorInt
public static int shiftBackgroundColorForLightText(@ColorInt int backgroundColor) {
while (ColorUtil.isColorLight(backgroundColor)) {
backgroundColor = ColorUtil.darkenColor(backgroundColor);
}
return backgroundColor;
}
@ColorInt
public static int shiftBackgroundColorForDarkText(@ColorInt int backgroundColor) {
while (!ColorUtil.isColorLight(backgroundColor)) {
backgroundColor = ColorUtil.lightenColor(backgroundColor);
}
return backgroundColor;
}
}

View file

@ -0,0 +1,86 @@
package com.dkanada.gramophone.util;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Point;
import android.os.Build;
import androidx.annotation.AttrRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.util.TypedValue;
import android.view.Display;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import com.dkanada.gramophone.R;
public class Util {
public static int getActionBarSize(@NonNull Context context) {
TypedValue typedValue = new TypedValue();
int[] textSizeAttr = new int[]{R.attr.actionBarSize};
int indexOfAttrTextSize = 0;
TypedArray a = context.obtainStyledAttributes(typedValue.data, textSizeAttr);
int actionBarSize = a.getDimensionPixelSize(indexOfAttrTextSize, -1);
a.recycle();
return actionBarSize;
}
public static Point getScreenSize(@NonNull Context c) {
Display display = ((WindowManager) c.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size;
}
@TargetApi(Build.VERSION_CODES.KITKAT)
public static void setStatusBarTranslucent(@NonNull Window window) {
window.setFlags(
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
public static void setAllowDrawUnderStatusBar(@NonNull Window window) {
window.getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
public static void hideSoftKeyboard(@Nullable Activity activity) {
if (activity != null) {
View currentFocus = activity.getCurrentFocus();
if (currentFocus != null) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0);
}
}
}
public static boolean isTablet(@NonNull final Resources resources) {
return resources.getConfiguration().smallestScreenWidthDp >= 600;
}
public static boolean isLandscape(@NonNull final Resources resources) {
return resources.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
}
public static int resolveDimensionPixelSize(@NonNull Context context, @AttrRes int dimenAttr) {
TypedArray a = context.obtainStyledAttributes(new int[]{dimenAttr});
int dimensionPixelSize = a.getDimensionPixelSize(0, 0);
a.recycle();
return dimensionPixelSize;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public static boolean isRTL(@NonNull Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Configuration config = context.getResources().getConfiguration();
return config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
} else return false;
}
}

View file

@ -0,0 +1,95 @@
package com.dkanada.gramophone.util;
import android.animation.Animator;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Build;
import androidx.annotation.ColorInt;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.animation.PathInterpolator;
import android.widget.TextView;
import com.kabouzeid.appthemehelper.util.ATHUtil;
import com.kabouzeid.appthemehelper.util.ColorUtil;
import com.kabouzeid.appthemehelper.util.MaterialValueHelper;
import com.dkanada.gramophone.R;
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
public class ViewUtil {
public final static int PHONOGRAPH_ANIM_TIME = 1000;
public static Animator createBackgroundColorTransition(final View v, @ColorInt final int startColor, @ColorInt final int endColor) {
return createColorAnimator(v, "backgroundColor", startColor, endColor);
}
public static Animator createTextColorTransition(final TextView v, @ColorInt final int startColor, @ColorInt final int endColor) {
return createColorAnimator(v, "textColor", startColor, endColor);
}
private static Animator createColorAnimator(Object target, String propertyName, @ColorInt int startColor, @ColorInt int endColor) {
ObjectAnimator animator;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
animator = ObjectAnimator.ofArgb(target, propertyName, startColor, endColor);
} else {
animator = ObjectAnimator.ofInt(target, propertyName, startColor, endColor);
animator.setEvaluator(new ArgbEvaluator());
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
animator.setInterpolator(new PathInterpolator(0.4f, 0f, 1f, 1f));
}
animator.setDuration(PHONOGRAPH_ANIM_TIME);
return animator;
}
public static Drawable createSelectorDrawable(Context context, @ColorInt int color) {
final StateListDrawable baseSelector = new StateListDrawable();
baseSelector.addState(new int[]{android.R.attr.state_activated}, new ColorDrawable(color));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return new RippleDrawable(ColorStateList.valueOf(color), baseSelector, new ColorDrawable(Color.WHITE));
}
baseSelector.addState(new int[]{}, new ColorDrawable(Color.TRANSPARENT));
baseSelector.addState(new int[]{android.R.attr.state_pressed}, new ColorDrawable(color));
return baseSelector;
}
public static boolean hitTest(View v, int x, int y) {
final int tx = (int) (v.getTranslationX() + 0.5f);
final int ty = (int) (v.getTranslationY() + 0.5f);
final int left = v.getLeft() + tx;
final int right = v.getRight() + tx;
final int top = v.getTop() + ty;
final int bottom = v.getBottom() + ty;
return (x >= left) && (x <= right) && (y >= top) && (y <= bottom);
}
public static void setUpFastScrollRecyclerViewColor(Context context, FastScrollRecyclerView recyclerView, int accentColor) {
recyclerView.setPopupBgColor(accentColor);
recyclerView.setPopupTextColor(MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(accentColor)));
recyclerView.setThumbColor(accentColor);
recyclerView.setTrackColor(ColorUtil.withAlpha(ATHUtil.resolveColor(context, R.attr.colorControlNormal), 0.12f));
}
public static float convertDpToPixel(float dp, Resources resources) {
DisplayMetrics metrics = resources.getDisplayMetrics();
return dp * metrics.density;
}
public static float convertPixelsToDp(float px, Resources resources) {
DisplayMetrics metrics = resources.getDisplayMetrics();
return px / metrics.density;
}
}