diff --git a/app/build.gradle b/app/build.gradle index 2f73bc55..e268f2e0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -79,10 +79,11 @@ dependencies { //Compose implementation "androidx.compose.ui:ui:$compose_version" implementation "androidx.compose.ui:ui-tooling:$compose_version" + implementation "androidx.compose.animation:animation:$compose_version" implementation "androidx.compose.runtime:runtime-livedata:$compose_version" implementation "androidx.compose.material:material:$compose_version" implementation "androidx.compose.material:material-icons-extended:$compose_version" - + //Compose-Navigation implementation "androidx.navigation:navigation-compose:1.0.0-alpha04" @@ -90,6 +91,7 @@ dependencies { implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" + implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version" //Coroutines implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" @@ -98,13 +100,13 @@ dependencies { //Room kapt "androidx.room:room-compiler:$room_version" - implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-ktx:$room_version" + implementation "androidx.room:room-runtime:$room_version" //Hilt + kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha02' kapt "com.google.dagger:hilt-android-compiler:$hilt_version" implementation "com.google.dagger:hilt-android:$hilt_version" - kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha02' implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02' //FFmpeg diff --git a/app/src/main/java/com/shabinder/spotiflyer/MainActivity.kt b/app/src/main/java/com/shabinder/spotiflyer/MainActivity.kt index f9392e8c..603925f0 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/MainActivity.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/MainActivity.kt @@ -25,11 +25,16 @@ import androidx.compose.ui.res.vectorResource import androidx.core.view.WindowCompat import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope +import androidx.navigation.NavController +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController import com.shabinder.spotiflyer.navigation.ComposeNavigation +import com.shabinder.spotiflyer.navigation.navigateToPlatform import com.shabinder.spotiflyer.networking.SpotifyService import com.shabinder.spotiflyer.networking.SpotifyServiceTokenRequest import com.shabinder.spotiflyer.ui.ComposeLearnTheme import com.shabinder.spotiflyer.ui.appNameStyle +import com.shabinder.spotiflyer.ui.colorOffWhite import com.shabinder.spotiflyer.utils.* import com.squareup.moshi.Moshi import dagger.hilt.android.AndroidEntryPoint @@ -51,6 +56,7 @@ import com.shabinder.spotiflyer.utils.showDialog as showDialog1 class MainActivity : AppCompatActivity() { private var spotifyService : SpotifyService? = null + lateinit var navController: NavHostController @Inject lateinit var moshi: Moshi @Inject lateinit var spotifyServiceTokenRequest: SpotifyServiceTokenRequest @@ -62,19 +68,24 @@ class MainActivity : AppCompatActivity() { WindowCompat.setDecorFitsSystemWindows(window, false) setContent { ComposeLearnTheme { - ProvideWindowInsets { - Column { - val appBarColor = MaterialTheme.colors.surface.copy(alpha = 0.87f) + Providers(AmbientContentColor provides colorOffWhite) { + ProvideWindowInsets { + Column { + val appBarColor = MaterialTheme.colors.surface.copy(alpha = 0.87f) - // Draw a scrim over the status bar which matches the app bar - Spacer(Modifier.background(appBarColor).fillMaxWidth().statusBarsHeight()) + // Draw a scrim over the status bar which matches the app bar + Spacer( + Modifier.background(appBarColor).fillMaxWidth().statusBarsHeight() + ) - AppBar( - backgroundColor = appBarColor, - modifier = Modifier.fillMaxWidth() - ) + AppBar( + backgroundColor = appBarColor, + modifier = Modifier.fillMaxWidth() + ) + navController = rememberNavController() - ComposeNavigation() + ComposeNavigation(navController) + } } } } @@ -93,7 +104,6 @@ class MainActivity : AppCompatActivity() { override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) - //Return to MainFragment For Further Processing of this Intent handleIntentFromExternalActivity(intent) } @@ -172,7 +182,7 @@ class MainActivity : AppCompatActivity() { if ("text/plain" == intent.type) { intent.getStringExtra(Intent.EXTRA_TEXT)?.let { log("Intent Received", it) - sharedViewModel.intentString.value = it + navController.navigateToPlatform(it) } } } @@ -238,7 +248,7 @@ fun DefaultPreview() { modifier = Modifier.fillMaxWidth() ) - ComposeNavigation() + //ComposeNavigation() } } } diff --git a/app/src/main/java/com/shabinder/spotiflyer/SharedViewModel.kt b/app/src/main/java/com/shabinder/spotiflyer/SharedViewModel.kt index 839bbadc..0e8d440c 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/SharedViewModel.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/SharedViewModel.kt @@ -22,9 +22,11 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.github.kiulian.downloader.YoutubeDownloader import com.shabinder.spotiflyer.database.DatabaseDAO +import com.shabinder.spotiflyer.models.PlatformQueryResult import com.shabinder.spotiflyer.networking.GaanaInterface import com.shabinder.spotiflyer.networking.SpotifyService import dagger.hilt.android.scopes.ActivityRetainedScoped +import kotlinx.coroutines.flow.Flow @ActivityRetainedScoped class SharedViewModel @ViewModelInject constructor( diff --git a/app/src/main/java/com/shabinder/spotiflyer/navigation/ComposeNavigation.kt b/app/src/main/java/com/shabinder/spotiflyer/navigation/ComposeNavigation.kt index 14f7439b..8f5816a9 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/navigation/ComposeNavigation.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/navigation/ComposeNavigation.kt @@ -2,6 +2,7 @@ package com.shabinder.spotiflyer.navigation import androidx.compose.runtime.Composable import androidx.navigation.NavController +import androidx.navigation.NavHostController import androidx.navigation.NavType import androidx.navigation.compose.* import androidx.navigation.compose.popUpTo @@ -14,8 +15,7 @@ import com.shabinder.spotiflyer.utils.sharedViewModel import com.shabinder.spotiflyer.utils.showDialog @Composable -fun ComposeNavigation() { - val navController = rememberNavController() +fun ComposeNavigation(navController: NavHostController) { NavHost( navController = navController, startDestination = "home" diff --git a/app/src/main/java/com/shabinder/spotiflyer/ui/Color.kt b/app/src/main/java/com/shabinder/spotiflyer/ui/Color.kt index fe34eeac..a9487fc5 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/ui/Color.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/Color.kt @@ -12,6 +12,7 @@ val colorAccent = Color(0xFF9AB3FF) val colorRedError = Color(0xFFFF9494) val colorSuccessGreen = Color(0xFF59C351) val darkBackgroundColor = Color(0xFF000000) +val colorOffWhite = Color(0xFFE7E7E7) val SpotiFlyerColors = darkColors( primary = colorPrimary, diff --git a/app/src/main/java/com/shabinder/spotiflyer/ui/Type.kt b/app/src/main/java/com/shabinder/spotiflyer/ui/Type.kt index 85aee6ad..cc53ba8c 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/ui/Type.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/Type.kt @@ -80,7 +80,6 @@ val SpotiFlyerTypography = Typography( fontWeight = FontWeight.Medium, lineHeight = 20.sp, letterSpacing = 0.15.sp, - color = colorAccent ), body2 = TextStyle( fontFamily = Montserrat, diff --git a/app/src/main/java/com/shabinder/spotiflyer/ui/base/TrackListViewModel.kt b/app/src/main/java/com/shabinder/spotiflyer/ui/base/TrackListViewModel.kt deleted file mode 100644 index 55d6457a..00000000 --- a/app/src/main/java/com/shabinder/spotiflyer/ui/base/TrackListViewModel.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2020 Shabinder Singh - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.shabinder.spotiflyer.ui.base - -import androidx.lifecycle.ViewModel -import com.shabinder.spotiflyer.models.TrackDetails -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow - -abstract class TrackListViewModel:ViewModel() { - abstract var folderType:String - abstract var subFolder:String - private val _trackList = MutableStateFlow>(mutableListOf()) - open val trackList:StateFlow> - get() = _trackList - - fun updateTrackList(list:List){ - _trackList.value = list - } - - private val loading = "Loading!" - open var title = MutableStateFlow(loading) - open var coverUrl = MutableStateFlow(loading) - -} \ No newline at end of file diff --git a/app/src/main/java/com/shabinder/spotiflyer/ui/home/Home.kt b/app/src/main/java/com/shabinder/spotiflyer/ui/home/Home.kt index 4f63ab49..3345b6c4 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/ui/home/Home.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/home/Home.kt @@ -85,7 +85,8 @@ fun AboutColumn(modifier: Modifier = Modifier) { Column(modifier.padding(12.dp)) { Text( text = stringResource(R.string.supported_platform), - style = SpotiFlyerTypography.body1 + style = SpotiFlyerTypography.body1, + color = colorAccent ) Spacer(modifier = Modifier.padding(top = 12.dp)) Row(horizontalArrangement = Arrangement.Center,modifier = modifier.fillMaxWidth()) { @@ -115,7 +116,8 @@ fun AboutColumn(modifier: Modifier = Modifier) { Column(modifier.padding(12.dp)) { Text( text = stringResource(R.string.support_development), - style = SpotiFlyerTypography.body1 + style = SpotiFlyerTypography.body1, + color = colorAccent ) Spacer(modifier = Modifier.padding(top = 6.dp)) Row(verticalAlignment = Alignment.CenterVertically, diff --git a/app/src/main/java/com/shabinder/spotiflyer/ui/platforms/gaana/Gaana.kt b/app/src/main/java/com/shabinder/spotiflyer/ui/platforms/gaana/Gaana.kt index 877542d3..4db1fe7a 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/ui/platforms/gaana/Gaana.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/platforms/gaana/Gaana.kt @@ -1,8 +1,15 @@ package com.shabinder.spotiflyer.ui.platforms.gaana import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.navigation.NavController +import com.shabinder.spotiflyer.models.PlatformQueryResult +import com.shabinder.spotiflyer.models.spotify.Source +import com.shabinder.spotiflyer.ui.tracklist.TrackList import com.shabinder.spotiflyer.utils.* import kotlinx.coroutines.launch @@ -11,6 +18,9 @@ fun Gaana( fullLink: String, navController: NavController ) { + val source = Source.Gaana + var result by remember { mutableStateOf(null) } + //Coroutine Scope Active till this Composable is Active val coroutineScope = rememberCoroutineScope() @@ -29,17 +39,17 @@ fun Gaana( } coroutineScope.launch { - val result = gaanaSearch( + result = gaanaSearch( type, link, sharedViewModel.gaanaInterface, sharedViewModel.databaseDAO, ) - - log("Gaana",result.toString()) - log("Gaana Tracks",result.trackList.size.toString()) - - - + } + result?.let { + TrackList( + result = it, + source = source + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/shabinder/spotiflyer/ui/platforms/spotify/Spotify.kt b/app/src/main/java/com/shabinder/spotiflyer/ui/platforms/spotify/Spotify.kt index f9c8fc09..1b29eed8 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/ui/platforms/spotify/Spotify.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/platforms/spotify/Spotify.kt @@ -1,12 +1,15 @@ package com.shabinder.spotiflyer.ui.platforms.spotify import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.viewinterop.viewModel -import androidx.lifecycle.viewModelScope import androidx.navigation.NavController +import com.shabinder.spotiflyer.models.PlatformQueryResult import com.shabinder.spotiflyer.models.spotify.Source -import com.shabinder.spotiflyer.networking.SpotifyService +import com.shabinder.spotiflyer.ui.tracklist.TrackList import com.shabinder.spotiflyer.utils.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -14,8 +17,8 @@ import kotlinx.coroutines.launch @Composable fun Spotify(fullLink: String, navController: NavController,) { val source: Source = Source.Spotify - val coroutineScope = rememberCoroutineScope() + var result by remember { mutableStateOf(null) } var spotifyLink = "https://" + fullLink.substringAfterLast("https://").substringBefore(" ").trim() @@ -57,7 +60,7 @@ fun Spotify(fullLink: String, navController: NavController,) { showDialog("Authentication Failed") navController.popBackStack() }else{ - val result = spotifySearch( + result = spotifySearch( type, link, sharedViewModel.spotifyService.value!!, @@ -66,4 +69,11 @@ fun Spotify(fullLink: String, navController: NavController,) { } } } + result?.let { + log("Spotify",it.trackList.size.toString()) + TrackList( + result = it, + source = source + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/shabinder/spotiflyer/ui/platforms/youtube/Youtube.kt b/app/src/main/java/com/shabinder/spotiflyer/ui/platforms/youtube/Youtube.kt index 7ea3c31f..c27ed658 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/ui/platforms/youtube/Youtube.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/platforms/youtube/Youtube.kt @@ -1,9 +1,15 @@ package com.shabinder.spotiflyer.ui.platforms.youtube import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.navigation.NavController +import com.shabinder.spotiflyer.models.PlatformQueryResult import com.shabinder.spotiflyer.models.spotify.Source +import com.shabinder.spotiflyer.ui.tracklist.TrackList import com.shabinder.spotiflyer.utils.sharedViewModel import com.shabinder.spotiflyer.utils.showDialog import kotlinx.coroutines.launch @@ -15,7 +21,7 @@ private const val sampleDomain1 = "youtube.com" @Composable fun Youtube(fullLink: String, navController: NavController,) { val source = Source.YouTube - + var result by remember { mutableStateOf(null) } //Coroutine Scope Active till this Composable is Active val coroutineScope = rememberCoroutineScope() @@ -38,7 +44,7 @@ fun Youtube(fullLink: String, navController: NavController,) { searchId = link.substringAfterLast("/","error") } if(searchId != "error") { - getYTTrack( + result = getYTTrack( searchId, sharedViewModel.ytDownloader, sharedViewModel.databaseDAO @@ -49,4 +55,10 @@ fun Youtube(fullLink: String, navController: NavController,) { } } } + result?.let { + TrackList( + result = it, + source = source + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/shabinder/spotiflyer/ui/tracklist/TrackList.kt b/app/src/main/java/com/shabinder/spotiflyer/ui/tracklist/TrackList.kt index 392ca605..5312099d 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/ui/tracklist/TrackList.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/tracklist/TrackList.kt @@ -1,14 +1,69 @@ package com.shabinder.spotiflyer.ui.tracklist +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import androidx.compose.ui.viewinterop.viewModel import androidx.navigation.NavController +import com.bumptech.glide.RequestManager +import com.shabinder.spotiflyer.R +import com.shabinder.spotiflyer.models.PlatformQueryResult +import com.shabinder.spotiflyer.models.TrackDetails +import com.shabinder.spotiflyer.models.spotify.Source +import com.shabinder.spotiflyer.ui.SpotiFlyerTypography +import com.shabinder.spotiflyer.ui.colorAccent +import dev.chrisbanes.accompanist.glide.GlideImage /* * UI for List of Tracks to be universally used. * */ @Composable -fun TrackList(modifier: Modifier = Modifier){ +fun TrackList( + result: PlatformQueryResult, + source: Source, + modifier: Modifier = Modifier +){ + LazyColumn( + verticalArrangement = Arrangement.spacedBy(8.dp), + content = { + items(result.trackList) { + TrackCard(track = it) + } + }, + modifier = Modifier.fillMaxSize() + ) +} + +@Composable +fun TrackCard(track:TrackDetails) { + Row(verticalAlignment = Alignment.CenterVertically,modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)) { + GlideImage( + data = track.albumArtURL, + loading = { Image(vectorResource(id = R.drawable.ic_song_placeholder)) }, + error = { Image(vectorResource(id = R.drawable.ic_musicplaceholder)) }, + contentScale = ContentScale.Inside, + modifier = Modifier.preferredHeight(75.dp).preferredWidth(90.dp) + ) + Column(modifier = Modifier.padding(horizontal = 8.dp).fillMaxHeight().weight(1f),verticalArrangement = Arrangement.SpaceBetween) { + Text(track.title,maxLines = 1,overflow = TextOverflow.Ellipsis,style = SpotiFlyerTypography.h6,color = colorAccent) + Row( + horizontalArrangement = Arrangement.SpaceBetween, + modifier = Modifier.padding(horizontal = 12.dp).fillMaxSize() + ){ + Text("${track.artists.firstOrNull()}...",fontSize = 13.sp) + Text("${track.durationSec/60} minutes, ${track.durationSec%60} sec",fontSize = 13.sp) + } + } + Image(vectorResource(id = R.drawable.ic_arrow)) + } } \ No newline at end of file diff --git a/app/src/main/java/com/shabinder/spotiflyer/utils/Utils.kt b/app/src/main/java/com/shabinder/spotiflyer/utils/Utils.kt index 71c07519..ddcfef8f 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/utils/Utils.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/utils/Utils.kt @@ -2,17 +2,38 @@ package com.shabinder.spotiflyer.utils import android.content.Context import android.content.Intent +import android.graphics.drawable.Drawable import android.net.ConnectivityManager import android.net.NetworkCapabilities import android.os.Build import android.util.Log +import android.widget.ImageView import android.widget.Toast +import androidx.compose.foundation.Image +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.vectorResource import androidx.core.content.ContextCompat +import androidx.core.graphics.drawable.toBitmap +import androidx.core.net.toUri +import com.bumptech.glide.Glide +import com.bumptech.glide.RequestManager +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.Target import com.shabinder.spotiflyer.MainActivity +import com.shabinder.spotiflyer.R import com.shabinder.spotiflyer.models.TrackDetails import com.shabinder.spotiflyer.models.spotify.Source import com.shabinder.spotiflyer.worker.ForegroundService +import dev.chrisbanes.accompanist.glide.GlideImage +import dev.chrisbanes.accompanist.glide.GlideImageDefaults +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import java.io.File +import java.io.IOException /** * mainActivity Instance to use whereEver Needed , as Its God Activity. @@ -54,7 +75,6 @@ fun finalOutputDir(itemName:String ,type:String, subFolder:String,extension:Stri removeIllegalChars(itemName) + extension } - /** * Util. Function To Check Connection Status * */ diff --git a/app/src/main/res/drawable/ic_arrow.xml b/app/src/main/res/drawable/ic_arrow.xml new file mode 100644 index 00000000..2c26c5e8 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow.xml @@ -0,0 +1,27 @@ + + + + + + + + + + +