mirror of
https://github.com/antebudimir/tempus.git
synced 2025-12-31 09:33:33 +00:00
feat: added the ability to pin playlists to the home screen
This commit is contained in:
parent
078aa87521
commit
fb7296b467
12 changed files with 1288 additions and 8 deletions
1065
app/schemas/com.cappielloantonio.tempo.database.AppDatabase/10.json
Normal file
1065
app/schemas/com.cappielloantonio.tempo.database.AppDatabase/10.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -12,6 +12,7 @@ import com.cappielloantonio.tempo.database.converter.DateConverters;
|
|||
import com.cappielloantonio.tempo.database.dao.ChronologyDao;
|
||||
import com.cappielloantonio.tempo.database.dao.DownloadDao;
|
||||
import com.cappielloantonio.tempo.database.dao.FavoriteDao;
|
||||
import com.cappielloantonio.tempo.database.dao.PlaylistDao;
|
||||
import com.cappielloantonio.tempo.database.dao.QueueDao;
|
||||
import com.cappielloantonio.tempo.database.dao.RecentSearchDao;
|
||||
import com.cappielloantonio.tempo.database.dao.ServerDao;
|
||||
|
|
@ -23,12 +24,13 @@ import com.cappielloantonio.tempo.model.Queue;
|
|||
import com.cappielloantonio.tempo.model.RecentSearch;
|
||||
import com.cappielloantonio.tempo.model.Server;
|
||||
import com.cappielloantonio.tempo.model.SessionMediaItem;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Playlist;
|
||||
|
||||
@UnstableApi
|
||||
@Database(
|
||||
version = 9,
|
||||
entities = {Queue.class, Server.class, RecentSearch.class, Download.class, Chronology.class, Favorite.class, SessionMediaItem.class},
|
||||
autoMigrations = {@AutoMigration(from = 8, to = 9)}
|
||||
version = 10,
|
||||
entities = {Queue.class, Server.class, RecentSearch.class, Download.class, Chronology.class, Favorite.class, SessionMediaItem.class, Playlist.class},
|
||||
autoMigrations = {@AutoMigration(from = 9, to = 10)}
|
||||
)
|
||||
@TypeConverters({DateConverters.class})
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
|
|
@ -58,4 +60,6 @@ public abstract class AppDatabase extends RoomDatabase {
|
|||
public abstract FavoriteDao favoriteDao();
|
||||
|
||||
public abstract SessionMediaItemDao sessionMediaItemDao();
|
||||
|
||||
public abstract PlaylistDao playlistDao();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
package com.cappielloantonio.tempo.repository;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.cappielloantonio.tempo.App;
|
||||
import com.cappielloantonio.tempo.database.AppDatabase;
|
||||
import com.cappielloantonio.tempo.database.dao.PlaylistDao;
|
||||
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Playlist;
|
||||
|
|
@ -17,6 +20,7 @@ import retrofit2.Callback;
|
|||
import retrofit2.Response;
|
||||
|
||||
public class PlaylistRepository {
|
||||
private final PlaylistDao playlistDao = AppDatabase.getInstance().playlistDao();
|
||||
public MutableLiveData<List<Playlist>> getPlaylists(boolean random, int size) {
|
||||
MutableLiveData<List<Playlist>> listLivePlaylists = new MutableLiveData<>(new ArrayList<>());
|
||||
|
||||
|
|
@ -153,4 +157,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import com.cappielloantonio.tempo.databinding.FragmentHomeTabMusicBinding;
|
|||
import com.cappielloantonio.tempo.helper.recyclerview.CustomLinearSnapHelper;
|
||||
import com.cappielloantonio.tempo.helper.recyclerview.DotsIndicatorDecoration;
|
||||
import com.cappielloantonio.tempo.interfaces.ClickCallback;
|
||||
import com.cappielloantonio.tempo.interfaces.PlaylistCallback;
|
||||
import com.cappielloantonio.tempo.model.Download;
|
||||
import com.cappielloantonio.tempo.model.HomeSector;
|
||||
import com.cappielloantonio.tempo.service.DownloaderManager;
|
||||
|
|
@ -44,12 +45,13 @@ import com.cappielloantonio.tempo.ui.adapter.AlbumHorizontalAdapter;
|
|||
import com.cappielloantonio.tempo.ui.adapter.ArtistAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.ArtistHorizontalAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.DiscoverSongAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.GridTrackAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.PlaylistHorizontalAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.ShareHorizontalAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.SimilarTrackAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.SongHorizontalAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.YearAdapter;
|
||||
import com.cappielloantonio.tempo.ui.dialog.HomeRearrangementDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.PlaylistEditorDialog;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
|
|
@ -85,7 +87,7 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
private AlbumAdapter mostPlayedAlbumAdapter;
|
||||
private AlbumHorizontalAdapter newReleasesAlbumAdapter;
|
||||
private YearAdapter yearAdapter;
|
||||
private GridTrackAdapter gridTrackAdapter;
|
||||
private PlaylistHorizontalAdapter playlistHorizontalAdapter;
|
||||
private ShareHorizontalAdapter shareHorizontalAdapter;
|
||||
|
||||
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
|
||||
|
|
@ -122,6 +124,7 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
initYearSongView();
|
||||
initRecentAddedAlbumView();
|
||||
initTopSongsView();
|
||||
initPinnedPlaylistsView();
|
||||
initSharesView();
|
||||
initHomeReorganizer();
|
||||
|
||||
|
|
@ -422,7 +425,8 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
} else {
|
||||
if (bind != null) bind.homeGridTracksSector.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.afterGridDivider.setVisibility(View.VISIBLE);
|
||||
if (bind != null) bind.topSongsRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), UIUtil.getSpanCount(chronologies.size(), 5), GridLayoutManager.HORIZONTAL, false));
|
||||
if (bind != null)
|
||||
bind.topSongsRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), UIUtil.getSpanCount(chronologies.size(), 5), GridLayoutManager.HORIZONTAL, false));
|
||||
|
||||
List<Child> topSongs = chronologies.stream()
|
||||
.map(cronologia -> (Child) cronologia)
|
||||
|
|
@ -671,6 +675,26 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
recentAddedAlbumSnapHelper.attachToRecyclerView(bind.recentlyAddedAlbumsRecyclerView);
|
||||
}
|
||||
|
||||
private void initPinnedPlaylistsView() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_PINNED_PLAYLISTS)) return;
|
||||
|
||||
bind.pinnedPlaylistsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
|
||||
bind.pinnedPlaylistsRecyclerView.setHasFixedSize(true);
|
||||
|
||||
playlistHorizontalAdapter = new PlaylistHorizontalAdapter(this);
|
||||
bind.pinnedPlaylistsRecyclerView.setAdapter(playlistHorizontalAdapter);
|
||||
homeViewModel.getPinnedPlaylists(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), playlists -> {
|
||||
if (playlists == null) {
|
||||
if (bind != null) bind.pinnedPlaylistsSector.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (bind != null)
|
||||
bind.pinnedPlaylistsSector.setVisibility(!playlists.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
|
||||
playlistHorizontalAdapter.setItems(playlists);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initSharesView() {
|
||||
if (homeViewModel.checkHomeSectorVisibility(Constants.HOME_SECTOR_SHARED)) return;
|
||||
|
||||
|
|
@ -708,7 +732,9 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
|
||||
private void initHomeReorganizer() {
|
||||
final Handler handler = new Handler();
|
||||
final Runnable runnable = () -> { if (bind != null) bind.homeSectorRearrangementButton.setVisibility(View.VISIBLE); };
|
||||
final Runnable runnable = () -> {
|
||||
if (bind != null) bind.homeSectorRearrangementButton.setVisibility(View.VISIBLE);
|
||||
};
|
||||
handler.postDelayed(runnable, 5000);
|
||||
|
||||
bind.homeSectorRearrangementButton.setOnClickListener(v -> {
|
||||
|
|
@ -789,6 +815,9 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
case Constants.HOME_SECTOR_RECENTLY_ADDED:
|
||||
bind.homeLinearLayoutContainer.addView(bind.homeRecentlyAddedAlbumsSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_PINNED_PLAYLISTS:
|
||||
bind.homeLinearLayoutContainer.addView(bind.pinnedPlaylistsSector);
|
||||
break;
|
||||
case Constants.HOME_SECTOR_SHARED:
|
||||
bind.homeLinearLayoutContainer.addView(bind.sharesSector);
|
||||
break;
|
||||
|
|
@ -824,6 +853,17 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
popup.show();
|
||||
}
|
||||
|
||||
private void refreshPlaylistView() {
|
||||
final Handler handler = new Handler();
|
||||
|
||||
final Runnable runnable = () -> {
|
||||
if (getView() != null && bind != null && homeViewModel != null)
|
||||
homeViewModel.getPinnedPlaylists(getViewLifecycleOwner());
|
||||
};
|
||||
|
||||
handler.postDelayed(runnable, 100);
|
||||
}
|
||||
|
||||
private void initializeMediaBrowser() {
|
||||
mediaBrowserListenableFuture = new MediaBrowser.Builder(requireContext(), new SessionToken(requireContext(), new ComponentName(requireContext(), MediaService.class))).buildAsync();
|
||||
}
|
||||
|
|
@ -922,6 +962,24 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
|
|||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaylistClick(Bundle bundle) {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.playlistPageFragment, bundle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaylistLongClick(Bundle bundle) {
|
||||
PlaylistEditorDialog dialog = new PlaylistEditorDialog(new PlaylistCallback() {
|
||||
@Override
|
||||
public void onDismiss() {
|
||||
refreshPlaylistView();
|
||||
}
|
||||
});
|
||||
|
||||
dialog.setArguments(bundle);
|
||||
dialog.show(activity.getSupportFragmentManager(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShareLongClick(Bundle bundle) {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.shareBottomSheetDialog, bundle);
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback {
|
|||
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
inflater.inflate(R.menu.playlist_page_menu, menu);
|
||||
initMenuOption(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -115,6 +116,12 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback {
|
|||
}
|
||||
});
|
||||
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;
|
||||
|
|
@ -124,6 +131,13 @@ public class PlaylistPageFragment extends Fragment implements ClickCallback {
|
|||
playlistPageViewModel.setPlaylist(requireArguments().getParcelable(Constants.PLAYLIST_OBJECT));
|
||||
}
|
||||
|
||||
private void initMenuOption(Menu menu) {
|
||||
playlistPageViewModel.isPinned(getViewLifecycleOwner()).observe(getViewLifecycleOwner(), 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -105,5 +105,6 @@ object Constants {
|
|||
const val HOME_SECTOR_MOST_PLAYED = "HOME_SECTOR_MOST_PLAYED"
|
||||
const val HOME_SECTOR_LAST_PLAYED = "HOME_SECTOR_LAST_PLAYED"
|
||||
const val HOME_SECTOR_RECENTLY_ADDED = "HOME_SECTOR_RECENTLY_ADDED"
|
||||
const val HOME_SECTOR_PINNED_PLAYLISTS = "HOME_SECTOR_PINNED_PLAYLISTS"
|
||||
const val HOME_SECTOR_SHARED = "HOME_SECTOR_SHARED"
|
||||
}
|
||||
|
|
@ -70,7 +70,8 @@ public class HomeRearrangementViewModel extends AndroidViewModel {
|
|||
sectors.add(new HomeSector(Constants.HOME_SECTOR_MOST_PLAYED, getApplication().getString(R.string.home_title_most_played), true, 11));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_LAST_PLAYED, getApplication().getString(R.string.home_title_last_played), true, 12));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_RECENTLY_ADDED, getApplication().getString(R.string.home_title_recently_added), true, 13));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_SHARED, getApplication().getString(R.string.home_title_shares), true, 14));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_PINNED_PLAYLISTS, getApplication().getString(R.string.home_title_pinned_playlists), true, 14));
|
||||
sectors.add(new HomeSector(Constants.HOME_SECTOR_SHARED, getApplication().getString(R.string.home_title_shares), true, 15));
|
||||
|
||||
return sectors;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,11 +16,13 @@ import com.cappielloantonio.tempo.repository.AlbumRepository;
|
|||
import com.cappielloantonio.tempo.repository.ArtistRepository;
|
||||
import com.cappielloantonio.tempo.repository.ChronologyRepository;
|
||||
import com.cappielloantonio.tempo.repository.FavoriteRepository;
|
||||
import com.cappielloantonio.tempo.repository.PlaylistRepository;
|
||||
import com.cappielloantonio.tempo.repository.SharingRepository;
|
||||
import com.cappielloantonio.tempo.repository.SongRepository;
|
||||
import com.cappielloantonio.tempo.subsonic.models.AlbumID3;
|
||||
import com.cappielloantonio.tempo.subsonic.models.ArtistID3;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Playlist;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Share;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
|
|
@ -32,6 +34,7 @@ import java.util.Collections;
|
|||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class HomeViewModel extends AndroidViewModel {
|
||||
private static final String TAG = "HomeViewModel";
|
||||
|
|
@ -41,6 +44,7 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
private final ArtistRepository artistRepository;
|
||||
private final ChronologyRepository chronologyRepository;
|
||||
private final FavoriteRepository favoriteRepository;
|
||||
private final PlaylistRepository playlistRepository;
|
||||
private final SharingRepository sharingRepository;
|
||||
|
||||
private final MutableLiveData<List<Child>> dicoverSongSample = new MutableLiveData<>(null);
|
||||
|
|
@ -60,6 +64,7 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
private final MutableLiveData<List<Child>> mediaInstantMix = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<Child>> artistInstantMix = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<Child>> artistBestOf = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<Playlist>> pinnedPlaylists = new MutableLiveData<>(null);
|
||||
private final MutableLiveData<List<Share>> shares = new MutableLiveData<>(null);
|
||||
|
||||
private List<HomeSector> sectors;
|
||||
|
|
@ -74,6 +79,7 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
artistRepository = new ArtistRepository();
|
||||
chronologyRepository = new ChronologyRepository();
|
||||
favoriteRepository = new FavoriteRepository();
|
||||
playlistRepository = new PlaylistRepository();
|
||||
sharingRepository = new SharingRepository();
|
||||
|
||||
setOfflineFavorite();
|
||||
|
|
@ -224,6 +230,24 @@ public class HomeViewModel extends AndroidViewModel {
|
|||
return artistBestOf;
|
||||
}
|
||||
|
||||
public LiveData<List<Playlist>> getPinnedPlaylists(LifecycleOwner owner) {
|
||||
pinnedPlaylists.setValue(Collections.emptyList());
|
||||
|
||||
playlistRepository.getPlaylists(false, -1).observe(owner, remotes -> {
|
||||
playlistRepository.getPinnedPlaylists().observe(owner, locals -> {
|
||||
if (remotes != null && locals != null) {
|
||||
List<Playlist> toReturn = remotes.stream()
|
||||
.filter(remote -> locals.stream().anyMatch(local -> local.getId().equals(remote.getId())))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
pinnedPlaylists.setValue(toReturn);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return pinnedPlaylists;
|
||||
}
|
||||
|
||||
public LiveData<List<Share>> getShares(LifecycleOwner owner) {
|
||||
if (shares.getValue() == null) {
|
||||
sharingRepository.getShares().observe(owner, shares::postValue);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ import android.app.Application;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.cappielloantonio.tempo.repository.PlaylistRepository;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
|
|
@ -35,4 +37,22 @@ public class PlaylistPageViewModel extends AndroidViewModel {
|
|||
public void setPlaylist(Playlist playlist) {
|
||||
this.playlist = playlist;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> isPinned(LifecycleOwner owner) {
|
||||
MutableLiveData<Boolean> isPinnedLive = new MutableLiveData<>();
|
||||
|
||||
playlistRepository.getPinnedPlaylists().observe(owner, playlists -> {
|
||||
isPinnedLive.postValue(playlists.stream().anyMatch(obj -> obj.getId().equals(playlist.getId())));
|
||||
});
|
||||
|
||||
return isPinnedLive;
|
||||
}
|
||||
|
||||
public void setPinned(boolean isNowPinned) {
|
||||
if (isNowPinned) {
|
||||
playlistRepository.insert(playlist);
|
||||
} else {
|
||||
playlistRepository.delete(playlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -720,6 +720,36 @@
|
|||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Playlists -->
|
||||
<LinearLayout
|
||||
android:id="@+id/pinned_playlists_sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pinned_playlists_text_view"
|
||||
style="@style/TitleLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_title_pinned_playlists" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/pinned_playlists_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:clipToPadding="false"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Shares -->
|
||||
<LinearLayout
|
||||
android:id="@+id/shares_sector"
|
||||
|
|
|
|||
|
|
@ -6,4 +6,14 @@
|
|||
android:icon="@drawable/ic_file_download"
|
||||
android:title="@string/menu_download_all_button"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_pin_playlist"
|
||||
android:icon="@drawable/ic_add"
|
||||
android:title="@string/menu_pin_button"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_unpin_playlist"
|
||||
android:icon="@drawable/ic_close"
|
||||
android:title="@string/menu_unpin_button"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
||||
|
|
@ -125,6 +125,7 @@
|
|||
<string name="home_title_most_played_see_all_button">See all</string>
|
||||
<string name="home_title_new_releases">New releases</string>
|
||||
<string name="home_title_newest_podcasts">Newest podcasts</string>
|
||||
<string name="home_title_pinned_playlists">Playlists</string>
|
||||
<string name="home_title_podcast_channels">Channels</string>
|
||||
<string name="home_title_podcast_channels_see_all_button">See all</string>
|
||||
<string name="home_title_radio_station">Radio stations</string>
|
||||
|
|
@ -175,6 +176,8 @@
|
|||
<string name="menu_sort_name">Name</string>
|
||||
<string name="menu_sort_random">Random</string>
|
||||
<string name="menu_sort_recently_added">Recently added</string>
|
||||
<string name="menu_pin_button">Add to home screen</string>
|
||||
<string name="menu_unpin_button">Remove from home screen</string>
|
||||
<string name="menu_sort_year">Year</string>
|
||||
<string name="player_playback_speed">%1$.2fx</string>
|
||||
<string name="player_queue_clean_all_button">Clean play queue</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue