feat: updated podcast channel UI

This commit is contained in:
antonio 2023-07-30 12:23:49 +02:00
parent 7a8880ee68
commit f9573b3eab
2 changed files with 124 additions and 126 deletions

View file

@ -5,6 +5,7 @@ import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.PopupMenu;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
@ -17,7 +18,6 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import com.cappielloantonio.tempo.R; import com.cappielloantonio.tempo.R;
import com.cappielloantonio.tempo.databinding.FragmentPodcastChannelPageBinding; import com.cappielloantonio.tempo.databinding.FragmentPodcastChannelPageBinding;
import com.cappielloantonio.tempo.glide.CustomGlideRequest;
import com.cappielloantonio.tempo.interfaces.ClickCallback; import com.cappielloantonio.tempo.interfaces.ClickCallback;
import com.cappielloantonio.tempo.service.MediaManager; import com.cappielloantonio.tempo.service.MediaManager;
import com.cappielloantonio.tempo.service.MediaService; import com.cappielloantonio.tempo.service.MediaService;
@ -31,8 +31,6 @@ import com.cappielloantonio.tempo.viewmodel.PodcastChannelPageViewModel;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@UnstableApi @UnstableApi
public class PodcastChannelPageFragment extends Fragment implements ClickCallback { public class PodcastChannelPageFragment extends Fragment implements ClickCallback {
@ -84,28 +82,26 @@ public class PodcastChannelPageFragment extends Fragment implements ClickCallbac
} }
private void initAppBar() { private void initAppBar() {
activity.setSupportActionBar(bind.animToolbar); activity.setSupportActionBar(bind.toolbar);
if (activity.getSupportActionBar() != null)
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
bind.collapsingToolbar.setTitle(MusicUtil.getReadableString(podcastChannelPageViewModel.getPodcastChannel().getTitle())); if (activity.getSupportActionBar() != null) {
bind.animToolbar.setNavigationOnClickListener(v -> activity.navController.navigateUp()); activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
bind.collapsingToolbar.setExpandedTitleColor(getResources().getColor(R.color.white, null)); activity.getSupportActionBar().setDisplayShowHomeEnabled(true);
}
bind.toolbar.setTitle(MusicUtil.getReadableString(podcastChannelPageViewModel.getPodcastChannel().getTitle()));
bind.toolbar.setNavigationOnClickListener(v -> activity.navController.navigateUp());
bind.toolbar.setTitle(MusicUtil.getReadableString(podcastChannelPageViewModel.getPodcastChannel().getTitle()));
} }
private void initPodcastChannelInfo() { private void initPodcastChannelInfo() {
String normalizePodcastChannelDescription = MusicUtil.forceReadableString(podcastChannelPageViewModel.getPodcastChannel().getDescription()); String normalizePodcastChannelDescription = MusicUtil.forceReadableString(podcastChannelPageViewModel.getPodcastChannel().getDescription());
if (bind != null) if (bind != null) {
bind.podcastChannelDescriptionTextView.setVisibility(!normalizePodcastChannelDescription.trim().isEmpty() ? View.VISIBLE : View.GONE); bind.podcastChannelDescriptionTextView.setVisibility(!normalizePodcastChannelDescription.trim().isEmpty() ? View.VISIBLE : View.GONE);
if (getContext() != null && bind != null) CustomGlideRequest.Builder
.from(requireContext(), podcastChannelPageViewModel.getPodcastChannel().getCoverArtId())
.build()
.into(bind.podcastChannelBackdropImageView);
if (bind != null)
bind.podcastChannelDescriptionTextView.setText(normalizePodcastChannelDescription); bind.podcastChannelDescriptionTextView.setText(normalizePodcastChannelDescription);
bind.podcastEpisodesFilterImageView.setOnClickListener(view -> showPopupMenu(view, R.menu.filter_podcast_episode_popup_menu));
}
} }
private void initPodcastChannelEpisodesView() { private void initPodcastChannelEpisodesView() {
@ -116,24 +112,27 @@ public class PodcastChannelPageFragment extends Fragment implements ClickCallbac
bind.podcastEpisodesRecyclerView.setAdapter(podcastEpisodeAdapter); bind.podcastEpisodesRecyclerView.setAdapter(podcastEpisodeAdapter);
podcastChannelPageViewModel.getPodcastChannelEpisodes().observe(getViewLifecycleOwner(), channels -> { podcastChannelPageViewModel.getPodcastChannelEpisodes().observe(getViewLifecycleOwner(), channels -> {
if (channels == null) { if (channels == null) {
if (bind != null)
bind.podcastChannelPageEpisodesPlaceholder.placeholder.setVisibility(View.VISIBLE);
if (bind != null) bind.podcastChannelPageEpisodesSector.setVisibility(View.GONE);
} else {
if (bind != null)
bind.podcastChannelPageEpisodesPlaceholder.placeholder.setVisibility(View.GONE);
if (!channels.isEmpty() && channels.get(0) != null && channels.get(0).getEpisodes() != null) {
List<PodcastEpisode> availableEpisode = channels.get(0).getEpisodes().stream().filter(podcastEpisode -> Objects.equals(podcastEpisode.getStatus(), "completed")).collect(Collectors.toList());
if (bind != null) { if (bind != null) {
bind.podcastEpisodesRecyclerView.setVisibility(availableEpisode.isEmpty() ? View.GONE : View.VISIBLE); bind.podcastEpisodesRecyclerView.setVisibility(View.GONE);
bind.podcastEpisodesAvailabilityTextView.setVisibility(availableEpisode.isEmpty() ? View.VISIBLE : View.GONE); bind.podcastEpisodesAvailabilityTextView.setVisibility(View.VISIBLE);
}
} else {
if (bind != null) {
bind.podcastEpisodesRecyclerView.setVisibility(View.VISIBLE);
bind.podcastEpisodesAvailabilityTextView.setVisibility(View.GONE);
} }
if (!channels.isEmpty() && channels.get(0) != null && channels.get(0).getEpisodes() != null) {
List<PodcastEpisode> availableEpisode = channels.get(0).getEpisodes();
if (bind != null && availableEpisode != null) {
bind.podcastEpisodesRecyclerView.setVisibility(availableEpisode.isEmpty() ? View.GONE : View.VISIBLE);
bind.podcastEpisodesAvailabilityTextView.setVisibility(availableEpisode.isEmpty() ? View.VISIBLE : View.GONE);
podcastEpisodeAdapter.setItems(availableEpisode); podcastEpisodeAdapter.setItems(availableEpisode);
} }
} }
}
}); });
} }
@ -145,6 +144,25 @@ public class PodcastChannelPageFragment extends Fragment implements ClickCallbac
MediaBrowser.releaseFuture(mediaBrowserListenableFuture); MediaBrowser.releaseFuture(mediaBrowserListenableFuture);
} }
private void showPopupMenu(View view, int menuResource) {
PopupMenu popup = new PopupMenu(requireContext(), view);
popup.getMenuInflater().inflate(menuResource, popup.getMenu());
popup.setOnMenuItemClickListener(menuItem -> {
if (menuItem.getItemId() == R.id.menu_podcast_filter_download) {
podcastEpisodeAdapter.sort(Constants.PODCAST_FILTER_BY_DOWNLOAD);
return true;
} else if (menuItem.getItemId() == R.id.menu_podcast_filter_all) {
podcastEpisodeAdapter.sort(Constants.PODCAST_FILTER_BY_ALL);
return true;
}
return false;
});
popup.show();
}
@Override @Override
public void onPodcastEpisodeClick(Bundle bundle) { public void onPodcastEpisodeClick(Bundle bundle) {
MediaManager.startPodcast(mediaBrowserListenableFuture, bundle.getParcelable(Constants.PODCAST_OBJECT)); MediaManager.startPodcast(mediaBrowserListenableFuture, bundle.getParcelable(Constants.PODCAST_OBJECT));

View file

@ -1,74 +1,45 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/layout" android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:navigationIcon="@drawable/ic_arrow_back" />
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar" android:id="@+id/app_bar_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/appbar_header_height"> android:layout_height="wrap_content">
<com.google.android.material.appbar.CollapsingToolbarLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/collapsing_toolbar" android:id="@+id/podcast_channel_page_info_sector"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
app:contentScrim="?attr/colorSurface" android:background="?attr/colorSurface"
app:expandedTitleMarginStart="@dimen/activity_margin_content"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"> app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<ImageView
android:id="@+id/podcast_channel_backdrop_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax" />
<View
android:layout_width="match_parent"
android:layout_height="@dimen/appbar_header_height"
android:layout_gravity="top"
android:background="@drawable/gradient_backdrop_background_image" />
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/anim_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/fragment_artist_page_nested_scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingTop="18dp"
android:paddingBottom="@dimen/global_padding_bottom">
<LinearLayout
android:id="@+id/podcast_channel_page_bio_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="22dp">
<TextView <TextView
android:id="@+id/podcast_channel_description_label"
style="@style/TitleLarge" style="@style/TitleLarge"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingEnd="8dp" android:paddingEnd="8dp"
android:text="@string/podcast_channel_page_title_description_section" /> android:text="@string/podcast_channel_page_title_description_section"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView <TextView
android:id="@+id/podcast_channel_description_text_view" android:id="@+id/podcast_channel_description_text_view"
@ -77,63 +48,72 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingTop="8dp" android:paddingTop="8dp"
android:paddingEnd="16dp" /> android:paddingEnd="16dp"
</LinearLayout> app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
<include app:layout_constraintTop_toBottomOf="@+id/podcast_channel_description_label" />
android:id="@+id/podcast_channel_page_description_placeholder"
layout="@layout/item_placehoder_biography"
android:visibility="gone" />
<View <View
android:id="@+id/upper_button_divider" android:id="@+id/upper_button_divider"
style="@style/Divider" style="@style/Divider"
android:layout_marginHorizontal="16dp" /> android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
<!-- Label and button --> app:layout_constraintEnd_toEndOf="parent"
<LinearLayout app:layout_constraintStart_toStartOf="parent"
android:id="@+id/podcast_channel_page_episodes_sector" app:layout_constraintTop_toBottomOf="@+id/podcast_channel_description_text_view" />
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="22dp">
<TextView <TextView
android:id="@+id/podcast_episodes_section_label"
style="@style/TitleLarge" style="@style/TitleLarge"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingTop="16dp"
android:paddingEnd="8dp" android:paddingEnd="8dp"
android:text="@string/podcast_channel_page_title_episode_section" /> android:paddingBottom="12dp"
android:text="@string/podcast_channel_page_title_episode_section"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/upper_button_divider" />
<Button
android:id="@+id/podcast_episodes_filter_image_view"
style="@style/Widget.Material3.Button.TonalButton.Icon"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
app:cornerRadius="30dp"
app:icon="@drawable/ic_filter_list"
app:layout_constraintBottom_toBottomOf="@+id/podcast_episodes_section_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/podcast_episodes_section_label" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/podcast_episodes_recycler_view" android:id="@+id/podcast_episodes_recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:clipToPadding="false" android:clipToPadding="false"
android:nestedScrollingEnabled="false" android:paddingBottom="@dimen/global_padding_bottom"
android:paddingTop="8dp" /> app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<TextView <TextView
android:id="@+id/podcast_episodes_availability_text_view" android:id="@+id/podcast_episodes_availability_text_view"
style="@style/TitleMedium" style="@style/TitleMedium"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="8dp" android:paddingEnd="8dp"
android:text="@string/podcast_channel_page_title_no_episode_available" android:text="@string/podcast_channel_page_title_no_episode_available"
android:visibility="gone" /> android:visibility="gone" />
</LinearLayout>
<include
android:id="@+id/podcast_channel_page_episodes_placeholder"
layout="@layout/item_placeholder_horizontal"
android:visibility="gone" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>