Progress Showing Improvements.

This commit is contained in:
Shabinder 2020-12-01 12:28:36 +05:30
parent e1d88da580
commit 2e40db5452
6 changed files with 215 additions and 90 deletions

View File

@ -35,10 +35,8 @@ import com.shabinder.spotiflyer.models.TrackDetails
import com.shabinder.spotiflyer.models.spotify.Source
import com.shabinder.spotiflyer.recyclerView.TrackListAdapter
import com.shabinder.spotiflyer.ui.base.BaseFragment
import com.shabinder.spotiflyer.utils.*
import com.shabinder.spotiflyer.utils.Provider.mainActivity
import com.shabinder.spotiflyer.utils.bindImage
import com.shabinder.spotiflyer.utils.isOnline
import com.shabinder.spotiflyer.utils.showNoConnectionAlert
import com.tonyodev.fetch2.Status
abstract class TrackListFragment<VM : TrackListViewModel, args: NavArgs> : BaseFragment<TrackListFragmentBinding,VM>() {
@ -48,6 +46,7 @@ abstract class TrackListFragment<VM : TrackListViewModel, args: NavArgs> : BaseF
protected abstract var source: Source
private var intentFilter: IntentFilter? = null
private var updateUIReceiver: BroadcastReceiver? = null
private var queryReceiver: BroadcastReceiver? = null
protected abstract val args:NavArgs
override fun onCreate(savedInstanceState: Bundle?) {
@ -87,7 +86,7 @@ abstract class TrackListFragment<VM : TrackListViewModel, args: NavArgs> : BaseF
if (!it.isNullOrEmpty()){
Log.i("GaanaFragment","TrackList Updated")
adapter.submitList(it, source)
checkIfAllDownloaded()
updateTracksStatus()
}
})
@ -101,14 +100,14 @@ abstract class TrackListFragment<VM : TrackListViewModel, args: NavArgs> : BaseF
}
private fun initializeBroadcast() {
intentFilter = IntentFilter()
intentFilter?.addAction(Status.QUEUED.name)
intentFilter?.addAction(Status.FAILED.name)
intentFilter?.addAction(Status.DOWNLOADING.name)
intentFilter?.addAction("Progress")
intentFilter?.addAction("Converting")
intentFilter?.addAction("track_download_completed")
intentFilter = IntentFilter().apply {
addAction(Status.QUEUED.name)
addAction(Status.FAILED.name)
addAction(Status.DOWNLOADING.name)
addAction("Progress")
addAction("Converting")
addAction("track_download_completed")
}
updateUIReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
//UI update here
@ -145,7 +144,28 @@ abstract class TrackListFragment<VM : TrackListViewModel, args: NavArgs> : BaseF
}
viewModel.trackList.value?.set(position, it)
adapter.notifyItemChanged(position)
checkIfAllDownloaded()
updateTracksStatus()
}
}
}
}
}
}
val queryFilter = IntentFilter().apply { addAction("query_result") }
queryReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
//UI update here
if (intent != null){
val trackList = intent.getParcelableArrayListExtra<TrackDetails?>("tracks") ?: listOf()
Log.i("Service Response", "${trackList.size} Tracks Active")
for (trackDetails in trackList) {
trackDetails?.let { it ->
val position: Int = viewModel.trackList.value?.map { it.title }?.indexOf(trackDetails.title) ?: -1
Log.i("BroadCast Received","$position, ${it.downloaded} , ${trackDetails.title}")
if(position != -1) {
viewModel.trackList.value?.set(position,it)
adapter.notifyItemChanged(position)
updateTracksStatus()
}
}
}
@ -153,6 +173,7 @@ abstract class TrackListFragment<VM : TrackListViewModel, args: NavArgs> : BaseF
}
}
requireActivity().registerReceiver(updateUIReceiver, intentFilter)
requireActivity().registerReceiver(queryReceiver, queryFilter)
}
override fun onResume() {
@ -163,10 +184,25 @@ abstract class TrackListFragment<VM : TrackListViewModel, args: NavArgs> : BaseF
override fun onPause() {
super.onPause()
requireActivity().unregisterReceiver(updateUIReceiver)
requireActivity().unregisterReceiver(queryReceiver)
}
private fun checkIfAllDownloaded() {
if(!viewModel.trackList.value!!.any { it.downloaded == DownloadStatus.NotDownloaded || it.downloaded == DownloadStatus.Queued || it.downloaded == DownloadStatus.Converting }){
//All Tracks Downloaded
private fun updateTracksStatus() {
var allDownloaded = true
var allProcessing = true
for (track in viewModel.trackList.value!!){
if(track.downloaded != DownloadStatus.Downloaded)allDownloaded = false
if(track.downloaded == DownloadStatus.NotDownloaded)allProcessing = false
}
if(allProcessing){
binding.btnDownloadAll.visibility = View.GONE
binding.downloadingFab.apply{
setImageResource(R.drawable.ic_refresh)
visible()
rotate()
}
}
if(allDownloaded){
binding.btnDownloadAll.visibility = View.GONE
binding.downloadingFab.apply{
setImageResource(R.drawable.ic_tick)

View File

@ -29,6 +29,7 @@ import com.shabinder.spotiflyer.networking.GaanaInterface
import com.shabinder.spotiflyer.ui.base.tracklistbase.TrackListViewModel
import com.shabinder.spotiflyer.utils.Provider
import com.shabinder.spotiflyer.utils.finalOutputDir
import com.shabinder.spotiflyer.utils.queryActiveTracks
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -45,67 +46,98 @@ class GaanaViewModel @ViewModelInject constructor(
private val gaanaPlaceholderImageUrl = "https://a10.gaanacdn.com/images/social/gaana_social.jpg"
fun gaanaSearch(type:String,link:String){
when(type){
"song" -> {
viewModelScope.launch {
gaanaInterface.getGaanaSong(seokey = link).value?.tracks?.firstOrNull()?.also {
viewModelScope.launch {
when (type) {
"song" -> {
gaanaInterface.getGaanaSong(seokey = link).value?.tracks?.firstOrNull()?.also {
folderType = "Tracks"
if(File(finalOutputDir(it.track_title,folderType,subFolder)).exists()){//Download Already Present!!
if (File(
finalOutputDir(
it.track_title,
folderType,
subFolder
)
).exists()
) {//Download Already Present!!
it.downloaded = DownloadStatus.Downloaded
}
trackList.value = listOf(it).toTrackDetailsList()
title.value = it.track_title
coverUrl.value = it.artworkLink
withContext(Dispatchers.IO){
withContext(Dispatchers.IO) {
databaseDAO.insert(
DownloadRecord(
type = "Track",
name = title.value!!,
link = "https://gaana.com/$type/$link",
coverUrl = coverUrl.value!!,
totalFiles = 1,
downloaded = it.downloaded == DownloadStatus.Downloaded,
directory = finalOutputDir(it.track_title,folderType,subFolder)
)
type = "Track",
name = title.value!!,
link = "https://gaana.com/$type/$link",
coverUrl = coverUrl.value!!,
totalFiles = 1,
downloaded = it.downloaded == DownloadStatus.Downloaded,
directory = finalOutputDir(
it.track_title,
folderType,
subFolder
)
)
)
}
}
}
}
"album" -> {
viewModelScope.launch {
"album" -> {
gaanaInterface.getGaanaAlbum(seokey = link).value?.also {
folderType = "Albums"
subFolder = link
it.tracks.forEach { track ->
if(File(finalOutputDir(track.track_title,folderType,subFolder)).exists()){//Download Already Present!!
if (File(
finalOutputDir(
track.track_title,
folderType,
subFolder
)
).exists()
) {//Download Already Present!!
track.downloaded = DownloadStatus.Downloaded
}
}
trackList.value = it.tracks.toTrackDetailsList()
title.value = link
coverUrl.value = it.custom_artworks.size_480p
withContext(Dispatchers.IO){
databaseDAO.insert(DownloadRecord(
type = "Album",
name = title.value!!,
link = "https://gaana.com/$type/$link",
coverUrl = coverUrl.value.toString(),
totalFiles = trackList.value?.size ?: 0,
downloaded = File(finalOutputDir(type = folderType,subFolder = subFolder)).listFiles()?.size == trackList.value?.size,
directory = finalOutputDir(type = folderType,subFolder = subFolder)
))
withContext(Dispatchers.IO) {
databaseDAO.insert(
DownloadRecord(
type = "Album",
name = title.value!!,
link = "https://gaana.com/$type/$link",
coverUrl = coverUrl.value.toString(),
totalFiles = trackList.value?.size ?: 0,
downloaded = File(
finalOutputDir(
type = folderType,
subFolder = subFolder
)
).listFiles()?.size == trackList.value?.size,
directory = finalOutputDir(
type = folderType,
subFolder = subFolder
)
)
)
}
}
}
}
"playlist" -> {
viewModelScope.launch {
"playlist" -> {
gaanaInterface.getGaanaPlaylist(seokey = link).value?.also {
folderType = "Playlists"
subFolder = link
it.tracks.forEach {track ->
if(File(finalOutputDir(track.track_title,folderType,subFolder)).exists()){//Download Already Present!!
it.tracks.forEach { track ->
if (File(
finalOutputDir(
track.track_title,
folderType,
subFolder
)
).exists()
) {//Download Already Present!!
track.downloaded = DownloadStatus.Downloaded
}
}
@ -113,49 +145,77 @@ class GaanaViewModel @ViewModelInject constructor(
title.value = link
//coverUrl.value = "TODO"
coverUrl.value = gaanaPlaceholderImageUrl
withContext(Dispatchers.IO){
databaseDAO.insert(DownloadRecord(
type = "Playlist",
name = title.value.toString(),
link = "https://gaana.com/$type/$link",
coverUrl = coverUrl.value.toString(),
totalFiles = it.tracks.size,
downloaded = File(finalOutputDir(type = folderType,subFolder = subFolder)).listFiles()?.size == trackList.value?.size,
directory = finalOutputDir(type = folderType,subFolder = subFolder)
))
withContext(Dispatchers.IO) {
databaseDAO.insert(
DownloadRecord(
type = "Playlist",
name = title.value.toString(),
link = "https://gaana.com/$type/$link",
coverUrl = coverUrl.value.toString(),
totalFiles = it.tracks.size,
downloaded = File(
finalOutputDir(
type = folderType,
subFolder = subFolder
)
).listFiles()?.size == trackList.value?.size,
directory = finalOutputDir(
type = folderType,
subFolder = subFolder
)
)
)
}
}
}
}
"artist" -> {
viewModelScope.launch {
"artist" -> {
folderType = "Artist"
subFolder = link
val artistDetails = gaanaInterface.getGaanaArtistDetails(seokey = link).value?.artist?.firstOrNull()?.also {
title.value = it.name
coverUrl.value = it.artworkLink
}
val artistDetails =
gaanaInterface.getGaanaArtistDetails(seokey = link).value?.artist?.firstOrNull()
?.also {
title.value = it.name
coverUrl.value = it.artworkLink
}
gaanaInterface.getGaanaArtistTracks(seokey = link).value?.also {
it.tracks.forEach {track ->
if(File(finalOutputDir(track.track_title,folderType,subFolder)).exists()){//Download Already Present!!
it.tracks.forEach { track ->
if (File(
finalOutputDir(
track.track_title,
folderType,
subFolder
)
).exists()
) {//Download Already Present!!
track.downloaded = DownloadStatus.Downloaded
}
}
trackList.value = it.tracks.toTrackDetailsList()
withContext(Dispatchers.IO){
databaseDAO.insert(DownloadRecord(
type = "Artist",
name = artistDetails?.name ?: link,
link = "https://gaana.com/$type/$link",
coverUrl = coverUrl.value.toString(),
totalFiles = trackList.value?.size ?: 0,
downloaded = File(finalOutputDir(type = folderType,subFolder = subFolder)).listFiles()?.size == trackList.value?.size,
directory = finalOutputDir(type = folderType,subFolder = subFolder)
))
withContext(Dispatchers.IO) {
databaseDAO.insert(
DownloadRecord(
type = "Artist",
name = artistDetails?.name ?: link,
link = "https://gaana.com/$type/$link",
coverUrl = coverUrl.value.toString(),
totalFiles = trackList.value?.size ?: 0,
downloaded = File(
finalOutputDir(
type = folderType,
subFolder = subFolder
)
).listFiles()?.size == trackList.value?.size,
directory = finalOutputDir(
type = folderType,
subFolder = subFolder
)
)
)
}
}
}
}
queryActiveTracks()
}
}

View File

@ -33,6 +33,7 @@ import com.shabinder.spotiflyer.networking.SpotifyService
import com.shabinder.spotiflyer.ui.base.tracklistbase.TrackListViewModel
import com.shabinder.spotiflyer.utils.Provider.imageDir
import com.shabinder.spotiflyer.utils.finalOutputDir
import com.shabinder.spotiflyer.utils.queryActiveTracks
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -199,6 +200,7 @@ class SpotifyViewModel @ViewModelInject constructor(
"show" -> {//TODO
}
}
queryActiveTracks()
}
}

View File

@ -28,11 +28,8 @@ import com.shabinder.spotiflyer.models.DownloadStatus
import com.shabinder.spotiflyer.models.TrackDetails
import com.shabinder.spotiflyer.models.spotify.Source
import com.shabinder.spotiflyer.ui.base.tracklistbase.TrackListViewModel
import com.shabinder.spotiflyer.utils.*
import com.shabinder.spotiflyer.utils.Provider.imageDir
import com.shabinder.spotiflyer.utils.finalOutputDir
import com.shabinder.spotiflyer.utils.isOnline
import com.shabinder.spotiflyer.utils.removeIllegalChars
import com.shabinder.spotiflyer.utils.showMessage
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -100,6 +97,7 @@ class YoutubeViewModel @ViewModelInject constructor(
downloaded = File(finalOutputDir(itemName = removeIllegalChars(name),type = folderType,subFolder = subFolder)).exists()
))
}
queryActiveTracks()
}
}catch (e:com.github.kiulian.downloader.YoutubeException.BadPageException){
showMessage("An Error Occurred While Processing!")
@ -145,6 +143,7 @@ class YoutubeViewModel @ViewModelInject constructor(
directory = finalOutputDir(type = "YT_Downloads")
))
}
queryActiveTracks()
}
} catch (e:com.github.kiulian.downloader.YoutubeException){
showMessage("An Error Occurred While Processing!")

View File

@ -52,11 +52,17 @@ fun loadAllImages(context: Context?, images:List<String>? = null,source:Source)
context?.let { ContextCompat.startForegroundService(it, serviceIntent) }
}
fun startService(context:Context?,objects:ArrayList<DownloadObject>? = null ) {
fun startService(context:Context? = mainActivity,objects:ArrayList<DownloadObject>? = null ) {
val serviceIntent = Intent(context, ForegroundService::class.java)
objects?.let { serviceIntent.putParcelableArrayListExtra("object",it) }
context?.let { ContextCompat.startForegroundService(it, serviceIntent) }
}
fun queryActiveTracks(context:Context? = mainActivity) {
val serviceIntent = Intent(context, ForegroundService::class.java).apply {
action = "query"
}
context?.let { ContextCompat.startForegroundService(it, serviceIntent) }
}
fun finalOutputDir(itemName:String? = null,type:String, subFolder:String?=null,extension:String? = ".mp3"): String{
return defaultDir + removeIllegalChars(type) + File.separator +

View File

@ -47,6 +47,7 @@ import com.mpatric.mp3agic.ID3v24Tag
import com.mpatric.mp3agic.Mp3File
import com.shabinder.spotiflyer.R
import com.shabinder.spotiflyer.models.DownloadObject
import com.shabinder.spotiflyer.models.DownloadStatus
import com.shabinder.spotiflyer.models.TrackDetails
import com.shabinder.spotiflyer.models.spotify.Source
import com.shabinder.spotiflyer.utils.Provider
@ -73,11 +74,12 @@ class ForegroundService : Service(){
private var serviceJob = Job()
private val serviceScope = CoroutineScope(Dispatchers.IO + serviceJob)
private val requestMap = mutableMapOf<Request, TrackDetails>()
private val allTracksDetails = mutableListOf<TrackDetails>()
private var defaultDir = Provider.defaultDir
private var wakeLock: PowerManager.WakeLock? = null
private var isServiceStarted = false
var notificationLine = 0
var messageList = mutableListOf("", "", "", "")
private var notificationLine = 0
private var messageList = mutableListOf("", "", "", "")
private var cancelIntent:PendingIntent? = null
override fun onBind(intent: Intent): IBinder? = null
@ -103,6 +105,14 @@ class ForegroundService : Service(){
if(intent.action == "kill") killService()
if(intent.action == "query"){
val response = Intent().apply {
action = "query_result"
putParcelableArrayListExtra("tracks", allTracksDetails as ArrayList<TrackDetails> )
}
sendBroadcast(response)
}
val downloadObjects: ArrayList<DownloadObject>? = (intent.getParcelableArrayListExtra("object") ?: intent.extras?.getParcelableArrayList(
"object"
))
@ -119,6 +129,9 @@ class ForegroundService : Service(){
downloadObjects?.let {
total += downloadObjects.size
updateNotification()
it.forEach { it1 ->
allTracksDetails.add(it1.trackDetails.apply { downloaded = DownloadStatus.Queued })
}
downloadAllTracks(downloadObjects)
}
@ -207,7 +220,6 @@ class ForegroundService : Service(){
download: Download,
waitingOnNetwork: Boolean
) {
//Notify Download Completed
val intent = Intent()
.setAction(Status.QUEUED.name)
.putExtra("track", requestMap[download.request])
@ -247,10 +259,14 @@ class ForegroundService : Service(){
}
}
Log.i(tag, "${track?.title} Download Started")
track?.let{
allTracksDetails[allTracksDetails.map{ trackDetails -> trackDetails.title}.indexOf(it.title)] =
it.apply { downloaded = DownloadStatus.Downloading }
}
updateNotification()
val intent = Intent()
.setAction(Status.DOWNLOADING.name)
.putExtra("track", requestMap[download.request])
.putExtra("track", track)
this@ForegroundService.sendBroadcast(intent)
}
@ -277,7 +293,11 @@ class ForegroundService : Service(){
serviceScope.launch {
try{
track?.let { convertToMp3(download.file, it) }
track?.let {
convertToMp3(download.file, it)
allTracksDetails[allTracksDetails.map{ trackDetails -> trackDetails.title}.indexOf(it.title)] =
it.apply { downloaded = DownloadStatus.Converting }
}
Log.i(tag, "${track?.title} Download Completed")
}catch (
e: KotlinNullPointerException
@ -360,6 +380,8 @@ class ForegroundService : Service(){
val id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
//Checking if the received broadcast is for our enqueued download by matching download id
if (downloadID == id) {
allTracksDetails[allTracksDetails.map{ trackDetails -> trackDetails.title}.indexOf(track.title)] =
track.apply { downloaded = DownloadStatus.Converting }
convertToMp3(outputDir, track)
converted++
//Unregister this broadcast Receiver
@ -419,7 +441,7 @@ class ForegroundService : Service(){
newFile.renameTo(file)
converted++
updateNotification()
allTracksDetails.removeAt(allTracksDetails.map{ trackDetails -> trackDetails.title}.indexOf(track.title))
//Notify Download Completed
val intent = Intent()
.setAction("track_download_completed")
@ -689,4 +711,4 @@ class ForegroundService : Service(){
//Starting fresh
fetch.removeAll()
}
}
}