mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-25 02:14:32 +01:00
Added Gradients in App Ui & Added Download All Tracks Functionality
This commit is contained in:
parent
735f7c270e
commit
0ce929df9b
@ -36,6 +36,10 @@
|
||||
android:name="com.spotify.sdk.android.authentication.LoginActivity"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
|
||||
|
||||
<meta-data
|
||||
android:name="preloaded_fonts"
|
||||
android:resource="@array/preloaded_fonts" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -104,8 +104,8 @@ class MainActivity : AppCompatActivity() ,DownloadHelper{
|
||||
|
||||
sharedViewModel.uiScope.launch {
|
||||
val me = spotifyExtra?.getMe()?.display_name
|
||||
sharedViewModel.userName.value = me
|
||||
Log.i("Network",me!!)
|
||||
sharedViewModel.userName.value = "Logged in as: $me"
|
||||
Log.i("Network","Hello, " + me!!)
|
||||
}
|
||||
|
||||
sharedViewModel.userName.observe(this, Observer {
|
||||
|
@ -14,43 +14,49 @@ import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
|
||||
interface DownloadHelper {
|
||||
suspend fun downloadTrack(ytDownloader: YoutubeDownloader?, downloadManager: DownloadManager?, searchQuery:String){
|
||||
suspend fun downloadTrack(
|
||||
ytDownloader: YoutubeDownloader?,
|
||||
downloadManager: DownloadManager?,
|
||||
searchQuery: String
|
||||
) {
|
||||
|
||||
withContext(Dispatchers.IO){
|
||||
val downloadIdList = mutableListOf<Int>()
|
||||
withContext(Dispatchers.IO) {
|
||||
val data = YoutubeInterface.search(searchQuery)?.get(0)
|
||||
if (data==null){Log.i("DownloadHelper","Youtube Request Failed!")}else{
|
||||
if (data == null) {
|
||||
Log.i("DownloadHelper", "Youtube Request Failed!")
|
||||
} else {
|
||||
|
||||
val video = ytDownloader?.getVideo(data.id)
|
||||
//Fetching a Video Object.
|
||||
val details = video?.details()
|
||||
|
||||
val format:Format = video?.findAudioWithQuality(AudioQuality.low)?.get(0) as Format
|
||||
|
||||
try{
|
||||
val format: Format =
|
||||
video?.findAudioWithQuality(AudioQuality.medium)?.get(0) as Format
|
||||
val audioUrl = format.url()
|
||||
|
||||
Log.i("DHelper Link Found", audioUrl)
|
||||
if (audioUrl != null) {
|
||||
downloadFile(audioUrl,downloadManager,details!!.title())
|
||||
Log.i("DHelper Start Download", audioUrl)
|
||||
}else{Log.i("YT audio url is null", format.toString())}
|
||||
|
||||
downloadFile(audioUrl, downloadManager, details!!.title())
|
||||
} else {
|
||||
Log.i("YT audio url is null", format.toString())
|
||||
}
|
||||
}catch (e:ArrayIndexOutOfBoundsException){
|
||||
Log.i("Catch",e.toString())
|
||||
}
|
||||
|
||||
|
||||
// Library Inbuilt function to Save File (Need Scoped Storage Implementation)
|
||||
// val file: File = video.download( format , outputDir)
|
||||
}
|
||||
//@data = 1st object from YT query.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Downloading Using Android Download Manager
|
||||
* */
|
||||
suspend fun downloadFile(url: String, downloadManager: DownloadManager?,title:String){
|
||||
withContext(Dispatchers.IO){
|
||||
suspend fun downloadFile(url: String, downloadManager: DownloadManager?, title: String) {
|
||||
withContext(Dispatchers.IO) {
|
||||
val audioUri = Uri.parse(url)
|
||||
val outputDir = File.separator + "Spotify-Downloads" +File.separator + "${removeIllegalChars(title)}.mp3"
|
||||
val outputDir =
|
||||
File.separator + "Spotify-Downloads" + File.separator + "${removeIllegalChars(title)}.mp3"
|
||||
|
||||
val request = DownloadManager.Request(audioUri)
|
||||
.setAllowedNetworkTypes(
|
||||
@ -60,10 +66,10 @@ interface DownloadHelper {
|
||||
.setAllowedOverRoaming(false)
|
||||
.setTitle(title)
|
||||
.setDescription("Spotify Downloader Working Up here...")
|
||||
.setDestinationInExternalPublicDir(Environment.DIRECTORY_MUSIC,outputDir)
|
||||
.setDestinationInExternalPublicDir(Environment.DIRECTORY_MUSIC, outputDir)
|
||||
.setNotificationVisibility(VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
|
||||
downloadManager?.enqueue(request)
|
||||
Log.i("DownloadManager","Download Request Sent")
|
||||
Log.i("DownloadManager", "Download Request Sent")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,7 @@ class MainFragment : Fragment(),DownloadHelper {
|
||||
adapter.trackList = trackList
|
||||
adapter.notifyDataSetChanged()
|
||||
Log.i("Adapter",trackList.size.toString())
|
||||
binding.btnDownloadAll.setOnClickListener { downloadAllTracks(trackList) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,13 +69,12 @@ class MainFragment : Fragment(),DownloadHelper {
|
||||
sharedViewModel.uiScope.launch{
|
||||
|
||||
val albumObject = sharedViewModel.getAlbumDetails(link)
|
||||
|
||||
binding.titleView.text = albumObject!!.name
|
||||
binding.titleView.visibility =View.VISIBLE
|
||||
// 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) }
|
||||
albumObject!!.tracks?.items?.forEach { trackList.add(it as Track) }
|
||||
adapter.totalItems = trackList.size
|
||||
adapter.trackList = trackList
|
||||
adapter.notifyDataSetChanged()
|
||||
@ -82,6 +82,8 @@ class MainFragment : Fragment(),DownloadHelper {
|
||||
Log.i("Adapter",trackList.size.toString())
|
||||
|
||||
bindImage(binding.imageView, albumObject.images[0].url)
|
||||
binding.btnDownloadAll.setOnClickListener { downloadAllTracks(trackList) }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -90,23 +92,26 @@ class MainFragment : Fragment(),DownloadHelper {
|
||||
"playlist" -> {
|
||||
sharedViewModel.uiScope.launch{
|
||||
val playlistObject = sharedViewModel.getPlaylistDetails(link)
|
||||
binding.btnDownloadAll.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.imageView.visibility =View.VISIBLE
|
||||
binding.playlistOwner.visibility =View.VISIBLE
|
||||
binding.playlistOwner.text = "by: ${playlistObject.owner.display_name}"
|
||||
// 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) }
|
||||
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) }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -127,6 +132,12 @@ class MainFragment : Fragment(),DownloadHelper {
|
||||
return binding.root
|
||||
}
|
||||
|
||||
private fun downloadAllTracks(trackList : List<Track>) {
|
||||
sharedViewModel.uiScope.launch {
|
||||
trackList.forEach { downloadTrack(sharedViewModel.ytDownloader,sharedViewModel.downloadManager,"${it.name} ${it.artists[0].name?:""}") }
|
||||
}
|
||||
}
|
||||
|
||||
private fun showToast(message:String){
|
||||
Toast.makeText(context,message,Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ object YoutubeInterface {
|
||||
private var youtube: YouTube? = null
|
||||
private var query:YouTube.Search.List? = null
|
||||
var apiKey:String = "AIzaSyDuRmMA_2mF56BjlhhNpa0SIbjMgjjFaEI"
|
||||
var apiKey2:String = "AIzaSyCotyqgqmz5qw4-IH0tiezIrIIDHLI2yNs"
|
||||
|
||||
var clientID : String = "1040727735015-er2mvvljt45cabkuqimsh3iabqvfpvms.apps.googleusercontent.com"
|
||||
|
||||
fun youtubeConnector() {
|
||||
@ -23,14 +25,14 @@ object YoutubeInterface {
|
||||
query?.maxResults = 1
|
||||
query?.type = "video"
|
||||
query?.fields =
|
||||
"items(id/kind,id/videoId,snippet/title,snippet/description,snippet/thumbnails/default/url)"
|
||||
"items(id/videoId,snippet/title,snippet/thumbnails/default/url)"
|
||||
} catch (e: IOException) {
|
||||
Log.i("YC", "Could not initialize: $e")
|
||||
Log.i("YI", "Could not initialize: $e")
|
||||
}
|
||||
}
|
||||
|
||||
fun search(keywords: String?): List<VideoItem>? {
|
||||
Log.i("YC searched for",keywords.toString())
|
||||
Log.i("YI searched for",keywords.toString())
|
||||
if (youtube == null){youtubeConnector()}
|
||||
query!!.q= keywords
|
||||
return try {
|
||||
@ -42,23 +44,25 @@ object YoutubeInterface {
|
||||
val item = VideoItem(
|
||||
id = result.id.videoId,
|
||||
title = result.snippet.title,
|
||||
description = result.snippet.description,
|
||||
// description = result.snippet.description,
|
||||
thumbnailUrl = result.snippet.thumbnails.default.url
|
||||
)
|
||||
items.add(item)
|
||||
Log.i("YC links received",item.id)
|
||||
Log.i("YI links received",item.id)
|
||||
}
|
||||
items
|
||||
} catch (e: IOException) {
|
||||
Log.d("YC", "Could not search: $e")
|
||||
null
|
||||
Log.d("YI", "Could not search: $e")
|
||||
if(query?.key == apiKey2){return null}
|
||||
query?.key = apiKey2
|
||||
search(keywords)
|
||||
}
|
||||
}
|
||||
|
||||
data class VideoItem(
|
||||
val id:String,
|
||||
val title:String,
|
||||
val description: String,
|
||||
// val description: String,
|
||||
val thumbnailUrl:String
|
||||
)
|
||||
|
||||
|
@ -12,12 +12,12 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:background="@drawable/text_background"
|
||||
android:background="@drawable/text_background_accented"
|
||||
android:padding="5dp"
|
||||
android:paddingTop="6dp"
|
||||
android:text="MainFragment"
|
||||
android:text="Authentication Needed"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:textSize="12dp"
|
||||
android:textSize="10dp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
@ -10,64 +10,96 @@
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".fragments.MainFragment">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/btn_download_all"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:background="@drawable/btn_design"
|
||||
android:drawableEnd="@drawable/ic_arrow_slim"
|
||||
android:drawablePadding="4dp"
|
||||
android:drawableTint="@color/black"
|
||||
android:padding="12dp"
|
||||
android:text="Download All |"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp"
|
||||
android:visibility="visible"
|
||||
app:layout_anchor="@+id/constraint_layout"
|
||||
app:layout_anchorGravity="top|center" />
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="230dp">
|
||||
android:layout_height="280dp">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:contentScrim="?attr/colorPrimary"
|
||||
app:contentScrim="#CE6A40FF"
|
||||
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
|
||||
app:layout_scrollInterpolator="@android:anim/decelerate_interpolator"
|
||||
app:toolbarId="@+id/toolbar">
|
||||
<LinearLayout
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/constraintLayout"
|
||||
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">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
||||
<EditText
|
||||
android:id="@+id/spotifyLink"
|
||||
android:layout_width="257dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:background="@drawable/text_background"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="@drawable/text_background_accented"
|
||||
android:ems="10"
|
||||
android:hint="Link From Spotify"
|
||||
android:inputType="text"
|
||||
android:padding="5dp"
|
||||
android:padding="8dp"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/white"
|
||||
android:textColorHint="@color/grey"
|
||||
android:textSize="19sp" />
|
||||
android:textSize="19sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/image_view"
|
||||
app:layout_constraintEnd_toStartOf="@+id/btn_search"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<Button
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
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:layout_height="44dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@drawable/btn_design"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingRight="4dp"
|
||||
android:text="Search"
|
||||
android:textSize="18sp" />
|
||||
</LinearLayout>
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp"
|
||||
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/image_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:contentDescription="Album Cover"
|
||||
android:scaleType="centerInside"
|
||||
android:foreground="@drawable/gradient"
|
||||
android:padding="20dp"
|
||||
android:paddingBottom="35dp"
|
||||
android:src="@drawable/ic_launcher_foreground"
|
||||
app:layout_collapseMode="parallax"/>
|
||||
</LinearLayout>
|
||||
android:visibility="gone"
|
||||
app:layout_collapseMode="parallax"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/btn_search" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
@ -113,7 +145,7 @@
|
||||
android:id="@+id/track_list"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginTop="22dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
@ -28,17 +28,16 @@
|
||||
android:id="@+id/track_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:fontFamily="monospace"
|
||||
android:letterSpacing="-0.03"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="14dp"
|
||||
android:fontFamily="@font/raleway_semibold"
|
||||
android:letterSpacing="0.04"
|
||||
android:lines="1"
|
||||
android:text="The Spectre"
|
||||
android:textAllCaps="false"
|
||||
android:textAppearance="@style/TextAppearance.AppTheme.Headline4"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#9AB3FF"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/btn_download"
|
||||
app:layout_constraintStart_toStartOf="@+id/artist"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
@ -49,9 +48,11 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:paddingLeft="9dp"
|
||||
android:text="Alan Walker"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/duration"
|
||||
app:layout_constraintStart_toEndOf="@+id/imageUrl"
|
||||
@ -63,8 +64,10 @@
|
||||
style="@style/TextAppearance.AppCompat.Body2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="3dp"
|
||||
android:paddingLeft="9dp"
|
||||
android:text="4 minutes, 20 sec"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/artist"
|
||||
app:layout_constraintEnd_toStartOf="@+id/btn_download"
|
||||
app:layout_constraintStart_toEndOf="@+id/artist"
|
||||
|
@ -1,8 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<resources>
|
||||
<color name="colorPrimary">#0AFF02</color>
|
||||
<color name="colorPrimaryDark">#43FF56</color>
|
||||
<color name="colorAccent">#43FF56</color>
|
||||
<color name="colorPrimary">#FC5C7D</color>
|
||||
<color name="colorPrimaryDark">#CE1CFF</color>
|
||||
<color name="colorAccent">#8497FA</color>
|
||||
<color name="white">#FFFFFF</color>
|
||||
<color name="grey">#99FFFFFF</color>
|
||||
<color name="black">#000000</color>
|
||||
|
@ -2,12 +2,12 @@
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimaryDark">#00730C</item>
|
||||
<item name="colorPrimary">#05A300</item>
|
||||
<item name="colorPrimaryDark">#000000</item>
|
||||
<item name="colorPrimary">#FC5C7D</item>
|
||||
<item name="android:background">#000000</item>
|
||||
<item name="android:textColor">#FFFFFF</item>
|
||||
<item name="colorAccent">#43FF56</item>
|
||||
<item name="android:outlineAmbientShadowColor" tools:targetApi="p">#6DFF7C</item>
|
||||
<item name="colorAccent">#6A82FB</item>
|
||||
<item name="android:outlineAmbientShadowColor" tools:targetApi="p">#A9B200FF</item>
|
||||
<item name="android:radius">11dp</item>
|
||||
<!-- Text Appearances !-->
|
||||
<!-- use our brand's custom TextAppearance4 !-->
|
||||
|
Loading…
Reference in New Issue
Block a user