Album Bug Fixes & Dependencies Updated.

This commit is contained in:
Shabinder 2020-11-04 17:56:42 +05:30
parent bae0ba6e52
commit 86062f405c
187 changed files with 635 additions and 193 deletions

0
.github/FUNDING.yml vendored Normal file → Executable file
View File

16
.idea/codeStyles/Project.xml Normal file → Executable file
View File

@ -1,6 +1,22 @@
<component name="ProjectCodeStyleConfiguration"> <component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173"> <code_scheme name="Project" version="173">
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>
<package name="java.util" alias="false" withSubpackages="false" />
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
<package name="io.ktor" alias="false" withSubpackages="true" />
</value>
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings> </JetCodeStyleSettings>
<codeStyleSettings language="XML"> <codeStyleSettings language="XML">

0
.idea/codeStyles/codeStyleConfig.xml Normal file → Executable file
View File

6
.idea/dictionaries/shabinder.xml Normal file → Executable file
View File

@ -2,15 +2,21 @@
<dictionary name="shabinder"> <dictionary name="shabinder">
<words> <words>
<w>downloadrecord</w> <w>downloadrecord</w>
<w>emoji</w>
<w>ffmpeg</w> <w>ffmpeg</w>
<w>flyer</w> <w>flyer</w>
<w>insta</w> <w>insta</w>
<w>instagram</w> <w>instagram</w>
<w>jetbrains</w>
<w>kotlinx</w>
<w>mainfragment</w> <w>mainfragment</w>
<w>maxresdefault</w> <w>maxresdefault</w>
<w>moshi</w> <w>moshi</w>
<w>mozilla</w>
<w>musicforeveryone</w> <w>musicforeveryone</w>
<w>musicplaceholder</w> <w>musicplaceholder</w>
<w>raleway</w>
<w>semibold</w>
<w>shabinder</w> <w>shabinder</w>
<w>singh</w> <w>singh</w>
<w>spoti</w> <w>spoti</w>

1
.idea/gradle.xml Normal file → Executable file
View File

@ -16,6 +16,7 @@
</set> </set>
</option> </option>
<option name="resolveModulePerSourceSet" value="false" /> <option name="resolveModulePerSourceSet" value="false" />
<option name="useQualifiedModuleNames" value="true" />
</GradleProjectSettings> </GradleProjectSettings>
</option> </option>
</component> </component>

0
.idea/jarRepositories.xml Normal file → Executable file
View File

2
.idea/misc.xml Normal file → Executable file
View File

@ -8,7 +8,7 @@
<component name="ProjectPlainTextFileTypeManager"> <component name="ProjectPlainTextFileTypeManager">
<file url="file://$PROJECT_DIR$/app/src/main/java/com/shabinder/spotiflyer/testing/YoutubeInterface.kt.backup" /> <file url="file://$PROJECT_DIR$/app/src/main/java/com/shabinder/spotiflyer/testing/YoutubeInterface.kt.backup" />
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

0
.idea/runConfigurations.xml Normal file → Executable file
View File

0
.idea/vcs.xml Normal file → Executable file
View File

0
LICENSE Normal file → Executable file
View File

0
README.md Normal file → Executable file
View File

0
ScreenShots/DownloadHistory.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

0
ScreenShots/HomeScreen.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

0
ScreenShots/LibraryScreen.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 73 KiB

0
ScreenShots/LibraryScreen2.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

0
ScreenShots/Notification.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

0
ScreenShots/PlayList.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

0
app/.gitignore vendored Normal file → Executable file
View File

0
app/SpotifyDownload.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

54
app/build.gradle Normal file → Executable file
View File

@ -25,7 +25,7 @@ apply plugin: 'dagger.hilt.android.plugin'
android { android {
compileSdkVersion 29 compileSdkVersion 29
buildToolsVersion "30.0.0" buildToolsVersion "30.0.2"
buildFeatures{ buildFeatures{
dataBinding = true dataBinding = true
@ -35,8 +35,8 @@ android {
applicationId 'com.shabinder.spotiflyer' applicationId 'com.shabinder.spotiflyer'
minSdkVersion 22 minSdkVersion 22
targetSdkVersion 29 targetSdkVersion 29
versionCode 5 versionCode 6
versionName "1.4" versionName "1.5"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
packagingOptions { packagingOptions {
@ -61,6 +61,9 @@ android {
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
} }
kotlinOptions {
jvmTarget = "1.8"
}
lintOptions { lintOptions {
abortOnError false abortOnError false
} }
@ -73,20 +76,20 @@ android {
dependencies { dependencies {
implementation fileTree(dir: 'libs', include:['*.jar']) implementation fileTree(dir: 'libs', include:['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib:1.4.10"
implementation 'androidx.core:core-ktx:1.3.1' implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.browser:browser:1.2.0' implementation 'androidx.browser:browser:1.2.0'
implementation 'androidx.webkit:webkit:1.2.0' implementation 'androidx.webkit:webkit:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0' implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.0' implementation 'androidx.navigation:navigation-ui-ktx:2.3.1'
implementation 'androidx.recyclerview:recyclerview:1.1.0' implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.google.android.material:material:1.2.0' implementation 'com.google.android.material:material:1.2.1'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7" implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.0'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7" implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.0'
implementation "androidx.room:room-runtime:2.2.5" implementation "androidx.room:room-runtime:2.2.5"
kapt "androidx.room:room-compiler:2.2.5" kapt "androidx.room:room-compiler:2.2.5"
@ -106,30 +109,21 @@ dependencies {
transitive = true transitive = true
} }
// Authentication Way Changed! implementation 'com.squareup.okhttp3:okhttp:4.9.0'
// implementation ('com.google.apis:google-api-services-youtube:v3-rev180-1.22.0'){
// exclude module: 'httpclient'
// }
// //noinspection GradleDependency
// implementation ('com.google.oauth-client:google-oauth-client:1.22.0'){
// exclude module: 'httpclient'
// }
// implementation 'com.spotify.android:auth:1.1.0'
implementation 'com.squareup.okhttp3:okhttp:4.8.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation "com.squareup.moshi:moshi:1.9.3" implementation 'com.squareup.moshi:moshi:1.11.0'
implementation "com.squareup.moshi:moshi-kotlin:1.9.3" implementation 'com.squareup.moshi:moshi-kotlin:1.11.0'
implementation "com.squareup.retrofit2:converter-moshi:2.9.0" implementation "com.squareup.retrofit2:converter-moshi:2.9.0"
implementation 'com.mpatric:mp3agic:0.9.1' implementation 'com.mpatric:mp3agic:0.9.1'
implementation 'com.shreyaspatil:EasyUpiPayment:2.2' implementation 'com.shreyaspatil:EasyUpiPayment:3.0.0'
implementation 'com.github.sealedtx:java-youtube-downloader:2.2.3' implementation 'com.github.sealedtx:java-youtube-downloader:2.4.2'
implementation "androidx.tonyodev.fetch2:xfetch2:3.1.4" implementation "androidx.tonyodev.fetch2:xfetch2:3.1.5"
implementation 'com.github.javiersantos:AppUpdater:2.7' implementation 'com.github.javiersantos:AppUpdater:2.7'
implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava' implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
testImplementation 'junit:junit:4.13' testImplementation 'junit:junit:4.13.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
} }

0
app/build_passing.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 724 B

After

Width:  |  Height:  |  Size: 724 B

0
app/proguard-rules.pro vendored Normal file → Executable file
View File

16
app/src/main/AndroidManifest.xml Normal file → Executable file
View File

@ -17,6 +17,7 @@
--> -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.shabinder.spotiflyer"> package="com.shabinder.spotiflyer">
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
@ -29,8 +30,6 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<!-- <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />-->
<application <application
android:name=".App" android:name=".App"
android:allowBackup="true" android:allowBackup="true"
@ -38,10 +37,13 @@
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:forceDarkAllowed="true"
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme"
tools:targetApi="q">
<activity android:name="com.shabinder.spotiflyer.MainActivity"> <activity android:name="com.shabinder.spotiflyer.MainActivity"
android:launchMode="singleTask">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEND" /> <action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
@ -57,10 +59,7 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<!-- <activity
android:name="com.spotify.sdk.android.authentication.LoginActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
-->
<meta-data <meta-data
android:name="preloaded_fonts" android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" /> android:resource="@array/preloaded_fonts" />
@ -68,5 +67,4 @@
<service android:name=".worker.ForegroundService"/> <service android:name=".worker.ForegroundService"/>
</application> </application>
</manifest> </manifest>

0
app/src/main/ic_launcher-playstore.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

0
app/src/main/java/com/shabinder/spotiflyer/App.kt Normal file → Executable file
View File

View File

@ -29,6 +29,7 @@ import android.os.PowerManager
import android.provider.Settings import android.provider.Settings
import android.util.Log import android.util.Log
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import com.github.javiersantos.appupdater.AppUpdater import com.github.javiersantos.appupdater.AppUpdater
@ -37,7 +38,7 @@ import com.shabinder.spotiflyer.databinding.MainActivityBinding
import com.shabinder.spotiflyer.downloadHelper.SpotifyDownloadHelper import com.shabinder.spotiflyer.downloadHelper.SpotifyDownloadHelper
import com.shabinder.spotiflyer.utils.SpotifyService import com.shabinder.spotiflyer.utils.SpotifyService
import com.shabinder.spotiflyer.utils.SpotifyServiceTokenRequest import com.shabinder.spotiflyer.utils.SpotifyServiceTokenRequest
import com.shabinder.spotiflyer.utils.createDirectory import com.shabinder.spotiflyer.utils.createDirectories
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -62,20 +63,12 @@ class MainActivity : AppCompatActivity(){
@Inject lateinit var spotifyServiceTokenRequest: SpotifyServiceTokenRequest @Inject lateinit var spotifyServiceTokenRequest: SpotifyServiceTokenRequest
@Inject lateinit var moshi: Moshi @Inject lateinit var moshi: Moshi
companion object{
private var instance = MainActivity()
fun getInstance():MainActivity{
return instance
}
}
init {
instance = this
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.main_activity) binding = DataBindingUtil.setContentView(this, R.layout.main_activity)
sharedViewModel = ViewModelProvider(this).get(SharedViewModel::class.java) sharedViewModel = ViewModelProvider(this).get(SharedViewModel::class.java)
//Enabling Dark Mode
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
sharedPref = this.getPreferences(Context.MODE_PRIVATE) sharedPref = this.getPreferences(Context.MODE_PRIVATE)
//starting Notification and Downloader Service! //starting Notification and Downloader Service!
@ -98,6 +91,12 @@ class MainActivity : AppCompatActivity(){
handleIntentFromExternalActivity() handleIntentFromExternalActivity()
} }
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
Log.i("NEW INTENT", "Received")
handleIntentFromExternalActivity(intent)
}
@SuppressLint("BatteryLife") @SuppressLint("BatteryLife")
fun disableDozeMode() { fun disableDozeMode() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
@ -175,12 +174,12 @@ class MainActivity : AppCompatActivity(){
} }
private fun handleIntentFromExternalActivity() { private fun handleIntentFromExternalActivity(intent: Intent? = getIntent()) {
if (intent?.action == Intent.ACTION_SEND) { if (intent?.action == Intent.ACTION_SEND) {
if ("text/plain" == intent.type) { if ("text/plain" == intent.type) {
intent.getStringExtra(Intent.EXTRA_TEXT)?.let { intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
Log.i("Intent Received", it) Log.i("Intent Received", it)
sharedViewModel.intentString = it sharedViewModel.intentString.value = it
} }
} }
} }
@ -208,15 +207,6 @@ class MainActivity : AppCompatActivity(){
} }
} }
private fun createDirectories() {
createDirectory(SpotifyDownloadHelper.defaultDir)
createDirectory(SpotifyDownloadHelper.defaultDir+".Images/")
createDirectory(SpotifyDownloadHelper.defaultDir+"Tracks/")
createDirectory(SpotifyDownloadHelper.defaultDir+"Albums/")
createDirectory(SpotifyDownloadHelper.defaultDir+"Playlists/")
createDirectory(SpotifyDownloadHelper.defaultDir+"YT_Downloads/")
}
private fun checkIfLatestVersion() { private fun checkIfLatestVersion() {
val appUpdater = AppUpdater(this) val appUpdater = AppUpdater(this)
.showAppUpdated(false)//true:Show App is Update Dialog .showAppUpdated(false)//true:Show App is Update Dialog
@ -234,4 +224,14 @@ class MainActivity : AppCompatActivity(){
} }
appUpdater.start() appUpdater.start()
} }
companion object{
private var instance = MainActivity()
fun getInstance():MainActivity{
return instance
}
}
init {
instance = this
}
} }

View File

@ -31,7 +31,7 @@ import kotlinx.coroutines.Job
import java.io.File import java.io.File
class SharedViewModel : ViewModel() { class SharedViewModel : ViewModel() {
var intentString = "" var intentString = MutableLiveData<String>().apply { value = "" }
var spotifyService = MutableLiveData<SpotifyService>() var spotifyService = MutableLiveData<SpotifyService>()
var accessToken = MutableLiveData<String>().apply { value = "" } var accessToken = MutableLiveData<String>().apply { value = "" }
var isConnected = MutableLiveData<Boolean>().apply { value = false } var isConnected = MutableLiveData<Boolean>().apply { value = false }

View File

View File

View File

@ -27,7 +27,6 @@ import android.util.Log
import android.view.View import android.view.View
import android.view.animation.AlphaAnimation import android.view.animation.AlphaAnimation
import android.view.animation.Animation import android.view.animation.Animation
import android.webkit.ValueCallback
import android.webkit.WebView import android.webkit.WebView
import android.webkit.WebViewClient import android.webkit.WebViewClient
import android.widget.TextView import android.widget.TextView
@ -38,6 +37,7 @@ import com.github.kiulian.downloader.model.quality.AudioQuality
import com.shabinder.spotiflyer.models.DownloadObject import com.shabinder.spotiflyer.models.DownloadObject
import com.shabinder.spotiflyer.models.Track import com.shabinder.spotiflyer.models.Track
import com.shabinder.spotiflyer.ui.spotify.SpotifyViewModel import com.shabinder.spotiflyer.ui.spotify.SpotifyViewModel
import com.shabinder.spotiflyer.utils.getEmojiByUnicode
import com.shabinder.spotiflyer.worker.ForegroundService import com.shabinder.spotiflyer.worker.ForegroundService
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -53,6 +53,7 @@ object SpotifyDownloadHelper {
private var isBrowserLoading = false private var isBrowserLoading = false
private var total = 0 private var total = 0
private var Processed = 0 private var Processed = 0
private var notFound = 0
private var listProcessed:Boolean = false private var listProcessed:Boolean = false
var youtubeList = mutableListOf<YoutubeRequest>() var youtubeList = mutableListOf<YoutubeRequest>()
@ -107,20 +108,25 @@ object SpotifyDownloadHelper {
super.onPageFinished(view, url) super.onPageFinished(view, url)
view?.evaluateJavascript( view?.evaluateJavascript(
"document.getElementsByClassName(\"yt-simple-endpoint style-scope ytd-video-renderer\")[0].href" "document.getElementsByClassName(\"yt-simple-endpoint style-scope ytd-video-renderer\")[0].href"
,object :ValueCallback<String>{ ) { value ->
override fun onReceiveValue(value: String?) { Log.i("YT-id Link", value.toString().replace("\"", ""))
Log.i("YT-id",value.toString().replace("\"",""))
val id = value!!.substringAfterLast("=", "error").replace("\"", "") val id = value!!.substringAfterLast("=", "error").replace("\"", "")
Log.i("YT-id",id) Log.i("YT-ID", id)
if (id != "error") {//Link extracting error if (id != "error") {//Link extracting error
Processed++ Processed++
updateStatusBar()
downloadFile(subFolder, type, track, ytDownloader, id) downloadFile(subFolder, type, track, ytDownloader, id)
} }else notFound++
updateStatusBar()
if (youtubeList.isNotEmpty()) { if (youtubeList.isNotEmpty()) {
val request = youtubeList[0] val request = youtubeList[0]
spotifyViewModel!!.uiScope.launch { spotifyViewModel!!.uiScope.launch {
getYTLink(request.type,request.subFolder,request.ytDownloader,request.searchQuery,request.track) getYTLink(
request.type,
request.subFolder,
request.ytDownloader,
request.searchQuery,
request.track
)
} }
youtubeList.remove(request) youtubeList.remove(request)
if (youtubeList.size == 0) {//list processing completed , webView is free again! if (youtubeList.size == 0) {//list processing completed , webView is free again!
@ -136,7 +142,6 @@ object SpotifyDownloadHelper {
}, 1500) }, 1500)
} }
} }
} )
} }
} }
} }
@ -144,13 +149,14 @@ object SpotifyDownloadHelper {
private fun updateStatusBar() { private fun updateStatusBar() {
statusBar!!.visibility = View.VISIBLE statusBar!!.visibility = View.VISIBLE
statusBar?.text = "Total: $total Processed: $Processed" statusBar?.text = "Total: $total ${getEmojiByUnicode(0x2705)}: $Processed ${getEmojiByUnicode(0x274C)}: $notFound"
} }
fun downloadFile(subFolder: String?, type: String, track:Track, ytDownloader: YoutubeDownloader?, id: String) { fun downloadFile(subFolder: String?, type: String, track:Track, ytDownloader: YoutubeDownloader?, id: String) {
spotifyViewModel!!.uiScope.launch { spotifyViewModel!!.uiScope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
try {
val video = ytDownloader?.getVideo(id) val video = ytDownloader?.getVideo(id)
val detail = video?.details() val detail = video?.details()
val format: Format? = try { val format: Format? = try {
@ -169,9 +175,14 @@ object SpotifyDownloadHelper {
} }
format?.let { format?.let {
val url: String = format.url() val url: String = format.url()
// Log.i("DHelper Link Found", url) Log.i("DHelper Link Found", url)
val outputFile:String = Environment.getExternalStorageDirectory().toString() + File.separator + val outputFile: String =
defaultDir + removeIllegalChars(type) + File.separator + (if(subFolder == null){""}else{ removeIllegalChars(subFolder) + File.separator} + removeIllegalChars(track.name!!)+".m4a") Environment.getExternalStorageDirectory().toString() + File.separator +
defaultDir + removeIllegalChars(type) + File.separator + (if (subFolder == null) {
""
} else {
removeIllegalChars(subFolder) + File.separator
} + removeIllegalChars(track.name!!) + ".m4a")
val downloadObject = DownloadObject( val downloadObject = DownloadObject(
track = track, track = track,
@ -181,6 +192,9 @@ object SpotifyDownloadHelper {
Log.i("DH", outputFile) Log.i("DH", outputFile)
startService(context!!, downloadObject) startService(context!!, downloadObject)
} }
}catch (e: com.github.kiulian.downloader.YoutubeException){
Log.i("DH", "Error- Maybe Network")
}
} }
} }
} }

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

@ -54,6 +54,7 @@ class SpotifyTrackListAdapter: ListAdapter<Track,SpotifyTrackListAdapter.ViewHol
if(itemCount ==1 || isAlbum){ if(itemCount ==1 || isAlbum){
holder.binding.imageUrl.visibility = View.GONE}else{ holder.binding.imageUrl.visibility = View.GONE}else{
spotifyViewModel!!.uiScope.launch { spotifyViewModel!!.uiScope.launch {
//Placeholder Set
bindImage(holder.binding.imageUrl, item.album!!.images?.get(0)?.url) bindImage(holder.binding.imageUrl, item.album!!.images?.get(0)?.url)
} }
} }

View File

View File

@ -28,13 +28,12 @@ import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.shabinder.spotiflyer.R import com.shabinder.spotiflyer.R
import com.shabinder.spotiflyer.SharedViewModel import com.shabinder.spotiflyer.SharedViewModel
import com.shabinder.spotiflyer.databinding.MainFragmentBinding import com.shabinder.spotiflyer.databinding.MainFragmentBinding
import com.shreyaspatil.EasyUpiPayment.EasyUpiPayment import com.shreyaspatil.easyupipayment.EasyUpiPayment
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject import javax.inject.Inject
@ -92,7 +91,17 @@ class MainFragment : Fragment() {
* Handle Intent If there is any! * Handle Intent If there is any!
**/ **/
private fun handleIntent() { private fun handleIntent() {
sharedViewModel.accessToken.observe(viewLifecycleOwner, Observer { sharedViewModel.intentString.observe(viewLifecycleOwner,{
//Waiting for Authentication to Finish with Spotify()Access Token Observe
if(sharedViewModel.accessToken.value != ""){
if(it != ""){
binding.linkSearch.setText(sharedViewModel.intentString.value)
binding.btnSearch.performClick()
sharedViewModel.intentString.value = ""
}
}
})/*
sharedViewModel.accessToken.observe(viewLifecycleOwner, {
//Waiting for Authentication to Finish with Spotify()Access Token Observe //Waiting for Authentication to Finish with Spotify()Access Token Observe
if (it != ""){ if (it != ""){
if(sharedViewModel.intentString != ""){ if(sharedViewModel.intentString != ""){
@ -101,7 +110,7 @@ class MainFragment : Fragment() {
sharedViewModel.intentString = "" sharedViewModel.intentString = ""
} }
} }
}) })*/
} }
/** /**

View File

@ -36,6 +36,7 @@ import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.SimpleItemAnimator
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException import com.bumptech.glide.load.engine.GlideException
@ -96,7 +97,7 @@ class SpotifyFragment : Fragment() {
if(sharedViewModel.spotifyService.value == null){//Authentication pending!! if(sharedViewModel.spotifyService.value == null){//Authentication pending!!
(activity as MainActivity).authenticateSpotify() (activity as MainActivity).authenticateSpotify()
} }
if(!isNotOnline()){//Device Offline if(!isOnline()){//Device Offline
sharedViewModel.showAlertDialog(resources,requireContext()) sharedViewModel.showAlertDialog(resources,requireContext())
}else if (type == "Error" || link == "Error") {//Incorrect Link }else if (type == "Error" || link == "Error") {//Incorrect Link
showToast("Please Check Your Link!") showToast("Please Check Your Link!")
@ -179,14 +180,14 @@ class SpotifyFragment : Fragment() {
/** /**
* CoverUrl Binding Observer! * CoverUrl Binding Observer!
**/ **/
spotifyViewModel.coverUrl.observe(viewLifecycleOwner, Observer { spotifyViewModel.coverUrl.observe(viewLifecycleOwner, {
if(it!="Loading") bindImage(binding.spotifyCoverImage,it) if(it!="Loading") bindImage(binding.spotifyCoverImage,it)
}) })
/** /**
* TrackList Binding Observer! * TrackList Binding Observer!
**/ **/
spotifyViewModel.trackList.observe(viewLifecycleOwner, Observer { spotifyViewModel.trackList.observe(viewLifecycleOwner, {
if (it.isNotEmpty()){ if (it.isNotEmpty()){
Log.i("SpotifyFragment","TrackList Updated") Log.i("SpotifyFragment","TrackList Updated")
adapterConfig(it) adapterConfig(it)
@ -197,9 +198,17 @@ class SpotifyFragment : Fragment() {
/** /**
* Title Binding Observer! * Title Binding Observer!
**/ **/
spotifyViewModel.title.observe(viewLifecycleOwner, Observer { spotifyViewModel.title.observe(viewLifecycleOwner, {
binding.titleViewSpotify.text = it binding.titleViewSpotify.text = it
}) })
sharedViewModel.intentString.observe(viewLifecycleOwner,{
//Waiting for Authentication to Finish with Spotify()Access Token Observe
if(it != "" && it!=SpotifyFragmentArgs.fromBundle(requireArguments()).link){
//New Intent Received , Time TO RELOAD
(activity as MainActivity).onBackPressed()
}
})
} }
private fun checkIfAllDownloaded() { private fun checkIfAllDownloaded() {
@ -230,6 +239,7 @@ class SpotifyFragment : Fragment() {
SpotifyDownloadHelper.spotifyViewModel = spotifyViewModel SpotifyDownloadHelper.spotifyViewModel = spotifyViewModel
SpotifyDownloadHelper.statusBar = binding.StatusBarSpotify SpotifyDownloadHelper.statusBar = binding.StatusBarSpotify
binding.trackListSpotify.adapter = adapterSpotify binding.trackListSpotify.adapter = adapterSpotify
(binding.trackListSpotify.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
} }
/** /**
@ -237,7 +247,7 @@ class SpotifyFragment : Fragment() {
**/ **/
private fun loadAllImages(trackList: List<Track>) { private fun loadAllImages(trackList: List<Track>) {
trackList.forEach { trackList.forEach {
val imgUrl = it.album!!.images?.get(0)?.url val imgUrl = it.album?.images?.get(0)?.url
imgUrl?.let { imgUrl?.let {
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build() val imgUri = imgUrl.toUri().buildUpon().scheme("https").build()
Glide Glide
@ -295,14 +305,14 @@ class SpotifyFragment : Fragment() {
/** /**
* Util. Function to create toasts! * Util. Function to create toasts!
**/ **/
fun showToast(message:String){ private fun showToast(message:String){
Toast.makeText(context,message,Toast.LENGTH_SHORT).show() Toast.makeText(context,message,Toast.LENGTH_SHORT).show()
} }
/** /**
* Util. Function To Check Connection Status * Util. Function To Check Connection Status
**/ **/
private fun isNotOnline(): Boolean { private fun isOnline(): Boolean {
val cm = val cm =
requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val netInfo = cm.activeNetworkInfo val netInfo = cm.activeNetworkInfo

View File

@ -24,6 +24,7 @@ import androidx.lifecycle.ViewModel
import com.shabinder.spotiflyer.database.DatabaseDAO import com.shabinder.spotiflyer.database.DatabaseDAO
import com.shabinder.spotiflyer.database.DownloadRecord import com.shabinder.spotiflyer.database.DownloadRecord
import com.shabinder.spotiflyer.models.Album import com.shabinder.spotiflyer.models.Album
import com.shabinder.spotiflyer.models.Image
import com.shabinder.spotiflyer.models.Playlist import com.shabinder.spotiflyer.models.Playlist
import com.shabinder.spotiflyer.models.Track import com.shabinder.spotiflyer.models.Track
import com.shabinder.spotiflyer.utils.SpotifyService import com.shabinder.spotiflyer.utils.SpotifyService
@ -78,23 +79,24 @@ class SpotifyViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO
uiScope.launch { uiScope.launch {
val albumObject = getAlbumDetails(link) val albumObject = getAlbumDetails(link)
folderType = "Albums" folderType = "Albums"
subFolder = albumObject?.name!! subFolder = albumObject?.name.toString()
val tempTrackList = mutableListOf<Track>() val tempTrackList = mutableListOf<Track>()
albumObject.tracks?.items?.forEach { albumObject?.tracks?.items?.forEach {
if(File(finalOutputDir(it.name!!,folderType,subFolder)).exists()){//Download Already Present!! if(File(finalOutputDir(it.name!!,folderType,subFolder)).exists()){//Download Already Present!!
it.downloaded = "Downloaded" it.downloaded = "Downloaded"
} }
it.album = Album(images = listOf(Image(url = albumObject.images?.get(0)?.url)))
tempTrackList.add(it) tempTrackList.add(it)
} }
trackList.value = tempTrackList trackList.value = tempTrackList
title.value = albumObject.name title.value = albumObject?.name
coverUrl.value = albumObject.images?.get(0)!!.url!! coverUrl.value = albumObject?.images?.get(0)?.url
withContext(Dispatchers.IO){ withContext(Dispatchers.IO){
databaseDAO.insert(DownloadRecord( databaseDAO.insert(DownloadRecord(
type = "Album", type = "Album",
name = title.value!!, name = title.value!!,
link = "https://open.spotify.com/$type/$link", link = "https://open.spotify.com/$type/$link",
coverUrl = coverUrl.value!!, coverUrl = coverUrl.value.toString(),
totalFiles = tempTrackList.size, totalFiles = tempTrackList.size,
downloaded = File(finalOutputDir(type = folderType,subFolder = subFolder)).listFiles()?.size == tempTrackList.size, downloaded = File(finalOutputDir(type = folderType,subFolder = subFolder)).listFiles()?.size == tempTrackList.size,
directory = finalOutputDir(type = folderType,subFolder = subFolder) directory = finalOutputDir(type = folderType,subFolder = subFolder)
@ -107,9 +109,10 @@ class SpotifyViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO
uiScope.launch { uiScope.launch {
val playlistObject = getPlaylistDetails(link) val playlistObject = getPlaylistDetails(link)
folderType = "Playlists" folderType = "Playlists"
subFolder = playlistObject?.name!! subFolder = playlistObject?.name.toString()
val tempTrackList = mutableListOf<Track>() val tempTrackList = mutableListOf<Track>()
playlistObject.tracks?.items?.forEach { Log.i("Tracks Fetched",playlistObject?.tracks?.items?.size.toString())
playlistObject?.tracks?.items?.forEach {
it.track?.let { it.track?.let {
it1 -> if(File(finalOutputDir(it1.name!!,folderType,subFolder)).exists()){//Download Already Present!! it1 -> if(File(finalOutputDir(it1.name!!,folderType,subFolder)).exists()){//Download Already Present!!
it1.downloaded = "Downloaded" it1.downloaded = "Downloaded"
@ -118,8 +121,8 @@ class SpotifyViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO
} }
} }
trackList.value = tempTrackList trackList.value = tempTrackList
title.value = playlistObject.name title.value = playlistObject?.name
coverUrl.value = playlistObject.images?.get(0)!!.url!! coverUrl.value = playlistObject?.images?.get(0)!!.url!!
withContext(Dispatchers.IO){ withContext(Dispatchers.IO){
databaseDAO.insert(DownloadRecord( databaseDAO.insert(DownloadRecord(
type = "Playlist", type = "Playlist",

View File

@ -17,8 +17,6 @@
package com.shabinder.spotiflyer.utils package com.shabinder.spotiflyer.utils
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Environment import android.os.Environment
import android.util.Log import android.util.Log
import android.view.View import android.view.View
@ -40,7 +38,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import java.io.FileInputStream
import java.io.IOException import java.io.IOException
fun finalOutputDir(itemName:String? = null,type:String, subFolder:String?=null,extension:String? = ".mp3"): String{ fun finalOutputDir(itemName:String? = null,type:String, subFolder:String?=null,extension:String? = ".mp3"): String{
@ -68,7 +65,7 @@ fun bindImage(imgView: ImageView, imgUrl: String?) {
imgUrl?.let { imgUrl?.let {
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build() val imgUri = imgUrl.toUri().buildUpon().scheme("https").build()
Glide Glide
.with(imgView.context) .with(imgView)
.asFile() .asFile()
.load(imgUri) .load(imgUri)
.placeholder(R.drawable.ic_song_placeholder) .placeholder(R.drawable.ic_song_placeholder)
@ -97,12 +94,12 @@ fun bindImage(imgView: ImageView, imgUrl: String?) {
Environment.getExternalStorageDirectory(), Environment.getExternalStorageDirectory(),
SpotifyDownloadHelper.defaultDir+".Images/" + imgUrl.substringAfterLast('/',imgUrl) + ".jpeg" SpotifyDownloadHelper.defaultDir+".Images/" + imgUrl.substringAfterLast('/',imgUrl) + ".jpeg"
) // the File to save , append increasing numeric counter to prevent files from getting overwritten. ) // the File to save , append increasing numeric counter to prevent files from getting overwritten.
val options = BitmapFactory.Options()
options.inPreferredConfig = Bitmap.Config.ARGB_8888
val bitmap = BitmapFactory.decodeStream(FileInputStream(resource), null, options)
resource?.copyTo(file) resource?.copyTo(file)
withContext(Dispatchers.Main){ withContext(Dispatchers.Main){
imgView.setImageBitmap(bitmap) Glide.with(imgView)
.load(file)
.placeholder(R.drawable.ic_song_placeholder)
.into(imgView)
// Log.i("Glide","imageSaved") // Log.i("Glide","imageSaved")
} }
} catch (e: IOException) { } catch (e: IOException) {

View File

@ -23,7 +23,7 @@ import com.shabinder.spotiflyer.App
import com.shabinder.spotiflyer.MainActivity import com.shabinder.spotiflyer.MainActivity
import com.shabinder.spotiflyer.database.DatabaseDAO import com.shabinder.spotiflyer.database.DatabaseDAO
import com.shabinder.spotiflyer.database.DownloadRecordDatabase import com.shabinder.spotiflyer.database.DownloadRecordDatabase
import com.shreyaspatil.EasyUpiPayment.EasyUpiPayment import com.shreyaspatil.easyupipayment.EasyUpiPayment
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import dagger.Module import dagger.Module
@ -34,7 +34,6 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory import retrofit2.converter.moshi.MoshiConverterFactory
import javax.inject.Singleton import javax.inject.Singleton
@ -53,14 +52,13 @@ object Provider {
@Provides @Provides
@Singleton @Singleton
fun provideUpi():EasyUpiPayment { fun provideUpi():EasyUpiPayment {
return EasyUpiPayment.Builder() return EasyUpiPayment.Builder(MainActivity.getInstance())
.with(MainActivity.getInstance())
.setPayeeVpa("technoshab@paytm") .setPayeeVpa("technoshab@paytm")
.setPayeeName("Shabinder Singh") .setPayeeName("Shabinder Singh")
.setTransactionId("UNIQUE_TRANSACTION_ID") .setTransactionId("UNIQUE_TRANSACTION_ID")
.setTransactionRefId("UNIQUE_TRANSACTION_REF_ID") .setTransactionRefId("UNIQUE_TRANSACTION_REF_ID")
.setDescription("Thanks for donating") .setDescription("Thanks for donating")
.setAmount("39.00") .setAmount("49.00")
.build() .build()
} }
@ -82,15 +80,13 @@ object Provider {
@Singleton @Singleton
fun getSpotifyTokenInterface():SpotifyServiceTokenRequest{ fun getSpotifyTokenInterface():SpotifyServiceTokenRequest{
val httpClient2: OkHttpClient.Builder = OkHttpClient.Builder() val httpClient2: OkHttpClient.Builder = OkHttpClient.Builder()
httpClient2.addInterceptor(object : Interceptor { httpClient2.addInterceptor(Interceptor { chain ->
override fun intercept(chain: Interceptor.Chain): Response {
val request: Request = val request: Request =
chain.request().newBuilder().addHeader( chain.request().newBuilder().addHeader(
"Authorization", "Authorization",
"Basic ${android.util.Base64.encodeToString("${App.clientId}:${App.clientSecret}".toByteArray(),android.util.Base64.NO_WRAP)}" "Basic ${android.util.Base64.encodeToString("${App.clientId}:${App.clientSecret}".toByteArray(),android.util.Base64.NO_WRAP)}"
).build() ).build()
return chain.proceed(request) chain.proceed(request)
}
}) })
val retrofit = Retrofit.Builder() val retrofit = Retrofit.Builder()

View File

View File

@ -0,0 +1,32 @@
/*
* Copyright (C) 2020 Shabinder Singh
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.shabinder.spotiflyer.utils
import com.shabinder.spotiflyer.downloadHelper.SpotifyDownloadHelper
fun createDirectories() {
createDirectory(SpotifyDownloadHelper.defaultDir)
createDirectory(SpotifyDownloadHelper.defaultDir + ".Images/")
createDirectory(SpotifyDownloadHelper.defaultDir + "Tracks/")
createDirectory(SpotifyDownloadHelper.defaultDir + "Albums/")
createDirectory(SpotifyDownloadHelper.defaultDir + "Playlists/")
createDirectory(SpotifyDownloadHelper.defaultDir + "YT_Downloads/")
}
fun getEmojiByUnicode(unicode: Int): String? {
return String(Character.toChars(unicode))
}

View File

@ -42,7 +42,6 @@ import com.shabinder.spotiflyer.models.DownloadObject
import com.shabinder.spotiflyer.models.Track import com.shabinder.spotiflyer.models.Track
import com.tonyodev.fetch2.* import com.tonyodev.fetch2.*
import com.tonyodev.fetch2core.DownloadBlock import com.tonyodev.fetch2core.DownloadBlock
import com.tonyodev.fetch2core.Func
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@ -123,9 +122,9 @@ class ForegroundService : Service(){
val notification = NotificationCompat.Builder(this, channelId) val notification = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.down_arrowbw) .setSmallIcon(R.drawable.down_arrowbw)
.setNotificationSilent() .setNotificationSilent()
.setSubText("Speed: $speed KB/s") .setSubText("Total: $total Completed:$converted")
.setStyle(NotificationCompat.InboxStyle() .setStyle(NotificationCompat.InboxStyle()
.setBigContentTitle("Total: $total Completed:$converted") .setBigContentTitle("Speed: $speed KB/s")
.addLine(messageList[0]) .addLine(messageList[0])
.addLine(messageList[1]) .addLine(messageList[1])
.addLine(messageList[2]) .addLine(messageList[2])
@ -164,12 +163,12 @@ class ForegroundService : Service(){
request.networkType = NetworkType.ALL request.networkType = NetworkType.ALL
fetch!!.enqueue(request, fetch!!.enqueue(request,
Func { {
obj.track?.let { it1 -> requestMap.put(it, it1) } obj.track?.let { it1 -> requestMap.put(it, it1) }
downloadList.remove(obj) downloadList.remove(obj)
Log.i(tag, "Enqueuing Download") Log.i(tag, "Enqueuing Download")
}, },
Func { {
Log.i(tag, "Enqueuing Error:${it.throwable.toString()}")} Log.i(tag, "Enqueuing Error:${it.throwable.toString()}")}
) )
} }
@ -337,7 +336,7 @@ class ForegroundService : Service(){
requestMap.remove(download.request) requestMap.remove(download.request)
} }
} }
if(requestMap.keys.toList().isEmpty()) speed = 0 speed = 0
updateNotification() updateNotification()
} }
@ -473,10 +472,10 @@ class ForegroundService : Service(){
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notification = NotificationCompat.Builder(this, channelId) val notification = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.down_arrowbw) .setSmallIcon(R.drawable.down_arrowbw)
.setSubText("Speed: $speed KB/s") .setSubText("Total: $total Completed:$converted")
.setNotificationSilent() .setNotificationSilent()
.setStyle(NotificationCompat.InboxStyle() .setStyle(NotificationCompat.InboxStyle()
.setBigContentTitle("Total: $total Completed:$converted") .setBigContentTitle("Speed: $speed KB/s")
.addLine(messageList[0]) .addLine(messageList[0])
.addLine(messageList[1]) .addLine(messageList[1])
.addLine(messageList[2]) .addLine(messageList[2])

View File

@ -1,3 +1,20 @@
<!--
~ Copyright (C) 2020 Shabinder Singh
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt" xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp" android:width="108dp"

17
app/src/main/res/drawable/btn_design.xml Normal file → Executable file
View File

@ -1,4 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (C) 2020 Shabinder Singh
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<shape <shape
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"> android:shape="rectangle">

0
app/src/main/res/drawable/down_arrowbw.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

0
app/src/main/res/drawable/gradient.xml Normal file → Executable file
View File

17
app/src/main/res/drawable/ic_arrow.xml Normal file → Executable file
View File

@ -1,3 +1,20 @@
<!--
~ Copyright (C) 2020 Shabinder Singh
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="26dp" <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="26dp"
android:height="22dp" android:viewportWidth="512" android:viewportHeight="512"> android:height="22dp" android:viewportWidth="512" android:viewportHeight="512">
<path android:fillColor="#516AEC" android:pathData="m296,288 l60,-60c7.73,-7.73 17.86,-11.6 28,-11.6 10.055,0 20.101,3.806 27.806,11.407 15.612,15.402 15.207,41.18 -0.3,56.687l-134.293,134.293c-11.716,11.716 -30.711,11.716 -42.426,0l-134.787,-134.787c-7.73,-7.73 -11.6,-17.86 -11.6,-28 0,-10.055 3.806,-20.101 11.407,-27.806 15.402,-15.612 41.18,-15.207 56.687,0.3l59.506,59.506v-232c0,-22.091 17.909,-40 40,-40 22.091,0 40,17.909 40,40z"/> <path android:fillColor="#516AEC" android:pathData="m296,288 l60,-60c7.73,-7.73 17.86,-11.6 28,-11.6 10.055,0 20.101,3.806 27.806,11.407 15.612,15.402 15.207,41.18 -0.3,56.687l-134.293,134.293c-11.716,11.716 -30.711,11.716 -42.426,0l-134.787,-134.787c-7.73,-7.73 -11.6,-17.86 -11.6,-28 0,-10.055 3.806,-20.101 11.407,-27.806 15.402,-15.612 41.18,-15.207 56.687,0.3l59.506,59.506v-232c0,-22.091 17.909,-40 40,-40 22.091,0 40,17.909 40,40z"/>

0
app/src/main/res/drawable/ic_arrow_share.xml Normal file → Executable file
View File

0
app/src/main/res/drawable/ic_arrow_slim.xml Normal file → Executable file
View File

0
app/src/main/res/drawable/ic_github.xml Normal file → Executable file
View File

0
app/src/main/res/drawable/ic_heart.xml Normal file → Executable file
View File

0
app/src/main/res/drawable/ic_history.xml Normal file → Executable file
View File

0
app/src/main/res/drawable/ic_instagram.xml Normal file → Executable file
View File

17
app/src/main/res/drawable/ic_launcher_background.xml Normal file → Executable file
View File

@ -1,4 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 Shabinder Singh
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp" android:width="108dp"
android:height="108dp" android:height="108dp"

0
app/src/main/res/drawable/ic_linkedin.xml Normal file → Executable file
View File

0
app/src/main/res/drawable/ic_mug.xml Normal file → Executable file
View File

17
app/src/main/res/drawable/ic_musicplaceholder.xml Normal file → Executable file
View File

@ -1,3 +1,20 @@
<!--
~ Copyright (C) 2020 Shabinder Singh
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="300dp" <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="300dp"
android:height="300dp" android:viewportWidth="512" android:viewportHeight="512"> android:height="300dp" android:viewportWidth="512" android:viewportHeight="512">
<path android:fillColor="#A3FFFFFF" android:pathData="m256,80a48.054,48.054 0,0 1,48 48v32h12a19.991,19.991 0,0 0,3.524 -39.671,63.984 63.984,0 0,0 -127.048,0 19.991,19.991 0,0 0,3.524 39.671h12v-32a48.054,48.054 0,0 1,48 -48z"/> <path android:fillColor="#A3FFFFFF" android:pathData="m256,80a48.054,48.054 0,0 1,48 48v32h12a19.991,19.991 0,0 0,3.524 -39.671,63.984 63.984,0 0,0 -127.048,0 19.991,19.991 0,0 0,3.524 39.671h12v-32a48.054,48.054 0,0 1,48 -48z"/>

0
app/src/main/res/drawable/ic_refresh.xml Normal file → Executable file
View File

0
app/src/main/res/drawable/ic_refreshgradient.xml Normal file → Executable file
View File

0
app/src/main/res/drawable/ic_share_open.xml Normal file → Executable file
View File

17
app/src/main/res/drawable/ic_song_placeholder.xml Normal file → Executable file
View File

@ -1,3 +1,20 @@
<!--
~ Copyright (C) 2020 Shabinder Singh
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="42dp" <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="42dp"
android:height="42dp" android:viewportWidth="512" android:viewportHeight="512"> android:height="42dp" android:viewportWidth="512" android:viewportHeight="512">
<path android:fillColor="#A3FFFFFF" android:pathData="m511.739,103.734 l-257,50.947v233.725c-10.733,-7.199 -23.633,-11.406 -37.5,-11.406 -37.22,0 -67.5,30.28 -67.5,67.5s30.28,67.5 67.5,67.5c34.684,0 63.329,-26.299 67.073,-60h0.427v-182.682l197,-39.053v98.141c-10.733,-7.199 -23.633,-11.406 -37.5,-11.406 -37.22,0 -67.5,30.28 -67.5,67.5s30.28,67.5 67.5,67.5c39.927,0 71.547,-34.762 67.073,-75h0.427zM217.239,482c-20.678,0 -37.5,-16.822 -37.5,-37.5s16.822,-37.5 37.5,-37.5 37.5,16.822 37.5,37.5 -16.822,37.5 -37.5,37.5zM444.239,422c-20.678,0 -37.5,-16.822 -37.5,-37.5s16.822,-37.5 37.5,-37.5 37.5,16.822 37.5,37.5 -16.822,37.5 -37.5,37.5zM481.739,199.682 L284.739,238.735v-59.416l197,-39.053z"/> <path android:fillColor="#A3FFFFFF" android:pathData="m511.739,103.734 l-257,50.947v233.725c-10.733,-7.199 -23.633,-11.406 -37.5,-11.406 -37.22,0 -67.5,30.28 -67.5,67.5s30.28,67.5 67.5,67.5c34.684,0 63.329,-26.299 67.073,-60h0.427v-182.682l197,-39.053v98.141c-10.733,-7.199 -23.633,-11.406 -37.5,-11.406 -37.22,0 -67.5,30.28 -67.5,67.5s30.28,67.5 67.5,67.5c39.927,0 71.547,-34.762 67.073,-75h0.427zM217.239,482c-20.678,0 -37.5,-16.822 -37.5,-37.5s16.822,-37.5 37.5,-37.5 37.5,16.822 37.5,37.5 -16.822,37.5 -37.5,37.5zM444.239,422c-20.678,0 -37.5,-16.822 -37.5,-37.5s16.822,-37.5 37.5,-37.5 37.5,16.822 37.5,37.5 -16.822,37.5 -37.5,37.5zM481.739,199.682 L284.739,238.735v-59.416l197,-39.053z"/>

0
app/src/main/res/drawable/ic_spotify_logo.xml Normal file → Executable file
View File

0
app/src/main/res/drawable/ic_tick.xml Normal file → Executable file
View File

0
app/src/main/res/drawable/ic_youtube.xml Normal file → Executable file
View File

17
app/src/main/res/drawable/rounded_gradient.xml Normal file → Executable file
View File

@ -1,4 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 Shabinder Singh
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android" > <shape xmlns:android="http://schemas.android.com/apk/res/android" >
<gradient <gradient
android:angle="90" android:angle="90"

0
app/src/main/res/drawable/spotify_download.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

17
app/src/main/res/drawable/text_background.xml Normal file → Executable file
View File

@ -1,4 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 Shabinder Singh
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android" <shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" android:shape="rectangle"
> >

19
app/src/main/res/drawable/text_background_accented.xml Normal file → Executable file
View File

@ -1,4 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?><layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <?xml version="1.0" encoding="UTF-8"?><!--
~ Copyright (C) 2020 Shabinder Singh
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item> <item>
<!-- create gradient you want to use with the angle you want to use --> <!-- create gradient you want to use with the angle you want to use -->

0
app/src/main/res/drawable/transparent.xml Normal file → Executable file
View File

0
app/src/main/res/font/amita.xml Normal file → Executable file
View File

17
app/src/main/res/font/averia_libre.xml Normal file → Executable file
View File

@ -1,4 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 Shabinder Singh
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<font-family xmlns:app="http://schemas.android.com/apk/res-auto" <font-family xmlns:app="http://schemas.android.com/apk/res-auto"
app:fontProviderAuthority="com.google.android.gms.fonts" app:fontProviderAuthority="com.google.android.gms.fonts"
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs" app:fontProviderCerts="@array/com_google_android_gms_fonts_certs"

17
app/src/main/res/font/capriola.xml Normal file → Executable file
View File

@ -1,4 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 Shabinder Singh
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<font-family xmlns:app="http://schemas.android.com/apk/res-auto" <font-family xmlns:app="http://schemas.android.com/apk/res-auto"
app:fontProviderAuthority="com.google.android.gms.fonts" app:fontProviderAuthority="com.google.android.gms.fonts"
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs" app:fontProviderCerts="@array/com_google_android_gms_fonts_certs"

17
app/src/main/res/font/raleway.xml Normal file → Executable file
View File

@ -1,4 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 Shabinder Singh
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<font-family xmlns:app="http://schemas.android.com/apk/res-auto" <font-family xmlns:app="http://schemas.android.com/apk/res-auto"
app:fontProviderAuthority="com.google.android.gms.fonts" app:fontProviderAuthority="com.google.android.gms.fonts"
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs" app:fontProviderCerts="@array/com_google_android_gms_fonts_certs"

17
app/src/main/res/font/raleway_semibold.xml Normal file → Executable file
View File

@ -1,4 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 Shabinder Singh
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<font-family xmlns:app="http://schemas.android.com/apk/res-auto" <font-family xmlns:app="http://schemas.android.com/apk/res-auto"
app:fontProviderAuthority="com.google.android.gms.fonts" app:fontProviderAuthority="com.google.android.gms.fonts"
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs" app:fontProviderCerts="@array/com_google_android_gms_fonts_certs"

Some files were not shown because too many files have changed in this diff Show More