feat: Add bottom sheet for grouped views in Download tab

This commit is contained in:
GallowsDove 2023-09-05 18:54:48 +02:00
parent 68527b2c91
commit f43d7fb394
9 changed files with 296 additions and 18 deletions

View file

@ -29,4 +29,5 @@ public interface ClickCallback {
default void onMusicFolderClick(Bundle bundle) {}
default void onMusicDirectoryClick(Bundle bundle) {}
default void onMusicIndexClick(Bundle bundle) {}
default void onDownloadGroupLongClick(Bundle bundle) {}
}

View file

@ -191,7 +191,7 @@ public class DownloadHorizontalAdapter extends RecyclerView.Adapter<DownloadHori
.into(holder.item.itemCoverImageView);
holder.item.itemCoverImageView.setVisibility(View.VISIBLE);
holder.item.downloadedItemMoreButton.setVisibility(View.GONE);
holder.item.downloadedItemMoreButton.setVisibility(View.VISIBLE);
holder.item.divider.setVisibility(View.VISIBLE);
if (position > 0 && grouped.get(position - 1) != null && !Objects.equals(grouped.get(position - 1).getArtist(), grouped.get(position).getArtist())) {
@ -213,7 +213,7 @@ public class DownloadHorizontalAdapter extends RecyclerView.Adapter<DownloadHori
.into(holder.item.itemCoverImageView);
holder.item.itemCoverImageView.setVisibility(View.VISIBLE);
holder.item.downloadedItemMoreButton.setVisibility(View.GONE);
holder.item.downloadedItemMoreButton.setVisibility(View.VISIBLE);
holder.item.divider.setVisibility(View.GONE);
}
@ -224,7 +224,7 @@ public class DownloadHorizontalAdapter extends RecyclerView.Adapter<DownloadHori
holder.item.downloadedItemSubtitleTextView.setText(holder.itemView.getContext().getString(R.string.download_item_single_subtitle_formatter, countSong(Constants.DOWNLOAD_TYPE_GENRE, song.getGenre(), songs)));
holder.item.itemCoverImageView.setVisibility(View.GONE);
holder.item.downloadedItemMoreButton.setVisibility(View.GONE);
holder.item.downloadedItemMoreButton.setVisibility(View.VISIBLE);
holder.item.divider.setVisibility(View.GONE);
}
@ -235,7 +235,7 @@ public class DownloadHorizontalAdapter extends RecyclerView.Adapter<DownloadHori
holder.item.downloadedItemSubtitleTextView.setText(holder.itemView.getContext().getString(R.string.download_item_single_subtitle_formatter, countSong(Constants.DOWNLOAD_TYPE_YEAR, song.getYear().toString(), songs)));
holder.item.itemCoverImageView.setVisibility(View.GONE);
holder.item.downloadedItemMoreButton.setVisibility(View.GONE);
holder.item.downloadedItemMoreButton.setVisibility(View.VISIBLE);
holder.item.divider.setVisibility(View.GONE);
}
@ -287,22 +287,36 @@ public class DownloadHorizontalAdapter extends RecyclerView.Adapter<DownloadHori
private boolean onLongClick() {
Bundle bundle = new Bundle();
switch (view) {
case Constants.DOWNLOAD_TYPE_TRACK:
bundle.putParcelable(Constants.TRACK_OBJECT, grouped.get(getBindingAdapterPosition()));
click.onMediaLongClick(bundle);
return true;
case Constants.DOWNLOAD_TYPE_ALBUM:
bundle.putString(Constants.DOWNLOAD_TYPE_ALBUM, grouped.get(getBindingAdapterPosition()).getAlbumId());
click.onAlbumLongClick(bundle);
return true;
case Constants.DOWNLOAD_TYPE_ARTIST:
bundle.putString(Constants.DOWNLOAD_TYPE_ARTIST, grouped.get(getBindingAdapterPosition()).getArtistId());
click.onArtistLongClick(bundle);
return true;
if (view.equals(Constants.DOWNLOAD_TYPE_TRACK)) {
bundle.putParcelable(Constants.TRACK_OBJECT, grouped.get(getBindingAdapterPosition()));
click.onMediaLongClick(bundle);
return true;
}
return false;
List<Child> filteredSongs = null;
switch (view) {
case Constants.DOWNLOAD_TYPE_ALBUM:
filteredSongs = filterSong(Constants.DOWNLOAD_TYPE_ALBUM, grouped.get(getBindingAdapterPosition()).getAlbumId(), songs);
break;
case Constants.DOWNLOAD_TYPE_ARTIST:
filteredSongs = filterSong(Constants.DOWNLOAD_TYPE_ARTIST, grouped.get(getBindingAdapterPosition()).getArtistId(), songs);
break;
case Constants.DOWNLOAD_TYPE_GENRE:
filteredSongs = filterSong(Constants.DOWNLOAD_TYPE_GENRE, grouped.get(getBindingAdapterPosition()).getGenre(), songs);
break;
case Constants.DOWNLOAD_TYPE_YEAR:
filteredSongs = filterSong(Constants.DOWNLOAD_TYPE_YEAR, grouped.get(getBindingAdapterPosition()).getYear().toString(), songs);
break;
}
if (filteredSongs == null) {
return false;
}
bundle.putParcelableArrayList(Constants.DOWNLOAD_TYPE_GROUP, new ArrayList<>(filteredSongs));
bundle.putString(Constants.DOWNLOAD_TYPE_GROUP_NAME, item.downloadedItemTitleTextView.getText().toString());
click.onDownloadGroupLongClick(bundle);
return true;
}
}
}

View file

@ -234,4 +234,9 @@ public class DownloadFragment extends Fragment implements ClickCallback {
public void onMediaLongClick(Bundle bundle) {
Navigation.findNavController(requireView()).navigate(R.id.songBottomSheetDialog, bundle);
}
@Override
public void onDownloadGroupLongClick(Bundle bundle) {
Navigation.findNavController(requireView()).navigate(R.id.downloadBottomSheetDialog, bundle);
}
}

View file

@ -0,0 +1,133 @@
package com.cappielloantonio.tempo.ui.fragment.bottomsheetdialog;
import android.content.ComponentName;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.media3.common.MediaItem;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.session.MediaBrowser;
import androidx.media3.session.SessionToken;
import com.cappielloantonio.tempo.R;
import com.cappielloantonio.tempo.glide.CustomGlideRequest;
import com.cappielloantonio.tempo.model.Download;
import com.cappielloantonio.tempo.service.MediaManager;
import com.cappielloantonio.tempo.service.MediaService;
import com.cappielloantonio.tempo.subsonic.models.Child;
import com.cappielloantonio.tempo.ui.activity.MainActivity;
import com.cappielloantonio.tempo.util.Constants;
import com.cappielloantonio.tempo.util.DownloadUtil;
import com.cappielloantonio.tempo.util.MappingUtil;
import com.cappielloantonio.tempo.util.MusicUtil;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@UnstableApi
public class DownloadedBottomSheetDialog extends BottomSheetDialogFragment implements View.OnClickListener {
private List<Child> songs;
private String groupName;
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bottom_sheet_downloaded_dialog, container, false);
songs = this.requireArguments().getParcelableArrayList(Constants.DOWNLOAD_TYPE_GROUP);
groupName = this.requireArguments().getString(Constants.DOWNLOAD_TYPE_GROUP_NAME);
init(view);
return view;
}
@Override
public void onStart() {
super.onStart();
initializeMediaBrowser();
}
@Override
public void onStop() {
releaseMediaBrowser();
super.onStop();
}
private void init(View view) {
ImageView coverAlbum = view.findViewById(R.id.album_cover_image_view);
CustomGlideRequest.Builder
.from(requireContext(), songs.get(0).getCoverArtId())
.build()
.into(coverAlbum);
TextView groupNameView = view.findViewById(R.id.group_name_text_view);
groupNameView.setText(MusicUtil.getReadableString(this.groupName));
groupNameView.setSelected(true);
TextView playRandom = view.findViewById(R.id.play_random_text_view);
playRandom.setOnClickListener(v -> {
Collections.shuffle(songs);
MediaManager.startQueue(mediaBrowserListenableFuture, songs, 0);
((MainActivity) requireActivity()).setBottomSheetInPeek(true);
dismissBottomSheet();
});
TextView playNext = view.findViewById(R.id.play_next_text_view);
playNext.setOnClickListener(v -> {
MediaManager.enqueue(mediaBrowserListenableFuture, songs, true);
((MainActivity) requireActivity()).setBottomSheetInPeek(true);
dismissBottomSheet();
}
);
TextView addToQueue = view.findViewById(R.id.add_to_queue_text_view);
addToQueue.setOnClickListener(v -> {
MediaManager.enqueue(mediaBrowserListenableFuture, songs, false);
((MainActivity) requireActivity()).setBottomSheetInPeek(true);
dismissBottomSheet();
});
TextView removeAll = view.findViewById(R.id.remove_all_text_view);
List<MediaItem> mediaItems = MappingUtil.mapDownloads(songs);
List<Download> downloads = songs.stream().map(Download::new).collect(Collectors.toList());
removeAll.setOnClickListener(v -> {
DownloadUtil.getDownloadTracker(requireContext()).remove(mediaItems, downloads);
dismissBottomSheet();
});
}
@Override
public void onClick(View v) {
dismissBottomSheet();
}
private void dismissBottomSheet() {
dismiss();
}
private void initializeMediaBrowser() {
mediaBrowserListenableFuture = new MediaBrowser.Builder(requireContext(), new SessionToken(requireContext(), new ComponentName(requireContext(), MediaService.class))).buildAsync();
}
private void releaseMediaBrowser() {
MediaBrowser.releaseFuture(mediaBrowserListenableFuture);
}
}

View file

@ -79,6 +79,8 @@ object Constants {
const val DOWNLOAD_TYPE_TRACK = "download_type_track"
const val DOWNLOAD_TYPE_ALBUM = "download_type_album"
const val DOWNLOAD_TYPE_ARTIST = "download_type_artist"
const val DOWNLOAD_TYPE_GROUP = "download_type_group"
const val DOWNLOAD_TYPE_GROUP_NAME = "download_type_group_name"
const val DOWNLOAD_TYPE_GENRE = "download_type_genre"
const val DOWNLOAD_TYPE_YEAR = "download_type_year"

View file

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="20dp"
android:paddingTop="12dp"
android:paddingEnd="20dp">
<!-- Header -->
<ImageView
android:id="@+id/album_cover_image_view"
android:layout_width="54dp"
android:layout_height="54dp"
android:layout_margin="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/group_name_text_view"
style="@style/LabelMedium"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:focusable="true"
android:focusableInTouchMode="true"
android:marqueeRepeatLimit="marquee_forever"
android:paddingStart="12dp"
android:paddingTop="8dp"
android:paddingEnd="12dp"
android:scrollHorizontally="true"
android:singleLine="true"
android:text="@string/label_placeholder"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/album_cover_image_view"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:id="@+id/option_linear_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="8dp"
android:paddingBottom="12dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<TextView
android:id="@+id/play_random_text_view"
style="@style/LabelMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:paddingStart="20dp"
android:paddingTop="12dp"
android:paddingEnd="20dp"
android:paddingBottom="12dp"
android:text="@string/downloaded_bottom_sheet_shuffle" />
<TextView
android:id="@+id/play_next_text_view"
style="@style/LabelMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:paddingStart="20dp"
android:paddingTop="12dp"
android:paddingEnd="20dp"
android:paddingBottom="12dp"
android:text="@string/downloaded_bottom_sheet_play_next" />
<TextView
android:id="@+id/add_to_queue_text_view"
style="@style/LabelMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:paddingStart="20dp"
android:paddingTop="12dp"
android:paddingEnd="20dp"
android:paddingBottom="12dp"
android:text="@string/downloaded_bottom_sheet_add_to_queue" />
<TextView
android:id="@+id/remove_all_text_view"
style="@style/LabelMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:paddingStart="20dp"
android:paddingTop="12dp"
android:paddingEnd="20dp"
android:paddingBottom="12dp"
android:text="@string/downloaded_bottom_sheet_remove_all" />
</LinearLayout>
</LinearLayout>

View file

@ -315,6 +315,11 @@
android:name="com.cappielloantonio.tempo.ui.fragment.bottomsheetdialog.AlbumBottomSheetDialog"
android:label="AlbumBottomSheetDialog"
tools:layout="@layout/bottom_sheet_album_dialog" />
<dialog
android:id="@+id/downloadBottomSheetDialog"
android:name="com.cappielloantonio.tempo.ui.fragment.bottomsheetdialog.DownloadedBottomSheetDialog"
android:label="DownloadBottomSheetDialog"
tools:layout="@layout/bottom_sheet_downloaded_dialog" />
<dialog
android:id="@+id/podcastEpisodeBottomSheetDialog"
android:name="com.cappielloantonio.tempo.ui.fragment.bottomsheetdialog.PodcastEpisodeBottomSheetDialog"

View file

@ -297,4 +297,8 @@
<string name="menu_group_by_artist">Künstler</string>
<string name="menu_group_by_genre">Genre</string>
<string name="menu_group_by_year">Jahr</string>
<string name="downloaded_bottom_sheet_shuffle">Mischen</string>
<string name="downloaded_bottom_sheet_play_next">Nächsten Titel spielen</string>
<string name="downloaded_bottom_sheet_add_to_queue">Zur Warteschlange hinzufügen</string>
<string name="downloaded_bottom_sheet_remove_all">Alle entfernen</string>
</resources>

View file

@ -300,4 +300,8 @@
<string name="menu_group_by_artist">Artist</string>
<string name="menu_group_by_genre">Genre</string>
<string name="menu_group_by_year">Year</string>
<string name="downloaded_bottom_sheet_shuffle">Shuffle</string>
<string name="downloaded_bottom_sheet_play_next">Play next</string>
<string name="downloaded_bottom_sheet_add_to_queue">Add to queue</string>
<string name="downloaded_bottom_sheet_remove_all">Remove all</string>
</resources>