mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-24 18:04:33 +01:00
Repo refreshed and cleaned,Basic YT Functionality Added(TODO Coroutines!)
This commit is contained in:
parent
3cb3162beb
commit
8fcb22ab5d
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" 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" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
@ -30,6 +30,13 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@ -51,6 +58,8 @@ dependencies {
|
||||
implementation "androidx.room:room-runtime:2.2.5"
|
||||
kapt "androidx.room:room-compiler:2.2.5"
|
||||
implementation "androidx.room:room-ktx:2.2.5"
|
||||
implementation "com.github.bumptech.glide:glide:4.11.0"
|
||||
kapt "com.github.bumptech.glide:compiler:4.11.0"
|
||||
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
|
||||
@ -62,6 +71,8 @@ dependencies {
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.8.0'
|
||||
|
||||
implementation 'com.github.sealedtx:java-youtube-downloader:2.2.1'
|
||||
|
||||
implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
|
||||
testImplementation 'junit:junit:4.13'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
|
@ -3,6 +3,7 @@
|
||||
package="com.shabinder.musicForEveryone">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
|
@ -0,0 +1,20 @@
|
||||
package com.shabinder.musicForEveryone
|
||||
|
||||
import android.widget.ImageView
|
||||
import androidx.core.net.toUri
|
||||
import androidx.databinding.BindingAdapter
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
|
||||
|
||||
@BindingAdapter("imageUrl")
|
||||
fun bindImage(imgView: ImageView, imgUrl: String?) {
|
||||
imgUrl?.let {
|
||||
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build()
|
||||
Glide.with(imgView.context)
|
||||
.load(imgUri)
|
||||
.apply(RequestOptions()
|
||||
.error(R.drawable.ic_musicplaceholder))
|
||||
.into(imgView)
|
||||
}
|
||||
}
|
@ -9,29 +9,33 @@ import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.github.kiulian.downloader.YoutubeDownloader
|
||||
import com.shabinder.musicForEveryone.databinding.MainActivityBinding
|
||||
import com.shabinder.musicForEveryone.utils.YoutubeConnector
|
||||
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 kaaes.spotify.webapi.android.SpotifyApi
|
||||
import kaaes.spotify.webapi.android.SpotifyService
|
||||
import retrofit.RestAdapter
|
||||
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private lateinit var binding: MainActivityBinding
|
||||
var ytDownloader : YoutubeDownloader? = null
|
||||
val REDIRECT_URI = "musicforeveryone://callback"
|
||||
val CLIENT_ID:String = "694d8bf4f6ec420fa66ea7fb4c68f89d"
|
||||
// val musicDirectory = File(this.filesDir?.absolutePath + "/Music/")
|
||||
var message :String =""
|
||||
var token :String =""
|
||||
var spotify: SpotifyService? = null
|
||||
lateinit var mainViewModel: MainViewModel
|
||||
lateinit var sharedViewModel: SharedViewModel
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = DataBindingUtil.setContentView(this,R.layout.main_activity)
|
||||
|
||||
mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
|
||||
sharedViewModel = ViewModelProvider(this).get(SharedViewModel::class.java)
|
||||
val policy =
|
||||
StrictMode.ThreadPolicy.Builder().permitAll().build()
|
||||
StrictMode.setThreadPolicy(policy)
|
||||
@ -41,15 +45,16 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
requestPermission()
|
||||
|
||||
//Object to download From Youtube {"https://github.com/sealedtx/java-youtube-downloader"}
|
||||
ytDownloader = YoutubeDownloader()
|
||||
sharedViewModel.ytDownloader = ytDownloader
|
||||
//Initialing Communication with Youtube
|
||||
YoutubeConnector.youtubeConnector()
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fun authenticateSpotify() {
|
||||
val builder = AuthenticationRequest.Builder(CLIENT_ID,AuthenticationResponse.Type.TOKEN,REDIRECT_URI)
|
||||
.setShowDialog(true)
|
||||
.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()
|
||||
AuthenticationClient.openLoginActivity(this, LoginActivity.REQUEST_CODE, request)
|
||||
}
|
||||
|
||||
override fun onActivityResult(
|
||||
requestCode: Int,
|
||||
@ -64,18 +69,18 @@ class MainActivity : AppCompatActivity() {
|
||||
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
|
||||
mainViewModel.spotify = api.service
|
||||
sharedViewModel.spotify = api.service
|
||||
//Initiate Processes In Main Fragment
|
||||
val me = spotify?.me?.display_name
|
||||
mainViewModel.userName.value = me
|
||||
sharedViewModel.userName.value = me
|
||||
Log.i("Network",me!!)
|
||||
|
||||
|
||||
}
|
||||
AuthenticationResponse.Type.ERROR -> {
|
||||
Log.i("Network",response.error.toString())
|
||||
@ -87,6 +92,25 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding my own new Spotify Web Api Requests!
|
||||
* */
|
||||
private fun implementSpotifyExtra() {
|
||||
val restAdapter = RestAdapter.Builder()
|
||||
.setEndpoint(SpotifyApi.SPOTIFY_WEB_API_ENDPOINT)
|
||||
.setRequestInterceptor { request ->
|
||||
request.addHeader(
|
||||
"Authorization",
|
||||
"Bearer $token"
|
||||
)
|
||||
}
|
||||
.build()
|
||||
|
||||
val spotifyExtra = restAdapter.create(SpotifyNewService::class.java)
|
||||
sharedViewModel.spotifyExtra = spotifyExtra
|
||||
}
|
||||
|
||||
|
||||
private fun requestPermission() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
requestPermissions(
|
||||
@ -96,5 +120,13 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun authenticateSpotify() {
|
||||
val builder = AuthenticationRequest.Builder(CLIENT_ID,AuthenticationResponse.Type.TOKEN,REDIRECT_URI)
|
||||
.setShowDialog(true)
|
||||
.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()
|
||||
AuthenticationClient.openLoginActivity(this, LoginActivity.REQUEST_CODE, request)
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package com.shabinder.musicForEveryone
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import kaaes.spotify.webapi.android.SpotifyService
|
||||
|
||||
class MainViewModel : ViewModel() {
|
||||
|
||||
var apiCame = MutableLiveData<Int>().apply { value = 0 }
|
||||
var userName = MutableLiveData<String>().apply { value = "Placeholder" }
|
||||
|
||||
|
||||
var spotify :SpotifyService? = null
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.shabinder.musicForEveryone
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.github.kiulian.downloader.YoutubeDownloader
|
||||
import kaaes.spotify.webapi.android.SpotifyService
|
||||
import kaaes.spotify.webapi.android.models.Album
|
||||
import kaaes.spotify.webapi.android.models.Playlist
|
||||
import kaaes.spotify.webapi.android.models.Track
|
||||
|
||||
class SharedViewModel : ViewModel() {
|
||||
var accessToken:String = ""
|
||||
var userName = MutableLiveData<String>().apply { value = "Placeholder" }
|
||||
var spotify :SpotifyService? = null
|
||||
var spotifyExtra :SpotifyNewService? = null
|
||||
var ytDownloader : YoutubeDownloader? = null
|
||||
|
||||
fun getTrackDetails(trackLink:String): Track?{
|
||||
return spotify?.getTrack(trackLink)
|
||||
}
|
||||
fun getAlbumDetails(albumLink:String): Album?{
|
||||
return spotify?.getAlbum(albumLink)
|
||||
}
|
||||
fun getPlaylistDetails(link:String): Playlist?{
|
||||
return spotifyExtra?.getPlaylist(link)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.shabinder.musicForEveryone
|
||||
|
||||
import kaaes.spotify.webapi.android.models.Playlist
|
||||
import retrofit.http.GET
|
||||
import retrofit.http.Path
|
||||
|
||||
|
||||
interface SpotifyNewService {
|
||||
|
||||
@GET("/playlists/{playlist_id}")
|
||||
fun getPlaylist(@Path("playlist_id") playlistId: String?): Playlist?
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,21 +1,27 @@
|
||||
package com.shabinder.musicForEveryone.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.shabinder.musicForEveryone.MainViewModel
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.shabinder.musicForEveryone.R
|
||||
import com.shabinder.musicForEveryone.SharedViewModel
|
||||
import com.shabinder.musicForEveryone.bindImage
|
||||
import com.shabinder.musicForEveryone.databinding.MainFragmentBinding
|
||||
import com.shabinder.musicForEveryone.utils.YoutubeConnector
|
||||
import kaaes.spotify.webapi.android.SpotifyService
|
||||
|
||||
|
||||
class MainFragment : Fragment() {
|
||||
lateinit var binding:MainFragmentBinding
|
||||
private lateinit var mainViewModel: MainViewModel
|
||||
private lateinit var sharedViewModel: SharedViewModel
|
||||
var spotify : SpotifyService? = null
|
||||
|
||||
override fun onCreateView(
|
||||
@ -23,17 +29,89 @@ class MainFragment : Fragment() {
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
binding = DataBindingUtil.inflate(inflater,R.layout.main_fragment,container,false)
|
||||
|
||||
sharedViewModel = ViewModelProvider(this.requireActivity()).get(SharedViewModel::class.java)
|
||||
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.btnGetDetails.setOnClickListener {
|
||||
val spotifyLink = binding.spotifyLink.text.toString()
|
||||
|
||||
val link = spotifyLink.substringAfterLast('/' , "Error").substringBefore('?')
|
||||
val type = spotifyLink.substringBeforeLast('/' , "Error").substringAfterLast('/')
|
||||
|
||||
Log.i("Fragment",link)
|
||||
|
||||
when(type){
|
||||
"track" -> {
|
||||
val trackObject = sharedViewModel.getTrackDetails(link)
|
||||
Log.i("Fragment",trackObject?.name.toString())
|
||||
binding.name.text = trackObject?.name ?: "Error"
|
||||
var artistNames = ""
|
||||
trackObject?.artists?.forEach { artistNames = artistNames.plus("${it.name} ,") }
|
||||
binding.artist.text = artistNames
|
||||
binding.popularity.text = trackObject?.popularity.toString()
|
||||
binding.duration.text = ((trackObject?.duration_ms!! /1000/60).toString() + "minutes")
|
||||
binding.albumName.text = trackObject.album.name
|
||||
bindImage(binding.imageUrl, trackObject.album.images[0].url)
|
||||
}
|
||||
|
||||
"album" -> {
|
||||
val albumObject = sharedViewModel.getAlbumDetails(link)
|
||||
Log.i("Fragment",albumObject?.name.toString())
|
||||
binding.name.text = albumObject?.name ?: "Error"
|
||||
var artistNames = ""
|
||||
albumObject?.artists?.forEach { artistNames = artistNames.plus(", ${it.name}") }
|
||||
binding.artist.text = artistNames
|
||||
binding.popularity.text = albumObject?.popularity.toString()
|
||||
binding.duration.visibility = View.GONE
|
||||
binding.textView5.visibility = View.GONE
|
||||
binding.albumName.text = albumObject?.name
|
||||
bindImage(binding.imageUrl, albumObject?.images?.get(0)?.url)
|
||||
}
|
||||
|
||||
"playlist" -> {
|
||||
val playlistObject = sharedViewModel.getPlaylistDetails(link)
|
||||
Log.i("Fragment",playlistObject?.name.toString())
|
||||
binding.name.text = playlistObject?.name ?: "Error"
|
||||
binding.artist.visibility = View.GONE
|
||||
binding.textView1.visibility = View.GONE
|
||||
binding.popularity.text = playlistObject?.followers?.total.toString()
|
||||
binding.textview3.text = "Followers"
|
||||
binding.duration.visibility = View.GONE
|
||||
binding.textView5.visibility = View.GONE
|
||||
binding.textView7.text = "Total Tracks"
|
||||
binding.albumName.text = playlistObject?.tracks?.items?.size.toString()
|
||||
bindImage(binding.imageUrl, playlistObject?.images?.get(0)?.url)
|
||||
}
|
||||
|
||||
"episode" -> {showToast("Implementation Pending")}
|
||||
"show" -> {showToast("Implementation Pending ")}
|
||||
}
|
||||
|
||||
binding.spotifyLink.setText(link)
|
||||
}
|
||||
|
||||
binding.btnDownload.setOnClickListener {
|
||||
val data = YoutubeConnector.search(
|
||||
"${binding.name.text} ${if(binding.artist.text != "TextView" ){binding.artist.text}else{""}}")
|
||||
?.get(0)
|
||||
if (data==null){showToast("Youtube Request Failed!")}else{
|
||||
val ytDownloader = sharedViewModel.ytDownloader
|
||||
val video = ytDownloader?.getVideo(data.id)
|
||||
val details = video?.details()
|
||||
Log.i("ytDownloader", details?.title()?:"Error")
|
||||
binding.name.text = details?.title()
|
||||
}
|
||||
}
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
mainViewModel = ViewModelProvider(this.requireActivity()).get(MainViewModel::class.java)
|
||||
spotify = mainViewModel.spotify
|
||||
mainViewModel.userName.observeForever {
|
||||
binding.message.text = it
|
||||
}
|
||||
|
||||
private fun showToast(message:String){
|
||||
Toast.makeText(context,message,Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.shabinder.musicForEveryone.utils
|
||||
|
||||
import android.util.Log
|
||||
import com.google.api.client.http.HttpRequestInitializer
|
||||
import com.google.api.client.http.javanet.NetHttpTransport
|
||||
import com.google.api.client.json.jackson2.JacksonFactory
|
||||
import com.google.api.services.youtube.YouTube
|
||||
import java.io.IOException
|
||||
|
||||
object YoutubeConnector {
|
||||
private var youtube: YouTube? = null
|
||||
private var query:YouTube.Search.List? = null
|
||||
var apiKey:String = "AIzaSyDuRmMA_2mF56BjlhhNpa0SIbjMgjjFaEI"
|
||||
var clientID : String = "1040727735015-er2mvvljt45cabkuqimsh3iabqvfpvms.apps.googleusercontent.com"
|
||||
|
||||
fun youtubeConnector() {
|
||||
youtube =
|
||||
YouTube.Builder(NetHttpTransport(), JacksonFactory(),
|
||||
HttpRequestInitializer { })
|
||||
.setApplicationName("Music For Everyone").build()
|
||||
try {
|
||||
query = youtube?.search()?.list("id,snippet")
|
||||
query?.key = apiKey
|
||||
query?.maxResults = 1
|
||||
query?.type = "video"
|
||||
query?.fields =
|
||||
"items(id/kind,id/videoId,snippet/title,snippet/description,snippet/thumbnails/default/url)"
|
||||
} catch (e: IOException) {
|
||||
Log.i("YC", "Could not initialize: $e")
|
||||
}
|
||||
}
|
||||
|
||||
fun search(keywords: String?): List<VideoItem>? {
|
||||
Log.i("YC searched for",keywords.toString())
|
||||
if (youtube == null){youtubeConnector()}
|
||||
query!!.q= keywords
|
||||
return try {
|
||||
val response = query!!.execute()
|
||||
val results =
|
||||
response.items
|
||||
val items = mutableListOf<VideoItem>()
|
||||
for (result in results) {
|
||||
val item = VideoItem(
|
||||
id = result.id.videoId,
|
||||
title = result.snippet.title,
|
||||
description = result.snippet.description,
|
||||
thumbnailUrl = result.snippet.thumbnails.default.url
|
||||
)
|
||||
items.add(item)
|
||||
Log.i("YC links received",item.id)
|
||||
}
|
||||
items
|
||||
} catch (e: IOException) {
|
||||
Log.d("YC", "Could not search: $e")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
data class VideoItem(
|
||||
val id:String,
|
||||
val title:String,
|
||||
val description: String,
|
||||
val thumbnailUrl:String
|
||||
)
|
||||
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
@ -13,11 +14,156 @@
|
||||
android:id="@+id/message"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="MainFragment"
|
||||
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="24dp"
|
||||
android:ems="10"
|
||||
android:inputType="text"
|
||||
android:text="Song Link From Spotify"
|
||||
app:layout_constraintEnd_toStartOf="@+id/btn_getDetails"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<Button
|
||||
android:id="@+id/btn_getDetails"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Get Details"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/spotifyLink"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/spotifyLink"
|
||||
app:layout_constraintTop_toTopOf="@+id/spotifyLink" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageUrl"
|
||||
android:layout_width="180dp"
|
||||
android:layout_height="200dp"
|
||||
android:layout_marginTop="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/spotifyLink"
|
||||
tools:srcCompat="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:fontFamily="monospace"
|
||||
android:text="TextView"
|
||||
android:textAllCaps="false"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/imageUrl" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Artist
|
||||
"
|
||||
app:layout_constraintBottom_toTopOf="@+id/textview3"
|
||||
app:layout_constraintEnd_toStartOf="@+id/artist"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/btn_download" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/artist"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="TextView"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/textView1"
|
||||
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="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Popularity"
|
||||
app:layout_constraintBottom_toTopOf="@+id/textView5"
|
||||
app:layout_constraintEnd_toStartOf="@+id/popularity"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textView1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/popularity"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
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="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Duration"
|
||||
app:layout_constraintBottom_toTopOf="@+id/textView7"
|
||||
app:layout_constraintEnd_toStartOf="@+id/duration"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textview3" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/duration"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="TextView"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/textView5"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/textView5"
|
||||
app:layout_constraintTop_toTopOf="@+id/textView5" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView7"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Album Name"
|
||||
app:layout_constraintBottom_toTopOf="@+id/message"
|
||||
app:layout_constraintEnd_toStartOf="@+id/albumName"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textView5" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/albumName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="TextView"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/textView7"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/textView7"
|
||||
app:layout_constraintTop_toTopOf="@+id/textView7" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_download"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Download"
|
||||
app:layout_constraintEnd_toEndOf="@+id/name"
|
||||
app:layout_constraintStart_toStartOf="@+id/name"
|
||||
app:layout_constraintTop_toBottomOf="@+id/name" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
|
36
build.gradle
Normal file
36
build.gradle
Normal file
@ -0,0 +1,36 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
ext{
|
||||
kotlin_version = "1.3.72"
|
||||
navigationVersion = '2.3.0'
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
}
|
||||
dependencies {
|
||||
classpath "com.android.tools.build:gradle:4.0.0"
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
//safe-Args
|
||||
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven { url "https://jitpack.io" }
|
||||
flatDir {
|
||||
dirs 'libs'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
21
gradle.properties
Normal file
21
gradle.properties
Normal file
@ -0,0 +1,21 @@
|
||||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app"s APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableJetifier=true
|
||||
# Kotlin code style for this project: "official" or "obsolete":
|
||||
kotlin.code.style=official
|
2
settings.gradle
Normal file
2
settings.gradle
Normal file
@ -0,0 +1,2 @@
|
||||
include ':app'
|
||||
rootProject.name = "musicForEveryone"
|
Loading…
Reference in New Issue
Block a user