mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-24 18:04:33 +01:00
Unifying All Things For Better Maintenance and Less Trouble.
This commit is contained in:
parent
cac306e9e8
commit
180a284a54
@ -25,7 +25,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
|
||||
class SharedViewModel : ViewModel() {
|
||||
var intentString = MutableLiveData<String>().apply { value = "" }
|
||||
var intentString = MutableLiveData<String>()
|
||||
var spotifyService = MutableLiveData<SpotifyService>()
|
||||
|
||||
private var viewModelJob = Job()
|
||||
|
@ -33,8 +33,8 @@ import com.shabinder.spotiflyer.models.TrackDetails
|
||||
import com.shabinder.spotiflyer.networking.YoutubeMusicApi
|
||||
import com.shabinder.spotiflyer.networking.makeJsonBody
|
||||
import com.shabinder.spotiflyer.utils.*
|
||||
import com.shabinder.spotiflyer.utils.Provider.activity
|
||||
import com.shabinder.spotiflyer.utils.Provider.defaultDir
|
||||
import com.shabinder.spotiflyer.utils.Provider.mainActivity
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -76,9 +76,9 @@ object DownloadHelper {
|
||||
//Delay is Added ,if a request is in processing it may finish
|
||||
Log.i("Spotify Helper","Download Request Sent")
|
||||
sharedViewModel?.uiScope?.launch (Dispatchers.Main){
|
||||
Toast.makeText(activity,"Download Started, Now You can leave the App!", Toast.LENGTH_SHORT).show()
|
||||
Toast.makeText(mainActivity,"Download Started, Now You can leave the App!", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
startService(activity,downloadList)
|
||||
startService(mainActivity,downloadList)
|
||||
},5000)
|
||||
}
|
||||
}else{
|
||||
@ -121,9 +121,9 @@ object DownloadHelper {
|
||||
//Delay is Added ,if a request is in processing it may finish
|
||||
Log.i("Spotify Helper","Download Request Sent")
|
||||
sharedViewModel?.uiScope?.launch (Dispatchers.Main){
|
||||
Toast.makeText(activity,"Download Started, Now You can leave the App!", Toast.LENGTH_SHORT).show()
|
||||
Toast.makeText(mainActivity,"Download Started, Now You can leave the App!", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
startService(activity,downloadList)
|
||||
startService(mainActivity,downloadList)
|
||||
},5000)
|
||||
}
|
||||
}
|
||||
|
@ -22,8 +22,8 @@ import android.util.Log
|
||||
import android.widget.Toast
|
||||
import com.shabinder.spotiflyer.models.DownloadObject
|
||||
import com.shabinder.spotiflyer.models.TrackDetails
|
||||
import com.shabinder.spotiflyer.utils.Provider.activity
|
||||
import com.shabinder.spotiflyer.utils.Provider.defaultDir
|
||||
import com.shabinder.spotiflyer.utils.Provider.mainActivity
|
||||
import com.shabinder.spotiflyer.utils.isOnline
|
||||
import com.shabinder.spotiflyer.utils.removeIllegalChars
|
||||
import com.shabinder.spotiflyer.utils.showNoConnectionAlert
|
||||
@ -63,8 +63,8 @@ object YTDownloadHelper {
|
||||
}
|
||||
Log.i("YT Downloader Helper","Download Request Sent")
|
||||
withContext(Dispatchers.Main){
|
||||
Toast.makeText(activity,"Download Started, Now You can leave the App!", Toast.LENGTH_SHORT).show()
|
||||
startService(activity,downloadList)
|
||||
Toast.makeText(mainActivity,"Download Started, Now You can leave the App!", Toast.LENGTH_SHORT).show()
|
||||
startService(mainActivity,downloadList)
|
||||
}
|
||||
}
|
||||
}
|
@ -40,6 +40,7 @@ data class TrackDetails(
|
||||
var lyrics:String?=null,
|
||||
var trackUrl:String?=null,
|
||||
var albumArt: File,
|
||||
var albumArtURL: String,
|
||||
var source: Source,
|
||||
var downloaded: DownloadStatus = DownloadStatus.NotDownloaded
|
||||
):Parcelable
|
||||
|
@ -18,7 +18,7 @@
|
||||
package com.shabinder.spotiflyer.models.gaana
|
||||
|
||||
data class GaanaAlbum (
|
||||
val tracks : List<Tracks>,
|
||||
val tracks : List<GaanaTrack>,
|
||||
val count : Int,
|
||||
val custom_artworks : CustomArtworks,
|
||||
val release_year : Int,
|
||||
|
@ -19,5 +19,5 @@ package com.shabinder.spotiflyer.models.gaana
|
||||
|
||||
data class GaanaArtistTracks(
|
||||
val count : Int,
|
||||
val tracks : List<Tracks>
|
||||
val tracks : List<GaanaTrack>
|
||||
)
|
@ -18,11 +18,11 @@
|
||||
package com.shabinder.spotiflyer.models.gaana
|
||||
|
||||
data class GaanaPlaylist (
|
||||
val tags : String,
|
||||
val fromCache : Int,
|
||||
val modified_on : String,
|
||||
val count : Int,
|
||||
val created_on : String,
|
||||
val favorite_count : Int,
|
||||
val tracks : List<Tracks>,
|
||||
val tags : String,
|
||||
val fromCache : Int,
|
||||
val modified_on : String,
|
||||
val count : Int,
|
||||
val created_on : String,
|
||||
val favorite_count : Int,
|
||||
val tracks : List<GaanaTrack>,
|
||||
)
|
@ -18,5 +18,5 @@
|
||||
package com.shabinder.spotiflyer.models.gaana
|
||||
|
||||
data class GaanaSong(
|
||||
val tracks : List<Tracks>
|
||||
val tracks : List<GaanaTrack>
|
||||
)
|
@ -17,9 +17,10 @@
|
||||
|
||||
package com.shabinder.spotiflyer.models.gaana
|
||||
|
||||
import com.shabinder.spotiflyer.models.DownloadStatus
|
||||
import com.squareup.moshi.Json
|
||||
|
||||
data class Tracks (
|
||||
data class GaanaTrack (
|
||||
val tags : List<Tags>,
|
||||
val seokey : String,
|
||||
val albumseokey : String,
|
||||
@ -35,4 +36,5 @@ data class Tracks (
|
||||
val release_date : String,
|
||||
val play_ct : String,
|
||||
val secondary_language : String,
|
||||
var downloaded: DownloadStatus? = DownloadStatus.NotDownloaded
|
||||
)
|
@ -40,6 +40,6 @@ data class Track(
|
||||
var album: Album? = null,
|
||||
var external_ids: Map<String?, String?>? = null,
|
||||
var popularity: Int? = null,
|
||||
var downloaded: DownloadStatus? = DownloadStatus.NotDownloaded
|
||||
var downloaded: DownloadStatus = DownloadStatus.NotDownloaded
|
||||
):Parcelable
|
||||
|
||||
|
@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Shabinder Singh
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.shabinder.spotiflyer.recyclerView
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Environment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.shabinder.spotiflyer.R
|
||||
import com.shabinder.spotiflyer.databinding.TrackListItemBinding
|
||||
import com.shabinder.spotiflyer.downloadHelper.DownloadHelper.downloadAllTracks
|
||||
import com.shabinder.spotiflyer.models.DownloadStatus
|
||||
import com.shabinder.spotiflyer.models.TrackDetails
|
||||
import com.shabinder.spotiflyer.models.spotify.Source
|
||||
import com.shabinder.spotiflyer.models.spotify.Track
|
||||
import com.shabinder.spotiflyer.ui.spotify.SpotifyViewModel
|
||||
import com.shabinder.spotiflyer.utils.*
|
||||
import com.shabinder.spotiflyer.utils.Provider.activity
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
|
||||
class SpotifyTrackListAdapter(private val spotifyViewModel : SpotifyViewModel): ListAdapter<Track,SpotifyTrackListAdapter.ViewHolder>(SpotifyTrackDiffCallback()) {
|
||||
|
||||
var isAlbum:Boolean = false
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val layoutInflater = LayoutInflater.from(parent.context)
|
||||
val binding = TrackListItemBinding.inflate(layoutInflater,parent,false)
|
||||
return ViewHolder(binding)
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
if(itemCount ==1 || isAlbum){
|
||||
holder.binding.imageUrl.visibility = View.GONE}else{
|
||||
spotifyViewModel.uiScope.launch {
|
||||
//Placeholder Set
|
||||
bindImage(holder.binding.imageUrl, item.album?.images?.get(0)?.url, Source.Spotify)
|
||||
}
|
||||
}
|
||||
|
||||
holder.binding.trackName.text = "${if(item.name!!.length > 17){"${item.name!!.subSequence(0,16)}..."}else{item.name}}"
|
||||
holder.binding.artist.text = "${item.artists?.get(0)?.name?:""}..."
|
||||
holder.binding.duration.text = "${item.duration_ms/1000/60} minutes, ${(item.duration_ms/1000)%60} sec"
|
||||
when (item.downloaded) {
|
||||
DownloadStatus.Downloaded -> {
|
||||
holder.binding.btnDownload.setImageResource(R.drawable.ic_tick)
|
||||
holder.binding.btnDownload.clearAnimation()
|
||||
}
|
||||
DownloadStatus.Downloading -> {
|
||||
holder.binding.btnDownload.setImageResource(R.drawable.ic_refresh)
|
||||
rotateAnim(holder.binding.btnDownload)
|
||||
}
|
||||
DownloadStatus.NotDownloaded -> {
|
||||
holder.binding.btnDownload.setImageResource(R.drawable.ic_arrow)
|
||||
holder.binding.btnDownload.clearAnimation()
|
||||
holder.binding.btnDownload.setOnClickListener{
|
||||
if(!isOnline()){
|
||||
showNoConnectionAlert()
|
||||
return@setOnClickListener
|
||||
}
|
||||
Toast.makeText(activity,"Processing!",Toast.LENGTH_SHORT).show()
|
||||
holder.binding.btnDownload.setImageResource(R.drawable.ic_refresh)
|
||||
rotateAnim(it)
|
||||
item.downloaded = DownloadStatus.Downloading
|
||||
spotifyViewModel.uiScope.launch {
|
||||
val itemList = mutableListOf<TrackDetails>()
|
||||
itemList.add(item.let { track ->
|
||||
val artistsList = mutableListOf<String>()
|
||||
track.artists?.forEach { artist -> artistsList.add(artist!!.name!!) }
|
||||
TrackDetails(
|
||||
title = track.name.toString(),
|
||||
artists = artistsList,
|
||||
durationSec = (track.duration_ms/1000).toInt(),
|
||||
albumArt = File(
|
||||
Environment.getExternalStorageDirectory(),
|
||||
Provider.defaultDir +".Images/" + (track.album?.images?.get(0)?.url.toString()).substringAfterLast('/') + ".jpeg"),
|
||||
albumName = track.album?.name,
|
||||
year = track.album?.release_date,
|
||||
comment = "Genres:${track.album?.genres?.joinToString()}",
|
||||
trackUrl = track.href,
|
||||
source = Source.Spotify
|
||||
)
|
||||
}
|
||||
)
|
||||
downloadAllTracks(spotifyViewModel.folderType,spotifyViewModel.subFolder,itemList)
|
||||
}
|
||||
notifyItemChanged(position)//start showing anim!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
class ViewHolder(val binding: TrackListItemBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
}
|
||||
|
||||
class SpotifyTrackDiffCallback: DiffUtil.ItemCallback<Track>(){
|
||||
override fun areItemsTheSame(oldItem: Track, newItem: Track): Boolean {
|
||||
return oldItem.name == newItem.name
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: Track, newItem: Track): Boolean {
|
||||
return oldItem == newItem //Downloaded Check
|
||||
}
|
||||
}
|
@ -22,39 +22,35 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.shabinder.spotiflyer.R
|
||||
import com.shabinder.spotiflyer.databinding.TrackListItemBinding
|
||||
import com.shabinder.spotiflyer.downloadHelper.DownloadHelper
|
||||
import com.shabinder.spotiflyer.downloadHelper.YTDownloadHelper
|
||||
import com.shabinder.spotiflyer.models.DownloadStatus
|
||||
import com.shabinder.spotiflyer.models.TrackDetails
|
||||
import com.shabinder.spotiflyer.models.spotify.Source
|
||||
import com.shabinder.spotiflyer.ui.youtube.YoutubeViewModel
|
||||
import com.shabinder.spotiflyer.utils.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class YoutubeTrackListAdapter(private val youtubeViewModel :YoutubeViewModel): ListAdapter<TrackDetails,SpotifyTrackListAdapter.ViewHolder>(YouTubeTrackDiffCallback()) {
|
||||
class TrackListAdapter(private val viewModel :BaseViewModel): ListAdapter<TrackDetails, TrackListAdapter.ViewHolder>(TrackDiffCallback()) {
|
||||
|
||||
var source:Source =Source.Spotify
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): SpotifyTrackListAdapter.ViewHolder {
|
||||
): ViewHolder {
|
||||
val layoutInflater = LayoutInflater.from(parent.context)
|
||||
val binding = TrackListItemBinding.inflate(layoutInflater,parent,false)
|
||||
// val view = layoutInflater.inflate(R.layout.track_list_item,parent,false)
|
||||
return SpotifyTrackListAdapter.ViewHolder(binding)
|
||||
return ViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: SpotifyTrackListAdapter.ViewHolder, position: Int) {
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
if(itemCount == 1){
|
||||
holder.binding.imageUrl.visibility = View.GONE}else{
|
||||
youtubeViewModel.uiScope.launch {
|
||||
bindImage(holder.binding.imageUrl,
|
||||
"https://i.ytimg.com/vi/${item.albumArt.absolutePath.substringAfterLast("/")
|
||||
.substringBeforeLast(".")}/hqdefault.jpg"
|
||||
,
|
||||
Source.YouTube
|
||||
)
|
||||
if(itemCount == 1){ holder.binding.imageUrl.visibility = View.GONE}else{
|
||||
viewModel.uiScope.launch {
|
||||
bindImage(holder.binding.imageUrl,item.albumArtURL, source)
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,14 +75,25 @@ class YoutubeTrackListAdapter(private val youtubeViewModel :YoutubeViewModel): L
|
||||
holder.binding.btnDownload.setImageResource(R.drawable.ic_refresh)
|
||||
rotateAnim(it)
|
||||
item.downloaded = DownloadStatus.Downloading
|
||||
youtubeViewModel.uiScope.launch {
|
||||
val itemList = mutableListOf<TrackDetails>()
|
||||
itemList.add(item)
|
||||
YTDownloadHelper.downloadYTTracks(
|
||||
youtubeViewModel.folderType,
|
||||
youtubeViewModel.subFolder,
|
||||
itemList
|
||||
)
|
||||
when(source){
|
||||
Source.Spotify -> {
|
||||
viewModel.uiScope.launch {
|
||||
DownloadHelper.downloadAllTracks(
|
||||
viewModel.folderType,
|
||||
viewModel.subFolder,
|
||||
listOf(item)
|
||||
)
|
||||
}
|
||||
}
|
||||
Source.YouTube -> {
|
||||
viewModel.uiScope.launch {
|
||||
YTDownloadHelper.downloadYTTracks(
|
||||
viewModel.folderType,
|
||||
viewModel.subFolder,
|
||||
listOf(item)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
notifyItemChanged(position)//start showing anim!
|
||||
}
|
||||
@ -97,8 +104,15 @@ class YoutubeTrackListAdapter(private val youtubeViewModel :YoutubeViewModel): L
|
||||
holder.binding.artist.text = "${item.artists.get(0)}..."
|
||||
holder.binding.duration.text = "${item.durationSec/60} minutes, ${item.durationSec%60} sec"
|
||||
}
|
||||
|
||||
class ViewHolder(val binding: TrackListItemBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
fun submitList(list: MutableList<TrackDetails>?, source: Source) {
|
||||
super.submitList(list)
|
||||
this.source = source
|
||||
}
|
||||
}
|
||||
class YouTubeTrackDiffCallback: DiffUtil.ItemCallback<TrackDetails>(){
|
||||
class TrackDiffCallback: DiffUtil.ItemCallback<TrackDetails>(){
|
||||
override fun areItemsTheSame(oldItem: TrackDetails, newItem: TrackDetails): Boolean {
|
||||
return oldItem.title == newItem.title
|
||||
}
|
@ -20,6 +20,7 @@ package com.shabinder.spotiflyer.ui.gaana
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.IntentFilter
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@ -29,8 +30,14 @@ import androidx.lifecycle.ViewModelProvider
|
||||
import com.shabinder.spotiflyer.R
|
||||
import com.shabinder.spotiflyer.SharedViewModel
|
||||
import com.shabinder.spotiflyer.databinding.TrackListFragmentBinding
|
||||
import com.shabinder.spotiflyer.downloadHelper.DownloadHelper
|
||||
import com.shabinder.spotiflyer.models.DownloadStatus
|
||||
import com.shabinder.spotiflyer.networking.GaanaInterface
|
||||
import com.shabinder.spotiflyer.networking.YoutubeMusicApi
|
||||
import com.shabinder.spotiflyer.recyclerView.TrackListAdapter
|
||||
import com.shabinder.spotiflyer.utils.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class GaanaFragment : Fragment() {
|
||||
@ -39,6 +46,7 @@ class GaanaFragment : Fragment() {
|
||||
private lateinit var sharedViewModel: SharedViewModel
|
||||
@Inject lateinit var youtubeMusicApi: YoutubeMusicApi
|
||||
private lateinit var viewModel: GaanaViewModel
|
||||
private lateinit var adapter: TrackListAdapter
|
||||
@Inject lateinit var gaanaInterface: GaanaInterface
|
||||
private var intentFilter: IntentFilter? = null
|
||||
private var updateUIReceiver: BroadcastReceiver? = null
|
||||
@ -49,6 +57,63 @@ class GaanaFragment : Fragment() {
|
||||
): View? {
|
||||
binding = DataBindingUtil.inflate(inflater,R.layout.track_list_fragment, container, false)
|
||||
viewModel = ViewModelProvider(this).get(GaanaViewModel::class.java)
|
||||
adapter = TrackListAdapter(viewModel)
|
||||
|
||||
val gaanaLink = GaanaFragmentArgs.fromBundle(requireArguments()).link.substringAfter("gaana.com/")
|
||||
//Link Schema: https://gaana.com/type/link
|
||||
val link = gaanaLink.substringAfterLast('/', "error")
|
||||
val type = gaanaLink.substringBeforeLast('/', "error").substringAfterLast('/')
|
||||
|
||||
Log.i("Gaana Fragment", "$type : $link")
|
||||
|
||||
when{
|
||||
type == "Error" || link == "Error" -> {
|
||||
showMessage("Please Check Your Link!")
|
||||
Provider.mainActivity.onBackPressed()
|
||||
}
|
||||
|
||||
else -> {
|
||||
viewModel.gaanaSearch(type,link)
|
||||
|
||||
binding.btnDownloadAll.setOnClickListener {
|
||||
if(!isOnline()){
|
||||
showNoConnectionAlert()
|
||||
return@setOnClickListener
|
||||
}
|
||||
binding.btnDownloadAll.visibility = View.GONE
|
||||
binding.downloadingFab.visibility = View.VISIBLE
|
||||
|
||||
rotateAnim(binding.downloadingFab)
|
||||
for (track in viewModel.trackList.value!!){
|
||||
if(track.downloaded != DownloadStatus.Downloaded){
|
||||
track.downloaded = DownloadStatus.Downloading
|
||||
adapter.notifyItemChanged(viewModel.trackList.value!!.indexOf(track))
|
||||
}
|
||||
}
|
||||
showMessage("Processing!")
|
||||
sharedViewModel.uiScope.launch(Dispatchers.Default){
|
||||
val urlList = arrayListOf<String>()
|
||||
viewModel.trackList.value?.forEach { urlList.add(it.albumArtURL) }
|
||||
//Appending Source
|
||||
urlList.add("spotify")
|
||||
loadAllImages(
|
||||
requireActivity(),
|
||||
urlList
|
||||
)
|
||||
}
|
||||
viewModel.uiScope.launch {
|
||||
val finalList = viewModel.trackList.value
|
||||
if(finalList.isNullOrEmpty())showMessage("Not Downloading Any Song")
|
||||
DownloadHelper.downloadAllTracks(
|
||||
viewModel.folderType,
|
||||
viewModel.subFolder,
|
||||
finalList ?: listOf(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return binding.root
|
||||
}
|
||||
}
|
@ -18,7 +18,18 @@
|
||||
package com.shabinder.spotiflyer.ui.gaana
|
||||
|
||||
import androidx.hilt.lifecycle.ViewModelInject
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.shabinder.spotiflyer.database.DatabaseDAO
|
||||
import com.shabinder.spotiflyer.networking.GaanaInterface
|
||||
import com.shabinder.spotiflyer.utils.BaseViewModel
|
||||
|
||||
class GaanaViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO) : ViewModel()
|
||||
class GaanaViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO) : BaseViewModel(){
|
||||
|
||||
override var folderType:String = ""
|
||||
override var subFolder:String = ""
|
||||
var gaanaInterface : GaanaInterface? = null
|
||||
|
||||
fun gaanaSearch(type:String,link:String){
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -65,19 +65,60 @@ class MainFragment : Fragment() {
|
||||
return@setOnClickListener
|
||||
}
|
||||
val link = binding.linkSearch.text.toString()
|
||||
if (link.contains("spotify",true)){
|
||||
if(sharedViewModel.spotifyService.value == null){//Authentication pending!!
|
||||
(activity as MainActivity).authenticateSpotify()
|
||||
when{
|
||||
//SPOTIFY
|
||||
link.contains("spotify",true) -> {
|
||||
if(sharedViewModel.spotifyService.value == null){//Authentication pending!!
|
||||
(activity as MainActivity).authenticateSpotify()
|
||||
}
|
||||
findNavController().navigate(MainFragmentDirections.actionMainFragmentToSpotifyFragment(link))
|
||||
}
|
||||
findNavController().navigate(MainFragmentDirections.actionMainFragmentToSpotifyFragment(link))
|
||||
}else if(link.contains("youtube.com",true) || link.contains("youtu.be",true) ){
|
||||
findNavController().navigate(MainFragmentDirections.actionMainFragmentToYoutubeFragment(link))
|
||||
}else showMessage("Link is Not Valid",true)
|
||||
|
||||
//YOUTUBE
|
||||
link.contains("youtube.com",true) || link.contains("youtu.be",true) -> {
|
||||
findNavController().navigate(MainFragmentDirections.actionMainFragmentToYoutubeFragment(link))
|
||||
}
|
||||
|
||||
//GAANA
|
||||
link.contains("gaana",true) -> {
|
||||
findNavController().navigate(MainFragmentDirections.actionMainFragmentToGaanaFragment(link))
|
||||
}
|
||||
|
||||
else -> showMessage("Link is Not Valid",true)
|
||||
}
|
||||
}
|
||||
handleIntent()
|
||||
return binding.root
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Intent If there is any!
|
||||
**/
|
||||
private fun handleIntent() {
|
||||
sharedViewModel.intentString.observe(viewLifecycleOwner,{ it?.let {
|
||||
sharedViewModel.uiScope.launch(Dispatchers.IO) {
|
||||
//Wait for any Authentication to Finish ,
|
||||
// this Wait prevents from multiple Authentication Requests
|
||||
Thread.sleep(1000)
|
||||
if(sharedViewModel.spotifyService.value == null){
|
||||
//Not Authenticated Yet
|
||||
Provider.mainActivity.authenticateSpotify()
|
||||
while (sharedViewModel.spotifyService.value == null) {
|
||||
//Waiting for Authentication to Finish
|
||||
Thread.sleep(1000)
|
||||
}
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main){
|
||||
binding.linkSearch.setText(sharedViewModel.intentString.value)
|
||||
binding.btnSearch.performClick()
|
||||
//Intent Consumed
|
||||
sharedViewModel.intentString.value = null
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun initializeAll() {
|
||||
mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
|
||||
@ -94,44 +135,14 @@ class MainFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementing buttons
|
||||
**/
|
||||
private fun historyButton() {
|
||||
binding.btnHistory.setOnClickListener {
|
||||
findNavController().navigate(MainFragmentDirections.actionMainFragmentToDownloadRecord())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Intent If there is any!
|
||||
**/
|
||||
private fun handleIntent() {
|
||||
sharedViewModel.intentString.observe(viewLifecycleOwner,{
|
||||
if(it != ""){
|
||||
sharedViewModel.uiScope.launch(Dispatchers.IO) {
|
||||
//Wait for any Authentication to Finish ,
|
||||
// this Wait prevents from multiple Authentication Requests
|
||||
Thread.sleep(1000)
|
||||
if(sharedViewModel.spotifyService.value == null){
|
||||
//Not Authenticated Yet
|
||||
Provider.activity.authenticateSpotify()
|
||||
while (sharedViewModel.spotifyService.value == null) {
|
||||
//Waiting for Authentication to Finish
|
||||
Thread.sleep(1000)
|
||||
}
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main){
|
||||
binding.linkSearch.setText(sharedViewModel.intentString.value)
|
||||
binding.btnSearch.performClick()
|
||||
sharedViewModel.intentString.value = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementing buttons
|
||||
**/
|
||||
private fun openSpotifyButton() {
|
||||
val manager: PackageManager = requireActivity().packageManager
|
||||
try {
|
||||
|
@ -23,7 +23,6 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@ -41,13 +40,12 @@ import com.shabinder.spotiflyer.models.DownloadStatus
|
||||
import com.shabinder.spotiflyer.models.TrackDetails
|
||||
import com.shabinder.spotiflyer.models.spotify.Source
|
||||
import com.shabinder.spotiflyer.networking.YoutubeMusicApi
|
||||
import com.shabinder.spotiflyer.recyclerView.SpotifyTrackListAdapter
|
||||
import com.shabinder.spotiflyer.recyclerView.TrackListAdapter
|
||||
import com.shabinder.spotiflyer.utils.*
|
||||
import com.shabinder.spotiflyer.utils.Provider.defaultDir
|
||||
import com.shabinder.spotiflyer.utils.Provider.mainActivity
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@ -58,7 +56,7 @@ class SpotifyFragment : Fragment() {
|
||||
private lateinit var sharedViewModel: SharedViewModel
|
||||
@Inject lateinit var youtubeMusicApi: YoutubeMusicApi
|
||||
private lateinit var viewModel: SpotifyViewModel
|
||||
private lateinit var adapter:SpotifyTrackListAdapter
|
||||
private lateinit var adapter:TrackListAdapter
|
||||
private var intentFilter:IntentFilter? = null
|
||||
private var updateUIReceiver: BroadcastReceiver? = null
|
||||
|
||||
@ -73,81 +71,70 @@ class SpotifyFragment : Fragment() {
|
||||
initializeLiveDataObservers()
|
||||
initializeBroadcast()
|
||||
|
||||
val args = SpotifyFragmentArgs.fromBundle(requireArguments())
|
||||
val spotifyLink = args.link
|
||||
val spotifyLink = SpotifyFragmentArgs.fromBundle(requireArguments()).link.substringAfter("open.spotify.com/")
|
||||
|
||||
val link = spotifyLink.substringAfterLast('/', "Error").substringBefore('?')
|
||||
val type = spotifyLink.substringBeforeLast('/', "Error").substringAfterLast('/')
|
||||
|
||||
Log.i("Fragment", "$type : $link")
|
||||
Log.i("Spotify Fragment", "$type : $link")
|
||||
|
||||
if(sharedViewModel.spotifyService.value == null){//Authentication pending!!
|
||||
(activity as MainActivity).authenticateSpotify()
|
||||
}
|
||||
if (type == "Error" || link == "Error") {//Incorrect Link
|
||||
showMessage("Please Check Your Link!")
|
||||
}else if(spotifyLink.contains("open.spotify",true)){//Link Validation!!
|
||||
if(type == "episode" || type == "show"){//TODO Implementation
|
||||
showMessage("Implementing Soon, Stay Tuned!")
|
||||
|
||||
when{
|
||||
type == "Error" || link == "Error" -> {
|
||||
showMessage("Please Check Your Link!")
|
||||
mainActivity.onBackPressed()
|
||||
}
|
||||
else{
|
||||
viewModel.spotifySearch(type,link)
|
||||
if(type=="album")adapter.isAlbum = true
|
||||
|
||||
binding.btnDownloadAll.setOnClickListener {
|
||||
if(!isOnline()){
|
||||
showNoConnectionAlert()
|
||||
return@setOnClickListener
|
||||
}
|
||||
binding.btnDownloadAll.visibility = View.GONE
|
||||
binding.downloadingFab.visibility = View.VISIBLE
|
||||
else -> {
|
||||
if(type == "episode" || type == "show"){//TODO Implementation
|
||||
showMessage("Implementing Soon, Stay Tuned!")
|
||||
}
|
||||
else{
|
||||
viewModel.spotifySearch(type,link)
|
||||
|
||||
rotateAnim(binding.downloadingFab)
|
||||
for (track in viewModel.trackList.value!!){
|
||||
if(track.downloaded != DownloadStatus.Downloaded){
|
||||
track.downloaded = DownloadStatus.Downloading
|
||||
adapter.notifyItemChanged(viewModel.trackList.value!!.indexOf(track))
|
||||
binding.btnDownloadAll.setOnClickListener {
|
||||
if(!isOnline()){
|
||||
showNoConnectionAlert()
|
||||
return@setOnClickListener
|
||||
}
|
||||
}
|
||||
showMessage("Processing!")
|
||||
sharedViewModel.uiScope.launch(Dispatchers.Default){
|
||||
val urlList = arrayListOf<String>()
|
||||
viewModel.trackList.value?.forEach { urlList.add(it.album?.images?.get(0)?.url.toString()) }
|
||||
//Appending Source
|
||||
urlList.add("spotify")
|
||||
loadAllImages(
|
||||
requireActivity(),
|
||||
urlList
|
||||
)
|
||||
}
|
||||
viewModel.uiScope.launch {
|
||||
val finalList = viewModel.trackList.value?.map{
|
||||
val artistsList = mutableListOf<String>()
|
||||
it.artists?.forEach { artist -> artistsList.add(artist!!.name!!) }
|
||||
TrackDetails(
|
||||
title = it.name.toString(),
|
||||
artists = artistsList,
|
||||
durationSec = (it.duration_ms/1000).toInt(),
|
||||
albumArt = File(
|
||||
Environment.getExternalStorageDirectory(),
|
||||
defaultDir +".Images/" + (it.album?.images?.get(0)?.url.toString()).substringAfterLast('/') + ".jpeg"),
|
||||
albumName = it.album?.name,
|
||||
year = it.album?.release_date,
|
||||
comment = "Genres:${it.album?.genres?.joinToString()}",
|
||||
trackUrl = it.href,
|
||||
source = Source.Spotify
|
||||
binding.btnDownloadAll.visibility = View.GONE
|
||||
binding.downloadingFab.visibility = View.VISIBLE
|
||||
|
||||
rotateAnim(binding.downloadingFab)
|
||||
for (track in viewModel.trackList.value!!){
|
||||
if(track.downloaded != DownloadStatus.Downloaded){
|
||||
track.downloaded = DownloadStatus.Downloading
|
||||
adapter.notifyItemChanged(viewModel.trackList.value!!.indexOf(track))
|
||||
}
|
||||
}
|
||||
showMessage("Processing!")
|
||||
sharedViewModel.uiScope.launch(Dispatchers.Default){
|
||||
val urlList = arrayListOf<String>()
|
||||
viewModel.trackList.value?.forEach { urlList.add(it.albumArtURL) }
|
||||
//Appending Source
|
||||
urlList.add("spotify")
|
||||
loadAllImages(
|
||||
requireActivity(),
|
||||
urlList
|
||||
)
|
||||
}
|
||||
viewModel.uiScope.launch {
|
||||
val finalList = viewModel.trackList.value
|
||||
if(finalList.isNullOrEmpty())showMessage("Not Downloading Any Song")
|
||||
DownloadHelper.downloadAllTracks(
|
||||
viewModel.folderType,
|
||||
viewModel.subFolder,
|
||||
finalList ?: listOf(),
|
||||
)
|
||||
}
|
||||
if(finalList.isNullOrEmpty())showMessage("Not Downloading Any Song")
|
||||
DownloadHelper.downloadAllTracks(
|
||||
viewModel.folderType,
|
||||
viewModel.subFolder,
|
||||
finalList ?: listOf(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
@ -160,7 +147,7 @@ class SpotifyFragment : Fragment() {
|
||||
sharedViewModel.spotifyService.observe(viewLifecycleOwner, {
|
||||
viewModel.spotifyService = it
|
||||
})
|
||||
adapter = SpotifyTrackListAdapter(viewModel)
|
||||
adapter = TrackListAdapter(viewModel)
|
||||
DownloadHelper.youtubeMusicApi = youtubeMusicApi
|
||||
DownloadHelper.sharedViewModel = sharedViewModel
|
||||
DownloadHelper.statusBar = binding.statusBar
|
||||
@ -211,7 +198,7 @@ class SpotifyFragment : Fragment() {
|
||||
if (intent != null){
|
||||
val trackDetails = intent.getParcelableExtra<TrackDetails?>("track")
|
||||
trackDetails?.let {
|
||||
val position: Int = viewModel.trackList.value?.map { it.name }?.indexOf(trackDetails.title) ?: -1
|
||||
val position: Int = viewModel.trackList.value?.map { it.title }?.indexOf(trackDetails.title) ?: -1
|
||||
Log.i("Track","Download Completed Intent :$position")
|
||||
if(position != -1) {
|
||||
val track = viewModel.trackList.value?.get(position)
|
||||
|
@ -17,34 +17,30 @@
|
||||
|
||||
package com.shabinder.spotiflyer.ui.spotify
|
||||
|
||||
import android.os.Environment
|
||||
import android.util.Log
|
||||
import androidx.hilt.lifecycle.ViewModelInject
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.shabinder.spotiflyer.database.DatabaseDAO
|
||||
import com.shabinder.spotiflyer.database.DownloadRecord
|
||||
import com.shabinder.spotiflyer.models.DownloadStatus
|
||||
import com.shabinder.spotiflyer.models.TrackDetails
|
||||
import com.shabinder.spotiflyer.models.spotify.*
|
||||
import com.shabinder.spotiflyer.networking.SpotifyService
|
||||
import com.shabinder.spotiflyer.utils.BaseViewModel
|
||||
import com.shabinder.spotiflyer.utils.Provider
|
||||
import com.shabinder.spotiflyer.utils.finalOutputDir
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
|
||||
class SpotifyViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO) :
|
||||
ViewModel(){
|
||||
class SpotifyViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO) : BaseViewModel(){
|
||||
|
||||
override var folderType:String = ""
|
||||
override var subFolder:String = ""
|
||||
|
||||
var folderType:String = ""
|
||||
var subFolder:String = ""
|
||||
var trackList = MutableLiveData<MutableList<Track>>()
|
||||
private val loading = "Loading"
|
||||
var title = MutableLiveData<String>().apply { value = loading }
|
||||
var coverUrl = MutableLiveData<String>().apply { value = loading }
|
||||
var spotifyService : SpotifyService? = null
|
||||
|
||||
private var viewModelJob = Job()
|
||||
val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
|
||||
|
||||
|
||||
fun spotifySearch(type:String,link: String){
|
||||
when (type) {
|
||||
"track" -> {
|
||||
@ -56,7 +52,7 @@ class SpotifyViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO
|
||||
trackObject.downloaded = DownloadStatus.Downloaded
|
||||
}
|
||||
tempTrackList.add(trackObject)
|
||||
trackList.value = tempTrackList
|
||||
trackList.value = tempTrackList.toTrackDetailsList()
|
||||
title.value = trackObject.name
|
||||
coverUrl.value = trackObject.album!!.images?.get(0)!!.url!!
|
||||
withContext(Dispatchers.IO){
|
||||
@ -86,7 +82,7 @@ class SpotifyViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO
|
||||
it.album = Album(images = listOf(Image(url = albumObject.images?.get(0)?.url)))
|
||||
tempTrackList.add(it)
|
||||
}
|
||||
trackList.value = tempTrackList
|
||||
trackList.value = tempTrackList.toTrackDetailsList()
|
||||
title.value = albumObject?.name
|
||||
coverUrl.value = albumObject?.images?.get(0)?.url
|
||||
withContext(Dispatchers.IO){
|
||||
@ -129,7 +125,7 @@ class SpotifyViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO
|
||||
moreTracksAvailable = !moreTracks?.next.isNullOrBlank()
|
||||
}
|
||||
Log.i("Total Tracks Fetched",tempTrackList.size.toString())
|
||||
trackList.value = tempTrackList
|
||||
trackList.value = tempTrackList.toTrackDetailsList()
|
||||
title.value = playlistObject?.name
|
||||
coverUrl.value = playlistObject?.images?.get(0)?.url.toString()
|
||||
withContext(Dispatchers.IO){
|
||||
@ -152,6 +148,26 @@ class SpotifyViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<Track>.toTrackDetailsList() = this.map {
|
||||
val artistsList = mutableListOf<String>()
|
||||
it.artists?.forEach { artist -> artistsList.add(artist!!.name!!) }
|
||||
TrackDetails(
|
||||
title = it.name.toString(),
|
||||
artists = artistsList,
|
||||
durationSec = (it.duration_ms/1000).toInt(),
|
||||
albumArt = File(
|
||||
Environment.getExternalStorageDirectory(),
|
||||
Provider.defaultDir +".Images/" + (it.album?.images?.get(0)?.url.toString()).substringAfterLast('/') + ".jpeg"),
|
||||
albumName = it.album?.name,
|
||||
year = it.album?.release_date,
|
||||
comment = "Genres:${it.album?.genres?.joinToString()}",
|
||||
trackUrl = it.href,
|
||||
downloaded = it.downloaded,
|
||||
source = Source.Spotify,
|
||||
albumArtURL = it.album?.images?.get(0)?.url.toString()
|
||||
)
|
||||
}.toMutableList()
|
||||
|
||||
private suspend fun getTrackDetails(trackLink:String): Track?{
|
||||
Log.i("Requesting","https://api.spotify.com/v1/tracks/$trackLink")
|
||||
return spotifyService?.getTrack(trackLink)?.value
|
||||
@ -168,10 +184,4 @@ class SpotifyViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO
|
||||
Log.i("Requesting","https://api.spotify.com/v1/playlists/$link/tracks?offset=$offset&limit=$limit")
|
||||
return spotifyService?.getPlaylistTracks(link, offset, limit)?.value
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
viewModelJob.cancel()
|
||||
}
|
||||
|
||||
}
|
@ -37,7 +37,7 @@ import com.shabinder.spotiflyer.downloadHelper.YTDownloadHelper
|
||||
import com.shabinder.spotiflyer.models.DownloadStatus
|
||||
import com.shabinder.spotiflyer.models.TrackDetails
|
||||
import com.shabinder.spotiflyer.models.spotify.Source
|
||||
import com.shabinder.spotiflyer.recyclerView.YoutubeTrackListAdapter
|
||||
import com.shabinder.spotiflyer.recyclerView.TrackListAdapter
|
||||
import com.shabinder.spotiflyer.utils.*
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -51,7 +51,7 @@ class YoutubeFragment : Fragment() {
|
||||
private lateinit var viewModel: YoutubeViewModel
|
||||
private lateinit var sharedViewModel: SharedViewModel
|
||||
@Inject lateinit var ytDownloader: YoutubeDownloader
|
||||
private lateinit var adapter : YoutubeTrackListAdapter
|
||||
private lateinit var adapter : TrackListAdapter
|
||||
private var intentFilter: IntentFilter? = null
|
||||
private var updateUIReceiver: BroadcastReceiver? = null
|
||||
private val sampleDomain2 = "youtu.be"
|
||||
@ -64,7 +64,7 @@ class YoutubeFragment : Fragment() {
|
||||
binding = DataBindingUtil.inflate(inflater,R.layout.track_list_fragment,container,false)
|
||||
viewModel = ViewModelProvider(this).get(YoutubeViewModel::class.java)
|
||||
sharedViewModel = ViewModelProvider(this.requireActivity()).get(SharedViewModel::class.java)
|
||||
adapter = YoutubeTrackListAdapter(viewModel)
|
||||
adapter = TrackListAdapter(viewModel)
|
||||
binding.trackList.adapter = adapter
|
||||
|
||||
initializeLiveDataObservers()
|
||||
@ -108,16 +108,16 @@ class YoutubeFragment : Fragment() {
|
||||
|
||||
rotateAnim(binding.downloadingFab)
|
||||
|
||||
for (track in viewModel.ytTrackList.value?: listOf()){
|
||||
for (track in viewModel.trackList.value?: listOf()){
|
||||
if(track.downloaded != DownloadStatus.Downloaded){
|
||||
track.downloaded = DownloadStatus.Downloading
|
||||
adapter.notifyItemChanged(viewModel.ytTrackList.value!!.indexOf(track))
|
||||
adapter.notifyItemChanged(viewModel.trackList.value!!.indexOf(track))
|
||||
}
|
||||
}
|
||||
showMessage("Processing!")
|
||||
sharedViewModel.uiScope.launch(Dispatchers.Default){
|
||||
val urlList = arrayListOf<String>()
|
||||
viewModel.ytTrackList.value?.forEach { urlList.add("https://i.ytimg.com/vi/${it.albumArt.absolutePath.substringAfterLast("/")
|
||||
viewModel.trackList.value?.forEach { urlList.add("https://i.ytimg.com/vi/${it.albumArt.absolutePath.substringAfterLast("/")
|
||||
.substringBeforeLast(".")}/hqdefault.jpg")}
|
||||
//Appending Source
|
||||
urlList.add("youtube")
|
||||
@ -130,7 +130,7 @@ class YoutubeFragment : Fragment() {
|
||||
YTDownloadHelper.downloadYTTracks(
|
||||
type = viewModel.folderType,
|
||||
subFolder = viewModel.subFolder,
|
||||
tracks = viewModel.ytTrackList.value ?: listOf()
|
||||
tracks = viewModel.trackList.value ?: listOf()
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -150,13 +150,13 @@ class YoutubeFragment : Fragment() {
|
||||
if (intent != null){
|
||||
val trackDetails = intent.getParcelableExtra<TrackDetails?>("track")
|
||||
trackDetails?.let {
|
||||
val position: Int = viewModel.ytTrackList.value?.map { it.title }?.indexOf(trackDetails.title) ?: -1
|
||||
val position: Int = viewModel.trackList.value?.map { it.title }?.indexOf(trackDetails.title) ?: -1
|
||||
Log.i("Track","Download Completed Intent :$position")
|
||||
if(position != -1) {
|
||||
val track = viewModel.ytTrackList.value?.get(position)
|
||||
val track = viewModel.trackList.value?.get(position)
|
||||
track?.let{
|
||||
it.downloaded = DownloadStatus.Downloaded
|
||||
viewModel.ytTrackList.value?.set(position, it)
|
||||
viewModel.trackList.value?.set(position, it)
|
||||
adapter.notifyItemChanged(position)
|
||||
checkIfAllDownloaded()
|
||||
}
|
||||
@ -174,7 +174,7 @@ class YoutubeFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun checkIfAllDownloaded() {
|
||||
if(!viewModel.ytTrackList.value!!.any { it.downloaded != DownloadStatus.Downloaded }){
|
||||
if(!viewModel.trackList.value!!.any { it.downloaded != DownloadStatus.Downloaded }){
|
||||
//All Tracks Downloaded
|
||||
binding.btnDownloadAll.visibility = View.GONE
|
||||
binding.downloadingFab.apply{
|
||||
@ -195,7 +195,7 @@ class YoutubeFragment : Fragment() {
|
||||
/**
|
||||
* TrackList Binding Observer!
|
||||
**/
|
||||
viewModel.ytTrackList.observe(viewLifecycleOwner, {
|
||||
viewModel.trackList.observe(viewLifecycleOwner, {
|
||||
adapter.submitList(it)
|
||||
})
|
||||
|
||||
|
@ -21,38 +21,31 @@ import android.annotation.SuppressLint
|
||||
import android.os.Environment
|
||||
import android.util.Log
|
||||
import androidx.hilt.lifecycle.ViewModelInject
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.github.kiulian.downloader.YoutubeDownloader
|
||||
import com.shabinder.spotiflyer.database.DatabaseDAO
|
||||
import com.shabinder.spotiflyer.database.DownloadRecord
|
||||
import com.shabinder.spotiflyer.models.DownloadStatus
|
||||
import com.shabinder.spotiflyer.models.TrackDetails
|
||||
import com.shabinder.spotiflyer.models.spotify.Source
|
||||
import com.shabinder.spotiflyer.utils.BaseViewModel
|
||||
import com.shabinder.spotiflyer.utils.Provider.defaultDir
|
||||
import com.shabinder.spotiflyer.utils.finalOutputDir
|
||||
import com.shabinder.spotiflyer.utils.removeIllegalChars
|
||||
import com.shabinder.spotiflyer.utils.showMessage
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
|
||||
class YoutubeViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO) : ViewModel(){
|
||||
|
||||
class YoutubeViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO) : BaseViewModel(){
|
||||
/*
|
||||
* YT Album Art Schema
|
||||
* HI-RES Url: https://i.ytimg.com/vi/$searchId/maxresdefault.jpg"
|
||||
* Normal Url: https://i.ytimg.com/vi/$searchId/hqdefault.jpg"
|
||||
* */
|
||||
|
||||
val ytTrackList = MutableLiveData<MutableList<TrackDetails>>()
|
||||
private val loading = "Loading"
|
||||
var title = MutableLiveData<String>().apply { value = "\"Loading!\"" }
|
||||
var coverUrl = MutableLiveData<String>().apply { value = loading }
|
||||
val folderType = "YT_Downloads"
|
||||
var subFolder = ""
|
||||
private var viewModelJob = Job()
|
||||
val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
|
||||
|
||||
override var folderType = "YT_Downloads"
|
||||
override var subFolder = ""
|
||||
|
||||
fun getYTPlaylist(searchId:String, ytDownloader:YoutubeDownloader){
|
||||
try{
|
||||
@ -67,7 +60,7 @@ class YoutubeViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO
|
||||
title.postValue(
|
||||
if(name.length > 17){"${name.subSequence(0,16)}..."}else{name}
|
||||
)
|
||||
ytTrackList.postValue(videos.map {
|
||||
this@YoutubeViewModel.trackList.postValue(videos.map {
|
||||
TrackDetails(
|
||||
title = it.title(),
|
||||
artists = listOf(it.author().toString()),
|
||||
@ -77,13 +70,13 @@ class YoutubeViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO
|
||||
defaultDir + ".Images/" + it.videoId() + ".jpeg"
|
||||
),
|
||||
source = Source.YouTube,
|
||||
albumArtURL = "https://i.ytimg.com/vi/${it.videoId()}/hqdefault.jpg",
|
||||
downloaded = if (File(
|
||||
finalOutputDir(
|
||||
itemName = it.title(),
|
||||
type = folderType,
|
||||
subFolder = subFolder
|
||||
)
|
||||
).exists()
|
||||
finalOutputDir(
|
||||
itemName = it.title(),
|
||||
type = folderType,
|
||||
subFolder = subFolder
|
||||
)).exists()
|
||||
)
|
||||
DownloadStatus.Downloaded
|
||||
else {
|
||||
@ -120,17 +113,18 @@ class YoutubeViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO
|
||||
val detail = video?.details()
|
||||
val name = detail?.title()?.replace(detail.author()!!.toUpperCase(),"",true) ?: detail?.title() ?: ""
|
||||
Log.i("YT View Model",detail.toString())
|
||||
ytTrackList.postValue(
|
||||
this@YoutubeViewModel.trackList.postValue(
|
||||
listOf(
|
||||
TrackDetails(
|
||||
title = name,
|
||||
artists = listOf(detail?.author().toString()),
|
||||
durationSec = detail?.lengthSeconds()?:0,
|
||||
albumArt = File(
|
||||
Environment.getExternalStorageDirectory(),
|
||||
defaultDir +".Images/" + searchId + ".jpeg"
|
||||
),
|
||||
source = Source.YouTube
|
||||
title = name,
|
||||
artists = listOf(detail?.author().toString()),
|
||||
durationSec = detail?.lengthSeconds()?:0,
|
||||
albumArt = File(
|
||||
Environment.getExternalStorageDirectory(),
|
||||
"$defaultDir.Images/$searchId.jpeg"
|
||||
),
|
||||
source = Source.YouTube,
|
||||
albumArtURL = "https://i.ytimg.com/vi/$searchId/hqdefault.jpg"
|
||||
)
|
||||
).toMutableList()
|
||||
)
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Shabinder Singh
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.shabinder.spotiflyer.utils
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.shabinder.spotiflyer.models.TrackDetails
|
||||
import kotlinx.coroutines.CompletableJob
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
|
||||
abstract class BaseViewModel:ViewModel() {
|
||||
abstract var folderType:String
|
||||
abstract var subFolder:String
|
||||
open val trackList = MutableLiveData<MutableList<TrackDetails>>()
|
||||
private val viewModelJob:CompletableJob = Job()
|
||||
open val uiScope = CoroutineScope(Dispatchers.Default + viewModelJob)
|
||||
|
||||
private val loading = "Loading!"
|
||||
open var title = MutableLiveData<String>().apply { value = loading }
|
||||
open var coverUrl = MutableLiveData<String>().apply { value = loading }
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
viewModelJob.cancel()
|
||||
}
|
||||
}
|
@ -49,7 +49,7 @@ import javax.inject.Singleton
|
||||
@Module
|
||||
object Provider {
|
||||
|
||||
val activity: MainActivity = MainActivity.getInstance()
|
||||
val mainActivity: MainActivity = MainActivity.getInstance()
|
||||
val defaultDir = Environment.DIRECTORY_MUSIC + File.separator + "SpotiFlyer" + File.separator
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@ object Provider {
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideUpi():EasyUpiPayment {
|
||||
return EasyUpiPayment.Builder(activity)
|
||||
return EasyUpiPayment.Builder(mainActivity)
|
||||
.setPayeeVpa("technoshab@paytm")
|
||||
.setPayeeName("Shabinder Singh")
|
||||
.setTransactionId("UNIQUE_TRANSACTION_ID")
|
||||
|
@ -41,13 +41,12 @@ import com.google.android.material.snackbar.Snackbar
|
||||
import com.shabinder.spotiflyer.R
|
||||
import com.shabinder.spotiflyer.models.DownloadObject
|
||||
import com.shabinder.spotiflyer.models.spotify.Source
|
||||
import com.shabinder.spotiflyer.utils.Provider.activity
|
||||
import com.shabinder.spotiflyer.utils.Provider.defaultDir
|
||||
import com.shabinder.spotiflyer.utils.Provider.mainActivity
|
||||
import com.shabinder.spotiflyer.worker.ForegroundService
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
@ -77,7 +76,7 @@ fun finalOutputDir(itemName:String? = null,type:String, subFolder:String?=null,e
|
||||
fun isOnline(): Boolean {
|
||||
var result = false
|
||||
val connectivityManager =
|
||||
activity.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
|
||||
mainActivity.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
|
||||
connectivityManager?.let {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
it.getNetworkCapabilities(connectivityManager.activeNetwork)?.apply {
|
||||
@ -90,7 +89,7 @@ fun isOnline(): Boolean {
|
||||
}
|
||||
} else {
|
||||
val netInfo =
|
||||
(activity.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).activeNetworkInfo
|
||||
(mainActivity.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).activeNetworkInfo
|
||||
result = netInfo != null && netInfo.isConnected
|
||||
}
|
||||
}
|
||||
@ -100,12 +99,12 @@ fun isOnline(): Boolean {
|
||||
fun showMessage(message: String, long: Boolean = false){
|
||||
CoroutineScope(Dispatchers.Main).launch{
|
||||
Snackbar.make(
|
||||
activity.snackBarAnchor,
|
||||
mainActivity.snackBarAnchor,
|
||||
message,
|
||||
if (long) Snackbar.LENGTH_LONG else Snackbar.LENGTH_SHORT
|
||||
).also { snackbar ->
|
||||
snackbar.setAction("Ok") {
|
||||
snackbar.dismiss()
|
||||
).apply {
|
||||
setAction("Ok") {
|
||||
dismiss()
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
@ -126,7 +125,7 @@ fun rotateAnim(view: View){
|
||||
|
||||
fun showNoConnectionAlert(){
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
activity.apply {
|
||||
mainActivity.apply {
|
||||
MaterialAlertDialogBuilder(this, R.style.AlertDialogTheme)
|
||||
.setTitle(resources.getString(R.string.title))
|
||||
.setMessage(resources.getString(R.string.supporting_text))
|
||||
@ -187,13 +186,10 @@ fun bindImage(imgView: ImageView, imgUrl: String?,source: Source?) {
|
||||
}
|
||||
// the File to save , append increasing numeric counter to prevent files from getting overwritten.
|
||||
resource?.copyTo(file)
|
||||
withContext(Dispatchers.Main){
|
||||
Glide.with(imgView)
|
||||
.load(file)
|
||||
.placeholder(R.drawable.ic_song_placeholder)
|
||||
.into(imgView)
|
||||
// Log.i("Glide","imageSaved")
|
||||
}
|
||||
Glide.with(imgView)
|
||||
.load(file)
|
||||
.placeholder(R.drawable.ic_song_placeholder)
|
||||
.into(imgView)
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
@ -22,15 +22,6 @@
|
||||
android:id="@+id/navigation"
|
||||
app:startDestination="@id/mainFragment">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/spotifyFragment"
|
||||
android:name="com.shabinder.spotiflyer.ui.spotify.SpotifyFragment"
|
||||
android:label="main_fragment"
|
||||
tools:layout="@layout/track_list_fragment" >
|
||||
<argument
|
||||
android:name="link"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/mainFragment"
|
||||
android:name="com.shabinder.spotiflyer.ui.mainfragment.MainFragment"
|
||||
@ -51,16 +42,11 @@
|
||||
app:destination="@id/downloadRecord"
|
||||
app:enterAnim="@android:anim/slide_in_left"
|
||||
app:exitAnim="@android:anim/slide_out_right" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_gaanaFragment"
|
||||
app:destination="@id/gaanaFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/youtubeFragment"
|
||||
android:name="com.shabinder.spotiflyer.ui.youtube.YoutubeFragment"
|
||||
android:label="YoutubeFragment"
|
||||
tools:layout="@layout/track_list_fragment">
|
||||
<argument
|
||||
android:name="link"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/downloadRecord"
|
||||
android:name="com.shabinder.spotiflyer.ui.downloadrecord.DownloadRecordFragment"
|
||||
@ -76,5 +62,35 @@
|
||||
app:destination="@id/youtubeFragment"
|
||||
app:enterAnim="@android:anim/slide_in_left"
|
||||
app:exitAnim="@android:anim/slide_out_right"/>
|
||||
<action
|
||||
android:id="@+id/action_downloadRecord_to_gaanaFragment"
|
||||
app:destination="@id/gaanaFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/spotifyFragment"
|
||||
android:name="com.shabinder.spotiflyer.ui.spotify.SpotifyFragment"
|
||||
android:label="main_fragment"
|
||||
tools:layout="@layout/track_list_fragment" >
|
||||
<argument
|
||||
android:name="link"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/youtubeFragment"
|
||||
android:name="com.shabinder.spotiflyer.ui.youtube.YoutubeFragment"
|
||||
android:label="YoutubeFragment"
|
||||
tools:layout="@layout/track_list_fragment">
|
||||
<argument
|
||||
android:name="link"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/gaanaFragment"
|
||||
android:name="com.shabinder.spotiflyer.ui.gaana.GaanaFragment"
|
||||
android:label="GaanaFragment"
|
||||
tools:layout="@layout/track_list_fragment">
|
||||
<argument
|
||||
android:name="link"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
</navigation>
|
Loading…
Reference in New Issue
Block a user