mirror of
https://github.com/antebudimir/tempus.git
synced 2025-12-31 17:43:32 +00:00
Saving play history. The tracks are saved in the db at the time of playback and every week a list of the most played tracks is generated in the home page in grid format
This commit is contained in:
parent
6a1c5d2ce3
commit
ff8bf4f6bf
14 changed files with 646 additions and 55 deletions
|
|
@ -0,0 +1,98 @@
|
|||
package com.cappielloantonio.play.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.media3.session.MediaBrowser;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.cappielloantonio.play.R;
|
||||
import com.cappielloantonio.play.glide.CustomGlideRequest;
|
||||
import com.cappielloantonio.play.model.Chronology;
|
||||
import com.cappielloantonio.play.model.Media;
|
||||
import com.cappielloantonio.play.service.MediaManager;
|
||||
import com.cappielloantonio.play.ui.activity.MainActivity;
|
||||
import com.cappielloantonio.play.util.MappingUtil;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GridTrackAdapter extends RecyclerView.Adapter<GridTrackAdapter.ViewHolder> {
|
||||
private static final String TAG = "SimilarTrackAdapter";
|
||||
|
||||
private final MainActivity activity;
|
||||
private final Context context;
|
||||
private final LayoutInflater mInflater;
|
||||
|
||||
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
|
||||
private List<Chronology> items;
|
||||
|
||||
public GridTrackAdapter(MainActivity activity, Context context) {
|
||||
this.activity = activity;
|
||||
this.context = context;
|
||||
this.mInflater = LayoutInflater.from(context);
|
||||
this.items = new ArrayList<>();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = mInflater.inflate(R.layout.item_home_grid_track, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
Chronology item = items.get(position);
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(context, item.getCoverArtId(), CustomGlideRequest.SONG_PIC, null)
|
||||
.build()
|
||||
.transform(new CenterCrop(), new RoundedCorners(CustomGlideRequest.CORNER_RADIUS))
|
||||
.into(holder.cover);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
public Chronology getItem(int position) {
|
||||
return items.get(position);
|
||||
}
|
||||
|
||||
public void setItems(List<Chronology> items) {
|
||||
this.items = items;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void setMediaBrowserListenableFuture(ListenableFuture<MediaBrowser> mediaBrowserListenableFuture) {
|
||||
this.mediaBrowserListenableFuture = mediaBrowserListenableFuture;
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
ImageView cover;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
cover = itemView.findViewById(R.id.track_cover_image_view);
|
||||
|
||||
itemView.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
List<Media> media = MappingUtil.mapChronology(items);
|
||||
MediaManager.startQueue(mediaBrowserListenableFuture, context, media, getBindingAdapterPosition());
|
||||
activity.setBottomSheetInPeek(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,11 +8,13 @@ import androidx.room.Database;
|
|||
import androidx.room.Room;
|
||||
import androidx.room.RoomDatabase;
|
||||
|
||||
import com.cappielloantonio.play.database.dao.ChronologyDao;
|
||||
import com.cappielloantonio.play.database.dao.DownloadDao;
|
||||
import com.cappielloantonio.play.database.dao.PlaylistDao;
|
||||
import com.cappielloantonio.play.database.dao.QueueDao;
|
||||
import com.cappielloantonio.play.database.dao.RecentSearchDao;
|
||||
import com.cappielloantonio.play.database.dao.ServerDao;
|
||||
import com.cappielloantonio.play.model.Chronology;
|
||||
import com.cappielloantonio.play.model.Download;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
import com.cappielloantonio.play.model.Queue;
|
||||
|
|
@ -21,9 +23,9 @@ import com.cappielloantonio.play.model.Server;
|
|||
|
||||
@SuppressLint("RestrictedApi")
|
||||
@Database(
|
||||
version = 41,
|
||||
entities = {Queue.class, Server.class, RecentSearch.class, Download.class, Playlist.class}
|
||||
// autoMigrations = {@AutoMigration(from = 39, to = 40)}
|
||||
version = 42,
|
||||
entities = {Queue.class, Server.class, RecentSearch.class, Download.class, Playlist.class, Chronology.class},
|
||||
autoMigrations = {@AutoMigration(from = 41, to = 42)}
|
||||
)
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
private static final String TAG = "AppDatabase";
|
||||
|
|
@ -50,4 +52,6 @@ public abstract class AppDatabase extends RoomDatabase {
|
|||
public abstract DownloadDao downloadDao();
|
||||
|
||||
public abstract PlaylistDao playlistDao();
|
||||
|
||||
public abstract ChronologyDao chronologyDao();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package com.cappielloantonio.play.database.dao;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
|
||||
import com.cappielloantonio.play.model.Chronology;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface ChronologyDao {
|
||||
@Query("SELECT * FROM chronology WHERE timestamp >= :startDate AND timestamp < :endDate GROUP BY id ORDER BY COUNT(id) DESC LIMIT 9")
|
||||
LiveData<List<Chronology>> getAllFrom(long startDate, long endDate);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
void insert(Chronology chronologyObject);
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.cappielloantonio.play.helper.recyclerview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
public class SquareLayout extends RelativeLayout {
|
||||
public SquareLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public SquareLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public SquareLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public SquareLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
package com.cappielloantonio.play.model;
|
||||
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
@Entity(tableName = "chronology")
|
||||
public class Chronology {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
private int uuid;
|
||||
|
||||
@ColumnInfo(name = "id")
|
||||
private String trackId;
|
||||
|
||||
@ColumnInfo(name = "title")
|
||||
private String title;
|
||||
|
||||
@ColumnInfo(name = "albumId")
|
||||
private String albumId;
|
||||
|
||||
@ColumnInfo(name = "albumName")
|
||||
private String albumName;
|
||||
|
||||
@ColumnInfo(name = "artistId")
|
||||
private String artistId;
|
||||
|
||||
@ColumnInfo(name = "artistName")
|
||||
private String artistName;
|
||||
|
||||
@ColumnInfo(name = "cover_art_id")
|
||||
private String coverArtId;
|
||||
|
||||
@ColumnInfo(name = "duration")
|
||||
private long duration;
|
||||
|
||||
@ColumnInfo(name = "container")
|
||||
private String container;
|
||||
|
||||
@ColumnInfo(name = "bitrate")
|
||||
private int bitrate;
|
||||
|
||||
@ColumnInfo(name = "extension")
|
||||
private String extension;
|
||||
|
||||
@ColumnInfo(name = "timestamp")
|
||||
private Long timestamp;
|
||||
|
||||
public Chronology(String trackId, String title, String albumId, String albumName, String artistId, String artistName, String coverArtId, long duration, String container, int bitrate, String extension) {
|
||||
this.trackId = trackId;
|
||||
this.title = title;
|
||||
this.albumId = albumId;
|
||||
this.albumName = albumName;
|
||||
this.artistId = artistId;
|
||||
this.artistName = artistName;
|
||||
this.coverArtId = coverArtId;
|
||||
this.duration = duration;
|
||||
this.container = container;
|
||||
this.bitrate = bitrate;
|
||||
this.extension = extension;
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public int getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUuid(int uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String getTrackId() {
|
||||
return trackId;
|
||||
}
|
||||
|
||||
public void setTrackId(String trackId) {
|
||||
this.trackId = trackId;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getAlbumId() {
|
||||
return albumId;
|
||||
}
|
||||
|
||||
public void setAlbumId(String albumId) {
|
||||
this.albumId = albumId;
|
||||
}
|
||||
|
||||
public String getAlbumName() {
|
||||
return albumName;
|
||||
}
|
||||
|
||||
public void setAlbumName(String albumName) {
|
||||
this.albumName = albumName;
|
||||
}
|
||||
|
||||
public String getArtistId() {
|
||||
return artistId;
|
||||
}
|
||||
|
||||
public void setArtistId(String artistId) {
|
||||
this.artistId = artistId;
|
||||
}
|
||||
|
||||
public String getArtistName() {
|
||||
return artistName;
|
||||
}
|
||||
|
||||
public void setArtistName(String artistName) {
|
||||
this.artistName = artistName;
|
||||
}
|
||||
|
||||
public String getCoverArtId() {
|
||||
return coverArtId;
|
||||
}
|
||||
|
||||
public void setCoverArtId(String coverArtId) {
|
||||
this.coverArtId = coverArtId;
|
||||
}
|
||||
|
||||
public long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(long duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public String getContainer() {
|
||||
return container;
|
||||
}
|
||||
|
||||
public void setContainer(String container) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
public int getBitrate() {
|
||||
return bitrate;
|
||||
}
|
||||
|
||||
public void setBitrate(int bitrate) {
|
||||
this.bitrate = bitrate;
|
||||
}
|
||||
|
||||
public String getExtension() {
|
||||
return extension;
|
||||
}
|
||||
|
||||
public void setExtension(String extension) {
|
||||
this.extension = extension;
|
||||
}
|
||||
|
||||
public Long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(Long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
|
@ -85,6 +85,7 @@ public class Media implements Parcelable {
|
|||
this.playCount = 0;
|
||||
this.lastPlay = 0;
|
||||
this.rating = child.getUserRating() != null ? child.getUserRating() : 0;
|
||||
// this.type = MEDIA_TYPE_MUSIC;
|
||||
this.type = child.getType();
|
||||
}
|
||||
|
||||
|
|
@ -106,6 +107,7 @@ public class Media implements Parcelable {
|
|||
this.container = podcastEpisode.getContentType();
|
||||
this.bitrate = podcastEpisode.getBitRate();
|
||||
this.extension = podcastEpisode.getSuffix();
|
||||
// this.type = MEDIA_TYPE_PODCAST;
|
||||
this.type = podcastEpisode.getType();
|
||||
}
|
||||
|
||||
|
|
@ -143,6 +145,21 @@ public class Media implements Parcelable {
|
|||
this.type = download.getType();
|
||||
}
|
||||
|
||||
public Media(Chronology item) {
|
||||
this.id = item.getTrackId();
|
||||
this.title = item.getTitle();
|
||||
this.albumId = item.getAlbumId();
|
||||
this.albumName = item.getAlbumName();
|
||||
this.artistId = item.getArtistId();
|
||||
this.artistName = item.getArtistName();
|
||||
this.coverArtId = item.getCoverArtId();
|
||||
this.duration = item.getDuration();
|
||||
this.container = item.getContainer();
|
||||
this.bitrate = item.getBitrate();
|
||||
this.extension = item.getExtension();
|
||||
this.type = MEDIA_TYPE_MUSIC;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
package com.cappielloantonio.play.repository;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.cappielloantonio.play.database.AppDatabase;
|
||||
import com.cappielloantonio.play.database.dao.ChronologyDao;
|
||||
import com.cappielloantonio.play.model.Chronology;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
public class ChronologyRepository {
|
||||
private static final String TAG = "ChronologyRepository";
|
||||
|
||||
private final ChronologyDao chronologyDao;
|
||||
|
||||
public ChronologyRepository(Application application) {
|
||||
AppDatabase database = AppDatabase.getInstance(application);
|
||||
chronologyDao = database.chronologyDao();
|
||||
}
|
||||
|
||||
public LiveData<List<Chronology>> getThisWeek() {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
|
||||
Calendar first = (Calendar) calendar.clone();
|
||||
first.add(Calendar.DAY_OF_WEEK, first.getFirstDayOfWeek() - first.get(Calendar.DAY_OF_WEEK));
|
||||
|
||||
Calendar last = (Calendar) first.clone();
|
||||
last.add(Calendar.DAY_OF_YEAR, 6);
|
||||
|
||||
return chronologyDao.getAllFrom(first.getTime().getTime(), last.getTime().getTime());
|
||||
}
|
||||
|
||||
public LiveData<List<Chronology>> getLastWeek() {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
|
||||
Calendar first = (Calendar) calendar.clone();
|
||||
first.add(Calendar.DAY_OF_WEEK, first.getFirstDayOfWeek() - first.get(Calendar.DAY_OF_WEEK) - 6);
|
||||
|
||||
Calendar last = (Calendar) first.clone();
|
||||
last.add(Calendar.DAY_OF_YEAR, 6);
|
||||
|
||||
return chronologyDao.getAllFrom(first.getTime().getTime(), last.getTime().getTime());
|
||||
}
|
||||
|
||||
public void insert(Chronology item) {
|
||||
InsertThreadSafe insert = new InsertThreadSafe(chronologyDao, item);
|
||||
Thread thread = new Thread(insert);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
private static class InsertThreadSafe implements Runnable {
|
||||
private final ChronologyDao chronologyDao;
|
||||
private final Chronology item;
|
||||
|
||||
public InsertThreadSafe(ChronologyDao chronologyDao, Chronology item) {
|
||||
this.chronologyDao = chronologyDao;
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
chronologyDao.insert(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ import androidx.media3.session.MediaBrowser;
|
|||
import com.cappielloantonio.play.App;
|
||||
import com.cappielloantonio.play.interfaces.MediaIndexCallback;
|
||||
import com.cappielloantonio.play.model.Media;
|
||||
import com.cappielloantonio.play.repository.ChronologyRepository;
|
||||
import com.cappielloantonio.play.repository.QueueRepository;
|
||||
import com.cappielloantonio.play.repository.SongRepository;
|
||||
import com.cappielloantonio.play.util.MappingUtil;
|
||||
|
|
@ -289,21 +290,22 @@ public class MediaManager {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
public static void setLastPlayedTimestamp(MediaItem mediaItem) {
|
||||
if (mediaItem != null) getQueueRepository().setLastPlayedTimestamp(mediaItem.mediaId);
|
||||
}
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
public static void setPlayingPausedTimestamp(MediaItem mediaItem, long ms) {
|
||||
if (mediaItem != null) getQueueRepository().setPlayingPausedTimestamp(mediaItem.mediaId, ms);
|
||||
}
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
public static void scrobble(MediaItem mediaItem) {
|
||||
if (mediaItem != null) getSongRepository().scrobble(mediaItem.mediaMetadata.extras.getString("id"));
|
||||
}
|
||||
|
||||
public static void saveChronology(MediaItem mediaItem) {
|
||||
if (mediaItem != null) getChronologyRepository().insert(MappingUtil.mapChronology(mediaItem));
|
||||
}
|
||||
|
||||
private static QueueRepository getQueueRepository() {
|
||||
return new QueueRepository(App.getInstance());
|
||||
}
|
||||
|
|
@ -312,6 +314,10 @@ public class MediaManager {
|
|||
return new SongRepository(App.getInstance());
|
||||
}
|
||||
|
||||
private static ChronologyRepository getChronologyRepository() {
|
||||
return new ChronologyRepository(App.getInstance());
|
||||
}
|
||||
|
||||
private static void enqueueDatabase(List<Media> media, boolean reset, int afterIndex) {
|
||||
getQueueRepository().insertAll(media, reset, afterIndex);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,20 +9,21 @@ import android.os.Bundle
|
|||
import androidx.media3.cast.CastPlayer
|
||||
import androidx.media3.cast.SessionAvailabilityListener
|
||||
import androidx.media3.common.*
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.session.*
|
||||
import androidx.media3.session.MediaSession.ControllerInfo
|
||||
import com.cappielloantonio.play.App
|
||||
import com.cappielloantonio.play.R
|
||||
import com.cappielloantonio.play.model.Media
|
||||
import com.cappielloantonio.play.repository.QueueRepository
|
||||
import com.cappielloantonio.play.ui.activity.MainActivity
|
||||
import com.cappielloantonio.play.util.UIUtil
|
||||
import com.google.android.gms.cast.framework.CastContext
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
|
||||
|
||||
@UnstableApi
|
||||
class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
||||
private val librarySessionCallback = CustomMediaLibrarySessionCallback()
|
||||
|
||||
|
|
@ -49,7 +50,10 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
|||
initializeMediaLibrarySession()
|
||||
initializePlayerListener()
|
||||
|
||||
setPlayer(null, if (castPlayer.isCastSessionAvailable) castPlayer else player)
|
||||
setPlayer(
|
||||
null,
|
||||
if (this::castPlayer.isInitialized && castPlayer.isCastSessionAvailable) castPlayer else player
|
||||
)
|
||||
}
|
||||
|
||||
override fun onGetSession(controllerInfo: ControllerInfo): MediaLibrarySession {
|
||||
|
|
@ -161,7 +165,7 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
|||
|
||||
override fun onAddMediaItems(
|
||||
mediaSession: MediaSession,
|
||||
controller: MediaSession.ControllerInfo,
|
||||
controller: ControllerInfo,
|
||||
mediaItems: List<MediaItem>
|
||||
): ListenableFuture<List<MediaItem>> {
|
||||
val updatedMediaItems = mediaItems.map {
|
||||
|
|
@ -198,8 +202,10 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
|||
}
|
||||
|
||||
private fun initializeCastPlayer() {
|
||||
castPlayer = CastPlayer(CastContext.getSharedInstance(this))
|
||||
castPlayer.setSessionAvailabilityListener(this)
|
||||
if (UIUtil.isCastApiAvailable(this)) {
|
||||
castPlayer = CastPlayer(CastContext.getSharedInstance(this))
|
||||
castPlayer.setSessionAvailabilityListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeMediaLibrarySession() {
|
||||
|
|
@ -224,8 +230,10 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
|||
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
|
||||
if (mediaItem == null) return
|
||||
MediaManager.setLastPlayedTimestamp(mediaItem)
|
||||
if (mediaItem.mediaMetadata.extras!!.getString("mediaType") == Media.MEDIA_TYPE_MUSIC)
|
||||
if (mediaItem.mediaMetadata.extras!!.getString("mediaType") == Media.MEDIA_TYPE_MUSIC) {
|
||||
MediaManager.scrobble(mediaItem)
|
||||
MediaManager.saveChronology(mediaItem)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
||||
|
|
@ -246,8 +254,8 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
|||
}
|
||||
|
||||
private fun releasePlayer() {
|
||||
castPlayer.setSessionAvailabilityListener(null)
|
||||
castPlayer.release()
|
||||
if (this::castPlayer.isInitialized) castPlayer.setSessionAvailabilityListener(null)
|
||||
if (this::castPlayer.isInitialized) castPlayer.release()
|
||||
player.release()
|
||||
mediaLibrarySession.release()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.cappielloantonio.play.ui.fragment;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ComponentName;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
|
|
@ -31,6 +30,7 @@ import com.cappielloantonio.play.adapter.AlbumHorizontalAdapter;
|
|||
import com.cappielloantonio.play.adapter.ArtistAdapter;
|
||||
import com.cappielloantonio.play.adapter.ArtistHorizontalAdapter;
|
||||
import com.cappielloantonio.play.adapter.DiscoverSongAdapter;
|
||||
import com.cappielloantonio.play.adapter.GridTrackAdapter;
|
||||
import com.cappielloantonio.play.adapter.PodcastEpisodeAdapter;
|
||||
import com.cappielloantonio.play.adapter.SimilarTrackAdapter;
|
||||
import com.cappielloantonio.play.adapter.SongHorizontalAdapter;
|
||||
|
|
@ -38,6 +38,7 @@ import com.cappielloantonio.play.adapter.YearAdapter;
|
|||
import com.cappielloantonio.play.databinding.FragmentHomeBinding;
|
||||
import com.cappielloantonio.play.helper.recyclerview.CustomLinearSnapHelper;
|
||||
import com.cappielloantonio.play.helper.recyclerview.DotsIndicatorDecoration;
|
||||
import com.cappielloantonio.play.helper.recyclerview.GridItemDecoration;
|
||||
import com.cappielloantonio.play.model.Album;
|
||||
import com.cappielloantonio.play.model.Artist;
|
||||
import com.cappielloantonio.play.model.Media;
|
||||
|
|
@ -71,6 +72,7 @@ public class HomeFragment extends Fragment {
|
|||
private AlbumHorizontalAdapter newReleasesAlbumAdapter;
|
||||
private YearAdapter yearAdapter;
|
||||
private PodcastEpisodeAdapter podcastEpisodeAdapter;
|
||||
private GridTrackAdapter gridTrackAdapter;
|
||||
|
||||
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
|
||||
|
||||
|
|
@ -119,6 +121,7 @@ public class HomeFragment extends Fragment {
|
|||
initRecentAddedAlbumView();
|
||||
initPinnedPlaylistsView();
|
||||
initNewestPodcastsView();
|
||||
initGridView();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -258,11 +261,14 @@ public class HomeFragment extends Fragment {
|
|||
bind.discoverSongViewPager.setOffscreenPageLimit(1);
|
||||
homeViewModel.getDiscoverSongSample(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), songs -> {
|
||||
if (songs == null) {
|
||||
if (bind != null) bind.homeDiscoveryPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null)
|
||||
bind.homeDiscoveryPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeDiscoverSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.homeDiscoveryPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null) bind.homeDiscoverSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeDiscoveryPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeDiscoverSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
discoverSongAdapter.setItems(songs);
|
||||
}
|
||||
|
|
@ -279,11 +285,14 @@ public class HomeFragment extends Fragment {
|
|||
bind.similarTracksRecyclerView.setAdapter(similarMusicAdapter);
|
||||
homeViewModel.getStarredTracksSample(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), songs -> {
|
||||
if (songs == null) {
|
||||
if (bind != null) bind.homeSimilarTracksPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null)
|
||||
bind.homeSimilarTracksPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeSimilarTracksSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.homeSimilarTracksPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null) bind.homeSimilarTracksSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeSimilarTracksPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeSimilarTracksSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
similarMusicAdapter.setItems(songs);
|
||||
}
|
||||
|
|
@ -301,11 +310,14 @@ public class HomeFragment extends Fragment {
|
|||
bind.radioArtistRecyclerView.setAdapter(radioArtistAdapter);
|
||||
homeViewModel.getStarredArtistsSample(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), artists -> {
|
||||
if (artists == null) {
|
||||
if (bind != null) bind.homeRadioArtistPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null)
|
||||
bind.homeRadioArtistPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeRadioArtistSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.homeRadioArtistPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null) bind.homeRadioArtistSector.setVisibility(!artists.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeRadioArtistPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeRadioArtistSector.setVisibility(!artists.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
radioArtistAdapter.setItems(artists);
|
||||
}
|
||||
|
|
@ -322,11 +334,14 @@ public class HomeFragment extends Fragment {
|
|||
bind.starredTracksRecyclerView.setAdapter(starredSongAdapter);
|
||||
homeViewModel.getStarredTracks(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), songs -> {
|
||||
if (songs == null) {
|
||||
if (bind != null) bind.starredTracksPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null)
|
||||
bind.starredTracksPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.starredTracksSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.starredTracksPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null) bind.starredTracksSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.starredTracksPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.starredTracksSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.starredTracksRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), UIUtil.getSpanCount(songs.size(), 5), GridLayoutManager.HORIZONTAL, false));
|
||||
|
||||
|
|
@ -354,11 +369,14 @@ public class HomeFragment extends Fragment {
|
|||
bind.starredAlbumsRecyclerView.setAdapter(starredAlbumAdapter);
|
||||
homeViewModel.getStarredAlbums(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), albums -> {
|
||||
if (albums == null) {
|
||||
if (bind != null) bind.starredAlbumsPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null)
|
||||
bind.starredAlbumsPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.starredAlbumsSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.starredAlbumsPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null) bind.starredAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.starredAlbumsPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.starredAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.starredAlbumsRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), UIUtil.getSpanCount(albums.size(), 5), GridLayoutManager.HORIZONTAL, false));
|
||||
|
||||
|
|
@ -386,11 +404,14 @@ public class HomeFragment extends Fragment {
|
|||
bind.starredArtistsRecyclerView.setAdapter(starredArtistAdapter);
|
||||
homeViewModel.getStarredArtists(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), artists -> {
|
||||
if (artists == null) {
|
||||
if (bind != null) bind.starredArtistsPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null)
|
||||
bind.starredArtistsPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.starredArtistsSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.starredArtistsPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null) bind.starredArtistsSector.setVisibility(!artists.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.starredArtistsPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.starredArtistsSector.setVisibility(!artists.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.starredArtistsRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), UIUtil.getSpanCount(artists.size(), 5), GridLayoutManager.HORIZONTAL, false));
|
||||
|
||||
|
|
@ -418,11 +439,14 @@ public class HomeFragment extends Fragment {
|
|||
bind.newReleasesRecyclerView.setAdapter(newReleasesAlbumAdapter);
|
||||
homeViewModel.getRecentlyReleasedAlbums(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), albums -> {
|
||||
if (albums == null) {
|
||||
if (bind != null) bind.homeNewReleasesPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null)
|
||||
bind.homeNewReleasesPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeNewReleasesSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.homeNewReleasesPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null) bind.homeNewReleasesSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeNewReleasesPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeNewReleasesSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.newReleasesRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), UIUtil.getSpanCount(albums.size(), 5), GridLayoutManager.HORIZONTAL, false));
|
||||
|
||||
|
|
@ -457,11 +481,14 @@ public class HomeFragment extends Fragment {
|
|||
bind.yearsRecyclerView.setAdapter(yearAdapter);
|
||||
homeViewModel.getYearList(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), years -> {
|
||||
if (years == null) {
|
||||
if (bind != null) bind.homeFlashbackPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null)
|
||||
bind.homeFlashbackPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeFlashbackSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.homeFlashbackPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null) bind.homeFlashbackSector.setVisibility(!years.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeFlashbackPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeFlashbackSector.setVisibility(!years.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
yearAdapter.setItems(years);
|
||||
}
|
||||
|
|
@ -479,12 +506,15 @@ public class HomeFragment extends Fragment {
|
|||
bind.mostPlayedAlbumsRecyclerView.setAdapter(mostPlayedAlbumAdapter);
|
||||
homeViewModel.getMostPlayedAlbums(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), albums -> {
|
||||
if (albums == null) {
|
||||
if (bind != null) bind.homeMostPlayedAlbumsPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null)
|
||||
bind.homeMostPlayedAlbumsPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeMostPlayedAlbumsSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.homeMostPlayedAlbumsPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null) bind.homeMostPlayedAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (albums.size() < 10) reorder();
|
||||
if (bind != null)
|
||||
bind.homeMostPlayedAlbumsPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeMostPlayedAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (albums.size() < 5) reorder();
|
||||
|
||||
mostPlayedAlbumAdapter.setItems(albums);
|
||||
}
|
||||
|
|
@ -502,11 +532,14 @@ public class HomeFragment extends Fragment {
|
|||
bind.recentlyPlayedAlbumsRecyclerView.setAdapter(recentlyPlayedAlbumAdapter);
|
||||
homeViewModel.getRecentlyPlayedAlbumList(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), albums -> {
|
||||
if (albums == null) {
|
||||
if (bind != null) bind.homeRecentlyPlayedAlbumsPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null)
|
||||
bind.homeRecentlyPlayedAlbumsPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeRecentlyPlayedAlbumsSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.homeRecentlyPlayedAlbumsPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null) bind.homeRecentlyPlayedAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeRecentlyPlayedAlbumsPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeRecentlyPlayedAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
recentlyPlayedAlbumAdapter.setItems(albums);
|
||||
}
|
||||
|
|
@ -524,11 +557,14 @@ public class HomeFragment extends Fragment {
|
|||
bind.recentlyAddedAlbumsRecyclerView.setAdapter(recentlyAddedAlbumAdapter);
|
||||
homeViewModel.getMostRecentlyAddedAlbums(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), albums -> {
|
||||
if (albums == null) {
|
||||
if (bind != null) bind.homeRecentlyAddedAlbumsPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null)
|
||||
bind.homeRecentlyAddedAlbumsPlaceholder.placeholder.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.homeRecentlyAddedAlbumsSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.homeRecentlyAddedAlbumsPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null) bind.homeRecentlyAddedAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeRecentlyAddedAlbumsPlaceholder.placeholder.setVisibility(View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeRecentlyAddedAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
recentlyAddedAlbumAdapter.setItems(albums);
|
||||
}
|
||||
|
|
@ -606,7 +642,8 @@ public class HomeFragment extends Fragment {
|
|||
if (podcastEpisodes == null) {
|
||||
if (bind != null) bind.homeNewestPodcastsSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.homeNewestPodcastsSector.setVisibility(!podcastEpisodes.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if (bind != null)
|
||||
bind.homeNewestPodcastsSector.setVisibility(!podcastEpisodes.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
podcastEpisodeAdapter.setItems(podcastEpisodes);
|
||||
}
|
||||
|
|
@ -615,6 +652,26 @@ public class HomeFragment extends Fragment {
|
|||
setSlideViewOffset(bind.newestPodcastsViewPager, 20, 16);
|
||||
}
|
||||
|
||||
private void initGridView() {
|
||||
bind.gridTracksRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 3));
|
||||
bind.gridTracksRecyclerView.addItemDecoration(new GridItemDecoration(3, 8, false));
|
||||
bind.gridTracksRecyclerView.setHasFixedSize(true);
|
||||
|
||||
gridTrackAdapter = new GridTrackAdapter(activity, requireContext());
|
||||
bind.gridTracksRecyclerView.setAdapter(gridTrackAdapter);
|
||||
|
||||
homeViewModel.getGridSongSample(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), chronologies -> {
|
||||
if (chronologies == null || chronologies.size() == 0) {
|
||||
if (bind != null) bind.homeGridTracksSector.setVisibility(View.GONE);
|
||||
if (bind != null) bind.afterGridDivider.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null) bind.homeGridTracksSector.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.afterGridDivider.setVisibility(View.VISIBLE);
|
||||
gridTrackAdapter.setItems(chronologies);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setSlideViewOffset(ViewPager2 viewPager, float pageOffset, float pageMargin) {
|
||||
viewPager.setPageTransformer((page, position) -> {
|
||||
float myOffset = position * -(2 * pageOffset + pageMargin);
|
||||
|
|
@ -634,7 +691,12 @@ public class HomeFragment extends Fragment {
|
|||
if (bind != null) {
|
||||
bind.homeLinearLayoutContainer.removeAllViews();
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeDiscoverSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeSimilarTracksSector);
|
||||
// bind.homeLinearLayoutContainer.addView(bind.homeSimilarTracksSector);
|
||||
// bind.homeLinearLayoutContainer.addView(bind.homeRadioArtistSector);
|
||||
// bind.homeLinearLayoutContainer.addView(bind.homeGridTracksSector);
|
||||
// bind.homeLinearLayoutContainer.addView(bind.starredTracksSector);
|
||||
// bind.homeLinearLayoutContainer.addView(bind.starredAlbumsSector);
|
||||
// bind.homeLinearLayoutContainer.addView(bind.starredArtistsSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeRecentlyAddedAlbumsSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeFlashbackSector);
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeMostPlayedAlbumsSector);
|
||||
|
|
@ -643,7 +705,6 @@ public class HomeFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
private void initializeMediaBrowser() {
|
||||
mediaBrowserListenableFuture = new MediaBrowser.Builder(requireContext(), new SessionToken(requireContext(), new ComponentName(requireContext(), MediaService.class))).buildAsync();
|
||||
}
|
||||
|
|
@ -658,5 +719,6 @@ public class HomeFragment extends Fragment {
|
|||
starredSongAdapter.setMediaBrowserListenableFuture(mediaBrowserListenableFuture);
|
||||
radioArtistAdapter.setMediaBrowserListenableFuture(mediaBrowserListenableFuture);
|
||||
podcastEpisodeAdapter.setMediaBrowserListenableFuture(mediaBrowserListenableFuture);
|
||||
gridTrackAdapter.setMediaBrowserListenableFuture(mediaBrowserListenableFuture);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
package com.cappielloantonio.play.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.MediaMetadata;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
|
||||
import com.cappielloantonio.play.model.Album;
|
||||
import com.cappielloantonio.play.model.Artist;
|
||||
import com.cappielloantonio.play.model.Chronology;
|
||||
import com.cappielloantonio.play.model.Download;
|
||||
import com.cappielloantonio.play.model.Media;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
|
|
@ -201,7 +203,7 @@ public class MappingUtil {
|
|||
return genres;
|
||||
}
|
||||
|
||||
@SuppressLint("UnsafeOptInUsageError")
|
||||
@OptIn(markerClass = UnstableApi.class)
|
||||
public static MediaItem mapMediaItem(Context context, Media media, boolean stream) {
|
||||
boolean isDownloaded = DownloadUtil.getDownloadTracker(context).isDownloaded(MusicUtil.getDownloadUri(media.getId()));
|
||||
|
||||
|
|
@ -211,6 +213,7 @@ public class MappingUtil {
|
|||
bundle.putString("artistId", media.getArtistId());
|
||||
bundle.putString("coverArtId", media.getCoverArtId());
|
||||
bundle.putString("mediaType", media.getType());
|
||||
bundle.putLong("duration", media.getDuration());
|
||||
bundle.putString("container", media.getContainer());
|
||||
bundle.putInt("bitrate", media.getBitrate());
|
||||
bundle.putString("extension", media.getExtension());
|
||||
|
|
@ -268,6 +271,36 @@ public class MappingUtil {
|
|||
return mediaItems;
|
||||
}
|
||||
|
||||
public static Chronology mapChronology(MediaItem item) {
|
||||
return new Chronology(
|
||||
item.mediaId,
|
||||
item.mediaMetadata.title.toString(),
|
||||
item.mediaMetadata.extras.get("albumId").toString(),
|
||||
item.mediaMetadata.albumTitle.toString(),
|
||||
item.mediaMetadata.extras.get("artistId").toString(),
|
||||
item.mediaMetadata.artist.toString(),
|
||||
item.mediaMetadata.extras.get("coverArtId").toString(),
|
||||
(long) item.mediaMetadata.extras.get("duration"),
|
||||
item.mediaMetadata.extras.get("container").toString(),
|
||||
(int) item.mediaMetadata.extras.get("bitrate"),
|
||||
item.mediaMetadata.extras.get("extension").toString()
|
||||
);
|
||||
}
|
||||
|
||||
public static ArrayList<Media> mapChronology(List<Chronology> items) {
|
||||
ArrayList<Media> songs = new ArrayList();
|
||||
|
||||
for (Chronology item : items) {
|
||||
songs.add(mapSong(item));
|
||||
}
|
||||
|
||||
return songs;
|
||||
}
|
||||
|
||||
public static Media mapSong(Chronology item) {
|
||||
return new Media(item);
|
||||
}
|
||||
|
||||
public static ArrayList<PodcastChannel> mapPodcastChannel(List<com.cappielloantonio.play.subsonic.models.PodcastChannel> subsonicPodcastChannels) {
|
||||
ArrayList<PodcastChannel> podcastChannels = new ArrayList();
|
||||
|
||||
|
|
|
|||
|
|
@ -11,10 +11,12 @@ import androidx.lifecycle.MutableLiveData;
|
|||
import com.cappielloantonio.play.App;
|
||||
import com.cappielloantonio.play.model.Album;
|
||||
import com.cappielloantonio.play.model.Artist;
|
||||
import com.cappielloantonio.play.model.Chronology;
|
||||
import com.cappielloantonio.play.model.Media;
|
||||
import com.cappielloantonio.play.model.Playlist;
|
||||
import com.cappielloantonio.play.repository.AlbumRepository;
|
||||
import com.cappielloantonio.play.repository.ArtistRepository;
|
||||
import com.cappielloantonio.play.repository.ChronologyRepository;
|
||||
import com.cappielloantonio.play.repository.PlaylistRepository;
|
||||
import com.cappielloantonio.play.repository.PodcastRepository;
|
||||
import com.cappielloantonio.play.repository.SongRepository;
|
||||
|
|
@ -33,6 +35,7 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
private final ArtistRepository artistRepository;
|
||||
private final PlaylistRepository playlistRepository;
|
||||
private final PodcastRepository podcastRepository;
|
||||
private final ChronologyRepository chronologyRepository;
|
||||
|
||||
private final MutableLiveData<List<Media>> dicoverSongSample = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<Album>> newReleasedAlbum = new MutableLiveData<>(null);
|
||||
|
|
@ -48,6 +51,8 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
private final MutableLiveData<List<Playlist>> pinnedPlaylists = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<Media>> newestPodcastEpisodes = new MutableLiveData<>(null);
|
||||
|
||||
private final MutableLiveData<List<Chronology>> thisGridTopSong = new MutableLiveData<>(null);
|
||||
|
||||
public HomeViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
|
||||
|
|
@ -56,6 +61,7 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
artistRepository = new ArtistRepository(application);
|
||||
playlistRepository = new PlaylistRepository(application);
|
||||
podcastRepository = new PodcastRepository(application);
|
||||
chronologyRepository = new ChronologyRepository(application);
|
||||
}
|
||||
|
||||
public LiveData<List<Media>> getDiscoverSongSample(LifecycleOwner owner) {
|
||||
|
|
@ -66,6 +72,21 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
return dicoverSongSample;
|
||||
}
|
||||
|
||||
public LiveData<List<Chronology>> getGridSongSample(LifecycleOwner owner) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
|
||||
|
||||
if (thisGridTopSong.getValue() == null) {
|
||||
if (dayOfMonth >= 7) {
|
||||
chronologyRepository.getThisWeek().observe(owner, thisGridTopSong::postValue);
|
||||
} else {
|
||||
chronologyRepository.getLastWeek().observe(owner, thisGridTopSong::postValue);
|
||||
}
|
||||
}
|
||||
|
||||
return thisGridTopSong;
|
||||
}
|
||||
|
||||
public LiveData<List<Album>> getRecentlyReleasedAlbums(LifecycleOwner owner) {
|
||||
if (newReleasedAlbum.getValue() == null) {
|
||||
int currentYear = Calendar.getInstance().get(Calendar.YEAR);
|
||||
|
|
|
|||
|
|
@ -171,6 +171,55 @@
|
|||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="12dp" />
|
||||
|
||||
<!-- Grid tracks -->
|
||||
<LinearLayout
|
||||
android:id="@+id/home_grid_tracks_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grid_tracks_pre_text_view"
|
||||
style="@style/TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="Last week"
|
||||
android:textAllCaps="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grid_tracks_text_view"
|
||||
style="@style/TitleLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="Your top songs" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/grid_tracks_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:clipToPadding="false"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/after_grid_divider"
|
||||
style="@style/Divider"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="12dp" />
|
||||
|
||||
<!-- Favorites -->
|
||||
<LinearLayout
|
||||
android:id="@+id/starred_tracks_sector"
|
||||
|
|
|
|||
11
app/src/main/res/layout/item_home_grid_track.xml
Normal file
11
app/src/main/res/layout/item_home_grid_track.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.cappielloantonio.play.helper.recyclerview.SquareLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/track_cover_image_view"
|
||||
android:layout_width="156dp"
|
||||
android:layout_height="156dp"
|
||||
android:layout_gravity="center" />
|
||||
</com.cappielloantonio.play.helper.recyclerview.SquareLayout>
|
||||
Loading…
Add table
Add a link
Reference in a new issue