mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-25 02:14:32 +01:00
Made All Long Running Calls Asynchronous(Coroutines deployed!)
This commit is contained in:
parent
d4823f0e10
commit
735f7c270e
@ -1,6 +1,7 @@
|
|||||||
<component name="ProjectDictionaryState">
|
<component name="ProjectDictionaryState">
|
||||||
<dictionary name="shabinder">
|
<dictionary name="shabinder">
|
||||||
<words>
|
<words>
|
||||||
|
<w>moshi</w>
|
||||||
<w>musicforeveryone</w>
|
<w>musicforeveryone</w>
|
||||||
<w>musicplaceholder</w>
|
<w>musicplaceholder</w>
|
||||||
<w>shabinder</w>
|
<w>shabinder</w>
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
|
<component name="ProjectPlainTextFileTypeManager">
|
||||||
|
<file url="file://$PROJECT_DIR$/app/src/main/java/com/shabinder/musicForEveryone/downloadHelper/DownloadHelperLibrary.kt" />
|
||||||
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
|
@ -68,9 +68,14 @@ dependencies {
|
|||||||
implementation 'com.google.apis:google-api-services-youtube:v3-rev180-1.22.0'
|
implementation 'com.google.apis:google-api-services-youtube:v3-rev180-1.22.0'
|
||||||
implementation 'com.google.oauth-client:google-oauth-client:1.22.0'
|
implementation 'com.google.oauth-client:google-oauth-client:1.22.0'
|
||||||
implementation 'com.spotify.android:auth:1.1.0'
|
implementation 'com.spotify.android:auth:1.1.0'
|
||||||
implementation 'com.google.code.gson:gson:2.8.6'
|
|
||||||
implementation 'com.squareup.okhttp3:okhttp:4.8.0'
|
implementation 'com.squareup.okhttp3:okhttp:4.8.0'
|
||||||
|
|
||||||
|
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||||
|
implementation "com.squareup.moshi:moshi:1.9.3"
|
||||||
|
implementation "com.squareup.moshi:moshi-kotlin:1.9.3"
|
||||||
|
implementation "com.squareup.retrofit2:converter-moshi:2.9.0"
|
||||||
|
|
||||||
|
|
||||||
implementation 'com.github.sealedtx:java-youtube-downloader:2.2.2'
|
implementation 'com.github.sealedtx:java-youtube-downloader:2.2.2'
|
||||||
|
|
||||||
implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
|
implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
|
||||||
|
@ -21,6 +21,11 @@
|
|||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
|
|
||||||
<activity android:name="com.shabinder.musicForEveryone.MainActivity">
|
<activity android:name="com.shabinder.musicForEveryone.MainActivity">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="text/plain" />
|
||||||
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
@ -6,43 +6,52 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.StrictMode
|
|
||||||
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.utils.SpotifyNewService
|
import com.shabinder.musicForEveryone.utils.SpotifyNewService
|
||||||
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.AuthenticationClient
|
||||||
import com.spotify.sdk.android.authentication.AuthenticationRequest
|
import com.spotify.sdk.android.authentication.AuthenticationRequest
|
||||||
import com.spotify.sdk.android.authentication.AuthenticationResponse
|
import com.spotify.sdk.android.authentication.AuthenticationResponse
|
||||||
import com.spotify.sdk.android.authentication.LoginActivity
|
import com.spotify.sdk.android.authentication.LoginActivity
|
||||||
|
import com.squareup.moshi.Moshi
|
||||||
|
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||||
import kaaes.spotify.webapi.android.SpotifyApi
|
import kaaes.spotify.webapi.android.SpotifyApi
|
||||||
import kaaes.spotify.webapi.android.SpotifyService
|
import kaaes.spotify.webapi.android.SpotifyService
|
||||||
import retrofit.RestAdapter
|
import kotlinx.coroutines.launch
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.moshi.MoshiConverterFactory
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() ,DownloadHelper{
|
||||||
private lateinit var binding: MainActivityBinding
|
private lateinit var binding: MainActivityBinding
|
||||||
var ytDownloader : YoutubeDownloader? = null
|
var ytDownloader : YoutubeDownloader? = null
|
||||||
|
var spotifyExtra : SpotifyNewService? = null
|
||||||
var downloadManager : DownloadManager? = null
|
var downloadManager : DownloadManager? = null
|
||||||
val REDIRECT_URI = "musicforeveryone://callback"
|
val REDIRECT_URI = "musicforeveryone://callback"
|
||||||
val CLIENT_ID:String = "694d8bf4f6ec420fa66ea7fb4c68f89d"
|
val CLIENT_ID:String = "694d8bf4f6ec420fa66ea7fb4c68f89d"
|
||||||
// val musicDirectory = File(this.filesDir?.absolutePath + "/Music/")
|
|
||||||
var message :String =""
|
|
||||||
var token :String =""
|
var token :String =""
|
||||||
var spotify: SpotifyService? = null
|
var spotify: SpotifyService? = null
|
||||||
lateinit var sharedViewModel: SharedViewModel
|
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 =
|
// val policy =
|
||||||
StrictMode.ThreadPolicy.Builder().permitAll().build()
|
// StrictMode.ThreadPolicy.Builder().permitAll().build()
|
||||||
StrictMode.setThreadPolicy(policy)
|
// StrictMode.setThreadPolicy(policy)
|
||||||
//TODO Use Coroutines
|
//TODO Use Coroutines
|
||||||
if(spotify==null){
|
if(spotify==null){
|
||||||
authenticateSpotify()
|
authenticateSpotify()
|
||||||
@ -59,7 +68,14 @@ class MainActivity : AppCompatActivity() {
|
|||||||
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) {
|
||||||
|
if ("text/plain" == intent.type) {
|
||||||
|
intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
|
||||||
|
Log.i("Intent Received",it)
|
||||||
|
sharedViewModel.intentString = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -85,13 +101,21 @@ class MainActivity : AppCompatActivity() {
|
|||||||
spotify = api.service
|
spotify = api.service
|
||||||
sharedViewModel.spotify = api.service
|
sharedViewModel.spotify = api.service
|
||||||
//Initiate Processes In Main Fragment
|
//Initiate Processes In Main Fragment
|
||||||
val me = spotify?.me?.display_name
|
|
||||||
sharedViewModel.userName.value = me
|
sharedViewModel.uiScope.launch {
|
||||||
Log.i("Network",me!!)
|
val me = spotifyExtra?.getMe()?.display_name
|
||||||
|
sharedViewModel.userName.value = me
|
||||||
|
Log.i("Network",me!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
sharedViewModel.userName.observe(this, Observer {
|
||||||
|
binding.message.text = it
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AuthenticationResponse.Type.ERROR -> {
|
AuthenticationResponse.Type.ERROR -> {
|
||||||
Log.i("Network",response.error.toString())
|
Log.i("Network",response.error.toString())
|
||||||
|
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
}
|
}
|
||||||
@ -103,17 +127,33 @@ class MainActivity : AppCompatActivity() {
|
|||||||
* Adding my own new Spotify Web Api Requests!
|
* Adding my own new Spotify Web Api Requests!
|
||||||
* */
|
* */
|
||||||
private fun implementSpotifyExtra() {
|
private fun implementSpotifyExtra() {
|
||||||
val restAdapter = RestAdapter.Builder()
|
|
||||||
.setEndpoint(SpotifyApi.SPOTIFY_WEB_API_ENDPOINT)
|
val httpClient: OkHttpClient.Builder = OkHttpClient.Builder()
|
||||||
.setRequestInterceptor { request ->
|
|
||||||
request.addHeader(
|
httpClient.addInterceptor(object : Interceptor {
|
||||||
"Authorization",
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
"Bearer $token"
|
val request: Request =
|
||||||
)
|
chain.request().newBuilder().addHeader(
|
||||||
|
"Authorization",
|
||||||
|
"Bearer $token"
|
||||||
|
).build()
|
||||||
|
return chain.proceed(request)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
val moshi = Moshi.Builder()
|
||||||
|
.add(KotlinJsonAdapterFactory())
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val spotifyExtra = restAdapter.create(SpotifyNewService::class.java)
|
val retrofit: Retrofit =
|
||||||
|
Retrofit.Builder()
|
||||||
|
.baseUrl("https://api.spotify.com/v1/")
|
||||||
|
.client(httpClient.build())
|
||||||
|
.addConverterFactory(MoshiConverterFactory.create(moshi))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
spotifyExtra = retrofit.create(SpotifyNewService::class.java)
|
||||||
sharedViewModel.spotifyExtra = spotifyExtra
|
sharedViewModel.spotifyExtra = spotifyExtra
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +169,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun authenticateSpotify() {
|
private fun authenticateSpotify() {
|
||||||
val builder = AuthenticationRequest.Builder(CLIENT_ID,AuthenticationResponse.Type.TOKEN,REDIRECT_URI)
|
val builder = AuthenticationRequest.Builder(CLIENT_ID,AuthenticationResponse.Type.TOKEN,REDIRECT_URI)
|
||||||
.setShowDialog(true)
|
.setShowDialog(false)
|
||||||
.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)
|
||||||
|
@ -9,8 +9,12 @@ import kaaes.spotify.webapi.android.SpotifyService
|
|||||||
import kaaes.spotify.webapi.android.models.Album
|
import kaaes.spotify.webapi.android.models.Album
|
||||||
import kaaes.spotify.webapi.android.models.Playlist
|
import kaaes.spotify.webapi.android.models.Playlist
|
||||||
import kaaes.spotify.webapi.android.models.Track
|
import kaaes.spotify.webapi.android.models.Track
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
|
||||||
class SharedViewModel : ViewModel() {
|
class SharedViewModel : ViewModel() {
|
||||||
|
var intentString = ""
|
||||||
var accessToken:String = ""
|
var accessToken:String = ""
|
||||||
var userName = MutableLiveData<String>().apply { value = "Placeholder" }
|
var userName = MutableLiveData<String>().apply { value = "Placeholder" }
|
||||||
var spotify :SpotifyService? = null
|
var spotify :SpotifyService? = null
|
||||||
@ -18,15 +22,23 @@ class SharedViewModel : ViewModel() {
|
|||||||
var ytDownloader : YoutubeDownloader? = null
|
var ytDownloader : YoutubeDownloader? = null
|
||||||
var downloadManager : DownloadManager? = null
|
var downloadManager : DownloadManager? = null
|
||||||
|
|
||||||
|
var viewModelJob = Job()
|
||||||
|
|
||||||
fun getTrackDetails(trackLink:String): Track?{
|
val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
|
||||||
return spotify?.getTrack(trackLink)
|
|
||||||
|
suspend fun getTrackDetails(trackLink:String): Track?{
|
||||||
|
return spotifyExtra?.getTrack(trackLink)
|
||||||
}
|
}
|
||||||
fun getAlbumDetails(albumLink:String): Album?{
|
suspend fun getAlbumDetails(albumLink:String): Album?{
|
||||||
return spotify?.getAlbum(albumLink)
|
return spotifyExtra?.getAlbum(albumLink)
|
||||||
}
|
}
|
||||||
fun getPlaylistDetails(link:String): Playlist?{
|
suspend fun getPlaylistDetails(link:String): Playlist?{
|
||||||
return spotifyExtra?.getPlaylist(link)
|
return spotifyExtra?.getPlaylist(link)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
super.onCleared()
|
||||||
|
viewModelJob.cancel()
|
||||||
|
}
|
||||||
}
|
}
|
@ -9,51 +9,62 @@ 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.utils.YoutubeInterface
|
import com.shabinder.musicForEveryone.utils.YoutubeInterface
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
interface DownloadHelper {
|
interface DownloadHelper {
|
||||||
fun downloadTrack(ytDownloader: YoutubeDownloader?, downloadManager: DownloadManager?, searchQuery:String){
|
suspend fun downloadTrack(ytDownloader: YoutubeDownloader?, downloadManager: DownloadManager?, searchQuery:String){
|
||||||
//@data = 1st object from YT query.
|
|
||||||
val data = YoutubeInterface.search(searchQuery)?.get(0)
|
|
||||||
if (data==null){Log.i("DownloadHelper","Youtube Request Failed!")}else{
|
|
||||||
|
|
||||||
//Fetching a Video Object.
|
withContext(Dispatchers.IO){
|
||||||
val video = ytDownloader?.getVideo(data.id)
|
val downloadIdList = mutableListOf<Int>()
|
||||||
val details = video?.details()
|
val data = YoutubeInterface.search(searchQuery)?.get(0)
|
||||||
|
if (data==null){Log.i("DownloadHelper","Youtube Request Failed!")}else{
|
||||||
|
|
||||||
val format:Format = video?.findAudioWithQuality(AudioQuality.low)?.get(0) as Format
|
val video = ytDownloader?.getVideo(data.id)
|
||||||
|
//Fetching a Video Object.
|
||||||
|
val details = video?.details()
|
||||||
|
|
||||||
val audioUrl = format.url()
|
val format:Format = video?.findAudioWithQuality(AudioQuality.low)?.get(0) as Format
|
||||||
|
|
||||||
|
val audioUrl = format.url()
|
||||||
|
|
||||||
|
if (audioUrl != null) {
|
||||||
|
downloadFile(audioUrl,downloadManager,details!!.title())
|
||||||
|
Log.i("DHelper Start Download", audioUrl)
|
||||||
|
}else{Log.i("YT audio url is null", format.toString())}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (audioUrl != null) {
|
|
||||||
downloadFile(audioUrl,downloadManager,details?.title()?:"Error")
|
|
||||||
Log.i("DHelper Start Download", audioUrl)
|
|
||||||
}else{Log.i("YT audio url is null", format.toString())}
|
|
||||||
|
|
||||||
// Library Inbuilt function to Save File (Need Scoped Storage Implementation)
|
// Library Inbuilt function to Save File (Need Scoped Storage Implementation)
|
||||||
// val file: File = video.download( format , outputDir)
|
// val file: File = video.download( format , outputDir)
|
||||||
}
|
}
|
||||||
|
//@data = 1st object from YT query.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Downloading Using Android Download Manager
|
* Downloading Using Android Download Manager
|
||||||
* */
|
* */
|
||||||
fun downloadFile(url: String, downloadManager: DownloadManager?,title:String){
|
suspend fun downloadFile(url: String, downloadManager: DownloadManager?,title:String){
|
||||||
val audioUri = Uri.parse(url)
|
withContext(Dispatchers.IO){
|
||||||
val outputDir = File.separator + "Spotify-Downloads" +File.separator + "${removeIllegalChars(title)}.mp3"
|
val audioUri = Uri.parse(url)
|
||||||
|
val outputDir = File.separator + "Spotify-Downloads" +File.separator + "${removeIllegalChars(title)}.mp3"
|
||||||
|
|
||||||
val request = DownloadManager.Request(audioUri)
|
val request = DownloadManager.Request(audioUri)
|
||||||
.setAllowedNetworkTypes(
|
.setAllowedNetworkTypes(
|
||||||
DownloadManager.Request.NETWORK_WIFI or
|
DownloadManager.Request.NETWORK_WIFI or
|
||||||
DownloadManager.Request.NETWORK_MOBILE
|
DownloadManager.Request.NETWORK_MOBILE
|
||||||
)
|
)
|
||||||
.setAllowedOverRoaming(false)
|
.setAllowedOverRoaming(false)
|
||||||
.setTitle(title)
|
.setTitle(title)
|
||||||
.setDescription("Spotify Downloader Working Up here...")
|
.setDescription("Spotify Downloader Working Up here...")
|
||||||
.setDestinationInExternalPublicDir(Environment.DIRECTORY_MUSIC,outputDir)
|
.setDestinationInExternalPublicDir(Environment.DIRECTORY_MUSIC,outputDir)
|
||||||
.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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import com.shabinder.musicForEveryone.recyclerView.TrackListAdapter
|
|||||||
import com.shabinder.musicForEveryone.utils.bindImage
|
import com.shabinder.musicForEveryone.utils.bindImage
|
||||||
import kaaes.spotify.webapi.android.SpotifyService
|
import kaaes.spotify.webapi.android.SpotifyService
|
||||||
import kaaes.spotify.webapi.android.models.Track
|
import kaaes.spotify.webapi.android.models.Track
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
class MainFragment : Fragment(),DownloadHelper {
|
class MainFragment : Fragment(),DownloadHelper {
|
||||||
@ -25,6 +26,7 @@ class MainFragment : Fragment(),DownloadHelper {
|
|||||||
private lateinit var sharedViewModel: SharedViewModel
|
private lateinit var sharedViewModel: SharedViewModel
|
||||||
var spotify : SpotifyService? = null
|
var spotify : SpotifyService? = null
|
||||||
var type:String = ""
|
var type:String = ""
|
||||||
|
var spotifyLink = ""
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
@ -33,13 +35,9 @@ class MainFragment : Fragment(),DownloadHelper {
|
|||||||
|
|
||||||
sharedViewModel = ViewModelProvider(this.requireActivity()).get(SharedViewModel::class.java)
|
sharedViewModel = ViewModelProvider(this.requireActivity()).get(SharedViewModel::class.java)
|
||||||
spotify = sharedViewModel.spotify
|
spotify = sharedViewModel.spotify
|
||||||
sharedViewModel.userName.observe(viewLifecycleOwner, Observer {
|
|
||||||
binding.message.text = it
|
|
||||||
// if(it!="Placeholder"){Snackbar.make(requireView(),"Hello, $it!", Snackbar.LENGTH_SHORT).show()}
|
|
||||||
})
|
|
||||||
|
|
||||||
binding.btnSearch.setOnClickListener {
|
binding.btnSearch.setOnClickListener {
|
||||||
val spotifyLink = binding.spotifyLink.text.toString()
|
spotifyLink = binding.spotifyLink.text.toString()
|
||||||
|
|
||||||
val link = spotifyLink.substringAfterLast('/' , "Error").substringBefore('?')
|
val link = spotifyLink.substringAfterLast('/' , "Error").substringBefore('?')
|
||||||
type = spotifyLink.substringBeforeLast('/' , "Error").substringAfterLast('/')
|
type = spotifyLink.substringBeforeLast('/' , "Error").substringAfterLast('/')
|
||||||
@ -49,60 +47,83 @@ class MainFragment : Fragment(),DownloadHelper {
|
|||||||
val adapter = TrackListAdapter()
|
val adapter = TrackListAdapter()
|
||||||
binding.trackList.adapter = adapter
|
binding.trackList.adapter = adapter
|
||||||
adapter.sharedViewModel = sharedViewModel
|
adapter.sharedViewModel = sharedViewModel
|
||||||
|
|
||||||
when(type){
|
when(type){
|
||||||
"track" -> {
|
"track" -> {
|
||||||
val trackObject = sharedViewModel.getTrackDetails(link)
|
sharedViewModel.uiScope.launch{
|
||||||
|
val trackObject = sharedViewModel.getTrackDetails(link)
|
||||||
|
|
||||||
val trackList = mutableListOf<Track>()
|
binding.imageView.visibility =View.VISIBLE
|
||||||
trackList.add(trackObject!!)
|
|
||||||
adapter.totalItems = 1
|
|
||||||
adapter.trackList = trackList
|
|
||||||
adapter.notifyDataSetChanged()
|
|
||||||
|
|
||||||
Log.i("Adapter",trackList.size.toString())
|
val trackList = mutableListOf<Track>()
|
||||||
|
trackList.add(trackObject!!)
|
||||||
|
bindImage(binding.imageView, trackObject.album.images[0].url)
|
||||||
|
adapter.totalItems = 1
|
||||||
|
adapter.trackList = trackList
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
Log.i("Adapter",trackList.size.toString())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"album" -> {
|
"album" -> {
|
||||||
val albumObject = sharedViewModel.getAlbumDetails(link)
|
sharedViewModel.uiScope.launch{
|
||||||
|
|
||||||
bindImage(binding.imageView,albumObject!!.images[1].url)
|
val albumObject = sharedViewModel.getAlbumDetails(link)
|
||||||
binding.titleView.text = albumObject.name
|
|
||||||
binding.titleView.visibility =View.VISIBLE
|
|
||||||
binding.imageView.visibility =View.VISIBLE
|
|
||||||
|
|
||||||
val trackList = mutableListOf<Track>()
|
binding.titleView.text = albumObject!!.name
|
||||||
albumObject.tracks?.items?.forEach { trackList.add(it as Track) }
|
binding.titleView.visibility =View.VISIBLE
|
||||||
adapter.totalItems = trackList.size
|
binding.imageView.visibility =View.VISIBLE
|
||||||
adapter.trackList = trackList
|
|
||||||
adapter.notifyDataSetChanged()
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
Log.i("Adapter",trackList.size.toString())
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
"playlist" -> {
|
"playlist" -> {
|
||||||
val playlistObject = sharedViewModel.getPlaylistDetails(link)
|
sharedViewModel.uiScope.launch{
|
||||||
|
val playlistObject = sharedViewModel.getPlaylistDetails(link)
|
||||||
|
|
||||||
bindImage(binding.imageView,playlistObject!!.images[0].url)
|
binding.titleView.text = "${if(playlistObject!!.name.length > 18){"${playlistObject.name.subSequence(0,17)}..."}else{playlistObject.name}}"
|
||||||
binding.titleView.text = playlistObject.name
|
binding.titleView.visibility =View.VISIBLE
|
||||||
binding.titleView.visibility =View.VISIBLE
|
binding.imageView.visibility =View.VISIBLE
|
||||||
binding.imageView.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)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
|
|
||||||
"episode" -> {showToast("Implementation Pending")}
|
"episode" -> {showToast("Implementation Pending")}
|
||||||
"show" -> {showToast("Implementation Pending ")}
|
"show" -> {showToast("Implementation Pending ")}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.spotifyLink.setText(link)
|
|
||||||
}
|
}
|
||||||
|
binding.spotifyLink.setText(sharedViewModel.intentString)
|
||||||
|
sharedViewModel.userName.observe(viewLifecycleOwner, Observer {
|
||||||
|
//Waiting for Authentication to Finish with Spotify
|
||||||
|
if (it != "Placeholder"){
|
||||||
|
if(sharedViewModel.intentString != ""){binding.btnSearch.performClick()}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ package com.shabinder.musicForEveryone.recyclerView
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Button
|
import android.widget.ImageButton
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
@ -12,6 +12,7 @@ import com.shabinder.musicForEveryone.SharedViewModel
|
|||||||
import com.shabinder.musicForEveryone.downloadHelper.DownloadHelper
|
import com.shabinder.musicForEveryone.downloadHelper.DownloadHelper
|
||||||
import com.shabinder.musicForEveryone.utils.bindImage
|
import com.shabinder.musicForEveryone.utils.bindImage
|
||||||
import kaaes.spotify.webapi.android.models.Track
|
import kaaes.spotify.webapi.android.models.Track
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class TrackListAdapter:RecyclerView.Adapter<TrackListAdapter.ViewHolder>(),DownloadHelper {
|
class TrackListAdapter:RecyclerView.Adapter<TrackListAdapter.ViewHolder>(),DownloadHelper {
|
||||||
|
|
||||||
@ -30,25 +31,25 @@ 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{
|
||||||
|
bindImage(holder.coverImage,item.album.images[0].url)
|
||||||
|
}
|
||||||
|
|
||||||
bindImage(holder.coverImage,item.album.images[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 > 22){"${item.name.subSequence(0,19)}..."}else{item.name}}"
|
|
||||||
holder.artistName.text = "${item.artists[0]?.name?:""}..."
|
holder.artistName.text = "${item.artists[0]?.name?:""}..."
|
||||||
holder.popularity.text = item.popularity.toString()
|
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} seconds"
|
|
||||||
holder.downloadBtn.setOnClickListener{
|
holder.downloadBtn.setOnClickListener{
|
||||||
downloadTrack(sharedViewModel.ytDownloader,sharedViewModel.downloadManager,"${item.name} ${item.artists[0].name?:""}")
|
sharedViewModel.uiScope.launch {
|
||||||
|
downloadTrack(sharedViewModel.ytDownloader,sharedViewModel.downloadManager,"${item.name} ${item.artists[0].name?:""}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
|
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
|
||||||
val trackName:TextView = itemView.findViewById(R.id.track_name)
|
val trackName:TextView = itemView.findViewById(R.id.track_name)
|
||||||
val artistName:TextView = itemView.findViewById(R.id.artist)
|
val artistName:TextView = itemView.findViewById(R.id.artist)
|
||||||
val popularity:TextView = itemView.findViewById(R.id.popularity)
|
|
||||||
val duration:TextView = itemView.findViewById(R.id.duration)
|
val duration:TextView = itemView.findViewById(R.id.duration)
|
||||||
val downloadBtn:Button = itemView.findViewById(R.id.btn_download)
|
val downloadBtn:ImageButton = itemView.findViewById(R.id.btn_download)
|
||||||
val coverImage:ImageView = itemView.findViewById(R.id.imageUrl)
|
val coverImage:ImageView = itemView.findViewById(R.id.imageUrl)
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@ -10,12 +10,14 @@ import com.shabinder.musicForEveryone.R
|
|||||||
|
|
||||||
@BindingAdapter("imageUrl")
|
@BindingAdapter("imageUrl")
|
||||||
fun bindImage(imgView: ImageView, imgUrl: String?) {
|
fun bindImage(imgView: ImageView, imgUrl: String?) {
|
||||||
imgUrl?.let {
|
|
||||||
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build()
|
imgUrl?.let {
|
||||||
Glide.with(imgView.context)
|
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build()
|
||||||
.load(imgUri)
|
Glide.with(imgView.context)
|
||||||
.apply(RequestOptions()
|
.load(imgUri)
|
||||||
.error(R.drawable.ic_musicplaceholder))
|
.apply(RequestOptions()
|
||||||
.into(imgView)
|
.error(R.drawable.ic_musicplaceholder))
|
||||||
}
|
.into(imgView)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,15 +1,36 @@
|
|||||||
package com.shabinder.musicForEveryone.utils
|
package com.shabinder.musicForEveryone.utils
|
||||||
|
|
||||||
import kaaes.spotify.webapi.android.models.Playlist
|
import kaaes.spotify.webapi.android.models.*
|
||||||
import retrofit.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit.http.Path
|
import retrofit2.http.Path
|
||||||
|
|
||||||
|
|
||||||
interface SpotifyNewService {
|
interface SpotifyNewService {
|
||||||
|
|
||||||
@GET("/playlists/{playlist_id}")
|
@GET("playlists/{playlist_id}")
|
||||||
fun getPlaylist(@Path("playlist_id") playlistId: String?): Playlist?
|
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)
|
@ -7,13 +7,32 @@
|
|||||||
android:id="@+id/mainActivity"
|
android:id="@+id/mainActivity"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/message"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="2dp"
|
||||||
|
android:background="@drawable/text_background"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:text="MainFragment"
|
||||||
|
android:textColor="@color/colorPrimary"
|
||||||
|
android:textSize="12dp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/NavHostFragment"
|
android:id="@+id/NavHostFragment"
|
||||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
app:defaultNavHost="true"
|
app:defaultNavHost="true"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/message"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:navGraph="@navigation/navigation"
|
app:navGraph="@navigation/navigation"
|
||||||
tools:ignore="FragmentTagUsage" />
|
tools:ignore="FragmentTagUsage" />
|
||||||
|
|
||||||
|
@ -1,105 +1,128 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<layout
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:id="@+id/main"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="25dp"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
tools:context=".fragments.MainFragment">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:id="@+id/appbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="230dp">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:contentScrim="?attr/colorPrimary"
|
||||||
|
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
|
||||||
|
app:layout_scrollInterpolator="@android:anim/decelerate_interpolator"
|
||||||
|
app:toolbarId="@+id/toolbar">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/spotifyLink"
|
||||||
|
android:layout_width="257dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:background="@drawable/text_background"
|
||||||
|
android:ems="10"
|
||||||
|
android:hint="Link From Spotify"
|
||||||
|
android:inputType="text"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textColorHint="@color/grey"
|
||||||
|
android:textSize="19sp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_search"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:backgroundTint="@color/colorPrimary"
|
||||||
|
android:text="Search"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/image_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:contentDescription="Album Cover"
|
||||||
|
android:scaleType="centerInside"
|
||||||
|
android:src="@drawable/ic_launcher_foreground"
|
||||||
|
app:layout_collapseMode="parallax"/>
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/main"
|
android:id="@+id/constraint_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".fragments.MainFragment">
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/message"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:text="MainFragment"
|
|
||||||
android:background="@drawable/text_backdround"
|
|
||||||
android:padding="5dp"
|
|
||||||
android:textColor="@color/colorPrimary"
|
|
||||||
android:textSize="12dp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/spotifyLink"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="25dp"
|
|
||||||
android:background="@drawable/text_backdround"
|
|
||||||
android:hint="Link From Spotify"
|
|
||||||
android:ems="10"
|
|
||||||
android:padding="5dp"
|
|
||||||
android:inputType="text"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textColorHint="@color/grey"
|
|
||||||
android:textSize="20dp"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/btn_search"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/btn_search"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
|
||||||
android:backgroundTint="@color/colorPrimary"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Search"
|
|
||||||
android:textSize="18sp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/spotifyLink"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/spotifyLink"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/spotifyLink" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/track_list"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_marginTop="2dp"
|
|
||||||
android:layout_marginBottom="3dp"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/message"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/title_view"
|
|
||||||
app:layout_constraintVertical_bias="0.0" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/image_view"
|
|
||||||
android:layout_width="150dp"
|
|
||||||
android:layout_height="150dp"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/spotifyLink"
|
|
||||||
android:visibility="gone"/>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/title_view"
|
android:id="@+id/title_view"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginBottom="5dp"
|
android:text="Shabinder's Playlist"
|
||||||
android:text="TextView"
|
android:textAlignment="center"
|
||||||
android:background="@drawable/text_backdround"
|
|
||||||
android:drawableTint="@color/colorPrimary"
|
|
||||||
android:paddingLeft="6dp"
|
|
||||||
android:paddingRight="6dp"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppTheme.Headline4"
|
|
||||||
android:textAllCaps="false"
|
|
||||||
android:textColor="@color/colorPrimary"
|
android:textColor="@color/colorPrimary"
|
||||||
android:textSize="24sp"
|
android:textSize="26sp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:textStyle="bold"
|
app:layout_constraintBottom_toTopOf="@+id/track_list"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/playlist_owner"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/playlist_owner"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/text_background_accented"
|
||||||
|
android:paddingLeft="8dp"
|
||||||
|
android:paddingRight="8dp"
|
||||||
|
android:text="by : Shabinder"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/title_view"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/title_view" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/track_list"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/image_view" />
|
app:layout_constraintTop_toBottomOf="@+id/title_view" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
</layout>
|
</layout>
|
||||||
|
@ -6,130 +6,80 @@
|
|||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="80dp"
|
||||||
android:background="#000000"
|
android:background="#000000"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
>
|
>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/imageUrl"
|
android:id="@+id/imageUrl"
|
||||||
android:layout_width="100dp"
|
android:layout_width="100dp"
|
||||||
android:layout_height="100dp"
|
android:layout_height="80dp"
|
||||||
android:contentDescription="Track Image"
|
android:contentDescription="Track Image"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/artist"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:srcCompat="@drawable/ic_musicplaceholder"
|
app:srcCompat="@drawable/ic_musicplaceholder"
|
||||||
tools:tint="#A3FFFFFF"/>
|
tools:tint="#A3FFFFFF" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/track_name"
|
android:id="@+id/track_name"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
android:fontFamily="monospace"
|
android:fontFamily="monospace"
|
||||||
android:text="TextView"
|
android:letterSpacing="-0.03"
|
||||||
|
android:lines="1"
|
||||||
|
android:text="The Spectre"
|
||||||
android:textAllCaps="false"
|
android:textAllCaps="false"
|
||||||
android:textAppearance="@style/TextAppearance.AppTheme.Headline4"
|
android:textAppearance="@style/TextAppearance.AppTheme.Headline4"
|
||||||
android:textColor="@color/colorPrimary"
|
android:textColor="@color/colorPrimary"
|
||||||
android:textSize="20sp"
|
android:textSize="18sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toStartOf="@+id/btn_download"
|
||||||
app:layout_constraintStart_toEndOf="@+id/imageUrl"
|
app:layout_constraintStart_toStartOf="@+id/artist"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textView1"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
android:paddingLeft="9dp"
|
|
||||||
android:text="Artist"
|
|
||||||
android:textSize="12dp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/textview3"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/artist"
|
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/imageUrl"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/track_name" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/artist"
|
android:id="@+id/artist"
|
||||||
style="@style/TextAppearance.AppCompat.Body2"
|
style="@style/TextAppearance.AppCompat.Body2"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
android:paddingLeft="9dp"
|
android:paddingLeft="9dp"
|
||||||
android:text="TextView"
|
android:text="Alan Walker"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/textView1"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/textView1"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/textView1" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textview3"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingLeft="9dp"
|
|
||||||
android:text="Popularity"
|
|
||||||
android:textSize="12dp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/textView5"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/popularity"
|
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/imageUrl"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/textView1" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/popularity"
|
|
||||||
style="@style/TextAppearance.AppCompat.Body2"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingLeft="9dp"
|
|
||||||
android:text="TextView"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/textview3"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/textview3"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/textview3" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textView5"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="4dp"
|
|
||||||
android:paddingLeft="9dp"
|
|
||||||
android:text="Duration"
|
|
||||||
android:textSize="12dp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/btn_download"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/duration"
|
app:layout_constraintEnd_toStartOf="@+id/duration"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/imageUrl"
|
app:layout_constraintStart_toEndOf="@+id/imageUrl"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/textview3" />
|
app:layout_constraintTop_toBottomOf="@+id/track_name" />
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/duration"
|
android:id="@+id/duration"
|
||||||
style="@style/TextAppearance.AppCompat.Body2"
|
style="@style/TextAppearance.AppCompat.Body2"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingLeft="9dp"
|
android:paddingLeft="9dp"
|
||||||
android:text="TextView"
|
android:text="4 minutes, 20 sec"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/textView5"
|
app:layout_constraintBottom_toBottomOf="@+id/artist"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toStartOf="@+id/btn_download"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintStart_toEndOf="@+id/artist"
|
||||||
app:layout_constraintStart_toEndOf="@+id/textView5"
|
app:layout_constraintTop_toTopOf="@+id/artist" />
|
||||||
app:layout_constraintTop_toTopOf="@+id/textView5" />
|
|
||||||
|
|
||||||
<Button
|
<ImageButton
|
||||||
android:id="@+id/btn_download"
|
android:id="@+id/btn_download"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
android:layout_width="60dp"
|
||||||
android:layout_width="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:backgroundTint="@color/black"
|
||||||
android:backgroundTint="#27FF3D"
|
android:scaleType="fitCenter"
|
||||||
android:text="Download"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
android:textSize="14sp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="1.0"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:srcCompat="@drawable/ic_arrow" />
|
||||||
app:layout_constraintTop_toBottomOf="@+id/imageUrl" />
|
|
||||||
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
Loading…
Reference in New Issue
Block a user