diff --git a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt index c6d534634..d5932974e 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt @@ -57,6 +57,7 @@ import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.navigateSafe import org.oxycblt.auxio.util.setFullWidthLookup +import org.oxycblt.auxio.util.share import org.oxycblt.auxio.util.showToast import org.oxycblt.auxio.util.unlikelyToBeNull @@ -163,6 +164,10 @@ class AlbumDetailFragment : musicModel.addToPlaylist(currentAlbum) true } + R.id.action_share -> { + requireContext().share(currentAlbum) + true + } else -> false } } diff --git a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt index f1d699563..4dca06a0e 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt @@ -54,6 +54,7 @@ import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.navigateSafe import org.oxycblt.auxio.util.setFullWidthLookup +import org.oxycblt.auxio.util.share import org.oxycblt.auxio.util.showToast import org.oxycblt.auxio.util.unlikelyToBeNull @@ -159,6 +160,10 @@ class ArtistDetailFragment : musicModel.addToPlaylist(currentArtist) true } + R.id.action_share -> { + requireContext().share(currentArtist) + true + } else -> false } } diff --git a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt index 387f16b9f..b3d417761 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt @@ -55,6 +55,7 @@ import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.navigateSafe import org.oxycblt.auxio.util.setFullWidthLookup +import org.oxycblt.auxio.util.share import org.oxycblt.auxio.util.showToast import org.oxycblt.auxio.util.unlikelyToBeNull @@ -158,6 +159,10 @@ class GenreDetailFragment : musicModel.addToPlaylist(currentGenre) true } + R.id.action_share -> { + requireContext().share(currentGenre) + true + } else -> false } } diff --git a/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt index 10f0a8411..5b63806ad 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt @@ -58,6 +58,7 @@ import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.navigateSafe import org.oxycblt.auxio.util.setFullWidthLookup +import org.oxycblt.auxio.util.share import org.oxycblt.auxio.util.showToast import org.oxycblt.auxio.util.unlikelyToBeNull @@ -209,6 +210,10 @@ class PlaylistDetailFragment : musicModel.deletePlaylist(currentPlaylist) true } + R.id.action_share -> { + requireContext().share(currentPlaylist) + true + } R.id.action_save -> { detailModel.savePlaylistEdit() true diff --git a/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt b/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt index 4be7af179..7127400f4 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/ListFragment.kt @@ -37,6 +37,7 @@ import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.navigation.MainNavigationAction import org.oxycblt.auxio.navigation.NavigationViewModel import org.oxycblt.auxio.util.logD +import org.oxycblt.auxio.util.share import org.oxycblt.auxio.util.showToast /** @@ -104,6 +105,9 @@ abstract class ListFragment : R.id.action_go_album -> { navModel.exploreNavigateTo(song.album) } + R.id.action_share -> { + requireContext().share(song) + } R.id.action_playlist_add -> { musicModel.addToPlaylist(song) } @@ -152,6 +156,9 @@ abstract class ListFragment : R.id.action_playlist_add -> { musicModel.addToPlaylist(album) } + R.id.action_share -> { + requireContext().share(album) + } else -> { error("Unexpected menu item selected") } @@ -189,6 +196,9 @@ abstract class ListFragment : R.id.action_playlist_add -> { musicModel.addToPlaylist(artist) } + R.id.action_share -> { + requireContext().share(artist) + } else -> { error("Unexpected menu item selected") } @@ -226,6 +236,9 @@ abstract class ListFragment : R.id.action_playlist_add -> { musicModel.addToPlaylist(genre) } + R.id.action_share -> { + requireContext().share(genre) + } else -> { error("Unexpected menu item selected") } @@ -266,6 +279,9 @@ abstract class ListFragment : R.id.action_delete -> { musicModel.deletePlaylist(playlist) } + R.id.action_share -> { + requireContext().share(playlist) + } else -> { error("Unexpected menu item selected") } diff --git a/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionFragment.kt b/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionFragment.kt index cb7bce063..88bdba6d8 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/selection/SelectionFragment.kt @@ -26,6 +26,7 @@ import org.oxycblt.auxio.R import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.ui.ViewBindingFragment +import org.oxycblt.auxio.util.share import org.oxycblt.auxio.util.showToast /** @@ -79,6 +80,10 @@ abstract class SelectionFragment : playbackModel.shuffle(selectionModel.take()) true } + R.id.action_selection_share -> { + requireContext().share(selectionModel.take()) + true + } else -> false } } diff --git a/app/src/main/java/org/oxycblt/auxio/music/fs/Fs.kt b/app/src/main/java/org/oxycblt/auxio/music/fs/Fs.kt index defbb7c3f..63ef57a0c 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/fs/Fs.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/fs/Fs.kt @@ -147,6 +147,16 @@ data class MusicDirectories(val dirs: List, val shouldInclude: Boolea * @author Alexander Capehart (OxygenCobalt) */ data class MimeType(val fromExtension: String, val fromFormat: String?) { + + /** + * Return a mime-type such as "audio/ogg" + * + * @return A raw mime-type string. Will first try [fromFormat], then falling back to + * [fromExtension], and then null if that fails. + */ + val raw: String + get() = fromFormat ?: fromExtension + /** * Resolve the mime type into a human-readable format name, such as "Ogg Vorbis". * diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt index f7bad82e9..2cce12949 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt @@ -43,6 +43,7 @@ import org.oxycblt.auxio.playback.state.RepeatMode import org.oxycblt.auxio.playback.ui.StyledSeekBar import org.oxycblt.auxio.ui.ViewBindingFragment import org.oxycblt.auxio.util.collectImmediately +import org.oxycblt.auxio.util.share import org.oxycblt.auxio.util.showToast import org.oxycblt.auxio.util.systemBarInsetsCompat @@ -180,6 +181,10 @@ class PlaybackPanelFragment : } true } + R.id.action_share -> { + playbackModel.song.value?.let { requireContext().share(it) } + true + } else -> false } diff --git a/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt b/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt index 67d5d68ef..b70c6051a 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt @@ -27,6 +27,7 @@ import android.view.WindowInsets import androidx.annotation.RequiresApi import androidx.appcompat.widget.AppCompatButton import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.core.app.ShareCompat import androidx.core.graphics.Insets import androidx.core.graphics.drawable.DrawableCompat import androidx.navigation.NavController @@ -34,6 +35,12 @@ import androidx.navigation.NavDirections import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.viewbinding.ViewBinding +import java.lang.IllegalArgumentException +import org.oxycblt.auxio.music.Music +import org.oxycblt.auxio.music.MusicParent +import org.oxycblt.auxio.music.Song + +private const val MIME_TYPE_FALLBACK = "audio/*" /** * Get if this [View] contains the given [PointF], with optional leeway. @@ -262,3 +269,37 @@ fun WindowInsets.replaceSystemBarInsetsCompat( } } } + +/** + * Show system share sheet to share songs + * + * @param music the [Music] to share + */ +fun Context.share(music: Music) = share( + when (music) { + is Song -> listOf(music) + is MusicParent -> music.songs + } +) + +/** + * Show system share sheet to share multiple song + * + * @param songs the collection of [Song] to share + */ +fun Context.share(songs: Collection) { + if (songs.isEmpty()) { + return + } + val type = songs.mapTo(HashSet(songs.size)) { + it.mimeType.raw + }.singleOrNull() ?: MIME_TYPE_FALLBACK + ShareCompat.IntentBuilder(this) + .apply { + for (song in songs) { + addStream(song.uri) + } + } + .setType(type) + .startChooser() +} diff --git a/app/src/main/res/menu/menu_album_actions.xml b/app/src/main/res/menu/menu_album_actions.xml index 7292d9016..6f9f28aff 100644 --- a/app/src/main/res/menu/menu_album_actions.xml +++ b/app/src/main/res/menu/menu_album_actions.xml @@ -18,4 +18,7 @@ + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_album_detail.xml b/app/src/main/res/menu/menu_album_detail.xml index 34de6eb5e..f0b18e132 100644 --- a/app/src/main/res/menu/menu_album_detail.xml +++ b/app/src/main/res/menu/menu_album_detail.xml @@ -9,6 +9,9 @@ + diff --git a/app/src/main/res/menu/menu_album_song_actions.xml b/app/src/main/res/menu/menu_album_song_actions.xml index 256322f3e..d356eeedb 100644 --- a/app/src/main/res/menu/menu_album_song_actions.xml +++ b/app/src/main/res/menu/menu_album_song_actions.xml @@ -12,6 +12,9 @@ + diff --git a/app/src/main/res/menu/menu_artist_album_actions.xml b/app/src/main/res/menu/menu_artist_album_actions.xml index c94d6886f..a39b0127e 100644 --- a/app/src/main/res/menu/menu_artist_album_actions.xml +++ b/app/src/main/res/menu/menu_artist_album_actions.xml @@ -18,4 +18,7 @@ + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_artist_song_actions.xml b/app/src/main/res/menu/menu_artist_song_actions.xml index 4b20abd21..aaad4040a 100644 --- a/app/src/main/res/menu/menu_artist_song_actions.xml +++ b/app/src/main/res/menu/menu_artist_song_actions.xml @@ -12,6 +12,9 @@ + diff --git a/app/src/main/res/menu/menu_parent_actions.xml b/app/src/main/res/menu/menu_parent_actions.xml index 4e6112035..b741fd51b 100644 --- a/app/src/main/res/menu/menu_parent_actions.xml +++ b/app/src/main/res/menu/menu_parent_actions.xml @@ -12,6 +12,9 @@ + diff --git a/app/src/main/res/menu/menu_parent_detail.xml b/app/src/main/res/menu/menu_parent_detail.xml index 3a2225ea3..e73829b41 100644 --- a/app/src/main/res/menu/menu_parent_detail.xml +++ b/app/src/main/res/menu/menu_parent_detail.xml @@ -9,4 +9,7 @@ + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_playback.xml b/app/src/main/res/menu/menu_playback.xml index 0c24bb5da..5dca5f5dd 100644 --- a/app/src/main/res/menu/menu_playback.xml +++ b/app/src/main/res/menu/menu_playback.xml @@ -14,6 +14,9 @@ android:id="@+id/action_go_album" android:title="@string/lbl_go_album" app:showAsAction="never" /> + diff --git a/app/src/main/res/menu/menu_playlist_actions.xml b/app/src/main/res/menu/menu_playlist_actions.xml index 395ec387b..6a165da6a 100644 --- a/app/src/main/res/menu/menu_playlist_actions.xml +++ b/app/src/main/res/menu/menu_playlist_actions.xml @@ -18,4 +18,7 @@ + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_playlist_detail.xml b/app/src/main/res/menu/menu_playlist_detail.xml index 05a11b388..666629234 100644 --- a/app/src/main/res/menu/menu_playlist_detail.xml +++ b/app/src/main/res/menu/menu_playlist_detail.xml @@ -12,4 +12,7 @@ + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_selection_actions.xml b/app/src/main/res/menu/menu_selection_actions.xml index 568d04a62..e596b97a6 100644 --- a/app/src/main/res/menu/menu_selection_actions.xml +++ b/app/src/main/res/menu/menu_selection_actions.xml @@ -21,4 +21,8 @@ android:id="@+id/action_selection_shuffle" android:title="@string/lbl_shuffle_selected" app:showAsAction="never"/> + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_song_actions.xml b/app/src/main/res/menu/menu_song_actions.xml index abb176fb5..cba78013b 100644 --- a/app/src/main/res/menu/menu_song_actions.xml +++ b/app/src/main/res/menu/menu_song_actions.xml @@ -15,6 +15,9 @@ + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bf01fa3dd..c09fbe4ea 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -120,6 +120,7 @@ Go to artist Go to album View properties + Share Song properties File name