improve item detail strings and implement favorite songs

This commit is contained in:
dkanada 2020-04-30 00:52:06 +09:00
commit 551cc719af
13 changed files with 127 additions and 203 deletions

View file

@ -82,10 +82,7 @@ public class PlaylistSongAdapter extends AbsOffsetSongAdapter {
@Override @Override
protected boolean onSongMenuItemClick(MenuItem item) { protected boolean onSongMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.action_go_to_album) { if (item.getItemId() == R.id.action_go_to_album) {
Pair[] albumPairs = new Pair[]{ Pair[] albumPairs = new Pair[]{Pair.create(image, activity.getString(R.string.transition_album_art))};
Pair.create(image, activity.getString(R.string.transition_album_art))
};
NavigationUtil.goToAlbum(activity, dataSet.get(getAdapterPosition() - 1).albumId, albumPairs); NavigationUtil.goToAlbum(activity, dataSet.get(getAdapterPosition() - 1).albumId, albumPairs);
return true; return true;
} }

View file

@ -8,7 +8,6 @@ import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
import android.text.Html; import android.text.Html;
import android.text.Spanned; import android.text.Spanned;
import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
@ -17,17 +16,6 @@ import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.MusicUtil; import com.kabouzeid.gramophone.util.MusicUtil;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.AudioHeader;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.tag.TagException;
import java.io.File;
import java.io.IOException;
public class SongDetailDialog extends DialogFragment { public class SongDetailDialog extends DialogFragment {
public static final String TAG = SongDetailDialog.class.getSimpleName(); public static final String TAG = SongDetailDialog.class.getSimpleName();
@ -81,29 +69,9 @@ public class SongDetailDialog extends DialogFragment {
samplingRate.setText(makeTextWithTitle(context, R.string.label_sampling_rate, "-")); samplingRate.setText(makeTextWithTitle(context, R.string.label_sampling_rate, "-"));
if (song != null) { 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();
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);
trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(song.duration)));
}
} else {
fileName.setText(makeTextWithTitle(context, R.string.label_file_name, song.title)); fileName.setText(makeTextWithTitle(context, R.string.label_file_name, song.title));
trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(song.duration))); trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(song.duration)));
} }
}
return dialog; return dialog;
} }

View file

@ -20,17 +20,15 @@ import java.util.List;
public class SongLoader { public class SongLoader {
protected static final String BASE_SELECTION = AudioColumns.IS_MUSIC + "=1" + " AND " + AudioColumns.TITLE + " != ''"; protected static final String BASE_SELECTION = AudioColumns.IS_MUSIC + "=1" + " AND " + AudioColumns.TITLE + " != ''";
protected static final String[] BASE_PROJECTION = new String[]{ protected static final String[] BASE_PROJECTION = new String[]{
BaseColumns._ID,// 0 BaseColumns._ID,
AudioColumns.TITLE,// 1 AudioColumns.TITLE,
AudioColumns.TRACK,// 2 AudioColumns.TRACK,
AudioColumns.YEAR,// 3 AudioColumns.YEAR,
AudioColumns.DURATION,// 4 AudioColumns.DURATION,
AudioColumns.DATA,// 5 AudioColumns.ALBUM_ID,
AudioColumns.DATE_MODIFIED,// 6 AudioColumns.ALBUM,
AudioColumns.ALBUM_ID,// 7 AudioColumns.ARTIST_ID,
AudioColumns.ALBUM,// 8 AudioColumns.ARTIST,
AudioColumns.ARTIST_ID,// 9
AudioColumns.ARTIST,// 10
}; };
@NonNull @NonNull
@ -73,9 +71,11 @@ public class SongLoader {
} else { } else {
song = Song.EMPTY_SONG; song = Song.EMPTY_SONG;
} }
if (cursor != null) { if (cursor != null) {
cursor.close(); cursor.close();
} }
return song; return song;
} }
@ -86,14 +86,14 @@ public class SongLoader {
final int trackNumber = cursor.getInt(2); final int trackNumber = cursor.getInt(2);
final int year = cursor.getInt(3); final int year = cursor.getInt(3);
final long duration = cursor.getLong(4); final long duration = cursor.getLong(4);
final String data = cursor.getString(5);
final long dateModified = cursor.getLong(6);
final String albumId = cursor.getString(7);
final String albumName = cursor.getString(8);
final String artistId = cursor.getString(9);
final String artistName = cursor.getString(10);
return new Song(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName, artistId, artistName); final String albumId = cursor.getString(5);
final String albumName = cursor.getString(6);
final String artistId = cursor.getString(7);
final String artistName = cursor.getString(8);
return new Song(id, title, trackNumber, year, duration, albumId, albumName, artistId, artistName);
} }
@Nullable @Nullable

View file

@ -14,20 +14,19 @@ public class Album implements Parcelable {
public String id; public String id;
public String title; public String title;
public int year;
public String artistId; public String artistId;
public String artistName; public String artistName;
public int year;
public Album(BaseItemDto itemDto) { public Album(BaseItemDto itemDto) {
this.id = itemDto.getId(); this.id = itemDto.getId();
this.title = itemDto.getName(); this.title = itemDto.getName();
this.year = itemDto.getProductionYear() != null ? itemDto.getProductionYear() : 0;
this.artistId = itemDto.getAlbumArtists().get(0).getId(); this.artistId = itemDto.getAlbumArtists().get(0).getId();
this.artistName = itemDto.getAlbumArtists().get(0).getName(); this.artistName = itemDto.getAlbumArtists().get(0).getName();
if (itemDto.getProductionYear() != null) {
this.year = itemDto.getProductionYear();
}
this.songs = new ArrayList<>(); this.songs = new ArrayList<>();
} }
@ -59,11 +58,6 @@ public class Album implements Parcelable {
return songs.size(); return songs.size();
} }
@NonNull
public Song safeGetFirstSong() {
return songs.isEmpty() ? Song.EMPTY_SONG : songs.get(0);
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;

View file

@ -4,13 +4,13 @@ import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import org.jellyfin.apiclient.model.dto.BaseItemDto; import org.jellyfin.apiclient.model.dto.BaseItemDto;
import org.jellyfin.apiclient.model.dto.GenreDto;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Artist implements Parcelable { public class Artist implements Parcelable {
public static final String UNKNOWN_ARTIST_DISPLAY_NAME = "Unknown Artist"; public List<Genre> genres;
public List<Album> albums; public List<Album> albums;
public List<Song> songs; public List<Song> songs;
@ -23,8 +23,15 @@ public class Artist implements Parcelable {
this.name = itemDto.getName(); this.name = itemDto.getName();
this.duration = itemDto.getRunTimeTicks() / 10000; this.duration = itemDto.getRunTimeTicks() / 10000;
this.genres = new ArrayList<>();
this.albums = new ArrayList<>(); this.albums = new ArrayList<>();
this.songs = new ArrayList<>(); this.songs = new ArrayList<>();
if (itemDto.getGenreItems() != null) {
for (GenreDto genre : itemDto.getGenreItems()) {
genres.add(new Genre(genre));
}
}
} }
public Artist() { public Artist() {

View file

@ -4,24 +4,25 @@ import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import org.jellyfin.apiclient.model.dto.BaseItemDto; import org.jellyfin.apiclient.model.dto.BaseItemDto;
import org.jellyfin.apiclient.model.dto.GenreDto;
public class Genre implements Parcelable { public class Genre implements Parcelable {
public final String id; public final String id;
public final String name; public final String name;
public final int songCount; public final int songCount;
public Genre(GenreDto genreDto) {
this.id = genreDto.getId();
this.name = genreDto.getName();
this.songCount = 0;
}
public Genre(BaseItemDto itemDto) { public Genre(BaseItemDto itemDto) {
this.id = itemDto.getId(); this.id = itemDto.getId();
this.name = itemDto.getName(); this.name = itemDto.getName();
this.songCount = itemDto.getSongCount() != null ? itemDto.getSongCount() : 0; this.songCount = itemDto.getSongCount() != null ? itemDto.getSongCount() : 0;
} }
public Genre(final int id, final String name, final int songCount) {
this.id = Integer.toString(id);
this.name = name;
this.songCount = songCount;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;

View file

@ -6,46 +6,52 @@ import android.os.Parcelable;
import org.jellyfin.apiclient.model.dto.BaseItemDto; import org.jellyfin.apiclient.model.dto.BaseItemDto;
public class Song implements Parcelable { public class Song implements Parcelable {
public static final Song EMPTY_SONG = new Song("", "", -1, -1, -1, "", -1, "", "", "", ""); public static final Song EMPTY_SONG = new Song(null, "", -1, -1, -1, null, "", null, "");
public final String id; public final String id;
public final String title; public final String title;
public final int trackNumber; public final int trackNumber;
public final int year; public final int year;
public final long duration; public final long duration;
public final String data;
public final long dateModified;
public final String albumId; public final String albumId;
public final String albumName; public final String albumName;
public final String artistId; public final String artistId;
public final String artistName; public final String artistName;
public boolean favorite;
public Song(BaseItemDto itemDto) { public Song(BaseItemDto itemDto) {
this.id = itemDto.getId(); this.id = itemDto.getId();
this.title = itemDto.getName(); this.title = itemDto.getName();
this.trackNumber = itemDto.getIndexNumber() != null ? itemDto.getIndexNumber() : 0; this.trackNumber = itemDto.getIndexNumber() != null ? itemDto.getIndexNumber() : 0;
this.year = itemDto.getProductionYear() != null ? itemDto.getProductionYear() : 0; this.year = itemDto.getProductionYear() != null ? itemDto.getProductionYear() : 0;
this.duration = itemDto.getRunTimeTicks() / 10000; this.duration = itemDto.getRunTimeTicks() / 10000;
this.data = "";
this.dateModified = 2;
this.albumId = itemDto.getAlbumId(); this.albumId = itemDto.getAlbumId();
this.albumName = itemDto.getAlbum(); this.albumName = itemDto.getAlbum();
this.artistId = itemDto.getAlbumArtists().get(0).getId(); this.artistId = itemDto.getAlbumArtists().get(0).getId();
this.artistName = itemDto.getAlbumArtists().get(0).getName(); this.artistName = itemDto.getAlbumArtists().get(0).getName();
this.favorite = itemDto.getUserData() != null && itemDto.getUserData().getIsFavorite();
} }
public Song(String id, String title, int trackNumber, int year, long duration, String data, long dateModified, String albumId, String albumName, String artistId, String artistName) { public Song(String id, String title, int trackNumber, int year, long duration, String albumId, String albumName, String artistId, String artistName) {
this.id = id; this.id = id;
this.title = title; this.title = title;
this.trackNumber = trackNumber; this.trackNumber = trackNumber;
this.year = year; this.year = year;
this.duration = duration; this.duration = duration;
this.data = data;
this.dateModified = dateModified;
this.albumId = albumId; this.albumId = albumId;
this.albumName = albumName; this.albumName = albumName;
this.artistId = artistId; this.artistId = artistId;
this.artistName = artistName; this.artistName = artistName;
this.favorite = false;
} }
@Override @Override
@ -79,10 +85,10 @@ public class Song implements Parcelable {
dest.writeInt(this.trackNumber); dest.writeInt(this.trackNumber);
dest.writeInt(this.year); dest.writeInt(this.year);
dest.writeLong(this.duration); dest.writeLong(this.duration);
dest.writeString(this.data);
dest.writeLong(this.dateModified);
dest.writeString(this.albumId); dest.writeString(this.albumId);
dest.writeString(this.albumName); dest.writeString(this.albumName);
dest.writeString(this.artistId); dest.writeString(this.artistId);
dest.writeString(this.artistName); dest.writeString(this.artistName);
} }
@ -93,12 +99,14 @@ public class Song implements Parcelable {
this.trackNumber = in.readInt(); this.trackNumber = in.readInt();
this.year = in.readInt(); this.year = in.readInt();
this.duration = in.readLong(); this.duration = in.readLong();
this.data = in.readString();
this.dateModified = in.readLong();
this.albumId = in.readString(); this.albumId = in.readString();
this.albumName = in.readString(); this.albumName = in.readString();
this.artistId = in.readString(); this.artistId = in.readString();
this.artistName = in.readString(); this.artistName = in.readString();
this.favorite = false;
} }
public static final Creator<Song> CREATOR = new Creator<Song>() { public static final Creator<Song> CREATOR = new Creator<Song>() {

View file

@ -145,8 +145,6 @@ public class QueueStore extends SQLiteOpenHelper {
values.put(AudioColumns.TRACK, song.trackNumber); values.put(AudioColumns.TRACK, song.trackNumber);
values.put(AudioColumns.YEAR, song.year); values.put(AudioColumns.YEAR, song.year);
values.put(AudioColumns.DURATION, song.duration); values.put(AudioColumns.DURATION, song.duration);
values.put(AudioColumns.DATA, song.data);
values.put(AudioColumns.DATE_MODIFIED, song.dateModified);
values.put(AudioColumns.ALBUM_ID, song.albumId); values.put(AudioColumns.ALBUM_ID, song.albumId);
values.put(AudioColumns.ALBUM, song.albumName); values.put(AudioColumns.ALBUM, song.albumName);
values.put(AudioColumns.ARTIST_ID, song.artistId); values.put(AudioColumns.ARTIST_ID, song.artistId);

View file

@ -569,7 +569,8 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
if (PreferenceUtil.getInstance(this).getShowAlbumCover()) { if (PreferenceUtil.getInstance(this).getShowAlbumCover()) {
final Point screenSize = Util.getScreenSize(MusicService.this); final Point screenSize = Util.getScreenSize(MusicService.this);
final BitmapRequestBuilder<?, Bitmap> request = CustomGlideRequest.Builder.from(Glide.with(MusicService.this), song.albumId) final BitmapRequestBuilder<?, Bitmap> request = CustomGlideRequest.Builder
.from(Glide.with(MusicService.this), song.albumId)
.asBitmap().build(); .asBitmap().build();
if (PreferenceUtil.getInstance(this).getBlurAlbumCover()) { if (PreferenceUtil.getInstance(this).getBlurAlbumCover()) {
@ -604,6 +605,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
if (config == null) { if (config == null) {
config = Bitmap.Config.RGB_565; config = Bitmap.Config.RGB_565;
} }
try { try {
return bitmap.copy(config, false); return bitmap.copy(config, false);
} catch (OutOfMemoryError e) { } catch (OutOfMemoryError e) {
@ -684,7 +686,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
public void openQueue(@Nullable final List<Song> playingQueue, final int startPosition, final boolean startPlaying) { public void openQueue(@Nullable final List<Song> playingQueue, final int startPosition, final boolean startPlaying) {
if (playingQueue != null && !playingQueue.isEmpty() && startPosition >= 0 && startPosition < playingQueue.size()) { if (playingQueue != null && !playingQueue.isEmpty() && startPosition >= 0 && startPosition < playingQueue.size()) {
// it is important to copy the playing queue here first as we might add/remove songs later // it is important to copy the playing queue here first as we might add or remove songs later
originalPlayingQueue = new ArrayList<>(playingQueue); originalPlayingQueue = new ArrayList<>(playingQueue);
this.playingQueue = new ArrayList<>(originalPlayingQueue); this.playingQueue = new ArrayList<>(originalPlayingQueue);
@ -693,11 +695,13 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
ShuffleHelper.makeShuffleList(this.playingQueue, startPosition); ShuffleHelper.makeShuffleList(this.playingQueue, startPosition);
position = 0; position = 0;
} }
if (startPlaying) { if (startPlaying) {
playSongAt(position); playSongAt(position);
} else { } else {
setPosition(position); setPosition(position);
} }
notifyChange(QUEUE_CHANGED); notifyChange(QUEUE_CHANGED);
} }
} }
@ -735,7 +739,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
} }
rePosition(position); rePosition(position);
notifyChange(QUEUE_CHANGED); notifyChange(QUEUE_CHANGED);
} }
@ -746,11 +749,13 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
rePosition(i); rePosition(i);
} }
} }
for (int i = 0; i < originalPlayingQueue.size(); i++) { for (int i = 0; i < originalPlayingQueue.size(); i++) {
if (originalPlayingQueue.get(i).id == song.id) { if (originalPlayingQueue.get(i).id == song.id) {
originalPlayingQueue.remove(i); originalPlayingQueue.remove(i);
} }
} }
notifyChange(QUEUE_CHANGED); notifyChange(QUEUE_CHANGED);
} }
@ -776,6 +781,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
Song tmpSong = originalPlayingQueue.remove(from); Song tmpSong = originalPlayingQueue.remove(from);
originalPlayingQueue.add(to, tmpSong); originalPlayingQueue.add(to, tmpSong);
} }
if (from > currentPosition && to <= currentPosition) { if (from > currentPosition && to <= currentPosition) {
position = currentPosition + 1; position = currentPosition + 1;
} else if (from < currentPosition && to >= currentPosition) { } else if (from < currentPosition && to >= currentPosition) {
@ -783,6 +789,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
} else if (from == currentPosition) { } else if (from == currentPosition) {
position = to; position = to;
} }
notifyChange(QUEUE_CHANGED); notifyChange(QUEUE_CHANGED);
} }

View file

@ -89,8 +89,6 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
private RecyclerView.Adapter wrappedAdapter; private RecyclerView.Adapter wrappedAdapter;
private RecyclerViewDragDropManager recyclerViewDragDropManager; private RecyclerViewDragDropManager recyclerViewDragDropManager;
private AsyncTask updateIsFavoriteTask;
private Impl impl; private Impl impl;
@Override @Override
@ -256,32 +254,13 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
} }
private void updateIsFavorite() { private void updateIsFavorite() {
if (updateIsFavoriteTask != null) updateIsFavoriteTask.cancel(false); boolean favorite = MusicPlayerRemote.getCurrentSong().favorite;
updateIsFavoriteTask = new AsyncTask<Song, Void, Boolean>() { int res = favorite ? R.drawable.ic_favorite_white_24dp : R.drawable.ic_favorite_border_white_24dp;
@Override int color = ToolbarContentTintHelper.toolbarContentColor(getActivity(), Color.TRANSPARENT);
protected Boolean doInBackground(Song... params) { Drawable drawable = ImageUtil.getTintedVectorDrawable(getActivity(), res, color);
Activity activity = getActivity();
if (activity != null) {
return MusicUtil.isFavorite(getActivity(), params[0]);
} else {
cancel(false);
return null;
}
}
@Override
protected void onPostExecute(Boolean isFavorite) {
Activity activity = getActivity();
if (activity != null) {
int res = isFavorite ? R.drawable.ic_favorite_white_24dp : R.drawable.ic_favorite_border_white_24dp;
int color = ToolbarContentTintHelper.toolbarContentColor(activity, Color.TRANSPARENT);
Drawable drawable = ImageUtil.getTintedVectorDrawable(activity, res, color);
toolbar.getMenu().findItem(R.id.action_toggle_favorite) toolbar.getMenu().findItem(R.id.action_toggle_favorite)
.setIcon(drawable) .setIcon(drawable)
.setTitle(isFavorite ? getString(R.string.action_remove_from_favorites) : getString(R.string.action_add_to_favorites)); .setTitle(favorite ? getString(R.string.action_remove_from_favorites) : getString(R.string.action_add_to_favorites));
}
}
}.execute(MusicPlayerRemote.getCurrentSong());
} }
@Override @Override
@ -299,9 +278,10 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
protected void toggleFavorite(Song song) { protected void toggleFavorite(Song song) {
super.toggleFavorite(song); super.toggleFavorite(song);
if (song.id == MusicPlayerRemote.getCurrentSong().id) { if (song.id == MusicPlayerRemote.getCurrentSong().id) {
if (MusicUtil.isFavorite(getActivity(), song)) { if (song.favorite) {
playerAlbumCoverFragment.showHeartAnimation(); playerAlbumCoverFragment.showHeartAnimation();
} }
updateIsFavorite(); updateIsFavorite();
} }
} }
@ -455,6 +435,7 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
fragment.slidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); fragment.slidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
} }
}); });
currentSongViewHolder.menu.setOnClickListener(new SongMenuHelper.OnClickSongMenu((AppCompatActivity) fragment.getActivity()) { currentSongViewHolder.menu.setOnClickListener(new SongMenuHelper.OnClickSongMenu((AppCompatActivity) fragment.getActivity()) {
@Override @Override
public Song getSong() { public Song getSong() {
@ -475,6 +456,7 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
SongShareDialog.create(getSong()).show(fragment.getFragmentManager(), "SONG_SHARE_DIALOG"); SongShareDialog.create(getSong()).show(fragment.getFragmentManager(), "SONG_SHARE_DIALOG");
return true; return true;
} }
return super.onMenuItemClick(item); return super.onMenuItemClick(item);
} }
}); });
@ -490,8 +472,8 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
albumCoverContainer.getLayoutParams().height = albumCoverContainer.getHeight() - (minPanelHeight - availablePanelHeight); albumCoverContainer.getLayoutParams().height = albumCoverContainer.getHeight() - (minPanelHeight - availablePanelHeight);
albumCoverContainer.forceSquare(false); albumCoverContainer.forceSquare(false);
} }
fragment.slidingUpPanelLayout.setPanelHeight(Math.max(minPanelHeight, availablePanelHeight));
fragment.slidingUpPanelLayout.setPanelHeight(Math.max(minPanelHeight, availablePanelHeight));
((AbsSlidingMusicPanelActivity) fragment.getActivity()).setAntiDragView(fragment.slidingUpPanelLayout.findViewById(R.id.player_panel)); ((AbsSlidingMusicPanelActivity) fragment.getActivity()).setAntiDragView(fragment.slidingUpPanelLayout.findViewById(R.id.player_panel));
} }
@ -507,7 +489,6 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
super.animateColorChange(newColor); super.animateColorChange(newColor);
fragment.slidingUpPanelLayout.setBackgroundColor(fragment.lastColor); fragment.slidingUpPanelLayout.setBackgroundColor(fragment.lastColor);
createDefaultColorChangeAnimatorSet(newColor).start(); createDefaultColorChangeAnimatorSet(newColor).start();
} }
} }
@ -520,7 +501,6 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
@Override @Override
public void init() { public void init() {
} }
@Override @Override
@ -546,6 +526,7 @@ public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
AnimatorSet animatorSet = createDefaultColorChangeAnimatorSet(newColor); AnimatorSet animatorSet = createDefaultColorChangeAnimatorSet(newColor);
animatorSet.play(ViewUtil.createBackgroundColorTransition(fragment.toolbar, fragment.lastColor, newColor)) animatorSet.play(ViewUtil.createBackgroundColorTransition(fragment.toolbar, fragment.lastColor, newColor))
.with(ViewUtil.createBackgroundColorTransition(fragment.getView().findViewById(R.id.status_bar), ColorUtil.darkenColor(fragment.lastColor), ColorUtil.darkenColor(newColor))); .with(ViewUtil.createBackgroundColorTransition(fragment.getView().findViewById(R.id.status_bar), ColorUtil.darkenColor(fragment.lastColor), ColorUtil.darkenColor(newColor)));
animatorSet.start(); animatorSet.start();
} }
} }

View file

@ -82,8 +82,6 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
private RecyclerView.Adapter wrappedAdapter; private RecyclerView.Adapter wrappedAdapter;
private RecyclerViewDragDropManager recyclerViewDragDropManager; private RecyclerViewDragDropManager recyclerViewDragDropManager;
private AsyncTask updateIsFavoriteTask;
private Impl impl; private Impl impl;
@Override @Override
@ -248,32 +246,13 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
} }
private void updateIsFavorite() { private void updateIsFavorite() {
if (updateIsFavoriteTask != null) updateIsFavoriteTask.cancel(false); boolean favorite = MusicPlayerRemote.getCurrentSong().favorite;
updateIsFavoriteTask = new AsyncTask<Song, Void, Boolean>() { int res = favorite ? R.drawable.ic_favorite_white_24dp : R.drawable.ic_favorite_border_white_24dp;
@Override int color = ToolbarContentTintHelper.toolbarContentColor(getActivity(), Color.TRANSPARENT);
protected Boolean doInBackground(Song... params) { Drawable drawable = ImageUtil.getTintedVectorDrawable(getActivity(), res, color);
Activity activity = getActivity();
if (activity != null) {
return MusicUtil.isFavorite(getActivity(), params[0]);
} else {
cancel(false);
return null;
}
}
@Override
protected void onPostExecute(Boolean isFavorite) {
Activity activity = getActivity();
if (activity != null) {
int res = isFavorite ? R.drawable.ic_favorite_white_24dp : R.drawable.ic_favorite_border_white_24dp;
int color = ToolbarContentTintHelper.toolbarContentColor(activity, Color.TRANSPARENT);
Drawable drawable = ImageUtil.getTintedVectorDrawable(activity, res, color);
toolbar.getMenu().findItem(R.id.action_toggle_favorite) toolbar.getMenu().findItem(R.id.action_toggle_favorite)
.setIcon(drawable) .setIcon(drawable)
.setTitle(isFavorite ? getString(R.string.action_remove_from_favorites) : getString(R.string.action_add_to_favorites)); .setTitle(favorite ? getString(R.string.action_remove_from_favorites) : getString(R.string.action_add_to_favorites));
}
}
}.execute(MusicPlayerRemote.getCurrentSong());
} }
@Override @Override
@ -291,9 +270,10 @@ public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbum
protected void toggleFavorite(Song song) { protected void toggleFavorite(Song song) {
super.toggleFavorite(song); super.toggleFavorite(song);
if (song.id == MusicPlayerRemote.getCurrentSong().id) { if (song.id == MusicPlayerRemote.getCurrentSong().id) {
if (MusicUtil.isFavorite(getActivity(), song)) { if (song.favorite) {
playerAlbumCoverFragment.showHeartAnimation(); playerAlbumCoverFragment.showHeartAnimation();
} }
updateIsFavorite(); updateIsFavorite();
} }
} }

View file

@ -6,7 +6,6 @@ import android.net.Uri;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.content.FileProvider;
import android.text.TextUtils; import android.text.TextUtils;
import android.widget.Toast; import android.widget.Toast;
@ -18,7 +17,9 @@ import com.kabouzeid.gramophone.model.Genre;
import com.kabouzeid.gramophone.model.Playlist; import com.kabouzeid.gramophone.model.Playlist;
import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.model.Song;
import java.io.File; import org.jellyfin.apiclient.interaction.Response;
import org.jellyfin.apiclient.model.dto.UserItemDataDto;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -30,11 +31,7 @@ public class MusicUtil {
@NonNull @NonNull
public static Intent createShareSongFileIntent(@NonNull final Song song, Context context) { public static Intent createShareSongFileIntent(@NonNull final Song song, Context context) {
try { try {
return new Intent() return new Intent();
.setAction(Intent.ACTION_SEND)
.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName(), new File(song.data)))
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.setType("audio/*");
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
e.printStackTrace(); e.printStackTrace();
Toast.makeText(context, R.string.error_share_file, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.error_share_file, Toast.LENGTH_SHORT).show();
@ -44,31 +41,17 @@ public class MusicUtil {
@NonNull @NonNull
public static String getArtistInfoString(@NonNull final Context context, @NonNull final Artist artist) { public static String getArtistInfoString(@NonNull final Context context, @NonNull final Artist artist) {
int albumCount = artist.getAlbumCount(); return artist.genres.size() != 0 ? artist.genres.get(0).name : artist.id;
int songCount = artist.getSongCount();
return MusicUtil.buildInfoString(
MusicUtil.getAlbumCountString(context, albumCount),
MusicUtil.getSongCountString(context, songCount)
);
} }
@NonNull @NonNull
public static String getAlbumInfoString(@NonNull final Context context, @NonNull final Album album) { public static String getAlbumInfoString(@NonNull final Context context, @NonNull final Album album) {
int songCount = album.getSongCount(); return album.artistName;
return MusicUtil.buildInfoString(
album.getArtistName(),
MusicUtil.getSongCountString(context, songCount)
);
} }
@NonNull @NonNull
public static String getSongInfoString(@NonNull final Song song) { public static String getSongInfoString(@NonNull final Song song) {
return MusicUtil.buildInfoString( return song.albumName;
song.artistName,
song.albumName
);
} }
@NonNull @NonNull
@ -126,18 +109,18 @@ public class MusicUtil {
} }
@NonNull @NonNull
public static String buildInfoString(@Nullable final String string1, @Nullable final String string2) { public static String buildInfoString(@Nullable final String one, @Nullable final String two) {
// Skip empty strings // skip empty strings
if (TextUtils.isEmpty(string1)) { if (TextUtils.isEmpty(one)) {
//noinspection ConstantConditions // noinspection ConstantConditions
return TextUtils.isEmpty(string2) ? "" : string2; return TextUtils.isEmpty(two) ? "" : two;
} }
if (TextUtils.isEmpty(string2)) { if (TextUtils.isEmpty(two)) {
//noinspection ConstantConditions // noinspection ConstantConditions
return TextUtils.isEmpty(string1) ? "" : string1; return TextUtils.isEmpty(one) ? "" : one;
} }
return string1 + "" + string2; return one + "" + two;
} }
// iTunes uses for example 1002 for track 2 CD1 or 3011 for track 11 CD3. // iTunes uses for example 1002 for track 2 CD1 or 3011 for track 11 CD3.
@ -150,24 +133,22 @@ public class MusicUtil {
return playlist.name != null && playlist.name.equals(context.getString(R.string.favorites)); return playlist.name != null && playlist.name.equals(context.getString(R.string.favorites));
} }
public static Playlist getFavoritesPlaylist(@NonNull final Context context) {
return new Playlist();
}
private static Playlist getOrCreateFavoritesPlaylist(@NonNull final Context context) {
return new Playlist();
}
public static boolean isFavorite(@NonNull final Context context, @NonNull final Song song) {
return false;
}
public static void toggleFavorite(@NonNull final Context context, @NonNull final Song song) { public static void toggleFavorite(@NonNull final Context context, @NonNull final Song song) {
if (isFavorite(context, song)) { song.favorite = !song.favorite;
PlaylistsUtil.removeFromPlaylist(context, song, getFavoritesPlaylist(context).id);
} else { String user = App.getApiClient().getCurrentUserId();
PlaylistsUtil.addToPlaylist(context, song, getOrCreateFavoritesPlaylist(context).id, false); App.getApiClient().UpdateFavoriteStatusAsync(song.id, user, song.favorite, new Response<UserItemDataDto>() {
@Override
public void onResponse(UserItemDataDto data) {
song.favorite = data.getIsFavorite();
} }
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
}
);
} }
@NonNull @NonNull

View file

@ -11,6 +11,7 @@ import com.kabouzeid.gramophone.model.Song;
import org.jellyfin.apiclient.interaction.Response; import org.jellyfin.apiclient.interaction.Response;
import org.jellyfin.apiclient.model.dto.BaseItemDto; import org.jellyfin.apiclient.model.dto.BaseItemDto;
import org.jellyfin.apiclient.model.querying.ArtistsQuery; import org.jellyfin.apiclient.model.querying.ArtistsQuery;
import org.jellyfin.apiclient.model.querying.ItemFields;
import org.jellyfin.apiclient.model.querying.ItemQuery; import org.jellyfin.apiclient.model.querying.ItemQuery;
import org.jellyfin.apiclient.model.querying.ItemsByNameQuery; import org.jellyfin.apiclient.model.querying.ItemsByNameQuery;
import org.jellyfin.apiclient.model.querying.ItemsResult; import org.jellyfin.apiclient.model.querying.ItemsResult;
@ -155,6 +156,7 @@ public class QueryUtil {
public static void getArtists(MediaCallback callback) { public static void getArtists(MediaCallback callback) {
ArtistsQuery query = new ArtistsQuery(); ArtistsQuery query = new ArtistsQuery();
query.setFields(new ItemFields[]{ItemFields.Genres});
query.setUserId(App.getApiClient().getCurrentUserId()); query.setUserId(App.getApiClient().getCurrentUserId());
query.setLimit(100); query.setLimit(100);
query.setRecursive(true); query.setRecursive(true);