Merge branch 'RetroMusicPlayer:dev' into feat/audio_focus_2

This commit is contained in:
Doozy 2022-05-06 21:28:11 +03:00 committed by GitHub
commit 51f772247a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
305 changed files with 2587 additions and 5938 deletions

View file

@ -1,54 +0,0 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.util;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.annotation.NonNull;
import com.bumptech.glide.signature.ObjectKey;
/** @author Karim Abou Zeid (kabouzeid) */
public class ArtistSignatureUtil {
private static final String ARTIST_SIGNATURE_PREFS = "artist_signatures";
private static ArtistSignatureUtil sInstance;
private final SharedPreferences mPreferences;
private ArtistSignatureUtil(@NonNull final Context context) {
mPreferences = context.getSharedPreferences(ARTIST_SIGNATURE_PREFS, Context.MODE_PRIVATE);
}
public static ArtistSignatureUtil getInstance(@NonNull final Context context) {
if (sInstance == null) {
sInstance = new ArtistSignatureUtil(context.getApplicationContext());
}
return sInstance;
}
public void updateArtistSignature(String artistName) {
mPreferences.edit().putLong(artistName, System.currentTimeMillis()).apply();
}
public long getArtistSignatureRaw(String artistName) {
return mPreferences.getLong(artistName, 0);
}
public ObjectKey getArtistSignature(String artistName) {
return new ObjectKey(String.valueOf(getArtistSignatureRaw(artistName)));
}
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.util
import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import com.bumptech.glide.signature.ObjectKey
/** @author Karim Abou Zeid (kabouzeid)
*/
class ArtistSignatureUtil private constructor(context: Context) {
private val mPreferences: SharedPreferences =
context.getSharedPreferences(ARTIST_SIGNATURE_PREFS, Context.MODE_PRIVATE)
fun updateArtistSignature(artistName: String?) {
mPreferences.edit { putLong(artistName, System.currentTimeMillis()) }
}
private fun getArtistSignatureRaw(artistName: String?): Long {
return mPreferences.getLong(artistName, 0)
}
fun getArtistSignature(artistName: String?): ObjectKey {
return ObjectKey(getArtistSignatureRaw(artistName).toString())
}
companion object {
private const val ARTIST_SIGNATURE_PREFS = "artist_signatures"
private var INSTANCE: ArtistSignatureUtil? = null
fun getInstance(context: Context): ArtistSignatureUtil {
if (INSTANCE == null) {
INSTANCE = ArtistSignatureUtil(context.applicationContext)
}
return INSTANCE!!
}
}
}

View file

@ -1,52 +0,0 @@
package code.name.monkey.retromusic.util;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import androidx.annotation.NonNull;
import com.bumptech.glide.Glide;
import java.util.ArrayList;
import java.util.List;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.model.Song;
public class AutoGeneratedPlaylistBitmap {
public static Bitmap getBitmap(
Context context, List<Song> songPlaylist) {
if (songPlaylist == null || songPlaylist.isEmpty()) return getDefaultBitmap(context);
if (songPlaylist.size() == 1)
return getBitmapWithAlbumId(context, songPlaylist.get(0).getAlbumId());
List<Long> albumID = new ArrayList<>();
for (Song song : songPlaylist) {
if (!albumID.contains(song.getAlbumId())) albumID.add(song.getAlbumId());
}
List<Bitmap> art = new ArrayList<>();
for (Long id : albumID) {
Bitmap bitmap = getBitmapWithAlbumId(context, id);
if (bitmap != null) art.add(BitmapEditor.getRoundedCornerBitmap(bitmap, 20));
if (art.size() == 9) break;
}
return MergedImageUtils.INSTANCE.joinImages(art);
}
private static Bitmap getBitmapWithAlbumId(@NonNull Context context, Long id) {
try {
return Glide.with(context)
.asBitmap()
.load(MusicUtil.getMediaStoreAlbumCoverUri(id))
.submit(200, 200)
.get();
} catch (Exception e) {
return null;
}
}
public static Bitmap getDefaultBitmap(@NonNull Context context) {
return BitmapFactory.decodeResource(context.getResources(), R.drawable.default_album_art);
}
}

View file

@ -0,0 +1,48 @@
package code.name.monkey.retromusic.util
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MergedImageUtils.joinImages
import code.name.monkey.retromusic.util.MusicUtil.getMediaStoreAlbumCoverUri
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
object AutoGeneratedPlaylistBitmap {
fun getBitmap(
context: Context, songPlaylist: List<Song>?
): Bitmap? {
if (songPlaylist == null || songPlaylist.isEmpty()) return getDefaultBitmap(context)
if (songPlaylist.size == 1) return getBitmapWithAlbumId(context, songPlaylist[0].albumId)
val albumID: MutableList<Long> = ArrayList()
for (song in songPlaylist) {
if (!albumID.contains(song.albumId)) albumID.add(song.albumId)
}
val art: MutableList<Bitmap> = ArrayList()
for (id in albumID) {
val bitmap = getBitmapWithAlbumId(context, id)
if (bitmap != null) art.add(bitmap)
if (art.size == 9) break
}
return joinImages(art)
}
private fun getBitmapWithAlbumId(context: Context, id: Long): Bitmap? {
return try {
GlideApp.with(context)
.asBitmap()
.transform(RoundedCorners(20))
.load(getMediaStoreAlbumCoverUri(id))
.submit(200, 200)
.get()
} catch (e: Exception) {
null
}
}
private fun getDefaultBitmap(context: Context): Bitmap {
return BitmapFactory.decodeResource(context.resources, R.drawable.default_album_art)
}
}

View file

@ -2,8 +2,8 @@ package code.name.monkey.retromusic.util
import android.content.Context
import android.content.Intent
import android.widget.Toast
import androidx.core.content.FileProvider
import code.name.monkey.retromusic.extensions.showToast
import java.io.File
object BackupUtil {
@ -19,11 +19,9 @@ object BackupUtil {
).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION).setType("*/*")
} catch (e: IllegalArgumentException) {
e.printStackTrace()
Toast.makeText(
context,
"Could not share this file.",
Toast.LENGTH_SHORT
).show()
context.showToast(
"Could not share this file."
)
Intent()
}
}

View file

@ -1,998 +0,0 @@
package code.name.monkey.retromusic.util;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import android.view.View;
import android.widget.ImageView;
/** Created by trung on 7/11/2017. */
public final class BitmapEditor {
/**
* Stack Blur v1.0 from http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html Java
* Author: Mario Klingemann <mario at quasimondo.com> http://incubator.quasimondo.com
*
* <p>created Feburary 29, 2004 Android port : Yahel Bouaziz <yahel at kayenko.com>
* http://www.kayenko.com ported april 5th, 2012
*
* <p>This is A compromise between Gaussian Blur and Box blur It creates much better looking blurs
* than Box Blur, but is 7x faster than my Gaussian Blur implementation.
*
* <p>I called it Stack Blur because this describes best how this filter works internally: it
* creates A kind of moving stack of colors whilst scanning through the image. Thereby it just has
* to add one new block of color to the right side of the stack and removeFromParent the leftmost
* color. The remaining colors on the topmost layer of the stack are either added on or reduced by
* one, depending on if they are on the right or on the x side of the stack.
*
* <p>If you are using this algorithm in your code please add the following line: Stack Blur
* Algorithm by Mario Klingemann <mario@quasimondo.com>
*/
public static Bitmap FastBlurSupportAlpha(Bitmap sentBitmap, float scale, int radius) {
int width = Math.round(sentBitmap.getWidth() * scale);
int height = Math.round(sentBitmap.getHeight() * scale);
sentBitmap = Bitmap.createScaledBitmap(sentBitmap, width, height, false);
Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
if (radius < 1) {
return (null);
}
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] pix = new int[w * h];
// Log.e("pix", w + " " + h + " " + pix.length);
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
int wm = w - 1;
int hm = h - 1;
int wh = w * h;
int div = radius + radius + 1;
int[] r = new int[wh];
int[] g = new int[wh];
int[] b = new int[wh];
int[] a = new int[wh];
int rsum, gsum, bsum, asum, x, y, i, p, yp, yi, yw;
int[] vmin = new int[Math.max(w, h)];
int divsum = (div + 1) >> 1;
divsum *= divsum;
int[] dv = new int[256 * divsum];
for (i = 0; i < 256 * divsum; i++) {
dv[i] = (i / divsum);
}
yw = yi = 0;
int[][] stack = new int[div][4];
int stackpointer;
int stackstart;
int[] sir;
int rbs;
int r1 = radius + 1;
int routsum, goutsum, boutsum, aoutsum;
int rinsum, ginsum, binsum, ainsum;
for (y = 0; y < h; y++) {
rinsum =
ginsum =
binsum =
ainsum = routsum = goutsum = boutsum = aoutsum = rsum = gsum = bsum = asum = 0;
for (i = -radius; i <= radius; i++) {
p = pix[yi + Math.min(wm, Math.max(i, 0))];
sir = stack[i + radius];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
sir[3] = 0xff & (p >> 24);
rbs = r1 - Math.abs(i);
rsum += sir[0] * rbs;
gsum += sir[1] * rbs;
bsum += sir[2] * rbs;
asum += sir[3] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
ainsum += sir[3];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
aoutsum += sir[3];
}
}
stackpointer = radius;
for (x = 0; x < w; x++) {
r[yi] = dv[rsum];
g[yi] = dv[gsum];
b[yi] = dv[bsum];
a[yi] = dv[asum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
asum -= aoutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
aoutsum -= sir[3];
if (y == 0) {
vmin[x] = Math.min(x + radius + 1, wm);
}
p = pix[yw + vmin[x]];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
sir[3] = 0xff & (p >> 24);
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
ainsum += sir[3];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
asum += ainsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[(stackpointer) % div];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
aoutsum += sir[3];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
ainsum -= sir[3];
yi++;
}
yw += w;
}
for (x = 0; x < w; x++) {
rinsum =
ginsum =
binsum =
ainsum = routsum = goutsum = boutsum = aoutsum = rsum = gsum = bsum = asum = 0;
yp = -radius * w;
for (i = -radius; i <= radius; i++) {
yi = Math.max(0, yp) + x;
sir = stack[i + radius];
sir[0] = r[yi];
sir[1] = g[yi];
sir[2] = b[yi];
sir[3] = a[yi];
rbs = r1 - Math.abs(i);
rsum += r[yi] * rbs;
gsum += g[yi] * rbs;
bsum += b[yi] * rbs;
asum += a[yi] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
ainsum += sir[3];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
aoutsum += sir[3];
}
if (i < hm) {
yp += w;
}
}
yi = x;
stackpointer = radius;
for (y = 0; y < h; y++) {
pix[yi] = (dv[asum] << 24) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
asum -= aoutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
aoutsum -= sir[3];
if (x == 0) {
vmin[y] = Math.min(y + r1, hm) * w;
}
p = x + vmin[y];
sir[0] = r[p];
sir[1] = g[p];
sir[2] = b[p];
sir[3] = a[p];
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
ainsum += sir[3];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
asum += ainsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[stackpointer];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
aoutsum += sir[3];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
ainsum -= sir[3];
yi += w;
}
}
// Log.e("pix", w + " " + h + " " + pix.length);
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
return (bitmap);
}
public static boolean PerceivedBrightness(int will_White, int[] c) {
double TBT = Math.sqrt(c[0] * c[0] * .241 + c[1] * c[1] * .691 + c[2] * c[2] * .068);
// Log.d("themee",TBT+"");
return !(TBT > will_White);
}
public static int[] getAverageColorRGB(Bitmap bitmap) {
final int width = bitmap.getWidth();
final int height = bitmap.getHeight();
int size = width * height;
int pixelColor;
int r, g, b;
r = g = b = 0;
for (int x = 0; x < width; ++x) {
for (int y = 0; y < height; ++y) {
pixelColor = bitmap.getPixel(x, y);
if (pixelColor == 0) {
size--;
continue;
}
r += Color.red(pixelColor);
g += Color.green(pixelColor);
b += Color.blue(pixelColor);
}
}
r /= size;
g /= size;
b /= size;
return new int[] {r, g, b};
}
public static Bitmap updateSat(Bitmap src, float settingSat) {
int w = src.getWidth();
int h = src.getHeight();
Bitmap bitmapResult = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvasResult = new Canvas(bitmapResult);
Paint paint = new Paint();
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(settingSat);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrix);
paint.setColorFilter(filter);
canvasResult.drawBitmap(src, 0, 0, paint);
canvasResult.setBitmap(null);
canvasResult = null;
return bitmapResult;
}
/**
* Stack Blur v1.0 from http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html Java
* Author: Mario Klingemann <mario at quasimondo.com> http://incubator.quasimondo.com
*
* <p>created Feburary 29, 2004 Android port : Yahel Bouaziz <yahel at kayenko.com>
* http://www.kayenko.com ported april 5th, 2012
*
* <p>This is A compromise between Gaussian Blur and Box blur It creates much better looking blurs
* than Box Blur, but is 7x faster than my Gaussian Blur implementation.
*
* <p>I called it Stack Blur because this describes best how this filter works internally: it
* creates A kind of moving stack of colors whilst scanning through the image. Thereby it just has
* to add one new block of color to the right side of the stack and removeFromParent the leftmost
* color. The remaining colors on the topmost layer of the stack are either added on or reduced by
* one, depending on if they are on the right or on the x side of the stack.
*
* <p>If you are using this algorithm in your code please add the following line: Stack Blur
* Algorithm by Mario Klingemann <mario@quasimondo.com>
*/
public static Bitmap fastblur(Bitmap sentBitmap, float scale, int radius) {
Bitmap afterscaleSentBitmap;
Bitmap bitmap;
if (scale != 1) {
int width = Math.round(sentBitmap.getWidth() * scale); // lấy chiều rộng làm tròn
int height = Math.round(sentBitmap.getHeight() * scale); // lấy chiều cao làm tròn
afterscaleSentBitmap =
Bitmap.createScaledBitmap(sentBitmap, width, height, false); // tạo bitmap scaled
bitmap = afterscaleSentBitmap.copy(afterscaleSentBitmap.getConfig(), true);
afterscaleSentBitmap.recycle();
} else {
bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); // đơn giản chỉ copy
}
if (radius < 1) {
return (sentBitmap.copy(sentBitmap.getConfig(), true));
}
int w = bitmap.getWidth(); // w is the width of sample bitmap
int h = bitmap.getHeight(); // h is the height of sample bitmap
int[] pix = new int[w * h]; // pix is the arrary of all bitmap pixel
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
int wm = w - 1;
int hm = h - 1;
int wh = w * h;
int div = radius + radius + 1;
int[] r = new int[wh];
int[] g = new int[wh];
int[] b = new int[wh];
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
int[] vmin = new int[Math.max(w, h)];
int divsum = (div + 1) >> 1;
divsum *= divsum;
int[] dv = new int[256 * divsum];
for (i = 0; i < 256 * divsum; i++) {
dv[i] = (i / divsum);
}
yw = yi = 0;
int[][] stack = new int[div][3];
int stackpointer;
int stackstart;
int[] sir;
int rbs;
int r1 = radius + 1;
int routsum, goutsum, boutsum;
int rinsum, ginsum, binsum;
for (y = 0; y < h; y++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
for (i = -radius; i <= radius; i++) {
p = pix[yi + Math.min(wm, Math.max(i, 0))];
sir = stack[i + radius];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rbs = r1 - Math.abs(i);
rsum += sir[0] * rbs;
gsum += sir[1] * rbs;
bsum += sir[2] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
}
stackpointer = radius;
for (x = 0; x < w; x++) {
r[yi] = dv[rsum];
g[yi] = dv[gsum];
b[yi] = dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (y == 0) {
vmin[x] = Math.min(x + radius + 1, wm);
}
p = pix[yw + vmin[x]];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[(stackpointer) % div];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi++;
}
yw += w;
}
for (x = 0; x < w; x++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
yp = -radius * w;
for (i = -radius; i <= radius; i++) {
yi = Math.max(0, yp) + x;
sir = stack[i + radius];
sir[0] = r[yi];
sir[1] = g[yi];
sir[2] = b[yi];
rbs = r1 - Math.abs(i);
rsum += r[yi] * rbs;
gsum += g[yi] * rbs;
bsum += b[yi] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
if (i < hm) {
yp += w;
}
}
yi = x;
stackpointer = radius;
for (y = 0; y < h; y++) {
// Preserve alpha channel: ( 0xff000000 & pix[yi] )
pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (x == 0) {
vmin[y] = Math.min(y + r1, hm) * w;
}
p = x + vmin[y];
sir[0] = r[p];
sir[1] = g[p];
sir[2] = b[p];
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[stackpointer];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi += w;
}
}
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
return (bitmap);
}
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {
Bitmap output =
Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
// final ScreenSize rectF = new ScreenSize(rect);
final float roundPx = pixels;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
// canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
canvas.drawPath(
BitmapEditor.RoundedRect(
0, 0, bitmap.getWidth(), bitmap.getHeight(), roundPx, roundPx, false),
paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
/**
* getResizedBitmap method is used to Resized the Image according to custom width and height
*
* @param image image to be resized
* @param newHeight (new desired height)
* @param newWidth (new desired Width)
* @return image (new resized image)
*/
public static Bitmap getResizedBitmap(Bitmap image, int newHeight, int newWidth) {
int width = image.getWidth();
int height = image.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// create A matrix for the manipulation
Matrix matrix = new Matrix();
// onTap the bit map
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new Bitmap
return Bitmap.createBitmap(image, 0, 0, width, height, matrix, false);
}
public static boolean TrueIfBitmapBigger(Bitmap bitmap, int size) {
int sizeBitmap =
Math.max(bitmap.getHeight(), bitmap.getWidth());
return sizeBitmap > size;
}
public static Bitmap getRoundedBitmapWithBlurShadow(
Bitmap original, int paddingTop, int paddingBottom, int paddingLeft, int paddingRight) {
int original_width = original.getWidth();
int original_height = original.getHeight();
int bitmap_width = original_width + paddingLeft + paddingRight;
int bitmap_height = original_height + paddingTop + paddingBottom;
Bitmap bitmap = Bitmap.createBitmap(bitmap_width, bitmap_height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
// paint.setAlpha(60);
// canvas.drawRect(0,0,bitmap_width,bitmap_height,paint);
paint.setAntiAlias(true);
canvas.drawBitmap(original, paddingLeft, paddingTop, paint);
Bitmap blurred_bitmap = getBlurredWithGoodPerformance(bitmap, 1, 6, 4);
canvas.setBitmap(null);
bitmap.recycle();
return blurred_bitmap;
}
// Activity.
// |
// Original bitmap.
// |
// | To make the blur background, the original must to padding.
// |
// | | | |
// |
// V
// V V V V
// V
public static Bitmap GetRoundedBitmapWithBlurShadow(
Context context,
Bitmap original,
int paddingTop,
int paddingBottom,
int paddingLeft,
int paddingRight,
int TopBack // this value makes the overview bitmap is higher or belower the background.
,
int alphaBlurBackground // this is the alpha of the background Bitmap, you need A number
// between 0 -> 255, the value recommend is 180.
,
int valueBlurBackground // this is the value used to blur the background Bitmap, the
// recommended one is 12.
,
int valueSaturationBlurBackground // this is the value used to background Bitmap more
// colorful, if valueBlur is 12, the valudeSaturation should
// be 2.
) {
int original_width = original.getWidth();
int orginal_height = original.getHeight();
int bitmap_width = original_width + paddingLeft + paddingRight;
int bitmap_height = orginal_height + paddingTop + paddingBottom;
Bitmap bitmap = Bitmap.createBitmap(bitmap_width, bitmap_height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
canvas.drawBitmap(original, paddingLeft, paddingTop, paint);
Bitmap blurred_bitmap =
getBlurredWithGoodPerformance(
context, bitmap, 1, valueBlurBackground, valueSaturationBlurBackground);
// Bitmap blurred_bitmap= getBlurredWithGoodPerformance(context, bitmap,1,15,3);
Bitmap end_bitmap = Bitmap.createBitmap(bitmap_width, bitmap_height, Bitmap.Config.ARGB_8888);
canvas.setBitmap(end_bitmap);
paint.setAlpha(alphaBlurBackground);
canvas.drawBitmap(
blurred_bitmap,
new Rect(0, 0, blurred_bitmap.getWidth(), blurred_bitmap.getHeight()),
new Rect(0, 0, bitmap_width, bitmap_height),
paint);
paint.setAlpha(255);
canvas.drawBitmap(bitmap, 0, TopBack, paint); // drawVisualWave cái lớn
canvas.setBitmap(null);
blurred_bitmap.recycle();
bitmap.recycle();
return end_bitmap;
}
public static void setBitmapforImageView(ImageView imv, Bitmap apply) {
Bitmap old = ((BitmapDrawable) imv.getDrawable()).getBitmap();
imv.setImageBitmap(apply);
if (old != null) old.recycle();
}
public static Bitmap getBlurredWithGoodPerformance(
Bitmap bitmap, int scale, int radius, int saturation) {
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap bitmap1 = getResizedBitmap(bitmap, 50, 50);
Bitmap updateSatBitmap = updateSat(bitmap1, saturation);
Bitmap blurredBitmap = FastBlurSupportAlpha(updateSatBitmap, scale, radius);
updateSatBitmap.recycle();
bitmap1.recycle();
return blurredBitmap;
}
public static Path RoundedRect(
float left,
float top,
float right,
float bottom,
float rx,
float ry,
boolean conformToOriginalPost) {
Path path = new Path();
if (rx < 0) rx = 0;
if (ry < 0) ry = 0;
float width = right - left;
float height = bottom - top;
if (rx > width / 2) rx = width / 2;
if (ry > height / 2) ry = height / 2;
float widthMinusCorners = (width - (2 * rx)); // do dai phan "thang" cua chieu rong
float heightMinusCorners = (height - (2 * ry)); // do dai phan "thang" cua chieu dai
path.moveTo(right, top + ry); // bat dau tu day
path.rQuadTo(0, -ry, -rx, -ry); // y-right corner
path.rLineTo(-widthMinusCorners, 0);
path.rQuadTo(-rx, 0, -rx, ry); // y-x corner
path.rLineTo(0, heightMinusCorners);
if (conformToOriginalPost) {
path.rLineTo(0, ry);
path.rLineTo(width, 0);
path.rLineTo(0, -ry);
} else {
path.rQuadTo(0, ry, rx, ry); // bottom-x corner
path.rLineTo(widthMinusCorners, 0);
path.rQuadTo(rx, 0, rx, -ry); // bottom-right corner
}
path.rLineTo(0, -heightMinusCorners);
path.close(); // Given close, last lineto can be removed.
return path;
}
public static int mixTwoColors(int color1, int color2, float amount) {
final byte ALPHA_CHANNEL = 24;
final byte RED_CHANNEL = 16;
final byte GREEN_CHANNEL = 8;
final byte BLUE_CHANNEL = 0;
final float inverseAmount = 1.0f - amount;
int a =
((int)
(((float) (color1 >> ALPHA_CHANNEL & 0xff) * amount)
+ ((float) (color2 >> ALPHA_CHANNEL & 0xff) * inverseAmount)))
& 0xff;
int r =
((int)
(((float) (color1 >> RED_CHANNEL & 0xff) * amount)
+ ((float) (color2 >> RED_CHANNEL & 0xff) * inverseAmount)))
& 0xff;
int g =
((int)
(((float) (color1 >> GREEN_CHANNEL & 0xff) * amount)
+ ((float) (color2 >> GREEN_CHANNEL & 0xff) * inverseAmount)))
& 0xff;
int b =
((int) (((float) (color1 & 0xff) * amount) + ((float) (color2 & 0xff) * inverseAmount)))
& 0xff;
return a << ALPHA_CHANNEL | r << RED_CHANNEL | g << GREEN_CHANNEL | b << BLUE_CHANNEL;
}
public static Bitmap getBlurredWithGoodPerformance(
Context context, Bitmap bitmap, int scale, int radius, float saturation) {
Bitmap bitmap1 = getResizedBitmap(bitmap, 150, 150);
Bitmap updateSatBimap = updateSat(bitmap1, saturation);
Bitmap blurredBitmap = BlurBitmapWithRenderScript(context, updateSatBimap, radius);
updateSatBimap.recycle();
bitmap1.recycle();
return blurredBitmap;
}
public static Bitmap getBlurredBimapWithRenderScript(
Context context, Bitmap bitmapOriginal, float radius) {
// define this only once if blurring multiple times
RenderScript rs = RenderScript.create(context);
// this will blur the bitmapOriginal with A radius of 8 and save it in bitmapOriginal
final Allocation input =
Allocation.createFromBitmap(
rs, bitmapOriginal); // use this constructor for best performance, because it uses
// USAGE_SHARED mode which reuses memory
final Allocation output = Allocation.createTyped(rs, input.getType());
final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setRadius(radius);
script.setInput(input);
script.forEach(output);
output.copyTo(bitmapOriginal);
return bitmapOriginal;
}
public static Bitmap BlurBitmapWithRenderScript(Context context, Bitmap bitmap, float radius) {
// Let's create an empty bitmap with the same size of the bitmap we want to blur
Bitmap outBitmap =
Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
// Instantiate A new Renderscript
RenderScript rs = RenderScript.create(context);
// Create an Intrinsic Blur Script using the Renderscript
ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
// Create the Allocations (in/out) with the Renderscript and the in/out bitmaps
Allocation allIn = Allocation.createFromBitmap(rs, bitmap);
Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);
// Set the radius of the blur
blurScript.setRadius(radius);
// Perform the Renderscript
blurScript.setInput(allIn);
blurScript.forEach(allOut);
// Copy the final bitmap created by the out Allocation to the outBitmap
allOut.copyTo(outBitmap);
// recycle the original bitmap
// After finishing everything, we destroy the Renderscript.
rs.destroy();
return outBitmap;
}
public static Drawable covertBitmapToDrawable(Context context, Bitmap bitmap) {
Drawable d = new BitmapDrawable(context.getResources(), bitmap);
return d;
}
public static Bitmap convertDrawableToBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
Bitmap bitmap =
Bitmap.createBitmap(
drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
public static Bitmap changeBitmapColor(Bitmap sourceBitmap, int color) {
Bitmap resultBitmap = sourceBitmap.copy(sourceBitmap.getConfig(), true);
Paint paint = new Paint();
ColorFilter filter = new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN);
paint.setColorFilter(filter);
Canvas canvas = new Canvas(resultBitmap);
canvas.drawBitmap(resultBitmap, 0, 0, paint);
return resultBitmap;
}
/**
* @param mode
* @return 0 : CLEAR <br>
* 1 : SRC <br>
* 2 : DST <br>
* 3 : SRC_OVER <br>
* 4 : DST_OVER <br>
* 5 : SRC_IN <br>
* 6 : DST_IN <br>
* 7 : SRC_OUT <br>
* 8 : DST_OUT <br>
* 9 : SRC_ATOP <br>
* 10 : DST_ATOP <br>
* 11 : XOR <br>
* 12 : ADD <br>
* 13 : MULTIPLY <br>
* 14 : SCREEN <br>
* 15 : OVERLAY <br>
* 16 : DARKEN <br>
* 17 : LIGHTEN
*/
public static PorterDuff.Mode getPorterMode(int mode) {
switch (mode) {
default:
case 0:
return PorterDuff.Mode.CLEAR;
case 1:
return PorterDuff.Mode.SRC;
case 2:
return PorterDuff.Mode.DST;
case 3:
return PorterDuff.Mode.SRC_OVER;
case 4:
return PorterDuff.Mode.DST_OVER;
case 5:
return PorterDuff.Mode.SRC_IN;
case 6:
return PorterDuff.Mode.DST_IN;
case 7:
return PorterDuff.Mode.SRC_OUT;
case 8:
return PorterDuff.Mode.DST_OUT;
case 9:
return PorterDuff.Mode.SRC_ATOP;
case 10:
return PorterDuff.Mode.DST_ATOP;
case 11:
return PorterDuff.Mode.XOR;
case 16:
return PorterDuff.Mode.DARKEN;
case 17:
return PorterDuff.Mode.LIGHTEN;
case 13:
return PorterDuff.Mode.MULTIPLY;
case 14:
return PorterDuff.Mode.SCREEN;
case 12:
return PorterDuff.Mode.ADD;
case 15:
return PorterDuff.Mode.OVERLAY;
}
}
public static void applyNewColor4Bitmap(
Context context, int[] idBitmaps, ImageView[] imageViews, int color, float alpha) {
android.content.res.Resources resource = context.getResources();
int size = idBitmaps.length;
Bitmap usingBitmap, resultBitmap;
for (int i = 0; i < size; i++) {
usingBitmap = BitmapFactory.decodeResource(resource, idBitmaps[i]);
resultBitmap = changeBitmapColor(usingBitmap, color);
imageViews[i].setImageBitmap(resultBitmap);
imageViews[i].setAlpha(alpha);
}
}
public static void applyNewColor4Bitmap(
Context context, int idBitmap, ImageView applyView, int color, float alpha) {
android.content.res.Resources resource = context.getResources();
Bitmap usingBitmap = BitmapFactory.decodeResource(resource, idBitmap);
Bitmap resultBitmap = changeBitmapColor(usingBitmap, color);
applyView.setImageBitmap(resultBitmap);
applyView.setAlpha(alpha);
}
public static Bitmap getBitmapFromView(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bitmap);
view.layout(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
view.draw(c);
return bitmap;
}
public static Bitmap getBitmapFromView(View view, int left, int top, int right, int bottom) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bitmap);
view.layout(left, top, right, bottom);
view.draw(c);
return bitmap;
}
public static Bitmap getBackgroundBitmapAViewWithParent(View childView, View parentView) {
int[] pos_child = new int[2];
childView.getLocationOnScreen(pos_child);
return getBitmapFromView(
parentView, pos_child[0], pos_child[1], parentView.getRight(), parentView.getBottom());
}
public static Bitmap getBackgroundBlurAViewWithParent(
Activity activity, View childView, View parentView) {
Bitmap b1 = getBackgroundBitmapAViewWithParent(childView, parentView);
Bitmap b2 = getBlurredWithGoodPerformance(activity, b1, 1, 8, 2);
b1.recycle();
return b2;
}
}

View file

@ -1,140 +0,0 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.util;
import java.util.Calendar;
import java.util.GregorianCalendar;
/** @author Eugene Cheung (arkon) */
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 final 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 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 + 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 + 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(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(month) * MS_PER_DAY;
month--;
}
return elapsed;
}
/**
* Gets the number of days for the given month in the given year.
*
* @param month The month (1 - 12).
* @return The days in that month/year.
*/
private int getDaysInMonth(int month) {
final Calendar monthCal = new GregorianCalendar(calendar.get(Calendar.YEAR), month, 1);
return monthCal.getActualMaximum(Calendar.DAY_OF_MONTH);
}
/**
* 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;
}
}

View file

@ -0,0 +1,125 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.util
import java.util.*
/** @author Eugene Cheung (arkon)
*/
class CalendarUtil {
private val calendar = Calendar.getInstance()// Time elapsed so far today
/**
* Returns the time elapsed so far today in milliseconds.
*
* @return Time elapsed today in milliseconds.
*/
val elapsedToday: Long
get() =// Time elapsed so far today
(calendar[Calendar.HOUR_OF_DAY] * 60 + calendar[Calendar.MINUTE]) * MS_PER_MINUTE + calendar[Calendar.SECOND] * 1000 + calendar[Calendar.MILLISECOND]// Today + days passed this week
/**
* Returns the time elapsed so far this week in milliseconds.
*
* @return Time elapsed this week in milliseconds.
*/
val elapsedWeek: Long
get() {
// Today + days passed this week
var elapsed = elapsedToday
val passedWeekdays = calendar[Calendar.DAY_OF_WEEK] - 1 - calendar.firstDayOfWeek
if (passedWeekdays > 0) {
elapsed += passedWeekdays * MS_PER_DAY
}
return elapsed
}// Today + rest of this month
/**
* Returns the time elapsed so far this month in milliseconds.
*
* @return Time elapsed this month in milliseconds.
*/
val elapsedMonth: Long
get() =// Today + rest of this month
elapsedToday + (calendar[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.
*/
fun getElapsedMonths(numMonths: Int): Long {
// Today + rest of this month
var elapsed = elapsedMonth
// Previous numMonths months
var month = calendar[Calendar.MONTH]
var year = calendar[Calendar.YEAR]
for (i in 0 until numMonths) {
month--
if (month < Calendar.JANUARY) {
month = Calendar.DECEMBER
year--
}
elapsed += getDaysInMonth(month) * MS_PER_DAY
}
return elapsed
}// Today + rest of this month + previous months until January
/**
* Returns the time elapsed so far this year in milliseconds.
*
* @return Time elapsed this year in milliseconds.
*/
val elapsedYear: Long
get() {
// Today + rest of this month + previous months until January
var elapsed = elapsedMonth
var month = calendar[Calendar.MONTH] - 1
while (month > Calendar.JANUARY) {
elapsed += getDaysInMonth(month) * MS_PER_DAY
month--
}
return elapsed
}
/**
* Gets the number of days for the given month in the given year.
*
* @param month The month (1 - 12).
* @return The days in that month/year.
*/
private fun getDaysInMonth(month: Int): Int {
val monthCal: Calendar = GregorianCalendar(calendar[Calendar.YEAR], month, 1)
return monthCal.getActualMaximum(Calendar.DAY_OF_MONTH)
}
/**
* Returns the time elapsed so far last N days in milliseconds.
*
* @return Time elapsed since N days in milliseconds.
*/
fun getElapsedDays(numDays: Int): Long {
var elapsed = elapsedToday
elapsed += numDays * MS_PER_DAY
return elapsed
}
companion object {
private const val MS_PER_MINUTE = (60 * 1000).toLong()
private const val MS_PER_DAY = 24 * 60 * MS_PER_MINUTE
}
}

View file

@ -1,19 +0,0 @@
package code.name.monkey.retromusic.util
import android.animation.ArgbEvaluator
import android.animation.ValueAnimator
class ColorAnimUtil {
companion object {
fun createColorAnimator(
fromColor: Int,
toColor: Int,
mDuration: Long = 300
): ValueAnimator {
return ValueAnimator.ofInt(fromColor, toColor).apply {
setEvaluator(ArgbEvaluator())
duration = mDuration
}
}
}
}

View file

@ -1,80 +0,0 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.util;
import android.content.Context;
import android.graphics.Bitmap;
import java.io.File;
import java.io.IOException;
/**
* Created on : June 18, 2016 Author : zetbaitsu Name : Zetra GitHub : https://github.com/zetbaitsu
*/
public class Compressor {
// max width and height values of the compressed image is taken as 612x816
private int maxWidth = 612;
private int maxHeight = 816;
private Bitmap.CompressFormat compressFormat = Bitmap.CompressFormat.JPEG;
private int quality = 80;
private String destinationDirectoryPath;
public Compressor(Context context) {
destinationDirectoryPath = context.getCacheDir().getPath() + File.separator + "images";
}
public Compressor setMaxWidth(int maxWidth) {
this.maxWidth = maxWidth;
return this;
}
public Compressor setMaxHeight(int maxHeight) {
this.maxHeight = maxHeight;
return this;
}
public Compressor setCompressFormat(Bitmap.CompressFormat compressFormat) {
this.compressFormat = compressFormat;
return this;
}
public Compressor setQuality(int quality) {
this.quality = quality;
return this;
}
public Compressor setDestinationDirectoryPath(String destinationDirectoryPath) {
this.destinationDirectoryPath = destinationDirectoryPath;
return this;
}
public File compressToFile(File imageFile) throws IOException {
return compressToFile(imageFile, imageFile.getName());
}
public File compressToFile(File imageFile, String compressedFileName) throws IOException {
return ImageUtil.compressImage(
imageFile,
maxWidth,
maxHeight,
compressFormat,
quality,
destinationDirectoryPath + File.separator + compressedFileName);
}
public Bitmap compressToBitmap(File imageFile) throws IOException {
return ImageUtil.decodeSampledBitmapFromFile(imageFile, maxWidth, maxHeight);
}
}

View file

@ -14,25 +14,21 @@
package code.name.monkey.retromusic.util
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.AsyncTask
import android.provider.MediaStore
import android.widget.Toast
import androidx.core.content.edit
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.model.Artist
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.transition.Transition
import java.io.BufferedOutputStream
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.util.*
@ -44,78 +40,71 @@ class CustomArtistImageUtil private constructor(context: Context) {
Context.MODE_PRIVATE
)
fun setCustomArtistImage(artist: Artist, uri: Uri) {
Glide.with(App.getContext())
.asBitmap()
.load(uri)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.into(object : SimpleTarget<Bitmap>() {
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
Toast.makeText(App.getContext(), "Load Failed", Toast.LENGTH_LONG).show()
suspend fun setCustomArtistImage(artist: Artist, uri: Uri) {
val context = App.getContext()
withContext(IO) {
runCatching {
GlideApp.with(context)
.asBitmap()
.load(uri)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.submit()
.get()
}
.onSuccess {
saveImage(context, artist, it)
}
@SuppressLint("StaticFieldLeak")
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
object : AsyncTask<Void, Void, Void>() {
override fun doInBackground(vararg params: Void): Void? {
val dir = File(App.getContext().filesDir, FOLDER_NAME)
if (!dir.exists()) {
if (!dir.mkdirs()) { // create the folder
return null
}
}
val file = File(dir, getFileName(artist))
var succesful = false
try {
val os = BufferedOutputStream(FileOutputStream(file))
succesful = ImageUtil.resizeBitmap(resource, 2048)
.compress(Bitmap.CompressFormat.JPEG, 100, os)
os.close()
} catch (e: IOException) {
Toast.makeText(App.getContext(), e.toString(), Toast.LENGTH_LONG)
.show()
}
if (succesful) {
mPreferences.edit { putBoolean(getFileName(artist), true) }
ArtistSignatureUtil.getInstance(App.getContext())
.updateArtistSignature(artist.name)
App.getContext().contentResolver.notifyChange(
MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
null
) // trigger media store changed to force artist image reload
}
return null
}
}.execute()
.onFailure {
context.showToast("Load Failed")
}
})
}
}
@SuppressLint("StaticFieldLeak")
fun resetCustomArtistImage(artist: Artist) {
object : AsyncTask<Void, Void, Void>() {
@SuppressLint("ApplySharedPref")
override fun doInBackground(vararg params: Void): Void? {
mPreferences.edit(commit = true) { putBoolean(getFileName(artist), false) }
ArtistSignatureUtil.getInstance(App.getContext()).updateArtistSignature(artist.name)
App.getContext().contentResolver.notifyChange(
MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
null
) // trigger media store changed to force artist image reload
val file = getFile(artist)
if (!file.exists()) {
return null
} else {
file.delete()
}
return null
private fun saveImage(context: Context, artist: Artist, bitmap: Bitmap) {
val dir = File(context.filesDir, FOLDER_NAME)
if (!dir.exists()) {
if (!dir.mkdirs()) { // create the folder
return
}
}.execute()
}
val file = File(dir, getFileName(artist))
var successful = false
try {
file.outputStream().buffered().use { bos ->
successful = ImageUtil.resizeBitmap(bitmap, 2048)
.compress(Bitmap.CompressFormat.JPEG, 100, bos)
}
} catch (e: IOException) {
context.showToast(e.toString(), Toast.LENGTH_LONG)
}
if (successful) {
mPreferences.edit { putBoolean(getFileName(artist), true) }
ArtistSignatureUtil.getInstance(context)
.updateArtistSignature(artist.name)
context.contentResolver.notifyChange(
MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
null
) // trigger media store changed to force artist image reload
}
}
suspend fun resetCustomArtistImage(artist: Artist) {
withContext(IO) {
mPreferences.edit { putBoolean(getFileName(artist), false) }
ArtistSignatureUtil.getInstance(App.getContext()).updateArtistSignature(artist.name)
App.getContext().contentResolver.notifyChange(
MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
null
) // trigger media store changed to force artist image reload
val file = getFile(artist)
if (file.exists()) {
file.delete()
}
}
}
// shared prefs saves us many IO operations

View file

@ -1,14 +1,13 @@
package code.name.monkey.retromusic.util
import android.os.Environment
import java.io.File
object FilePathUtil {
fun blacklistFilePaths(): List<String> {
return listOf<File>(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS),
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_RINGTONES),
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_NOTIFICATIONS)
return listOf(
getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS),
getExternalStoragePublicDirectory(Environment.DIRECTORY_RINGTONES),
getExternalStoragePublicDirectory(Environment.DIRECTORY_NOTIFICATIONS)
).map {
FileUtil.safeGetCanonicalPath(it)
}

View file

@ -14,10 +14,11 @@
package code.name.monkey.retromusic.util;
import static code.name.monkey.retromusic.util.FileUtilsKt.getExternalStorageDirectory;
import android.content.Context;
import android.database.Cursor;
import android.os.Environment;
import android.provider.MediaStore;
import android.webkit.MimeTypeMap;
import androidx.annotation.NonNull;
@ -40,6 +41,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import code.name.monkey.retromusic.Constants;
import code.name.monkey.retromusic.adapter.Storage;
import code.name.monkey.retromusic.model.Song;
import code.name.monkey.retromusic.repository.RealSongRepository;
@ -87,7 +89,7 @@ public final class FileUtil {
if (files.size() > 0
&& files.size() < 999) { // 999 is the max amount Androids SQL implementation can handle.
selection =
MediaStore.Audio.AudioColumns.DATA + " IN (" + makePlaceholders(files.size()) + ")";
Constants.DATA + " IN (" + makePlaceholders(files.size()) + ")";
}
}
@ -96,7 +98,7 @@ public final class FileUtil {
return songCursor == null
? null
: new SortedCursor(songCursor, paths, MediaStore.Audio.AudioColumns.DATA);
: new SortedCursor(songCursor, paths, Constants.DATA);
}
private static String makePlaceholders(int len) {
@ -113,12 +115,6 @@ public final class FileUtil {
if (files != null) {
String[] paths = new String[files.size()];
for (int i = 0; i < files.size(); i++) {
/*try {
paths[i] = files.get(i).getCanonicalPath(); // canonical path is important here because we want to compare the path with the media store entry later
} catch (IOException e) {
e.printStackTrace();
paths[i] = files.get(i).getPath();
}*/
paths[i] = safeGetCanonicalPath(files.get(i));
}
return paths;
@ -268,7 +264,7 @@ public final class FileUtil {
public static ArrayList<Storage> listRoots() {
ArrayList<Storage> storageItems = new ArrayList<>();
HashSet<String> paths = new HashSet<>();
String defaultPath = Environment.getExternalStorageDirectory().getPath();
String defaultPath = getExternalStorageDirectory().getPath();
String defaultPathState = Environment.getExternalStorageState();
if (defaultPathState.equals(Environment.MEDIA_MOUNTED) || defaultPathState.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
Storage ext = new Storage();
@ -277,7 +273,7 @@ public final class FileUtil {
} else {
ext.title = "Internal Storage";
}
ext.file = Environment.getExternalStorageDirectory();
ext.file = getExternalStorageDirectory();
storageItems.add(ext);
paths.add(defaultPath);
}

View file

@ -2,6 +2,7 @@ package code.name.monkey.retromusic.util
import android.content.Context
import android.net.Uri
import android.os.Environment
import android.util.Log
import java.io.File
import java.io.IOException
@ -23,7 +24,13 @@ object FileUtils {
* @return the file
* @throws IOException
*/
fun createFile(context: Context, directoryName: String, fileName: String, body: String, fileType: String): File {
fun createFile(
context: Context,
directoryName: String,
fileName: String,
body: String,
fileType: String
): File {
val root = createDirectory(context, directoryName)
val filePath = "$root/$fileName$fileType"
val file = File(filePath)
@ -57,4 +64,13 @@ object FileUtils {
}
return file
}
}
@Suppress("Deprecation")
fun getExternalStorageDirectory(): File {
return Environment.getExternalStorageDirectory()
}
@Suppress("Deprecation")
fun getExternalStoragePublicDirectory(type: String): File {
return Environment.getExternalStoragePublicDirectory(type)
}

View file

@ -14,128 +14,17 @@
package code.name.monkey.retromusic.util;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.media.ExifInterface;
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.res.ResourcesCompat;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import code.name.monkey.appthemehelper.util.TintHelper;
/**
* Created on : June 18, 2016 Author : zetbaitsu Name : Zetra GitHub : https://github.com/zetbaitsu
*/
public class ImageUtil {
private static final int TOLERANCE = 20;
// Alpha amount for which values below are considered transparent.
private static final int ALPHA_TOLERANCE = 50;
private static int[] mTempBuffer;
private ImageUtil() {}
public static boolean isGrayscale(Bitmap bitmap) {
final int height = bitmap.getHeight();
final int width = bitmap.getWidth();
int size = height * width;
ensureBufferSize(size);
bitmap.getPixels(mTempBuffer, 0, width, 0, 0, width, height);
for (int i = 0; i < size; i++) {
if (!isGrayscale(mTempBuffer[i])) {
return false;
}
}
return true;
}
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 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 getVectorDrawable(
@NonNull Resources res, @DrawableRes int resId, @Nullable Resources.Theme theme) {
return ResourcesCompat.getDrawable(res,resId, theme);
}
/** Makes sure that {@code mTempBuffer} has at least length {@code size}. */
private static void ensureBufferSize(int size) {
if (mTempBuffer == null || mTempBuffer.length < size) {
mTempBuffer = new int[size];
}
}
public static Bitmap setBitmapColor(Bitmap bitmap, int color) {
Bitmap result =
Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth() - 1, bitmap.getHeight() - 1);
Paint paint = new Paint();
paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
Canvas canvas = new Canvas(result);
canvas.drawBitmap(result, 0, 0, paint);
return result;
}
public static boolean isGrayscale(int color) {
int alpha = 0xFF & (color >> 24);
if (alpha < ALPHA_TOLERANCE) {
return true;
}
int r = 0xFF & (color >> 16);
int g = 0xFF & (color >> 8);
int b = 0xFF & color;
return Math.abs(r - g) < TOLERANCE
&& Math.abs(r - b) < TOLERANCE
&& Math.abs(g - b) < TOLERANCE;
} // Amount (max is 255) that two channels can differ before the color is no longer "gray".
public static Bitmap resizeBitmap(@NonNull Bitmap src, int maxForSmallerSize) {
int width = src.getWidth();
int height = src.getHeight();
@ -185,108 +74,4 @@ public class ImageUtil {
return inSampleSize;
}
static File compressImage(
File imageFile,
int reqWidth,
int reqHeight,
Bitmap.CompressFormat compressFormat,
int quality,
String destinationPath)
throws IOException {
FileOutputStream fileOutputStream = null;
File file = new File(destinationPath).getParentFile();
if (!file.exists()) {
file.mkdirs();
}
try {
fileOutputStream = new FileOutputStream(destinationPath);
// write the compressed bitmap at the destination specified by destinationPath.
decodeSampledBitmapFromFile(imageFile, reqWidth, reqHeight)
.compress(compressFormat, quality, fileOutputStream);
} finally {
if (fileOutputStream != null) {
fileOutputStream.flush();
fileOutputStream.close();
}
}
return new File(destinationPath);
}
static Bitmap decodeSampledBitmapFromFile(File imageFile, int reqWidth, int reqHeight)
throws IOException {
// First decode with inJustDecodeBounds=true to check dimensions
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap scaledBitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);
// check the rotation of the image and display it properly
ExifInterface exif;
exif = new ExifInterface(imageFile.getAbsolutePath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
Matrix matrix = new Matrix();
if (orientation == 6) {
matrix.postRotate(90);
} else if (orientation == 3) {
matrix.postRotate(180);
} else if (orientation == 8) {
matrix.postRotate(270);
}
scaledBitmap =
Bitmap.createBitmap(
scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
return scaledBitmap;
}
private static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || 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) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
@NonNull
public static Bitmap getResizedBitmap(@NonNull Bitmap image, int maxSize) {
int width = image.getWidth();
int height = image.getHeight();
float bitmapRatio = (float) width / (float) height;
if (bitmapRatio > 1) {
width = maxSize;
height = (int) (width / bitmapRatio);
} else {
height = maxSize;
width = (int) (height * bitmapRatio);
}
return Bitmap.createScaledBitmap(image, width, height, true);
}
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

@ -13,7 +13,6 @@
*/
package code.name.monkey.retromusic.util
import android.os.Environment
import android.util.Log
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics
@ -26,7 +25,7 @@ import java.io.*
*/
object LyricUtil {
private val lrcRootPath =
Environment.getExternalStorageDirectory().toString() + "/RetroMusic/lyrics/"
getExternalStorageDirectory().toString() + "/RetroMusic/lyrics/"
private const val TAG = "LyricUtil"
fun writeLrcToLoc(
title: String, artist: String, lrcContext: String

View file

@ -5,27 +5,25 @@ import android.content.Context
import android.content.Intent
import android.database.Cursor
import android.net.Uri
import android.os.Environment
import android.provider.BaseColumns
import android.provider.MediaStore
import android.util.Log
import android.widget.Toast
import androidx.core.content.FileProvider
import androidx.core.content.contentValuesOf
import androidx.core.net.toUri
import androidx.fragment.app.FragmentActivity
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.Constants
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.db.PlaylistEntity
import code.name.monkey.retromusic.db.SongEntity
import code.name.monkey.retromusic.db.toSongEntity
import code.name.monkey.retromusic.extensions.getLong
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.helper.MusicPlayerRemote.removeFromQueue
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Playlist
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics
import code.name.monkey.retromusic.repository.RealPlaylistRepository
import code.name.monkey.retromusic.repository.Repository
import code.name.monkey.retromusic.repository.SongRepository
import code.name.monkey.retromusic.service.MusicService
@ -56,14 +54,10 @@ object MusicUtil : KoinComponent {
)
).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION).setType("audio/*")
} catch (e: IllegalArgumentException) {
// TODO the path is most likely not like /storage/emulated/0/... but something like /storage/28C7-75B0/...
e.printStackTrace()
Toast.makeText(
context,
"Could not share this file, I'm aware of the issue.",
Toast.LENGTH_SHORT
).show()
Intent()
Intent().setAction(Intent.ACTION_SEND).putExtra(
Intent.EXTRA_STREAM,
getSongFileUri(song.id)
).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION).setType("audio/*")
}
}
@ -83,7 +77,7 @@ object MusicUtil : KoinComponent {
private fun createAlbumArtDir(context: Context): File {
val albumArtDir = File(
if (VersionUtils.hasR()) context.cacheDir else Environment.getExternalStorageDirectory(),
if (VersionUtils.hasR()) context.cacheDir else getExternalStorageDirectory(),
"/albumthumbs/"
)
if (!albumArtDir.exists()) {
@ -268,15 +262,14 @@ object MusicUtil : KoinComponent {
)
}
fun getSongFilePath(context: Context, uri: Uri): String? {
val projection = arrayOf(MediaStore.MediaColumns.DATA)
return context.contentResolver.query(uri, projection, null, null, null)?.use {
fun getSongFilePath(context: Context, uri: Uri): String {
val projection = arrayOf(Constants.DATA)
context.contentResolver.query(uri, projection, null, null, null)?.use {
if (it.moveToFirst()) {
it.getString(0)
} else {
""
return it.getString(0)
}
}
return ""
}
fun getTotalDuration(songs: List<Song>): Long {
@ -340,48 +333,21 @@ object MusicUtil : KoinComponent {
return false
}
fun isFavorite(context: Context, song: Song): Boolean {
return PlaylistsUtil
.doPlaylistContains(context, getFavoritesPlaylist(context).id, song.id)
}
fun isFavoritePlaylist(
context: Context,
playlist: Playlist
): Boolean {
return playlist.name == context.getString(R.string.favorites)
}
val repository = get<Repository>()
fun toggleFavorite(context: Context, song: Song) {
GlobalScope.launch {
val playlist: PlaylistEntity = repository.favoritePlaylist()
if (playlist != null) {
val songEntity = song.toSongEntity(playlist.playListId)
val isFavorite = repository.isFavoriteSong(songEntity).isNotEmpty()
if (isFavorite) {
repository.removeSongFromPlaylist(songEntity)
} else {
repository.insertSongs(listOf(song.toSongEntity(playlist.playListId)))
}
val songEntity = song.toSongEntity(playlist.playListId)
val isFavorite = repository.isFavoriteSong(songEntity).isNotEmpty()
if (isFavorite) {
repository.removeSongFromPlaylist(songEntity)
} else {
repository.insertSongs(listOf(song.toSongEntity(playlist.playListId)))
}
context.sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED))
}
}
private fun getFavoritesPlaylist(context: Context): Playlist {
return RealPlaylistRepository(context.contentResolver).playlist(context.getString(R.string.favorites))
}
private fun getOrCreateFavoritesPlaylist(context: Context): Playlist {
return RealPlaylistRepository(context.contentResolver).playlist(
PlaylistsUtil.createPlaylist(
context,
context.getString(R.string.favorites)
)
)
}
fun deleteTracks(
activity: FragmentActivity,
songs: List<Song>,
@ -390,7 +356,7 @@ object MusicUtil : KoinComponent {
) {
val songRepository: SongRepository = get()
val projection = arrayOf(
BaseColumns._ID, MediaStore.MediaColumns.DATA
BaseColumns._ID, Constants.DATA
)
// Split the query into multiple batches, and merge the resulting cursors
var batchStart: Int
@ -457,20 +423,14 @@ object MusicUtil : KoinComponent {
}
activity.contentResolver.notifyChange("content://media".toUri(), null)
activity.runOnUiThread {
Toast.makeText(
activity,
activity.getString(R.string.deleted_x_songs, songCount),
Toast.LENGTH_SHORT
)
.show()
activity.showToast(activity.getString(R.string.deleted_x_songs, songCount))
callback?.run()
}
}
}
suspend fun deleteTracks(context: Context, songs: List<Song>) {
val projection = arrayOf(BaseColumns._ID, MediaStore.MediaColumns.DATA)
val projection = arrayOf(BaseColumns._ID, Constants.DATA)
val selection = StringBuilder()
selection.append(BaseColumns._ID + " IN (")
for (i in songs.indices) {
@ -520,11 +480,7 @@ object MusicUtil : KoinComponent {
cursor.close()
}
withContext(Dispatchers.Main) {
Toast.makeText(
context,
context.getString(R.string.deleted_x_songs, deletedCount),
Toast.LENGTH_SHORT
).show()
context.showToast(context.getString(R.string.deleted_x_songs, deletedCount))
}
} catch (ignored: SecurityException) {

View file

@ -19,9 +19,11 @@ import android.content.Context
import android.content.Intent
import android.media.audiofx.AudioEffect
import android.widget.Toast
import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.*
import code.name.monkey.retromusic.activities.bugreport.BugReportActivity
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.helper.MusicPlayerRemote.audioSessionId
object NavigationUtil {
@ -55,10 +57,9 @@ object NavigationUtil {
)
}
fun gotoWhatNews(activity: Activity) {
activity.startActivity(
Intent(activity, WhatsNewActivity::class.java), null
)
fun gotoWhatNews(activity: FragmentActivity) {
val changelogBottomSheet = WhatsNewFragment()
changelogBottomSheet.show(activity.supportFragmentManager, WhatsNewFragment.TAG)
}
fun openEqualizer(activity: Activity) {
@ -68,10 +69,7 @@ object NavigationUtil {
private fun stockEqualizer(activity: Activity) {
val sessionId = audioSessionId
if (sessionId == AudioEffect.ERROR_BAD_VALUE) {
Toast.makeText(
activity, activity.resources.getString(R.string.no_audio_ID), Toast.LENGTH_LONG
)
.show()
activity.showToast(R.string.no_audio_ID, Toast.LENGTH_LONG)
} else {
try {
val effects = Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL)
@ -79,12 +77,7 @@ object NavigationUtil {
effects.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC)
activity.startActivityForResult(effects, 0)
} catch (notFound: ActivityNotFoundException) {
Toast.makeText(
activity,
activity.resources.getString(R.string.no_equalizer),
Toast.LENGTH_SHORT
)
.show()
activity.showToast(R.string.no_equalizer)
}
}
}

View file

@ -71,7 +71,7 @@ class PackageValidator(
/**
* Checks whether the caller attempting to connect to a [MediaBrowserServiceCompat] is known.
* See [MusicService.onGetRoot] for where this is utilized.
* See [MediaBrowserServiceCompat.onGetRoot] for where this is utilized.
*
* @param callingPackage The package name of the caller.
* @param callingUid The user id of the caller.

View file

@ -1,333 +0,0 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.util;
import static android.provider.MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
import android.provider.BaseColumns;
import android.provider.MediaStore;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.db.PlaylistWithSongs;
import code.name.monkey.retromusic.helper.M3UWriter;
import code.name.monkey.retromusic.model.Playlist;
import code.name.monkey.retromusic.model.PlaylistSong;
import code.name.monkey.retromusic.model.Song;
public class PlaylistsUtil {
public static long createPlaylist(@NonNull final Context context, @Nullable final String name) {
int id = -1;
if (name != null && name.length() > 0) {
try {
Cursor cursor =
context
.getContentResolver()
.query(
EXTERNAL_CONTENT_URI,
new String[] {MediaStore.Audio.Playlists._ID},
MediaStore.Audio.PlaylistsColumns.NAME + "=?",
new String[] {name},
null);
if (cursor == null || cursor.getCount() < 1) {
final ContentValues values = new ContentValues(1);
values.put(MediaStore.Audio.PlaylistsColumns.NAME, name);
final Uri uri = context.getContentResolver().insert(EXTERNAL_CONTENT_URI, values);
if (uri != null) {
// Necessary because somehow the MediaStoreObserver is not notified when adding a
// playlist
context.getContentResolver().notifyChange(Uri.parse("content://media"), null);
Toast.makeText(
context,
context.getResources().getString(R.string.created_playlist_x, name),
Toast.LENGTH_SHORT)
.show();
id = Integer.parseInt(uri.getLastPathSegment());
}
} else {
// Playlist exists
if (cursor.moveToFirst()) {
id = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Playlists._ID));
}
}
if (cursor != null) {
cursor.close();
}
} catch (SecurityException e) {
e.printStackTrace();
}
}
if (id == -1) {
Toast.makeText(
context,
context.getResources().getString(R.string.could_not_create_playlist),
Toast.LENGTH_SHORT)
.show();
}
return id;
}
public static void deletePlaylists(
@NonNull final Context context, @NonNull final List<Playlist> playlists) {
final StringBuilder selection = new StringBuilder();
selection.append(MediaStore.Audio.Playlists._ID + " IN (");
for (int i = 0; i < playlists.size(); i++) {
selection.append(playlists.get(i).getId());
if (i < playlists.size() - 1) {
selection.append(",");
}
}
selection.append(")");
try {
context.getContentResolver().delete(EXTERNAL_CONTENT_URI, selection.toString(), null);
context.getContentResolver().notifyChange(Uri.parse("content://media"), null);
} catch (SecurityException ignored) {
}
}
public static void addToPlaylist(
@NonNull final Context context,
final Song song,
final long playlistId,
final boolean showToastOnFinish) {
List<Song> helperList = new ArrayList<>();
helperList.add(song);
addToPlaylist(context, helperList, playlistId, showToastOnFinish);
}
public static void addToPlaylist(
@NonNull final Context context,
@NonNull final List<Song> songs,
final long playlistId,
final boolean showToastOnFinish) {
final int size = songs.size();
final ContentResolver resolver = context.getContentResolver();
final String[] projection =
new String[] {
"max(" + MediaStore.Audio.Playlists.Members.PLAY_ORDER + ")",
};
final Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId);
Cursor cursor = null;
int base = 0;
try {
try {
cursor = resolver.query(uri, projection, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
base = cursor.getInt(0) + 1;
}
} finally {
if (cursor != null) {
cursor.close();
}
}
int numInserted = 0;
for (int offSet = 0; offSet < size; offSet += 1000)
numInserted += resolver.bulkInsert(uri, makeInsertItems(songs, offSet, 1000, base));
if (showToastOnFinish) {
Toast.makeText(
context,
context
.getResources()
.getString(
R.string.inserted_x_songs_into_playlist_x,
numInserted,
getNameForPlaylist(context, playlistId)),
Toast.LENGTH_SHORT)
.show();
}
} catch (SecurityException exception) {
exception.printStackTrace();
}
}
@NonNull
public static ContentValues[] makeInsertItems(
@NonNull final List<Song> songs, final int offset, int len, final int base) {
if (offset + len > songs.size()) {
len = songs.size() - offset;
}
ContentValues[] contentValues = new ContentValues[len];
for (int i = 0; i < len; i++) {
contentValues[i] = new ContentValues();
contentValues[i].put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, base + offset + i);
contentValues[i].put(
MediaStore.Audio.Playlists.Members.AUDIO_ID, songs.get(offset + i).getId());
}
return contentValues;
}
public static String getNameForPlaylist(@NonNull final Context context, final long id) {
try {
Cursor cursor =
context
.getContentResolver()
.query(
EXTERNAL_CONTENT_URI,
new String[] {MediaStore.Audio.PlaylistsColumns.NAME},
BaseColumns._ID + "=?",
new String[] {String.valueOf(id)},
null);
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
return cursor.getString(0);
}
} finally {
cursor.close();
}
}
} catch (SecurityException ignored) {
}
return "";
}
public static void removeFromPlaylist(
@NonNull final Context context, @NonNull final Song song, long playlistId) {
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId);
String selection = MediaStore.Audio.Playlists.Members.AUDIO_ID + " =?";
String[] selectionArgs = new String[] {String.valueOf(song.getId())};
try {
context.getContentResolver().delete(uri, selection, selectionArgs);
} catch (SecurityException ignored) {
}
}
public static void removeFromPlaylist(
@NonNull final Context context, @NonNull final List<PlaylistSong> songs) {
final long playlistId = songs.get(0).getPlaylistId();
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId);
String[] selectionArgs = new String[songs.size()];
for (int i = 0; i < selectionArgs.length; i++) {
selectionArgs[i] = String.valueOf(songs.get(i).getIdInPlayList());
}
StringBuilder selection = new StringBuilder(MediaStore.Audio.Playlists.Members._ID + " in (");
for (String selectionArg : selectionArgs) selection.append("?, ");
selection = new StringBuilder(selection.substring(0, selection.length() - 2) + ")");
try {
context.getContentResolver().delete(uri, selection.toString(), selectionArgs);
} catch (SecurityException ignored) {
}
}
public static boolean doPlaylistContains(
@NonNull final Context context, final long playlistId, final long songId) {
if (playlistId != -1) {
try {
Cursor c =
context
.getContentResolver()
.query(
MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId),
new String[] {MediaStore.Audio.Playlists.Members.AUDIO_ID},
MediaStore.Audio.Playlists.Members.AUDIO_ID + "=?",
new String[] {String.valueOf(songId)},
null);
int count = 0;
if (c != null) {
count = c.getCount();
c.close();
}
return count > 0;
} catch (SecurityException ignored) {
}
}
return false;
}
public static boolean moveItem(
@NonNull final Context context, long playlistId, int from, int to) {
return MediaStore.Audio.Playlists.Members.moveItem(
context.getContentResolver(), playlistId, from, to);
}
public static void renamePlaylist(
@NonNull final Context context, final long id, final String newName) {
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Audio.PlaylistsColumns.NAME, newName);
try {
context
.getContentResolver()
.update(
EXTERNAL_CONTENT_URI,
contentValues,
MediaStore.Audio.Playlists._ID + "=?",
new String[] {String.valueOf(id)});
context.getContentResolver().notifyChange(Uri.parse("content://media"), null);
} catch (SecurityException ignored) {
}
}
public static File savePlaylist(Context context, Playlist playlist) throws IOException {
return M3UWriter.write(
new File(Environment.getExternalStorageDirectory(), "Playlists"), playlist);
}
public static File savePlaylistWithSongs(PlaylistWithSongs playlist) throws IOException {
return M3UWriter.writeIO(
new File(Environment.getExternalStorageDirectory(), "Playlists"), playlist);
}
public static boolean doesPlaylistExist(@NonNull final Context context, final int playlistId) {
return playlistId != -1
&& doesPlaylistExist(
context,
MediaStore.Audio.Playlists._ID + "=?",
new String[] {String.valueOf(playlistId)});
}
public static boolean doesPlaylistExist(@NonNull final Context context, final String name) {
return doesPlaylistExist(
context, MediaStore.Audio.PlaylistsColumns.NAME + "=?", new String[] {name});
}
private static boolean doesPlaylistExist(
@NonNull Context context, @NonNull final String selection, @NonNull final String[] values) {
Cursor cursor =
context
.getContentResolver()
.query(EXTERNAL_CONTENT_URI, new String[]{}, selection, values, null);
boolean exists = false;
if (cursor != null) {
exists = cursor.getCount() != 0;
cursor.close();
}
return exists;
}
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.util
import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.helper.M3UWriter.writeIO
import java.io.File
import java.io.IOException
object PlaylistsUtil {
@Throws(IOException::class)
fun savePlaylistWithSongs(playlist: PlaylistWithSongs?): File {
return writeIO(
File(getExternalStorageDirectory(), "Playlists"), playlist!!
)
}
}

View file

@ -1,10 +1,12 @@
package code.name.monkey.retromusic.util
import android.content.Context
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.net.ConnectivityManager
import android.net.NetworkInfo
import androidx.core.content.edit
import androidx.core.content.getSystemService
import androidx.core.content.res.use
import androidx.fragment.app.Fragment
import androidx.preference.PreferenceManager
import androidx.viewpager.widget.ViewPager
import code.name.monkey.appthemehelper.util.VersionUtils
@ -97,10 +99,10 @@ object PreferenceUtil {
val languageCode: String get() = sharedPreferences.getString(LANGUAGE_NAME, "auto") ?: "auto"
var userName
var Fragment.userName
get() = sharedPreferences.getString(
USER_NAME,
App.getContext().getString(R.string.user_name)
getString(R.string.user_name)
)
set(value) = sharedPreferences.edit {
putString(USER_NAME, value)
@ -333,15 +335,12 @@ object PreferenceUtil {
val isLockScreen get() = sharedPreferences.getBoolean(LOCK_SCREEN, false)
fun isAllowedToDownloadMetadata(): Boolean {
fun isAllowedToDownloadMetadata(context: Context): Boolean {
return when (autoDownloadImagesPolicy) {
"always" -> true
"only_wifi" -> {
val connectivityManager = App.getContext().getSystemService<ConnectivityManager>()
var netInfo: NetworkInfo? = null
if (connectivityManager != null) {
netInfo = connectivityManager.activeNetworkInfo
}
val connectivityManager = context.getSystemService<ConnectivityManager>()
val netInfo = connectivityManager?.activeNetworkInfo
netInfo != null && netInfo.type == ConnectivityManager.TYPE_WIFI && netInfo.isConnectedOrConnecting
}
"never" -> false
@ -395,9 +394,15 @@ object PreferenceUtil {
val filterLength get() = sharedPreferences.getInt(FILTER_SONG, 20)
var lastVersion
get() = sharedPreferences.getInt(LAST_CHANGELOG_VERSION, 0)
// This was stored as an integer before now it's a long, so avoid a ClassCastException
get() = try {
sharedPreferences.getLong(LAST_CHANGELOG_VERSION, 0)
} catch (e: ClassCastException) {
sharedPreferences.edit { remove(LAST_CHANGELOG_VERSION) }
0
}
set(value) = sharedPreferences.edit {
putInt(LAST_CHANGELOG_VERSION, value)
putLong(LAST_CHANGELOG_VERSION, value)
}
var lastSleepTimerValue
@ -432,10 +437,11 @@ object PreferenceUtil {
val position = sharedPreferences.getStringOrDefault(
HOME_ARTIST_GRID_STYLE, "0"
).toInt()
val typedArray = App.getContext()
.resources.obtainTypedArray(R.array.pref_home_grid_style_layout)
val layoutRes = typedArray.getResourceId(position, 0)
typedArray.recycle()
val layoutRes =
App.getContext().resources.obtainTypedArray(R.array.pref_home_grid_style_layout)
.use {
it.getResourceId(position, 0)
}
return if (layoutRes == 0) {
R.layout.item_artist
} else layoutRes
@ -446,10 +452,10 @@ object PreferenceUtil {
val position = sharedPreferences.getStringOrDefault(
HOME_ALBUM_GRID_STYLE, "4"
).toInt()
val typedArray = App.getContext()
.resources.obtainTypedArray(R.array.pref_home_grid_style_layout)
val layoutRes = typedArray.getResourceId(position, 0)
typedArray.recycle()
val layoutRes = App.getContext()
.resources.obtainTypedArray(R.array.pref_home_grid_style_layout).use {
it.getResourceId(position, 0)
}
return if (layoutRes == 0) {
R.layout.item_image
} else layoutRes
@ -590,7 +596,7 @@ object PreferenceUtil {
4 -> VerticalFlipTransformation()
5 -> HingeTransformation()
6 -> VerticalStackTransformer()
else -> NormalPageTransformer()
else -> ViewPager.PageTransformer { _, _ -> }
}
}

View file

@ -1,262 +0,0 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.util;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.res.ResourcesCompat;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.text.DecimalFormat;
import java.util.Collections;
import java.util.List;
import code.name.monkey.appthemehelper.util.TintHelper;
import code.name.monkey.retromusic.App;
public class RetroUtil {
private static final int[] TEMP_ARRAY = new int[1];
private static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar";
public static int calculateNoOfColumns(@NonNull Context context) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
float dpWidth = displayMetrics.widthPixels / displayMetrics.density;
return (int) (dpWidth / 180);
}
@NonNull
public static Bitmap createBitmap(@NonNull 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 String formatValue(float value) {
String[] arr = {"", "K", "M", "B", "T", "P", "E"};
int index = 0;
while ((value / 1000) >= 1) {
value = value / 1000;
index++;
}
DecimalFormat decimalFormat = new DecimalFormat("#.##");
return String.format("%s %s", decimalFormat.format(value), arr[index]);
}
public static float frequencyCount(int frequency) {
return (float) (frequency / 1000.0);
}
public static Point getScreenSize(@NonNull Context c) {
Display display = null;
if (c.getSystemService(Context.WINDOW_SERVICE) != null) {
display = ((WindowManager) c.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
}
Point size = new Point();
if (display != null) {
display.getSize(size);
}
return size;
}
public static int getStatusBarHeight() {
int result = 0;
int resourceId =
App.Companion.getContext()
.getResources()
.getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = App.Companion.getContext().getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public static int getNavigationBarHeight() {
int result = 0;
int resourceId =
App.Companion.getContext()
.getResources()
.getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
result = App.Companion.getContext().getResources().getDimensionPixelSize(resourceId);
}
return result;
}
@NonNull
public static Drawable getTintedVectorDrawable(
@NonNull Context context, @DrawableRes int id, @ColorInt int color) {
return TintHelper.createTintedDrawable(
getVectorDrawable(context.getResources(), id, context.getTheme()), color);
}
@NonNull
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);
}
@Nullable
public static Drawable getVectorDrawable(
@NonNull Resources res, @DrawableRes int resId, @Nullable Resources.Theme theme) {
return ResourcesCompat.getDrawable(res, resId, theme);
}
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);
if (inputMethodManager != null) {
inputMethodManager.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0);
}
}
}
}
public static boolean isAllowedToDownloadMetadata(final @NonNull Context context) {
switch (PreferenceUtil.INSTANCE.getAutoDownloadImagesPolicy()) {
case "always":
return true;
case "only_wifi":
final ConnectivityManager connectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo();
return netInfo != null
&& netInfo.getType() == ConnectivityManager.TYPE_WIFI
&& netInfo.isConnectedOrConnecting();
case "never":
default:
return false;
}
}
public static boolean isLandscape() {
return App.Companion.getContext().getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public static boolean isRTL(@NonNull Context context) {
Configuration config = context.getResources().getConfiguration();
return config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
}
public static boolean isTablet() {
return App.Companion.getContext().getResources().getConfiguration().smallestScreenWidthDp
>= 600;
}
public static void openUrl(@NonNull Activity context, @NonNull String str) {
Intent intent = new Intent("android.intent.action.VIEW");
intent.setData(Uri.parse(str));
intent.setFlags(268435456);
context.startActivity(intent);
}
public static void setAllowDrawUnderNavigationBar(Window window) {
window.setNavigationBarColor(Color.TRANSPARENT);
window
.getDecorView()
.setSystemUiVisibility(
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
? View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
: View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
}
public static void setAllowDrawUnderStatusBar(@NonNull Window window) {
window
.getDecorView()
.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
window.setStatusBarColor(Color.TRANSPARENT);
}
public static String getIpAddress(boolean useIPv4) {
try {
List<NetworkInterface> interfaces =
Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface intf : interfaces) {
List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
for (InetAddress addr : addrs) {
if (!addr.isLoopbackAddress()) {
String sAddr = addr.getHostAddress();
//boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);
boolean isIPv4 = sAddr.indexOf(':') < 0;
if (useIPv4) {
if (isIPv4) return sAddr;
} else {
if (!isIPv4) {
int delim = sAddr.indexOf('%'); // drop ip6 zone suffix
if (delim < 0) {
return sAddr.toUpperCase();
} else {
return sAddr.substring(
0,
delim
).toUpperCase();
}
}
}
}
}
}
} catch (Exception ignored) {
}
return "";
}
}

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.util
import android.content.Context
import android.content.res.Configuration
import android.graphics.Point
import code.name.monkey.retromusic.App.Companion.getContext
import java.net.InetAddress
import java.net.NetworkInterface
import java.text.DecimalFormat
import java.util.*
object RetroUtil {
fun formatValue(numValue: Float): String {
var value = numValue
val arr = arrayOf("", "K", "M", "B", "T", "P", "E")
var index = 0
while (value / 1000 >= 1) {
value /= 1000
index++
}
val decimalFormat = DecimalFormat("#.##")
return String.format("%s %s", decimalFormat.format(value.toDouble()), arr[index])
}
fun frequencyCount(frequency: Int): Float {
return (frequency / 1000.0).toFloat()
}
fun getScreenSize(context: Context): Point {
val x: Int = context.resources.displayMetrics.widthPixels
val y: Int = context.resources.displayMetrics.heightPixels
return Point(x, y)
}
val statusBarHeight: Int
get() {
var result = 0
val resourceId = getContext()
.resources
.getIdentifier("status_bar_height", "dimen", "android")
if (resourceId > 0) {
result = getContext().resources.getDimensionPixelSize(resourceId)
}
return result
}
val navigationBarHeight: Int
get() {
var result = 0
val resourceId = getContext()
.resources
.getIdentifier("navigation_bar_height", "dimen", "android")
if (resourceId > 0) {
result = getContext().resources.getDimensionPixelSize(resourceId)
}
return result
}
val isLandscape: Boolean
get() = (getContext().resources.configuration.orientation
== Configuration.ORIENTATION_LANDSCAPE)
val isTablet: Boolean
get() = (getContext().resources.configuration.smallestScreenWidthDp
>= 600)
fun getIpAddress(useIPv4: Boolean): String? {
try {
val interfaces: List<NetworkInterface> =
Collections.list(NetworkInterface.getNetworkInterfaces())
for (intf in interfaces) {
val addrs: List<InetAddress> = Collections.list(intf.inetAddresses)
for (addr in addrs) {
if (!addr.isLoopbackAddress) {
val sAddr = addr.hostAddress
if (sAddr != null) {
val isIPv4 = sAddr.indexOf(':') < 0
if (useIPv4) {
if (isIPv4) return sAddr
} else {
if (!isIPv4) {
val delim = sAddr.indexOf('%') // drop ip6 zone suffix
return if (delim < 0) {
sAddr.uppercase()
} else {
sAddr.substring(
0,
delim
).uppercase()
}
}
}
} else {
return null
}
}
}
}
} catch (ignored: Exception) {
}
return ""
}
}

View file

@ -19,10 +19,10 @@ import android.content.Intent
import android.provider.BaseColumns
import android.provider.MediaStore
import android.provider.Settings
import android.widget.Toast
import androidx.core.net.toUri
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil.getSongFileUri
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -45,7 +45,7 @@ class RingtoneManager(val context: Context) {
Settings.System.putString(resolver, Settings.System.RINGTONE, uri.toString())
val message = context
.getString(R.string.x_has_been_set_as_ringtone, cursorSong.getString(0))
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
context.showToast(message)
}
}
} catch (ignored: SecurityException) {

View file

@ -6,6 +6,7 @@ import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import androidx.annotation.RequiresApi
import code.name.monkey.retromusic.Constants
object UriUtil {
@RequiresApi(Build.VERSION_CODES.Q)
@ -13,7 +14,7 @@ object UriUtil {
val uri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL)
val proj = arrayOf(MediaStore.Files.FileColumns._ID)
context.contentResolver.query(
uri, proj, MediaStore.Files.FileColumns.DATA + "=?", arrayOf(path), null
uri, proj, Constants.DATA + "=?", arrayOf(path), null
)?.use { cursor ->
if (cursor.count != 0) {
cursor.moveToFirst()

View file

@ -1,31 +1,29 @@
package code.name.monkey.retromusic.util.theme
import android.content.Context
import androidx.annotation.StyleRes
import androidx.appcompat.app.AppCompatDelegate
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.generalThemeValue
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.theme.ThemeMode.*
object ThemeManager {
@StyleRes
fun getThemeResValue(): Int =
if (PreferenceUtil.materialYou) {
R.style.Theme_RetroMusic_MD3
} else {
when (App.getContext().generalThemeValue) {
LIGHT -> R.style.Theme_RetroMusic_Light
DARK -> R.style.Theme_RetroMusic_Base
BLACK -> R.style.Theme_RetroMusic_Black
AUTO -> R.style.Theme_RetroMusic_FollowSystem
}
@StyleRes
fun Context.getThemeResValue(): Int =
if (PreferenceUtil.materialYou) {
if (generalThemeValue == BLACK) R.style.Theme_RetroMusic_MD3_Black
else R.style.Theme_RetroMusic_MD3
} else {
when (generalThemeValue) {
LIGHT -> R.style.Theme_RetroMusic_Light
DARK -> R.style.Theme_RetroMusic_Base
BLACK -> R.style.Theme_RetroMusic_Black
AUTO -> R.style.Theme_RetroMusic_FollowSystem
}
fun getNightMode(): Int = when (App.getContext().generalThemeValue) {
LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
DARK -> AppCompatDelegate.MODE_NIGHT_YES
else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
}
fun Context.getNightMode(): Int = when (generalThemeValue) {
LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
DARK -> AppCompatDelegate.MODE_NIGHT_YES
else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
}