From a1ee70c24f87565a056a426a674cf6c8324cb5a1 Mon Sep 17 00:00:00 2001 From: antonio Date: Sun, 7 May 2023 17:11:34 +0200 Subject: [PATCH] feat: radio --- .../play/interfaces/ClickCallback.java | 4 + .../play/repository/RadioRepository.java | 39 ++++++++ .../play/service/MediaManager.java | 18 ++++ .../play/subsonic/Subsonic.java | 9 ++ .../internetradio/InternetRadioClient.java | 41 ++++++++ .../internetradio/InternetRadioService.java | 24 +++++ .../subsonic/models/InternetRadioStation.kt | 6 +- .../subsonic/models/InternetRadioStations.kt | 3 + .../adapter/InternetRadioStationAdapter.java | 99 +++++++++++++++++++ .../ui/fragment/HomeTabRadioFragment.java | 57 ++++++++++- .../ui/fragment/PlayerControllerFragment.java | 13 ++- .../cappielloantonio/play/util/Constants.kt | 2 + .../play/util/MappingUtil.java | 31 ++++++ .../play/viewmodel/RadioViewModel.java | 26 +++++ .../res/layout/fragment_home_tab_radio.xml | 46 ++++++++- .../item_home_internet_radio_station.xml | 71 +++++++++++++ 16 files changed, 478 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/com/cappielloantonio/play/repository/RadioRepository.java create mode 100644 app/src/main/java/com/cappielloantonio/play/subsonic/api/internetradio/InternetRadioClient.java create mode 100644 app/src/main/java/com/cappielloantonio/play/subsonic/api/internetradio/InternetRadioService.java create mode 100644 app/src/main/java/com/cappielloantonio/play/ui/adapter/InternetRadioStationAdapter.java create mode 100644 app/src/main/java/com/cappielloantonio/play/viewmodel/RadioViewModel.java create mode 100644 app/src/main/res/layout/item_home_internet_radio_station.xml diff --git a/app/src/main/java/com/cappielloantonio/play/interfaces/ClickCallback.java b/app/src/main/java/com/cappielloantonio/play/interfaces/ClickCallback.java index 85a049e4..5216e632 100644 --- a/app/src/main/java/com/cappielloantonio/play/interfaces/ClickCallback.java +++ b/app/src/main/java/com/cappielloantonio/play/interfaces/ClickCallback.java @@ -31,4 +31,8 @@ public interface ClickCallback { default void onPodcastClick(Bundle bundle) {} default void onPodcastLongClick(Bundle bundle) {} + + default void onInternetRadioStationClick(Bundle bundle) {} + + default void onInternetRadioStationLongClick(Bundle bundle) {} } diff --git a/app/src/main/java/com/cappielloantonio/play/repository/RadioRepository.java b/app/src/main/java/com/cappielloantonio/play/repository/RadioRepository.java new file mode 100644 index 00000000..2654efbf --- /dev/null +++ b/app/src/main/java/com/cappielloantonio/play/repository/RadioRepository.java @@ -0,0 +1,39 @@ +package com.cappielloantonio.play.repository; + +import androidx.annotation.NonNull; +import androidx.lifecycle.MutableLiveData; + +import com.cappielloantonio.play.App; +import com.cappielloantonio.play.subsonic.base.ApiResponse; +import com.cappielloantonio.play.subsonic.models.InternetRadioStation; + +import java.util.List; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class RadioRepository { + public MutableLiveData> getInternetRadioStations() { + MutableLiveData> radioStation = new MutableLiveData<>(); + + App.getSubsonicClientInstance(false) + .getInternetRadioClient() + .getInternetRadioStations() + .enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getInternetRadioStations() != null) { + radioStation.setValue(response.body().getSubsonicResponse().getInternetRadioStations().getInternetRadioStations()); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + + } + }); + + return radioStation; + } +} diff --git a/app/src/main/java/com/cappielloantonio/play/service/MediaManager.java b/app/src/main/java/com/cappielloantonio/play/service/MediaManager.java index 286148e8..f2d3643d 100644 --- a/app/src/main/java/com/cappielloantonio/play/service/MediaManager.java +++ b/app/src/main/java/com/cappielloantonio/play/service/MediaManager.java @@ -9,6 +9,7 @@ import com.cappielloantonio.play.repository.ChronologyRepository; import com.cappielloantonio.play.repository.QueueRepository; import com.cappielloantonio.play.repository.SongRepository; import com.cappielloantonio.play.subsonic.models.Child; +import com.cappielloantonio.play.subsonic.models.InternetRadioStation; import com.cappielloantonio.play.util.MappingUtil; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; @@ -128,6 +129,23 @@ public class MediaManager { } } + public static void startRadio(ListenableFuture mediaBrowserListenableFuture, InternetRadioStation internetRadioStation) { + if (mediaBrowserListenableFuture != null) { + mediaBrowserListenableFuture.addListener(() -> { + try { + if (mediaBrowserListenableFuture.isDone()) { + mediaBrowserListenableFuture.get().clearMediaItems(); + mediaBrowserListenableFuture.get().setMediaItem(MappingUtil.mapInternetRadioStation(internetRadioStation)); + mediaBrowserListenableFuture.get().prepare(); + mediaBrowserListenableFuture.get().play(); + } + } catch (ExecutionException | InterruptedException e) { + e.printStackTrace(); + } + }, MoreExecutors.directExecutor()); + } + } + public static void enqueue(ListenableFuture mediaBrowserListenableFuture, List media, boolean playImmediatelyAfter) { if (mediaBrowserListenableFuture != null) { mediaBrowserListenableFuture.addListener(() -> { diff --git a/app/src/main/java/com/cappielloantonio/play/subsonic/Subsonic.java b/app/src/main/java/com/cappielloantonio/play/subsonic/Subsonic.java index 6eeebc7f..3d3fc1a4 100644 --- a/app/src/main/java/com/cappielloantonio/play/subsonic/Subsonic.java +++ b/app/src/main/java/com/cappielloantonio/play/subsonic/Subsonic.java @@ -3,6 +3,7 @@ package com.cappielloantonio.play.subsonic; import com.cappielloantonio.play.subsonic.api.albumsonglist.AlbumSongListClient; import com.cappielloantonio.play.subsonic.api.bookmarks.BookmarksClient; import com.cappielloantonio.play.subsonic.api.browsing.BrowsingClient; +import com.cappielloantonio.play.subsonic.api.internetradio.InternetRadioClient; import com.cappielloantonio.play.subsonic.api.mediaannotation.MediaAnnotationClient; import com.cappielloantonio.play.subsonic.api.medialibraryscanning.MediaLibraryScanningClient; import com.cappielloantonio.play.subsonic.api.mediaretrieval.MediaRetrievalClient; @@ -31,6 +32,7 @@ public class Subsonic { private PodcastClient podcastClient; private MediaLibraryScanningClient mediaLibraryScanningClient; private BookmarksClient bookmarksClient; + private InternetRadioClient internetRadioClient; public Subsonic(SubsonicPreferences preferences) { this.preferences = preferences; @@ -110,6 +112,13 @@ public class Subsonic { return bookmarksClient; } + public InternetRadioClient getInternetRadioClient() { + if (internetRadioClient == null) { + internetRadioClient = new InternetRadioClient(this); + } + return internetRadioClient; + } + public String getUrl() { String url = preferences.getServerUrl() + "/rest/"; return url.replace("//rest", "/rest"); diff --git a/app/src/main/java/com/cappielloantonio/play/subsonic/api/internetradio/InternetRadioClient.java b/app/src/main/java/com/cappielloantonio/play/subsonic/api/internetradio/InternetRadioClient.java new file mode 100644 index 00000000..4497fcf9 --- /dev/null +++ b/app/src/main/java/com/cappielloantonio/play/subsonic/api/internetradio/InternetRadioClient.java @@ -0,0 +1,41 @@ +package com.cappielloantonio.play.subsonic.api.internetradio; + +import android.util.Log; + +import com.cappielloantonio.play.subsonic.RetrofitClient; +import com.cappielloantonio.play.subsonic.Subsonic; +import com.cappielloantonio.play.subsonic.base.ApiResponse; + +import retrofit2.Call; + +public class InternetRadioClient { + private static final String TAG = "InternetRadioClient"; + + private final Subsonic subsonic; + private final InternetRadioService internetRadioService; + + public InternetRadioClient(Subsonic subsonic) { + this.subsonic = subsonic; + this.internetRadioService = new RetrofitClient(subsonic).getRetrofit().create(InternetRadioService.class); + } + + public Call getInternetRadioStations() { + Log.d(TAG, "getInternetRadioStations()"); + return internetRadioService.getInternetRadioStations(subsonic.getParams()); + } + + public Call createInternetRadioStation(String streamUrl, String name, String homepageUrl) { + Log.d(TAG, "createInternetRadioStation()"); + return internetRadioService.createInternetRadioStation(subsonic.getParams(), streamUrl, name, homepageUrl); + } + + public Call updateInternetRadioStation(String id, String streamUrl, String name, String homepageUrl) { + Log.d(TAG, "updateInternetRadioStation()"); + return internetRadioService.updateInternetRadioStation(subsonic.getParams(), id, streamUrl, name, homepageUrl); + } + + public Call deleteInternetRadioStation(String id) { + Log.d(TAG, "deleteInternetRadioStation()"); + return internetRadioService.deleteInternetRadioStation(subsonic.getParams(), id); + } +} diff --git a/app/src/main/java/com/cappielloantonio/play/subsonic/api/internetradio/InternetRadioService.java b/app/src/main/java/com/cappielloantonio/play/subsonic/api/internetradio/InternetRadioService.java new file mode 100644 index 00000000..9eb18f2d --- /dev/null +++ b/app/src/main/java/com/cappielloantonio/play/subsonic/api/internetradio/InternetRadioService.java @@ -0,0 +1,24 @@ +package com.cappielloantonio.play.subsonic.api.internetradio; + +import com.cappielloantonio.play.subsonic.base.ApiResponse; + +import java.util.Map; + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Query; +import retrofit2.http.QueryMap; + +public interface InternetRadioService { + @GET("getInternetRadioStations") + Call getInternetRadioStations(@QueryMap Map params); + + @GET("createInternetRadioStation") + Call createInternetRadioStation(@QueryMap Map params, @Query("streamUrl") String streamUrl, @Query("name") String name, @Query("homepageUrl") String homepageUrl); + + @GET("updateInternetRadioStation") + Call updateInternetRadioStation(@QueryMap Map params, @Query("id") String id, @Query("streamUrl") String streamUrl, @Query("name") String name, @Query("homepageUrl") String homepageUrl); + + @GET("deleteInternetRadioStation") + Call deleteInternetRadioStation(@QueryMap Map params, @Query("id") String id); +} diff --git a/app/src/main/java/com/cappielloantonio/play/subsonic/models/InternetRadioStation.kt b/app/src/main/java/com/cappielloantonio/play/subsonic/models/InternetRadioStation.kt index a5164e36..8ba6c75c 100644 --- a/app/src/main/java/com/cappielloantonio/play/subsonic/models/InternetRadioStation.kt +++ b/app/src/main/java/com/cappielloantonio/play/subsonic/models/InternetRadioStation.kt @@ -1,6 +1,10 @@ package com.cappielloantonio.play.subsonic.models -class InternetRadioStation { +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +class InternetRadioStation : Parcelable { var id: String? = null var name: String? = null var streamUrl: String? = null diff --git a/app/src/main/java/com/cappielloantonio/play/subsonic/models/InternetRadioStations.kt b/app/src/main/java/com/cappielloantonio/play/subsonic/models/InternetRadioStations.kt index 3c96ba45..caa9f08a 100644 --- a/app/src/main/java/com/cappielloantonio/play/subsonic/models/InternetRadioStations.kt +++ b/app/src/main/java/com/cappielloantonio/play/subsonic/models/InternetRadioStations.kt @@ -1,5 +1,8 @@ package com.cappielloantonio.play.subsonic.models +import com.google.gson.annotations.SerializedName + class InternetRadioStations { + @SerializedName("internetRadioStation") var internetRadioStations: List? = null } \ No newline at end of file diff --git a/app/src/main/java/com/cappielloantonio/play/ui/adapter/InternetRadioStationAdapter.java b/app/src/main/java/com/cappielloantonio/play/ui/adapter/InternetRadioStationAdapter.java new file mode 100644 index 00000000..0f6d29c6 --- /dev/null +++ b/app/src/main/java/com/cappielloantonio/play/ui/adapter/InternetRadioStationAdapter.java @@ -0,0 +1,99 @@ +package com.cappielloantonio.play.ui.adapter; + +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.media3.common.util.UnstableApi; +import androidx.recyclerview.widget.RecyclerView; + +import com.cappielloantonio.play.databinding.ItemHomeInternetRadioStationBinding; +import com.cappielloantonio.play.glide.CustomGlideRequest; +import com.cappielloantonio.play.interfaces.ClickCallback; +import com.cappielloantonio.play.subsonic.models.InternetRadioStation; +import com.cappielloantonio.play.util.Constants; + +import java.util.Collections; +import java.util.List; + +@UnstableApi +public class InternetRadioStationAdapter extends RecyclerView.Adapter { + private final ClickCallback click; + + private List internetRadioStations; + + public InternetRadioStationAdapter(ClickCallback click) { + this.click = click; + this.internetRadioStations = Collections.emptyList(); + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + ItemHomeInternetRadioStationBinding view = ItemHomeInternetRadioStationBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + InternetRadioStation internetRadioStation = internetRadioStations.get(position); + + holder.item.internetRadioStationTitleTextView.setText(internetRadioStation.getName()); + holder.item.internetRadioStationSubtitleTextView.setText(internetRadioStation.getStreamUrl()); + + CustomGlideRequest.Builder + .from(holder.itemView.getContext(), internetRadioStation.getStreamUrl()) + .build() + .into(holder.item.internetRadioStationCoverImageView); + } + + @Override + public int getItemCount() { + return internetRadioStations.size(); + } + + public void setItems(List internetRadioStations) { + this.internetRadioStations = internetRadioStations; + notifyDataSetChanged(); + } + + public InternetRadioStation getItem(int position) { + return internetRadioStations.get(position); + } + + public class ViewHolder extends RecyclerView.ViewHolder { + ItemHomeInternetRadioStationBinding item; + + ViewHolder(ItemHomeInternetRadioStationBinding item) { + super(item.getRoot()); + + this.item = item; + + item.internetRadioStationTitleTextView.setSelected(true); + item.internetRadioStationSubtitleTextView.setSelected(true); + + itemView.setOnClickListener(v -> onClick()); + itemView.setOnLongClickListener(v -> onLongClick()); + + item.internetRadioStationMoreButton.setOnClickListener(v -> onLongClick()); + } + + public void onClick() { + Bundle bundle = new Bundle(); + bundle.putParcelable(Constants.INTERNET_RADIO_STATION_OBJECT, internetRadioStations.get(getBindingAdapterPosition())); + + click.onInternetRadioStationClick(bundle); + } + + private boolean onLongClick() { + Bundle bundle = new Bundle(); + bundle.putParcelable(Constants.INTERNET_RADIO_STATION_OBJECT, internetRadioStations.get(getBindingAdapterPosition())); + + click.onInternetRadioStationLongClick(bundle); + + return false; + } + } +} diff --git a/app/src/main/java/com/cappielloantonio/play/ui/fragment/HomeTabRadioFragment.java b/app/src/main/java/com/cappielloantonio/play/ui/fragment/HomeTabRadioFragment.java index 4af3ade1..34704941 100644 --- a/app/src/main/java/com/cappielloantonio/play/ui/fragment/HomeTabRadioFragment.java +++ b/app/src/main/java/com/cappielloantonio/play/ui/fragment/HomeTabRadioFragment.java @@ -5,6 +5,7 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -13,21 +14,27 @@ import androidx.lifecycle.ViewModelProvider; import androidx.media3.common.util.UnstableApi; import androidx.media3.session.MediaBrowser; import androidx.media3.session.SessionToken; +import androidx.recyclerview.widget.LinearLayoutManager; -import com.cappielloantonio.play.databinding.FragmentHomeTabPodcastBinding; import com.cappielloantonio.play.databinding.FragmentHomeTabRadioBinding; +import com.cappielloantonio.play.interfaces.ClickCallback; +import com.cappielloantonio.play.service.MediaManager; import com.cappielloantonio.play.service.MediaService; import com.cappielloantonio.play.ui.activity.MainActivity; -import com.cappielloantonio.play.viewmodel.HomeViewModel; +import com.cappielloantonio.play.ui.adapter.InternetRadioStationAdapter; +import com.cappielloantonio.play.util.Constants; +import com.cappielloantonio.play.viewmodel.RadioViewModel; import com.google.common.util.concurrent.ListenableFuture; @UnstableApi -public class HomeTabRadioFragment extends Fragment { +public class HomeTabRadioFragment extends Fragment implements ClickCallback { private static final String TAG = "HomeTabRadioFragment"; private FragmentHomeTabRadioBinding bind; private MainActivity activity; - private HomeViewModel homeViewModel; + private RadioViewModel radioViewModel; + + private InternetRadioStationAdapter internetRadioStationAdapter; private ListenableFuture mediaBrowserListenableFuture; @@ -38,11 +45,18 @@ public class HomeTabRadioFragment extends Fragment { bind = FragmentHomeTabRadioBinding.inflate(inflater, container, false); View view = bind.getRoot(); - homeViewModel = new ViewModelProvider(requireActivity()).get(HomeViewModel.class); + radioViewModel = new ViewModelProvider(requireActivity()).get(RadioViewModel.class); return view; } + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + initRadioStationView(); + } + @Override public void onStart() { super.onStart(); @@ -62,6 +76,28 @@ public class HomeTabRadioFragment extends Fragment { bind = null; } + private void initRadioStationView() { + bind.internetRadioStationRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); + bind.internetRadioStationRecyclerView.setHasFixedSize(true); + + internetRadioStationAdapter = new InternetRadioStationAdapter(this); + bind.internetRadioStationRecyclerView.setAdapter(internetRadioStationAdapter); + radioViewModel.getInternetRadioStations().observe(getViewLifecycleOwner(), internetRadioStations -> { + if (internetRadioStations == null) { + if (bind != null) + bind.internetRadioStationPlaceholder.placeholder.setVisibility(View.VISIBLE); + if (bind != null) bind.internetRadioStationSector.setVisibility(View.GONE); + } else { + if (bind != null) + bind.internetRadioStationPlaceholder.placeholder.setVisibility(View.GONE); + if (bind != null) + bind.internetRadioStationSector.setVisibility(!internetRadioStations.isEmpty() ? View.VISIBLE : View.GONE); + + internetRadioStationAdapter.setItems(internetRadioStations); + } + }); + } + private void initializeMediaBrowser() { mediaBrowserListenableFuture = new MediaBrowser.Builder(requireContext(), new SessionToken(requireContext(), new ComponentName(requireContext(), MediaService.class))).buildAsync(); } @@ -69,4 +105,15 @@ public class HomeTabRadioFragment extends Fragment { private void releaseMediaBrowser() { MediaBrowser.releaseFuture(mediaBrowserListenableFuture); } + + @Override + public void onInternetRadioStationClick(Bundle bundle) { + MediaManager.startRadio(mediaBrowserListenableFuture, bundle.getParcelable(Constants.INTERNET_RADIO_STATION_OBJECT)); + activity.setBottomSheetInPeek(true); + } + + @Override + public void onInternetRadioStationLongClick(Bundle bundle) { + Toast.makeText(requireContext(), "Long click!", Toast.LENGTH_SHORT).show(); + } } diff --git a/app/src/main/java/com/cappielloantonio/play/ui/fragment/PlayerControllerFragment.java b/app/src/main/java/com/cappielloantonio/play/ui/fragment/PlayerControllerFragment.java index 23db5744..05f0921b 100644 --- a/app/src/main/java/com/cappielloantonio/play/ui/fragment/PlayerControllerFragment.java +++ b/app/src/main/java/com/cappielloantonio/play/ui/fragment/PlayerControllerFragment.java @@ -1,9 +1,7 @@ package com.cappielloantonio.play.ui.fragment; import android.content.ComponentName; -import android.graphics.Point; import android.os.Bundle; -import android.view.Display; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -214,6 +212,17 @@ public class PlayerControllerFragment extends Fragment { bind.getRoot().findViewById(R.id.player_skip_silence_toggle_button).setVisibility(View.VISIBLE); setPlaybackParameters(mediaBrowser); break; + case Constants.MEDIA_TYPE_RADIO: + bind.getRoot().setShowShuffleButton(false); + bind.getRoot().setShowRewindButton(false); + bind.getRoot().setShowPreviousButton(false); + bind.getRoot().setShowNextButton(false); + bind.getRoot().setShowFastForwardButton(false); + bind.getRoot().setRepeatToggleModes(RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE); + bind.getRoot().findViewById(R.id.player_playback_speed_button).setVisibility(View.GONE); + bind.getRoot().findViewById(R.id.player_skip_silence_toggle_button).setVisibility(View.GONE); + setPlaybackParameters(mediaBrowser); + break; case Constants.MEDIA_TYPE_MUSIC: default: bind.getRoot().setShowShuffleButton(true); diff --git a/app/src/main/java/com/cappielloantonio/play/util/Constants.kt b/app/src/main/java/com/cappielloantonio/play/util/Constants.kt index e5207548..59abb1d6 100644 --- a/app/src/main/java/com/cappielloantonio/play/util/Constants.kt +++ b/app/src/main/java/com/cappielloantonio/play/util/Constants.kt @@ -12,6 +12,7 @@ object Constants { const val GENRE_OBJECT = "GENRE_OBJECT" const val PLAYLIST_OBJECT = "PLAYLIST_OBJECT" const val PODCAST_OBJECT = "PODCAST_OBJECT" + const val INTERNET_RADIO_STATION_OBJECT = "INTERNET_RADIO_STATION_OBJECT" const val ALBUM_RECENTLY_PLAYED = "ALBUM_RECENTLY_PLAYED" const val ALBUM_MOST_PLAYED = "ALBUM_MOST_PLAYED" @@ -42,6 +43,7 @@ object Constants { const val MEDIA_TYPE_PODCAST = "podcast" const val MEDIA_TYPE_AUDIOBOOK = "audiobook" const val MEDIA_TYPE_VIDEO = "video" + const val MEDIA_TYPE_RADIO = "radio" const val MEDIA_PLAYBACK_SPEED_080 = 0.8f const val MEDIA_PLAYBACK_SPEED_100 = 1.0f diff --git a/app/src/main/java/com/cappielloantonio/play/util/MappingUtil.java b/app/src/main/java/com/cappielloantonio/play/util/MappingUtil.java index 979dfc88..966c1135 100644 --- a/app/src/main/java/com/cappielloantonio/play/util/MappingUtil.java +++ b/app/src/main/java/com/cappielloantonio/play/util/MappingUtil.java @@ -11,6 +11,7 @@ import androidx.media3.common.util.UnstableApi; import com.cappielloantonio.play.App; import com.cappielloantonio.play.subsonic.models.Child; +import com.cappielloantonio.play.subsonic.models.InternetRadioStation; import java.util.ArrayList; import java.util.List; @@ -121,6 +122,36 @@ public class MappingUtil { .build(); } + public static MediaItem mapInternetRadioStation(InternetRadioStation internetRadioStation) { + Uri uri = Uri.parse(internetRadioStation.getStreamUrl()); + + Bundle bundle = new Bundle(); + bundle.putString("id", internetRadioStation.getId()); + bundle.putString("title", internetRadioStation.getName()); + bundle.putString("artist", uri.toString()); + bundle.putString("uri", uri.toString()); + bundle.putString("type", Constants.MEDIA_TYPE_RADIO); + + return new MediaItem.Builder() + .setMediaId(internetRadioStation.getId()) + .setMediaMetadata( + new MediaMetadata.Builder() + .setTitle(internetRadioStation.getName()) + .setArtist(internetRadioStation.getStreamUrl()) + .setExtras(bundle) + .build() + ) + .setRequestMetadata( + new MediaItem.RequestMetadata.Builder() + .setMediaUri(uri) + .setExtras(bundle) + .build() + ) + .setMimeType(MimeTypes.BASE_TYPE_AUDIO) + .setUri(uri) + .build(); + } + private static Uri getUri(Child media) { return DownloadUtil.getDownloadTracker(App.getContext()).isDownloaded(media.getId()) ? MusicUtil.getDownloadUri(media.getId()) diff --git a/app/src/main/java/com/cappielloantonio/play/viewmodel/RadioViewModel.java b/app/src/main/java/com/cappielloantonio/play/viewmodel/RadioViewModel.java new file mode 100644 index 00000000..f32af92c --- /dev/null +++ b/app/src/main/java/com/cappielloantonio/play/viewmodel/RadioViewModel.java @@ -0,0 +1,26 @@ +package com.cappielloantonio.play.viewmodel; + +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; + +import com.cappielloantonio.play.repository.RadioRepository; +import com.cappielloantonio.play.subsonic.models.InternetRadioStation; + +import java.util.List; + +public class RadioViewModel extends AndroidViewModel { + private final RadioRepository radioRepository; + + public RadioViewModel(@NonNull Application application) { + super(application); + + radioRepository = new RadioRepository(); + } + + public LiveData> getInternetRadioStations() { + return radioRepository.getInternetRadioStations(); + } +} diff --git a/app/src/main/res/layout/fragment_home_tab_radio.xml b/app/src/main/res/layout/fragment_home_tab_radio.xml index 9eb4d271..951fc2d9 100644 --- a/app/src/main/res/layout/fragment_home_tab_radio.xml +++ b/app/src/main/res/layout/fragment_home_tab_radio.xml @@ -1,7 +1,47 @@ - + android:layout_height="wrap_content"> + + + + + + + + + + + + + + - diff --git a/app/src/main/res/layout/item_home_internet_radio_station.xml b/app/src/main/res/layout/item_home_internet_radio_station.xml new file mode 100644 index 00000000..30606371 --- /dev/null +++ b/app/src/main/res/layout/item_home_internet_radio_station.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + \ No newline at end of file