diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4bb0013..0d227b5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -76,6 +76,7 @@ dependencies { implementation(libs.androidx.navigation.compose) implementation(libs.androidx.navigation.ui.ktx) implementation(libs.androidx.hilt.navigation.compose) + implementation(libs.accompanist.navigation.material) implementation(libs.androidx.lifecycle.viewModel.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) @@ -96,6 +97,7 @@ dependencies { implementation(libs.androidx.compose.animation) implementation(libs.androidx.compose.ui.tooling.preview) debugImplementation(libs.androidx.compose.ui.tooling) + implementation(libs.androidx.compose.material) implementation(libs.androidx.compose.material.iconsExtended) compileOnly(libs.androidx.compose.compiler) implementation(libs.androidx.compose.paging) diff --git a/app/src/main/java/com/devdunnapps/amplify/di/AppModule.kt b/app/src/main/java/com/devdunnapps/amplify/di/AppModule.kt index 08e2fb6..01fe2d6 100644 --- a/app/src/main/java/com/devdunnapps/amplify/di/AppModule.kt +++ b/app/src/main/java/com/devdunnapps/amplify/di/AppModule.kt @@ -39,7 +39,9 @@ object AppModule { @Provides @Singleton - fun provideMusicServiceConnection(@ApplicationContext context: Context): MusicServiceConnection = + fun provideMusicServiceConnection( + @ApplicationContext context: Context + ): MusicServiceConnection = MusicServiceConnection(context, ComponentName(context, MusicService::class.java)) @Provides @@ -59,7 +61,8 @@ object AppModule { .create(PlexTVAPI::class.java) @Provides - fun providePlexTVRepository(plexTVAPI: PlexTVAPI): PlexTVRepository = PlexTVRepositoryImpl(plexTVAPI) + fun providePlexTVRepository(plexTVAPI: PlexTVAPI): PlexTVRepository = + PlexTVRepositoryImpl(plexTVAPI) @Provides fun providePlexAPI(@ApplicationContext context: Context): PlexAPI { @@ -82,7 +85,8 @@ object AppModule { @Provides @Named("library") fun provideLibrary(@ApplicationContext context: Context): String = - PreferencesUtils.readSharedSetting(context, PreferencesUtils.PREF_PLEX_SERVER_LIBRARY).orEmpty() + PreferencesUtils.readSharedSetting(context, PreferencesUtils.PREF_PLEX_SERVER_LIBRARY) + .orEmpty() @Provides fun providePlexRepository(api: PlexAPI, @Named("library") library: String): PlexRepository = @@ -90,7 +94,9 @@ object AppModule { @Provides @Singleton - fun providePreferencesDataStore(@ApplicationContext context: Context): DataStore = + fun providePreferencesDataStore( + @ApplicationContext context: Context + ): DataStore = DataStoreFactory.create( scope = CoroutineScope(Dispatchers.IO + SupervisorJob()), serializer = UserPreferencesSerializer() @@ -100,6 +106,7 @@ object AppModule { @Provides @Singleton - fun providePreferencesRepository(preferencesDataStore: DataStore): PreferencesRepository = - PreferencesRepositoryImpl(preferences = preferencesDataStore) + fun providePreferencesRepository( + preferencesDataStore: DataStore + ): PreferencesRepository = PreferencesRepositoryImpl(preferences = preferencesDataStore) } diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/about/AboutActivity.kt b/app/src/main/java/com/devdunnapps/amplify/ui/about/AboutActivity.kt index e05312f..6f2a6cd 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/about/AboutActivity.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/about/AboutActivity.kt @@ -15,7 +15,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import com.devdunnapps.amplify.R -import com.google.accompanist.themeadapter.material3.Mdc3Theme +import com.devdunnapps.amplify.ui.theme.Theme class AboutActivity : AppCompatActivity() { @@ -23,7 +23,7 @@ class AboutActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContent { - Mdc3Theme { + Theme { AboutScreen(onNavigateUp = ::onNavigateUp) } } @@ -32,7 +32,7 @@ class AboutActivity : AppCompatActivity() { @OptIn(ExperimentalMaterial3Api::class) @Composable -private fun AboutScreen(onNavigateUp: () -> Unit) { +internal fun AboutScreen(onNavigateUp: () -> Unit) { Scaffold( topBar = { AboutTopBar(onNavigateUp = onNavigateUp) }, content = { contentPadding -> diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/about/AboutNavigation.kt b/app/src/main/java/com/devdunnapps/amplify/ui/about/AboutNavigation.kt new file mode 100644 index 0000000..b48c457 --- /dev/null +++ b/app/src/main/java/com/devdunnapps/amplify/ui/about/AboutNavigation.kt @@ -0,0 +1,17 @@ +package com.devdunnapps.amplify.ui.about + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType +import androidx.navigation.compose.composable +import androidx.navigation.navArgument + +fun NavGraphBuilder.aboutScreen(onNavigateUp: () -> Unit) { + composable(route = "about") { + AboutScreen(onNavigateUp = onNavigateUp) + } +} + +fun NavController.navigateToAbout() { + navigate("about") +} diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/addtoplaylist/AddToPlaylistBottomSheetFragment.kt b/app/src/main/java/com/devdunnapps/amplify/ui/addtoplaylist/AddToPlaylistBottomSheetFragment.kt index e65b4ae..ddcf852 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/addtoplaylist/AddToPlaylistBottomSheetFragment.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/addtoplaylist/AddToPlaylistBottomSheetFragment.kt @@ -31,8 +31,8 @@ import androidx.lifecycle.viewmodel.compose.viewModel import com.devdunnapps.amplify.R import com.devdunnapps.amplify.domain.models.Playlist import com.devdunnapps.amplify.ui.components.LoadingPager +import com.devdunnapps.amplify.ui.theme.Theme import com.devdunnapps.amplify.utils.Resource -import com.google.accompanist.themeadapter.material3.Mdc3Theme import com.google.android.material.bottomsheet.BottomSheetDialogFragment import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch @@ -53,7 +53,7 @@ class AddToPlaylistBottomSheetFragment : BottomSheetDialogFragment() { return ComposeView(requireContext()).apply { setContent { - Mdc3Theme { + Theme { AddToPlaylistBottomSheet(viewModel = viewModel) } } diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/album/AlbumFragment.kt b/app/src/main/java/com/devdunnapps/amplify/ui/album/AlbumFragment.kt index bcc2c4e..285e3f7 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/album/AlbumFragment.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/album/AlbumFragment.kt @@ -6,7 +6,17 @@ import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.RoundedCornerShape @@ -14,9 +24,19 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.outlined.PlaylistPlay import androidx.compose.material.icons.outlined.QueueMusic -import androidx.compose.material3.* +import androidx.compose.material3.Button +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -38,6 +58,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.fragment.findNavController import coil.compose.AsyncImage import com.devdunnapps.amplify.MobileNavigationDirections @@ -47,6 +68,7 @@ import com.devdunnapps.amplify.domain.models.Song import com.devdunnapps.amplify.ui.components.ErrorScreen import com.devdunnapps.amplify.ui.components.ExpandableText import com.devdunnapps.amplify.ui.components.LoadingScreen +import com.devdunnapps.amplify.ui.theme.Theme import com.devdunnapps.amplify.ui.utils.FragmentSubDestinationScaffold import com.devdunnapps.amplify.ui.utils.getCurrentSizeClass import com.devdunnapps.amplify.utils.PlexUtils @@ -82,7 +104,11 @@ class AlbumFragment : Fragment() { } @Composable -fun AlbumRoute(viewModel: AlbumViewModel, onSongMenuClick: (String) -> Unit, modifier: Modifier = Modifier) { +fun AlbumRoute( + viewModel: AlbumViewModel = hiltViewModel(), + onSongMenuClick: (String) -> Unit, + modifier: Modifier = Modifier +) { AlbumScreen( album = viewModel.album.collectAsState().value, onSongClick = { viewModel.playSong(it) }, @@ -552,7 +578,7 @@ private fun AlbumSong( @Preview @Composable private fun PreviewAlbumHeader() { - Mdc3Theme { + Theme { Surface { val album = Album( artistId = "0", @@ -579,7 +605,7 @@ private fun PreviewAlbumHeader() { @Preview @Composable private fun PreviewAlbumSong() { - Mdc3Theme { + Theme { Surface { val song = Song( year = "2021", diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/album/AlbumNavigation.kt b/app/src/main/java/com/devdunnapps/amplify/ui/album/AlbumNavigation.kt new file mode 100644 index 0000000..bca4d65 --- /dev/null +++ b/app/src/main/java/com/devdunnapps/amplify/ui/album/AlbumNavigation.kt @@ -0,0 +1,22 @@ +package com.devdunnapps.amplify.ui.album + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType +import androidx.navigation.compose.composable +import androidx.navigation.navArgument + +fun NavGraphBuilder.albumScreen( + onOpenSongMenu: (String) -> Unit +) { + composable( + route = "albums/{albumId}", + arguments = listOf(navArgument("albumId") { type = NavType.StringType }) + ) { + AlbumRoute(onSongMenuClick = onOpenSongMenu) + } +} + +fun NavController.navigateToAlbum(albumId: String) { + navigate("albums/$albumId") +} diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/album/AlbumViewModel.kt b/app/src/main/java/com/devdunnapps/amplify/ui/album/AlbumViewModel.kt index 9d88812..0d35b0f 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/album/AlbumViewModel.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/album/AlbumViewModel.kt @@ -29,7 +29,7 @@ class AlbumViewModel @Inject constructor( private val musicServiceConnection: MusicServiceConnection ) : ViewModel() { - private val albumId = AlbumFragmentArgs.fromSavedStateHandle(savedStateHandle).albumId + private val albumId: String = checkNotNull(savedStateHandle["albumId"]) private val _album = MutableStateFlow>(Resource.Loading) val album = _album.asStateFlow() diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/albums/AlbumsFragment.kt b/app/src/main/java/com/devdunnapps/amplify/ui/albums/AlbumsFragment.kt index 7bdb506..7ea15b4 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/albums/AlbumsFragment.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/albums/AlbumsFragment.kt @@ -52,7 +52,7 @@ class AlbumsFragment : Fragment() { } @Composable -private fun AlbumsRoute( +internal fun AlbumsRoute( onAlbumClick: (String) -> Unit, modifier: Modifier = Modifier, viewModel: AlbumsViewModel = hiltViewModel() diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/artist/ArtistFragment.kt b/app/src/main/java/com/devdunnapps/amplify/ui/artist/ArtistFragment.kt index dd1f492..38f103d 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/artist/ArtistFragment.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/artist/ArtistFragment.kt @@ -35,6 +35,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import coil.compose.AsyncImage @@ -96,8 +97,8 @@ class ArtistFragment : Fragment() { } @Composable -private fun ArtistRoute( - viewModel: ArtistViewModel, +internal fun ArtistRoute( + viewModel: ArtistViewModel = hiltViewModel(), onAlbumClick: (String) -> Unit, onViewAllAlbumsClick: () -> Unit, onViewAllSinglesEPsClick: () -> Unit, diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/artist/ArtistNavigation.kt b/app/src/main/java/com/devdunnapps/amplify/ui/artist/ArtistNavigation.kt new file mode 100644 index 0000000..05a1a86 --- /dev/null +++ b/app/src/main/java/com/devdunnapps/amplify/ui/artist/ArtistNavigation.kt @@ -0,0 +1,34 @@ +package com.devdunnapps.amplify.ui.artist + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType +import androidx.navigation.compose.composable +import androidx.navigation.navArgument + +private const val ARTIST_ID_ARG = "artistId" + +fun NavGraphBuilder.artistScreen( + onNavigateToAlbum: (String) -> Unit, + onNavigateToAllArtistAlbums: () -> Unit, + onNavigateToAllArtistEPsSingles: () -> Unit, + onOpenSongMenu: (String) -> Unit, + onNavigateToAllArtistSongs: () -> Unit +) { + composable( + route = "artists/{artistId}", + arguments = listOf(navArgument(ARTIST_ID_ARG) { type = NavType.StringType }) + ) { + ArtistRoute( + onAlbumClick = onNavigateToAlbum, + onViewAllAlbumsClick = onNavigateToAllArtistAlbums, + onViewAllSinglesEPsClick = onNavigateToAllArtistEPsSingles, + onSongMenuClick = onOpenSongMenu, + onViewAllSongsClick = onNavigateToAllArtistSongs + ) + } +} + +fun NavController.navigateToArtist(artistId: String) { + navigate("artists/$artistId") +} diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/artist/ArtistViewModel.kt b/app/src/main/java/com/devdunnapps/amplify/ui/artist/ArtistViewModel.kt index 27d92fb..922cf5f 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/artist/ArtistViewModel.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/artist/ArtistViewModel.kt @@ -32,7 +32,7 @@ class ArtistViewModel @Inject constructor( private val musicServiceConnection: MusicServiceConnection ) : ViewModel() { - private val artistId = ArtistFragmentArgs.fromSavedStateHandle(savedStateHandle).artistKey + private val artistId: String = checkNotNull(savedStateHandle["artistId"]) private val _artistSongs = MutableStateFlow>>(Resource.Loading) val artistSongs = _artistSongs.asStateFlow() diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/artists/ArtistsFragment.kt b/app/src/main/java/com/devdunnapps/amplify/ui/artists/ArtistsFragment.kt index 8d14059..381bb8a 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/artists/ArtistsFragment.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/artists/ArtistsFragment.kt @@ -52,7 +52,7 @@ class ArtistsFragment : Fragment() { } @Composable -private fun ArtistsRoute( +internal fun ArtistsRoute( onArtistClick: (String) -> Unit, modifier: Modifier = Modifier, viewModel: ArtistsViewModel = hiltViewModel() diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/components/AlbumCard.kt b/app/src/main/java/com/devdunnapps/amplify/ui/components/AlbumCard.kt index eab2aa1..db42289 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/components/AlbumCard.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/components/AlbumCard.kt @@ -20,8 +20,8 @@ import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import com.devdunnapps.amplify.R import com.devdunnapps.amplify.domain.models.Album +import com.devdunnapps.amplify.ui.theme.Theme import com.devdunnapps.amplify.utils.PlexUtils -import com.google.accompanist.themeadapter.material3.Mdc3Theme @Composable fun AlbumCard(onClick: () -> Unit, album: Album, modifier: Modifier = Modifier) { @@ -54,7 +54,7 @@ fun AlbumCard(onClick: () -> Unit, album: Album, modifier: Modifier = Modifier) @Preview @Composable fun AlbumCardPreview() { - Mdc3Theme { + Theme { AlbumCard( onClick = {}, album = Album( diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/components/AmplifyScaffold.kt b/app/src/main/java/com/devdunnapps/amplify/ui/components/AmplifyScaffold.kt index cb0c2f4..cc7dc4a 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/components/AmplifyScaffold.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/components/AmplifyScaffold.kt @@ -5,7 +5,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import com.google.accompanist.themeadapter.material3.Mdc3Theme +import com.devdunnapps.amplify.ui.theme.Theme @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -15,7 +15,7 @@ fun AmplifyScaffold( floatingActionButton: @Composable () -> Unit = {}, content: @Composable (PaddingValues) -> Unit ) { - Mdc3Theme { + Theme { Scaffold( topBar = topBar, content = content, diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/components/ArtistCard.kt b/app/src/main/java/com/devdunnapps/amplify/ui/components/ArtistCard.kt index b699403..22abce3 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/components/ArtistCard.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/components/ArtistCard.kt @@ -17,16 +17,14 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import coil.compose.AsyncImage -import com.devdunnapps.amplify.R import com.devdunnapps.amplify.domain.models.Artist +import com.devdunnapps.amplify.ui.theme.Theme import com.devdunnapps.amplify.utils.PlexUtils -import com.google.accompanist.themeadapter.material3.Mdc3Theme @Composable fun ArtistCard(onClick: () -> Unit, artist: Artist, modifier: Modifier = Modifier) { @@ -61,7 +59,7 @@ fun ArtistCard(onClick: () -> Unit, artist: Artist, modifier: Modifier = Modifie @Preview @Composable fun ArtistCardPreview() { - Mdc3Theme { + Theme { ArtistCard( onClick = {}, artist = Artist( diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/components/ExpandableText.kt b/app/src/main/java/com/devdunnapps/amplify/ui/components/ExpandableText.kt index a5f9486..fea2ece 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/components/ExpandableText.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/components/ExpandableText.kt @@ -7,7 +7,11 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -15,7 +19,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.devdunnapps.amplify.R -import com.google.accompanist.themeadapter.material3.Mdc3Theme +import com.devdunnapps.amplify.ui.theme.Theme @Composable fun ExpandableText( @@ -59,7 +63,7 @@ fun ExpandableText( @Preview @Composable fun ExpandableTextPreview() { - Mdc3Theme { + Theme { Surface { ExpandableText(text = stringResource(id = R.string.sample_summary)) } diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/components/PlaylistItem.kt b/app/src/main/java/com/devdunnapps/amplify/ui/components/PlaylistItem.kt index 2677617..2bed4ae 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/components/PlaylistItem.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/components/PlaylistItem.kt @@ -1,7 +1,13 @@ package com.devdunnapps.amplify.ui.components import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material3.Icon @@ -23,8 +29,8 @@ import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import com.devdunnapps.amplify.R import com.devdunnapps.amplify.domain.models.Playlist +import com.devdunnapps.amplify.ui.theme.Theme import com.devdunnapps.amplify.utils.PlexUtils -import com.google.accompanist.themeadapter.material3.Mdc3Theme @Composable fun PlaylistItem( @@ -98,7 +104,7 @@ fun PlaylistItemPreview() { summary = "", composite = "" ) - Mdc3Theme { + Theme { Surface { PlaylistItem( playlist = playlist, diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/components/RootDestinationAppBar.kt b/app/src/main/java/com/devdunnapps/amplify/ui/components/RootDestinationAppBar.kt index c6ba081..83f90c6 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/components/RootDestinationAppBar.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/components/RootDestinationAppBar.kt @@ -1,7 +1,5 @@ package com.devdunnapps.amplify.ui.components -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.statusBars import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.Search @@ -10,7 +8,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import com.devdunnapps.amplify.R -import com.google.accompanist.themeadapter.material3.Mdc3Theme +import com.devdunnapps.amplify.ui.theme.Theme @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -26,7 +24,7 @@ fun RootDestinationAppBar( CenterAlignedTopAppBar( title = { Text(text = title) }, scrollBehavior = scrollBehavior, - windowInsets = WindowInsets.statusBars, +// windowInsets = WindowInsets.statusBars, actions = { IconButton(onClick = onNavigateToSearch) { Icon( @@ -68,7 +66,7 @@ fun RootDestinationAppBar( @Preview @Composable fun AmplifyAppBarPreview() { - Mdc3Theme { + Theme { RootDestinationAppBar( title = "App Bar", onNavigateToSearch = {}, diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/components/SongItem.kt b/app/src/main/java/com/devdunnapps/amplify/ui/components/SongItem.kt index b51c73f..5d16130 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/components/SongItem.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/components/SongItem.kt @@ -1,7 +1,13 @@ package com.devdunnapps.amplify.ui.components import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material3.Icon @@ -24,9 +30,9 @@ import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import com.devdunnapps.amplify.R import com.devdunnapps.amplify.domain.models.Song +import com.devdunnapps.amplify.ui.theme.Theme import com.devdunnapps.amplify.utils.PlexUtils import com.devdunnapps.amplify.utils.TimeUtils -import com.google.accompanist.themeadapter.material3.Mdc3Theme @Composable fun SongItem( @@ -105,7 +111,7 @@ fun SongItemPreview() { userRating = 0, playCount = 10 ) - Mdc3Theme { + Theme { Surface { SongItem( song = song, diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/components/SubDestinationAppBar.kt b/app/src/main/java/com/devdunnapps/amplify/ui/components/SubDestinationAppBar.kt index f08a4fe..2d74be9 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/components/SubDestinationAppBar.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/components/SubDestinationAppBar.kt @@ -11,7 +11,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import com.devdunnapps.amplify.R -import com.google.accompanist.themeadapter.material3.Mdc3Theme +import com.devdunnapps.amplify.ui.theme.Theme @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -75,7 +75,7 @@ fun SubDestinationAppBar( @Preview @Composable fun SubDestinationAppBarPreview() { - Mdc3Theme { + Theme { SubDestinationAppBar( title = "App Bar", onNavigateUp = {}, diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/main/AmplifyApp.kt b/app/src/main/java/com/devdunnapps/amplify/ui/main/AmplifyApp.kt new file mode 100644 index 0000000..971fe3e --- /dev/null +++ b/app/src/main/java/com/devdunnapps/amplify/ui/main/AmplifyApp.kt @@ -0,0 +1,150 @@ +package com.devdunnapps.amplify.ui.main + +import android.support.v4.media.MediaMetadataCompat +import android.support.v4.media.session.PlaybackStateCompat +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.consumeWindowInsets +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.BottomSheetScaffold +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.NavigationBar +import androidx.compose.material3.NavigationBarItem +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SheetValue +import androidx.compose.material3.Text +import androidx.compose.material3.windowsizeclass.WindowSizeClass +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.navigation.compose.NavHost +import com.devdunnapps.amplify.ui.components.RootDestinationAppBar +import com.devdunnapps.amplify.ui.navigation.TopLevelDestination +import com.devdunnapps.amplify.ui.nowplaying.NowPlayingScreen +import com.devdunnapps.amplify.utils.NOTHING_PLAYING +import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi +import com.google.accompanist.navigation.material.ModalBottomSheetLayout +import kotlinx.coroutines.launch + +@OptIn( + ExperimentalMaterial3Api::class, + ExperimentalMaterialNavigationApi::class, + ExperimentalLayoutApi::class +) +@Composable +fun AmplifyApp( + windowSizeClass: WindowSizeClass, + appState: AmplifyAppState = rememberAmplifyAppState(windowSizeClass = windowSizeClass), + playbackState: Int, + currentlyPlayingMetadata: MediaMetadataCompat +) { + ModalBottomSheetLayout(bottomSheetNavigator = appState.bottomSheetNavigator) { + Scaffold( + bottomBar = { + AmplifyBottomBar( + destinations = appState.topLevelDestinations, + onNavigateToDestination = appState::navigateToTopLevelDestination, + currentDestination = appState.currentTopLevelDestination, + ) + }, + topBar = { + RootDestinationAppBar( + title = "Amplify", + onNavigateToSearch = { /*TODO*/ }, + onNavigateToSettings = { /*TODO*/ }, + onNavigateToAbout = { /*TODO*/ } + ) + }, + modifier = Modifier.fillMaxSize() + ) { padding -> + BottomSheetScaffold( + modifier = Modifier + .padding(padding) + .consumeWindowInsets(padding), + scaffoldState = appState.bottomSheetScaffoldState, + sheetPeekHeight = 64.dp, + + sheetContent = { + val bottomSheetState = appState.bottomSheetScaffoldState.bottomSheetState + val coroutineScope = rememberCoroutineScope() + + println(bottomSheetState.currentValue) + + if (bottomSheetState.targetValue == SheetValue.Expanded || bottomSheetState.isVisible) { + NowPlayingScreen( + onCollapseNowPlaying = { + coroutineScope.launch { bottomSheetState.hide() } + }, + onNowPlayingMenuClick = { + } + ) + } + +// if (bottomSheetState.targetValue == SheetValue.PartiallyExpanded) { + if (currentlyPlayingMetadata != NOTHING_PLAYING) { + NowPlayingCollapsed( + albumArtUrl = currentlyPlayingMetadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI), + title = currentlyPlayingMetadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE), + subtitle = currentlyPlayingMetadata.getString(MediaMetadataCompat.METADATA_KEY_ARTIST), + isPlaying = playbackState == PlaybackStateCompat.STATE_PLAYING, + onPlayPauseClick = { }, + onSkipClick = { }, + modifier = Modifier.clickable { + coroutineScope.launch { bottomSheetState.expand() } + } + ) + } +// } + } + ) { childPadding -> + Column(modifier = Modifier.padding(childPadding)) { + NavHost( + navController = appState.navController, + startDestination = "main_route" + ) { + mainGraph( + navController = appState.navController + ) + } + } + } + } + } +} + +@Composable +private fun AmplifyBottomBar( + destinations: List, + onNavigateToDestination: (TopLevelDestination) -> Unit, + currentDestination: TopLevelDestination, + modifier: Modifier = Modifier +) { + NavigationBar(modifier = modifier) { + destinations.forEach { destination -> + val isSelected = currentDestination == destination + + NavigationBarItem( + selected = isSelected, + onClick = { onNavigateToDestination(destination) }, + icon = { + Icon( + painter = painterResource( + id = if (isSelected) + destination.selectedIcon + else + destination.unselectedIcon + ), + contentDescription = null + ) + }, + label = { Text(text = stringResource(id = destination.iconText)) } + ) + } + } +} diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/main/AmplifyAppState.kt b/app/src/main/java/com/devdunnapps/amplify/ui/main/AmplifyAppState.kt new file mode 100644 index 0000000..a13af00 --- /dev/null +++ b/app/src/main/java/com/devdunnapps/amplify/ui/main/AmplifyAppState.kt @@ -0,0 +1,71 @@ +package com.devdunnapps.amplify.ui.main + +import androidx.compose.material3.BottomSheetScaffoldState +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.rememberBottomSheetScaffoldState +import androidx.compose.material3.windowsizeclass.WindowSizeClass +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.navigation.NavGraph.Companion.findStartDestination +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import androidx.navigation.navOptions +import com.devdunnapps.amplify.ui.navigation.TopLevelDestination +import com.google.accompanist.navigation.material.BottomSheetNavigator +import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi +import com.google.accompanist.navigation.material.rememberBottomSheetNavigator + +@OptIn(ExperimentalMaterialNavigationApi::class, ExperimentalMaterial3Api::class) +@Composable +fun rememberAmplifyAppState( + windowSizeClass: WindowSizeClass, + bottomSheetNavigator: BottomSheetNavigator = rememberBottomSheetNavigator(), + navController: NavHostController = rememberNavController(bottomSheetNavigator), + bottomSheetScaffoldState: BottomSheetScaffoldState = rememberBottomSheetScaffoldState() +): AmplifyAppState = + remember(navController, bottomSheetNavigator, windowSizeClass, bottomSheetScaffoldState) { + AmplifyAppState(navController, bottomSheetNavigator, windowSizeClass, bottomSheetScaffoldState) + } + +@OptIn(ExperimentalMaterialNavigationApi::class, ExperimentalMaterial3Api::class) +@Stable +class AmplifyAppState( + val navController: NavHostController, + val bottomSheetNavigator: BottomSheetNavigator, + val windowSizeClass: WindowSizeClass, + val bottomSheetScaffoldState: BottomSheetScaffoldState +) { + var currentTopLevelDestination: TopLevelDestination by mutableStateOf(TopLevelDestination.ARTISTS) + private set + + val topLevelDestinations: List = TopLevelDestination.values().asList() + + fun navigateToTopLevelDestination(topLevelDestination: TopLevelDestination) { + currentTopLevelDestination = topLevelDestination + + val topLevelNavOptions = navOptions { + // Pop up to the start destination of the graph to + // avoid building up a large stack of destinations + // on the back stack as users select items + popUpTo(navController.graph.findStartDestination().id) { + saveState = true + } + // Avoid multiple copies of the same destination when + // reselecting the same item + launchSingleTop = true + // Restore state when reselecting a previously selected item + restoreState = true + } + + when (topLevelDestination) { + TopLevelDestination.ARTISTS -> navController.navigate(ArtistsDestination.route) + TopLevelDestination.ALBUMS -> navController.navigate(AlbumsDestination.route) + TopLevelDestination.SONGS -> navController.navigate(SongsDestination.route) + TopLevelDestination.PLAYLISTS -> navController.navigate(PlaylistsDestination.route) + } + } +} diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/main/MainActivity.kt b/app/src/main/java/com/devdunnapps/amplify/ui/main/MainActivity.kt index 5c60705..e4c0220 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/main/MainActivity.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/main/MainActivity.kt @@ -2,18 +2,15 @@ package com.devdunnapps.amplify.ui.main import android.content.Intent import android.os.Bundle -import android.support.v4.media.MediaMetadataCompat -import android.support.v4.media.session.PlaybackStateCompat -import android.util.TypedValue -import android.view.View +import androidx.activity.compose.setContent import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Pause @@ -23,6 +20,8 @@ import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text +import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi +import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.ui.Alignment @@ -31,135 +30,139 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.constraintlayout.widget.ConstraintLayout -import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.WindowCompat -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import androidx.navigation.Navigation.findNavController -import androidx.navigation.fragment.NavHostFragment -import androidx.navigation.ui.NavigationUI -import androidx.navigation.ui.setupWithNavController import coil.compose.AsyncImage -import com.devdunnapps.amplify.MobileNavigationDirections -import com.devdunnapps.amplify.R import com.devdunnapps.amplify.databinding.ActivityMainBinding -import com.devdunnapps.amplify.ui.nowplaying.NowPlayingScreen import com.devdunnapps.amplify.ui.onboarding.OnBoardingActivity -import com.devdunnapps.amplify.utils.NOTHING_PLAYING +import com.devdunnapps.amplify.ui.theme.Theme import com.devdunnapps.amplify.utils.PreferencesUtils -import com.google.accompanist.themeadapter.material3.Mdc3Theme import com.google.android.material.bottomsheet.BottomSheetBehavior import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch @AndroidEntryPoint class MainActivity : AppCompatActivity() { - private lateinit var binding: ActivityMainBinding +// private lateinit var binding: ActivityMainBinding lateinit var bottomSheet: BottomSheetBehavior private val viewModel: MainActivityViewModel by viewModels() + @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) startOnBoardingIfFirstTime() - binding = ActivityMainBinding.inflate(layoutInflater) - setContentView(binding.root) - drawUnderSystemBars() - val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_content_frame) as NavHostFragment - binding.navView.apply { - val navController = navHostFragment.navController - setupWithNavController(navController) - setOnItemSelectedListener { item -> - if (selectedItemId == item.itemId) - navController.popBackStack(item.itemId, false) - - NavigationUI.onNavDestinationSelected(item, navController) - true - } - } - bottomSheet = BottomSheetBehavior.from(binding.bottomSheet) - binding.nowPlayingBoxCollapsed.setContent { - Mdc3Theme { + setContent { + Theme { val playbackState = viewModel.playbackState.collectAsState().value.state val currentlyPlayingMetadata = viewModel.mediaMetadata.collectAsState().value - if (currentlyPlayingMetadata != NOTHING_PLAYING) { - NowPlayingCollapsed( - albumArtUrl = currentlyPlayingMetadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI), - title = currentlyPlayingMetadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE), - subtitle = currentlyPlayingMetadata.getString(MediaMetadataCompat.METADATA_KEY_ARTIST), - isPlaying = playbackState == PlaybackStateCompat.STATE_PLAYING, - onPlayPauseClick = viewModel::togglePlaybackState, - onSkipClick = viewModel::skipToNext - ) - } - } - } - - binding.nowPlayingExpanded.setContent { - NowPlayingScreen( - onCollapseNowPlaying = { - bottomSheet.state = BottomSheetBehavior.STATE_COLLAPSED - }, - onNowPlayingMenuClick = { songId -> - val action = MobileNavigationDirections.actionGlobalNavigationSongBottomSheet(songId) - findNavController(binding.navContentFrame).navigate(action) - } - ) - } - - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.playbackState.collect { - if (it.state == PlaybackStateCompat.STATE_PLAYING) { - val marginInDp = - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 64f, resources.displayMetrics).toInt() - (binding.navContentFrame.layoutParams as CoordinatorLayout.LayoutParams).setMargins(0, 0, 0, marginInDp) - - binding.bottomSheet.visibility = View.VISIBLE - } - } + AmplifyApp( + windowSizeClass = calculateWindowSizeClass(this), + playbackState = playbackState, + currentlyPlayingMetadata = currentlyPlayingMetadata + ) } } - bottomSheet.isGestureInsetBottomIgnored = true - bottomSheet.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { - override fun onStateChanged(bottomSheet: View, newState: Int) { - when (newState) { - BottomSheetBehavior.STATE_EXPANDED -> { - binding.navView.visibility = View.GONE - binding.nowPlayingBoxCollapsed.visibility = View.INVISIBLE - } - - BottomSheetBehavior.STATE_COLLAPSED -> { - binding.nowPlayingExpanded.visibility = View.INVISIBLE - } - - else -> Unit - } - } - - override fun onSlide(bottomSheet: View, slideOffset: Float) { - binding.navView.visibility = View.VISIBLE - binding.nowPlayingBoxCollapsed.visibility = View.VISIBLE - binding.nowPlayingExpanded.visibility = View.VISIBLE - binding.nowPlayingExpanded.alpha = slideOffset - binding.nowPlayingBoxCollapsed.alpha = 1 - slideOffset - - // TODO: animate the navigation view off the page - } - }) - - binding.bottomSheet.setOnClickListener { - bottomSheet.state = BottomSheetBehavior.STATE_EXPANDED - } +// binding = ActivityMainBinding.inflate(layoutInflater) +// setContentView(binding.root) +// +// drawUnderSystemBars() +// +// val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_content_frame) as NavHostFragment +// binding.navView.apply { +// val navController = navHostFragment.navController +// setupWithNavController(navController) +// setOnItemSelectedListener { item -> +// if (selectedItemId == item.itemId) +// navController.popBackStack(item.itemId, false) +// +// NavigationUI.onNavDestinationSelected(item, navController) +// true +// } +// } +// +// bottomSheet = BottomSheetBehavior.from(binding.bottomSheet) +// +// binding.nowPlayingBoxCollapsed.setContent { +// Mdc3Theme { +// +// +// if (currentlyPlayingMetadata != NOTHING_PLAYING) { +// NowPlayingCollapsed( +// albumArtUrl = currentlyPlayingMetadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI), +// title = currentlyPlayingMetadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE), +// subtitle = currentlyPlayingMetadata.getString(MediaMetadataCompat.METADATA_KEY_ARTIST), +// isPlaying = playbackState == PlaybackStateCompat.STATE_PLAYING, +// onPlayPauseClick = viewModel::togglePlaybackState, +// onSkipClick = viewModel::skipToNext +// ) +// } +// } +// } +// +// binding.nowPlayingExpanded.setContent { +// NowPlayingScreen( +// onCollapseNowPlaying = { +// bottomSheet.state = BottomSheetBehavior.STATE_COLLAPSED +// }, +// onNowPlayingMenuClick = { songId -> +// val action = MobileNavigationDirections.actionGlobalNavigationSongBottomSheet(songId) +// findNavController(binding.navContentFrame).navigate(action) +// } +// ) +// } +// +// lifecycleScope.launch { +// repeatOnLifecycle(Lifecycle.State.STARTED) { +// viewModel.playbackState.collect { +// if (it.state == PlaybackStateCompat.STATE_PLAYING) { +// val marginInDp = +// TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 64f, resources.displayMetrics).toInt() +// (binding.navContentFrame.layoutParams as CoordinatorLayout.LayoutParams).setMargins(0, 0, 0, marginInDp) +// +// binding.bottomSheet.visibility = View.VISIBLE +// } +// } +// } +// } +// +// bottomSheet.isGestureInsetBottomIgnored = true +// bottomSheet.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { +// override fun onStateChanged(bottomSheet: View, newState: Int) { +// when (newState) { +// BottomSheetBehavior.STATE_EXPANDED -> { +// binding.navView.visibility = View.GONE +// binding.nowPlayingBoxCollapsed.visibility = View.INVISIBLE +// } +// +// BottomSheetBehavior.STATE_COLLAPSED -> { +// binding.nowPlayingExpanded.visibility = View.INVISIBLE +// } +// +// else -> Unit +// } +// } +// +// override fun onSlide(bottomSheet: View, slideOffset: Float) { +// binding.navView.visibility = View.VISIBLE +// binding.nowPlayingBoxCollapsed.visibility = View.VISIBLE +// binding.nowPlayingExpanded.visibility = View.VISIBLE +// binding.nowPlayingExpanded.alpha = slideOffset +// binding.nowPlayingBoxCollapsed.alpha = 1 - slideOffset +// +// // TODO: animate the navigation view off the page +// } +// }) +// +// binding.bottomSheet.setOnClickListener { +// bottomSheet.state = BottomSheetBehavior.STATE_EXPANDED +// } } /** @@ -184,32 +187,33 @@ class MainActivity : AppCompatActivity() { val shouldOpenNowPlaying = intent.getBooleanExtra("launchNowPlaying", false) if (shouldOpenNowPlaying) { - bottomSheet.state = BottomSheetBehavior.STATE_EXPANDED +// bottomSheet.state = BottomSheetBehavior.STATE_EXPANDED } } - override fun onBackPressed() { - if (bottomSheet.state == BottomSheetBehavior.STATE_EXPANDED) { - bottomSheet.state = BottomSheetBehavior.STATE_COLLAPSED - } else { - super.onBackPressed() - } - } +// override fun onBackPressed() { +// if (bottomSheet.state == BottomSheetBehavior.STATE_EXPANDED) { +// bottomSheet.state = BottomSheetBehavior.STATE_COLLAPSED +// } else { +// super.onBackPressed() +// } +// } } @Composable -private fun NowPlayingCollapsed( +internal fun NowPlayingCollapsed( albumArtUrl: String, title: String, subtitle: String, isPlaying: Boolean, + modifier: Modifier = Modifier, onPlayPauseClick: () -> Unit, onSkipClick: () -> Unit ) { Row( verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .height(64.dp) + modifier = modifier + .requiredHeight(64.dp) .fillMaxWidth() .background(MaterialTheme.colorScheme.secondaryContainer) ) { @@ -254,7 +258,7 @@ private fun NowPlayingCollapsed( @Preview @Composable private fun NowPlayingCollapsedPreview() { - Mdc3Theme { + Theme { NowPlayingCollapsed( albumArtUrl = "", title = "Vienna", diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/main/MainNavigation.kt b/app/src/main/java/com/devdunnapps/amplify/ui/main/MainNavigation.kt new file mode 100644 index 0000000..49e6a1d --- /dev/null +++ b/app/src/main/java/com/devdunnapps/amplify/ui/main/MainNavigation.kt @@ -0,0 +1,99 @@ +package com.devdunnapps.amplify.ui.main + +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.composable +import androidx.navigation.navigation +import com.devdunnapps.amplify.ui.album.albumScreen +import com.devdunnapps.amplify.ui.album.navigateToAlbum +import com.devdunnapps.amplify.ui.albums.AlbumsRoute +import com.devdunnapps.amplify.ui.artist.artistScreen +import com.devdunnapps.amplify.ui.artist.navigateToArtist +import com.devdunnapps.amplify.ui.artists.ArtistsRoute +import com.devdunnapps.amplify.ui.navigation.AmplifyNavigationDestination +import com.devdunnapps.amplify.ui.nowplaying.lyricsBottomSheet +import com.devdunnapps.amplify.ui.nowplaying.openLyricsBottomSheet +import com.devdunnapps.amplify.ui.playlist.navigateToPlaylist +import com.devdunnapps.amplify.ui.playlist.playlistScreen +import com.devdunnapps.amplify.ui.playlists.PlaylistsRoute +import com.devdunnapps.amplify.ui.playlists.openPlaylistBottomSheet +import com.devdunnapps.amplify.ui.playlists.playlistBottomSheet +import com.devdunnapps.amplify.ui.songbottomsheet.openSongSongBottomSheet +import com.devdunnapps.amplify.ui.songbottomsheet.songBottomSheet +import com.devdunnapps.amplify.ui.songs.SongsRoute + +object ArtistsDestination : AmplifyNavigationDestination { + override val route = "artists" + override val destination = "artists_destination" +} + +object AlbumsDestination : AmplifyNavigationDestination { + override val route = "albums" + override val destination = "albums_destination" +} + +object SongsDestination : AmplifyNavigationDestination { + override val route = "songs" + override val destination = "songs_destination" +} + +object PlaylistsDestination : AmplifyNavigationDestination { + override val route = "playlists" + override val destination = "playlist_destination" +} + +fun NavGraphBuilder.mainGraph( + navController: NavHostController +) { + navigation( + route = "main_route", + startDestination = ArtistsDestination.route + ) { + composable(route = ArtistsDestination.route) { + ArtistsRoute(onArtistClick = { artistId -> navController.navigateToArtist(artistId) }) + } + + composable(route = AlbumsDestination.route) { + AlbumsRoute(onAlbumClick = { albumId -> navController.navigateToAlbum(albumId) }) + } + + composable(route = SongsDestination.route) { + SongsRoute(onSongMenuClick = { songId -> navController.openSongSongBottomSheet(songId) }) + } + + composable(route = PlaylistsDestination.route) { + PlaylistsRoute( + onPlaylistClick = { playlistId -> navController.navigateToPlaylist(playlistId) }, + onPlaylistMenuClick = { playlistId -> navController.openPlaylistBottomSheet(playlistId) } + ) + } + + artistScreen( + onNavigateToAlbum = { albumId -> navController.navigateToAlbum(albumId) }, + onNavigateToAllArtistAlbums = {}, + onNavigateToAllArtistEPsSingles = {}, + onOpenSongMenu = { songId -> navController.openSongSongBottomSheet(songId) }, + onNavigateToAllArtistSongs = {} + ) + + albumScreen( + onOpenSongMenu = { songId -> navController.openSongSongBottomSheet(songId) } + ) + + playlistScreen( + onOpenSongMenu = { songId -> navController.openSongSongBottomSheet(songId) } + ) + + songBottomSheet( + onNavigateToAlbum = {albumId -> navController.navigateToAlbum(albumId) }, + onNavigateToArtist = { artistId -> navController.navigateToArtist(artistId) }, + onOpenLyricsBottomSheet = { songId -> navController.openLyricsBottomSheet(songId) } + ) + + playlistBottomSheet( + onDeletePlaylistClicked = {} + ) + + lyricsBottomSheet() + } +} diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/navigation/AmplifyNavHost.kt b/app/src/main/java/com/devdunnapps/amplify/ui/navigation/AmplifyNavHost.kt index de4a82e..4ec407c 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/navigation/AmplifyNavHost.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/navigation/AmplifyNavHost.kt @@ -5,8 +5,11 @@ import androidx.compose.ui.Modifier import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.rememberNavController +import com.devdunnapps.amplify.ui.about.aboutScreen +import com.devdunnapps.amplify.ui.main.mainGraph import com.devdunnapps.amplify.ui.onboarding.OnboardingDestination import com.devdunnapps.amplify.ui.onboarding.onboardingGraph +import com.devdunnapps.amplify.ui.settings.settingsScreen @Composable internal fun AmplifyNavHost( @@ -24,6 +27,16 @@ internal fun AmplifyNavHost( navController = navController, onFinishOnboarding = onFinishOnboarding ) + + + + settingsScreen( + onNavigateUp = { navController.popBackStack() } + ) + + aboutScreen( + onNavigateUp = { } + ) } } diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/navigation/TopLevelDestination.kt b/app/src/main/java/com/devdunnapps/amplify/ui/navigation/TopLevelDestination.kt new file mode 100644 index 0000000..b54f952 --- /dev/null +++ b/app/src/main/java/com/devdunnapps/amplify/ui/navigation/TopLevelDestination.kt @@ -0,0 +1,35 @@ +package com.devdunnapps.amplify.ui.navigation + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import com.devdunnapps.amplify.R + +enum class TopLevelDestination( + @DrawableRes val selectedIcon: Int, + @DrawableRes val unselectedIcon: Int, + @StringRes val iconText: Int +) { + ARTISTS( + selectedIcon = R.drawable.ic_artists, + unselectedIcon = R.drawable.ic_artists_outlined, + iconText = R.string.artists + ), + + ALBUMS( + selectedIcon = R.drawable.ic_album, + unselectedIcon = R.drawable.ic_album_outlined, + iconText = R.string.albums + ), + + SONGS( + selectedIcon = R.drawable.ic_songs, + unselectedIcon = R.drawable.ic_songs_outlined, + iconText = R.string.songs + ), + + PLAYLISTS( + selectedIcon = R.drawable.ic_playlists, + unselectedIcon = R.drawable.ic_playlists_outlined, + iconText = R.string.playlists + ) +} diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/nowplaying/LyricsBottomSheet.kt b/app/src/main/java/com/devdunnapps/amplify/ui/nowplaying/LyricsBottomSheet.kt index ea87352..0fb12a7 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/nowplaying/LyricsBottomSheet.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/nowplaying/LyricsBottomSheet.kt @@ -18,34 +18,32 @@ import com.devdunnapps.amplify.domain.models.Lyric import com.devdunnapps.amplify.ui.components.BottomSheetHeader import com.devdunnapps.amplify.ui.components.ErrorScreen import com.devdunnapps.amplify.ui.components.LoadingPager +import com.devdunnapps.amplify.ui.theme.Theme import com.devdunnapps.amplify.utils.Resource -import com.google.accompanist.themeadapter.material3.Mdc3Theme import com.google.android.material.bottomsheet.BottomSheetDialogFragment import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class LyricsBottomSheet : BottomSheetDialogFragment() { - private val args: LyricsBottomSheetArgs by navArgs() +// private val args: LyricsBottomSheetArgs by navArgs() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) = ComposeView(requireContext()).apply { setContent { - Mdc3Theme { - LyricsBottomSheet(title = args.song.title, subtitle = args.song.artistName) + Theme { + LyricsBottomSheetRoute() } } } } @Composable -private fun LyricsBottomSheet( - title: String, - subtitle: String, +internal fun LyricsBottomSheetRoute( viewModel: LyricsBottomSheetViewModel = hiltViewModel() ) { Column { - BottomSheetHeader(title, subtitle) + BottomSheetHeader("fix me", "fix me") LazyColumn { item { LyricsContent(lyrics = viewModel.songLyrics.collectAsState().value) } diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/nowplaying/LyricsBottomSheetNavigation.kt b/app/src/main/java/com/devdunnapps/amplify/ui/nowplaying/LyricsBottomSheetNavigation.kt new file mode 100644 index 0000000..d83e5a1 --- /dev/null +++ b/app/src/main/java/com/devdunnapps/amplify/ui/nowplaying/LyricsBottomSheetNavigation.kt @@ -0,0 +1,29 @@ +package com.devdunnapps.amplify.ui.nowplaying + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.ui.Modifier +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType +import androidx.navigation.navArgument +import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi +import com.google.accompanist.navigation.material.bottomSheet + +@OptIn(ExperimentalMaterialNavigationApi::class) +fun NavGraphBuilder.lyricsBottomSheet( +) { + bottomSheet( + route = "songs/{songId}/lyrics", + arguments = listOf(navArgument("songId") { type = NavType.StringType }) + ) { + Box(modifier = Modifier.navigationBarsPadding()) { + LyricsBottomSheetRoute() + } + } +} + +fun NavController.openLyricsBottomSheet(songId: String) { + navigate("songs/$songId/lyrics") +} diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/nowplaying/LyricsBottomSheetViewModel.kt b/app/src/main/java/com/devdunnapps/amplify/ui/nowplaying/LyricsBottomSheetViewModel.kt index 77ece6d..d655cef 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/nowplaying/LyricsBottomSheetViewModel.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/nowplaying/LyricsBottomSheetViewModel.kt @@ -18,7 +18,7 @@ class LyricsBottomSheetViewModel @Inject constructor( private val getSongLyricsUseCase: GetSongLyricsUseCase ) : ViewModel() { - private val songId = LyricsBottomSheetArgs.fromSavedStateHandle(savedStateHandle).song.id + private val songId:String = checkNotNull(savedStateHandle["songId"]) private val _songLyrics = MutableStateFlow>(Resource.Loading) val songLyrics = _songLyrics.asStateFlow() diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/nowplaying/NowPlayingScreen.kt b/app/src/main/java/com/devdunnapps/amplify/ui/nowplaying/NowPlayingScreen.kt index 6f30296..d047f32 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/nowplaying/NowPlayingScreen.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/nowplaying/NowPlayingScreen.kt @@ -129,7 +129,7 @@ private fun NowPlayingHeader( Column( modifier = Modifier - .fillMaxSize() + .fillMaxWidth() .background(color = MaterialTheme.colorScheme.background) .padding(top = 32.dp) ) { diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/onboarding/OnBoardingActivity.kt b/app/src/main/java/com/devdunnapps/amplify/ui/onboarding/OnBoardingActivity.kt index 98c73d8..6a84d6a 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/onboarding/OnBoardingActivity.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/onboarding/OnBoardingActivity.kt @@ -7,7 +7,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.view.WindowCompat import com.devdunnapps.amplify.ui.main.MainActivity import com.devdunnapps.amplify.ui.navigation.AmplifyNavHost -import com.google.accompanist.themeadapter.material3.Mdc3Theme +import com.devdunnapps.amplify.ui.theme.Theme import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -19,7 +19,7 @@ class OnBoardingActivity : AppCompatActivity() { WindowCompat.setDecorFitsSystemWindows(window,true) setContent { - Mdc3Theme { + Theme { AmplifyNavHost( onFinishOnboarding = { val mainActivityIntent = Intent(this, MainActivity::class.java) diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/onboarding/WelcomeScreen.kt b/app/src/main/java/com/devdunnapps/amplify/ui/onboarding/WelcomeScreen.kt index b32cc8b..3190c74 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/onboarding/WelcomeScreen.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/onboarding/WelcomeScreen.kt @@ -17,7 +17,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.devdunnapps.amplify.R -import com.google.accompanist.themeadapter.material3.Mdc3Theme +import com.devdunnapps.amplify.ui.theme.Theme @Composable fun WelcomeScreen(onNavigateToLogin: () -> Unit) { @@ -61,7 +61,7 @@ fun WelcomeScreen(onNavigateToLogin: () -> Unit) { @Preview(showBackground = true) @Composable private fun WelcomeScreenPreview() { - Mdc3Theme { + Theme { WelcomeScreen {} } } diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/playlist/PlaylistFragment.kt b/app/src/main/java/com/devdunnapps/amplify/ui/playlist/PlaylistFragment.kt index 66eaab3..9246336 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/playlist/PlaylistFragment.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/playlist/PlaylistFragment.kt @@ -45,6 +45,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.navigation.fragment.findNavController @@ -99,18 +100,22 @@ class PlaylistFragment : Fragment() { } } } - navBackStackEntry.getLifecycle().addObserver(observer) +// navBackStackEntry.getLifecycle().addObserver(observer) viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event -> if (event == Lifecycle.Event.ON_DESTROY) { - navBackStackEntry.getLifecycle().removeObserver(observer) +// navBackStackEntry.getLifecycle().removeObserver(observer) } }) } } @Composable -fun PlaylistRoute(viewModel: PlaylistViewModel, onSongMenuClick: (Song) -> Unit, modifier: Modifier = Modifier) { +fun PlaylistRoute( + viewModel: PlaylistViewModel = hiltViewModel(), + onSongMenuClick: (Song) -> Unit, + modifier: Modifier = Modifier +) { PlaylistScreen( uiState = viewModel.uiState.collectAsState().value, onSongClick = viewModel::playSong, diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/playlist/PlaylistNavigation.kt b/app/src/main/java/com/devdunnapps/amplify/ui/playlist/PlaylistNavigation.kt new file mode 100644 index 0000000..0b8fb07 --- /dev/null +++ b/app/src/main/java/com/devdunnapps/amplify/ui/playlist/PlaylistNavigation.kt @@ -0,0 +1,22 @@ +package com.devdunnapps.amplify.ui.playlist + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType +import androidx.navigation.compose.composable +import androidx.navigation.navArgument + +fun NavGraphBuilder.playlistScreen( + onOpenSongMenu: (String) -> Unit +) { + composable( + route = "playlists/{playlistId}", + arguments = listOf(navArgument("playlistId") { type = NavType.StringType }) + ) { + PlaylistRoute(onSongMenuClick = { onOpenSongMenu(it.id) }) + } +} + +fun NavController.navigateToPlaylist(playlistId: String) { + navigate("playlists/$playlistId") +} diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/playlists/PlaylistBottomSheetNavigation.kt b/app/src/main/java/com/devdunnapps/amplify/ui/playlists/PlaylistBottomSheetNavigation.kt new file mode 100644 index 0000000..4faa864 --- /dev/null +++ b/app/src/main/java/com/devdunnapps/amplify/ui/playlists/PlaylistBottomSheetNavigation.kt @@ -0,0 +1,31 @@ +package com.devdunnapps.amplify.ui.playlists + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.ui.Modifier +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType +import androidx.navigation.navArgument +import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi +import com.google.accompanist.navigation.material.bottomSheet + +@OptIn(ExperimentalMaterialNavigationApi::class) +fun NavGraphBuilder.playlistBottomSheet( + onDeletePlaylistClicked: () -> Unit +) { + bottomSheet( + route = "playlists/{playlistId}/details", + arguments = listOf(navArgument("playlistId") { type = NavType.StringType }) + ) { + Box(modifier = Modifier.navigationBarsPadding()) { + PlaylistBottomSheet( + onDeletePlaylistClicked = onDeletePlaylistClicked + ) + } + } +} + +fun NavController.openPlaylistBottomSheet(playlistId: String) { + navigate("playlists/$playlistId/details") +} diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/playlists/PlaylistMenuBottomSheetFragment.kt b/app/src/main/java/com/devdunnapps/amplify/ui/playlists/PlaylistMenuBottomSheetFragment.kt index c761c51..ff1de23 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/playlists/PlaylistMenuBottomSheetFragment.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/playlists/PlaylistMenuBottomSheetFragment.kt @@ -14,6 +14,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.res.stringResource import androidx.fragment.app.viewModels +import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle @@ -24,8 +25,8 @@ import com.devdunnapps.amplify.ui.components.BottomSheetHeader import com.devdunnapps.amplify.ui.components.BottomSheetItem import com.devdunnapps.amplify.ui.components.ErrorScreen import com.devdunnapps.amplify.ui.components.LoadingPager +import com.devdunnapps.amplify.ui.theme.Theme import com.devdunnapps.amplify.utils.Resource -import com.google.accompanist.themeadapter.material3.Mdc3Theme import com.google.android.material.bottomsheet.BottomSheetDialogFragment import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch @@ -38,7 +39,7 @@ class PlaylistMenuBottomSheetFragment : BottomSheetDialogFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = ComposeView(requireContext()).apply { setContent { - Mdc3Theme { + Theme { var isDeletePlaylistDialogVisible by remember { mutableStateOf(false) } PlaylistBottomSheet( @@ -92,7 +93,10 @@ private fun DeletePlaylistDialog(isVisible: Boolean, onSubmit: () -> Unit, onDis } @Composable -private fun PlaylistBottomSheet(viewModel: PlaylistMenuBottomSheetViewModel, onDeletePlaylistClicked: () -> Unit) { +internal fun PlaylistBottomSheet( + viewModel: PlaylistMenuBottomSheetViewModel = hiltViewModel(), + onDeletePlaylistClicked: () -> Unit +) { when(val uiState = viewModel.playlist.collectAsState().value) { is Resource.Loading -> LoadingPager() is Resource.Error -> ErrorScreen() diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/playlists/PlaylistsFragment.kt b/app/src/main/java/com/devdunnapps/amplify/ui/playlists/PlaylistsFragment.kt index 317cfb1..d42ed1a 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/playlists/PlaylistsFragment.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/playlists/PlaylistsFragment.kt @@ -104,11 +104,11 @@ class PlaylistsFragment : Fragment() { } } } - navBackStackEntry.getLifecycle().addObserver(observer) +// navBackStackEntry.getLifecycle().addObserver(observer) viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event -> if (event == Lifecycle.Event.ON_DESTROY) { - navBackStackEntry.getLifecycle().removeObserver(observer) +// navBackStackEntry.getLifecycle().removeObserver(observer) } }) } @@ -155,7 +155,7 @@ private fun CreatePlaylistDialog(onSubmit: (String) -> Unit, onDismiss: () -> Un } @Composable -private fun PlaylistsRoute( +internal fun PlaylistsRoute( onPlaylistClick: (String) -> Unit, onPlaylistMenuClick: (String) -> Unit, modifier: Modifier = Modifier, diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/settings/SettingsActivity.kt b/app/src/main/java/com/devdunnapps/amplify/ui/settings/SettingsActivity.kt index e843626..ca0f1f8 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/settings/SettingsActivity.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/settings/SettingsActivity.kt @@ -20,6 +20,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringArrayResource import androidx.compose.ui.res.stringResource +import androidx.hilt.navigation.compose.hiltViewModel import com.devdunnapps.amplify.R import com.devdunnapps.amplify.domain.models.Preferences import com.devdunnapps.amplify.domain.models.ThemeConfig @@ -28,7 +29,7 @@ import com.devdunnapps.amplify.ui.components.ListPreferenceItem import com.devdunnapps.amplify.ui.components.LoadingScreen import com.devdunnapps.amplify.ui.components.StaticTextCell import com.devdunnapps.amplify.ui.main.MainActivity -import com.google.accompanist.themeadapter.material3.Mdc3Theme +import com.devdunnapps.amplify.ui.theme.Theme import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint @@ -41,7 +42,7 @@ class SettingsActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContent { - Mdc3Theme { + Theme { SettingsScreen( uiState = viewModel.uiState.collectAsState().value, onNavigateUpClick = { onBackPressed() }, @@ -68,6 +69,20 @@ class SettingsActivity : AppCompatActivity() { } } +@Composable +internal fun SettingsRoute( + viewModel: SettingsActivityViewModel = hiltViewModel(), + onNavigateUp: () -> Unit, + onSignOutClick: () -> Unit +) { + SettingsScreen( + uiState = viewModel.uiState.collectAsState().value, + onNavigateUpClick = onNavigateUp, + onChooseThemeClick = viewModel::changeTheme, + onSignOutClick = {} + ) +} + @OptIn(ExperimentalMaterial3Api::class) @Composable private fun SettingsScreen( diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/settings/SettingsNavigation.kt b/app/src/main/java/com/devdunnapps/amplify/ui/settings/SettingsNavigation.kt new file mode 100644 index 0000000..06bc755 --- /dev/null +++ b/app/src/main/java/com/devdunnapps/amplify/ui/settings/SettingsNavigation.kt @@ -0,0 +1,22 @@ +package com.devdunnapps.amplify.ui.settings + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType +import androidx.navigation.compose.composable +import androidx.navigation.navArgument + +fun NavGraphBuilder.settingsScreen(onNavigateUp: () -> Unit) { + composable( + route = "settings" + ) { + SettingsRoute( + onNavigateUp = onNavigateUp, + onSignOutClick = {} + ) + } +} + +fun NavController.navigateToSettings() { + navigate("settings") +} diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/songbottomsheet/SongAdditionalInfoBottomSheetFragment.kt b/app/src/main/java/com/devdunnapps/amplify/ui/songbottomsheet/SongAdditionalInfoBottomSheetFragment.kt index c2b1457..237fef9 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/songbottomsheet/SongAdditionalInfoBottomSheetFragment.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/songbottomsheet/SongAdditionalInfoBottomSheetFragment.kt @@ -15,7 +15,7 @@ import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.unit.dp import androidx.navigation.fragment.navArgs import com.devdunnapps.amplify.R -import com.google.accompanist.themeadapter.material3.Mdc3Theme +import com.devdunnapps.amplify.ui.theme.Theme import com.google.android.material.bottomsheet.BottomSheetDialogFragment class SongAdditionalInfoBottomSheetFragment: BottomSheetDialogFragment() { @@ -26,7 +26,7 @@ class SongAdditionalInfoBottomSheetFragment: BottomSheetDialogFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = ComposeView(requireContext()).apply { setContent { - Mdc3Theme { + Theme { val playCount = args.song.playCount Column(modifier = Modifier.fillMaxWidth()) { diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/songbottomsheet/SongBottomSheetNavigation.kt b/app/src/main/java/com/devdunnapps/amplify/ui/songbottomsheet/SongBottomSheetNavigation.kt new file mode 100644 index 0000000..1d13fe3 --- /dev/null +++ b/app/src/main/java/com/devdunnapps/amplify/ui/songbottomsheet/SongBottomSheetNavigation.kt @@ -0,0 +1,43 @@ +package com.devdunnapps.amplify.ui.songbottomsheet + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.ui.Modifier +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType +import androidx.navigation.compose.composable +import androidx.navigation.navArgument +import com.devdunnapps.amplify.ui.nowplaying.LyricsBottomSheet +import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi +import com.google.accompanist.navigation.material.bottomSheet + +@OptIn(ExperimentalMaterialNavigationApi::class) +fun NavGraphBuilder.songBottomSheet( + onNavigateToArtist: (String) -> Unit, + onNavigateToAlbum: (String) -> Unit, + onOpenLyricsBottomSheet: (String) -> Unit +) { + bottomSheet( + route = "songs/{songId}/details", + arguments = listOf(navArgument("songId") { type = NavType.StringType }) + ) { + Box(modifier = Modifier.navigationBarsPadding()) { + SongBottomSheet( + onPlayNextClick = { /*TODO*/ }, + onAddToQueueClick = { /*TODO*/ }, + onGoToAlbumClick = onNavigateToAlbum, + onGoToArtistClick = onNavigateToArtist, + onAddToPlaylist = {}, + onLyricsClick = onOpenLyricsBottomSheet, + onInfoClick = {}, + refreshPreviousScreen = {} + ) + } + } +} + +fun NavController.openSongSongBottomSheet(songId: String) { + navigate("songs/$songId/details") +} diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/songbottomsheet/SongMenuBottomSheetFragment.kt b/app/src/main/java/com/devdunnapps/amplify/ui/songbottomsheet/SongMenuBottomSheetFragment.kt index 4f50b5b..d4103c1 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/songbottomsheet/SongMenuBottomSheetFragment.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/songbottomsheet/SongMenuBottomSheetFragment.kt @@ -28,6 +28,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.LocalContext import androidx.fragment.app.viewModels +import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import com.devdunnapps.amplify.MobileNavigationDirections @@ -39,10 +40,10 @@ import com.devdunnapps.amplify.ui.components.BottomSheetItem import com.devdunnapps.amplify.ui.components.ErrorScreen import com.devdunnapps.amplify.ui.components.LoadingPager import com.devdunnapps.amplify.ui.main.MainActivity +import com.devdunnapps.amplify.ui.theme.Theme import com.devdunnapps.amplify.utils.PlexUtils import com.devdunnapps.amplify.utils.Resource import com.devdunnapps.amplify.utils.WhenToPlay -import com.google.accompanist.themeadapter.material3.Mdc3Theme import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialogFragment import dagger.hilt.android.AndroidEntryPoint @@ -56,7 +57,7 @@ class SongMenuBottomSheetFragment : BottomSheetDialogFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = ComposeView(requireContext()).apply { setContent { - Mdc3Theme { + Theme { SongBottomSheet( viewModel = viewModel, onPlayNextClick = { @@ -85,9 +86,9 @@ class SongMenuBottomSheetFragment : BottomSheetDialogFragment() { findNavController().navigate(action) }, onRemoveFromPlaylist = navArgs.playlistId?.let { viewModel::removeSongFromPlaylist }, - onLyricsClick = { song -> + onLyricsClick = { songId -> val action = SongMenuBottomSheetFragmentDirections - .actionNavigationSongBottomSheetToSongLyrics(song) + .actionNavigationSongBottomSheetToSongLyrics(songId) findNavController().navigate(action) }, onInfoClick = { song -> @@ -106,15 +107,15 @@ class SongMenuBottomSheetFragment : BottomSheetDialogFragment() { } @Composable -private fun SongBottomSheet( - viewModel: SongMenuBottomSheetViewModel, +internal fun SongBottomSheet( + viewModel: SongMenuBottomSheetViewModel = hiltViewModel(), onPlayNextClick: () -> Unit, onAddToQueueClick: () -> Unit, onGoToAlbumClick: (String) -> Unit, onGoToArtistClick: (String) -> Unit, onAddToPlaylist: (String) -> Unit, onRemoveFromPlaylist: (() -> Unit)? = null, - onLyricsClick: (Song) -> Unit, + onLyricsClick: (String) -> Unit, onInfoClick: (Song) -> Unit, refreshPreviousScreen: () -> Unit ) { @@ -147,7 +148,7 @@ private fun SongBottomSheetContent( onGoToArtistClick: (String) -> Unit, onAddToPlaylist: (String) -> Unit, onRemoveFromPlaylist: (() -> Unit)? = null, - onLyricsClick: (Song) -> Unit, + onLyricsClick: (String) -> Unit, onInfoClick: (Song) -> Unit, onRatingClick: (Int) -> Unit, refreshPreviousScreen: () -> Unit @@ -224,7 +225,7 @@ private fun SongBottomSheetContent( BottomSheetItem( icon = Icons.Outlined.Lyrics, text = R.string.lyrics, - onClick = { onLyricsClick(song) } + onClick = { onLyricsClick(song.id) } ) } diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/songs/SongsFragment.kt b/app/src/main/java/com/devdunnapps/amplify/ui/songs/SongsFragment.kt index 3c8cdf9..f7b4a51 100644 --- a/app/src/main/java/com/devdunnapps/amplify/ui/songs/SongsFragment.kt +++ b/app/src/main/java/com/devdunnapps/amplify/ui/songs/SongsFragment.kt @@ -51,7 +51,7 @@ class SongsFragment : Fragment() { } @Composable -private fun SongsRoute( +internal fun SongsRoute( onSongMenuClick: (String) -> Unit, modifier: Modifier = Modifier, viewModel: SongsViewModel = hiltViewModel() diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/theme/Color.kt b/app/src/main/java/com/devdunnapps/amplify/ui/theme/Color.kt new file mode 100644 index 0000000..411868c --- /dev/null +++ b/app/src/main/java/com/devdunnapps/amplify/ui/theme/Color.kt @@ -0,0 +1,67 @@ +package com.devdunnapps.amplify.ui.theme + +import androidx.compose.ui.graphics.Color + +val md_theme_light_primary = Color(0xFF006A69) +val md_theme_light_onPrimary = Color(0xFFFFFFFF) +val md_theme_light_primaryContainer = Color(0xFF6FF7F5) +val md_theme_light_onPrimaryContainer = Color(0xFF00201F) +val md_theme_light_secondary = Color(0xFF4A6362) +val md_theme_light_onSecondary = Color(0xFFFFFFFF) +val md_theme_light_secondaryContainer = Color(0xFFCCE8E7) +val md_theme_light_onSecondaryContainer = Color(0xFF051F1F) +val md_theme_light_tertiary = Color(0xFF4B607C) +val md_theme_light_onTertiary = Color(0xFFFFFFFF) +val md_theme_light_tertiaryContainer = Color(0xFFD2E4FF) +val md_theme_light_onTertiaryContainer = Color(0xFF031C35) +val md_theme_light_error = Color(0xFFBA1A1A) +val md_theme_light_errorContainer = Color(0xFFFFDAD6) +val md_theme_light_onError = Color(0xFFFFFFFF) +val md_theme_light_onErrorContainer = Color(0xFF410002) +val md_theme_light_background = Color(0xFFFAFDFC) +val md_theme_light_onBackground = Color(0xFF191C1C) +val md_theme_light_surface = Color(0xFFFAFDFC) +val md_theme_light_onSurface = Color(0xFF191C1C) +val md_theme_light_surfaceVariant = Color(0xFFDAE5E3) +val md_theme_light_onSurfaceVariant = Color(0xFF3F4948) +val md_theme_light_outline = Color(0xFF6F7978) +val md_theme_light_inverseOnSurface = Color(0xFFEFF1F0) +val md_theme_light_inverseSurface = Color(0xFF2D3131) +val md_theme_light_inversePrimary = Color(0xFF4DDAD8) +val md_theme_light_shadow = Color(0xFF000000) +val md_theme_light_surfaceTint = Color(0xFF006A69) +val md_theme_light_outlineVariant = Color(0xFFBEC9C8) +val md_theme_light_scrim = Color(0xFF000000) + +val md_theme_dark_primary = Color(0xFF4DDAD8) +val md_theme_dark_onPrimary = Color(0xFF003736) +val md_theme_dark_primaryContainer = Color(0xFF00504F) +val md_theme_dark_onPrimaryContainer = Color(0xFF6FF7F5) +val md_theme_dark_secondary = Color(0xFFB0CCCB) +val md_theme_dark_onSecondary = Color(0xFF1B3534) +val md_theme_dark_secondaryContainer = Color(0xFF324B4A) +val md_theme_dark_onSecondaryContainer = Color(0xFFCCE8E7) +val md_theme_dark_tertiary = Color(0xFFB2C8E8) +val md_theme_dark_onTertiary = Color(0xFF1B324B) +val md_theme_dark_tertiaryContainer = Color(0xFF334863) +val md_theme_dark_onTertiaryContainer = Color(0xFFD2E4FF) +val md_theme_dark_error = Color(0xFFFFB4AB) +val md_theme_dark_errorContainer = Color(0xFF93000A) +val md_theme_dark_onError = Color(0xFF690005) +val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6) +val md_theme_dark_background = Color(0xFF191C1C) +val md_theme_dark_onBackground = Color(0xFFE0E3E2) +val md_theme_dark_surface = Color(0xFF191C1C) +val md_theme_dark_onSurface = Color(0xFFE0E3E2) +val md_theme_dark_surfaceVariant = Color(0xFF3F4948) +val md_theme_dark_onSurfaceVariant = Color(0xFFBEC9C8) +val md_theme_dark_outline = Color(0xFF889392) +val md_theme_dark_inverseOnSurface = Color(0xFF191C1C) +val md_theme_dark_inverseSurface = Color(0xFFE0E3E2) +val md_theme_dark_inversePrimary = Color(0xFF006A69) +val md_theme_dark_shadow = Color(0xFF000000) +val md_theme_dark_surfaceTint = Color(0xFF4DDAD8) +val md_theme_dark_outlineVariant = Color(0xFF3F4948) +val md_theme_dark_scrim = Color(0xFF000000) + +val seed = Color(0xFF006A69) diff --git a/app/src/main/java/com/devdunnapps/amplify/ui/theme/Theme.kt b/app/src/main/java/com/devdunnapps/amplify/ui/theme/Theme.kt new file mode 100644 index 0000000..3ee8cc1 --- /dev/null +++ b/app/src/main/java/com/devdunnapps/amplify/ui/theme/Theme.kt @@ -0,0 +1,88 @@ +package com.devdunnapps.amplify.ui.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.runtime.Composable + +private val LightColors = lightColorScheme( + primary = md_theme_light_primary, + onPrimary = md_theme_light_onPrimary, + primaryContainer = md_theme_light_primaryContainer, + onPrimaryContainer = md_theme_light_onPrimaryContainer, + secondary = md_theme_light_secondary, + onSecondary = md_theme_light_onSecondary, + secondaryContainer = md_theme_light_secondaryContainer, + onSecondaryContainer = md_theme_light_onSecondaryContainer, + tertiary = md_theme_light_tertiary, + onTertiary = md_theme_light_onTertiary, + tertiaryContainer = md_theme_light_tertiaryContainer, + onTertiaryContainer = md_theme_light_onTertiaryContainer, + error = md_theme_light_error, + errorContainer = md_theme_light_errorContainer, + onError = md_theme_light_onError, + onErrorContainer = md_theme_light_onErrorContainer, + background = md_theme_light_background, + onBackground = md_theme_light_onBackground, + surface = md_theme_light_surface, + onSurface = md_theme_light_onSurface, + surfaceVariant = md_theme_light_surfaceVariant, + onSurfaceVariant = md_theme_light_onSurfaceVariant, + outline = md_theme_light_outline, + inverseOnSurface = md_theme_light_inverseOnSurface, + inverseSurface = md_theme_light_inverseSurface, + inversePrimary = md_theme_light_inversePrimary, + surfaceTint = md_theme_light_surfaceTint, + outlineVariant = md_theme_light_outlineVariant, + scrim = md_theme_light_scrim, +) + +private val DarkColors = darkColorScheme( + primary = md_theme_dark_primary, + onPrimary = md_theme_dark_onPrimary, + primaryContainer = md_theme_dark_primaryContainer, + onPrimaryContainer = md_theme_dark_onPrimaryContainer, + secondary = md_theme_dark_secondary, + onSecondary = md_theme_dark_onSecondary, + secondaryContainer = md_theme_dark_secondaryContainer, + onSecondaryContainer = md_theme_dark_onSecondaryContainer, + tertiary = md_theme_dark_tertiary, + onTertiary = md_theme_dark_onTertiary, + tertiaryContainer = md_theme_dark_tertiaryContainer, + onTertiaryContainer = md_theme_dark_onTertiaryContainer, + error = md_theme_dark_error, + errorContainer = md_theme_dark_errorContainer, + onError = md_theme_dark_onError, + onErrorContainer = md_theme_dark_onErrorContainer, + background = md_theme_dark_background, + onBackground = md_theme_dark_onBackground, + surface = md_theme_dark_surface, + onSurface = md_theme_dark_onSurface, + surfaceVariant = md_theme_dark_surfaceVariant, + onSurfaceVariant = md_theme_dark_onSurfaceVariant, + outline = md_theme_dark_outline, + inverseOnSurface = md_theme_dark_inverseOnSurface, + inverseSurface = md_theme_dark_inverseSurface, + inversePrimary = md_theme_dark_inversePrimary, + surfaceTint = md_theme_dark_surfaceTint, + outlineVariant = md_theme_dark_outlineVariant, + scrim = md_theme_dark_scrim, +) + +@Composable +fun Theme( + useDarkTheme: Boolean = isSystemInDarkTheme(), + content: @Composable () -> Unit +) { + val colors = if (!useDarkTheme) { + LightColors + } else { + DarkColors + } + + MaterialTheme( + colorScheme = colors, + content = content + ) +} diff --git a/app/src/main/java/com/devdunnapps/amplify/utils/PreferencesUtils.kt b/app/src/main/java/com/devdunnapps/amplify/utils/PreferencesUtils.kt index e4d2902..22e4a8d 100644 --- a/app/src/main/java/com/devdunnapps/amplify/utils/PreferencesUtils.kt +++ b/app/src/main/java/com/devdunnapps/amplify/utils/PreferencesUtils.kt @@ -10,6 +10,7 @@ object PreferencesUtils { const val PREF_PLEX_TV_USER_TOKEN = "user_plex_tv_token" const val PREF_PLEX_USER_TOKEN = "user_plex_token" const val PREF_PLEX_SERVER_LIBRARY = "user_plex_server_library" + const val PREF_THEME = "theme" fun readSharedSetting(ctx: Context, settingName: String): String? { val sharedPref = ctx.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 69765a0..db5747a 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -26,7 +26,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" app:behavior_peekHeight="64dp" - android:background="@color/md_theme_secondaryContainer" android:visibility="gone" tools:visibility="visible" app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> diff --git a/app/src/main/res/navigation/main_navigation.xml b/app/src/main/res/navigation/main_navigation.xml index a29b2c7..42ebd98 100644 --- a/app/src/main/res/navigation/main_navigation.xml +++ b/app/src/main/res/navigation/main_navigation.xml @@ -176,7 +176,7 @@ android:name="com.devdunnapps.amplify.ui.nowplaying.LyricsBottomSheet" android:label="LyricsBottomSheet"> + android:name="songId" + app:argType="string" /> diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml deleted file mode 100644 index 5d7a706..0000000 --- a/app/src/main/res/values-night/colors.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - #4DDAD8 - #003737 - #004F4F - #6FF7F5 - #B0CCCB - #1B3534 - #314B4A - #CCE8E7 - #B2C8E8 - #1C324B - #334862 - #D1E4FF - #FFB4A9 - #930006 - #680003 - #FFDAD4 - #191C1C - #E0E3E2 - #191C1C - #E0E3E2 - #3F4848 - #BEC9C8 - #889392 - #191C1C - #E0E3E2 - #006A69 - diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml deleted file mode 100644 index c8686a9..0000000 --- a/app/src/main/res/values/colors.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - #006A69 - #FFFFFF - #6FF7F5 - #002020 - #496362 - #FFFFFF - #CCE8E7 - #051F1F - #4B607C - #FFFFFF - #D1E4FF - #031C35 - #BA1B1B - #FFDAD4 - #FFFFFF - #410001 - #FAFDFC - #191C1C - #FAFDFC - #191C1C - #DAE4E3 - #3F4848 - #6F7978 - #EFF1F0 - #2E3131 - #4DDAD8 - - #018786 - #BA1B1B - diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index f081db0..77b6395 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,38 +1,9 @@