@@ -12,13 +12,14 @@
+
@@ -121,6 +122,7 @@
android:name=".appshortcuts.AppShortcutLauncherActivity"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
+
-
@@ -204,15 +203,14 @@
android:resource="@xml/app_widget_card_info" />
-
+ android:resource="@xml/provider_paths" />
diff --git a/app/src/main/assets/phonograph-changelog.html b/app/src/main/assets/phonograph-changelog.html
index fde3331b7..c975e6a14 100644
--- a/app/src/main/assets/phonograph-changelog.html
+++ b/app/src/main/assets/phonograph-changelog.html
@@ -27,6 +27,87 @@
You can view the changelog dialog again at any time from the about section.
+Version 1.3.1
+
+ - NEW: Artist image mosaics
+ - FIX: Ringtone sharing
+
+
+Version 1.3.0
+
+ - NEW: Show more information of songs, albums and artists
+ - NEW: Option to finish last song in sleep timer
+ - NEW: Support for Android Pie
+ - NEW: Option for last 7 days for recently played
+ - FIX: Artist images not loading
+ - IMPROVEMENT: Sync translations
+
+
+Version 1.2.0
+
+ - NEW:Support for devices with a notch
+
+
+Version 1.1.2
+
+ - FIX: Crash with custom artist images
+
+
+Version 1.1.1
+
+ - NEW: Preference to turn off shuffle mode when selecting new list of songs
+ - FIX: Fix app intro crash
+ - FIX: Fix a crash for some artist names which contain special characters
+ - FIX: Fix loading of very large embedded album art
+
+
+Version 1.1.0
+
+ - NEW: Select all items in a list
+ - NEW: Export multiple playlists at once
+ - FIX: Show unknown year consistently everywhere
+ - FIX: Also look for png album covers in the folder
+ - IMPROVEMENT: Updated translations
+
+
+Version 1.0.1
+
+ - FIX: Broken layout for super long artist names
+ - FIX: Show "-" instead of "0" when the album year is not available
+ - FIX: Show "Unknown Artist" when the artist name is unknown
+ - FIX: Navigation bar button colors for light themes
+ - IMPROVEMENT: Updated translations
+
+
+Version 1.0.0
+This is it, Phonograph 1.0.0! We are finally out of beta, therefore many bugs were fixed and the
+ album and artist pages received a brand new look.
+
+ - NEW: Album page redesign
+ - NEW: Artist page redesign
+ - NEW: Custom sort orders for titles, albums and artists
+ - NEW: Rescan media from the navigation drawer
+ - IMPROVEMENT: Updated translations
+ - FIX: Fixed many bugs and crashes
+
+
+Version 0.16.9
+
+ - FIX: Crash on start for some users
+
+
+Version 0.16.8
+
+ - IMPROVEMENT: Updated translations
+ - OTHER: Removed all analytics
+
+
+Version 0.16.7
+
+ - IMPROVEMENT: Updated translations
+ - IMPROVEMENT: Minor improvements
+
+
Version 0.16.6
- FIX: Broken dot animation in Playing Screen Preference
diff --git a/app/src/main/java/com/kabouzeid/gramophone/App.java b/app/src/main/java/com/kabouzeid/gramophone/App.java
index 7e0b8e1e6..f58bbd886 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/App.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/App.java
@@ -3,21 +3,18 @@
import android.app.Application;
import android.os.Build;
+import androidx.annotation.NonNull;
+
import com.anjlab.android.iab.v3.BillingProcessor;
import com.anjlab.android.iab.v3.TransactionDetails;
-import com.crashlytics.android.Crashlytics;
-import com.crashlytics.android.answers.Answers;
-import com.crashlytics.android.core.CrashlyticsCore;
import com.kabouzeid.appthemehelper.ThemeStore;
import com.kabouzeid.gramophone.appshortcuts.DynamicShortcutManager;
-import io.fabric.sdk.android.Fabric;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class App extends Application {
- public static final String TAG = App.class.getSimpleName();
public static final String GOOGLE_PLAY_LICENSE_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjMeADN5Ffnt/ml5SYxNPCn8kGcOYGpHEfNSCts99vVxqmCn6C01E94c17j7rUK2aeHur5uxphZylzopPlQ8P8l1fqty0GPUNRSo18FCJzfGH8HZAwZYOcnRFPaXdaq3InyFJhBiODh2oeAcVK/idH6QraQ4r9HIlzigAg6lgwzxl2wJKDh7X/GMdDntCyzDh8xDQ0wIawFgvgojHwqh2Ci8Gnq6EYRwPA9yHiIIksT8Q30QyM5ewl5QcnWepsls7enNqeHarhpmSibRUDgCsxHoOpny7SyuvZvUI3wuLckDR0ds9hrt614scHHqDOBp/qWCZiAgOPVAEQcURbV09qQIDAQAB";
public static final String PRO_VERSION_PRODUCT_ID = "pro_version";
@@ -34,22 +31,11 @@ public void onCreate() {
// default theme
if (!ThemeStore.isConfigured(this, 1)) {
ThemeStore.editTheme(this)
- .activityTheme(R.style.Theme_Phonograph_Light)
.primaryColorRes(R.color.md_indigo_500)
.accentColorRes(R.color.md_pink_A400)
.commit();
}
- // Set up Crashlytics, disabled for debug builds
- Crashlytics crashlyticsKit = new Crashlytics.Builder()
- .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
- .build();
- if (!BuildConfig.DEBUG) {
- Fabric.with(this, crashlyticsKit, new Answers());
- } else {
- Fabric.with(this, crashlyticsKit); // crashlytics kit is disabled here
- }
-
// Set up dynamic shortcuts
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
new DynamicShortcutManager(this).initDynamicShortcuts();
@@ -58,7 +44,7 @@ public void onCreate() {
// automatically restores purchases
billingProcessor = new BillingProcessor(this, App.GOOGLE_PLAY_LICENSE_KEY, new BillingProcessor.IBillingHandler() {
@Override
- public void onProductPurchased(String productId, TransactionDetails details) {
+ public void onProductPurchased(@NonNull String productId, TransactionDetails details) {
}
@Override
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/AlbumCoverPagerAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/AlbumCoverPagerAdapter.java
index bcac0e455..b0690df99 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/AlbumCoverPagerAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/AlbumCoverPagerAdapter.java
@@ -2,8 +2,9 @@
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -18,6 +19,7 @@
import com.kabouzeid.gramophone.util.PreferenceUtil;
import java.util.ArrayList;
+import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
@@ -27,14 +29,13 @@
* @author Karim Abou Zeid (kabouzeid)
*/
public class AlbumCoverPagerAdapter extends CustomFragmentStatePagerAdapter {
- public static final String TAG = AlbumCoverPagerAdapter.class.getSimpleName();
- private ArrayList dataSet;
+ private List dataSet;
private AlbumCoverFragment.ColorReceiver currentColorReceiver;
private int currentColorReceiverPosition = -1;
- public AlbumCoverPagerAdapter(FragmentManager fm, ArrayList dataSet) {
+ public AlbumCoverPagerAdapter(FragmentManager fm, List dataSet) {
super(fm);
this.dataSet = dataSet;
}
@@ -50,6 +51,7 @@ public int getCount() {
}
@Override
+ @NonNull
public Object instantiateItem(ViewGroup container, int position) {
Object o = super.instantiateItem(container, position);
if (currentColorReceiver != null && currentColorReceiverPosition == position) {
@@ -102,15 +104,14 @@ public void onCreate(final Bundle savedInstanceState) {
}
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_album_cover, container, false);
unbinder = ButterKnife.bind(this, view);
return view;
}
@Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
+ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
forceSquareAlbumCover(false);
// TODO
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/CategoryInfoAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/CategoryInfoAdapter.java
index 7dead410b..baeb95937 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/CategoryInfoAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/CategoryInfoAdapter.java
@@ -1,8 +1,9 @@
package com.kabouzeid.gramophone.adapter;
import android.annotation.SuppressLint;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.ItemTouchHelper;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -16,26 +17,28 @@
import com.kabouzeid.gramophone.util.SwipeAndDragHelper;
import java.util.ArrayList;
+import java.util.List;
public class CategoryInfoAdapter extends RecyclerView.Adapter implements SwipeAndDragHelper.ActionCompletionContract {
- private ArrayList categoryInfos;
+ private List categoryInfos;
private ItemTouchHelper touchHelper;
- public CategoryInfoAdapter(ArrayList categoryInfos) {
+ public CategoryInfoAdapter(List categoryInfos) {
this.categoryInfos = categoryInfos;
SwipeAndDragHelper swipeAndDragHelper = new SwipeAndDragHelper(this);
touchHelper = new ItemTouchHelper(swipeAndDragHelper);
}
@Override
- public CategoryInfoAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ @NonNull
+ public CategoryInfoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.preference_dialog_library_categories_listitem, parent, false);
return new ViewHolder(view);
}
@SuppressLint("ClickableViewAccessibility")
@Override
- public void onBindViewHolder(CategoryInfoAdapter.ViewHolder holder, int position) {
+ public void onBindViewHolder(@NonNull CategoryInfoAdapter.ViewHolder holder, int position) {
CategoryInfo categoryInfo = categoryInfos.get(position);
holder.checkBox.setChecked(categoryInfo.visible);
@@ -64,8 +67,7 @@ public int getItemCount() {
return categoryInfos.size();
}
-
- public void setCategoryInfos(ArrayList categoryInfos) {
+ public void setCategoryInfos(List categoryInfos) {
this.categoryInfos = categoryInfos;
notifyDataSetChanged();
}
@@ -82,7 +84,7 @@ public void attachToRecyclerView(RecyclerView recyclerView) {
touchHelper.attachToRecyclerView(recyclerView);
}
- public ArrayList getCategoryInfos() {
+ public List getCategoryInfos() {
return categoryInfos;
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/GenreAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/GenreAdapter.java
index d21f670f7..53f10d1a0 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/GenreAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/GenreAdapter.java
@@ -1,9 +1,9 @@
package com.kabouzeid.gramophone.adapter;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.RecyclerView;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -15,27 +15,26 @@
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
import java.util.ArrayList;
+import java.util.List;
public class GenreAdapter extends RecyclerView.Adapter implements FastScrollRecyclerView.SectionedAdapter {
- public static final String TAG = GenreAdapter.class.getSimpleName();
-
@NonNull
private final AppCompatActivity activity;
- private ArrayList dataSet;
+ private List dataSet;
private int itemLayoutRes;
- public GenreAdapter(@NonNull AppCompatActivity activity, ArrayList dataSet, @LayoutRes int itemLayoutRes) {
+ public GenreAdapter(@NonNull AppCompatActivity activity, List dataSet, @LayoutRes int itemLayoutRes) {
this.activity = activity;
this.dataSet = dataSet;
this.itemLayoutRes = itemLayoutRes;
}
- public ArrayList getDataSet() {
+ public List getDataSet() {
return dataSet;
}
- public void swapDataSet(ArrayList dataSet) {
+ public void swapDataSet(List dataSet) {
this.dataSet = dataSet;
notifyDataSetChanged();
}
@@ -47,7 +46,7 @@ public long getItemId(int position) {
@NonNull
@Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false);
return new ViewHolder(view);
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/MusicLibraryPagerAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/MusicLibraryPagerAdapter.java
index 9929a0c66..6c9b45f69 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/MusicLibraryPagerAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/MusicLibraryPagerAdapter.java
@@ -2,10 +2,10 @@
import android.content.Context;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentPagerAdapter;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentPagerAdapter;
import android.util.SparseArray;
import android.view.ViewGroup;
@@ -38,7 +38,7 @@ public MusicLibraryPagerAdapter(@NonNull final Context context, final FragmentMa
setCategoryInfos(PreferenceUtil.getInstance(context).getLibraryCategoryInfos());
}
- public void setCategoryInfos(@NonNull ArrayList categoryInfos) {
+ public void setCategoryInfos(@NonNull List categoryInfos) {
mHolderList.clear();
for (CategoryInfo categoryInfo : categoryInfos) {
@@ -165,9 +165,9 @@ public Class extends Fragment> getFragmentClass() {
public static MusicFragments of(Class> cl) {
MusicFragments[] fragments = All.FRAGMENTS;
- for (int i = 0; i < fragments.length; i++) {
- if (cl.equals(fragments[i].mFragmentClass))
- return fragments[i];
+ for (MusicFragments fragment : fragments) {
+ if (cl.equals(fragment.mFragmentClass))
+ return fragment;
}
throw new IllegalArgumentException("Unknown music fragment " + cl);
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/PlaylistAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/PlaylistAdapter.java
index c37b966e5..01127601d 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/PlaylistAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/PlaylistAdapter.java
@@ -1,18 +1,21 @@
package com.kabouzeid.gramophone.adapter;
+import android.content.Context;
import android.graphics.PorterDuff;
import android.os.Build;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.PopupMenu;
+import android.widget.Toast;
import com.kabouzeid.appthemehelper.util.ATHUtil;
+import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.adapter.base.AbsMultiSelectAdapter;
import com.kabouzeid.gramophone.adapter.base.MediaEntryViewHolder;
@@ -22,6 +25,7 @@
import com.kabouzeid.gramophone.helper.menu.SongsMenuHelper;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.loader.PlaylistSongLoader;
+import com.kabouzeid.gramophone.misc.WeakContextAsyncTask;
import com.kabouzeid.gramophone.model.AbsCustomPlaylist;
import com.kabouzeid.gramophone.model.Playlist;
import com.kabouzeid.gramophone.model.Song;
@@ -29,7 +33,9 @@
import com.kabouzeid.gramophone.model.smartplaylist.LastAddedPlaylist;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
+import com.kabouzeid.gramophone.util.PlaylistsUtil;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -38,16 +44,14 @@
*/
public class PlaylistAdapter extends AbsMultiSelectAdapter {
- public static final String TAG = PlaylistAdapter.class.getSimpleName();
-
private static final int SMART_PLAYLIST = 0;
private static final int DEFAULT_PLAYLIST = 1;
protected final AppCompatActivity activity;
- protected ArrayList dataSet;
+ protected List dataSet;
protected int itemLayoutRes;
- public PlaylistAdapter(AppCompatActivity activity, ArrayList dataSet, @LayoutRes int itemLayoutRes, @Nullable CabHolder cabHolder) {
+ public PlaylistAdapter(AppCompatActivity activity, List dataSet, @LayoutRes int itemLayoutRes, @Nullable CabHolder cabHolder) {
super(activity, cabHolder, R.menu.menu_playlists_selection);
this.activity = activity;
this.dataSet = dataSet;
@@ -55,11 +59,11 @@ public PlaylistAdapter(AppCompatActivity activity, ArrayList dataSet,
setHasStableIds(true);
}
- public ArrayList getDataSet() {
+ public List getDataSet() {
return dataSet;
}
- public void swapDataSet(ArrayList dataSet) {
+ public void swapDataSet(List dataSet) {
this.dataSet = dataSet;
notifyDataSetChanged();
}
@@ -69,9 +73,9 @@ public long getItemId(int position) {
return dataSet.get(position).id;
}
- @NonNull
@Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ @NonNull
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false);
return createViewHolder(view, viewType);
}
@@ -133,7 +137,7 @@ protected String getName(Playlist playlist) {
}
@Override
- protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull ArrayList selection) {
+ protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull List selection) {
switch (menuItem.getItemId()) {
case R.id.action_delete_playlist:
for (int i = 0; i < selection.size(); i++) {
@@ -149,15 +153,59 @@ protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull ArrayLi
DeletePlaylistDialog.create(selection).show(activity.getSupportFragmentManager(), "DELETE_PLAYLIST");
}
break;
+ case R.id.action_save_playlist:
+ if (selection.size() == 1) {
+ PlaylistMenuHelper.handleMenuClick(activity, selection.get(0), menuItem);
+ } else {
+ new SavePlaylistsAsyncTask(activity).execute(selection);
+ }
+ break;
default:
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.getItemId());
break;
}
}
+ private static class SavePlaylistsAsyncTask extends WeakContextAsyncTask, String, String> {
+ public SavePlaylistsAsyncTask(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected String doInBackground(List... params) {
+ int successes = 0;
+ int failures = 0;
+
+ String dir = "";
+
+ for (Playlist playlist : params[0]) {
+ try {
+ dir = PlaylistsUtil.savePlaylist(App.getInstance().getApplicationContext(), playlist).getParent();
+ successes++;
+ } catch (IOException e) {
+ failures++;
+ e.printStackTrace();
+ }
+ }
+
+ return failures == 0
+ ? String.format(App.getInstance().getApplicationContext().getString(R.string.saved_x_playlists_to_x), successes, dir)
+ : String.format(App.getInstance().getApplicationContext().getString(R.string.saved_x_playlists_to_x_failed_to_save_x), successes, dir, failures);
+ }
+
+ @Override
+ protected void onPostExecute(String string) {
+ super.onPostExecute(string);
+ Context context = getContext();
+ if (context != null) {
+ Toast.makeText(context, string, Toast.LENGTH_LONG).show();
+ }
+ }
+ }
+
@NonNull
- private ArrayList getSongList(@NonNull List playlists) {
- final ArrayList songs = new ArrayList<>();
+ private List getSongList(@NonNull List playlists) {
+ final List songs = new ArrayList<>();
for (Playlist playlist : playlists) {
if (playlist instanceof AbsCustomPlaylist) {
songs.addAll(((AbsCustomPlaylist) playlist).getSongs(activity));
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/SearchAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/SearchAdapter.java
index 225423bf6..d8bc49478 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/SearchAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/SearchAdapter.java
@@ -1,10 +1,10 @@
package com.kabouzeid.gramophone.adapter;
import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.v4.util.Pair;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.RecyclerView;
+import androidx.annotation.NonNull;
+import androidx.core.util.Pair;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -57,9 +57,9 @@ public int getItemViewType(int position) {
return HEADER;
}
- @NonNull
@Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ @NonNull
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == HEADER)
return new ViewHolder(LayoutInflater.from(activity).inflate(R.layout.sub_header, parent, false), viewType);
return new ViewHolder(LayoutInflater.from(activity).inflate(R.layout.item_list, parent, false), viewType);
@@ -72,7 +72,7 @@ public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
case ALBUM:
final Album album = (Album) dataSet.get(position);
holder.title.setText(album.getTitle());
- holder.text.setText(album.getArtistName());
+ holder.text.setText(MusicUtil.getAlbumInfoString(activity, album));
SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
.checkIgnoreMediaStore(activity).build()
.into(holder.image);
@@ -87,7 +87,7 @@ public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
case SONG:
final Song song = (Song) dataSet.get(position);
holder.title.setText(song.title);
- holder.text.setText(song.albumName);
+ holder.text.setText(MusicUtil.getSongInfoString(song));
break;
default:
holder.title.setText(dataSet.get(position).toString());
@@ -164,7 +164,7 @@ public void onClick(View view) {
));
break;
case SONG:
- ArrayList playList = new ArrayList<>();
+ List playList = new ArrayList<>();
playList.add((Song) item);
MusicPlayerRemote.openQueue(playList, 0, true);
break;
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/SongFileAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/SongFileAdapter.java
index 2745423fb..a067e478f 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/SongFileAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/SongFileAdapter.java
@@ -2,10 +2,10 @@
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
@@ -20,7 +20,7 @@
import com.kabouzeid.gramophone.adapter.base.MediaEntryViewHolder;
import com.kabouzeid.gramophone.glide.audiocover.AudioFileCover;
import com.kabouzeid.gramophone.interfaces.CabHolder;
-import com.kabouzeid.gramophone.util.Util;
+import com.kabouzeid.gramophone.util.ImageUtil;
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
import java.io.File;
@@ -64,12 +64,13 @@ public void swapDataSet(@NonNull List songFiles) {
}
@Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ @NonNull
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false));
}
@Override
- public void onBindViewHolder(final ViewHolder holder, int index) {
+ public void onBindViewHolder(@NonNull ViewHolder holder, int index) {
final File file = dataSet.get(index);
holder.itemView.setActivated(isChecked(file));
@@ -115,7 +116,7 @@ protected void loadFileImage(File file, final ViewHolder holder) {
holder.image.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN);
holder.image.setImageResource(R.drawable.ic_folder_white_24dp);
} else {
- Drawable error = Util.getTintedVectorDrawable(activity, R.drawable.ic_file_music_white_24dp, iconColor);
+ Drawable error = ImageUtil.getTintedVectorDrawable(activity, R.drawable.ic_file_music_white_24dp, iconColor);
Glide.with(activity)
.load(new AudioFileCover(file.getPath()))
.diskCacheStrategy(DiskCacheStrategy.NONE)
@@ -150,7 +151,7 @@ protected String getName(File object) {
}
@Override
- protected void onMultipleItemAction(MenuItem menuItem, ArrayList selection) {
+ protected void onMultipleItemAction(MenuItem menuItem, List selection) {
if (callbacks == null) return;
callbacks.onMultipleItemAction(menuItem, selection);
}
@@ -205,6 +206,6 @@ public interface Callbacks {
void onFileMenuClicked(File file, View view);
- void onMultipleItemAction(MenuItem item, ArrayList files);
+ void onMultipleItemAction(MenuItem item, List files);
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/album/AlbumAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/album/AlbumAdapter.java
index dfb79b953..fc34217e1 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/album/AlbumAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/album/AlbumAdapter.java
@@ -1,11 +1,11 @@
package com.kabouzeid.gramophone.adapter.album;
import android.graphics.drawable.Drawable;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.util.Pair;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.util.Pair;
+import androidx.appcompat.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
@@ -19,12 +19,15 @@
import com.kabouzeid.gramophone.adapter.base.MediaEntryViewHolder;
import com.kabouzeid.gramophone.glide.PhonographColoredTarget;
import com.kabouzeid.gramophone.glide.SongGlideRequest;
+import com.kabouzeid.gramophone.helper.SortOrder;
import com.kabouzeid.gramophone.helper.menu.SongsMenuHelper;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.model.Album;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
+import com.kabouzeid.gramophone.util.PreferenceUtil;
+
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
import java.util.ArrayList;
@@ -35,16 +38,14 @@
*/
public class AlbumAdapter extends AbsMultiSelectAdapter implements FastScrollRecyclerView.SectionedAdapter {
- public static final String TAG = AlbumAdapter.class.getSimpleName();
-
protected final AppCompatActivity activity;
- protected ArrayList dataSet;
+ protected List dataSet;
protected int itemLayoutRes;
protected boolean usePalette = false;
- public AlbumAdapter(@NonNull AppCompatActivity activity, ArrayList dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
+ public AlbumAdapter(@NonNull AppCompatActivity activity, List dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, cabHolder, R.menu.menu_media_selection);
this.activity = activity;
this.dataSet = dataSet;
@@ -59,18 +60,18 @@ public void usePalette(boolean usePalette) {
notifyDataSetChanged();
}
- public void swapDataSet(ArrayList dataSet) {
+ public void swapDataSet(List dataSet) {
this.dataSet = dataSet;
notifyDataSetChanged();
}
- public ArrayList getDataSet() {
+ public List getDataSet() {
return dataSet;
}
- @NonNull
@Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ @NonNull
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false);
return createViewHolder(view, viewType);
}
@@ -84,7 +85,10 @@ protected String getAlbumTitle(Album album) {
}
protected String getAlbumText(Album album) {
- return album.getArtistName();
+ return MusicUtil.buildInfoString(
+ album.getArtistName(),
+ MusicUtil.getSongCountString(activity, album.songs.size())
+ );
}
@Override
@@ -170,13 +174,13 @@ protected String getName(Album album) {
}
@Override
- protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull ArrayList selection) {
+ protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull List selection) {
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.getItemId());
}
@NonNull
- private ArrayList getSongList(@NonNull List albums) {
- final ArrayList songs = new ArrayList<>();
+ private List getSongList(@NonNull List albums) {
+ final List songs = new ArrayList<>();
for (Album album : albums) {
songs.addAll(album.songs);
}
@@ -186,7 +190,20 @@ private ArrayList getSongList(@NonNull List albums) {
@NonNull
@Override
public String getSectionName(int position) {
- return MusicUtil.getSectionName(dataSet.get(position).getTitle());
+ @Nullable String sectionName = null;
+ switch (PreferenceUtil.getInstance(activity).getAlbumSortOrder()) {
+ case SortOrder.AlbumSortOrder.ALBUM_A_Z:
+ case SortOrder.AlbumSortOrder.ALBUM_Z_A:
+ sectionName = dataSet.get(position).getTitle();
+ break;
+ case SortOrder.AlbumSortOrder.ALBUM_ARTIST:
+ sectionName = dataSet.get(position).getArtistName();
+ break;
+ case SortOrder.AlbumSortOrder.ALBUM_YEAR:
+ return MusicUtil.getYearString(dataSet.get(position).getYear());
+ }
+
+ return MusicUtil.getSectionName(sectionName);
}
public class ViewHolder extends MediaEntryViewHolder {
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/album/HorizontalAlbumAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/album/HorizontalAlbumAdapter.java
index 911bca19c..4bc42cf24 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/album/HorizontalAlbumAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/album/HorizontalAlbumAdapter.java
@@ -1,10 +1,10 @@
package com.kabouzeid.gramophone.adapter.album;
import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.CardView;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.cardview.widget.CardView;
import android.view.View;
import android.view.ViewGroup;
@@ -16,16 +16,17 @@
import com.kabouzeid.gramophone.helper.HorizontalAdapterHelper;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.model.Album;
+import com.kabouzeid.gramophone.util.MusicUtil;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class HorizontalAlbumAdapter extends AlbumAdapter {
- public static final String TAG = AlbumAdapter.class.getSimpleName();
- public HorizontalAlbumAdapter(@NonNull AppCompatActivity activity, ArrayList dataSet, boolean usePalette, @Nullable CabHolder cabHolder) {
+ public HorizontalAlbumAdapter(@NonNull AppCompatActivity activity, List dataSet, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, usePalette, cabHolder);
}
@@ -76,11 +77,7 @@ public void onColorReady(int color) {
@Override
protected String getAlbumText(Album album) {
- int year = album.getYear();
- if(year > 0) {
- return String.valueOf(year);
- }
- return "-";
+ return MusicUtil.getYearString(album.getYear());
}
@Override
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/artist/ArtistAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/artist/ArtistAdapter.java
index 89c69df9e..8c62dd633 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/artist/ArtistAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/artist/ArtistAdapter.java
@@ -1,11 +1,11 @@
package com.kabouzeid.gramophone.adapter.artist;
import android.graphics.drawable.Drawable;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.util.Pair;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.util.Pair;
+import androidx.appcompat.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
@@ -19,12 +19,14 @@
import com.kabouzeid.gramophone.adapter.base.MediaEntryViewHolder;
import com.kabouzeid.gramophone.glide.ArtistGlideRequest;
import com.kabouzeid.gramophone.glide.PhonographColoredTarget;
+import com.kabouzeid.gramophone.helper.SortOrder;
import com.kabouzeid.gramophone.helper.menu.SongsMenuHelper;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.model.Artist;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
+import com.kabouzeid.gramophone.util.PreferenceUtil;
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
import java.util.ArrayList;
@@ -36,13 +38,13 @@
public class ArtistAdapter extends AbsMultiSelectAdapter implements FastScrollRecyclerView.SectionedAdapter {
protected final AppCompatActivity activity;
- protected ArrayList dataSet;
+ protected List dataSet;
protected int itemLayoutRes;
protected boolean usePalette = false;
- public ArtistAdapter(@NonNull AppCompatActivity activity, ArrayList dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
+ public ArtistAdapter(@NonNull AppCompatActivity activity, List dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, cabHolder, R.menu.menu_media_selection);
this.activity = activity;
this.dataSet = dataSet;
@@ -51,12 +53,12 @@ public ArtistAdapter(@NonNull AppCompatActivity activity, ArrayList data
setHasStableIds(true);
}
- public void swapDataSet(ArrayList dataSet) {
+ public void swapDataSet(List dataSet) {
this.dataSet = dataSet;
notifyDataSetChanged();
}
- public ArrayList getDataSet() {
+ public List getDataSet() {
return dataSet;
}
@@ -71,7 +73,8 @@ public long getItemId(int position) {
}
@Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ @NonNull
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false);
return createViewHolder(view);
}
@@ -157,13 +160,13 @@ protected String getName(Artist artist) {
}
@Override
- protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull ArrayList selection) {
+ protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull List selection) {
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.getItemId());
}
@NonNull
- private ArrayList getSongList(@NonNull List artists) {
- final ArrayList songs = new ArrayList<>();
+ private List getSongList(@NonNull List artists) {
+ final List songs = new ArrayList<>();
for (Artist artist : artists) {
songs.addAll(artist.getSongs()); // maybe async in future?
}
@@ -173,7 +176,15 @@ private ArrayList getSongList(@NonNull List artists) {
@NonNull
@Override
public String getSectionName(int position) {
- return MusicUtil.getSectionName(dataSet.get(position).getName());
+ @Nullable String sectionName = null;
+ switch (PreferenceUtil.getInstance(activity).getArtistSortOrder()) {
+ case SortOrder.ArtistSortOrder.ARTIST_A_Z:
+ case SortOrder.ArtistSortOrder.ARTIST_Z_A:
+ sectionName = dataSet.get(position).getName();
+ break;
+ }
+
+ return MusicUtil.getSectionName(sectionName);
}
public class ViewHolder extends MediaEntryViewHolder {
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/base/AbsMultiSelectAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/base/AbsMultiSelectAdapter.java
index f7e15b8d9..1ea151895 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/base/AbsMultiSelectAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/base/AbsMultiSelectAdapter.java
@@ -1,9 +1,9 @@
package com.kabouzeid.gramophone.adapter.base;
import android.content.Context;
-import android.support.annotation.MenuRes;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
+import androidx.annotation.MenuRes;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuItem;
@@ -12,6 +12,7 @@
import com.kabouzeid.gramophone.interfaces.CabHolder;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
@@ -20,7 +21,7 @@ public abstract class AbsMultiSelectAdapter checked;
+ private List checked;
private int menuRes;
private final Context context;
@@ -31,37 +32,51 @@ public AbsMultiSelectAdapter(Context context, @Nullable CabHolder cabHolder, @Me
this.context = context;
}
- protected void overrideMultiSelectMenuRes(@MenuRes int menuRes) {
+ protected void setMultiSelectMenuRes(@MenuRes int menuRes) {
this.menuRes = menuRes;
}
protected boolean toggleChecked(final int position) {
if (cabHolder != null) {
- openCabIfNecessary();
-
I identifier = getIdentifier(position);
- if (!checked.remove(identifier)) checked.add(identifier);
- notifyItemChanged(position);
+ if (identifier == null) return false;
- final int size = checked.size();
- if (size <= 0) cab.finish();
- else if (size == 1) cab.setTitle(getName(checked.get(0)));
- else if (size > 1) cab.setTitle(context.getString(R.string.x_selected, size));
+ if (!checked.remove(identifier)) checked.add(identifier);
+ notifyItemChanged(position);
+ updateCab();
return true;
}
return false;
}
- private void openCabIfNecessary() {
+ protected void checkAll() {
+ if (cabHolder != null) {
+ checked.clear();
+ for (int i = 0; i < getItemCount(); i++) {
+ I identifier = getIdentifier(i);
+ if (identifier != null) {
+ checked.add(identifier);
+ }
+ }
+ notifyDataSetChanged();
+ updateCab();
+ }
+ }
+
+ private void updateCab() {
if (cabHolder != null) {
if (cab == null || !cab.isActive()) {
cab = cabHolder.openCab(menuRes, this);
}
+ final int size = checked.size();
+ if (size <= 0) cab.finish();
+ else if (size == 1) cab.setTitle(getName(checked.get(0)));
+ else cab.setTitle(context.getString(R.string.x_selected, size));
}
}
- private void unCheckAll() {
+ private void clearChecked() {
checked.clear();
notifyDataSetChanged();
}
@@ -81,15 +96,19 @@ public boolean onCabCreated(MaterialCab materialCab, Menu menu) {
@Override
public boolean onCabItemClicked(MenuItem menuItem) {
- onMultipleItemAction(menuItem, new ArrayList<>(checked));
- cab.finish();
- unCheckAll();
+ if (menuItem.getItemId() == R.id.action_multi_select_adapter_check_all) {
+ checkAll();
+ } else {
+ onMultipleItemAction(menuItem, new ArrayList<>(checked));
+ cab.finish();
+ clearChecked();
+ }
return true;
}
@Override
public boolean onCabFinished(MaterialCab materialCab) {
- unCheckAll();
+ clearChecked();
return true;
}
@@ -97,7 +116,8 @@ protected String getName(I object) {
return object.toString();
}
+ @Nullable
protected abstract I getIdentifier(int position);
- protected abstract void onMultipleItemAction(MenuItem menuItem, ArrayList selection);
+ protected abstract void onMultipleItemAction(MenuItem menuItem, List selection);
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/base/MediaEntryViewHolder.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/base/MediaEntryViewHolder.java
index 8ad2a3f10..63bc7dc18 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/base/MediaEntryViewHolder.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/base/MediaEntryViewHolder.java
@@ -1,9 +1,9 @@
package com.kabouzeid.gramophone.adapter.base;
import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/AbsOffsetSongAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/AbsOffsetSongAdapter.java
index b75170dde..6b615ade8 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/AbsOffsetSongAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/AbsOffsetSongAdapter.java
@@ -1,9 +1,9 @@
package com.kabouzeid.gramophone.adapter.song;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -14,6 +14,7 @@
import com.kabouzeid.gramophone.model.Song;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Eugene Cheung (arkon)
@@ -23,11 +24,11 @@ public abstract class AbsOffsetSongAdapter extends SongAdapter {
protected static final int OFFSET_ITEM = 0;
protected static final int SONG = 1;
- public AbsOffsetSongAdapter(AppCompatActivity activity, ArrayList dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
+ public AbsOffsetSongAdapter(AppCompatActivity activity, List dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, dataSet, itemLayoutRes, usePalette, cabHolder);
}
- public AbsOffsetSongAdapter(AppCompatActivity activity, ArrayList dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder, boolean showSectionName) {
+ public AbsOffsetSongAdapter(AppCompatActivity activity, List dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder, boolean showSectionName) {
super(activity, dataSet, itemLayoutRes, usePalette, cabHolder, showSectionName);
}
@@ -53,10 +54,11 @@ public long getItemId(int position) {
return super.getItemId(position);
}
+ @Nullable
@Override
protected Song getIdentifier(int position) {
position--;
- if (position < 0) return Song.EMPTY_SONG;
+ if (position < 0) return null;
return super.getIdentifier(position);
}
@@ -87,7 +89,8 @@ public ViewHolder(@NonNull View itemView) {
@Override
protected Song getSong() {
- if (getItemViewType() == OFFSET_ITEM) return Song.EMPTY_SONG;
+ if (getItemViewType() == OFFSET_ITEM)
+ return Song.EMPTY_SONG; // could also return null, just to be safe return empty song
return dataSet.get(getAdapterPosition() - 1);
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/AlbumSongAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/AlbumSongAdapter.java
index 8742c34b9..586f513e1 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/AlbumSongAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/AlbumSongAdapter.java
@@ -1,9 +1,9 @@
package com.kabouzeid.gramophone.adapter.song;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import com.kabouzeid.gramophone.interfaces.CabHolder;
@@ -11,15 +11,14 @@
import com.kabouzeid.gramophone.util.MusicUtil;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class AlbumSongAdapter extends SongAdapter {
- public static final String TAG = AlbumSongAdapter.class.getSimpleName();
-
- public AlbumSongAdapter(AppCompatActivity activity, ArrayList dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
+ public AlbumSongAdapter(AppCompatActivity activity, List dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, dataSet, itemLayoutRes, usePalette, cabHolder);
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/ArtistSongAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/ArtistSongAdapter.java
index 3f4f73779..886f642a6 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/ArtistSongAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/ArtistSongAdapter.java
@@ -1,10 +1,10 @@
package com.kabouzeid.gramophone.adapter.song;
import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.util.Pair;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.util.Pair;
+import androidx.appcompat.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -26,6 +26,7 @@
import com.kabouzeid.gramophone.util.NavigationUtil;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
@@ -34,13 +35,13 @@ public class ArtistSongAdapter extends ArrayAdapter implements MaterialCab
@Nullable
private final CabHolder cabHolder;
private MaterialCab cab;
- private ArrayList dataSet;
- private ArrayList checked;
+ private List dataSet;
+ private List checked;
@NonNull
private final AppCompatActivity activity;
- public ArtistSongAdapter(@NonNull AppCompatActivity activity, @NonNull ArrayList dataSet, @Nullable CabHolder cabHolder) {
+ public ArtistSongAdapter(@NonNull AppCompatActivity activity, @NonNull List dataSet, @Nullable CabHolder cabHolder) {
super(activity, R.layout.item_list, dataSet);
this.activity = activity;
this.cabHolder = cabHolder;
@@ -48,20 +49,20 @@ public ArtistSongAdapter(@NonNull AppCompatActivity activity, @NonNull ArrayList
checked = new ArrayList<>();
}
- public ArrayList getDataSet() {
+ public List getDataSet() {
return dataSet;
}
- public void swapDataSet(ArrayList dataSet) {
+ public void swapDataSet(List dataSet) {
this.dataSet = dataSet;
clear();
addAll(dataSet);
notifyDataSetChanged();
}
- @Nullable
@Override
- public View getView(final int position, @Nullable View convertView, ViewGroup parent) {
+ @NonNull
+ public View getView(final int position, View convertView, @NonNull ViewGroup parent) {
final Song song = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_list, parent, false);
@@ -129,7 +130,7 @@ public boolean onMenuItemClick(MenuItem item) {
return convertView;
}
- private void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull ArrayList selection) {
+ private void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull List selection) {
SongsMenuHelper.handleMenuClick(activity, selection, menuItem.getItemId());
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/OrderablePlaylistSongAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/OrderablePlaylistSongAdapter.java
index 18d141676..4a5220b93 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/OrderablePlaylistSongAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/OrderablePlaylistSongAdapter.java
@@ -1,9 +1,9 @@
package com.kabouzeid.gramophone.adapter.song;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
import android.view.MenuItem;
import android.view.View;
@@ -27,13 +27,11 @@
@SuppressWarnings("unchecked")
public class OrderablePlaylistSongAdapter extends PlaylistSongAdapter implements DraggableItemAdapter {
- public static final String TAG = OrderablePlaylistSongAdapter.class.getSimpleName();
-
private OnMoveItemListener onMoveItemListener;
- public OrderablePlaylistSongAdapter(@NonNull AppCompatActivity activity, @NonNull ArrayList dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder, @Nullable OnMoveItemListener onMoveItemListener) {
- super(activity, (ArrayList) (List) dataSet, itemLayoutRes, usePalette, cabHolder);
- overrideMultiSelectMenuRes(R.menu.menu_playlists_songs_selection);
+ public OrderablePlaylistSongAdapter(@NonNull AppCompatActivity activity, @NonNull List dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder, @Nullable OnMoveItemListener onMoveItemListener) {
+ super(activity, (List) (List) dataSet, itemLayoutRes, usePalette, cabHolder);
+ setMultiSelectMenuRes(R.menu.menu_playlists_songs_selection);
this.onMoveItemListener = onMoveItemListener;
}
@@ -46,14 +44,14 @@ protected SongAdapter.ViewHolder createViewHolder(View view) {
public long getItemId(int position) {
position--;
if (position < 0) return -2;
- return ((ArrayList) (List) dataSet).get(position).idInPlayList; // important!
+ return ((List) (List) dataSet).get(position).idInPlayList; // important!
}
@Override
- protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull ArrayList selection) {
+ protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull List selection) {
switch (menuItem.getItemId()) {
case R.id.action_remove_from_playlist:
- RemoveFromPlaylistDialog.create((ArrayList) (List) selection).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
+ RemoveFromPlaylistDialog.create((List) (List) selection).show(activity.getSupportFragmentManager(), "ADD_PLAYLIST");
return;
}
super.onMultipleItemAction(menuItem, selection);
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/PlayingQueueAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/PlayingQueueAdapter.java
index 51785b2a0..2314bec12 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/PlayingQueueAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/PlayingQueueAdapter.java
@@ -1,9 +1,9 @@
package com.kabouzeid.gramophone.adapter.song;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
import android.view.MenuItem;
import android.view.View;
@@ -18,6 +18,7 @@
import com.kabouzeid.gramophone.util.ViewUtil;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
@@ -30,7 +31,7 @@ public class PlayingQueueAdapter extends SongAdapter implements DraggableItemAda
private int current;
- public PlayingQueueAdapter(AppCompatActivity activity, ArrayList dataSet, int current, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
+ public PlayingQueueAdapter(AppCompatActivity activity, List dataSet, int current, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, dataSet, itemLayoutRes, usePalette, cabHolder);
this.current = current;
}
@@ -66,7 +67,7 @@ protected void loadAlbumCover(Song song, SongAdapter.ViewHolder holder) {
// We don't want to load it in this adapter
}
- public void swapDataSet(ArrayList dataSet, int position) {
+ public void swapDataSet(List dataSet, int position) {
this.dataSet = dataSet;
current = position;
notifyDataSetChanged();
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/PlaylistSongAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/PlaylistSongAdapter.java
index 938221f49..ad621979a 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/PlaylistSongAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/PlaylistSongAdapter.java
@@ -1,10 +1,10 @@
package com.kabouzeid.gramophone.adapter.song;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.util.Pair;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.util.Pair;
+import androidx.appcompat.app.AppCompatActivity;
import android.view.MenuItem;
import android.view.View;
@@ -16,17 +16,16 @@
import com.kabouzeid.gramophone.util.NavigationUtil;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class PlaylistSongAdapter extends AbsOffsetSongAdapter {
- public static final String TAG = PlaylistSongAdapter.class.getSimpleName();
-
- public PlaylistSongAdapter(AppCompatActivity activity, @NonNull ArrayList dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
+ public PlaylistSongAdapter(AppCompatActivity activity, @NonNull List dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, dataSet, itemLayoutRes, usePalette, cabHolder, false);
- overrideMultiSelectMenuRes(R.menu.menu_cannot_delete_single_songs_playlist_songs_selection);
+ setMultiSelectMenuRes(R.menu.menu_cannot_delete_single_songs_playlist_songs_selection);
}
@Override
@@ -90,4 +89,4 @@ protected boolean onSongMenuItemClick(MenuItem item) {
return super.onSongMenuItemClick(item);
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/ShuffleButtonSongAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/ShuffleButtonSongAdapter.java
index 7fd6e85b8..625494b47 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/ShuffleButtonSongAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/ShuffleButtonSongAdapter.java
@@ -1,10 +1,10 @@
package com.kabouzeid.gramophone.adapter.song;
import android.graphics.Typeface;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import com.kabouzeid.appthemehelper.ThemeStore;
@@ -14,13 +14,14 @@
import com.kabouzeid.gramophone.model.Song;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class ShuffleButtonSongAdapter extends AbsOffsetSongAdapter {
- public ShuffleButtonSongAdapter(AppCompatActivity activity, ArrayList dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
+ public ShuffleButtonSongAdapter(AppCompatActivity activity, List dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
super(activity, dataSet, itemLayoutRes, usePalette, cabHolder);
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/SongAdapter.java b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/SongAdapter.java
index ea1094469..79782d324 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/adapter/song/SongAdapter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/adapter/song/SongAdapter.java
@@ -1,11 +1,11 @@
package com.kabouzeid.gramophone.adapter.song;
import android.graphics.drawable.Drawable;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.util.Pair;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.util.Pair;
+import androidx.appcompat.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
@@ -21,36 +21,37 @@
import com.kabouzeid.gramophone.glide.PhonographColoredTarget;
import com.kabouzeid.gramophone.glide.SongGlideRequest;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
+import com.kabouzeid.gramophone.helper.SortOrder;
import com.kabouzeid.gramophone.helper.menu.SongMenuHelper;
import com.kabouzeid.gramophone.helper.menu.SongsMenuHelper;
import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
+import com.kabouzeid.gramophone.util.PreferenceUtil;
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class SongAdapter extends AbsMultiSelectAdapter implements MaterialCab.Callback, FastScrollRecyclerView.SectionedAdapter {
- public static final String TAG = AlbumSongAdapter.class.getSimpleName();
-
protected final AppCompatActivity activity;
- protected ArrayList dataSet;
+ protected List dataSet;
protected int itemLayoutRes;
protected boolean usePalette = false;
protected boolean showSectionName = true;
- public SongAdapter(AppCompatActivity activity, ArrayList dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
+ public SongAdapter(AppCompatActivity activity, List dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder) {
this(activity, dataSet, itemLayoutRes, usePalette, cabHolder, true);
}
- public SongAdapter(AppCompatActivity activity, ArrayList dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder, boolean showSectionName) {
+ public SongAdapter(AppCompatActivity activity, List dataSet, @LayoutRes int itemLayoutRes, boolean usePalette, @Nullable CabHolder cabHolder, boolean showSectionName) {
super(activity, cabHolder, R.menu.menu_media_selection);
this.activity = activity;
this.dataSet = dataSet;
@@ -60,7 +61,7 @@ public SongAdapter(AppCompatActivity activity, ArrayList dataSet, @LayoutR
setHasStableIds(true);
}
- public void swapDataSet(ArrayList dataSet) {
+ public void swapDataSet(List dataSet) {
this.dataSet = dataSet;
notifyDataSetChanged();
}
@@ -70,7 +71,7 @@ public void usePalette(boolean usePalette) {
notifyDataSetChanged();
}
- public ArrayList getDataSet() {
+ public List getDataSet() {
return dataSet;
}
@@ -79,9 +80,9 @@ public long getItemId(int position) {
return dataSet.get(position).id;
}
- @NonNull
@Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ @NonNull
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false);
return createViewHolder(view);
}
@@ -158,7 +159,7 @@ protected String getSongTitle(Song song) {
}
protected String getSongText(Song song) {
- return song.artistName;
+ return MusicUtil.getSongInfoString(song);
}
@Override
@@ -177,14 +178,34 @@ protected String getName(Song song) {
}
@Override
- protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull ArrayList selection) {
+ protected void onMultipleItemAction(@NonNull MenuItem menuItem, @NonNull List selection) {
SongsMenuHelper.handleMenuClick(activity, selection, menuItem.getItemId());
}
@NonNull
@Override
public String getSectionName(int position) {
- return showSectionName ? MusicUtil.getSectionName(dataSet.get(position).title) : "";
+ if (!showSectionName) {
+ return "";
+ }
+
+ @Nullable String sectionName = null;
+ switch (PreferenceUtil.getInstance(activity).getSongSortOrder()) {
+ case SortOrder.SongSortOrder.SONG_A_Z:
+ case SortOrder.SongSortOrder.SONG_Z_A:
+ sectionName = dataSet.get(position).title;
+ break;
+ case SortOrder.SongSortOrder.SONG_ALBUM:
+ sectionName = dataSet.get(position).albumName;
+ break;
+ case SortOrder.SongSortOrder.SONG_ARTIST:
+ sectionName = dataSet.get(position).artistName;
+ break;
+ case SortOrder.SongSortOrder.SONG_YEAR:
+ return MusicUtil.getYearString(dataSet.get(position).year);
+ }
+
+ return MusicUtil.getSectionName(sectionName);
}
public class ViewHolder extends MediaEntryViewHolder {
diff --git a/app/src/main/java/com/kabouzeid/gramophone/appshortcuts/AppShortcutIconGenerator.java b/app/src/main/java/com/kabouzeid/gramophone/appshortcuts/AppShortcutIconGenerator.java
index d4ea4a34e..6eda73c5a 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/appshortcuts/AppShortcutIconGenerator.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/appshortcuts/AppShortcutIconGenerator.java
@@ -1,27 +1,26 @@
package com.kabouzeid.gramophone.appshortcuts;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
-import android.support.annotation.RequiresApi;
-import android.support.v4.graphics.drawable.IconCompat;
+import androidx.annotation.RequiresApi;
+import androidx.core.graphics.drawable.IconCompat;
import android.util.TypedValue;
import com.kabouzeid.appthemehelper.ThemeStore;
import com.kabouzeid.gramophone.R;
+import com.kabouzeid.gramophone.util.ImageUtil;
import com.kabouzeid.gramophone.util.PreferenceUtil;
-import com.kabouzeid.gramophone.util.Util;
/**
* @author Adrian Campos
*/
@RequiresApi(Build.VERSION_CODES.N_MR1)
public final class AppShortcutIconGenerator {
+
public static Icon generateThemedIcon(Context context, int iconId) {
if (PreferenceUtil.getInstance(context).coloredAppShortcuts()) {
return generateUserThemedIcon(context, iconId).toIcon();
@@ -52,26 +51,19 @@ private static IconCompat generateUserThemedIcon(Context context, int iconId) {
private static IconCompat generateThemedIcon(Context context, int iconId, int foregroundColor, int backgroundColor) {
// Get and tint foreground and background drawables
- Drawable vectorDrawable = Util.getTintedVectorDrawable(context, iconId, foregroundColor);
- Drawable backgroundDrawable = Util.getTintedVectorDrawable(context, R.drawable.ic_app_shortcut_background, backgroundColor);
+ Drawable vectorDrawable = ImageUtil.getTintedVectorDrawable(context, iconId, foregroundColor);
+ Drawable backgroundDrawable = ImageUtil.getTintedVectorDrawable(context, R.drawable.ic_app_shortcut_background, backgroundColor);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AdaptiveIconDrawable adaptiveIconDrawable = new AdaptiveIconDrawable(backgroundDrawable, vectorDrawable);
- return IconCompat.createWithAdaptiveBitmap(drawableToBitmap(adaptiveIconDrawable));
+ return IconCompat.createWithAdaptiveBitmap(ImageUtil.createBitmap(adaptiveIconDrawable));
} else {
// Squash the two drawables together
LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{backgroundDrawable, vectorDrawable});
// Return as an Icon
- return IconCompat.createWithBitmap(drawableToBitmap(layerDrawable));
+ return IconCompat.createWithBitmap(ImageUtil.createBitmap(layerDrawable));
}
}
- private static Bitmap drawableToBitmap(Drawable drawable) {
- 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;
- }
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetBig.java b/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetBig.java
index c2833facb..f13909048 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetBig.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetBig.java
@@ -7,7 +7,7 @@
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import android.text.TextUtils;
import android.view.View;
import android.widget.RemoteViews;
@@ -23,6 +23,7 @@
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.ui.activities.MainActivity;
+import com.kabouzeid.gramophone.util.ImageUtil;
import com.kabouzeid.gramophone.util.Util;
public class AppWidgetBig extends BaseAppWidget {
@@ -47,9 +48,9 @@ protected void defaultAppWidget(final Context context, final int[] appWidgetIds)
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art);
- appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(Util.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getPrimaryTextColor(context, false)), 1f));
- appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(Util.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getPrimaryTextColor(context, false)), 1f));
- appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(Util.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, MaterialValueHelper.getPrimaryTextColor(context, false)), 1f));
+ appWidgetView.setImageViewBitmap(R.id.button_next, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getPrimaryTextColor(context, false))));
+ appWidgetView.setImageViewBitmap(R.id.button_prev, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getPrimaryTextColor(context, false))));
+ appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, MaterialValueHelper.getPrimaryTextColor(context, false))));
linkButtons(context, appWidgetView);
pushUpdate(context, appWidgetIds, appWidgetView);
@@ -75,11 +76,11 @@ public void performUpdate(final MusicService service, final int[] appWidgetIds)
// Set correct drawable for pause state
int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp;
- appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(Util.getTintedVectorDrawable(service, playPauseRes, MaterialValueHelper.getPrimaryTextColor(service, false)), 1f));
+ appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, playPauseRes, MaterialValueHelper.getPrimaryTextColor(service, false))));
// Set prev/next button drawables
- appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(Util.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getPrimaryTextColor(service, false)), 1f));
- appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(Util.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getPrimaryTextColor(service, false)), 1f));
+ appWidgetView.setImageViewBitmap(R.id.button_next, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getPrimaryTextColor(service, false))));
+ appWidgetView.setImageViewBitmap(R.id.button_prev, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getPrimaryTextColor(service, false))));
// Link actions buttons to intents
linkButtons(service, appWidgetView);
diff --git a/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetCard.java b/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetCard.java
index e8bd183fd..2deba464c 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetCard.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetCard.java
@@ -6,8 +6,8 @@
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
-import android.support.annotation.Nullable;
-import android.support.v7.graphics.Palette;
+import androidx.annotation.Nullable;
+import androidx.palette.graphics.Palette;
import android.text.TextUtils;
import android.view.View;
import android.widget.RemoteViews;
@@ -24,7 +24,7 @@
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.ui.activities.MainActivity;
-import com.kabouzeid.gramophone.util.Util;
+import com.kabouzeid.gramophone.util.ImageUtil;
public class AppWidgetCard extends BaseAppWidget {
public static final String NAME = "app_widget_card";
@@ -50,9 +50,9 @@ protected void defaultAppWidget(final Context context, final int[] appWidgetIds)
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art);
- appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(Util.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
- appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(Util.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
- appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(Util.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
+ appWidgetView.setImageViewBitmap(R.id.button_next, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true))));
+ appWidgetView.setImageViewBitmap(R.id.button_prev, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true))));
+ appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true))));
linkButtons(context, appWidgetView);
pushUpdate(context, appWidgetIds, appWidgetView);
@@ -78,11 +78,11 @@ public void performUpdate(final MusicService service, final int[] appWidgetIds)
// Set correct drawable for pause state
int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp;
- appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(Util.getTintedVectorDrawable(service, playPauseRes, MaterialValueHelper.getSecondaryTextColor(service, true)), 1f));
+ appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, playPauseRes, MaterialValueHelper.getSecondaryTextColor(service, true))));
// Set prev/next button drawables
- appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(Util.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getSecondaryTextColor(service, true)), 1f));
- appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(Util.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getSecondaryTextColor(service, true)), 1f));
+ appWidgetView.setImageViewBitmap(R.id.button_next, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getSecondaryTextColor(service, true))));
+ appWidgetView.setImageViewBitmap(R.id.button_prev, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getSecondaryTextColor(service, true))));
// Link actions buttons to intents
linkButtons(service, appWidgetView);
@@ -119,11 +119,11 @@ public void onLoadFailed(Exception e, Drawable errorDrawable) {
private void update(@Nullable Bitmap bitmap, int color) {
// Set correct drawable for pause state
int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp;
- appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(Util.getTintedVectorDrawable(service, playPauseRes, color), 1f));
+ appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, playPauseRes, color)));
// Set prev/next button drawables
- appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(Util.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, color), 1f));
- appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(Util.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, color), 1f));
+ appWidgetView.setImageViewBitmap(R.id.button_next, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, color)));
+ appWidgetView.setImageViewBitmap(R.id.button_prev, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, color)));
final Drawable image = getAlbumArtDrawable(service.getResources(), bitmap);
final Bitmap roundedBitmap = createRoundedBitmap(image, imageSize, imageSize, cardRadius, 0, cardRadius, 0);
diff --git a/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetClassic.java b/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetClassic.java
index 4412485e0..e99e517ad 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetClassic.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetClassic.java
@@ -6,8 +6,8 @@
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
-import android.support.annotation.Nullable;
-import android.support.v7.graphics.Palette;
+import androidx.annotation.Nullable;
+import androidx.palette.graphics.Palette;
import android.text.TextUtils;
import android.view.View;
import android.widget.RemoteViews;
@@ -24,7 +24,7 @@
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.ui.activities.MainActivity;
-import com.kabouzeid.gramophone.util.Util;
+import com.kabouzeid.gramophone.util.ImageUtil;
public class AppWidgetClassic extends BaseAppWidget {
public static final String NAME = "app_widget_classic";
@@ -50,9 +50,9 @@ protected void defaultAppWidget(final Context context, final int[] appWidgetIds)
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art);
- appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(Util.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
- appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(Util.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
- appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(Util.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
+ appWidgetView.setImageViewBitmap(R.id.button_next, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true))));
+ appWidgetView.setImageViewBitmap(R.id.button_prev, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true))));
+ appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true))));
linkButtons(context, appWidgetView);
pushUpdate(context, appWidgetIds, appWidgetView);
@@ -112,11 +112,11 @@ public void onLoadFailed(Exception e, Drawable errorDrawable) {
private void update(@Nullable Bitmap bitmap, int color) {
// Set correct drawable for pause state
int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp;
- appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(Util.getTintedVectorDrawable(service, playPauseRes, color), 1f));
+ appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, playPauseRes, color)));
// Set prev/next button drawables
- appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(Util.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, color), 1f));
- appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(Util.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, color), 1f));
+ appWidgetView.setImageViewBitmap(R.id.button_next, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, color)));
+ appWidgetView.setImageViewBitmap(R.id.button_prev, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, color)));
final Drawable image = getAlbumArtDrawable(service.getResources(), bitmap);
final Bitmap roundedBitmap = createRoundedBitmap(image, imageSize, imageSize, cardRadius, 0, cardRadius, 0);
diff --git a/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetSmall.java b/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetSmall.java
index 7d63c6ffa..e5d2011fd 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetSmall.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/appwidgets/AppWidgetSmall.java
@@ -6,8 +6,8 @@
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
-import android.support.annotation.Nullable;
-import android.support.v7.graphics.Palette;
+import androidx.annotation.Nullable;
+import androidx.palette.graphics.Palette;
import android.text.TextUtils;
import android.view.View;
import android.widget.RemoteViews;
@@ -24,7 +24,7 @@
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.ui.activities.MainActivity;
-import com.kabouzeid.gramophone.util.Util;
+import com.kabouzeid.gramophone.util.ImageUtil;
public class AppWidgetSmall extends BaseAppWidget {
public static final String NAME = "app_widget_small";
@@ -50,9 +50,9 @@ protected void defaultAppWidget(final Context context, final int[] appWidgetIds)
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE);
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art);
- appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(Util.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
- appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(Util.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
- appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(Util.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true)), 1f));
+ appWidgetView.setImageViewBitmap(R.id.button_next, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true))));
+ appWidgetView.setImageViewBitmap(R.id.button_prev, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true))));
+ appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true))));
linkButtons(context, appWidgetView);
pushUpdate(context, appWidgetIds, appWidgetView);
@@ -118,11 +118,11 @@ public void onLoadFailed(Exception e, Drawable errorDrawable) {
private void update(@Nullable Bitmap bitmap, int color) {
// Set correct drawable for pause state
int playPauseRes = isPlaying ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp;
- appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, createBitmap(Util.getTintedVectorDrawable(service, playPauseRes, color), 1f));
+ appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, playPauseRes, color)));
// Set prev/next button drawables
- appWidgetView.setImageViewBitmap(R.id.button_next, createBitmap(Util.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, color), 1f));
- appWidgetView.setImageViewBitmap(R.id.button_prev, createBitmap(Util.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, color), 1f));
+ appWidgetView.setImageViewBitmap(R.id.button_next, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, color)));
+ appWidgetView.setImageViewBitmap(R.id.button_prev, ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, color)));
final Drawable image = getAlbumArtDrawable(service.getResources(), bitmap);
final Bitmap roundedBitmap = createRoundedBitmap(image, imageSize, imageSize, cardRadius, 0, 0, 0);
diff --git a/app/src/main/java/com/kabouzeid/gramophone/appwidgets/base/BaseAppWidget.java b/app/src/main/java/com/kabouzeid/gramophone/appwidgets/base/BaseAppWidget.java
index 8ea1a3458..e54b73521 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/appwidgets/base/BaseAppWidget.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/appwidgets/base/BaseAppWidget.java
@@ -16,12 +16,12 @@
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
-import android.text.TextUtils;
import android.widget.RemoteViews;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService;
+import com.kabouzeid.gramophone.util.MusicUtil;
public abstract class BaseAppWidget extends AppWidgetProvider {
public static final String NAME = "app_widget";
@@ -82,14 +82,6 @@ protected PendingIntent buildPendingIntent(Context context, final String action,
}
}
- protected 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;
- }
-
protected static Bitmap createRoundedBitmap(Drawable drawable, int width, int height, float tl, float tr, float bl, float br) {
if (drawable == null) return null;
@@ -145,12 +137,6 @@ protected Drawable getAlbumArtDrawable(final Resources resources, final Bitmap b
}
protected String getSongArtistAndAlbum(final Song song) {
- final StringBuilder builder = new StringBuilder();
- builder.append(song.artistName);
- if (!TextUtils.isEmpty(song.artistName) && !TextUtils.isEmpty(song.albumName)) {
- builder.append(" • ");
- }
- builder.append(song.albumName);
- return builder.toString();
+ return MusicUtil.getSongInfoString(song);
}
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/AddToPlaylistDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/AddToPlaylistDialog.java
index 92af5db2d..4bfc227eb 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/AddToPlaylistDialog.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/AddToPlaylistDialog.java
@@ -2,9 +2,8 @@
import android.app.Dialog;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
-import android.view.View;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
import com.afollestad.materialdialogs.MaterialDialog;
import com.kabouzeid.gramophone.R;
@@ -24,16 +23,16 @@ public class AddToPlaylistDialog extends DialogFragment {
@NonNull
public static AddToPlaylistDialog create(Song song) {
- ArrayList list = new ArrayList<>();
+ List list = new ArrayList<>();
list.add(song);
return create(list);
}
@NonNull
- public static AddToPlaylistDialog create(ArrayList songs) {
+ public static AddToPlaylistDialog create(List songs) {
AddToPlaylistDialog dialog = new AddToPlaylistDialog();
Bundle args = new Bundle();
- args.putParcelableArrayList("songs", songs);
+ args.putParcelableArrayList("songs", new ArrayList<>(songs));
dialog.setArguments(args);
return dialog;
}
@@ -49,24 +48,41 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
}
final ArrayList songs = getArguments().getParcelableArrayList("songs");
- if(songs != null && songs.size() == 1)
+ int[] songIds = new int[songs.size()];
+ if(songs != null)
{
- //TODO: display checkboxes instead of checkmark
+ for(int i = 0; i < songs.size(); i++){
+ songIds[i] = songs.get(i).id;
+ }
+
+ for (int i = 0; i < playlists.size(); i++) {
+ int playlistId = playlists.get(i).id;
- long startTime = System.currentTimeMillis();//TEMP
+ long startTime = System.currentTimeMillis();//TODO: remove stopwatch
- Boolean[] songIsInPlaylist = new Boolean[playlists.size()];
- for(int i = 0; i < playlists.size(); i++){
- songIsInPlaylist[i] = PlaylistsUtil.doPlaylistContains(getActivity(), playlists.get(i).id, songs.get(0).id);
+ boolean isAnySongInPlaylist = PlaylistsUtil.doPlaylistContainsAnySong(getActivity(), playlistId, songIds);
+ long stopTime1 = System.currentTimeMillis();//TODO: remove stopwatch
+ boolean areAllSongsInPlaylist = PlaylistsUtil.doPlaylistContainsAllSongs(getActivity(), playlistId, songIds);
+ long stopTime2 = System.currentTimeMillis();//TODO: remove stopwatch
- //TEMP
- if(songIsInPlaylist[i]) {
- playlistNames[i + 1] = playlists.get(i).name + " \u2713";
+ //TODO: display checkboxes instead of checkmark
+ if (isAnySongInPlaylist) {
+ if(areAllSongsInPlaylist){
+ playlistNames[i + 1] = playlists.get(i).name + " \u2713"; //Add checkmark
+ }
+ else{
+ playlistNames[i + 1] = playlists.get(i).name + " (\u2713)"; //Add checkmark in brackets
+ }
}
- }
- long difference = System.currentTimeMillis() - startTime;
- long endTime = difference + startTime;
+ long stopTimeTotal = System.currentTimeMillis();//TODO: remove stopwatch
+ long Time1 = stopTime1 - startTime;
+ long Time2 = stopTime2 - stopTime1;
+ long Time3 = stopTimeTotal - stopTime2;
+ long TotalTime = stopTimeTotal - startTime;//TODO: remove stopwatch
+ int uselessAssignmentForDebugging = 7;//TODO: remove stopwatch
+ int c = uselessAssignmentForDebugging;//TODO: remove stopwatch
+ }
}
return new MaterialDialog.Builder(getActivity())
@@ -80,9 +96,9 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
CreatePlaylistDialog.create(songs).show(getActivity().getSupportFragmentManager(), "ADD_TO_PLAYLIST");
} else {
materialDialog.dismiss();
- PlaylistsUtil.addToPlaylist(getActivity(), songs, playlists.get(i - 1).id, true);
+ PlaylistsUtil.addToPlaylistWithoutDuplicates(getActivity(), songs, songIds, playlists.get(i - 1).id, true);
}
})
.build();
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/BlacklistFolderChooserDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/BlacklistFolderChooserDialog.java
index 4883e6c48..46830c5e9 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/BlacklistFolderChooserDialog.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/BlacklistFolderChooserDialog.java
@@ -6,12 +6,11 @@
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
-import android.support.annotation.NonNull;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.app.DialogFragment;
+import androidx.annotation.NonNull;
+import androidx.core.app.ActivityCompat;
+import androidx.fragment.app.DialogFragment;
import android.view.View;
-import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.kabouzeid.gramophone.R;
@@ -105,9 +104,6 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
.onNegative((materialDialog, dialogAction) -> dismiss())
.positiveText(R.string.add_action)
.negativeText(android.R.string.cancel);
- if (File.pathSeparator.equals(initialPath)) {
- canGoUp = false;
- }
return builder.build();
}
@@ -118,7 +114,7 @@ public void onSelection(MaterialDialog materialDialog, View view, int i, CharSeq
if (parentFolder.getAbsolutePath().equals("/storage/emulated")) {
parentFolder = parentFolder.getParentFile();
}
- canGoUp = parentFolder.getParent() != null;
+ checkIfCanGoUp();
} else {
parentFolder = parentContents[canGoUp ? i - 1 : i];
canGoUp = true;
@@ -130,11 +126,7 @@ public void onSelection(MaterialDialog materialDialog, View view, int i, CharSeq
}
private void checkIfCanGoUp() {
- try {
- canGoUp = parentFolder.getPath().split(File.pathSeparator).length > 1;
- } catch (IndexOutOfBoundsException e) {
- canGoUp = false;
- }
+ canGoUp = parentFolder.getParent() != null;
}
private void reload() {
diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/ChangelogDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/ChangelogDialog.java
index 34293c90f..96f24f5b7 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/ChangelogDialog.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/ChangelogDialog.java
@@ -3,13 +3,12 @@
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.View;
diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/ClearSmartPlaylistDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/ClearSmartPlaylistDialog.java
index 74b97063d..8f5017d1e 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/ClearSmartPlaylistDialog.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/ClearSmartPlaylistDialog.java
@@ -2,11 +2,10 @@
import android.app.Dialog;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
import android.text.Html;
-import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.model.smartplaylist.AbsSmartPlaylist;
@@ -47,4 +46,4 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
})
.build();
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/CreatePlaylistDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/CreatePlaylistDialog.java
index 1d2c3f046..908f5be8b 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/CreatePlaylistDialog.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/CreatePlaylistDialog.java
@@ -2,9 +2,9 @@
import android.app.Dialog;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.app.DialogFragment;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.DialogFragment;
import android.text.InputType;
import android.widget.Toast;
@@ -14,6 +14,7 @@
import com.kabouzeid.gramophone.util.PlaylistsUtil;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad)
@@ -29,17 +30,17 @@ public static CreatePlaylistDialog create() {
@NonNull
public static CreatePlaylistDialog create(@Nullable Song song) {
- ArrayList list = new ArrayList<>();
+ List list = new ArrayList<>();
if (song != null)
list.add(song);
return create(list);
}
@NonNull
- public static CreatePlaylistDialog create(ArrayList songs) {
+ public static CreatePlaylistDialog create(List songs) {
CreatePlaylistDialog dialog = new CreatePlaylistDialog();
Bundle args = new Bundle();
- args.putParcelableArrayList(SONGS, songs);
+ args.putParcelableArrayList(SONGS, new ArrayList<>(songs));
dialog.setArguments(args);
return dialog;
}
@@ -63,7 +64,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
final int playlistId = PlaylistsUtil.createPlaylist(getActivity(), name);
if (getActivity() != null) {
//noinspection unchecked
- ArrayList songs = getArguments().getParcelableArrayList(SONGS);
+ List songs = getArguments().getParcelableArrayList(SONGS);
if (songs != null && !songs.isEmpty()) {
PlaylistsUtil.addToPlaylist(getActivity(), songs, playlistId, true);
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java
index 397a5d925..3b2e21443 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java
@@ -2,17 +2,17 @@
import android.app.Dialog;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
import android.text.Html;
-import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.model.Playlist;
import com.kabouzeid.gramophone.util.PlaylistsUtil;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
@@ -21,16 +21,16 @@ public class DeletePlaylistDialog extends DialogFragment {
@NonNull
public static DeletePlaylistDialog create(Playlist playlist) {
- ArrayList list = new ArrayList<>();
+ List list = new ArrayList<>();
list.add(playlist);
return create(list);
}
@NonNull
- public static DeletePlaylistDialog create(ArrayList playlists) {
+ public static DeletePlaylistDialog create(List playlists) {
DeletePlaylistDialog dialog = new DeletePlaylistDialog();
Bundle args = new Bundle();
- args.putParcelableArrayList("playlists", playlists);
+ args.putParcelableArrayList("playlists", new ArrayList<>(playlists));
dialog.setArguments(args);
return dialog;
}
@@ -39,7 +39,7 @@ public static DeletePlaylistDialog create(ArrayList playlists) {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
//noinspection unchecked
- final ArrayList playlists = getArguments().getParcelableArrayList("playlists");
+ final List playlists = getArguments().getParcelableArrayList("playlists");
int title;
CharSequence content;
//noinspection ConstantConditions
@@ -62,4 +62,4 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
})
.build();
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java
index 602cbe80a..1dc2f482f 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java
@@ -2,17 +2,17 @@
import android.app.Dialog;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
import android.text.Html;
-import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.MusicUtil;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad)
@@ -21,16 +21,16 @@ public class DeleteSongsDialog extends DialogFragment {
@NonNull
public static DeleteSongsDialog create(Song song) {
- ArrayList list = new ArrayList<>();
+ List list = new ArrayList<>();
list.add(song);
return create(list);
}
@NonNull
- public static DeleteSongsDialog create(ArrayList songs) {
+ public static DeleteSongsDialog create(List songs) {
DeleteSongsDialog dialog = new DeleteSongsDialog();
Bundle args = new Bundle();
- args.putParcelableArrayList("songs", songs);
+ args.putParcelableArrayList("songs", new ArrayList<>(songs));
dialog.setArguments(args);
return dialog;
}
@@ -39,7 +39,7 @@ public static DeleteSongsDialog create(ArrayList songs) {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
//noinspection unchecked
- final ArrayList songs = getArguments().getParcelableArrayList("songs");
+ final List songs = getArguments().getParcelableArrayList("songs");
int title;
CharSequence content;
if (songs.size() > 1) {
@@ -61,4 +61,4 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
})
.build();
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DonationsDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DonationsDialog.java
index a1afce061..89e796e80 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DonationsDialog.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DonationsDialog.java
@@ -6,12 +6,11 @@
import android.graphics.Paint;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
import android.util.Log;
import android.view.LayoutInflater;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
@@ -62,7 +61,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
@SuppressLint("InflateParams")
View customView = LayoutInflater.from(getContext()).inflate(R.layout.dialog_donation, null);
- ProgressBar progressBar = ButterKnife.findById(customView, R.id.progress);
+ ProgressBar progressBar = customView.findViewById(R.id.progress);
MDTintHelper.setTint(progressBar, ThemeSingleton.get().positiveColor.getDefaultColor());
return new MaterialDialog.Builder(getContext())
@@ -84,7 +83,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
@Override
- public void onProductPurchased(String productId, TransactionDetails details) {
+ public void onProductPurchased(@NonNull String productId, TransactionDetails details) {
loadSkuDetails();
Toast.makeText(getContext(), R.string.thank_you, Toast.LENGTH_SHORT).show();
}
@@ -166,7 +165,7 @@ protected void onPostExecute(List skuDetails) {
View customView = ((MaterialDialog) dialog.getDialog()).getCustomView();
//noinspection ConstantConditions
customView.findViewById(R.id.progress_container).setVisibility(View.GONE);
- ListView listView = ButterKnife.findById(customView, R.id.list);
+ ListView listView = customView.findViewById(R.id.list);
listView.setAdapter(new SkuDetailsAdapter(dialog, skuDetails));
listView.setVisibility(View.VISIBLE);
}
@@ -184,7 +183,8 @@ public SkuDetailsAdapter(@NonNull DonationsDialog donationsDialog, @NonNull List
}
@Override
- public View getView(final int position, View convertView, ViewGroup parent) {
+ @NonNull
+ public View getView(final int position, View convertView, @NonNull ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(LAYOUT_RES_ID, parent, false);
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/LyricsDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/LyricsDialog.java
index ed8cc2ce8..18d6d5f07 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/LyricsDialog.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/LyricsDialog.java
@@ -2,8 +2,8 @@
import android.app.Dialog;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
import com.afollestad.materialdialogs.MaterialDialog;
import com.kabouzeid.gramophone.model.lyrics.Lyrics;
diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/RemoveFromPlaylistDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/RemoveFromPlaylistDialog.java
index 376fa5127..7c8060b05 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/RemoveFromPlaylistDialog.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/RemoveFromPlaylistDialog.java
@@ -2,17 +2,17 @@
import android.app.Dialog;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
import android.text.Html;
-import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.model.PlaylistSong;
import com.kabouzeid.gramophone.util.PlaylistsUtil;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
@@ -21,16 +21,16 @@ public class RemoveFromPlaylistDialog extends DialogFragment {
@NonNull
public static RemoveFromPlaylistDialog create(PlaylistSong song) {
- ArrayList list = new ArrayList<>();
+ List list = new ArrayList<>();
list.add(song);
return create(list);
}
@NonNull
- public static RemoveFromPlaylistDialog create(ArrayList songs) {
+ public static RemoveFromPlaylistDialog create(List songs) {
RemoveFromPlaylistDialog dialog = new RemoveFromPlaylistDialog();
Bundle args = new Bundle();
- args.putParcelableArrayList("songs", songs);
+ args.putParcelableArrayList("songs", new ArrayList<>(songs));
dialog.setArguments(args);
return dialog;
}
@@ -39,7 +39,7 @@ public static RemoveFromPlaylistDialog create(ArrayList songs) {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
//noinspection unchecked
- final ArrayList songs = getArguments().getParcelableArrayList("songs");
+ final List songs = getArguments().getParcelableArrayList("songs");
int title;
CharSequence content;
if (songs.size() > 1) {
@@ -61,4 +61,4 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
})
.build();
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/RenamePlaylistDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/RenamePlaylistDialog.java
index 340af6e10..b09887f90 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/RenamePlaylistDialog.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/RenamePlaylistDialog.java
@@ -2,8 +2,8 @@
import android.app.Dialog;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
import android.text.InputType;
import com.afollestad.materialdialogs.MaterialDialog;
diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/ScanMediaFolderChooserDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/ScanMediaFolderChooserDialog.java
new file mode 100644
index 000000000..09d5f7f98
--- /dev/null
+++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/ScanMediaFolderChooserDialog.java
@@ -0,0 +1,169 @@
+package com.kabouzeid.gramophone.dialogs;
+
+import android.Manifest;
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.media.MediaScannerConnection;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.app.ActivityCompat;
+import androidx.fragment.app.DialogFragment;
+import android.view.View;
+import android.widget.Toast;
+
+import com.afollestad.materialdialogs.MaterialDialog;
+import com.kabouzeid.gramophone.R;
+import com.kabouzeid.gramophone.misc.UpdateToastMediaScannerCompletionListener;
+import com.kabouzeid.gramophone.ui.fragments.mainactivity.folders.FoldersFragment;
+import com.kabouzeid.gramophone.util.PreferenceUtil;
+
+import java.io.File;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * @author Aidan Follestad (afollestad), modified by Karim Abou Zeid
+ */
+public class ScanMediaFolderChooserDialog extends DialogFragment implements MaterialDialog.ListCallback {
+
+ String initialPath = PreferenceUtil.getInstance(getContext()).getStartDirectory().getAbsolutePath();
+ private File parentFolder;
+ private File[] parentContents;
+ private boolean canGoUp = false;
+
+ public static ScanMediaFolderChooserDialog create() {
+ return new ScanMediaFolderChooserDialog();
+ }
+
+ private static void scanPaths(@NonNull WeakReference activityWeakReference, @NonNull Context applicationContext, @Nullable String[] toBeScanned) {
+ Activity activity = activityWeakReference.get();
+ if (toBeScanned == null || toBeScanned.length < 1) {
+ Toast.makeText(applicationContext, R.string.nothing_to_scan, Toast.LENGTH_SHORT).show();
+ } else {
+ MediaScannerConnection.scanFile(applicationContext, toBeScanned, null, activity != null ? new UpdateToastMediaScannerCompletionListener(activity, toBeScanned) : null);
+ }
+ }
+
+ private String[] getContentsArray() {
+ if (parentContents == null) {
+ if (canGoUp) {
+ return new String[]{".."};
+ }
+ return new String[]{};
+ }
+ String[] results = new String[parentContents.length + (canGoUp ? 1 : 0)];
+ if (canGoUp) {
+ results[0] = "..";
+ }
+ for (int i = 0; i < parentContents.length; i++) {
+ results[canGoUp ? i + 1 : i] = parentContents[i].getName();
+ }
+ return results;
+ }
+
+ private File[] listFiles() {
+ File[] contents = parentFolder.listFiles();
+ List results = new ArrayList<>();
+ if (contents != null) {
+ for (File fi : contents) {
+ if (fi.isDirectory()) {
+ results.add(fi);
+ }
+ }
+ Collections.sort(results, new FolderSorter());
+ return results.toArray(new File[results.size()]);
+ }
+ return null;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ && ActivityCompat.checkSelfPermission(
+ getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)
+ != PackageManager.PERMISSION_GRANTED) {
+ return new MaterialDialog.Builder(getActivity())
+ .title(R.string.md_error_label)
+ .content(R.string.md_storage_perm_error)
+ .positiveText(android.R.string.ok)
+ .build();
+ }
+ if (savedInstanceState == null) {
+ savedInstanceState = new Bundle();
+ }
+ if (!savedInstanceState.containsKey("current_path")) {
+ savedInstanceState.putString("current_path", initialPath);
+ }
+ parentFolder = new File(savedInstanceState.getString("current_path", File.pathSeparator));
+ checkIfCanGoUp();
+ parentContents = listFiles();
+ MaterialDialog.Builder builder =
+ new MaterialDialog.Builder(getActivity())
+ .title(parentFolder.getAbsolutePath())
+ .items((CharSequence[]) getContentsArray())
+ .itemsCallback(this)
+ .autoDismiss(false)
+ .onPositive((dialog, which) -> {
+ final Context applicationContext = getActivity().getApplicationContext();
+ final WeakReference activityWeakReference = new WeakReference<>(getActivity());
+ dismiss();
+ new FoldersFragment.ArrayListPathsAsyncTask(getActivity(), paths -> scanPaths(activityWeakReference, applicationContext, paths)).execute(new FoldersFragment.ArrayListPathsAsyncTask.LoadingInfo(parentFolder, FoldersFragment.AUDIO_FILE_FILTER));
+ })
+ .onNegative((materialDialog, dialogAction) -> dismiss())
+ .positiveText(R.string.action_scan_directory)
+ .negativeText(android.R.string.cancel);
+ return builder.build();
+ }
+
+ @Override
+ public void onSelection(MaterialDialog materialDialog, View view, int i, CharSequence s) {
+ if (canGoUp && i == 0) {
+ parentFolder = parentFolder.getParentFile();
+ if (parentFolder.getAbsolutePath().equals("/storage/emulated")) {
+ parentFolder = parentFolder.getParentFile();
+ }
+ checkIfCanGoUp();
+ } else {
+ parentFolder = parentContents[canGoUp ? i - 1 : i];
+ canGoUp = true;
+ if (parentFolder.getAbsolutePath().equals("/storage/emulated")) {
+ parentFolder = Environment.getExternalStorageDirectory();
+ }
+ }
+ reload();
+ }
+
+ private void checkIfCanGoUp() {
+ canGoUp = parentFolder.getParent() != null;
+ }
+
+ private void reload() {
+ parentContents = listFiles();
+ MaterialDialog dialog = (MaterialDialog) getDialog();
+ dialog.setTitle(parentFolder.getAbsolutePath());
+ dialog.setItems((CharSequence[]) getContentsArray());
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putString("current_path", parentFolder.getAbsolutePath());
+ }
+
+ private static class FolderSorter implements Comparator {
+
+ @Override
+ public int compare(File lhs, File rhs) {
+ return lhs.getName().compareTo(rhs.getName());
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/SleepTimerDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SleepTimerDialog.java
index b7d452c55..8c953e7f1 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/SleepTimerDialog.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SleepTimerDialog.java
@@ -9,8 +9,9 @@
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.SystemClock;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
+import android.widget.CheckBox;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
@@ -20,6 +21,7 @@
import com.afollestad.materialdialogs.internal.ThemeSingleton;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
+import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.ui.activities.PurchaseActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
@@ -37,6 +39,8 @@ public class SleepTimerDialog extends DialogFragment {
SeekArc seekArc;
@BindView(R.id.timer_display)
TextView timerDisplay;
+ @BindView(R.id.should_finish_last_song)
+ CheckBox shouldFinishLastSong;
private int seekArcProgress;
private MaterialDialog materialDialog;
@@ -65,6 +69,8 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
return;
}
+ PreferenceUtil.getInstance(getActivity()).setSleepTimerFinishMusic(shouldFinishLastSong.isChecked());
+
final int minutes = seekArcProgress;
PendingIntent pi = makeTimerPendingIntent(PendingIntent.FLAG_CANCEL_CURRENT);
@@ -87,6 +93,12 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
previous.cancel();
Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_canceled), Toast.LENGTH_SHORT).show();
}
+
+ MusicService musicService = MusicPlayerRemote.musicService;
+ if (musicService != null && musicService.pendingQuit) {
+ musicService.pendingQuit = false;
+ Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_canceled), Toast.LENGTH_SHORT).show();
+ }
})
.showListener(dialog -> {
if (makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE) != null) {
@@ -102,6 +114,9 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
ButterKnife.bind(this, materialDialog.getCustomView());
+ boolean finishMusic = PreferenceUtil.getInstance(getActivity()).getSleepTimerFinishMusic();
+ shouldFinishLastSong.setChecked(finishMusic);
+
seekArc.setProgressColor(ThemeSingleton.get().positiveColor.getDefaultColor());
seekArc.setThumbColor(ThemeSingleton.get().positiveColor.getDefaultColor());
@@ -153,8 +168,20 @@ private PendingIntent makeTimerPendingIntent(int flag) {
}
private Intent makeTimerIntent() {
- return new Intent(getActivity(), MusicService.class)
- .setAction(MusicService.ACTION_QUIT);
+ Intent intent = new Intent(getActivity(), MusicService.class);
+ if (shouldFinishLastSong.isChecked()) {
+ return intent.setAction(MusicService.ACTION_PENDING_QUIT);
+ }
+ return intent.setAction(MusicService.ACTION_QUIT);
+ }
+
+ private void updateCancelButton() {
+ MusicService musicService = MusicPlayerRemote.musicService;
+ if (musicService != null && musicService.pendingQuit) {
+ materialDialog.setActionButton(DialogAction.NEUTRAL, materialDialog.getContext().getString(R.string.cancel_current_timer));
+ } else {
+ materialDialog.setActionButton(DialogAction.NEUTRAL, null);
+ }
}
private class TimerUpdater extends CountDownTimer {
@@ -169,7 +196,7 @@ public void onTick(long millisUntilFinished) {
@Override
public void onFinish() {
- materialDialog.setActionButton(DialogAction.NEUTRAL, null);
+ updateCancelButton();
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/SongDetailDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SongDetailDialog.java
index f01afdb5b..8416e3a85 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/SongDetailDialog.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SongDetailDialog.java
@@ -4,8 +4,8 @@
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
import android.text.Html;
import android.text.Spanned;
import android.util.Log;
@@ -83,25 +83,32 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
bitRate.setText(makeTextWithTitle(context, R.string.label_bit_rate, "-"));
samplingRate.setText(makeTextWithTitle(context, R.string.label_sampling_rate, "-"));
- try {
- if (song != null) {
- final File songFile = new File(song.data);
- if (songFile.exists()) {
+ if (song != null) {
+ final File songFile = new File(song.data);
+ if (songFile.exists()) {
+ fileName.setText(makeTextWithTitle(context, R.string.label_file_name, songFile.getName()));
+ filePath.setText(makeTextWithTitle(context, R.string.label_file_path, songFile.getAbsolutePath()));
+ fileSize.setText(makeTextWithTitle(context, R.string.label_file_size, getFileSizeString(songFile.length())));
+ try {
AudioFile audioFile = AudioFileIO.read(songFile);
AudioHeader audioHeader = audioFile.getAudioHeader();
- fileName.setText(makeTextWithTitle(context, R.string.label_file_name, songFile.getName()));
- filePath.setText(makeTextWithTitle(context, R.string.label_file_path, songFile.getAbsolutePath()));
- fileSize.setText(makeTextWithTitle(context, R.string.label_file_size, getFileSizeString(songFile.length())));
fileFormat.setText(makeTextWithTitle(context, R.string.label_file_format, audioHeader.getFormat()));
trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(audioHeader.getTrackLength() * 1000)));
bitRate.setText(makeTextWithTitle(context, R.string.label_bit_rate, audioHeader.getBitRate() + " kb/s"));
samplingRate.setText(makeTextWithTitle(context, R.string.label_sampling_rate, audioHeader.getSampleRate() + " Hz"));
+ } catch (@NonNull CannotReadException | IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
+ Log.e(TAG, "error while reading the song file", e);
+ // fallback
+ trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(song.duration)));
}
+ } else {
+ // fallback
+ fileName.setText(makeTextWithTitle(context, R.string.label_file_name, song.title));
+ trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(song.duration)));
}
- } catch (@NonNull CannotReadException | IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
- Log.e(TAG, "error while reading the song file", e);
}
+
return dialog;
}
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/SongShareDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SongShareDialog.java
index daad6fc6c..3b904507e 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/SongShareDialog.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SongShareDialog.java
@@ -3,9 +3,8 @@
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
-import android.view.View;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
import com.afollestad.materialdialogs.MaterialDialog;
import com.kabouzeid.gramophone.R;
diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/ArtistGlideRequest.java b/app/src/main/java/com/kabouzeid/gramophone/glide/ArtistGlideRequest.java
index 73e9efd55..098d481cb 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/glide/ArtistGlideRequest.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/glide/ArtistGlideRequest.java
@@ -2,7 +2,10 @@
import android.content.Context;
import android.graphics.Bitmap;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
import com.bumptech.glide.BitmapRequestBuilder;
import com.bumptech.glide.DrawableRequestBuilder;
@@ -15,10 +18,13 @@
import com.bumptech.glide.request.target.Target;
import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
+import com.kabouzeid.gramophone.glide.artistimage.AlbumCover;
import com.kabouzeid.gramophone.glide.artistimage.ArtistImage;
import com.kabouzeid.gramophone.glide.palette.BitmapPaletteTranscoder;
import com.kabouzeid.gramophone.glide.palette.BitmapPaletteWrapper;
+import com.kabouzeid.gramophone.model.Album;
import com.kabouzeid.gramophone.model.Artist;
+import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.ArtistSignatureUtil;
import com.kabouzeid.gramophone.util.CustomArtistImageUtil;
@@ -27,7 +33,7 @@
*/
public class ArtistGlideRequest {
- private static final DiskCacheStrategy DEFAULT_DISK_CACHE_STRATEGY = DiskCacheStrategy.SOURCE;
+ private static final DiskCacheStrategy DEFAULT_DISK_CACHE_STRATEGY = DiskCacheStrategy.ALL;
private static final int DEFAULT_ERROR_IMAGE = R.drawable.default_artist_image;
public static final int DEFAULT_ANIMATION = android.R.anim.fade_in;
@@ -35,7 +41,6 @@ public static class Builder {
final RequestManager requestManager;
final Artist artist;
boolean noCustomImage;
- boolean forceDownload;
public static Builder from(@NonNull RequestManager requestManager, Artist artist) {
return new Builder(requestManager, artist);
@@ -59,14 +64,9 @@ public Builder noCustomImage(boolean noCustomImage) {
return this;
}
- public Builder forceDownload(boolean forceDownload) {
- this.forceDownload = forceDownload;
- return this;
- }
-
public DrawableRequestBuilder build() {
//noinspection unchecked
- return createBaseRequest(requestManager, artist, noCustomImage, forceDownload)
+ return createBaseRequest(requestManager, artist, noCustomImage)
.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
.error(DEFAULT_ERROR_IMAGE)
.animate(DEFAULT_ANIMATION)
@@ -85,7 +85,7 @@ public BitmapBuilder(Builder builder) {
public BitmapRequestBuilder, Bitmap> build() {
//noinspection unchecked
- return createBaseRequest(builder.requestManager, builder.artist, builder.noCustomImage, builder.forceDownload)
+ return createBaseRequest(builder.requestManager, builder.artist, builder.noCustomImage)
.asBitmap()
.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
.error(DEFAULT_ERROR_IMAGE)
@@ -107,7 +107,7 @@ public PaletteBuilder(Builder builder, Context context) {
public BitmapRequestBuilder, BitmapPaletteWrapper> build() {
//noinspection unchecked
- return createBaseRequest(builder.requestManager, builder.artist, builder.noCustomImage, builder.forceDownload)
+ return createBaseRequest(builder.requestManager, builder.artist, builder.noCustomImage)
.asBitmap()
.transcode(new BitmapPaletteTranscoder(context), BitmapPaletteWrapper.class)
.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
@@ -119,16 +119,21 @@ public BitmapRequestBuilder, BitmapPaletteWrapper> build() {
}
}
- public static DrawableTypeRequest createBaseRequest(RequestManager requestManager, Artist artist, boolean noCustomImage, boolean forceDownload) {
+ public static DrawableTypeRequest createBaseRequest(RequestManager requestManager, Artist artist, boolean noCustomImage) {
boolean hasCustomImage = CustomArtistImageUtil.getInstance(App.getInstance()).hasCustomArtistImage(artist);
if (noCustomImage || !hasCustomImage) {
- return requestManager.load(new ArtistImage(artist.getName(), forceDownload));
+ final List songs = new ArrayList<>();
+ for (final Album album : artist.albums) {
+ final Song song = album.safeGetFirstSong();
+ songs.add(new AlbumCover(album.getYear(), song.data));
+ }
+ return requestManager.load(new ArtistImage(artist.getName(), songs));
} else {
return requestManager.load(CustomArtistImageUtil.getFile(artist));
}
}
- public static Key createSignature(Artist artist) {
+ private static Key createSignature(Artist artist) {
return ArtistSignatureUtil.getInstance(App.getInstance()).getArtistSignature(artist.getName());
}
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/BlurTransformation.java b/app/src/main/java/com/kabouzeid/gramophone/glide/BlurTransformation.java
index 403e26e2b..66f5fde9c 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/glide/BlurTransformation.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/glide/BlurTransformation.java
@@ -10,8 +10,8 @@
import android.renderscript.RSRuntimeException;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
-import android.support.annotation.FloatRange;
-import android.support.annotation.NonNull;
+import androidx.annotation.FloatRange;
+import androidx.annotation.NonNull;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/PhonographGlideModule.java b/app/src/main/java/com/kabouzeid/gramophone/glide/PhonographGlideModule.java
index 5feb54eb1..407c28e0e 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/glide/PhonographGlideModule.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/glide/PhonographGlideModule.java
@@ -2,6 +2,8 @@
import android.content.Context;
+import java.io.InputStream;
+
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.module.GlideModule;
@@ -10,8 +12,6 @@
import com.kabouzeid.gramophone.glide.audiocover.AudioFileCover;
import com.kabouzeid.gramophone.glide.audiocover.AudioFileCoverLoader;
-import java.io.InputStream;
-
/**
* @author Karim Abou Zeid (kabouzeid)
*/
@@ -24,6 +24,6 @@ public void applyOptions(Context context, GlideBuilder builder) {
@Override
public void registerComponents(Context context, Glide glide) {
glide.register(AudioFileCover.class, InputStream.class, new AudioFileCoverLoader.Factory());
- glide.register(ArtistImage.class, InputStream.class, new ArtistImageLoader.Factory(context));
+ glide.register(ArtistImage.class, InputStream.class, new ArtistImageLoader.Factory());
}
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/SongGlideRequest.java b/app/src/main/java/com/kabouzeid/gramophone/glide/SongGlideRequest.java
index 27fe2b0e1..dad073b21 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/glide/SongGlideRequest.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/glide/SongGlideRequest.java
@@ -2,7 +2,7 @@
import android.content.Context;
import android.graphics.Bitmap;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import com.bumptech.glide.BitmapRequestBuilder;
import com.bumptech.glide.DrawableRequestBuilder;
diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/AlbumCover.java b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/AlbumCover.java
new file mode 100644
index 000000000..9f026078e
--- /dev/null
+++ b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/AlbumCover.java
@@ -0,0 +1,37 @@
+package com.kabouzeid.gramophone.glide.artistimage;
+
+/**
+ * Used to define the artist cover
+ */
+public class AlbumCover {
+
+ private int year;
+
+ private String filePath;
+
+ public AlbumCover(int year, String filePath) {
+
+ this.filePath = filePath;
+ this.year = year;
+ }
+
+ public int getYear() {
+
+ return year;
+ }
+
+ public void setYear(int year) {
+
+ this.year = year;
+ }
+
+ public String getFilePath() {
+
+ return filePath;
+ }
+
+ public void setFilePath(String filePath) {
+
+ this.filePath = filePath;
+ }
+}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImage.java b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImage.java
index 4c3803bb6..7dc3daf37 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImage.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImage.java
@@ -1,14 +1,27 @@
package com.kabouzeid.gramophone.glide.artistimage;
+import java.util.List;
+
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class ArtistImage {
public final String artistName;
- public final boolean skipOkHttpCache;
- public ArtistImage(String artistName, boolean skipOkHttpCache) {
+ // filePath to get the image of the artist
+ public final List albumCovers;
+
+ public ArtistImage(String artistName, final List albumCovers) {
+
this.artistName = artistName;
- this.skipOkHttpCache = skipOkHttpCache;
+ this.albumCovers = albumCovers;
+ }
+
+ public String toIdString() {
+ StringBuilder id = new StringBuilder(artistName);
+ for (AlbumCover albumCover: albumCovers) {
+ id.append(albumCover.getYear()).append(albumCover.getFilePath());
+ }
+ return id.toString();
}
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageFetcher.java b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageFetcher.java
index 1a49230fc..2cba8cee7 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageFetcher.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageFetcher.java
@@ -1,84 +1,175 @@
package com.kabouzeid.gramophone.glide.artistimage;
-import android.content.Context;
-
-import com.bumptech.glide.Priority;
-import com.bumptech.glide.load.data.DataFetcher;
-import com.bumptech.glide.load.model.GlideUrl;
-import com.bumptech.glide.load.model.ModelLoader;
-import com.kabouzeid.gramophone.lastfm.rest.LastFMRestClient;
-import com.kabouzeid.gramophone.lastfm.rest.model.LastFmArtist;
-import com.kabouzeid.gramophone.util.LastFMUtil;
-import com.kabouzeid.gramophone.util.MusicUtil;
-import com.kabouzeid.gramophone.util.Util;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.media.MediaMetadataRetriever;
+import android.util.Log;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
-import retrofit2.Response;
+import com.bumptech.glide.Priority;
+import com.bumptech.glide.load.data.DataFetcher;
+import com.kabouzeid.gramophone.glide.audiocover.AudioFileCoverUtils;
+import com.kabouzeid.gramophone.util.ImageUtil;
+import com.kabouzeid.gramophone.util.PreferenceUtil;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class ArtistImageFetcher implements DataFetcher {
- public static final String TAG = ArtistImageFetcher.class.getSimpleName();
- private Context context;
- private final LastFMRestClient lastFMRestClient;
+
private final ArtistImage model;
- private ModelLoader urlLoader;
- private final int width;
- private final int height;
- private volatile boolean isCancelled;
- private DataFetcher urlFetcher;
-
- public ArtistImageFetcher(Context context, LastFMRestClient lastFMRestClient, ArtistImage model, ModelLoader urlLoader, int width, int height) {
- this.context = context;
- this.lastFMRestClient = lastFMRestClient;
+
+ private InputStream stream;
+
+ private boolean ignoreMediaStore;
+
+ public ArtistImageFetcher(final ArtistImage model, boolean ignoreMediaStore) {
this.model = model;
- this.urlLoader = urlLoader;
- this.width = width;
- this.height = height;
+ this.ignoreMediaStore = ignoreMediaStore;
}
@Override
public String getId() {
- // makes sure we never ever return null here
- return String.valueOf(model.artistName);
+ Log.d("MOSAIC", "get id for" + model.artistName);
+ // never return NULL here!
+ // this id is used to determine whether the image is already cached
+ // we use the artist name as well as the album years + file paths
+ return model.toIdString() + "ignoremediastore:" + ignoreMediaStore;
}
@Override
public InputStream loadData(Priority priority) throws Exception {
- if (!MusicUtil.isArtistNameUnknown(model.artistName) && Util.isAllowedToDownloadMetadata(context)) {
- Response response = lastFMRestClient.getApiService().getArtistInfo(model.artistName, null, model.skipOkHttpCache ? "no-cache" : null).execute();
+ Log.d("MOSAIC", "load data for" + model.artistName);
+ return stream = getMosaic(model.albumCovers);
+ }
+
+ private InputStream getMosaic(final List albumCovers) throws FileNotFoundException {
+
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+
+ int artistBitMapSize = 512;
+
+ final Map images = new HashMap<>();
+
+ InputStream result = null;
+ List streams = new ArrayList<>();
+
+ try {
+ for (final AlbumCover cover : albumCovers) {
+ byte[] picture = null;
+ if (!ignoreMediaStore) {
+ retriever.setDataSource(cover.getFilePath());
+ picture = retriever.getEmbeddedPicture();
+ }
+ final InputStream stream;
+ if (picture != null) {
+ stream = new ByteArrayInputStream(picture);
+ } else {
+ stream = AudioFileCoverUtils.fallback(cover.getFilePath());
+ }
- if (!response.isSuccessful()) {
- throw new IOException("Request failed with code: " + response.code());
+ if (stream != null) {
+ images.put(stream, cover.getYear());
+ }
}
- LastFmArtist lastFmArtist = response.body();
+ int nbImages = images.size();
- if (isCancelled) return null;
+ if (nbImages > 3) {
+ streams = new ArrayList<>(images.keySet());
- GlideUrl url = new GlideUrl(LastFMUtil.getLargestArtistImageUrl(lastFmArtist.getArtist().getImage()));
- urlFetcher = urlLoader.getResourceFetcher(url, width, height);
+ int divisor = 1;
+ for (int i = 1; i < nbImages && Math.pow(i, 2) <= nbImages; ++i) {
+ divisor = i;
+ }
+ divisor += 1;
+ double nbTiles = Math.pow(divisor, 2);
+
+ if (nbImages < nbTiles) {
+ divisor -= 1;
+ nbTiles = Math.pow(divisor, 2);
+ }
+ final int resize = (artistBitMapSize / divisor) + 1;
+
+ final Bitmap bitmap = Bitmap.createBitmap(artistBitMapSize, artistBitMapSize, Bitmap.Config.RGB_565);
+ final Canvas canvas = new Canvas(bitmap);
+
+ int x = 0;
+ int y = 0;
+
+ for (int i = 0; i < streams.size() && i < nbTiles; ++i) {
+ final Bitmap bitmap1 = ImageUtil.resize(streams.get(i), resize, resize);
+ canvas.drawBitmap(bitmap1, x, y, null);
+ x += resize;
+
+ if (x >= artistBitMapSize) {
+ x = 0;
+ y += resize;
+ }
+ }
+
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);
+ result = new ByteArrayInputStream(bos.toByteArray());
+
+ } else if (nbImages > 0) {
+ // we return the last cover album of the artist
+ Map.Entry maxEntryYear = null;
+
+ for (final Map.Entry entry : images.entrySet()) {
+ if (maxEntryYear == null || entry.getValue()
+ .compareTo(maxEntryYear.getValue()) > 0) {
+ maxEntryYear = entry;
+ }
+ }
+
+ if (maxEntryYear != null) {
+ result = maxEntryYear.getKey();
+ } else {
+ result = images.entrySet()
+ .iterator()
+ .next()
+ .getKey();
+ }
+
+ }
+ } finally {
+ retriever.release();
+ try {
+ for (final InputStream stream : streams) {
+ stream.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
- return urlFetcher.loadData(priority);
}
- return null;
+ return result;
}
@Override
public void cleanup() {
- if (urlFetcher != null) {
- urlFetcher.cleanup();
+ // already cleaned up in loadData and ByteArrayInputStream will be GC'd
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException ignore) {
+ // can't do much about it
+ }
}
}
@Override
public void cancel() {
- isCancelled = true;
- if (urlFetcher != null) {
- urlFetcher.cancel();
- }
+
}
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageLoader.java b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageLoader.java
index f0f4b972c..ea6008031 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageLoader.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/glide/artistimage/ArtistImageLoader.java
@@ -2,68 +2,42 @@
import android.content.Context;
-import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
+import java.io.InputStream;
+
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.GenericLoaderFactory;
-import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.ModelLoader;
import com.bumptech.glide.load.model.ModelLoaderFactory;
import com.bumptech.glide.load.model.stream.StreamModelLoader;
-import com.kabouzeid.gramophone.lastfm.rest.LastFMRestClient;
-
-import java.io.InputStream;
-import java.util.concurrent.TimeUnit;
-
-import okhttp3.OkHttpClient;
+import com.kabouzeid.gramophone.util.PreferenceUtil;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class ArtistImageLoader implements StreamModelLoader {
- // we need these very low values to make sure our artist image loading calls doesn't block the image loading queue
- private static final int TIMEOUT = 500;
-
private Context context;
- private LastFMRestClient lastFMClient;
- private ModelLoader urlLoader;
- public ArtistImageLoader(Context context, LastFMRestClient lastFMRestClient, ModelLoader urlLoader) {
+ public ArtistImageLoader(Context context) {
this.context = context;
- this.lastFMClient = lastFMRestClient;
- this.urlLoader = urlLoader;
}
@Override
- public DataFetcher getResourceFetcher(ArtistImage model, int width, int height) {
- return new ArtistImageFetcher(context, lastFMClient, model, urlLoader, width, height);
+ public DataFetcher getResourceFetcher(final ArtistImage model, int width, int height) {
+
+ return new ArtistImageFetcher(model, PreferenceUtil.getInstance(context).ignoreMediaStoreArtwork());
}
public static class Factory implements ModelLoaderFactory {
- private LastFMRestClient lastFMClient;
- private OkHttpUrlLoader.Factory okHttpFactory;
-
- public Factory(Context context) {
- okHttpFactory = new OkHttpUrlLoader.Factory(new OkHttpClient.Builder()
- .connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
- .readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
- .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
- .build());
- lastFMClient = new LastFMRestClient(LastFMRestClient.createDefaultOkHttpClientBuilder(context)
- .connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
- .readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
- .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
- .build());
- }
@Override
public ModelLoader build(Context context, GenericLoaderFactory factories) {
- return new ArtistImageLoader(context, lastFMClient, okHttpFactory.build(context, factories));
+ return new ArtistImageLoader(context);
}
@Override
public void teardown() {
- okHttpFactory.teardown();
+
}
}
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/audiocover/AudioFileCoverFetcher.java b/app/src/main/java/com/kabouzeid/gramophone/glide/audiocover/AudioFileCoverFetcher.java
index e97cbc29c..e1deb6aab 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/glide/audiocover/AudioFileCoverFetcher.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/glide/audiocover/AudioFileCoverFetcher.java
@@ -2,24 +2,23 @@
import android.media.MediaMetadataRetriever;
-import com.bumptech.glide.Priority;
-import com.bumptech.glide.load.data.DataFetcher;
-
import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import com.bumptech.glide.Priority;
+import com.bumptech.glide.load.data.DataFetcher;
+
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class AudioFileCoverFetcher implements DataFetcher {
private final AudioFileCover model;
- private FileInputStream stream;
+
+ private InputStream stream;
public AudioFileCoverFetcher(AudioFileCover model) {
+
this.model = model;
}
@@ -30,32 +29,22 @@ public String getId() {
}
@Override
- public InputStream loadData(Priority priority) throws Exception {
- MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ public InputStream loadData(final Priority priority) throws Exception {
+
+ final MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
retriever.setDataSource(model.filePath);
byte[] picture = retriever.getEmbeddedPicture();
if (picture != null) {
- return new ByteArrayInputStream(picture);
+ stream = new ByteArrayInputStream(picture);
} else {
- return fallback(model.filePath);
+ stream = AudioFileCoverUtils.fallback(model.filePath);
}
} finally {
retriever.release();
}
- }
- private static final String[] FALLBACKS = {"cover.jpg", "album.jpg", "folder.jpg"};
-
- private InputStream fallback(String path) throws FileNotFoundException {
- File parent = new File(path).getParentFile();
- for (String fallback : FALLBACKS) {
- File cover = new File(parent, fallback);
- if (cover.exists()) {
- return stream = new FileInputStream(cover);
- }
- }
- return null;
+ return stream;
}
@Override
diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/audiocover/AudioFileCoverUtils.java b/app/src/main/java/com/kabouzeid/gramophone/glide/audiocover/AudioFileCoverUtils.java
new file mode 100644
index 000000000..51cbf994f
--- /dev/null
+++ b/app/src/main/java/com/kabouzeid/gramophone/glide/audiocover/AudioFileCoverUtils.java
@@ -0,0 +1,49 @@
+package com.kabouzeid.gramophone.glide.audiocover;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
+import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
+import org.jaudiotagger.audio.mp3.MP3File;
+import org.jaudiotagger.tag.TagException;
+import org.jaudiotagger.tag.images.Artwork;
+
+public class AudioFileCoverUtils {
+
+ public static final String[] FALLBACKS = {"cover.jpg", "album.jpg", "folder.jpg", "cover.png", "album.png", "folder.png"};
+
+
+ public static InputStream fallback(String path) throws FileNotFoundException {
+ // Method 1: use embedded high resolution album art if there is any
+ try {
+ MP3File mp3File = new MP3File(path);
+ if (mp3File.hasID3v2Tag()) {
+ Artwork art = mp3File.getTag().getFirstArtwork();
+ if (art != null) {
+ byte[] imageData = art.getBinaryData();
+ return new ByteArrayInputStream(imageData);
+ }
+ }
+ // If there are any exceptions, we ignore them and continue to the other fallback method
+ } catch (ReadOnlyFileException ignored) {
+ } catch (InvalidAudioFrameException ignored) {
+ } catch (TagException ignored) {
+ } catch (IOException ignored) {
+ }
+
+ // Method 2: look for album art in external files
+ final File parent = new File(path).getParentFile();
+ for (String fallback : FALLBACKS) {
+ File cover = new File(parent, fallback);
+ if (cover.exists()) {
+ return new FileInputStream(cover);
+ }
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/glide/palette/BitmapPaletteWrapper.java b/app/src/main/java/com/kabouzeid/gramophone/glide/palette/BitmapPaletteWrapper.java
index 441b98e95..ff28ee08e 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/glide/palette/BitmapPaletteWrapper.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/glide/palette/BitmapPaletteWrapper.java
@@ -1,7 +1,7 @@
package com.kabouzeid.gramophone.glide.palette;
import android.graphics.Bitmap;
-import android.support.v7.graphics.Palette;
+import androidx.palette.graphics.Palette;
public class BitmapPaletteWrapper {
private final Bitmap mBitmap;
diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/M3UWriter.java b/app/src/main/java/com/kabouzeid/gramophone/helper/M3UWriter.java
index d137143e9..7c36c24cd 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/helper/M3UWriter.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/helper/M3UWriter.java
@@ -12,16 +12,16 @@
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.List;
public class M3UWriter implements M3UConstants {
- public static final String TAG = M3UWriter.class.getSimpleName();
public static File write(Context context, File dir, Playlist playlist) throws IOException {
if (!dir.exists()) //noinspection ResultOfMethodCallIgnored
dir.mkdirs();
File file = new File(dir, playlist.name.concat("." + EXTENSION));
- ArrayList extends Song> songs;
+ List extends Song> songs;
if (playlist instanceof AbsCustomPlaylist) {
songs = ((AbsCustomPlaylist) playlist).getSongs(context);
} else {
@@ -44,4 +44,4 @@ public static File write(Context context, File dir, Playlist playlist) throws IO
return file;
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java b/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java
index 6a4bdeeaa..250cef0b2 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/helper/MusicPlayerRemote.java
@@ -15,8 +15,8 @@
import android.os.IBinder;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;
@@ -24,9 +24,11 @@
import com.kabouzeid.gramophone.loader.SongLoader;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService;
+import com.kabouzeid.gramophone.util.PreferenceUtil;
import java.io.File;
import java.util.ArrayList;
+import java.util.List;
import java.util.Random;
import java.util.WeakHashMap;
@@ -173,16 +175,19 @@ public static void resumePlaying() {
/**
* Async
*/
- public static void openQueue(final ArrayList queue, final int startPosition, final boolean startPlaying) {
+ public static void openQueue(final List queue, final int startPosition, final boolean startPlaying) {
if (!tryToHandleOpenPlayingQueue(queue, startPosition, startPlaying) && musicService != null) {
musicService.openQueue(queue, startPosition, startPlaying);
+ if (!PreferenceUtil.getInstance(musicService).rememberShuffle()){
+ setShuffleMode(MusicService.SHUFFLE_MODE_NONE);
+ }
}
}
/**
* Async
*/
- public static void openAndShuffleQueue(final ArrayList queue, boolean startPlaying) {
+ public static void openAndShuffleQueue(final List queue, boolean startPlaying) {
int startPosition = 0;
if (!queue.isEmpty()) {
startPosition = new Random().nextInt(queue.size());
@@ -194,7 +199,7 @@ public static void openAndShuffleQueue(final ArrayList queue, boolean star
}
}
- private static boolean tryToHandleOpenPlayingQueue(final ArrayList queue, final int startPosition, final boolean startPlaying) {
+ private static boolean tryToHandleOpenPlayingQueue(final List queue, final int startPosition, final boolean startPlaying) {
if (getPlayingQueue() == queue) {
if (startPlaying) {
playSongAt(startPosition);
@@ -220,7 +225,7 @@ public static int getPosition() {
return -1;
}
- public static ArrayList getPlayingQueue() {
+ public static List getPlayingQueue() {
if (musicService != null) {
return musicService.getPlayingQueue();
}
@@ -298,7 +303,7 @@ public static boolean playNext(Song song) {
if (getPlayingQueue().size() > 0) {
musicService.addSong(getPosition() + 1, song);
} else {
- ArrayList queue = new ArrayList<>();
+ List queue = new ArrayList<>();
queue.add(song);
openQueue(queue, 0, false);
}
@@ -308,7 +313,7 @@ public static boolean playNext(Song song) {
return false;
}
- public static boolean playNext(@NonNull ArrayList songs) {
+ public static boolean playNext(@NonNull List songs) {
if (musicService != null) {
if (getPlayingQueue().size() > 0) {
musicService.addSongs(getPosition() + 1, songs);
@@ -327,7 +332,7 @@ public static boolean enqueue(Song song) {
if (getPlayingQueue().size() > 0) {
musicService.addSong(song);
} else {
- ArrayList queue = new ArrayList<>();
+ List queue = new ArrayList<>();
queue.add(song);
openQueue(queue, 0, false);
}
@@ -337,7 +342,7 @@ public static boolean enqueue(Song song) {
return false;
}
- public static boolean enqueue(@NonNull ArrayList songs) {
+ public static boolean enqueue(@NonNull List songs) {
if (musicService != null) {
if (getPlayingQueue().size() > 0) {
musicService.addSongs(songs);
@@ -392,7 +397,7 @@ public static int getAudioSessionId() {
public static void playFromUri(Uri uri) {
if (musicService != null) {
- ArrayList songs = null;
+ List songs = null;
if (uri.getScheme() != null && uri.getAuthority() != null) {
if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
String songId = null;
diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/MusicProgressViewUpdateHelper.java b/app/src/main/java/com/kabouzeid/gramophone/helper/MusicProgressViewUpdateHelper.java
index 4f912e890..c3c8fe787 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/helper/MusicProgressViewUpdateHelper.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/helper/MusicProgressViewUpdateHelper.java
@@ -2,7 +2,7 @@
import android.os.Handler;
import android.os.Message;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
/**
* @author Karim Abou Zeid (kabouzeid)
diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/SearchQueryHelper.java b/app/src/main/java/com/kabouzeid/gramophone/helper/SearchQueryHelper.java
index 210846f5c..b11bd335b 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/helper/SearchQueryHelper.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/helper/SearchQueryHelper.java
@@ -4,12 +4,13 @@
import android.content.Context;
import android.os.Bundle;
import android.provider.MediaStore;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import com.kabouzeid.gramophone.loader.SongLoader;
import com.kabouzeid.gramophone.model.Song;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
@@ -21,68 +22,68 @@ public class SearchQueryHelper {
private static final String AND = " AND ";
@NonNull
- public static ArrayList getSongs(@NonNull final Context context, @NonNull final Bundle extras) {
+ public static List getSongs(@NonNull final Context context, @NonNull final Bundle extras) {
final String query = extras.getString(SearchManager.QUERY, null);
final String artistName = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST, null);
final String albumName = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM, null);
final String titleName = extras.getString(MediaStore.EXTRA_MEDIA_TITLE, null);
- ArrayList songs = new ArrayList<>();
+ List songs = new ArrayList<>();
if (artistName != null && albumName != null && titleName != null) {
- songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION + AND + ALBUM_SELECTION + AND + TITLE_SELECTION, new String[]{artistName.toLowerCase(), albumName.toLowerCase(), titleName.toLowerCase()}));
+ songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION + AND + ALBUM_SELECTION + AND + TITLE_SELECTION, new String[]{artistName.toLowerCase().trim(), albumName.toLowerCase().trim(), titleName.toLowerCase().trim()}));
}
if (!songs.isEmpty()) {
return songs;
}
if (artistName != null && titleName != null) {
- songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION + AND + TITLE_SELECTION, new String[]{artistName.toLowerCase(), titleName.toLowerCase()}));
+ songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION + AND + TITLE_SELECTION, new String[]{artistName.toLowerCase().trim(), titleName.toLowerCase().trim()}));
}
if (!songs.isEmpty()) {
return songs;
}
if (albumName != null && titleName != null) {
- songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION + AND + TITLE_SELECTION, new String[]{albumName.toLowerCase(), titleName.toLowerCase()}));
+ songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION + AND + TITLE_SELECTION, new String[]{albumName.toLowerCase().trim(), titleName.toLowerCase().trim()}));
}
if (!songs.isEmpty()) {
return songs;
}
if (artistName != null) {
- songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION, new String[]{artistName.toLowerCase()}));
+ songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION, new String[]{artistName.toLowerCase().trim()}));
}
if (!songs.isEmpty()) {
return songs;
}
if (albumName != null) {
- songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION, new String[]{albumName.toLowerCase()}));
+ songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION, new String[]{albumName.toLowerCase().trim()}));
}
if (!songs.isEmpty()) {
return songs;
}
if (titleName != null) {
- songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, TITLE_SELECTION, new String[]{titleName.toLowerCase()}));
+ songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, TITLE_SELECTION, new String[]{titleName.toLowerCase().trim()}));
}
if (!songs.isEmpty()) {
return songs;
}
- songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION, new String[]{query.toLowerCase()}));
+ songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION, new String[]{query.toLowerCase().trim()}));
if (!songs.isEmpty()) {
return songs;
}
- songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION, new String[]{query.toLowerCase()}));
+ songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION, new String[]{query.toLowerCase().trim()}));
if (!songs.isEmpty()) {
return songs;
}
- songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, TITLE_SELECTION, new String[]{query.toLowerCase()}));
+ songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, TITLE_SELECTION, new String[]{query.toLowerCase().trim()}));
if (!songs.isEmpty()) {
return songs;
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/ShuffleHelper.java b/app/src/main/java/com/kabouzeid/gramophone/helper/ShuffleHelper.java
index c55da086f..fb41098f0 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/helper/ShuffleHelper.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/helper/ShuffleHelper.java
@@ -1,6 +1,6 @@
package com.kabouzeid.gramophone.helper;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import com.kabouzeid.gramophone.model.Song;
diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/SortOrder.java b/app/src/main/java/com/kabouzeid/gramophone/helper/SortOrder.java
index ae805959f..89e750e26 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/helper/SortOrder.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/helper/SortOrder.java
@@ -60,11 +60,11 @@ public interface AlbumSortOrder {
+ " DESC";
/* Album sort order artist */
- String ALBUM_ARTIST = MediaStore.Audio.Albums.ARTIST;
+ String ALBUM_ARTIST = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER
+ + ", " + MediaStore.Audio.Albums.DEFAULT_SORT_ORDER;
/* Album sort order year */
- String ALBUM_YEAR = MediaStore.Audio.Albums.FIRST_YEAR + " DESC";
-
+ String ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC";
}
/**
@@ -78,10 +78,10 @@ public interface SongSortOrder {
String SONG_Z_A = SONG_A_Z + " DESC";
/* Song sort order artist */
- String SONG_ARTIST = MediaStore.Audio.Media.ARTIST;
+ String SONG_ARTIST = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER;
/* Song sort order album */
- String SONG_ALBUM = MediaStore.Audio.Media.ALBUM;
+ String SONG_ALBUM = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER;
/* Song sort order year */
String SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC";
diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/StackBlur.java b/app/src/main/java/com/kabouzeid/gramophone/helper/StackBlur.java
index 535d2a7ac..c810f7f06 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/helper/StackBlur.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/helper/StackBlur.java
@@ -3,6 +3,7 @@
import android.graphics.Bitmap;
import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -83,8 +84,8 @@ public static Bitmap blur(Bitmap original, float radius) {
original.getPixels(currentPixels, 0, w, 0, 0, w, h);
int cores = EXECUTOR_THREADS;
- ArrayList horizontal = new ArrayList(cores);
- ArrayList vertical = new ArrayList(cores);
+ List horizontal = new ArrayList<>(cores);
+ List vertical = new ArrayList<>(cores);
for (int i = 0; i < cores; i++) {
horizontal.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 1));
vertical.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 2));
diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/StopWatch.java b/app/src/main/java/com/kabouzeid/gramophone/helper/StopWatch.java
index d65f90751..581d8fc20 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/helper/StopWatch.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/helper/StopWatch.java
@@ -1,5 +1,7 @@
package com.kabouzeid.gramophone.helper;
+import java.util.Locale;
+
/**
* Simple thread safe stop watch.
*
@@ -77,6 +79,6 @@ public final long getElapsedTime() {
@Override
public String toString() {
- return String.format("%d millis", getElapsedTime());
+ return String.format(Locale.getDefault(), "%d millis", getElapsedTime());
}
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/menu/PlaylistMenuHelper.java b/app/src/main/java/com/kabouzeid/gramophone/helper/menu/PlaylistMenuHelper.java
index 7b405085a..13067c1b7 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/helper/menu/PlaylistMenuHelper.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/helper/menu/PlaylistMenuHelper.java
@@ -1,20 +1,20 @@
package com.kabouzeid.gramophone.helper.menu;
-import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
-import android.os.AsyncTask;
-import android.support.annotation.NonNull;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
import android.view.MenuItem;
import android.widget.Toast;
+import com.kabouzeid.gramophone.App;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog;
import com.kabouzeid.gramophone.dialogs.DeletePlaylistDialog;
import com.kabouzeid.gramophone.dialogs.RenamePlaylistDialog;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.loader.PlaylistSongLoader;
+import com.kabouzeid.gramophone.misc.WeakContextAsyncTask;
import com.kabouzeid.gramophone.model.AbsCustomPlaylist;
import com.kabouzeid.gramophone.model.Playlist;
import com.kabouzeid.gramophone.model.Song;
@@ -22,6 +22,7 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
@@ -48,43 +49,42 @@ public static boolean handleMenuClick(@NonNull AppCompatActivity activity, @NonN
DeletePlaylistDialog.create(playlist).show(activity.getSupportFragmentManager(), "DELETE_PLAYLIST");
return true;
case R.id.action_save_playlist:
- @SuppressLint("ShowToast")
- final Toast toast = Toast.makeText(activity, R.string.saving_to_file, Toast.LENGTH_SHORT);
- new AsyncTask() {
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- toast.show();
- }
-
- @Override
- protected String doInBackground(Context... params) {
- try {
- return String.format(params[0].getString(R.string.saved_playlist_to), PlaylistsUtil.savePlaylist(params[0], playlist));
- } catch (IOException e) {
- e.printStackTrace();
- return String.format(params[0].getString(R.string.failed_to_save_playlist), e);
- }
- }
-
- @Override
- protected void onPostExecute(String string) {
- super.onPostExecute(string);
- if (toast != null) {
- toast.setText(string);
- toast.show();
- }
- }
- }.execute(activity.getApplicationContext());
+ new SavePlaylistAsyncTask(activity).execute(playlist);
return true;
}
return false;
}
@NonNull
- private static ArrayList extends Song> getPlaylistSongs(@NonNull Activity activity, Playlist playlist) {
+ private static List extends Song> getPlaylistSongs(@NonNull Activity activity, Playlist playlist) {
return playlist instanceof AbsCustomPlaylist ?
((AbsCustomPlaylist) playlist).getSongs(activity) :
PlaylistSongLoader.getPlaylistSongList(activity, playlist.id);
}
+
+
+ private static class SavePlaylistAsyncTask extends WeakContextAsyncTask {
+ public SavePlaylistAsyncTask(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected String doInBackground(Playlist... params) {
+ try {
+ return String.format(App.getInstance().getApplicationContext().getString(R.string.saved_playlist_to), PlaylistsUtil.savePlaylist(App.getInstance().getApplicationContext(), params[0]));
+ } catch (IOException e) {
+ e.printStackTrace();
+ return String.format(App.getInstance().getApplicationContext().getString(R.string.failed_to_save_playlist), e);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(String string) {
+ super.onPostExecute(string);
+ Context context = getContext();
+ if (context != null) {
+ Toast.makeText(context, string, Toast.LENGTH_LONG).show();
+ }
+ }
+ }
}
diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/menu/SongMenuHelper.java b/app/src/main/java/com/kabouzeid/gramophone/helper/menu/SongMenuHelper.java
index a3cedbd22..b55c7f53e 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/helper/menu/SongMenuHelper.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/helper/menu/SongMenuHelper.java
@@ -1,9 +1,9 @@
package com.kabouzeid.gramophone.helper.menu;
import android.content.Intent;
-import android.support.annotation.NonNull;
-import android.support.v4.app.FragmentActivity;
-import android.support.v7.app.AppCompatActivity;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.FragmentActivity;
+import androidx.appcompat.app.AppCompatActivity;
import android.view.MenuItem;
import android.view.View;
import android.widget.PopupMenu;
@@ -19,6 +19,7 @@
import com.kabouzeid.gramophone.ui.activities.tageditor.SongTagEditorActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
+import com.kabouzeid.gramophone.util.RingtoneManager;
/**
* @author Karim Abou Zeid (kabouzeid)
@@ -29,7 +30,12 @@ public class SongMenuHelper {
public static boolean handleMenuClick(@NonNull FragmentActivity activity, @NonNull Song song, int menuItemId) {
switch (menuItemId) {
case R.id.action_set_as_ringtone:
- MusicUtil.setRingtone(activity, song.id);
+ if (RingtoneManager.requiresDialog(activity)) {
+ RingtoneManager.showDialog(activity);
+ } else {
+ RingtoneManager ringtoneManager = new RingtoneManager();
+ ringtoneManager.setRingtone(activity, song.id);
+ }
return true;
case R.id.action_share:
activity.startActivity(Intent.createChooser(MusicUtil.createShareSongFileIntent(song, activity), null));
diff --git a/app/src/main/java/com/kabouzeid/gramophone/helper/menu/SongsMenuHelper.java b/app/src/main/java/com/kabouzeid/gramophone/helper/menu/SongsMenuHelper.java
index 5adb08688..f3ce04fee 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/helper/menu/SongsMenuHelper.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/helper/menu/SongsMenuHelper.java
@@ -1,7 +1,7 @@
package com.kabouzeid.gramophone.helper.menu;
-import android.support.annotation.NonNull;
-import android.support.v4.app.FragmentActivity;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.FragmentActivity;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog;
@@ -10,12 +10,13 @@
import com.kabouzeid.gramophone.model.Song;
import java.util.ArrayList;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class SongsMenuHelper {
- public static boolean handleMenuClick(@NonNull FragmentActivity activity, @NonNull ArrayList songs, int menuItemId) {
+ public static boolean handleMenuClick(@NonNull FragmentActivity activity, @NonNull List songs, int menuItemId) {
switch (menuItemId) {
case R.id.action_play_next:
MusicPlayerRemote.playNext(songs);
diff --git a/app/src/main/java/com/kabouzeid/gramophone/interfaces/CabHolder.java b/app/src/main/java/com/kabouzeid/gramophone/interfaces/CabHolder.java
index 7818c2345..a7e93cd40 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/interfaces/CabHolder.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/interfaces/CabHolder.java
@@ -1,6 +1,6 @@
package com.kabouzeid.gramophone.interfaces;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import com.afollestad.materialcab.MaterialCab;
diff --git a/app/src/main/java/com/kabouzeid/gramophone/interfaces/PaletteColorHolder.java b/app/src/main/java/com/kabouzeid/gramophone/interfaces/PaletteColorHolder.java
index b6df7c74d..6036c1e67 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/interfaces/PaletteColorHolder.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/interfaces/PaletteColorHolder.java
@@ -1,6 +1,6 @@
package com.kabouzeid.gramophone.interfaces;
-import android.support.annotation.ColorInt;
+import androidx.annotation.ColorInt;
/**
* @author Aidan Follestad (afollestad)
diff --git a/app/src/main/java/com/kabouzeid/gramophone/lastfm/rest/LastFMRestClient.java b/app/src/main/java/com/kabouzeid/gramophone/lastfm/rest/LastFMRestClient.java
index 65fb8e5fb..c5ac4743a 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/lastfm/rest/LastFMRestClient.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/lastfm/rest/LastFMRestClient.java
@@ -1,20 +1,19 @@
package com.kabouzeid.gramophone.lastfm.rest;
import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.kabouzeid.gramophone.lastfm.rest.service.LastFMService;
import java.io.File;
-import java.io.IOException;
+import java.util.Locale;
import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
-import okhttp3.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
@@ -22,7 +21,7 @@
* @author Karim Abou Zeid (kabouzeid)
*/
public class LastFMRestClient {
- public static final String BASE_URL = "http://ws.audioscrobbler.com/2.0/";
+ public static final String BASE_URL = "https://ws.audioscrobbler.com/2.0/";
private LastFMService apiService;
@@ -56,7 +55,7 @@ public static Cache createDefaultCache(Context context) {
public static Interceptor createCacheControlInterceptor() {
return chain -> {
Request modifiedRequest = chain.request().newBuilder()
- .addHeader("Cache-Control", String.format("max-age=%d, max-stale=%d", 31536000, 31536000))
+ .addHeader("Cache-Control", String.format(Locale.getDefault(), "max-age=%d, max-stale=%d", 31536000, 31536000))
.build();
return chain.proceed(modifiedRequest);
};
diff --git a/app/src/main/java/com/kabouzeid/gramophone/lastfm/rest/service/LastFMService.java b/app/src/main/java/com/kabouzeid/gramophone/lastfm/rest/service/LastFMService.java
index 4a9b33c79..01be3e72f 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/lastfm/rest/service/LastFMService.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/lastfm/rest/service/LastFMService.java
@@ -1,6 +1,6 @@
package com.kabouzeid.gramophone.lastfm.rest.service;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import com.kabouzeid.gramophone.lastfm.rest.model.LastFmAlbum;
import com.kabouzeid.gramophone.lastfm.rest.model.LastFmArtist;
diff --git a/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumLoader.java b/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumLoader.java
index 89657a628..7956cc7d5 100644
--- a/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumLoader.java
+++ b/app/src/main/java/com/kabouzeid/gramophone/loader/AlbumLoader.java
@@ -2,14 +2,16 @@
import android.content.Context;
import android.provider.MediaStore.Audio.AudioColumns;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.kabouzeid.gramophone.model.Album;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.PreferenceUtil;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
* @author Karim Abou Zeid (kabouzeid)
@@ -21,8 +23,8 @@ public static String getSongLoaderSortOrder(Context context) {
}
@NonNull
- public static ArrayList getAllAlbums(@NonNull final Context context) {
- ArrayList songs = SongLoader.getSongs(SongLoader.makeSongCursor(
+ public static List getAllAlbums(@NonNull final Context context) {
+ List songs = SongLoader.getSongs(SongLoader.makeSongCursor(
context,
null,
null,
@@ -32,8 +34,8 @@ public static ArrayList getAllAlbums(@NonNull final Context context) {
}
@NonNull
- public static ArrayList getAlbums(@NonNull final Context context, String query) {
- ArrayList songs = SongLoader.getSongs(SongLoader.makeSongCursor(
+ public static List getAlbums(@NonNull final Context context, String query) {
+ List songs = SongLoader.getSongs(SongLoader.makeSongCursor(
context,
AudioColumns.ALBUM + " LIKE ?",
new String[]{"%" + query + "%"},
@@ -44,22 +46,27 @@ public static ArrayList getAlbums(@NonNull final Context context, String
@NonNull
public static Album getAlbum(@NonNull final Context context, int albumId) {
- ArrayList