Add settings to pin and unpin playlist in toolbar menu

This commit is contained in:
CappielloAntonio 2021-11-25 22:48:21 +01:00
parent afe0e0751c
commit e29b96d905
11 changed files with 170 additions and 5 deletions

View file

@ -8,18 +8,20 @@ import androidx.room.Room;
import androidx.room.RoomDatabase;
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.Download;
import com.cappielloantonio.play.model.Playlist;
import com.cappielloantonio.play.model.Queue;
import com.cappielloantonio.play.model.RecentSearch;
import com.cappielloantonio.play.model.Server;
@SuppressLint("RestrictedApi")
@Database(
version = 23,
entities = {Queue.class, Server.class, RecentSearch.class, Download.class}
version = 24,
entities = {Queue.class, Server.class, RecentSearch.class, Download.class, Playlist.class}
// autoMigrations = { @AutoMigration(from = 23, to = 24) }
)
public abstract class AppDatabase extends RoomDatabase {
@ -44,4 +46,6 @@ public abstract class AppDatabase extends RoomDatabase {
public abstract RecentSearchDao recentSearchDao();
public abstract DownloadDao downloadDao();
public abstract PlaylistDao playlistDao();
}

View file

@ -0,0 +1,24 @@
package com.cappielloantonio.play.database.dao;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import com.cappielloantonio.play.model.Playlist;
import java.util.List;
@Dao
public interface PlaylistDao {
@Query("SELECT * FROM playlist")
LiveData<List<Playlist>> getAll();
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Playlist playlist);
@Delete
void delete(Playlist playlist);
}

View file

@ -4,16 +4,34 @@ import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
@Entity(tableName = "playlist")
public class Playlist implements Parcelable {
public static final String ALL = "ALL";
public static final String DOWNLOADED = "DOWNLOADED";
@NonNull
@PrimaryKey
@ColumnInfo(name = "id")
private String id;
@ColumnInfo(name = "playlist_name")
private String name;
@Ignore
private String primary;
@Ignore
private String blurHash;
@Ignore
private int songCount;
@Ignore
private long duration;
public Playlist(com.cappielloantonio.play.subsonic.models.Playlist playlist) {
@ -25,11 +43,12 @@ public class Playlist implements Parcelable {
this.duration = playlist.getDuration();
}
public Playlist(String id, String name) {
public Playlist(@NonNull String id, String name) {
this.id = id;
this.name = name;
}
@NonNull
public String getId() {
return id;
}

View file

@ -3,10 +3,15 @@ package com.cappielloantonio.play.repository;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.cappielloantonio.play.App;
import com.cappielloantonio.play.database.AppDatabase;
import com.cappielloantonio.play.database.dao.PlaylistDao;
import com.cappielloantonio.play.database.dao.ServerDao;
import com.cappielloantonio.play.model.Playlist;
import com.cappielloantonio.play.model.Server;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.subsonic.models.SubsonicResponse;
import com.cappielloantonio.play.util.MappingUtil;
@ -21,9 +26,13 @@ import retrofit2.Response;
public class PlaylistRepository {
private final Application application;
private final PlaylistDao playlistDao;
public PlaylistRepository(Application application) {
this.application = application;
AppDatabase database = AppDatabase.getInstance(application);
this.playlistDao = database.playlistDao();
}
public MutableLiveData<List<Playlist>> getPlaylists(boolean random, int size) {
@ -144,4 +153,50 @@ public class PlaylistRepository {
}
});
}
public LiveData<List<Playlist>> getPinnedPlaylists() {
return playlistDao.getAll();
}
public void insert(Playlist playlist) {
InsertThreadSafe insert = new InsertThreadSafe(playlistDao, playlist);
Thread thread = new Thread(insert);
thread.start();
}
public void delete(Playlist playlist) {
DeleteThreadSafe delete = new DeleteThreadSafe(playlistDao, playlist);
Thread thread = new Thread(delete);
thread.start();
}
private static class InsertThreadSafe implements Runnable {
private final PlaylistDao playlistDao;
private final Playlist playlist;
public InsertThreadSafe(PlaylistDao playlistDao, Playlist playlist) {
this.playlistDao = playlistDao;
this.playlist = playlist;
}
@Override
public void run() {
playlistDao.insert(playlist);
}
}
private static class DeleteThreadSafe implements Runnable {
private final PlaylistDao playlistDao;
private final Playlist playlist;
public DeleteThreadSafe(PlaylistDao playlistDao, Playlist playlist) {
this.playlistDao = playlistDao;
this.playlist = playlist;
}
@Override
public void run() {
playlistDao.delete(playlist);
}
}
}

View file

@ -478,4 +478,8 @@ public class HomeFragment extends Fragment {
bind.homeLinearLayoutContainer.addView(bind.homeRecentlyPlayedAlbumsSector);
}
}
public void addPinnedPlaylistsView() {
}
}

View file

@ -20,7 +20,6 @@ import com.cappielloantonio.play.R;
import com.cappielloantonio.play.adapter.SongHorizontalAdapter;
import com.cappielloantonio.play.databinding.FragmentPlaylistPageBinding;
import com.cappielloantonio.play.glide.CustomGlideRequest;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.repository.QueueRepository;
import com.cappielloantonio.play.service.MusicPlayerRemote;
import com.cappielloantonio.play.ui.activity.MainActivity;
@ -29,7 +28,6 @@ import com.cappielloantonio.play.util.MusicUtil;
import com.cappielloantonio.play.viewmodel.PlaylistPageViewModel;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
public class PlaylistPageFragment extends Fragment {
@ -50,6 +48,7 @@ public class PlaylistPageFragment extends Fragment {
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.playlist_page_menu, menu);
initMenuOption(menu);
}
@Override
@ -90,6 +89,12 @@ public class PlaylistPageFragment extends Fragment {
}
});
return true;
} else if (item.getItemId() == R.id.action_pin_playlist) {
playlistPageViewModel.setPinned(true);
return true;
} else if (item.getItemId() == R.id.action_unpin_playlist) {
playlistPageViewModel.setPinned(false);
return true;
}
return false;
@ -100,6 +105,13 @@ public class PlaylistPageFragment extends Fragment {
playlistPageViewModel.setOffline(requireArguments().getBoolean("is_offline"));
}
private void initMenuOption(Menu menu) {
playlistPageViewModel.isPinned(requireActivity()).observe(requireActivity(), isPinned -> {
menu.findItem(R.id.action_unpin_playlist).setVisible(isPinned);
menu.findItem(R.id.action_pin_playlist).setVisible(!isPinned);
});
}
private void initAppBar() {
activity.setSupportActionBar(bind.animToolbar);

View file

@ -57,4 +57,18 @@ public class PlaylistPageViewModel extends AndroidViewModel {
public boolean isOffline() {
return isOffline;
}
public LiveData<Boolean> isPinned(FragmentActivity activity) {
MutableLiveData<Boolean> isPinnedLive = new MutableLiveData<>();
playlistRepository.getPinnedPlaylists().observe(activity, playlists -> isPinnedLive.postValue(playlists.contains(playlist)));
return isPinnedLive;
}
public void setPinned(boolean isNowPinned) {
if(isNowPinned) {
playlistRepository.insert(playlist);
} else {
playlistRepository.delete(playlist);
}
}
}

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/titleTextColor"
android:pathData="M16,9V4l1,0c0.55,0 1,-0.45 1,-1v0c0,-0.55 -0.45,-1 -1,-1H7C6.45,2 6,2.45 6,3v0c0,0.55 0.45,1 1,1l1,0v5c0,1.66 -1.34,3 -3,3h0v2h5.97v7l1,1l1,-1v-7H19v-2h0C17.34,12 16,10.66 16,9z"
android:fillType="evenOdd"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/titleTextColor"
android:pathData="M14,4v5c0,1.12 0.37,2.16 1,3H9c0.65,-0.86 1,-1.9 1,-3V4H14M17,2H7C6.45,2 6,2.45 6,3c0,0.55 0.45,1 1,1c0,0 0,0 0,0l1,0v5c0,1.66 -1.34,3 -3,3v2h5.97v7l1,1l1,-1v-7H19v-2c0,0 0,0 0,0c-1.66,0 -3,-1.34 -3,-3V4l1,0c0,0 0,0 0,0c0.55,0 1,-0.45 1,-1C18,2.45 17.55,2 17,2L17,2z"/>
</vector>

View file

@ -7,4 +7,16 @@
android:iconTint="@color/titleTextColor"
android:title="@string/menu_download_all_button"
app:showAsAction="never" />
<item
android:id="@+id/action_pin_playlist"
android:icon="@drawable/ic_pin_in"
android:iconTint="@color/titleTextColor"
android:title="@string/menu_pin_button"
app:showAsAction="never" />
<item
android:id="@+id/action_unpin_playlist"
android:icon="@drawable/ic_pin_out"
android:iconTint="@color/titleTextColor"
android:title="@string/menu_unpin_button"
app:showAsAction="never" />
</menu>

View file

@ -105,8 +105,10 @@
<string name="menu_download_label">Download</string>
<string name="menu_home_label">Home</string>
<string name="menu_library_label">Library</string>
<string name="menu_pin_button">Pin</string>
<string name="menu_search_button">Search</string>
<string name="menu_settings_button">Settings</string>
<string name="menu_unpin_button">Unpin</string>
<string name="player_bottom_sheet_title">Now playing</string>
<string name="playing_notification_description">The playing notification provides actions for play/pause etc.</string>
<string name="playing_notification_name">Playing Notification</string>