diff --git a/app/build.gradle b/app/build.gradle index 368332d8..436d8c12 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -89,10 +89,10 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7" implementation "androidx.room:room-runtime:2.2.5" - implementation project(path: ':mobile-ffmpeg') - implementation 'androidx.legacy:legacy-support-v4:1.0.0' kapt "androidx.room:room-compiler:2.2.5" implementation "androidx.room:room-ktx:2.2.5" + implementation project(path: ':mobile-ffmpeg') + implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation ("com.github.bumptech.glide:recyclerview-integration:4.11.0") { transitive = true } diff --git a/app/src/main/java/com/shabinder/spotiflyer/database/DatabaseDAO.kt b/app/src/main/java/com/shabinder/spotiflyer/database/DatabaseDAO.kt new file mode 100644 index 00000000..6cc02c97 --- /dev/null +++ b/app/src/main/java/com/shabinder/spotiflyer/database/DatabaseDAO.kt @@ -0,0 +1,35 @@ +/* + * 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 . + */ + +package com.shabinder.spotiflyer.database + +import androidx.room.* + +@Dao +interface DatabaseDAO { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(record: DownloadRecord) + + @Update + fun update(record: DownloadRecord) + + @Query("SELECT * from download_record_table ORDER BY id DESC") + suspend fun getRecord():List + + @Query("DELETE FROM download_record_table") + suspend fun deleteAll() +} \ No newline at end of file diff --git a/app/src/main/java/com/shabinder/spotiflyer/database/DownloadRecord.kt b/app/src/main/java/com/shabinder/spotiflyer/database/DownloadRecord.kt new file mode 100644 index 00000000..2f69c9e1 --- /dev/null +++ b/app/src/main/java/com/shabinder/spotiflyer/database/DownloadRecord.kt @@ -0,0 +1,57 @@ +/* + * 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 . + */ + +package com.shabinder.spotiflyer.database + +import android.os.Parcelable +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.Index +import androidx.room.PrimaryKey +import kotlinx.android.parcel.Parcelize + +@Parcelize +@Entity( + tableName = "download_record_table", + indices = [Index(value = ["id","link"], unique = true)] +) +data class DownloadRecord( + + @PrimaryKey(autoGenerate = true) + var id:Int = 0, + + @ColumnInfo(name = "type") + var type:String, + + @ColumnInfo(name = "name") + var name:String, + + @ColumnInfo(name = "link") + var link:String, + + @ColumnInfo(name = "coverUrl") + var coverUrl:String, + + @ColumnInfo(name = "totalFiles") + var totalFiles:Int = 1, + + @ColumnInfo(name = "downloaded") + var downloaded:Boolean=false, + + @ColumnInfo(name = "directory") + var directory:String?=null +):Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/shabinder/spotiflyer/database/DownloadRecordDatabase.kt b/app/src/main/java/com/shabinder/spotiflyer/database/DownloadRecordDatabase.kt new file mode 100644 index 00000000..17637597 --- /dev/null +++ b/app/src/main/java/com/shabinder/spotiflyer/database/DownloadRecordDatabase.kt @@ -0,0 +1,56 @@ +/* + * 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 . + */ + +package com.shabinder.spotiflyer.database + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase + +@Database(entities = [DownloadRecord::class], version = 1, exportSchema = false) +abstract class DownloadRecordDatabase:RoomDatabase() { + + abstract val databaseDAO: DatabaseDAO + + companion object { + @Volatile + private var INSTANCE: DownloadRecordDatabase? = null + + fun getInstance(context: Context): DownloadRecordDatabase { + synchronized(this) { + var instance = INSTANCE + if (instance == null) { + instance = Room.databaseBuilder( + context.applicationContext, + DownloadRecordDatabase::class.java, + "download_record_database") + .fallbackToDestructiveMigration() + .build() + + INSTANCE = instance + } + + return instance + } + + } + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/shabinder/spotiflyer/downloadHelper/SpotifyDownloadHelper.kt b/app/src/main/java/com/shabinder/spotiflyer/downloadHelper/SpotifyDownloadHelper.kt index 90c9cc1e..afe24cbf 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/downloadHelper/SpotifyDownloadHelper.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/downloadHelper/SpotifyDownloadHelper.kt @@ -34,10 +34,10 @@ import androidx.core.content.ContextCompat import com.github.kiulian.downloader.YoutubeDownloader import com.github.kiulian.downloader.model.formats.Format import com.github.kiulian.downloader.model.quality.AudioQuality -import com.shabinder.spotiflyer.SharedViewModel import com.shabinder.spotiflyer.models.DownloadObject import com.shabinder.spotiflyer.models.Track import com.shabinder.spotiflyer.ui.spotify.SpotifyFragment +import com.shabinder.spotiflyer.ui.spotify.SpotifyViewModel import com.shabinder.spotiflyer.worker.ForegroundService import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -49,7 +49,7 @@ object SpotifyDownloadHelper { var context : Context? = null var statusBar:TextView? = null val defaultDir = Environment.DIRECTORY_MUSIC + File.separator + "SpotiFlyer" + File.separator - var sharedViewModel:SharedViewModel? = null + var spotifyViewModel: SpotifyViewModel? = null private var isBrowserLoading = false private var total = 0 private var Processed = 0 @@ -66,9 +66,7 @@ object SpotifyDownloadHelper { withContext(Dispatchers.Main){ total += trackList.size // Adding New Download List Count to StatusBar trackList.forEach { - val outputFile:String = Environment.getExternalStorageDirectory().toString() + File.separator + - defaultDir + removeIllegalChars(type) + File.separator + (if(subFolder == null){""}else{ removeIllegalChars(subFolder) + File.separator} + removeIllegalChars(it.name!!)+".mp3") - if(File(outputFile).exists()){//Download Already Present!! + if(it.downloaded == "Downloaded"){//Download Already Present!! Processed++ }else{ if(isBrowserLoading){//WebView Busy!! @@ -124,7 +122,7 @@ object SpotifyDownloadHelper { } if(youtubeList.isNotEmpty()){ val request = youtubeList[0] - sharedViewModel!!.uiScope.launch { + spotifyViewModel!!.uiScope.launch { getYTLink(request.spotifyFragment,request.type,request.subFolder,request.ytDownloader,request.searchQuery,request.track) } youtubeList.remove(request) @@ -147,7 +145,7 @@ object SpotifyDownloadHelper { fun downloadFile(subFolder: String?, type: String, track:Track, ytDownloader: YoutubeDownloader?, id: String) { - sharedViewModel!!.uiScope.launch { + spotifyViewModel!!.uiScope.launch { withContext(Dispatchers.IO) { val video = ytDownloader?.getVideo(id) val detail = video?.details() diff --git a/app/src/main/java/com/shabinder/spotiflyer/downloadHelper/YTDownloadHelper.kt b/app/src/main/java/com/shabinder/spotiflyer/downloadHelper/YTDownloadHelper.kt new file mode 100644 index 00000000..92856c54 --- /dev/null +++ b/app/src/main/java/com/shabinder/spotiflyer/downloadHelper/YTDownloadHelper.kt @@ -0,0 +1,65 @@ +/* + * 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 . + */ + +package com.shabinder.spotiflyer.downloadHelper + +import android.content.Context +import android.content.Intent +import android.os.Environment +import android.util.Log +import android.view.View +import android.widget.TextView +import androidx.core.content.ContextCompat +import com.github.kiulian.downloader.model.formats.Format +import com.shabinder.spotiflyer.models.DownloadObject +import com.shabinder.spotiflyer.models.Track +import com.shabinder.spotiflyer.worker.ForegroundService +import java.io.File + +object YTDownloadHelper { + var context : Context? = null + var statusBar: TextView? = null + + fun downloadFile(subFolder: String?, type: String,ytTrack: Track,format: Format?) { + format?.let { + val url:String = format.url() +// Log.i("DHelper Link Found", url) + val outputFile:String = Environment.getExternalStorageDirectory().toString() + File.separator + + SpotifyDownloadHelper.defaultDir + SpotifyDownloadHelper.removeIllegalChars(type) + File.separator + (if(subFolder == null){""}else{ SpotifyDownloadHelper.removeIllegalChars(subFolder) + File.separator} + SpotifyDownloadHelper.removeIllegalChars( + ytTrack.name!! + ) +".m4a") + + val downloadObject = DownloadObject( + track = ytTrack, + url = url, + outputDir = outputFile + ) + Log.i("DH",outputFile) + startService(context!!, downloadObject) + statusBar?.visibility= View.VISIBLE + } + } + + + + private fun startService(context:Context, obj: DownloadObject? = null ) { + val serviceIntent = Intent(context, ForegroundService::class.java) + serviceIntent.putExtra("object",obj) + ContextCompat.startForegroundService(context, serviceIntent) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/shabinder/spotiflyer/models/Track.kt b/app/src/main/java/com/shabinder/spotiflyer/models/Track.kt index d16e764b..9ce8893c 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/models/Track.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/models/Track.kt @@ -40,4 +40,5 @@ data class Track( var album: Album? = null, var external_ids: Map? = null, var popularity: Int? = null, - var ytCoverUrl:String? = null):Parcelable \ No newline at end of file + var ytCoverUrl:String? = null, + var downloaded:String? = "notDownloaded"):Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/shabinder/spotiflyer/models/YTTrack.kt b/app/src/main/java/com/shabinder/spotiflyer/models/YTTrack.kt new file mode 100644 index 00000000..703a708b --- /dev/null +++ b/app/src/main/java/com/shabinder/spotiflyer/models/YTTrack.kt @@ -0,0 +1,31 @@ +/* + * 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 . + */ + +package com.shabinder.spotiflyer.models + +import android.os.Parcelable +import kotlinx.android.parcel.Parcelize + +@Parcelize +data class YTTrack( + var id:String?, + var title:String?, + var duration:Int?, + var author:String?, + var viewCount:Long?, + var thumbnails:List? +):Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/shabinder/spotiflyer/recyclerView/SpotifyTrackListAdapter.kt b/app/src/main/java/com/shabinder/spotiflyer/recyclerView/SpotifyTrackListAdapter.kt index 09cc1167..6d97dbd1 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/recyclerView/SpotifyTrackListAdapter.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/recyclerView/SpotifyTrackListAdapter.kt @@ -20,59 +20,84 @@ package com.shabinder.spotiflyer.recyclerView import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.ImageButton -import android.widget.ImageView -import android.widget.TextView +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.SharedViewModel +import com.shabinder.spotiflyer.databinding.TrackListItemBinding +import com.shabinder.spotiflyer.downloadHelper.SpotifyDownloadHelper.context import com.shabinder.spotiflyer.downloadHelper.SpotifyDownloadHelper.getYTLink import com.shabinder.spotiflyer.models.Track import com.shabinder.spotiflyer.ui.spotify.SpotifyFragment +import com.shabinder.spotiflyer.ui.spotify.SpotifyViewModel import com.shabinder.spotiflyer.utils.bindImage +import com.shabinder.spotiflyer.utils.rotateAnim import kotlinx.coroutines.launch -class SpotifyTrackListAdapter:RecyclerView.Adapter() { +class SpotifyTrackListAdapter: ListAdapter(SpotifyTrackDiffCallback()) { - var trackList = listOf() - var totalItems:Int = 0 - var sharedViewModel = SharedViewModel() + var spotifyViewModel = SpotifyViewModel() var isAlbum:Boolean = false var spotifyFragment: SpotifyFragment? = null - override fun getItemCount():Int = totalItems override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val layoutInflater = LayoutInflater.from(parent.context) - val view = layoutInflater.inflate(R.layout.track_list_item,parent,false) - return ViewHolder(view) + val binding = TrackListItemBinding.inflate(layoutInflater,parent,false) +// val view = layoutInflater.inflate(R.layout.track_list_item,parent,false) + return ViewHolder(binding) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { - val item = trackList[position] - if(totalItems == 1 || isAlbum){holder.coverImage.visibility = View.GONE}else{ - sharedViewModel.uiScope.launch { - bindImage(holder.coverImage, item.album!!.images?.get(0)?.url) + val item = getItem(position) + if(itemCount ==1 || isAlbum){ + holder.binding.imageUrl.visibility = View.GONE}else{ + spotifyViewModel.uiScope.launch { + bindImage(holder.binding.imageUrl, item.album!!.images?.get(0)?.url) } } - holder.trackName.text = "${if(item.name!!.length > 17){"${item.name!!.subSequence(0,16)}..."}else{item.name}}" - holder.artistName.text = "${item.artists?.get(0)?.name?:""}..." - holder.duration.text = "${item.duration_ms/1000/60} minutes, ${(item.duration_ms/1000)%60} sec" - holder.downloadBtn.setOnClickListener{ - sharedViewModel.uiScope.launch { - getYTLink(spotifyFragment,"Tracks",null,sharedViewModel.ytDownloader.value,"${item.name} ${item.artists?.get(0)!!.name?:""}",track = item) + 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) { + "Downloaded" -> { + holder.binding.btnDownload.setImageResource(R.drawable.ic_tick) + holder.binding.btnDownload.clearAnimation() + } + "Downloading" -> { + holder.binding.btnDownload.setImageResource(R.drawable.ic_refresh) + rotateAnim(holder.binding.btnDownload) + } + "notDownloaded" -> { + holder.binding.btnDownload.setImageResource(R.drawable.ic_arrow) + holder.binding.btnDownload.clearAnimation() + holder.binding.btnDownload.setOnClickListener{ + Toast.makeText(context,"Starting Download",Toast.LENGTH_SHORT).show() + holder.binding.btnDownload.setImageResource(R.drawable.ic_refresh) + rotateAnim(it) + item.downloaded = "Downloading" + spotifyViewModel.uiScope.launch { + getYTLink(spotifyFragment,"Tracks",null,spotifyViewModel.ytDownloader,"${item.name} ${item.artists?.get(0)!!.name?:""}",track = item) + } + notifyItemChanged(position) + } } } - } - class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){ - val trackName:TextView = itemView.findViewById(R.id.track_name) - val artistName:TextView = itemView.findViewById(R.id.artist) - val duration:TextView = itemView.findViewById(R.id.duration) - val downloadBtn:ImageButton = itemView.findViewById(R.id.btn_download) - val coverImage:ImageView = itemView.findViewById(R.id.imageUrl) - } + class ViewHolder(val binding: TrackListItemBinding) : RecyclerView.ViewHolder(binding.root) +} + +class SpotifyTrackDiffCallback: DiffUtil.ItemCallback(){ + 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 + } + } \ No newline at end of file diff --git a/app/src/main/java/com/shabinder/spotiflyer/recyclerView/YoutubeTrackListAdapter.kt b/app/src/main/java/com/shabinder/spotiflyer/recyclerView/YoutubeTrackListAdapter.kt new file mode 100644 index 00000000..4609e0b1 --- /dev/null +++ b/app/src/main/java/com/shabinder/spotiflyer/recyclerView/YoutubeTrackListAdapter.kt @@ -0,0 +1,76 @@ +/* + * 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 . + */ + +package com.shabinder.spotiflyer.recyclerView + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import com.github.kiulian.downloader.model.formats.Format +import com.shabinder.spotiflyer.SharedViewModel +import com.shabinder.spotiflyer.databinding.TrackListItemBinding +import com.shabinder.spotiflyer.downloadHelper.YTDownloadHelper +import com.shabinder.spotiflyer.models.Track +import com.shabinder.spotiflyer.utils.bindImage +import kotlinx.coroutines.launch + +class YoutubeTrackListAdapter: ListAdapter(YouTubeTrackDiffCallback()) { + + var format:Format? = null + var sharedViewModel = SharedViewModel() + + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): SpotifyTrackListAdapter.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) + } + + override fun onBindViewHolder(holder: SpotifyTrackListAdapter.ViewHolder, position: Int) { + val item = getItem(position) + if(itemCount == 1){ + holder.binding.imageUrl.visibility = View.GONE}else{ + sharedViewModel.uiScope.launch { + bindImage(holder.binding.imageUrl, item.ytCoverUrl) + } + } + + 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" + holder.binding.btnDownload.setOnClickListener{ + sharedViewModel.uiScope.launch { + YTDownloadHelper.downloadFile(null,"YT_Downloads",item,format) + } + } + } +} +class YouTubeTrackDiffCallback: DiffUtil.ItemCallback(){ + override fun areItemsTheSame(oldItem: Track, newItem: Track): Boolean { + return oldItem.name == newItem.name + } + + override fun areContentsTheSame(oldItem: Track, newItem: Track): Boolean { + return oldItem == newItem + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/shabinder/spotiflyer/ui/mainfragment/MainFragment.kt b/app/src/main/java/com/shabinder/spotiflyer/ui/mainfragment/MainFragment.kt new file mode 100644 index 00000000..13a34363 --- /dev/null +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/mainfragment/MainFragment.kt @@ -0,0 +1,165 @@ +/* + * 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 . + */ + +package com.shabinder.spotiflyer.ui.mainfragment + +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Bundle +import android.text.SpannableStringBuilder +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 androidx.navigation.fragment.findNavController +import com.shabinder.spotiflyer.R +import com.shabinder.spotiflyer.SharedViewModel +import com.shabinder.spotiflyer.databinding.MainFragmentBinding + +class MainFragment : Fragment() { + + private lateinit var viewModel: MainViewModel + private lateinit var sharedViewModel: SharedViewModel + private lateinit var binding: MainFragmentBinding + + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = DataBindingUtil.inflate(inflater,R.layout.main_fragment,container,false) + viewModel = ViewModelProvider(this).get(MainViewModel::class.java) + initializeAll() + + binding.btnSearch.setOnClickListener { + val link = binding.linkSearch.text.toString() + if (link.contains("spotify",true)){ + findNavController().navigate(MainFragmentDirections.actionMainFragmentToSpotifyFragment(link)) + }else if(link.contains("youtube.com",true) || link.contains("youtu.be",true) ){ + findNavController().navigate(MainFragmentDirections.actionMainFragmentToYoutubeFragment(link)) + }else{Toast.makeText(context,"Link is Not Valid",Toast.LENGTH_SHORT).show()} + } + handleIntent() + return binding.root + } + + private fun initializeAll() { + sharedViewModel = ViewModelProvider(this.requireActivity()).get(SharedViewModel::class.java) + setUpUsageText() + openYTButton() + openSpotifyButton() + openGithubButton() + openInstaButton() + openLinkedInButton() + binding.btnDonate.setOnClickListener { + sharedViewModel.easyUpiPayment?.startPayment() + } + + } + + /** + * Handle Intent If there is any! + **/ + private fun handleIntent() { + sharedViewModel.accessToken.observe(viewLifecycleOwner, Observer { + //Waiting for Authentication to Finish with Spotify()Access Token Observe + if (it != ""){ + if(sharedViewModel.intentString != ""){ + binding.linkSearch.setText(sharedViewModel.intentString) + binding.btnSearch.performClick() + sharedViewModel.intentString = "" + } + } + }) + } + + private fun setUpUsageText() { + val spanStringBuilder = SpannableStringBuilder() + spanStringBuilder.append(getText(R.string.d_one)).append("\n") + spanStringBuilder.append(getText(R.string.d_two)).append("\n") + spanStringBuilder.append(getText(R.string.d_three)).append("\n") + spanStringBuilder.append(getText(R.string.d_four)).append("\n") + binding.usage.text = spanStringBuilder + } + + + /** + * Implementing buttons + **/ + private fun openSpotifyButton() { + val manager: PackageManager = requireActivity().packageManager + try { + val i = manager.getLaunchIntentForPackage("com.spotify.music") + ?: throw PackageManager.NameNotFoundException() + i.addCategory(Intent.CATEGORY_LAUNCHER) + binding.btnSpotify.setOnClickListener { startActivity(i) } + } catch (e: PackageManager.NameNotFoundException) { + val uri: Uri = + Uri.parse("http://open.spotify.com") + val intent = Intent(Intent.ACTION_VIEW, uri) + binding.btnSpotify.setOnClickListener { + startActivity(intent) + } + } + } + private fun openYTButton() { + val manager: PackageManager = requireActivity().packageManager + try { + val i = manager.getLaunchIntentForPackage("com.google.android.youtube") + ?: throw PackageManager.NameNotFoundException() + i.addCategory(Intent.CATEGORY_LAUNCHER) + binding.btnYoutube.setOnClickListener { startActivity(i) } + } catch (e: PackageManager.NameNotFoundException) { + val uri: Uri = + Uri.parse("http://m.youtube.com") + val intent = Intent(Intent.ACTION_VIEW, uri) + binding.btnYoutube.setOnClickListener { + startActivity(intent) + } + } + } + private fun openGithubButton() { + val uri: Uri = + Uri.parse("http://github.com/Shabinder/SpotiFlyer") + val intent = Intent(Intent.ACTION_VIEW, uri) + binding.btnGithubSpotify.setOnClickListener { + startActivity(intent) + } + } + private fun openLinkedInButton() { + val uri: Uri = + Uri.parse("https://in.linkedin.com/in/shabinder") + val intent = Intent(Intent.ACTION_VIEW, uri) + binding.btnLinkedin.setOnClickListener { + startActivity(intent) + } + } + private fun openInstaButton() { + val uri: Uri = + Uri.parse("http://www.instagram.com/mr.shabinder") + val intent = Intent(Intent.ACTION_VIEW, uri) + binding.developerInstaSpotify.setOnClickListener { + startActivity(intent) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/shabinder/spotiflyer/ui/mainfragment/MainViewModel.kt b/app/src/main/java/com/shabinder/spotiflyer/ui/mainfragment/MainViewModel.kt new file mode 100644 index 00000000..46be4e6b --- /dev/null +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/mainfragment/MainViewModel.kt @@ -0,0 +1,24 @@ +/* + * 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 . + */ + +package com.shabinder.spotiflyer.ui.mainfragment + +import androidx.lifecycle.ViewModel + +class MainViewModel : ViewModel() { + // TODO: Implement the ViewModel +} \ No newline at end of file diff --git a/app/src/main/java/com/shabinder/spotiflyer/ui/spotify/SpotifyFragment.kt b/app/src/main/java/com/shabinder/spotiflyer/ui/spotify/SpotifyFragment.kt index 4b5f620f..ce530d8d 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/ui/spotify/SpotifyFragment.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/spotify/SpotifyFragment.kt @@ -18,7 +18,10 @@ package com.shabinder.spotiflyer.ui.spotify import android.annotation.SuppressLint +import android.content.BroadcastReceiver import android.content.Context +import android.content.Intent +import android.content.IntentFilter import android.net.ConnectivityManager import android.os.Bundle import android.os.Environment @@ -47,6 +50,7 @@ import com.shabinder.spotiflyer.models.Track import com.shabinder.spotiflyer.recyclerView.SpotifyTrackListAdapter import com.shabinder.spotiflyer.utils.bindImage import com.shabinder.spotiflyer.utils.copyTo +import com.shabinder.spotiflyer.utils.rotateAnim import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -60,6 +64,8 @@ class SpotifyFragment : Fragment() { private lateinit var sharedViewModel: SharedViewModel private lateinit var adapterSpotify:SpotifyTrackListAdapter private var webView: WebView? = null + private var intentFilter:IntentFilter? = null + private var updateUIReceiver: BroadcastReceiver? = null @SuppressLint("SetJavaScriptEnabled") @@ -71,6 +77,7 @@ class SpotifyFragment : Fragment() { adapterSpotify = SpotifyTrackListAdapter() initializeAll() initializeLiveDataObservers() + initializeBroadcast() val args = SpotifyFragmentArgs.fromBundle(requireArguments()) val spotifyLink = args.link @@ -95,6 +102,19 @@ class SpotifyFragment : Fragment() { spotifyViewModel.spotifySearch(type,link) if(type=="album")adapterSpotify.isAlbum = true binding.btnDownloadAllSpotify.setOnClickListener { + for (track in spotifyViewModel.trackList.value!!){ + if(track.downloaded != "Downloaded"){ + track.downloaded = "Downloading" + } + } + binding.btnDownloadAllSpotify.visibility = View.GONE + binding.downloadingFabSpotify.visibility = View.VISIBLE + rotateAnim(binding.downloadingFabSpotify) + for (track in spotifyViewModel.trackList.value!!){ + if(track.downloaded != "Downloaded"){ + adapterSpotify.notifyItemChanged(spotifyViewModel.trackList.value!!.indexOf(track)) + } + } showToast("Starting Download in Few Seconds") loadAllImages(spotifyViewModel.trackList.value!!) spotifyViewModel.uiScope.launch { @@ -111,6 +131,41 @@ class SpotifyFragment : Fragment() { return binding.root } + override fun onResume() { + super.onResume() + initializeBroadcast() + } + + private fun initializeBroadcast() { + intentFilter = IntentFilter() + intentFilter?.addAction("track_download_completed") + + updateUIReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + //UI update here + if (intent != null){ + val track = intent.getParcelableExtra("track") + track?.let { + val position: Int = spotifyViewModel.trackList.value?.indexOf(track)!! + Log.i("Track","Download Completed Intent :$position") + track.downloaded = "Downloaded" + if(position != -1) { + spotifyViewModel.trackList.value?.set(position, track) + adapterSpotify.notifyItemChanged(position) + checkIfAllDownloaded() + } + } + } + } + } + requireActivity().registerReceiver(updateUIReceiver, intentFilter) + } + + override fun onPause() { + super.onPause() + requireActivity().unregisterReceiver(updateUIReceiver) + } + /** *Live Data Observers **/ @@ -127,8 +182,9 @@ class SpotifyFragment : Fragment() { **/ spotifyViewModel.trackList.observe(viewLifecycleOwner, Observer { if (it.isNotEmpty()){ - Log.i("SpotifyFragment","TrackList Fetched!") + Log.i("SpotifyFragment","TrackList Updated") adapterConfig(it) + checkIfAllDownloaded() } }) @@ -140,6 +196,19 @@ class SpotifyFragment : Fragment() { }) } + private fun checkIfAllDownloaded() { + var allDownloaded = true + for (track in spotifyViewModel.trackList.value!!){ + if (track.downloaded != "Downloaded")allDownloaded = false + } + if(allDownloaded){ + binding.downloadingFabSpotify.setImageResource(R.drawable.ic_tick) + binding.btnDownloadAllSpotify.visibility = View.GONE + binding.downloadingFabSpotify.visibility = View.VISIBLE + binding.downloadingFabSpotify.clearAnimation() + } + } + /** * Basic Initialization **/ @@ -155,7 +224,7 @@ class SpotifyFragment : Fragment() { }) SpotifyDownloadHelper.webView = binding.webViewSpotify SpotifyDownloadHelper.context = requireContext() - SpotifyDownloadHelper.sharedViewModel = sharedViewModel + SpotifyDownloadHelper.spotifyViewModel = spotifyViewModel SpotifyDownloadHelper.statusBar = binding.StatusBarSpotify binding.trackListSpotify.adapter = adapterSpotify } @@ -214,11 +283,9 @@ class SpotifyFragment : Fragment() { * Configure Recycler View Adapter **/ private fun adapterConfig(trackList: List){ - adapterSpotify.trackList = trackList - adapterSpotify.totalItems = trackList.size adapterSpotify.spotifyFragment = this - adapterSpotify.sharedViewModel = sharedViewModel - adapterSpotify.notifyDataSetChanged() + adapterSpotify.spotifyViewModel = spotifyViewModel + adapterSpotify.submitList(trackList) } diff --git a/app/src/main/java/com/shabinder/spotiflyer/ui/spotify/SpotifyViewModel.kt b/app/src/main/java/com/shabinder/spotiflyer/ui/spotify/SpotifyViewModel.kt index a1d53213..a1815741 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/ui/spotify/SpotifyViewModel.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/spotify/SpotifyViewModel.kt @@ -25,16 +25,18 @@ import com.shabinder.spotiflyer.models.Album import com.shabinder.spotiflyer.models.Playlist import com.shabinder.spotiflyer.models.Track import com.shabinder.spotiflyer.utils.SpotifyService +import com.shabinder.spotiflyer.utils.finalOutputDir import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch +import java.io.File class SpotifyViewModel: ViewModel() { var folderType:String = "" var subFolder:String = "" - var trackList = MutableLiveData>() + var trackList = MutableLiveData>() private val loading = "Loading" var title = MutableLiveData().apply { value = loading } var coverUrl = MutableLiveData().apply { value = loading } @@ -50,42 +52,57 @@ class SpotifyViewModel: ViewModel() { "track" -> { uiScope.launch { val trackObject = getTrackDetails(link) + folderType = "Tracks" val tempTrackList = mutableListOf() - tempTrackList.add(trackObject!!) + if(File(finalOutputDir(trackObject?.name!!,folderType,subFolder)).exists()){//Download Already Present!! + trackObject.downloaded = "Downloaded" + } + tempTrackList.add(trackObject) trackList.value = tempTrackList title.value = trackObject.name coverUrl.value = trackObject.album!!.images?.get(0)!!.url!! - folderType = "Tracks" } } "album" -> { uiScope.launch { val albumObject = getAlbumDetails(link) + folderType = "Albums" + subFolder = albumObject?.name!! val tempTrackList = mutableListOf() - albumObject!!.tracks?.items?.forEach { tempTrackList.add(it) } + albumObject.tracks?.items?.forEach { + if(File(finalOutputDir(it.name!!,folderType,subFolder)).exists()){//Download Already Present!! + it.downloaded = "Downloaded" + } + tempTrackList.add(it) + } trackList.value = tempTrackList title.value = albumObject.name coverUrl.value = albumObject.images?.get(0)!!.url!! - folderType = "Albums" - subFolder = albumObject.name!! } } "playlist" -> { uiScope.launch { val playlistObject = getPlaylistDetails(link) + folderType = "Playlists" + subFolder = playlistObject?.name!! val tempTrackList = mutableListOf() - playlistObject!!.tracks?.items?.forEach { - it.track?.let { it1 -> tempTrackList.add(it1) } + playlistObject.tracks?.items?.forEach { + it.track?.let { + it1 -> if(File(finalOutputDir(it1.name!!,folderType,subFolder)).exists()){//Download Already Present!! + it1.downloaded = "Downloaded" + Log.i("ViewModel123","${it1.name} Downloaded") + } + tempTrackList.add(it1) + } } + Log.i("ViewModel",tempTrackList.size.toString()) + Log.i("ViewModel",playlistObject.tracks?.items?.size.toString()) trackList.value = tempTrackList - Log.i("VIEW MODEL",playlistObject.tracks?.items!!.toString()) - Log.i("VIEW MODEL",trackList.value?.size.toString()) title.value = playlistObject.name coverUrl.value = playlistObject.images?.get(0)!!.url!! - folderType = "Playlists" - subFolder = playlistObject.name!! + } } "episode" -> {//TODO diff --git a/app/src/main/java/com/shabinder/spotiflyer/ui/youtube/YoutubeFragment.kt b/app/src/main/java/com/shabinder/spotiflyer/ui/youtube/YoutubeFragment.kt new file mode 100644 index 00000000..03d9a251 --- /dev/null +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/youtube/YoutubeFragment.kt @@ -0,0 +1,145 @@ +/* + * 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 . + */ + +package com.shabinder.spotiflyer.ui.youtube + +import android.content.Context +import android.net.ConnectivityManager +import android.os.Bundle +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.spotiflyer.R +import com.shabinder.spotiflyer.SharedViewModel +import com.shabinder.spotiflyer.databinding.YoutubeFragmentBinding +import com.shabinder.spotiflyer.downloadHelper.YTDownloadHelper +import com.shabinder.spotiflyer.models.Track +import com.shabinder.spotiflyer.recyclerView.YoutubeTrackListAdapter +import com.shabinder.spotiflyer.utils.bindImage + +class YoutubeFragment : Fragment() { + + private lateinit var binding:YoutubeFragmentBinding + private lateinit var youtubeViewModel: YoutubeViewModel + private lateinit var sharedViewModel: SharedViewModel + private lateinit var adapter : YoutubeTrackListAdapter + private val sampleDomain1 = "youtube.com" + private val sampleDomain2 = "youtu.be" + + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = DataBindingUtil.inflate(inflater,R.layout.youtube_fragment,container,false) + youtubeViewModel = ViewModelProvider(this).get(YoutubeViewModel::class.java) + sharedViewModel = ViewModelProvider(this.requireActivity()).get(SharedViewModel::class.java) + adapter = YoutubeTrackListAdapter() + YTDownloadHelper.context = requireContext() + YTDownloadHelper.statusBar = binding.StatusBarYoutube + binding.trackListYoutube.adapter = adapter + sharedViewModel.ytDownloader.observe(viewLifecycleOwner, Observer { + youtubeViewModel.ytDownloader = it + }) + initializeLiveDataObservers() + + val args = YoutubeFragmentArgs.fromBundle(requireArguments()) + val link = args.link + youtubeSearch(link) + return binding.root + } + + private fun youtubeSearch(linkSearch:String) { + val link = linkSearch.removePrefix("https://").removePrefix("http://") + if(!link.contains("playlist",true)){ + var searchId = "error" + if(link.contains(sampleDomain1,true) ){ + searchId = link.substringAfterLast("=","error") + } + if(link.contains(sampleDomain2,true) && !link.contains("playlist",true) ){ + searchId = link.substringAfterLast("/","error") + } + if(searchId != "error") { +// val coverUrl = "https://i.ytimg.com/vi/$searchId/maxresdefault.jpg" + youtubeViewModel.getYTTrack(searchId) + binding.btnDownloadAllYoutube.setOnClickListener { + //TODO + } + }else{showToast("Your Youtube Link is not of a Video!!")} + }else(showToast("Your Youtube Link is not of a Video!!")) + } + + private fun initializeLiveDataObservers() { + /** + * CoverUrl Binding Observer! + **/ + youtubeViewModel.coverUrl.observe(viewLifecycleOwner, Observer { + if(it!="Loading") bindImage(binding.youtubeCoverImage,it) + }) + + /** + * TrackList Binding Observer! + **/ + youtubeViewModel.ytTrack.observe(viewLifecycleOwner, Observer { + val list = mutableListOf() + list.add(it) + adapterConfig(list) + }) + + youtubeViewModel.format.observe(viewLifecycleOwner, Observer { + adapter.format = it + }) + + /** + * Title Binding Observer! + **/ + youtubeViewModel.title.observe(viewLifecycleOwner, Observer { + binding.titleViewYoutube.text = it + }) + + } + + /** + * Configure Recycler View Adapter + **/ + private fun adapterConfig(list:List){ + adapter.sharedViewModel = sharedViewModel + adapter.submitList(list) + } + + /** + * Util. Function to create toasts! + **/ + private fun showToast(message:String){ + Toast.makeText(context,message, Toast.LENGTH_SHORT).show() + } + + /** + * Util. Function To Check Connection Status + **/ + private fun isNotOnline(): Boolean { + val cm = + requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val netInfo = cm.activeNetworkInfo + return netInfo != null && netInfo.isConnectedOrConnecting + } +} diff --git a/app/src/main/java/com/shabinder/spotiflyer/ui/youtube/YoutubeViewModel.kt b/app/src/main/java/com/shabinder/spotiflyer/ui/youtube/YoutubeViewModel.kt new file mode 100644 index 00000000..0a565da1 --- /dev/null +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/youtube/YoutubeViewModel.kt @@ -0,0 +1,82 @@ +/* + * 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 . + */ + +package com.shabinder.spotiflyer.ui.youtube + +import android.util.Log +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.github.kiulian.downloader.YoutubeDownloader +import com.github.kiulian.downloader.model.formats.Format +import com.github.kiulian.downloader.model.quality.AudioQuality +import com.shabinder.spotiflyer.models.Artist +import com.shabinder.spotiflyer.models.Track +import kotlinx.coroutines.* + +class YoutubeViewModel : ViewModel() { + + val ytTrack = MutableLiveData() + val format = MutableLiveData() + private val loading = "Loading" + var title = MutableLiveData().apply { value = "\"Loading!\"" } + var coverUrl = MutableLiveData().apply { value = loading } + var ytDownloader: YoutubeDownloader? = null + + + private var viewModelJob = Job() + val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob) + + + fun getYTTrack(searchId:String) { + uiScope.launch { + withContext(Dispatchers.IO){ + Log.i("YT View Model",searchId) + val video = ytDownloader?.getVideo(searchId) + val detail = video?.details() + val name = detail?.title()?.replace(detail.author()!!.toUpperCase(),"",true) ?: detail?.title() + Log.i("YT View Model",detail.toString()) + ytTrack.postValue( + Track( + id = searchId, + name = name, + artists = listOf(Artist(name = detail?.author())), + duration_ms = detail?.lengthSeconds()?.times(1000)?.toLong()?:0, + ytCoverUrl = "https://i.ytimg.com/vi/$searchId/maxresdefault.jpg" + )) + coverUrl.postValue("https://i.ytimg.com/vi/$searchId/maxresdefault.jpg") + title.postValue( + if(name?.length!! > 17){"${name.subSequence(0,16)}..."}else{name} + ) + format.postValue(try { + video?.findAudioWithQuality(AudioQuality.high)?.get(0) as Format + } catch (e: IndexOutOfBoundsException) { + try { + video?.findAudioWithQuality(AudioQuality.medium)?.get(0) as Format + } catch (e: IndexOutOfBoundsException) { + try { + video?.findAudioWithQuality(AudioQuality.low)?.get(0) as Format + } catch (e: IndexOutOfBoundsException) { + Log.i("YTDownloader", e.toString()) + null + } + } + }) + } + } + } +} + diff --git a/app/src/main/java/com/shabinder/spotiflyer/utils/BindingAdapter.kt b/app/src/main/java/com/shabinder/spotiflyer/utils/BindingAdapter.kt index 2f29889b..595057d6 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/utils/BindingAdapter.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/utils/BindingAdapter.kt @@ -21,6 +21,10 @@ import android.graphics.Bitmap import android.graphics.BitmapFactory import android.os.Environment import android.util.Log +import android.view.View +import android.view.animation.Animation +import android.view.animation.LinearInterpolator +import android.view.animation.RotateAnimation import android.widget.ImageView import androidx.core.net.toUri import androidx.databinding.BindingAdapter @@ -39,6 +43,25 @@ import java.io.File import java.io.FileInputStream import java.io.IOException +fun finalOutputDir(itemName:String,type:String, subFolder:String?=null): String{ + return Environment.getExternalStorageDirectory().toString() + File.separator + + SpotifyDownloadHelper.defaultDir + SpotifyDownloadHelper.removeIllegalChars(type) + File.separator + + (if(subFolder == null){""}else{ SpotifyDownloadHelper.removeIllegalChars(subFolder) + File.separator} + + SpotifyDownloadHelper.removeIllegalChars(itemName) +".mp3") +} + +fun rotateAnim(view: View){ + val rotate = RotateAnimation( + 0F, 360F, + Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f + ) + rotate.duration = 1000 + rotate.repeatCount = Animation.INFINITE + rotate.repeatMode = Animation.INFINITE + rotate.interpolator = LinearInterpolator() + view.animation = rotate +} + @BindingAdapter("imageUrl") fun bindImage(imgView: ImageView, imgUrl: String?) { diff --git a/app/src/main/java/com/shabinder/spotiflyer/worker/ForegroundService.kt b/app/src/main/java/com/shabinder/spotiflyer/worker/ForegroundService.kt index 1e251411..1b9cb4b9 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/worker/ForegroundService.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/worker/ForegroundService.kt @@ -98,9 +98,15 @@ class ForegroundService : Service(){ .setDownloadConcurrentLimit(4) .build() - fetch = Fetch.Impl.getInstance(fetchConfiguration) + Fetch.setDefaultInstanceConfiguration(fetchConfiguration) + + fetch = Fetch.getDefaultInstance() // fetch?.enableLogging(true) fetch?.addListener(fetchListener) + //clearing all not completed Downloads + //Starting fresh + fetch?.removeAll() + startForeground() } @@ -218,11 +224,11 @@ class ForegroundService : Service(){ super.onTaskRemoved(rootIntent) if(downloadMap.isEmpty() && converted == total ){ Log.i(tag,"Service Removed.") - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - stopForeground(true) - } else { +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { +// stopForeground(true) +// } else { stopSelf()//System will automatically close it - } +// } } } @@ -307,12 +313,17 @@ class ForegroundService : Service(){ override fun onCompleted(download: Download) { val track = requestMap[download.request] - for (message in messageList){ if( message == "Downloading ${track?.name}"){ messageList[messageList.indexOf(message)] = "" } } + //Notify Download Completed + val intent = Intent() + .setAction("track_download_completed") + .putExtra("track",track) + this@ForegroundService.sendBroadcast(intent) + serviceScope.launch { try{ diff --git a/app/src/main/res/drawable/gradient.xml b/app/src/main/res/drawable/gradient.xml index 7cd7fc37..6177f9f4 100644 --- a/app/src/main/res/drawable/gradient.xml +++ b/app/src/main/res/drawable/gradient.xml @@ -1,4 +1,21 @@ + + - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrow_slim.xml b/app/src/main/res/drawable/ic_arrow_slim.xml index adea43fd..67fc7edf 100644 --- a/app/src/main/res/drawable/ic_arrow_slim.xml +++ b/app/src/main/res/drawable/ic_arrow_slim.xml @@ -1,10 +1,27 @@ + + - - - - - - + + + + + + diff --git a/app/src/main/res/drawable/ic_linkedin.xml b/app/src/main/res/drawable/ic_linkedin.xml new file mode 100644 index 00000000..306000f7 --- /dev/null +++ b/app/src/main/res/drawable/ic_linkedin.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_refresh.xml b/app/src/main/res/drawable/ic_refresh.xml new file mode 100644 index 00000000..64cb8756 --- /dev/null +++ b/app/src/main/res/drawable/ic_refresh.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_refreshgradient.xml b/app/src/main/res/drawable/ic_refreshgradient.xml new file mode 100644 index 00000000..7db55bf7 --- /dev/null +++ b/app/src/main/res/drawable/ic_refreshgradient.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_spotify_logo.xml b/app/src/main/res/drawable/ic_spotify_logo.xml new file mode 100644 index 00000000..7100aaca --- /dev/null +++ b/app/src/main/res/drawable/ic_spotify_logo.xml @@ -0,0 +1,21 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_tick.xml b/app/src/main/res/drawable/ic_tick.xml new file mode 100644 index 00000000..a857fdcc --- /dev/null +++ b/app/src/main/res/drawable/ic_tick.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_youtube.xml b/app/src/main/res/drawable/ic_youtube.xml new file mode 100644 index 00000000..780f74bd --- /dev/null +++ b/app/src/main/res/drawable/ic_youtube.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/transparent.xml b/app/src/main/res/drawable/transparent.xml new file mode 100644 index 00000000..4d6c36bc --- /dev/null +++ b/app/src/main/res/drawable/transparent.xml @@ -0,0 +1,27 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/main_fragment.xml b/app/src/main/res/layout/main_fragment.xml new file mode 100644 index 00000000..2786c4a6 --- /dev/null +++ b/app/src/main/res/layout/main_fragment.xml @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/spotify_fragment.xml b/app/src/main/res/layout/spotify_fragment.xml index 580a1194..409a362e 100644 --- a/app/src/main/res/layout/spotify_fragment.xml +++ b/app/src/main/res/layout/spotify_fragment.xml @@ -34,7 +34,6 @@ 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" @@ -43,6 +42,21 @@ app:layout_anchor="@+id/appbar_spotify" app:layout_anchorGravity="bottom|center" /> + + + diff --git a/app/src/main/res/layout/track_list_item.xml b/app/src/main/res/layout/track_list_item.xml index 5a2e1c88..a809c617 100644 --- a/app/src/main/res/layout/track_list_item.xml +++ b/app/src/main/res/layout/track_list_item.xml @@ -20,6 +20,12 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile-ffmpeg/build.gradle b/mobile-ffmpeg/build.gradle new file mode 100644 index 00000000..34434740 --- /dev/null +++ b/mobile-ffmpeg/build.gradle @@ -0,0 +1,19 @@ +/* + * 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 . + */ + +configurations.maybeCreate("default") +artifacts.add("default", file('mobile-ffmpeg.aar')) \ No newline at end of file diff --git a/mobile-ffmpeg/build/.transforms/165f5e04bab83e4d7ef3793f6d3185e9.bin b/mobile-ffmpeg/build/.transforms/165f5e04bab83e4d7ef3793f6d3185e9.bin new file mode 100644 index 00000000..fecb16f6 --- /dev/null +++ b/mobile-ffmpeg/build/.transforms/165f5e04bab83e4d7ef3793f6d3185e9.bin @@ -0,0 +1 @@ +o/jetified-mobile-ffmpeg-runtime diff --git a/mobile-ffmpeg/build/.transforms/165f5e04bab83e4d7ef3793f6d3185e9/jetified-mobile-ffmpeg-runtime/classes.dex b/mobile-ffmpeg/build/.transforms/165f5e04bab83e4d7ef3793f6d3185e9/jetified-mobile-ffmpeg-runtime/classes.dex new file mode 100644 index 00000000..e244fda6 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/165f5e04bab83e4d7ef3793f6d3185e9/jetified-mobile-ffmpeg-runtime/classes.dex differ diff --git a/mobile-ffmpeg/build/.transforms/3c13e6a6cfec549801853313afef845a.bin b/mobile-ffmpeg/build/.transforms/3c13e6a6cfec549801853313afef845a.bin new file mode 100644 index 00000000..bb8096af --- /dev/null +++ b/mobile-ffmpeg/build/.transforms/3c13e6a6cfec549801853313afef845a.bin @@ -0,0 +1 @@ +o/com.arthenica.mobileffmpeg-r.txt diff --git a/mobile-ffmpeg/build/.transforms/3c13e6a6cfec549801853313afef845a/com.arthenica.mobileffmpeg-r.txt b/mobile-ffmpeg/build/.transforms/3c13e6a6cfec549801853313afef845a/com.arthenica.mobileffmpeg-r.txt new file mode 100644 index 00000000..e2eb1da5 --- /dev/null +++ b/mobile-ffmpeg/build/.transforms/3c13e6a6cfec549801853313afef845a/com.arthenica.mobileffmpeg-r.txt @@ -0,0 +1 @@ +com.arthenica.mobileffmpeg diff --git a/mobile-ffmpeg/build/.transforms/44c3c67b3dada830e25fac9cb57ed028.bin b/mobile-ffmpeg/build/.transforms/44c3c67b3dada830e25fac9cb57ed028.bin new file mode 100644 index 00000000..e69de29b diff --git a/mobile-ffmpeg/build/.transforms/45d3f5841add16c3c77369161b16fe9d.bin b/mobile-ffmpeg/build/.transforms/45d3f5841add16c3c77369161b16fe9d.bin new file mode 100644 index 00000000..e69de29b diff --git a/mobile-ffmpeg/build/.transforms/4d6234880e730a17a0007e738c8c25cc.bin b/mobile-ffmpeg/build/.transforms/4d6234880e730a17a0007e738c8c25cc.bin new file mode 100644 index 00000000..e69de29b diff --git a/mobile-ffmpeg/build/.transforms/547064cec230b3de550442910456e973.bin b/mobile-ffmpeg/build/.transforms/547064cec230b3de550442910456e973.bin new file mode 100644 index 00000000..a132d325 --- /dev/null +++ b/mobile-ffmpeg/build/.transforms/547064cec230b3de550442910456e973.bin @@ -0,0 +1 @@ +o/com.arthenica.mobileffmpeg diff --git a/mobile-ffmpeg/build/.transforms/5add90f7c7da77dc06e4ac523d8c6e3d.bin b/mobile-ffmpeg/build/.transforms/5add90f7c7da77dc06e4ac523d8c6e3d.bin new file mode 100644 index 00000000..c626d1be --- /dev/null +++ b/mobile-ffmpeg/build/.transforms/5add90f7c7da77dc06e4ac523d8c6e3d.bin @@ -0,0 +1 @@ +i/jars/classes.jar diff --git a/mobile-ffmpeg/build/.transforms/61f3fb17edf5b6324af75ec88d364253.bin b/mobile-ffmpeg/build/.transforms/61f3fb17edf5b6324af75ec88d364253.bin new file mode 100644 index 00000000..dfd7ee57 --- /dev/null +++ b/mobile-ffmpeg/build/.transforms/61f3fb17edf5b6324af75ec88d364253.bin @@ -0,0 +1 @@ +o/jetified-mobile-ffmpeg.aar diff --git a/mobile-ffmpeg/build/.transforms/61f3fb17edf5b6324af75ec88d364253/jetified-mobile-ffmpeg.aar b/mobile-ffmpeg/build/.transforms/61f3fb17edf5b6324af75ec88d364253/jetified-mobile-ffmpeg.aar new file mode 100644 index 00000000..a6d951f1 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/61f3fb17edf5b6324af75ec88d364253/jetified-mobile-ffmpeg.aar differ diff --git a/mobile-ffmpeg/build/.transforms/63ba26a29afbadbf40f923120b21c7bc.bin b/mobile-ffmpeg/build/.transforms/63ba26a29afbadbf40f923120b21c7bc.bin new file mode 100644 index 00000000..fcbf8d4b --- /dev/null +++ b/mobile-ffmpeg/build/.transforms/63ba26a29afbadbf40f923120b21c7bc.bin @@ -0,0 +1 @@ +i/AndroidManifest.xml diff --git a/mobile-ffmpeg/build/.transforms/799c2da7afd2c1f85f8aa47b8c64790b.bin b/mobile-ffmpeg/build/.transforms/799c2da7afd2c1f85f8aa47b8c64790b.bin new file mode 100644 index 00000000..fecb16f6 --- /dev/null +++ b/mobile-ffmpeg/build/.transforms/799c2da7afd2c1f85f8aa47b8c64790b.bin @@ -0,0 +1 @@ +o/jetified-mobile-ffmpeg-runtime diff --git a/mobile-ffmpeg/build/.transforms/799c2da7afd2c1f85f8aa47b8c64790b/jetified-mobile-ffmpeg-runtime/classes.dex b/mobile-ffmpeg/build/.transforms/799c2da7afd2c1f85f8aa47b8c64790b/jetified-mobile-ffmpeg-runtime/classes.dex new file mode 100644 index 00000000..a2700ffa Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/799c2da7afd2c1f85f8aa47b8c64790b/jetified-mobile-ffmpeg-runtime/classes.dex differ diff --git a/mobile-ffmpeg/build/.transforms/8b90c2ce4ad9857a4a0ae2f8d955bb8c.bin b/mobile-ffmpeg/build/.transforms/8b90c2ce4ad9857a4a0ae2f8d955bb8c.bin new file mode 100644 index 00000000..199366a7 --- /dev/null +++ b/mobile-ffmpeg/build/.transforms/8b90c2ce4ad9857a4a0ae2f8d955bb8c.bin @@ -0,0 +1 @@ +i/jni diff --git a/mobile-ffmpeg/build/.transforms/8ebf2a3310fba0519381cd3b5a7e0ed2.bin b/mobile-ffmpeg/build/.transforms/8ebf2a3310fba0519381cd3b5a7e0ed2.bin new file mode 100644 index 00000000..fecb16f6 --- /dev/null +++ b/mobile-ffmpeg/build/.transforms/8ebf2a3310fba0519381cd3b5a7e0ed2.bin @@ -0,0 +1 @@ +o/jetified-mobile-ffmpeg-runtime diff --git a/mobile-ffmpeg/build/.transforms/8ebf2a3310fba0519381cd3b5a7e0ed2/jetified-mobile-ffmpeg-runtime/classes.dex b/mobile-ffmpeg/build/.transforms/8ebf2a3310fba0519381cd3b5a7e0ed2/jetified-mobile-ffmpeg-runtime/classes.dex new file mode 100644 index 00000000..58bb1ef1 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/8ebf2a3310fba0519381cd3b5a7e0ed2/jetified-mobile-ffmpeg-runtime/classes.dex differ diff --git a/mobile-ffmpeg/build/.transforms/9f03d315974765c1db1e2df096c97ee3.bin b/mobile-ffmpeg/build/.transforms/9f03d315974765c1db1e2df096c97ee3.bin new file mode 100644 index 00000000..e69de29b diff --git a/mobile-ffmpeg/build/.transforms/b64c94aee9f0325a82b1e940b89746d3.bin b/mobile-ffmpeg/build/.transforms/b64c94aee9f0325a82b1e940b89746d3.bin new file mode 100644 index 00000000..e69de29b diff --git a/mobile-ffmpeg/build/.transforms/cb8873420fa698b6a6f9a021d5195e3e.bin b/mobile-ffmpeg/build/.transforms/cb8873420fa698b6a6f9a021d5195e3e.bin new file mode 100644 index 00000000..e69de29b diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177.bin b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177.bin new file mode 100644 index 00000000..e0a42b04 --- /dev/null +++ b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177.bin @@ -0,0 +1 @@ +o/jetified-mobile-ffmpeg diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/AndroidManifest.xml b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/AndroidManifest.xml new file mode 100644 index 00000000..b79ea6cc --- /dev/null +++ b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/R.txt b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/R.txt new file mode 100644 index 00000000..e69de29b diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jars/classes.jar b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jars/classes.jar new file mode 100644 index 00000000..daa98ce5 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jars/classes.jar differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libavcodec.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libavcodec.so new file mode 100644 index 00000000..1e6b9c22 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libavcodec.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libavdevice.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libavdevice.so new file mode 100644 index 00000000..f241d9b0 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libavdevice.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libavfilter.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libavfilter.so new file mode 100644 index 00000000..82f6335c Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libavfilter.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libavformat.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libavformat.so new file mode 100644 index 00000000..71e6721f Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libavformat.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libavutil.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libavutil.so new file mode 100644 index 00000000..381c82f5 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libavutil.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libmobileffmpeg.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libmobileffmpeg.so new file mode 100644 index 00000000..2bf671c0 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libmobileffmpeg.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libmobileffmpeg_abidetect.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libmobileffmpeg_abidetect.so new file mode 100644 index 00000000..87094ac8 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libmobileffmpeg_abidetect.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libswresample.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libswresample.so new file mode 100644 index 00000000..da8d813a Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libswresample.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libswscale.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libswscale.so new file mode 100644 index 00000000..8663f497 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/arm64-v8a/libswscale.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libavcodec.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libavcodec.so new file mode 100644 index 00000000..3cbcfc0a Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libavcodec.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libavdevice.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libavdevice.so new file mode 100644 index 00000000..0f5cde78 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libavdevice.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libavfilter.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libavfilter.so new file mode 100644 index 00000000..e4c80018 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libavfilter.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libavformat.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libavformat.so new file mode 100644 index 00000000..d4a46e5a Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libavformat.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libavutil.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libavutil.so new file mode 100644 index 00000000..b12358f1 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libavutil.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libmobileffmpeg.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libmobileffmpeg.so new file mode 100644 index 00000000..568b79f1 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libmobileffmpeg.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libmobileffmpeg_abidetect.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libmobileffmpeg_abidetect.so new file mode 100644 index 00000000..a0825552 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libmobileffmpeg_abidetect.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libswresample.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libswresample.so new file mode 100644 index 00000000..3fb76041 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libswresample.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libswscale.so b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libswscale.so new file mode 100644 index 00000000..e24c656b Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/jni/armeabi-v7a/libswscale.so differ diff --git a/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/proguard.txt b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/proguard.txt new file mode 100644 index 00000000..cc22ff8e --- /dev/null +++ b/mobile-ffmpeg/build/.transforms/e4ff8abd8f7cdbb20ada63ed51b88177/jetified-mobile-ffmpeg/proguard.txt @@ -0,0 +1,16 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +-keep class com.arthenica.mobileffmpeg.Config { + native ; + void log(int, byte[]); + void statistics(int, float, float, long, int, double, double); +} + +-keep class com.arthenica.mobileffmpeg.AbiDetect { + native ; +} diff --git a/mobile-ffmpeg/build/.transforms/f630a19dcb9579906cc8cbb927c0d522.bin b/mobile-ffmpeg/build/.transforms/f630a19dcb9579906cc8cbb927c0d522.bin new file mode 100644 index 00000000..e7a36f8c --- /dev/null +++ b/mobile-ffmpeg/build/.transforms/f630a19dcb9579906cc8cbb927c0d522.bin @@ -0,0 +1 @@ +o/jetified-mobile-ffmpeg-api.jar diff --git a/mobile-ffmpeg/build/.transforms/f630a19dcb9579906cc8cbb927c0d522/jetified-mobile-ffmpeg-api.jar b/mobile-ffmpeg/build/.transforms/f630a19dcb9579906cc8cbb927c0d522/jetified-mobile-ffmpeg-api.jar new file mode 100644 index 00000000..b52e8a9a Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/f630a19dcb9579906cc8cbb927c0d522/jetified-mobile-ffmpeg-api.jar differ diff --git a/mobile-ffmpeg/build/.transforms/fad071483110abc4ae1e5146bfd00936.bin b/mobile-ffmpeg/build/.transforms/fad071483110abc4ae1e5146bfd00936.bin new file mode 100644 index 00000000..d8b375e5 --- /dev/null +++ b/mobile-ffmpeg/build/.transforms/fad071483110abc4ae1e5146bfd00936.bin @@ -0,0 +1 @@ +o/jetified-mobile-ffmpeg-runtime.jar diff --git a/mobile-ffmpeg/build/.transforms/fad071483110abc4ae1e5146bfd00936/jetified-mobile-ffmpeg-runtime.jar b/mobile-ffmpeg/build/.transforms/fad071483110abc4ae1e5146bfd00936/jetified-mobile-ffmpeg-runtime.jar new file mode 100644 index 00000000..85f6b139 Binary files /dev/null and b/mobile-ffmpeg/build/.transforms/fad071483110abc4ae1e5146bfd00936/jetified-mobile-ffmpeg-runtime.jar differ diff --git a/mobile-ffmpeg/build/.transforms/fb32a1d49f174ed0855f1f32cbae8374.bin b/mobile-ffmpeg/build/.transforms/fb32a1d49f174ed0855f1f32cbae8374.bin new file mode 100644 index 00000000..e69de29b diff --git a/mobile-ffmpeg/mobile-ffmpeg.aar b/mobile-ffmpeg/mobile-ffmpeg.aar new file mode 100644 index 00000000..ba7575f6 Binary files /dev/null and b/mobile-ffmpeg/mobile-ffmpeg.aar differ