diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 37d461f3..ac6b0aec 100755 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -12,11 +12,9 @@ diff --git a/.idea/misc.xml b/.idea/misc.xml index d10a516c..c340fa86 100755 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -8,7 +8,7 @@ - + diff --git a/app/build.gradle b/app/build.gradle index 86a31347..f92aa26b 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,42 +15,33 @@ * along with this program. If not, see . */ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' -apply plugin: 'kotlin-kapt' -apply plugin: "androidx.navigation.safeargs.kotlin" -apply plugin: 'dagger.hilt.android.plugin' -apply plugin: 'kotlinx-serialization' +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'kotlin-kapt' + id 'kotlin-android-extensions' + id 'androidx.navigation.safeargs.kotlin' + id 'dagger.hilt.android.plugin' + id 'kotlinx-serialization' +} android { - compileSdkVersion 29 + compileSdkVersion 30 buildToolsVersion "30.0.2" buildFeatures{ - //dataBinding = true viewBinding = true } defaultConfig { applicationId 'com.shabinder.spotiflyer' minSdkVersion 22 - targetSdkVersion 29 + targetSdkVersion 30 versionCode 8 versionName "1.6" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } - packagingOptions { - exclude 'META-INF/DEPENDENCIES' - exclude 'META-INF/LICENSE' - exclude 'META-INF/LICENSE.txt' - exclude 'META-INF/license.txt' - exclude 'META-INF/NOTICE' - exclude 'META-INF/NOTICE.txt' - exclude 'META-INF/notice.txt' - exclude 'META-INF/ASL2.0' - exclude("META-INF/*.kotlin_module") - } + buildTypes { release { minifyEnabled false @@ -62,26 +53,42 @@ android { targetCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8 } + kotlinOptions { jvmTarget = "1.8" } + lintOptions { abortOnError false } + kotlinOptions { jvmTarget = JavaVersion.VERSION_1_8.toString() } + + packagingOptions { + exclude 'META-INF/DEPENDENCIES' + exclude 'META-INF/LICENSE' + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/license.txt' + exclude 'META-INF/NOTICE' + exclude 'META-INF/NOTICE.txt' + exclude 'META-INF/notice.txt' + exclude 'META-INF/ASL2.0' + exclude("META-INF/*.kotlin_module") + } } dependencies { - implementation fileTree(dir: 'libs', include:['*.jar']) + //Android implementation "org.jetbrains.kotlin:kotlin-stdlib:1.4.10" implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.browser:browser:1.2.0' implementation 'androidx.webkit:webkit:1.3.0' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' @@ -89,46 +96,49 @@ dependencies { implementation 'androidx.navigation:navigation-ui-ktx:2.3.1' implementation 'androidx.recyclerview:recyclerview:1.1.0' implementation 'com.google.android.material:material:1.2.1' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.1' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1' implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1" + //FFmpeg + implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs') + + //Room: Local SQL-lite Database implementation "androidx.room:room-runtime:2.2.5" implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0' kapt "androidx.room:room-compiler:2.2.5" implementation "androidx.room:room-ktx:2.2.5" + + //Hilt: Dependency Injection implementation "com.google.dagger:hilt-android:$hilt_version" kapt "com.google.dagger:hilt-android-compiler:$hilt_version" implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02' kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha02' - 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 - } - kapt ("com.github.bumptech.glide:recyclerview-integration:4.11.0") { - transitive = true - } + //Glide-Image Loading + implementation ("com.github.bumptech.glide:recyclerview-integration:4.11.0") {transitive = true} + kapt ("com.github.bumptech.glide:recyclerview-integration:4.11.0") {transitive = true} + //HTTP implementation 'com.squareup.okhttp3:okhttp:4.9.0' - implementation 'com.squareup.retrofit2:retrofit:2.9.0' + + //Json implementation 'com.squareup.moshi:moshi:1.11.0' implementation 'com.squareup.moshi:moshi-kotlin:1.11.0' implementation "com.squareup.retrofit2:converter-moshi:2.9.0" implementation "com.squareup.retrofit2:converter-scalars:2.9.0" implementation 'com.beust:klaxon:5.4' - implementation 'me.xdrop:fuzzywuzzy:1.3.1' + //Extras + implementation 'me.xdrop:fuzzywuzzy:1.3.1' implementation 'com.mpatric:mp3agic:0.9.1' implementation 'com.shreyaspatil:EasyUpiPayment:3.0.0' - implementation 'com.github.sealedtx:java-youtube-downloader:2.4.4' - implementation "androidx.tonyodev.fetch2:xfetch2:3.1.5" implementation 'com.github.javiersantos:AppUpdater:2.7' + implementation "androidx.tonyodev.fetch2:xfetch2:3.1.5" + implementation 'com.github.sealedtx:java-youtube-downloader:2.4.4' - implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava' testImplementation 'junit:junit:4.13.1' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' diff --git a/app/libs/mobile-ffmpeg.aar b/app/libs/mobile-ffmpeg.aar new file mode 100755 index 00000000..ba7575f6 Binary files /dev/null and b/app/libs/mobile-ffmpeg.aar differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a0b844e7..540f8fed 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -24,8 +24,10 @@ - + + @@ -38,9 +40,11 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:forceDarkAllowed="true" - android:requestLegacyExternalStorage="true" android:theme="@style/AppTheme" + android:requestLegacyExternalStorage="true" + tools:ignore="AllowBackup" tools:targetApi="q"> + diff --git a/app/src/main/java/com/shabinder/spotiflyer/MainActivity.kt b/app/src/main/java/com/shabinder/spotiflyer/MainActivity.kt index fe42798c..6b377c39 100755 --- a/app/src/main/java/com/shabinder/spotiflyer/MainActivity.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/MainActivity.kt @@ -39,7 +39,10 @@ import com.shabinder.spotiflyer.databinding.MainActivityBinding import com.shabinder.spotiflyer.downloadHelper.DownloadHelper import com.shabinder.spotiflyer.networking.SpotifyService import com.shabinder.spotiflyer.networking.SpotifyServiceTokenRequest -import com.shabinder.spotiflyer.utils.* +import com.shabinder.spotiflyer.utils.NetworkInterceptor +import com.shabinder.spotiflyer.utils.createDirectories +import com.shabinder.spotiflyer.utils.showMessage +import com.shabinder.spotiflyer.utils.startService import com.squareup.moshi.Moshi import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch @@ -53,7 +56,6 @@ import javax.inject.Inject /* * This is App's God Activity * */ -@Suppress("DEPRECATION") @AndroidEntryPoint class MainActivity : AppCompatActivity(){ private var spotifyService : SpotifyService? = null @@ -75,15 +77,15 @@ class MainActivity : AppCompatActivity(){ snackBarAnchor = binding.snackBarPosition DownloadHelper.youtubeMusicApi = sharedViewModel.youtubeMusicApi + //starting Notification and Downloader Service! + startService(this) + authenticateSpotify() requestPermission() disableDozeMode() checkIfLatestVersion() createDirectories() - Log.i("Connection Status", isOnline().toString()) - //starting Notification and Downloader Service! - startService(this) handleIntentFromExternalActivity() } diff --git a/app/src/main/java/com/shabinder/spotiflyer/downloadHelper/DownloadHelper.kt b/app/src/main/java/com/shabinder/spotiflyer/downloadHelper/DownloadHelper.kt index 33c8973f..ed250f45 100755 --- a/app/src/main/java/com/shabinder/spotiflyer/downloadHelper/DownloadHelper.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/downloadHelper/DownloadHelper.kt @@ -18,7 +18,6 @@ package com.shabinder.spotiflyer.downloadHelper import android.annotation.SuppressLint -import android.os.Environment import android.os.Handler import android.util.Log import android.view.View @@ -99,7 +98,6 @@ object DownloadHelper { if(videoId.isNullOrBlank()) {notFound++ ; updateStatusBar()} else {//Found Youtube Video ID val outputFile: String = - Environment.getExternalStorageDirectory().toString() + File.separator + defaultDir + removeIllegalChars(type) + File.separator + (if (subFolder == null) { "" } diff --git a/app/src/main/java/com/shabinder/spotiflyer/downloadHelper/YTDownloadHelper.kt b/app/src/main/java/com/shabinder/spotiflyer/downloadHelper/YTDownloadHelper.kt index 2e6637fa..4c075b61 100755 --- a/app/src/main/java/com/shabinder/spotiflyer/downloadHelper/YTDownloadHelper.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/downloadHelper/YTDownloadHelper.kt @@ -17,7 +17,6 @@ package com.shabinder.spotiflyer.downloadHelper -import android.os.Environment import android.util.Log import android.widget.Toast import com.shabinder.spotiflyer.models.DownloadObject @@ -44,9 +43,7 @@ object YTDownloadHelper { showNoConnectionAlert() return } - val outputFile: String = - Environment.getExternalStorageDirectory().toString() + File.separator + - defaultDir + + val outputFile: String = defaultDir + removeIllegalChars(type) + File.separator + (if (subFolder == null) { "" } else { removeIllegalChars(subFolder) + File.separator } diff --git a/app/src/main/java/com/shabinder/spotiflyer/models/gaana/GaanaPlaylist.kt b/app/src/main/java/com/shabinder/spotiflyer/models/gaana/GaanaPlaylist.kt index 38dc43ec..b64ca02e 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/models/gaana/GaanaPlaylist.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/models/gaana/GaanaPlaylist.kt @@ -18,7 +18,6 @@ package com.shabinder.spotiflyer.models.gaana data class GaanaPlaylist ( - val tags : String?, val modified_on : String, val count : Int, val created_on : String, diff --git a/app/src/main/java/com/shabinder/spotiflyer/ui/gaana/GaanaViewModel.kt b/app/src/main/java/com/shabinder/spotiflyer/ui/gaana/GaanaViewModel.kt index 3e80eb24..c7d5f57c 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/ui/gaana/GaanaViewModel.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/gaana/GaanaViewModel.kt @@ -17,7 +17,6 @@ package com.shabinder.spotiflyer.ui.gaana -import android.os.Environment import androidx.hilt.lifecycle.ViewModelInject import com.shabinder.spotiflyer.database.DatabaseDAO import com.shabinder.spotiflyer.database.DownloadRecord @@ -165,8 +164,7 @@ class GaanaViewModel @ViewModelInject constructor( artists = it.artist.map { artist -> artist?.name.toString() }, durationSec = it.duration, albumArt = File( - Environment.getExternalStorageDirectory(), - Provider.defaultDir +".Images/" + (it.artworkLink.substringBeforeLast('/').substringAfterLast('/')) + ".jpeg"), + Provider.imageDir + (it.artworkLink.substringBeforeLast('/').substringAfterLast('/')) + ".jpeg"), albumName = it.album_title, year = it.release_date, comment = "Genres:${it.genre?.map { genre -> genre?.name }?.reduceOrNull { acc, s -> acc + s }}", 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 ae0f7222..d63a9c6e 100755 --- a/app/src/main/java/com/shabinder/spotiflyer/ui/spotify/SpotifyViewModel.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/spotify/SpotifyViewModel.kt @@ -17,7 +17,6 @@ package com.shabinder.spotiflyer.ui.spotify -import android.os.Environment import android.util.Log import androidx.hilt.lifecycle.ViewModelInject import com.shabinder.spotiflyer.database.DatabaseDAO @@ -29,7 +28,7 @@ import com.shabinder.spotiflyer.models.spotify.Image import com.shabinder.spotiflyer.models.spotify.Source import com.shabinder.spotiflyer.models.spotify.Track import com.shabinder.spotiflyer.networking.SpotifyService -import com.shabinder.spotiflyer.utils.Provider +import com.shabinder.spotiflyer.utils.Provider.imageDir import com.shabinder.spotiflyer.utils.TrackListViewModel import com.shabinder.spotiflyer.utils.finalOutputDir import kotlinx.coroutines.Dispatchers @@ -200,8 +199,7 @@ class SpotifyViewModel @ViewModelInject constructor( artists = it.artists?.map { artist -> artist?.name.toString() } ?: listOf(), durationSec = (it.duration_ms/1000).toInt(), albumArt = File( - Environment.getExternalStorageDirectory(), - Provider.defaultDir +".Images/" + (it.album?.images?.elementAtOrNull(1)?.url ?: it.album?.images?.firstOrNull()?.url.toString()).substringAfterLast('/') + ".jpeg"), + imageDir + (it.album?.images?.elementAtOrNull(1)?.url ?: it.album?.images?.firstOrNull()?.url.toString()).substringAfterLast('/') + ".jpeg"), albumName = it.album?.name, year = it.album?.release_date, comment = "Genres:${it.album?.genres?.joinToString()}", 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 index bc0637c5..fe71231b 100755 --- a/app/src/main/java/com/shabinder/spotiflyer/ui/youtube/YoutubeFragment.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/youtube/YoutubeFragment.kt @@ -68,7 +68,7 @@ class YoutubeFragment : TrackListFragment( if(link.contains(sampleDomain1,true) ){ searchId = link.substringAfterLast("=","error") } - if(link.contains(sampleDomain2,true) && !link.contains("playlist",true) ){ + if(link.contains(sampleDomain2,true) ){ searchId = link.substringAfterLast("/","error") } if(searchId != "error") { 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 index fa28b80e..b740ef7d 100755 --- a/app/src/main/java/com/shabinder/spotiflyer/ui/youtube/YoutubeViewModel.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/ui/youtube/YoutubeViewModel.kt @@ -18,7 +18,6 @@ package com.shabinder.spotiflyer.ui.youtube import android.annotation.SuppressLint -import android.os.Environment import android.util.Log import androidx.hilt.lifecycle.ViewModelInject import com.github.kiulian.downloader.YoutubeDownloader @@ -28,7 +27,7 @@ import com.shabinder.spotiflyer.models.DownloadStatus import com.shabinder.spotiflyer.models.TrackDetails import com.shabinder.spotiflyer.models.spotify.Source import com.shabinder.spotiflyer.utils.* -import com.shabinder.spotiflyer.utils.Provider.defaultDir +import com.shabinder.spotiflyer.utils.Provider.imageDir import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -36,7 +35,7 @@ import java.io.File class YoutubeViewModel @ViewModelInject constructor( val databaseDAO: DatabaseDAO, - val ytDownloader: YoutubeDownloader + private val ytDownloader: YoutubeDownloader ) : TrackListViewModel(){ /* * YT Album Art Schema @@ -67,8 +66,7 @@ class YoutubeViewModel @ViewModelInject constructor( artists = listOf(it.author().toString()), durationSec = it.lengthSeconds(), albumArt = File( - Environment.getExternalStorageDirectory(), - defaultDir + ".Images/" + it.videoId() + ".jpeg" + imageDir + it.videoId() + ".jpeg" ), source = Source.YouTube, albumArtURL = "https://i.ytimg.com/vi/${it.videoId()}/hqdefault.jpg", @@ -121,10 +119,7 @@ class YoutubeViewModel @ViewModelInject constructor( title = name, artists = listOf(detail?.author().toString()), durationSec = detail?.lengthSeconds()?:0, - albumArt = File( - Environment.getExternalStorageDirectory(), - "$defaultDir.Images/$searchId.jpeg" - ), + albumArt = File(imageDir,"$searchId.jpeg"), source = Source.YouTube, albumArtURL = "https://i.ytimg.com/vi/$searchId/hqdefault.jpg" ) diff --git a/app/src/main/java/com/shabinder/spotiflyer/utils/Provider.kt b/app/src/main/java/com/shabinder/spotiflyer/utils/Provider.kt index f64378b8..ba84a06e 100755 --- a/app/src/main/java/com/shabinder/spotiflyer/utils/Provider.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/utils/Provider.kt @@ -49,13 +49,21 @@ import javax.inject.Singleton @Module object Provider { - /* - * mainActivity Instance to use whereEver Needed , as Its God Activity. - * (i.e, Active Through out App' Lifecycle ) - * */ + // mainActivity Instance to use whereEver Needed , as Its God Activity. + // (i.e, Active Through out App' Lifecycle ) val mainActivity: MainActivity = MainActivity.getInstance() - val defaultDir = Environment.DIRECTORY_MUSIC + File.separator + "SpotiFlyer" + File.separator + + //Default Directory to save Media in their Own Categorized Folders + @Suppress("DEPRECATION")// We Do Have Media Access (But Just Media in Media Directory,Not Anything Else) + val defaultDir = Environment.getExternalStorageDirectory().toString() + File.separator + + Environment.DIRECTORY_MUSIC + File.separator + + "SpotiFlyer"+ File.separator + + //Default Cache Directory to save Album Art to use them for writing in Media Later + val imageDir:String + get() = mainActivity.externalCacheDir?.absolutePath + File.separator + + ".Images" + File.separator @Provides diff --git a/app/src/main/java/com/shabinder/spotiflyer/utils/TrackListFragment.kt b/app/src/main/java/com/shabinder/spotiflyer/utils/TrackListFragment.kt index 5e9f5719..62fb3197 100644 --- a/app/src/main/java/com/shabinder/spotiflyer/utils/TrackListFragment.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/utils/TrackListFragment.kt @@ -22,6 +22,7 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.Bundle +import android.os.Handler import android.util.Log import android.view.LayoutInflater import android.view.View @@ -57,6 +58,7 @@ abstract class TrackListFragment : Frag showNoConnectionAlert() mainActivity.navController.popBackStack() } + Handler() sharedViewModel = ViewModelProvider(this.requireActivity()).get(SharedViewModel::class.java) } diff --git a/app/src/main/java/com/shabinder/spotiflyer/utils/Utils.kt b/app/src/main/java/com/shabinder/spotiflyer/utils/Utils.kt index ca125bd9..9240ef3b 100755 --- a/app/src/main/java/com/shabinder/spotiflyer/utils/Utils.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/utils/Utils.kt @@ -22,7 +22,6 @@ import android.content.Intent import android.net.ConnectivityManager import android.net.NetworkCapabilities import android.os.Build -import android.os.Environment import android.util.Log import android.view.View import android.view.animation.Animation @@ -42,6 +41,7 @@ import com.shabinder.spotiflyer.R import com.shabinder.spotiflyer.models.DownloadObject import com.shabinder.spotiflyer.models.spotify.Source import com.shabinder.spotiflyer.utils.Provider.defaultDir +import com.shabinder.spotiflyer.utils.Provider.imageDir import com.shabinder.spotiflyer.utils.Provider.mainActivity import com.shabinder.spotiflyer.worker.ForegroundService import kotlinx.coroutines.CoroutineScope @@ -63,8 +63,7 @@ fun startService(context:Context?,objects:ArrayList? = null ) { } fun finalOutputDir(itemName:String? = null,type:String, subFolder:String?=null,extension:String? = ".mp3"): String{ - return Environment.getExternalStorageDirectory().toString() + File.separator + - defaultDir + removeIllegalChars(type) + File.separator + + return defaultDir + removeIllegalChars(type) + File.separator + (if(subFolder == null){""}else{ removeIllegalChars(subFolder) + File.separator} + itemName?.let { removeIllegalChars(it) + extension}) } @@ -121,7 +120,7 @@ fun rotateAnim(view: View){ 0F, 360F, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f ) - rotate.duration = 1000 + rotate.duration = 2000 rotate.repeatCount = Animation.INFINITE rotate.repeatMode = Animation.INFINITE rotate.interpolator = LinearInterpolator() @@ -172,26 +171,22 @@ fun bindImage(imgView: ImageView, imgUrl: String?,source: Source?) { val file = when(source){ Source.Spotify->{ File( - Environment.getExternalStorageDirectory(), - defaultDir+".Images/" + imgUrl.substringAfterLast('/',imgUrl) + ".jpeg" + imageDir + imgUrl.substringAfterLast('/',imgUrl) + ".jpeg" ) } Source.YouTube->{ //Url Format: https://i.ytimg.com/vi/$searchId/maxresdefault.jpg" // We Are Naming using "$searchId" File( - Environment.getExternalStorageDirectory(), - defaultDir+".Images/" + imgUrl.substringBeforeLast('/',imgUrl).substringAfterLast('/',imgUrl) + ".jpeg" + imageDir + imgUrl.substringBeforeLast('/',imgUrl).substringAfterLast('/',imgUrl) + ".jpeg" ) } Source.Gaana -> { File( - Environment.getExternalStorageDirectory(), - Provider.defaultDir +".Images/" + (imgUrl.substringBeforeLast('/').substringAfterLast('/')) + ".jpeg") + imageDir + (imgUrl.substringBeforeLast('/').substringAfterLast('/')) + ".jpeg") } else -> File( - Environment.getExternalStorageDirectory(), - defaultDir+".Images/" + imgUrl.substringAfterLast('/',imgUrl) + ".jpeg" + imageDir + imgUrl.substringAfterLast('/',imgUrl) + ".jpeg" ) } // the File to save , append increasing numeric counter to prevent files from getting overwritten. @@ -221,18 +216,17 @@ fun File.copyTo(file: File) { } } fun createDirectory(dir:String){ - val yourAppDir = File(Environment.getExternalStorageDirectory(), - dir) + val yourAppDir = File(dir) if(!yourAppDir.exists() && !yourAppDir.isDirectory) { // create empty directory if (yourAppDir.mkdirs()) - {Log.i("CreateDir","App dir created")} + {Log.i("CreateDir","$dir created")} else - {Log.w("CreateDir","Unable to create app dir!")} + {Log.w("CreateDir","Unable to create Dir: $dir!")} } else - {Log.i("CreateDir","App dir already exists")} + {Log.i("CreateDir","$dir already exists")} } /** * Removing Illegal Chars from File Name @@ -277,7 +271,7 @@ fun removeIllegalChars(fileName: String): String? { fun createDirectories() { createDirectory(defaultDir) - createDirectory(defaultDir + ".Images/") + createDirectory(imageDir) createDirectory(defaultDir + "Tracks/") createDirectory(defaultDir + "Albums/") createDirectory(defaultDir + "Playlists/") @@ -285,20 +279,4 @@ fun createDirectories() { } fun getEmojiByUnicode(unicode: Int): String? { return String(Character.toChars(unicode)) -} - -/* -internal val nullOnEmptyConverterFactory = object : Converter.Factory() { - fun converterFactory() = this - override fun responseBodyConverter( - type: Type, - annotations: Array, - retrofit: Retrofit - ) = object : Converter { - val nextResponseBodyConverter = - retrofit.nextResponseBodyConverter(converterFactory(), type, annotations) - - override fun convert(value: ResponseBody) = - if (value.contentLength() != 0L) nextResponseBodyConverter.convert(value) else null - } -}*/ +} \ No newline at end of file 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 f6829393..db71ffcf 100755 --- a/app/src/main/java/com/shabinder/spotiflyer/worker/ForegroundService.kt +++ b/app/src/main/java/com/shabinder/spotiflyer/worker/ForegroundService.kt @@ -25,7 +25,10 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.net.Uri -import android.os.* +import android.os.Build +import android.os.Handler +import android.os.IBinder +import android.os.PowerManager import android.util.Log import androidx.annotation.RequiresApi import androidx.core.app.NotificationCompat @@ -50,6 +53,7 @@ import com.shabinder.spotiflyer.R import com.shabinder.spotiflyer.models.DownloadObject import com.shabinder.spotiflyer.models.TrackDetails import com.shabinder.spotiflyer.utils.Provider +import com.shabinder.spotiflyer.utils.Provider.imageDir import com.shabinder.spotiflyer.utils.copyTo import com.tonyodev.fetch2.* import com.tonyodev.fetch2core.DownloadBlock @@ -59,7 +63,6 @@ import java.io.FileInputStream import java.io.IOException import java.util.* -@Suppress("DEPRECATION") class ForegroundService : Service(){ private val tag = "Foreground Service" private val channelId = "ForegroundDownloaderService" @@ -73,19 +76,13 @@ class ForegroundService : Service(){ private var serviceJob = Job() private val serviceScope = CoroutineScope(Dispatchers.IO + serviceJob) private val requestMap = mutableMapOf() - private var speed :Long = 0 - private var defaultDir = Environment.DIRECTORY_MUSIC + File.separator + "SpotiFlyer" + File.separator - private val parentDirectory = File(Environment.getExternalStorageDirectory(), - defaultDir +File.separator - ) + private var defaultDir = Provider.defaultDir private var wakeLock: PowerManager.WakeLock? = null private var isServiceStarted = false var notificationLine = 0 val messageList = mutableListOf("","","","") private var pendingIntent:PendingIntent? = null - - override fun onBind(intent: Intent): IBinder? { return null } @@ -201,7 +198,7 @@ class ForegroundService : Service(){ if(converted == total){ Handler().postDelayed({ Log.i(tag,"Service destroyed.") - deleteFile(parentDirectory) + cleanFiles(File(defaultDir)) releaseWakeLock() stopForeground(true) },2000) @@ -212,7 +209,7 @@ class ForegroundService : Service(){ super.onTaskRemoved(rootIntent) if(converted == total ){ Log.i(tag,"Service Removed.") - deleteFile(parentDirectory) + cleanFiles(File(defaultDir)) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { stopForeground(true) } else { @@ -303,8 +300,6 @@ class ForegroundService : Service(){ requestMap.remove(download.request) } } - speed = 0 -// updateNotification() } override fun onDeleted(download: Download) { @@ -342,7 +337,6 @@ class ForegroundService : Service(){ ) { val track = requestMap[download.request] Log.i(tag,"${track?.title} ETA: ${etaInMilliSeconds/1000} sec") - speed = (downloadedBytesPerSecond/1000) // updateNotification() } @@ -361,9 +355,7 @@ class ForegroundService : Service(){ .setAllowedOverRoaming(false) .setTitle(track.title) .setDescription("Spotify Downloader Working Up here...") - .setDestinationInExternalPublicDir(Environment.DIRECTORY_MUSIC, outputDir.removePrefix( - Environment.getExternalStorageDirectory().toString() + Environment.DIRECTORY_MUSIC + File.separator - )) + .setDestinationUri(File(outputDir).toUri()) .setNotificationVisibility(VISIBILITY_VISIBLE_NOTIFY_COMPLETED) //Start Download val downloadID = downloadManager.enqueue(request) @@ -562,18 +554,18 @@ class ForegroundService : Service(){ } /** - * Deleting All Residual Files except Mp3 Files + * Cleaning All Residual Files except Mp3 Files **/ - private fun deleteFile(dir:File) { - Log.i(tag,"Starting Deletions in ${dir.path} ") + private fun cleanFiles(dir:File) { + Log.i(tag,"Starting Cleaning in ${dir.path} ") val fList = dir.listFiles() fList?.let { for (file in fList) { if (file.isDirectory) { - deleteFile(file) + cleanFiles(file) } else if(file.isFile) { if(file.path.toString().substringAfterLast(".") != "mp3"){ - Log.i(tag,"deleting ${file.path}") + Log.i(tag,"Cleaning ${file.path}") file.delete() } } @@ -618,25 +610,16 @@ class ForegroundService : Service(){ try { val file = when(source){ "spotify" ->{ - File( - Environment.getExternalStorageDirectory(), - defaultDir +".Images/" + url.substringAfterLast('/') + ".jpeg" - ) + File(imageDir, url.substringAfterLast('/') + ".jpeg") } "youtube" ->{ - File( - Environment.getExternalStorageDirectory(), - defaultDir +".Images/" + url.substringBeforeLast('/',url).substringAfterLast('/',url) + ".jpeg" - ) + File(imageDir, url.substringBeforeLast('/',url).substringAfterLast('/',url) + ".jpeg") } "gaana" -> { - File( - Environment.getExternalStorageDirectory(), - Provider.defaultDir +".Images/" + (url.substringBeforeLast('/').substringAfterLast('/')) + ".jpeg") + File(imageDir, (url.substringBeforeLast('/').substringAfterLast('/')) + ".jpeg") } - else -> File( - Environment.getExternalStorageDirectory(), - defaultDir +".Images/" + url.substringAfterLast('/') + ".jpeg") + + else -> File(imageDir, url.substringAfterLast('/') + ".jpeg") } resource?.copyTo(file) } catch (e: IOException) { diff --git a/app/src/main/res/drawable/circular_background.xml b/app/src/main/res/drawable/circular_background.xml new file mode 100644 index 00000000..64b65daa --- /dev/null +++ b/app/src/main/res/drawable/circular_background.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_arrow.xml b/app/src/main/res/drawable/ic_arrow.xml index 72dd206c..2c26c5e8 100755 --- a/app/src/main/res/drawable/ic_arrow.xml +++ b/app/src/main/res/drawable/ic_arrow.xml @@ -15,8 +15,8 @@ ~ along with this program. If not, see . --> - + diff --git a/app/src/main/res/layout/splash_screen.xml b/app/src/main/res/layout/splash_screen.xml index 3325c9c9..291f984a 100755 --- a/app/src/main/res/layout/splash_screen.xml +++ b/app/src/main/res/layout/splash_screen.xml @@ -41,10 +41,9 @@ android:layout_height="wrap_content" android:layout_marginBottom="48dp" android:background="@drawable/text_background_accented" - android:fontFamily="@font/raleway_semibold" android:foreground="@drawable/rounded_gradient" android:padding="7dp" - android:text="Developer: Shabinder Singh" + android:text=" Developer: Shabinder Singh " android:textColor="@color/white" android:textSize="16sp" android:visibility="visible" diff --git a/app/src/main/res/layout/track_list_item.xml b/app/src/main/res/layout/track_list_item.xml index 649e2fe9..96e3c72c 100755 --- a/app/src/main/res/layout/track_list_item.xml +++ b/app/src/main/res/layout/track_list_item.xml @@ -19,14 +19,14 @@ . */ -include ':mobile-ffmpeg' - include ':app' rootProject.name = "spotiflyer"