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">
<code_scheme name="Project" version="173">
<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" />
</JetCodeStyleSettings>
<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">
<words>
<w>downloadrecord</w>
<w>emoji</w>
<w>ffmpeg</w>
<w>flyer</w>
<w>insta</w>
<w>instagram</w>
<w>jetbrains</w>
<w>kotlinx</w>
<w>mainfragment</w>
<w>maxresdefault</w>
<w>moshi</w>
<w>mozilla</w>
<w>musicforeveryone</w>
<w>musicplaceholder</w>
<w>raleway</w>
<w>semibold</w>
<w>shabinder</w>
<w>singh</w>
<w>spoti</w>

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

@ -16,6 +16,7 @@
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
<option name="useQualifiedModuleNames" value="true" />
</GradleProjectSettings>
</option>
</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">
<file url="file://$PROJECT_DIR$/app/src/main/java/com/shabinder/spotiflyer/testing/YoutubeInterface.kt.backup" />
</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" />
</component>
<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 {
compileSdkVersion 29
buildToolsVersion "30.0.0"
buildToolsVersion "30.0.2"
buildFeatures{
dataBinding = true
@ -35,8 +35,8 @@ android {
applicationId 'com.shabinder.spotiflyer'
minSdkVersion 22
targetSdkVersion 29
versionCode 5
versionName "1.4"
versionCode 6
versionName "1.5"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
packagingOptions {
@ -61,6 +61,9 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
lintOptions {
abortOnError false
}
@ -73,20 +76,20 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include:['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.1'
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.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.webkit:webkit:1.3.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'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.1'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.google.android.material:material:1.2.0'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7"
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 "androidx.room:room-runtime:2.2.5"
kapt "androidx.room:room-compiler:2.2.5"
@ -106,30 +109,21 @@ dependencies {
transitive = true
}
// Authentication Way Changed!
// 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.okhttp3:okhttp:4.9.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation "com.squareup.moshi:moshi:1.9.3"
implementation "com.squareup.moshi:moshi-kotlin:1.9.3"
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.mpatric:mp3agic:0.9.1'
implementation 'com.shreyaspatil:EasyUpiPayment:2.2'
implementation 'com.github.sealedtx:java-youtube-downloader:2.2.3'
implementation "androidx.tonyodev.fetch2:xfetch2:3.1.4"
implementation 'com.shreyaspatil:EasyUpiPayment:3.0.0'
implementation 'com.github.sealedtx:java-youtube-downloader:2.4.2'
implementation "androidx.tonyodev.fetch2:xfetch2:3.1.5"
implementation 'com.github.javiersantos:AppUpdater:2.7'
implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
testImplementation 'junit:junit:4.13.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
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"
xmlns:tools="http://schemas.android.com/tools"
package="com.shabinder.spotiflyer">
<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.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<!-- <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />-->
<application
android:name=".App"
android:allowBackup="true"
@ -38,10 +37,13 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:forceDarkAllowed="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>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
@ -57,10 +59,7 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- <activity
android:name="com.spotify.sdk.android.authentication.LoginActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
-->
<meta-data
android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" />
@ -68,5 +67,4 @@
<service android:name=".worker.ForegroundService"/>
</application>
</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.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
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.utils.SpotifyService
import com.shabinder.spotiflyer.utils.SpotifyServiceTokenRequest
import com.shabinder.spotiflyer.utils.createDirectory
import com.shabinder.spotiflyer.utils.createDirectories
import com.squareup.moshi.Moshi
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
@ -62,20 +63,12 @@ class MainActivity : AppCompatActivity(){
@Inject lateinit var spotifyServiceTokenRequest: SpotifyServiceTokenRequest
@Inject lateinit var moshi: Moshi
companion object{
private var instance = MainActivity()
fun getInstance():MainActivity{
return instance
}
}
init {
instance = this
}
override fun onCreate(savedInstanceState: Bundle?) {
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)
//Enabling Dark Mode
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
sharedPref = this.getPreferences(Context.MODE_PRIVATE)
//starting Notification and Downloader Service!
@ -93,11 +86,17 @@ class MainActivity : AppCompatActivity(){
createDirectories()
isConnected = sharedViewModel.isOnline(this)
sharedViewModel.isConnected.value = isConnected
Log.i("Connection Status",isConnected.toString())
Log.i("Connection Status", isConnected.toString())
handleIntentFromExternalActivity()
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
Log.i("NEW INTENT", "Received")
handleIntentFromExternalActivity(intent)
}
@SuppressLint("BatteryLife")
fun disableDozeMode() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
@ -133,7 +132,7 @@ class MainActivity : AppCompatActivity(){
/**
* Adding my own new Spotify Web Api Requests!
* */
private fun implementSpotifyService(token:String) {
private fun implementSpotifyService(token: String) {
val httpClient: OkHttpClient.Builder = OkHttpClient.Builder()
httpClient.addInterceptor(object : Interceptor {
@ -175,12 +174,12 @@ class MainActivity : AppCompatActivity(){
}
private fun handleIntentFromExternalActivity() {
private fun handleIntentFromExternalActivity(intent: Intent? = getIntent()) {
if (intent?.action == Intent.ACTION_SEND) {
if ("text/plain" == intent.type) {
intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
Log.i("Intent Received",it)
sharedViewModel.intentString = it
Log.i("Intent Received", it)
sharedViewModel.intentString.value = it
}
}
}
@ -195,8 +194,8 @@ class MainActivity : AppCompatActivity(){
}
}
override fun onSaveInstanceState(savedInstanceState:Bundle) {
savedInstanceState.putString("token",token)
override fun onSaveInstanceState(savedInstanceState: Bundle) {
savedInstanceState.putString("token", token)
super.onSaveInstanceState(savedInstanceState)
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
@ -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() {
val appUpdater = AppUpdater(this)
.showAppUpdated(false)//true:Show App is Update Dialog
@ -234,4 +224,14 @@ class MainActivity : AppCompatActivity(){
}
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
class SharedViewModel : ViewModel() {
var intentString = ""
var intentString = MutableLiveData<String>().apply { value = "" }
var spotifyService = MutableLiveData<SpotifyService>()
var accessToken = MutableLiveData<String>().apply { value = "" }
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.animation.AlphaAnimation
import android.view.animation.Animation
import android.webkit.ValueCallback
import android.webkit.WebView
import android.webkit.WebViewClient
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.Track
import com.shabinder.spotiflyer.ui.spotify.SpotifyViewModel
import com.shabinder.spotiflyer.utils.getEmojiByUnicode
import com.shabinder.spotiflyer.worker.ForegroundService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -53,6 +53,7 @@ object SpotifyDownloadHelper {
private var isBrowserLoading = false
private var total = 0
private var Processed = 0
private var notFound = 0
private var listProcessed:Boolean = false
var youtubeList = mutableListOf<YoutubeRequest>()
@ -107,36 +108,40 @@ object SpotifyDownloadHelper {
super.onPageFinished(view, url)
view?.evaluateJavascript(
"document.getElementsByClassName(\"yt-simple-endpoint style-scope ytd-video-renderer\")[0].href"
,object :ValueCallback<String>{
override fun onReceiveValue(value: String?) {
Log.i("YT-id",value.toString().replace("\"",""))
val id = value!!.substringAfterLast("=", "error").replace("\"","")
Log.i("YT-id",id)
if(id !="error"){//Link extracting error
Processed++
updateStatusBar()
downloadFile(subFolder, type, track,ytDownloader,id)
}
if(youtubeList.isNotEmpty()){
val request = youtubeList[0]
spotifyViewModel!!.uiScope.launch {
getYTLink(request.type,request.subFolder,request.ytDownloader,request.searchQuery,request.track)
}
youtubeList.remove(request)
if(youtubeList.size == 0){//list processing completed , webView is free again!
isBrowserLoading = false
listProcessed = true
}
}else{//YT List Empty....Maybe it was one Single Download
Handler().postDelayed({//Delay of 1.5 sec
if(youtubeList.isEmpty()){//Lets Make It sure , There are No more Downloads In Queue.....
isBrowserLoading = false
listProcessed = true
}
},1500)
}
) { value ->
Log.i("YT-id Link", value.toString().replace("\"", ""))
val id = value!!.substringAfterLast("=", "error").replace("\"", "")
Log.i("YT-ID", id)
if (id != "error") {//Link extracting error
Processed++
downloadFile(subFolder, type, track, ytDownloader, id)
}else notFound++
updateStatusBar()
if (youtubeList.isNotEmpty()) {
val request = youtubeList[0]
spotifyViewModel!!.uiScope.launch {
getYTLink(
request.type,
request.subFolder,
request.ytDownloader,
request.searchQuery,
request.track
)
}
} )
youtubeList.remove(request)
if (youtubeList.size == 0) {//list processing completed , webView is free again!
isBrowserLoading = false
listProcessed = true
}
} else {//YT List Empty....Maybe it was one Single Download
Handler().postDelayed({//Delay of 1.5 sec
if (youtubeList.isEmpty()) {//Lets Make It sure , There are No more Downloads In Queue.....
isBrowserLoading = false
listProcessed = true
}
}, 1500)
}
}
}
}
}
@ -144,42 +149,51 @@ object SpotifyDownloadHelper {
private fun updateStatusBar() {
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) {
spotifyViewModel!!.uiScope.launch {
withContext(Dispatchers.IO) {
val video = ytDownloader?.getVideo(id)
val detail = video?.details()
val format:Format? =try {
video?.findAudioWithQuality(AudioQuality.high)?.get(0) as Format
}catch (e:java.lang.IndexOutOfBoundsException){
try {
video?.findAudioWithQuality(AudioQuality.medium)?.get(0) as Format
}catch (e:java.lang.IndexOutOfBoundsException){
try{
video?.findAudioWithQuality(AudioQuality.low)?.get(0) as Format
}catch (e:java.lang.IndexOutOfBoundsException){
Log.i("YTDownloader",e.toString())
null
try {
val video = ytDownloader?.getVideo(id)
val detail = video?.details()
val format: Format? = try {
video?.findAudioWithQuality(AudioQuality.high)?.get(0) as Format
} catch (e: java.lang.IndexOutOfBoundsException) {
try {
video?.findAudioWithQuality(AudioQuality.medium)?.get(0) as Format
} catch (e: java.lang.IndexOutOfBoundsException) {
try {
video?.findAudioWithQuality(AudioQuality.low)?.get(0) as Format
} catch (e: java.lang.IndexOutOfBoundsException) {
Log.i("YTDownloader", e.toString())
null
}
}
}
}
format?.let {
val url:String = format.url()
// Log.i("DHelper Link Found", url)
val outputFile:String = Environment.getExternalStorageDirectory().toString() + File.separator +
defaultDir + removeIllegalChars(type) + File.separator + (if(subFolder == null){""}else{ removeIllegalChars(subFolder) + File.separator} + removeIllegalChars(track.name!!)+".m4a")
format?.let {
val url: String = format.url()
Log.i("DHelper Link Found", url)
val outputFile: String =
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(
track = track,
url = url,
outputDir = outputFile
)
Log.i("DH",outputFile)
startService(context!!, downloadObject)
val downloadObject = DownloadObject(
track = track,
url = url,
outputDir = outputFile
)
Log.i("DH", outputFile)
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){
holder.binding.imageUrl.visibility = View.GONE}else{
spotifyViewModel!!.uiScope.launch {
//Placeholder Set
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 androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import com.shabinder.spotiflyer.R
import com.shabinder.spotiflyer.SharedViewModel
import com.shabinder.spotiflyer.databinding.MainFragmentBinding
import com.shreyaspatil.EasyUpiPayment.EasyUpiPayment
import com.shreyaspatil.easyupipayment.EasyUpiPayment
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@ -92,7 +91,17 @@ class MainFragment : Fragment() {
* Handle Intent If there is any!
**/
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
if (it != ""){
if(sharedViewModel.intentString != ""){
@ -101,7 +110,7 @@ class MainFragment : Fragment() {
sharedViewModel.intentString = ""
}
}
})
})*/
}
/**

View File

@ -36,6 +36,7 @@ import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.SimpleItemAnimator
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
@ -96,7 +97,7 @@ class SpotifyFragment : Fragment() {
if(sharedViewModel.spotifyService.value == null){//Authentication pending!!
(activity as MainActivity).authenticateSpotify()
}
if(!isNotOnline()){//Device Offline
if(!isOnline()){//Device Offline
sharedViewModel.showAlertDialog(resources,requireContext())
}else if (type == "Error" || link == "Error") {//Incorrect Link
showToast("Please Check Your Link!")
@ -179,14 +180,14 @@ class SpotifyFragment : Fragment() {
/**
* CoverUrl Binding Observer!
**/
spotifyViewModel.coverUrl.observe(viewLifecycleOwner, Observer {
spotifyViewModel.coverUrl.observe(viewLifecycleOwner, {
if(it!="Loading") bindImage(binding.spotifyCoverImage,it)
})
/**
* TrackList Binding Observer!
**/
spotifyViewModel.trackList.observe(viewLifecycleOwner, Observer {
spotifyViewModel.trackList.observe(viewLifecycleOwner, {
if (it.isNotEmpty()){
Log.i("SpotifyFragment","TrackList Updated")
adapterConfig(it)
@ -197,9 +198,17 @@ class SpotifyFragment : Fragment() {
/**
* Title Binding Observer!
**/
spotifyViewModel.title.observe(viewLifecycleOwner, Observer {
spotifyViewModel.title.observe(viewLifecycleOwner, {
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() {
@ -230,6 +239,7 @@ class SpotifyFragment : Fragment() {
SpotifyDownloadHelper.spotifyViewModel = spotifyViewModel
SpotifyDownloadHelper.statusBar = binding.StatusBarSpotify
binding.trackListSpotify.adapter = adapterSpotify
(binding.trackListSpotify.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
}
/**
@ -237,7 +247,7 @@ class SpotifyFragment : Fragment() {
**/
private fun loadAllImages(trackList: List<Track>) {
trackList.forEach {
val imgUrl = it.album!!.images?.get(0)?.url
val imgUrl = it.album?.images?.get(0)?.url
imgUrl?.let {
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build()
Glide
@ -295,14 +305,14 @@ class SpotifyFragment : Fragment() {
/**
* Util. Function to create toasts!
**/
fun showToast(message:String){
private fun showToast(message:String){
Toast.makeText(context,message,Toast.LENGTH_SHORT).show()
}
/**
* Util. Function To Check Connection Status
**/
private fun isNotOnline(): Boolean {
private fun isOnline(): Boolean {
val cm =
requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
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.DownloadRecord
import com.shabinder.spotiflyer.models.Album
import com.shabinder.spotiflyer.models.Image
import com.shabinder.spotiflyer.models.Playlist
import com.shabinder.spotiflyer.models.Track
import com.shabinder.spotiflyer.utils.SpotifyService
@ -78,23 +79,24 @@ class SpotifyViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO
uiScope.launch {
val albumObject = getAlbumDetails(link)
folderType = "Albums"
subFolder = albumObject?.name!!
subFolder = albumObject?.name.toString()
val tempTrackList = mutableListOf<Track>()
albumObject.tracks?.items?.forEach {
albumObject?.tracks?.items?.forEach {
if(File(finalOutputDir(it.name!!,folderType,subFolder)).exists()){//Download Already Present!!
it.downloaded = "Downloaded"
}
it.album = Album(images = listOf(Image(url = albumObject.images?.get(0)?.url)))
tempTrackList.add(it)
}
trackList.value = tempTrackList
title.value = albumObject.name
coverUrl.value = albumObject.images?.get(0)!!.url!!
title.value = albumObject?.name
coverUrl.value = albumObject?.images?.get(0)?.url
withContext(Dispatchers.IO){
databaseDAO.insert(DownloadRecord(
type = "Album",
name = title.value!!,
link = "https://open.spotify.com/$type/$link",
coverUrl = coverUrl.value!!,
coverUrl = coverUrl.value.toString(),
totalFiles = tempTrackList.size,
downloaded = File(finalOutputDir(type = folderType,subFolder = subFolder)).listFiles()?.size == tempTrackList.size,
directory = finalOutputDir(type = folderType,subFolder = subFolder)
@ -107,9 +109,10 @@ class SpotifyViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO
uiScope.launch {
val playlistObject = getPlaylistDetails(link)
folderType = "Playlists"
subFolder = playlistObject?.name!!
subFolder = playlistObject?.name.toString()
val tempTrackList = mutableListOf<Track>()
playlistObject.tracks?.items?.forEach {
Log.i("Tracks Fetched",playlistObject?.tracks?.items?.size.toString())
playlistObject?.tracks?.items?.forEach {
it.track?.let {
it1 -> if(File(finalOutputDir(it1.name!!,folderType,subFolder)).exists()){//Download Already Present!!
it1.downloaded = "Downloaded"
@ -118,8 +121,8 @@ class SpotifyViewModel @ViewModelInject constructor(val databaseDAO: DatabaseDAO
}
}
trackList.value = tempTrackList
title.value = playlistObject.name
coverUrl.value = playlistObject.images?.get(0)!!.url!!
title.value = playlistObject?.name
coverUrl.value = playlistObject?.images?.get(0)!!.url!!
withContext(Dispatchers.IO){
databaseDAO.insert(DownloadRecord(
type = "Playlist",

View File

@ -17,8 +17,6 @@
package com.shabinder.spotiflyer.utils
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Environment
import android.util.Log
import android.view.View
@ -40,7 +38,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileInputStream
import java.io.IOException
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 {
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build()
Glide
.with(imgView.context)
.with(imgView)
.asFile()
.load(imgUri)
.placeholder(R.drawable.ic_song_placeholder)
@ -97,12 +94,12 @@ fun bindImage(imgView: ImageView, imgUrl: String?) {
Environment.getExternalStorageDirectory(),
SpotifyDownloadHelper.defaultDir+".Images/" + imgUrl.substringAfterLast('/',imgUrl) + ".jpeg"
) // 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)
withContext(Dispatchers.Main){
imgView.setImageBitmap(bitmap)
Glide.with(imgView)
.load(file)
.placeholder(R.drawable.ic_song_placeholder)
.into(imgView)
// Log.i("Glide","imageSaved")
}
} catch (e: IOException) {

View File

@ -23,7 +23,7 @@ import com.shabinder.spotiflyer.App
import com.shabinder.spotiflyer.MainActivity
import com.shabinder.spotiflyer.database.DatabaseDAO
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.kotlin.reflect.KotlinJsonAdapterFactory
import dagger.Module
@ -34,7 +34,6 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import javax.inject.Singleton
@ -53,14 +52,13 @@ object Provider {
@Provides
@Singleton
fun provideUpi():EasyUpiPayment {
return EasyUpiPayment.Builder()
.with(MainActivity.getInstance())
return EasyUpiPayment.Builder(MainActivity.getInstance())
.setPayeeVpa("technoshab@paytm")
.setPayeeName("Shabinder Singh")
.setTransactionId("UNIQUE_TRANSACTION_ID")
.setTransactionRefId("UNIQUE_TRANSACTION_REF_ID")
.setDescription("Thanks for donating")
.setAmount("39.00")
.setAmount("49.00")
.build()
}
@ -82,15 +80,13 @@ object Provider {
@Singleton
fun getSpotifyTokenInterface():SpotifyServiceTokenRequest{
val httpClient2: OkHttpClient.Builder = OkHttpClient.Builder()
httpClient2.addInterceptor(object : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request: Request =
chain.request().newBuilder().addHeader(
"Authorization",
"Basic ${android.util.Base64.encodeToString("${App.clientId}:${App.clientSecret}".toByteArray(),android.util.Base64.NO_WRAP)}"
).build()
return chain.proceed(request)
}
httpClient2.addInterceptor(Interceptor { chain ->
val request: Request =
chain.request().newBuilder().addHeader(
"Authorization",
"Basic ${android.util.Base64.encodeToString("${App.clientId}:${App.clientSecret}".toByteArray(),android.util.Base64.NO_WRAP)}"
).build()
chain.proceed(request)
})
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.tonyodev.fetch2.*
import com.tonyodev.fetch2core.DownloadBlock
import com.tonyodev.fetch2core.Func
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@ -123,9 +122,9 @@ class ForegroundService : Service(){
val notification = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.down_arrowbw)
.setNotificationSilent()
.setSubText("Speed: $speed KB/s")
.setSubText("Total: $total Completed:$converted")
.setStyle(NotificationCompat.InboxStyle()
.setBigContentTitle("Total: $total Completed:$converted")
.setBigContentTitle("Speed: $speed KB/s")
.addLine(messageList[0])
.addLine(messageList[1])
.addLine(messageList[2])
@ -164,12 +163,12 @@ class ForegroundService : Service(){
request.networkType = NetworkType.ALL
fetch!!.enqueue(request,
Func {
{
obj.track?.let { it1 -> requestMap.put(it, it1) }
downloadList.remove(obj)
Log.i(tag, "Enqueuing Download")
},
Func {
{
Log.i(tag, "Enqueuing Error:${it.throwable.toString()}")}
)
}
@ -337,7 +336,7 @@ class ForegroundService : Service(){
requestMap.remove(download.request)
}
}
if(requestMap.keys.toList().isEmpty()) speed = 0
speed = 0
updateNotification()
}
@ -473,10 +472,10 @@ class ForegroundService : Service(){
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notification = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.down_arrowbw)
.setSubText("Speed: $speed KB/s")
.setSubText("Total: $total Completed:$converted")
.setNotificationSilent()
.setStyle(NotificationCompat.InboxStyle()
.setBigContentTitle("Total: $total Completed:$converted")
.setBigContentTitle("Speed: $speed KB/s")
.addLine(messageList[0])
.addLine(messageList[1])
.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"
xmlns:aapt="http://schemas.android.com/aapt"
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"?>
<!--
~ 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"
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"
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"/>

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"?>
<!--
~ 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="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"
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"/>

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"
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"/>

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"?>
<!--
~ 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" >
<gradient
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"?>
<!--
~ 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"
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>
<!-- 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"?>
<!--
~ 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"
app:fontProviderAuthority="com.google.android.gms.fonts"
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"?>
<!--
~ 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"
app:fontProviderAuthority="com.google.android.gms.fonts"
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"?>
<!--
~ 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"
app:fontProviderAuthority="com.google.android.gms.fonts"
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"?>
<!--
~ 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"
app:fontProviderAuthority="com.google.android.gms.fonts"
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