mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-25 02:14:32 +01:00
Error Handling Improved,Shifted To client id:secret Flow(MoreLimit & Fast)
This commit is contained in:
parent
5d1974739e
commit
94f4560478
@ -26,9 +26,14 @@
|
|||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<data android:mimeType="text/plain" />
|
<data android:mimeType="text/plain" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
|
</activity>
|
||||||
|
<activity android:name="com.shabinder.musicForEveryone.splash.SplashScreen"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/Theme.Transparent">
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
BIN
app/src/main/ic_launcher-playstore.png
Normal file
BIN
app/src/main/ic_launcher-playstore.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
@ -4,26 +4,22 @@ import android.Manifest
|
|||||||
import android.app.DownloadManager
|
import android.app.DownloadManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.net.ConnectivityManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import com.github.kiulian.downloader.YoutubeDownloader
|
import com.github.kiulian.downloader.YoutubeDownloader
|
||||||
import com.shabinder.musicForEveryone.databinding.MainActivityBinding
|
import com.shabinder.musicForEveryone.databinding.MainActivityBinding
|
||||||
import com.shabinder.musicForEveryone.downloadHelper.DownloadHelper
|
import com.shabinder.musicForEveryone.downloadHelper.DownloadHelper
|
||||||
import com.shabinder.musicForEveryone.utils.SpotifyNewService
|
import com.shabinder.musicForEveryone.utils.SpotifyService
|
||||||
|
import com.shabinder.musicForEveryone.utils.SpotifyServiceToken
|
||||||
import com.shabinder.musicForEveryone.utils.YoutubeInterface
|
import com.shabinder.musicForEveryone.utils.YoutubeInterface
|
||||||
import com.spotify.sdk.android.authentication.AuthenticationClient
|
|
||||||
import com.spotify.sdk.android.authentication.AuthenticationRequest
|
|
||||||
import com.spotify.sdk.android.authentication.AuthenticationResponse
|
|
||||||
import com.spotify.sdk.android.authentication.LoginActivity
|
|
||||||
import com.squareup.moshi.Moshi
|
import com.squareup.moshi.Moshi
|
||||||
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||||
import kaaes.spotify.webapi.android.SpotifyApi
|
|
||||||
import kaaes.spotify.webapi.android.SpotifyService
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
@ -32,30 +28,43 @@ import okhttp3.Response
|
|||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.converter.moshi.MoshiConverterFactory
|
import retrofit2.converter.moshi.MoshiConverterFactory
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
class MainActivity : AppCompatActivity() ,DownloadHelper{
|
class MainActivity : AppCompatActivity() ,DownloadHelper{
|
||||||
private lateinit var binding: MainActivityBinding
|
private lateinit var binding: MainActivityBinding
|
||||||
var ytDownloader : YoutubeDownloader? = null
|
private var ytDownloader : YoutubeDownloader? = null
|
||||||
var spotifyExtra : SpotifyNewService? = null
|
private var spotifyService : SpotifyService? = null
|
||||||
var downloadManager : DownloadManager? = null
|
private var spotifyServiceToken : SpotifyServiceToken? = null
|
||||||
val REDIRECT_URI = "musicforeveryone://callback"
|
private var downloadManager : DownloadManager? = null
|
||||||
val CLIENT_ID:String = "694d8bf4f6ec420fa66ea7fb4c68f89d"
|
// private val redirectUri = "musicforeveryone://callback"
|
||||||
var token :String =""
|
private val clientId:String = "694d8bf4f6ec420fa66ea7fb4c68f89d"
|
||||||
var spotify: SpotifyService? = null
|
private val clientSecret:String = "02ca2d4021a7452dae2328b47a6e8fe8"
|
||||||
lateinit var sharedViewModel: SharedViewModel
|
private var isConnected: Boolean = false
|
||||||
|
private var sharedPref :SharedPreferences? = null
|
||||||
|
|
||||||
|
private var token :String =""
|
||||||
|
private lateinit var sharedViewModel: SharedViewModel
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = DataBindingUtil.setContentView(this,R.layout.main_activity)
|
binding = DataBindingUtil.setContentView(this,R.layout.main_activity)
|
||||||
|
|
||||||
sharedViewModel = ViewModelProvider(this).get(SharedViewModel::class.java)
|
sharedViewModel = ViewModelProvider(this).get(SharedViewModel::class.java)
|
||||||
// val policy =
|
sharedPref = this.getPreferences(Context.MODE_PRIVATE)
|
||||||
// StrictMode.ThreadPolicy.Builder().permitAll().build()
|
|
||||||
// StrictMode.setThreadPolicy(policy)
|
// if(sharedPref?.contains("token")!! && (sharedPref?.getLong("time",System.currentTimeMillis()/1000/60/60)!! < (System.currentTimeMillis()/1000/60/60)) ){
|
||||||
//TODO Use Coroutines
|
// val savedToken = sharedPref?.getString("token","error")!!
|
||||||
if(spotify==null){
|
// sharedViewModel.accessToken.value = savedToken
|
||||||
|
// Log.i("SharedPrefs Token:",savedToken)
|
||||||
|
// token = savedToken
|
||||||
|
//
|
||||||
|
// implementSpotifyService(savedToken)
|
||||||
|
// }else{authenticateSpotify()}
|
||||||
|
|
||||||
|
if(sharedViewModel.spotifyService == null){
|
||||||
authenticateSpotify()
|
authenticateSpotify()
|
||||||
|
}else{
|
||||||
|
implementSpotifyService(sharedViewModel.accessToken.value!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
requestPermission()
|
requestPermission()
|
||||||
|
|
||||||
//Object to download From Youtube {"https://github.com/sealedtx/java-youtube-downloader"}
|
//Object to download From Youtube {"https://github.com/sealedtx/java-youtube-downloader"}
|
||||||
@ -68,69 +77,22 @@ class MainActivity : AppCompatActivity() ,DownloadHelper{
|
|||||||
downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||||
sharedViewModel.downloadManager = downloadManager
|
sharedViewModel.downloadManager = downloadManager
|
||||||
|
|
||||||
if (intent?.action == Intent.ACTION_SEND) {
|
isConnected = isOnline()
|
||||||
if ("text/plain" == intent.type) {
|
sharedViewModel.isConnected.value = isConnected
|
||||||
intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
|
|
||||||
Log.i("Intent Received",it)
|
Log.i("Connection Status",isConnected.toString())
|
||||||
sharedViewModel.intentString = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun onActivityResult(
|
handleIntentFromExternalActivity()
|
||||||
requestCode: Int,
|
|
||||||
resultCode: Int,
|
|
||||||
intent: Intent?
|
|
||||||
) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, intent)
|
|
||||||
// Check if result comes from the correct activity
|
|
||||||
if (requestCode == LoginActivity.REQUEST_CODE) {
|
|
||||||
val response = AuthenticationClient.getResponse(resultCode, intent)
|
|
||||||
when (response.type) {
|
|
||||||
AuthenticationResponse.Type.TOKEN -> {
|
|
||||||
Log.i("Network",response.accessToken.toString())
|
|
||||||
token = response.accessToken
|
|
||||||
sharedViewModel.accessToken = response.accessToken
|
|
||||||
|
|
||||||
//Implementing My Own Spotify Requests
|
|
||||||
implementSpotifyExtra()
|
|
||||||
val api = SpotifyApi()
|
|
||||||
api.setAccessToken(token)
|
|
||||||
spotify = api.service
|
|
||||||
sharedViewModel.spotify = api.service
|
|
||||||
//Initiate Processes In Main Fragment
|
|
||||||
|
|
||||||
sharedViewModel.uiScope.launch {
|
|
||||||
val me = spotifyExtra?.getMe()?.display_name
|
|
||||||
sharedViewModel.userName.value = "Logged in as: $me"
|
|
||||||
Log.i("Network","Hello, " + me!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
sharedViewModel.userName.observe(this, Observer {
|
|
||||||
binding.message.text = it
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AuthenticationResponse.Type.ERROR -> {
|
|
||||||
Log.i("Network",response.error.toString())
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adding my own new Spotify Web Api Requests!
|
* Adding my own new Spotify Web Api Requests!
|
||||||
* */
|
* */
|
||||||
private fun implementSpotifyExtra() {
|
private fun implementSpotifyService(token:String) {
|
||||||
|
|
||||||
val httpClient: OkHttpClient.Builder = OkHttpClient.Builder()
|
val httpClient: OkHttpClient.Builder = OkHttpClient.Builder()
|
||||||
|
|
||||||
httpClient.addInterceptor(object : Interceptor {
|
httpClient.addInterceptor(object : Interceptor {
|
||||||
|
|
||||||
override fun intercept(chain: Interceptor.Chain): Response {
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
val request: Request =
|
val request: Request =
|
||||||
chain.request().newBuilder().addHeader(
|
chain.request().newBuilder().addHeader(
|
||||||
@ -146,17 +108,89 @@ class MainActivity : AppCompatActivity() ,DownloadHelper{
|
|||||||
.add(KotlinJsonAdapterFactory())
|
.add(KotlinJsonAdapterFactory())
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val retrofit: Retrofit =
|
val retrofit = Retrofit.Builder()
|
||||||
Retrofit.Builder()
|
|
||||||
.baseUrl("https://api.spotify.com/v1/")
|
.baseUrl("https://api.spotify.com/v1/")
|
||||||
.client(httpClient.build())
|
.client(httpClient.build())
|
||||||
.addConverterFactory(MoshiConverterFactory.create(moshi))
|
.addConverterFactory(MoshiConverterFactory.create(moshi))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
spotifyExtra = retrofit.create(SpotifyNewService::class.java)
|
spotifyService = retrofit.create(SpotifyService::class.java)
|
||||||
sharedViewModel.spotifyExtra = spotifyExtra
|
sharedViewModel.spotifyService = spotifyService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getSpotifyToken(){
|
||||||
|
val httpClient2: OkHttpClient.Builder = OkHttpClient.Builder()
|
||||||
|
httpClient2.addInterceptor(object : Interceptor {
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val request: Request =
|
||||||
|
chain.request().newBuilder().addHeader(
|
||||||
|
"Authorization",
|
||||||
|
"Basic ${android.util.Base64.encodeToString("$clientId:$clientSecret".toByteArray(),android.util.Base64.NO_WRAP)}"
|
||||||
|
).build()
|
||||||
|
return chain.proceed(request)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
val moshi = Moshi.Builder()
|
||||||
|
.add(KotlinJsonAdapterFactory())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val retrofit2 = Retrofit.Builder()
|
||||||
|
.baseUrl("https://accounts.spotify.com/")
|
||||||
|
.client(httpClient2.build())
|
||||||
|
.addConverterFactory(MoshiConverterFactory.create(moshi))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
spotifyServiceToken = retrofit2.create(SpotifyServiceToken::class.java)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun authenticateSpotify() {
|
||||||
|
if (spotifyServiceToken == null) {
|
||||||
|
getSpotifyToken()
|
||||||
|
}
|
||||||
|
sharedViewModel.uiScope.launch {
|
||||||
|
if (isConnected) {
|
||||||
|
Log.i("Post Request", "Made")
|
||||||
|
token = spotifyServiceToken!!.getToken()!!.access_token
|
||||||
|
implementSpotifyService(token)
|
||||||
|
Log.i("Post Request", token)
|
||||||
|
sharedViewModel.accessToken.value = token
|
||||||
|
saveToken(token)
|
||||||
|
}else{
|
||||||
|
Log.i("network", "unavailable")
|
||||||
|
// sharedViewModel.showAlertDialog(resources,this@MainActivity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveToken(token:String) {
|
||||||
|
with (sharedPref?.edit()) {
|
||||||
|
this?.let {
|
||||||
|
putString("token", token)
|
||||||
|
putLong("time",(System.currentTimeMillis()/1000/60/60))
|
||||||
|
commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleIntentFromExternalActivity() {
|
||||||
|
if (intent?.action == Intent.ACTION_SEND) {
|
||||||
|
if ("text/plain" == intent.type) {
|
||||||
|
intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
|
||||||
|
Log.i("Intent Received",it)
|
||||||
|
sharedViewModel.intentString = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isOnline(): Boolean {
|
||||||
|
val cm =
|
||||||
|
getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
|
val netInfo = cm.activeNetworkInfo
|
||||||
|
return netInfo != null && netInfo.isConnectedOrConnecting
|
||||||
|
}
|
||||||
|
|
||||||
private fun requestPermission() {
|
private fun requestPermission() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
@ -167,13 +201,66 @@ class MainActivity : AppCompatActivity() ,DownloadHelper{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(savedInstanceState:Bundle) {
|
||||||
|
savedInstanceState.putString("token",token)
|
||||||
|
super.onSaveInstanceState(savedInstanceState)
|
||||||
|
}
|
||||||
|
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
||||||
|
if (savedInstanceState.getString("token") ==""){
|
||||||
|
super.onRestoreInstanceState(savedInstanceState)
|
||||||
|
}else{
|
||||||
|
implementSpotifyService(savedInstanceState.getString("token")!!)
|
||||||
|
super.onRestoreInstanceState(savedInstanceState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
private fun authenticateSpotify() {
|
private fun authenticateSpotify() {
|
||||||
val builder = AuthenticationRequest.Builder(CLIENT_ID,AuthenticationResponse.Type.TOKEN,REDIRECT_URI)
|
val builder = AuthenticationRequest.Builder(clientId,AuthenticationResponse.Type.TOKEN,redirectUri)
|
||||||
.setShowDialog(false)
|
.setScopes(arrayOf("user-read-private"))
|
||||||
.setScopes(arrayOf("user-read-private","streaming","user-read-email","user-modify-playback-state","user-top-read","user-library-modify","user-read-currently-playing","user-library-read","user-read-recently-played"))
|
// .setScopes(arrayOf("user-read-private","streaming","user-read-email","user-modify-playback-state","user-top-read","user-library-modify","user-read-currently-playing","user-library-read","user-read-recently-played"))
|
||||||
val request: AuthenticationRequest = builder.build()
|
val request: AuthenticationRequest = builder.build()
|
||||||
AuthenticationClient.openLoginActivity(this, LoginActivity.REQUEST_CODE, request)
|
AuthenticationClient.openLoginActivity(this, LoginActivity.REQUEST_CODE, request)
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
/*override fun onActivityResult(
|
||||||
|
requestCode: Int,
|
||||||
|
resultCode: Int,
|
||||||
|
intent: Intent?
|
||||||
|
) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, intent)
|
||||||
|
// Check if result comes from the correct activity
|
||||||
|
if (requestCode == LoginActivity.REQUEST_CODE) {
|
||||||
|
val response = AuthenticationClient.getResponse(resultCode, intent)
|
||||||
|
when (response.type) {
|
||||||
|
AuthenticationResponse.Type.TOKEN -> {
|
||||||
|
Log.i("Network",response.accessToken.toString())
|
||||||
|
token = response.accessToken
|
||||||
|
sharedViewModel.accessToken = response.accessToken
|
||||||
|
|
||||||
|
//Implementing My Own Spotify Requests
|
||||||
|
implementSpotifyService(token)
|
||||||
|
|
||||||
|
sharedViewModel.uiScope.launch {
|
||||||
|
val me = spotifyService?.getMe()?.display_name
|
||||||
|
sharedViewModel.userName.value = "Logged in as: $me"
|
||||||
|
Log.i("Network","Hello, " + me!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
sharedViewModel.userName.observe(this, Observer {
|
||||||
|
binding.message.text = it
|
||||||
|
})
|
||||||
|
}
|
||||||
|
AuthenticationResponse.Type.ERROR -> {
|
||||||
|
Log.i("Network",response.error.toString())
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Log.i("Network","Something Weird Happened While Authenticating")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -1,39 +1,40 @@
|
|||||||
package com.shabinder.musicForEveryone
|
package com.shabinder.musicForEveryone
|
||||||
|
|
||||||
import android.app.DownloadManager
|
import android.app.DownloadManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.Resources
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import com.github.kiulian.downloader.YoutubeDownloader
|
import com.github.kiulian.downloader.YoutubeDownloader
|
||||||
import com.shabinder.musicForEveryone.utils.SpotifyNewService
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import kaaes.spotify.webapi.android.SpotifyService
|
import com.shabinder.musicForEveryone.models.Album
|
||||||
import kaaes.spotify.webapi.android.models.Album
|
import com.shabinder.musicForEveryone.models.Playlist
|
||||||
import kaaes.spotify.webapi.android.models.Playlist
|
import com.shabinder.musicForEveryone.models.Track
|
||||||
import kaaes.spotify.webapi.android.models.Track
|
import com.shabinder.musicForEveryone.utils.SpotifyService
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
|
||||||
class SharedViewModel : ViewModel() {
|
class SharedViewModel : ViewModel() {
|
||||||
var intentString = ""
|
var intentString = ""
|
||||||
var accessToken:String = ""
|
var accessToken = MutableLiveData<String>().apply { value = "" }
|
||||||
var userName = MutableLiveData<String>().apply { value = "Placeholder" }
|
var spotifyService : SpotifyService? = null
|
||||||
var spotify :SpotifyService? = null
|
|
||||||
var spotifyExtra : SpotifyNewService? = null
|
|
||||||
var ytDownloader : YoutubeDownloader? = null
|
var ytDownloader : YoutubeDownloader? = null
|
||||||
var downloadManager : DownloadManager? = null
|
var downloadManager : DownloadManager? = null
|
||||||
|
var isConnected = MutableLiveData<Boolean>().apply { value = false }
|
||||||
|
|
||||||
var viewModelJob = Job()
|
private var viewModelJob = Job()
|
||||||
|
|
||||||
val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
|
val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
|
||||||
|
|
||||||
suspend fun getTrackDetails(trackLink:String): Track?{
|
suspend fun getTrackDetails(trackLink:String): Track?{
|
||||||
return spotifyExtra?.getTrack(trackLink)
|
return spotifyService?.getTrack(trackLink)
|
||||||
}
|
}
|
||||||
suspend fun getAlbumDetails(albumLink:String): Album?{
|
suspend fun getAlbumDetails(albumLink:String): Album?{
|
||||||
return spotifyExtra?.getAlbum(albumLink)
|
return spotifyService?.getAlbum(albumLink)
|
||||||
}
|
}
|
||||||
suspend fun getPlaylistDetails(link:String): Playlist?{
|
suspend fun getPlaylistDetails(link:String): Playlist?{
|
||||||
return spotifyExtra?.getPlaylist(link)
|
return spotifyService?.getPlaylist(link)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -41,4 +42,15 @@ class SharedViewModel : ViewModel() {
|
|||||||
super.onCleared()
|
super.onCleared()
|
||||||
viewModelJob.cancel()
|
viewModelJob.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun showAlertDialog(resources:Resources,context: Context){
|
||||||
|
val dialog = MaterialAlertDialogBuilder(context,R.style.AlertDialogTheme)
|
||||||
|
.setTitle(resources.getString(R.string.title))
|
||||||
|
.setMessage(resources.getString(R.string.supporting_text))
|
||||||
|
.setPositiveButton(resources.getString(R.string.cancel)) { _, _ ->
|
||||||
|
// Respond to neutral button press
|
||||||
|
}
|
||||||
|
.setBackground(resources.getDrawable(R.drawable.gradient))
|
||||||
|
.show()
|
||||||
|
}
|
||||||
}
|
}
|
@ -8,18 +8,29 @@ import android.util.Log
|
|||||||
import com.github.kiulian.downloader.YoutubeDownloader
|
import com.github.kiulian.downloader.YoutubeDownloader
|
||||||
import com.github.kiulian.downloader.model.formats.Format
|
import com.github.kiulian.downloader.model.formats.Format
|
||||||
import com.github.kiulian.downloader.model.quality.AudioQuality
|
import com.github.kiulian.downloader.model.quality.AudioQuality
|
||||||
|
import com.shabinder.musicForEveryone.fragments.MainFragment
|
||||||
|
import com.shabinder.musicForEveryone.models.Track
|
||||||
import com.shabinder.musicForEveryone.utils.YoutubeInterface
|
import com.shabinder.musicForEveryone.utils.YoutubeInterface
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
interface DownloadHelper {
|
interface DownloadHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function To Download All Tracks Available in a List
|
||||||
|
**/
|
||||||
|
suspend fun downloadAllTracks(trackList : List<Track>, ytDownloader: YoutubeDownloader?, downloadManager: DownloadManager?) {
|
||||||
|
trackList.forEach { downloadTrack(null,ytDownloader,downloadManager,"${it.name} ${it.artists?.get(0)?.name ?:""}") }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
suspend fun downloadTrack(
|
suspend fun downloadTrack(
|
||||||
|
mainFragment: MainFragment?,
|
||||||
ytDownloader: YoutubeDownloader?,
|
ytDownloader: YoutubeDownloader?,
|
||||||
downloadManager: DownloadManager?,
|
downloadManager: DownloadManager?,
|
||||||
searchQuery: String
|
searchQuery: String
|
||||||
) {
|
) {
|
||||||
|
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
val data = YoutubeInterface.search(searchQuery)?.get(0)
|
val data = YoutubeInterface.search(searchQuery)?.get(0)
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
@ -36,11 +47,44 @@ interface DownloadHelper {
|
|||||||
Log.i("DHelper Link Found", audioUrl)
|
Log.i("DHelper Link Found", audioUrl)
|
||||||
if (audioUrl != null) {
|
if (audioUrl != null) {
|
||||||
downloadFile(audioUrl, downloadManager, details!!.title())
|
downloadFile(audioUrl, downloadManager, details!!.title())
|
||||||
|
withContext(Dispatchers.Main){
|
||||||
|
mainFragment?.showToast("Download Started")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.i("YT audio url is null", format.toString())
|
Log.i("YT audio url is null", format.toString())
|
||||||
}
|
}
|
||||||
}catch (e:ArrayIndexOutOfBoundsException){
|
}catch (e:ArrayIndexOutOfBoundsException){
|
||||||
Log.i("Catch",e.toString())
|
try{
|
||||||
|
val format: Format =
|
||||||
|
video?.findAudioWithQuality(AudioQuality.high)?.get(0) as Format
|
||||||
|
val audioUrl = format.url()
|
||||||
|
Log.i("DHelper Link Found", audioUrl)
|
||||||
|
if (audioUrl != null) {
|
||||||
|
downloadFile(audioUrl, downloadManager, details!!.title())
|
||||||
|
withContext(Dispatchers.Main){
|
||||||
|
mainFragment?.showToast("Download Started")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.i("YT audio url is null", format.toString())
|
||||||
|
}
|
||||||
|
}catch (e:ArrayIndexOutOfBoundsException){
|
||||||
|
try{
|
||||||
|
val format: Format =
|
||||||
|
video?.findAudioWithQuality(AudioQuality.high)?.get(0) as Format
|
||||||
|
val audioUrl = format.url()
|
||||||
|
Log.i("DHelper Link Found", audioUrl)
|
||||||
|
if (audioUrl != null) {
|
||||||
|
downloadFile(audioUrl, downloadManager, details!!.title())
|
||||||
|
withContext(Dispatchers.Main){
|
||||||
|
mainFragment?.showToast("Download Started")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.i("YT audio url is null", format.toString())
|
||||||
|
}
|
||||||
|
}catch(e:ArrayIndexOutOfBoundsException){
|
||||||
|
Log.i("Catch",e.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -70,6 +114,7 @@ interface DownloadHelper {
|
|||||||
.setNotificationVisibility(VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
|
.setNotificationVisibility(VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
|
||||||
downloadManager?.enqueue(request)
|
downloadManager?.enqueue(request)
|
||||||
Log.i("DownloadManager", "Download Request Sent")
|
Log.i("DownloadManager", "Download Request Sent")
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
package com.shabinder.musicForEveryone.fragments
|
package com.shabinder.musicForEveryone.fragments
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -14,19 +20,25 @@ import com.shabinder.musicForEveryone.R
|
|||||||
import com.shabinder.musicForEveryone.SharedViewModel
|
import com.shabinder.musicForEveryone.SharedViewModel
|
||||||
import com.shabinder.musicForEveryone.databinding.MainFragmentBinding
|
import com.shabinder.musicForEveryone.databinding.MainFragmentBinding
|
||||||
import com.shabinder.musicForEveryone.downloadHelper.DownloadHelper
|
import com.shabinder.musicForEveryone.downloadHelper.DownloadHelper
|
||||||
|
import com.shabinder.musicForEveryone.models.Track
|
||||||
import com.shabinder.musicForEveryone.recyclerView.TrackListAdapter
|
import com.shabinder.musicForEveryone.recyclerView.TrackListAdapter
|
||||||
|
import com.shabinder.musicForEveryone.utils.SpotifyService
|
||||||
import com.shabinder.musicForEveryone.utils.bindImage
|
import com.shabinder.musicForEveryone.utils.bindImage
|
||||||
import kaaes.spotify.webapi.android.SpotifyService
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kaaes.spotify.webapi.android.models.Track
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
class MainFragment : Fragment(),DownloadHelper {
|
class MainFragment : Fragment(),DownloadHelper {
|
||||||
lateinit var binding:MainFragmentBinding
|
private lateinit var binding:MainFragmentBinding
|
||||||
|
private lateinit var mainViewModel: MainViewModel
|
||||||
private lateinit var sharedViewModel: SharedViewModel
|
private lateinit var sharedViewModel: SharedViewModel
|
||||||
var spotify : SpotifyService? = null
|
private lateinit var adapter:TrackListAdapter
|
||||||
var type:String = ""
|
private var spotifyService : SpotifyService? = null
|
||||||
var spotifyLink = ""
|
private var type:String = ""
|
||||||
|
private var spotifyLink = ""
|
||||||
|
private var i: Intent? = null
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
@ -34,111 +46,211 @@ class MainFragment : Fragment(),DownloadHelper {
|
|||||||
binding = DataBindingUtil.inflate(inflater,R.layout.main_fragment,container,false)
|
binding = DataBindingUtil.inflate(inflater,R.layout.main_fragment,container,false)
|
||||||
|
|
||||||
sharedViewModel = ViewModelProvider(this.requireActivity()).get(SharedViewModel::class.java)
|
sharedViewModel = ViewModelProvider(this.requireActivity()).get(SharedViewModel::class.java)
|
||||||
spotify = sharedViewModel.spotify
|
mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
|
||||||
|
spotifyService = sharedViewModel.spotifyService
|
||||||
|
|
||||||
|
val spanStringBuilder = SpannableStringBuilder()
|
||||||
|
spanStringBuilder.append(getText(R.string.d_one)).append("\n")
|
||||||
|
spanStringBuilder.append(getText(R.string.d_two)).append("\n")
|
||||||
|
spanStringBuilder.append(getText(R.string.d_three)).append("\n")
|
||||||
|
|
||||||
|
binding.usage.text = spanStringBuilder
|
||||||
|
openSpotifyButton()
|
||||||
|
|
||||||
binding.btnSearch.setOnClickListener {
|
binding.btnSearch.setOnClickListener {
|
||||||
spotifyLink = binding.spotifyLink.text.toString()
|
sharedViewModel.isConnected.value = isOnline()
|
||||||
|
spotifyLink = binding.linkSearch.text.toString()
|
||||||
|
|
||||||
val link = spotifyLink.substringAfterLast('/' , "Error").substringBefore('?')
|
val link = spotifyLink.substringAfterLast('/', "Error").substringBefore('?')
|
||||||
type = spotifyLink.substringBeforeLast('/' , "Error").substringAfterLast('/')
|
type = spotifyLink.substringBeforeLast('/', "Error").substringAfterLast('/')
|
||||||
|
|
||||||
Log.i("Fragment", "$type : $link")
|
Log.i("Fragment", "$type : $link")
|
||||||
|
|
||||||
val adapter = TrackListAdapter()
|
if (type == "Error" || link == "Error") {
|
||||||
binding.trackList.adapter = adapter
|
showToast("Please Check Your Link!")
|
||||||
adapter.sharedViewModel = sharedViewModel
|
} else if(sharedViewModel.isConnected.value == false){
|
||||||
when(type){
|
sharedViewModel.showAlertDialog(resources,requireContext())
|
||||||
"track" -> {
|
}
|
||||||
sharedViewModel.uiScope.launch{
|
else {
|
||||||
val trackObject = sharedViewModel.getTrackDetails(link)
|
adapter = TrackListAdapter()
|
||||||
|
binding.trackList.adapter = adapter
|
||||||
|
adapter.sharedViewModel = sharedViewModel
|
||||||
|
adapter.mainFragment = this
|
||||||
|
setUiVisibility()
|
||||||
|
|
||||||
binding.imageView.visibility =View.VISIBLE
|
if(mainViewModel.searchLink == spotifyLink){
|
||||||
|
//it's a Device Configuration Change
|
||||||
|
adapterConfig(mainViewModel.trackList)
|
||||||
|
bindImage(binding.imageView,mainViewModel.coverUrl)
|
||||||
|
}else{
|
||||||
|
when (type) {
|
||||||
|
"track" -> {
|
||||||
|
mainViewModel.searchLink = spotifyLink
|
||||||
|
sharedViewModel.uiScope.launch {
|
||||||
|
val trackObject = sharedViewModel.getTrackDetails(link)
|
||||||
|
val trackList = mutableListOf<Track>()
|
||||||
|
trackList.add(trackObject!!)
|
||||||
|
mainViewModel.trackList = trackList
|
||||||
|
mainViewModel.coverUrl = trackObject.album!!.images?.get(0)!!.url!!
|
||||||
|
bindImage(binding.imageView,mainViewModel.coverUrl)
|
||||||
|
adapterConfig(trackList)
|
||||||
|
|
||||||
val trackList = mutableListOf<Track>()
|
binding.btnDownloadAll.setOnClickListener {
|
||||||
trackList.add(trackObject!!)
|
sharedViewModel.uiScope.launch {
|
||||||
bindImage(binding.imageView, trackObject.album.images[0].url)
|
withContext(Dispatchers.IO) {
|
||||||
adapter.totalItems = 1
|
downloadAllTracks(
|
||||||
adapter.trackList = trackList
|
trackList,
|
||||||
adapter.notifyDataSetChanged()
|
sharedViewModel.ytDownloader,
|
||||||
Log.i("Adapter",trackList.size.toString())
|
sharedViewModel.downloadManager
|
||||||
binding.btnDownloadAll.setOnClickListener { downloadAllTracks(trackList) }
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"album" -> {
|
||||||
|
mainViewModel.searchLink = spotifyLink
|
||||||
|
sharedViewModel.uiScope.launch {
|
||||||
|
val albumObject = sharedViewModel.getAlbumDetails(link)
|
||||||
|
val trackList = mutableListOf<Track>()
|
||||||
|
albumObject!!.tracks?.items?.forEach { trackList.add(it!!) }
|
||||||
|
mainViewModel.trackList = trackList
|
||||||
|
mainViewModel.coverUrl = albumObject.images?.get(0)!!.url!!
|
||||||
|
bindImage(binding.imageView,mainViewModel.coverUrl)
|
||||||
|
adapter.isAlbum = true
|
||||||
|
adapterConfig(trackList)
|
||||||
|
binding.btnDownloadAll.setOnClickListener {
|
||||||
|
sharedViewModel.uiScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
downloadAllTracks(
|
||||||
|
trackList,
|
||||||
|
sharedViewModel.ytDownloader,
|
||||||
|
sharedViewModel.downloadManager
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
"playlist" -> {
|
||||||
|
mainViewModel.searchLink = spotifyLink
|
||||||
|
sharedViewModel.uiScope.launch {
|
||||||
|
val playlistObject = sharedViewModel.getPlaylistDetails(link)
|
||||||
|
val trackList = mutableListOf<Track>()
|
||||||
|
playlistObject!!.tracks?.items!!.forEach { trackList.add(it?.track!!) }
|
||||||
|
mainViewModel.trackList = trackList
|
||||||
|
mainViewModel.coverUrl = playlistObject.images?.get(0)!!.url!!
|
||||||
|
bindImage(binding.imageView,mainViewModel.coverUrl)
|
||||||
|
adapterConfig(trackList)
|
||||||
|
binding.btnDownloadAll.setOnClickListener {
|
||||||
|
sharedViewModel.uiScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
downloadAllTracks(
|
||||||
|
trackList,
|
||||||
|
sharedViewModel.ytDownloader,
|
||||||
|
sharedViewModel.downloadManager
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
"episode" -> {
|
||||||
|
showToast("Implementation Pending")
|
||||||
|
}
|
||||||
|
"show" -> {
|
||||||
|
showToast("Implementation Pending ")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"album" -> {
|
|
||||||
sharedViewModel.uiScope.launch{
|
|
||||||
|
|
||||||
val albumObject = sharedViewModel.getAlbumDetails(link)
|
|
||||||
// binding.titleView.text = albumObject!!.name
|
|
||||||
// binding.titleView.visibility =View.VISIBLE
|
|
||||||
binding.imageView.visibility =View.VISIBLE
|
|
||||||
binding.btnDownloadAll.visibility =View.VISIBLE
|
|
||||||
val trackList = mutableListOf<Track>()
|
|
||||||
albumObject!!.tracks?.items?.forEach { trackList.add(it as Track) }
|
|
||||||
adapter.totalItems = trackList.size
|
|
||||||
adapter.trackList = trackList
|
|
||||||
adapter.notifyDataSetChanged()
|
|
||||||
|
|
||||||
Log.i("Adapter",trackList.size.toString())
|
|
||||||
|
|
||||||
bindImage(binding.imageView, albumObject.images[0].url)
|
|
||||||
binding.btnDownloadAll.setOnClickListener { downloadAllTracks(trackList) }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
"playlist" -> {
|
|
||||||
sharedViewModel.uiScope.launch{
|
|
||||||
val playlistObject = sharedViewModel.getPlaylistDetails(link)
|
|
||||||
binding.btnDownloadAll.visibility =View.VISIBLE
|
|
||||||
|
|
||||||
|
|
||||||
binding.imageView.visibility =View.VISIBLE
|
|
||||||
// binding.titleView.text = "${if(playlistObject!!.name.length > 18){"${playlistObject.name.subSequence(0,17)}..."}else{playlistObject.name}}"
|
|
||||||
// binding.titleView.visibility =View.VISIBLE
|
|
||||||
// binding.playlistOwner.visibility =View.VISIBLE
|
|
||||||
// binding.playlistOwner.text = "by: ${playlistObject.owner.display_name}"
|
|
||||||
val trackList = mutableListOf<Track>()
|
|
||||||
playlistObject!!.tracks?.items!!.forEach { trackList.add(it.track) }
|
|
||||||
adapter.trackList = trackList.toList()
|
|
||||||
adapter.totalItems = trackList.size
|
|
||||||
adapter.notifyDataSetChanged()
|
|
||||||
|
|
||||||
Log.i("Adapter",trackList.size.toString())
|
|
||||||
|
|
||||||
bindImage(binding.imageView, playlistObject.images[0].url)
|
|
||||||
|
|
||||||
binding.btnDownloadAll.setOnClickListener { downloadAllTracks(trackList) }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
"episode" -> {showToast("Implementation Pending")}
|
|
||||||
"show" -> {showToast("Implementation Pending ")}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.spotifyLink.setText(sharedViewModel.intentString)
|
handleIntent()
|
||||||
sharedViewModel.userName.observe(viewLifecycleOwner, Observer {
|
if(savedInstanceState != null && binding.linkSearch.text.toString() != ""){
|
||||||
//Waiting for Authentication to Finish with Spotify
|
binding.linkSearch.setText(savedInstanceState["searchLink"].toString())
|
||||||
if (it != "Placeholder"){
|
binding.btnSearch.performClick()
|
||||||
if(sharedViewModel.intentString != ""){binding.btnSearch.performClick()}
|
setUiVisibility()
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun downloadAllTracks(trackList : List<Track>) {
|
private fun openSpotifyButton() {
|
||||||
sharedViewModel.uiScope.launch {
|
val manager: PackageManager = requireActivity().packageManager
|
||||||
trackList.forEach { downloadTrack(sharedViewModel.ytDownloader,sharedViewModel.downloadManager,"${it.name} ${it.artists[0].name?:""}") }
|
try {
|
||||||
|
i = manager.getLaunchIntentForPackage("com.spotify.music")
|
||||||
|
if (i == null) throw PackageManager.NameNotFoundException()
|
||||||
|
i?.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
binding.btnOpenSpotify.setOnClickListener { startActivity(i) }
|
||||||
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
|
binding.textView.text = getString(R.string.spotify_not_installed)
|
||||||
|
binding.btnOpenSpotify.text = getString(R.string.spotify_web_link)
|
||||||
|
val uri: Uri =
|
||||||
|
Uri.parse("http://open.spotify.com")
|
||||||
|
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||||
|
binding.btnOpenSpotify.setOnClickListener {
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showToast(message:String){
|
/**
|
||||||
|
* Configure Recycler View Adapter
|
||||||
|
**/
|
||||||
|
private fun adapterConfig(trackList: List<Track>){
|
||||||
|
adapter.trackList = trackList.toList()
|
||||||
|
adapter.totalItems = trackList.size
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make Ui elements Visible
|
||||||
|
**/
|
||||||
|
private fun setUiVisibility() {
|
||||||
|
binding.btnDownloadAll.visibility =View.VISIBLE
|
||||||
|
binding.titleView.visibility = View.GONE
|
||||||
|
binding.openSpotify.visibility = View.GONE
|
||||||
|
binding.trackList.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle Intent If there is any!
|
||||||
|
**/
|
||||||
|
private fun handleIntent() {
|
||||||
|
binding.linkSearch.setText(sharedViewModel.intentString)
|
||||||
|
sharedViewModel.accessToken.observe(viewLifecycleOwner, Observer {
|
||||||
|
//Waiting for Authentication to Finish with Spotify
|
||||||
|
if (it != ""){
|
||||||
|
if(sharedViewModel.intentString != ""){
|
||||||
|
binding.btnSearch.performClick()
|
||||||
|
setUiVisibility()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Util. Function to create toasts!
|
||||||
|
**/
|
||||||
|
fun showToast(message:String){
|
||||||
Toast.makeText(context,message,Toast.LENGTH_SHORT).show()
|
Toast.makeText(context,message,Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
private fun isOnline(): Boolean {
|
||||||
|
val cm =
|
||||||
|
requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
|
val netInfo = cm.activeNetworkInfo
|
||||||
|
return netInfo != null && netInfo.isConnectedOrConnecting
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
super.onSaveInstanceState(outState)
|
||||||
|
outState.putCharSequence("searchLink",mainViewModel.searchLink)
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.shabinder.musicForEveryone.fragments
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.shabinder.musicForEveryone.models.Track
|
||||||
|
|
||||||
|
class MainViewModel: ViewModel() {
|
||||||
|
var searchLink:String = ""
|
||||||
|
var trackList = mutableListOf<Track>()
|
||||||
|
var coverUrl:String = ""
|
||||||
|
|
||||||
|
}
|
@ -10,8 +10,9 @@ import androidx.recyclerview.widget.RecyclerView
|
|||||||
import com.shabinder.musicForEveryone.R
|
import com.shabinder.musicForEveryone.R
|
||||||
import com.shabinder.musicForEveryone.SharedViewModel
|
import com.shabinder.musicForEveryone.SharedViewModel
|
||||||
import com.shabinder.musicForEveryone.downloadHelper.DownloadHelper
|
import com.shabinder.musicForEveryone.downloadHelper.DownloadHelper
|
||||||
|
import com.shabinder.musicForEveryone.fragments.MainFragment
|
||||||
|
import com.shabinder.musicForEveryone.models.Track
|
||||||
import com.shabinder.musicForEveryone.utils.bindImage
|
import com.shabinder.musicForEveryone.utils.bindImage
|
||||||
import kaaes.spotify.webapi.android.models.Track
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class TrackListAdapter:RecyclerView.Adapter<TrackListAdapter.ViewHolder>(),DownloadHelper {
|
class TrackListAdapter:RecyclerView.Adapter<TrackListAdapter.ViewHolder>(),DownloadHelper {
|
||||||
@ -19,6 +20,8 @@ class TrackListAdapter:RecyclerView.Adapter<TrackListAdapter.ViewHolder>(),Downl
|
|||||||
var trackList = listOf<Track>()
|
var trackList = listOf<Track>()
|
||||||
var totalItems:Int = 0
|
var totalItems:Int = 0
|
||||||
var sharedViewModel = SharedViewModel()
|
var sharedViewModel = SharedViewModel()
|
||||||
|
var isAlbum:Boolean = false
|
||||||
|
var mainFragment:MainFragment? = null
|
||||||
|
|
||||||
override fun getItemCount():Int = totalItems
|
override fun getItemCount():Int = totalItems
|
||||||
|
|
||||||
@ -31,16 +34,16 @@ class TrackListAdapter:RecyclerView.Adapter<TrackListAdapter.ViewHolder>(),Downl
|
|||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val item = trackList[position]
|
val item = trackList[position]
|
||||||
if(totalItems == 1){holder.coverImage.visibility = View.GONE}else{
|
if(totalItems == 1 || isAlbum){holder.coverImage.visibility = View.GONE}else{
|
||||||
bindImage(holder.coverImage,item.album.images[0].url)
|
bindImage(holder.coverImage, item.album!!.images?.get(0)?.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
holder.trackName.text = "${if(item.name.length > 17){"${item.name.subSequence(0,16)}..."}else{item.name}}"
|
holder.trackName.text = "${if(item.name!!.length > 17){"${item.name!!.subSequence(0,16)}..."}else{item.name}}"
|
||||||
holder.artistName.text = "${item.artists[0]?.name?:""}..."
|
holder.artistName.text = "${item.artists?.get(0)?.name?:""}..."
|
||||||
holder.duration.text = "${item.duration_ms/1000/60} minutes, ${(item.duration_ms/1000)%60} sec"
|
holder.duration.text = "${item.duration_ms/1000/60} minutes, ${(item.duration_ms/1000)%60} sec"
|
||||||
holder.downloadBtn.setOnClickListener{
|
holder.downloadBtn.setOnClickListener{
|
||||||
sharedViewModel.uiScope.launch {
|
sharedViewModel.uiScope.launch {
|
||||||
downloadTrack(sharedViewModel.ytDownloader,sharedViewModel.downloadManager,"${item.name} ${item.artists[0].name?:""}")
|
downloadTrack(mainFragment,sharedViewModel.ytDownloader,sharedViewModel.downloadManager,"${item.name} ${item.artists?.get(0)!!.name?:""}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,17 +7,15 @@ import com.bumptech.glide.Glide
|
|||||||
import com.bumptech.glide.request.RequestOptions
|
import com.bumptech.glide.request.RequestOptions
|
||||||
import com.shabinder.musicForEveryone.R
|
import com.shabinder.musicForEveryone.R
|
||||||
|
|
||||||
|
|
||||||
@BindingAdapter("imageUrl")
|
@BindingAdapter("imageUrl")
|
||||||
fun bindImage(imgView: ImageView, imgUrl: String?) {
|
fun bindImage(imgView: ImageView, imgUrl: String?) {
|
||||||
|
imgUrl?.let {
|
||||||
imgUrl?.let {
|
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build()
|
||||||
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build()
|
Glide.with(imgView.context)
|
||||||
Glide.with(imgView.context)
|
.load(imgUri)
|
||||||
.load(imgUri)
|
.apply(RequestOptions()
|
||||||
.apply(RequestOptions()
|
.placeholder(R.drawable.ic_song_placeholder)
|
||||||
.error(R.drawable.ic_musicplaceholder))
|
.error(R.drawable.ic_musicplaceholder))
|
||||||
.into(imgView)
|
.into(imgView)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,36 +0,0 @@
|
|||||||
package com.shabinder.musicForEveryone.utils
|
|
||||||
|
|
||||||
import kaaes.spotify.webapi.android.models.*
|
|
||||||
import retrofit2.http.GET
|
|
||||||
import retrofit2.http.Path
|
|
||||||
|
|
||||||
|
|
||||||
interface SpotifyNewService {
|
|
||||||
|
|
||||||
@GET("playlists/{playlist_id}")
|
|
||||||
suspend fun getPlaylist(@Path("playlist_id") playlistId: String?): Playlist?
|
|
||||||
|
|
||||||
@GET("tracks/{id}")
|
|
||||||
suspend fun getTrack(@Path("id") var1: String?): Track?
|
|
||||||
|
|
||||||
@GET("albums/{id}")
|
|
||||||
suspend fun getAlbum(@Path("id") var1: String?): Album?
|
|
||||||
|
|
||||||
@GET("me")
|
|
||||||
suspend fun getMe(): com.shabinder.musicForEveryone.utils.UserPrivate?
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
data class UserPrivate(
|
|
||||||
val country:String,
|
|
||||||
var display_name: String,
|
|
||||||
val email:String,
|
|
||||||
var external_urls: Map<String?, String?>? = null,
|
|
||||||
var followers: Followers? = null,
|
|
||||||
var href: String? = null,
|
|
||||||
var id: String? = null,
|
|
||||||
var images: List<Image?>? = null,
|
|
||||||
var product:String,
|
|
||||||
var type: String? = null,
|
|
||||||
var uri: String? = null)
|
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.shabinder.musicForEveryone.utils
|
||||||
|
|
||||||
|
import com.shabinder.musicForEveryone.models.*
|
||||||
|
import retrofit2.http.*
|
||||||
|
|
||||||
|
|
||||||
|
interface SpotifyService {
|
||||||
|
|
||||||
|
@GET("playlists/{playlist_id}")
|
||||||
|
suspend fun getPlaylist(@Path("playlist_id") playlistId: String?): Playlist?
|
||||||
|
|
||||||
|
@GET("tracks/{id}")
|
||||||
|
suspend fun getTrack(@Path("id") var1: String?): Track?
|
||||||
|
|
||||||
|
@GET("episodes/{id}")
|
||||||
|
suspend fun getEpisode(@Path("id") var1: String?): Track?
|
||||||
|
|
||||||
|
@GET("shows/{id}")
|
||||||
|
suspend fun getShow(@Path("id") var1: String?): Track?
|
||||||
|
|
||||||
|
@GET("albums/{id}")
|
||||||
|
suspend fun getAlbum(@Path("id") var1: String?): Album?
|
||||||
|
|
||||||
|
@GET("me")
|
||||||
|
suspend fun getMe(): UserPrivate?
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SpotifyServiceToken{
|
||||||
|
|
||||||
|
@POST("api/token")
|
||||||
|
@FormUrlEncoded
|
||||||
|
suspend fun getToken(@Field("grant_type") grant_type:String = "client_credentials"):Token?
|
||||||
|
|
||||||
|
}
|
@ -10,10 +10,8 @@ import java.io.IOException
|
|||||||
object YoutubeInterface {
|
object YoutubeInterface {
|
||||||
private var youtube: YouTube? = null
|
private var youtube: YouTube? = null
|
||||||
private var query:YouTube.Search.List? = null
|
private var query:YouTube.Search.List? = null
|
||||||
var apiKey:String = "AIzaSyDuRmMA_2mF56BjlhhNpa0SIbjMgjjFaEI"
|
private var apiKey:String = "AIzaSyDuRmMA_2mF56BjlhhNpa0SIbjMgjjFaEI"
|
||||||
var apiKey2:String = "AIzaSyCotyqgqmz5qw4-IH0tiezIrIIDHLI2yNs"
|
private var apiKey2:String = "AIzaSyCotyqgqmz5qw4-IH0tiezIrIIDHLI2yNs"
|
||||||
|
|
||||||
var clientID : String = "1040727735015-er2mvvljt45cabkuqimsh3iabqvfpvms.apps.googleusercontent.com"
|
|
||||||
|
|
||||||
fun youtubeConnector() {
|
fun youtubeConnector() {
|
||||||
youtube =
|
youtube =
|
||||||
|
Loading…
Reference in New Issue
Block a user