Album Bug Fixes & Dependencies Updated.
0
.github/FUNDING.yml
vendored
Normal file → Executable file
16
.idea/codeStyles/Project.xml
Normal file → Executable 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
6
.idea/dictionaries/shabinder.xml
Normal file → Executable 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
@ -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
2
.idea/misc.xml
Normal file → Executable 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
0
.idea/vcs.xml
Normal file → Executable file
0
ScreenShots/DownloadHistory.png
Normal file → Executable file
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
0
ScreenShots/HomeScreen.png
Normal file → Executable file
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
0
ScreenShots/LibraryScreen.jpg
Normal file → Executable file
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
0
ScreenShots/LibraryScreen2.jpg
Normal file → Executable file
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 111 KiB |
0
ScreenShots/Notification.png
Normal file → Executable file
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
0
ScreenShots/PlayList.png
Normal file → Executable file
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
0
app/.gitignore
vendored
Normal file → Executable file
0
app/SpotifyDownload.png
Normal file → Executable file
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
54
app/build.gradle
Normal file → Executable 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
Before Width: | Height: | Size: 724 B After Width: | Height: | Size: 724 B |
0
app/proguard-rules.pro
vendored
Normal file → Executable file
0
app/src/androidTest/java/com/shabinder/spotiflyer/ExampleInstrumentedTest.kt
Normal file → Executable file
16
app/src/main/AndroidManifest.xml
Normal file → Executable 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
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
56
app/src/main/java/com/shabinder/spotiflyer/MainActivity.kt
Normal file → Executable 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!
|
||||||
@ -93,11 +86,17 @@ class MainActivity : AppCompatActivity(){
|
|||||||
createDirectories()
|
createDirectories()
|
||||||
isConnected = sharedViewModel.isOnline(this)
|
isConnected = sharedViewModel.isOnline(this)
|
||||||
sharedViewModel.isConnected.value = isConnected
|
sharedViewModel.isConnected.value = isConnected
|
||||||
Log.i("Connection Status",isConnected.toString())
|
Log.i("Connection Status", isConnected.toString())
|
||||||
|
|
||||||
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) {
|
||||||
@ -133,7 +132,7 @@ class MainActivity : AppCompatActivity(){
|
|||||||
/**
|
/**
|
||||||
* Adding my own new Spotify Web Api Requests!
|
* Adding my own new Spotify Web Api Requests!
|
||||||
* */
|
* */
|
||||||
private fun implementSpotifyService(token:String) {
|
private fun implementSpotifyService(token: String) {
|
||||||
val httpClient: OkHttpClient.Builder = OkHttpClient.Builder()
|
val httpClient: OkHttpClient.Builder = OkHttpClient.Builder()
|
||||||
httpClient.addInterceptor(object : Interceptor {
|
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 (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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,8 +194,8 @@ class MainActivity : AppCompatActivity(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(savedInstanceState:Bundle) {
|
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||||
savedInstanceState.putString("token",token)
|
savedInstanceState.putString("token", token)
|
||||||
super.onSaveInstanceState(savedInstanceState)
|
super.onSaveInstanceState(savedInstanceState)
|
||||||
}
|
}
|
||||||
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
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() {
|
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
|
||||||
|
}
|
||||||
}
|
}
|
2
app/src/main/java/com/shabinder/spotiflyer/SharedViewModel.kt
Normal file → Executable 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 }
|
||||||
|
0
app/src/main/java/com/shabinder/spotiflyer/database/DatabaseDAO.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/database/DownloadRecord.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/database/DownloadRecordDatabase.kt
Normal file → Executable file
128
app/src/main/java/com/shabinder/spotiflyer/downloadHelper/SpotifyDownloadHelper.kt
Normal file → Executable 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,36 +108,40 @@ 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++
|
downloadFile(subFolder, type, track, ytDownloader, id)
|
||||||
updateStatusBar()
|
}else notFound++
|
||||||
downloadFile(subFolder, type, track,ytDownloader,id)
|
updateStatusBar()
|
||||||
}
|
if (youtubeList.isNotEmpty()) {
|
||||||
if(youtubeList.isNotEmpty()){
|
val request = youtubeList[0]
|
||||||
val request = youtubeList[0]
|
spotifyViewModel!!.uiScope.launch {
|
||||||
spotifyViewModel!!.uiScope.launch {
|
getYTLink(
|
||||||
getYTLink(request.type,request.subFolder,request.ytDownloader,request.searchQuery,request.track)
|
request.type,
|
||||||
}
|
request.subFolder,
|
||||||
youtubeList.remove(request)
|
request.ytDownloader,
|
||||||
if(youtubeList.size == 0){//list processing completed , webView is free again!
|
request.searchQuery,
|
||||||
isBrowserLoading = false
|
request.track
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} )
|
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() {
|
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) {
|
||||||
val video = ytDownloader?.getVideo(id)
|
try {
|
||||||
val detail = video?.details()
|
val video = ytDownloader?.getVideo(id)
|
||||||
val format:Format? =try {
|
val detail = video?.details()
|
||||||
video?.findAudioWithQuality(AudioQuality.high)?.get(0) as Format
|
val format: Format? = try {
|
||||||
}catch (e:java.lang.IndexOutOfBoundsException){
|
video?.findAudioWithQuality(AudioQuality.high)?.get(0) as Format
|
||||||
try {
|
} catch (e: java.lang.IndexOutOfBoundsException) {
|
||||||
video?.findAudioWithQuality(AudioQuality.medium)?.get(0) as Format
|
try {
|
||||||
}catch (e:java.lang.IndexOutOfBoundsException){
|
video?.findAudioWithQuality(AudioQuality.medium)?.get(0) as Format
|
||||||
try{
|
} catch (e: java.lang.IndexOutOfBoundsException) {
|
||||||
video?.findAudioWithQuality(AudioQuality.low)?.get(0) as Format
|
try {
|
||||||
}catch (e:java.lang.IndexOutOfBoundsException){
|
video?.findAudioWithQuality(AudioQuality.low)?.get(0) as Format
|
||||||
Log.i("YTDownloader",e.toString())
|
} catch (e: java.lang.IndexOutOfBoundsException) {
|
||||||
null
|
Log.i("YTDownloader", e.toString())
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
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 =
|
||||||
val outputFile:String = Environment.getExternalStorageDirectory().toString() + File.separator +
|
Environment.getExternalStorageDirectory().toString() + File.separator +
|
||||||
defaultDir + removeIllegalChars(type) + File.separator + (if(subFolder == null){""}else{ removeIllegalChars(subFolder) + File.separator} + removeIllegalChars(track.name!!)+".m4a")
|
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,
|
||||||
url = url,
|
url = url,
|
||||||
outputDir = outputFile
|
outputDir = outputFile
|
||||||
)
|
)
|
||||||
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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
0
app/src/main/java/com/shabinder/spotiflyer/downloadHelper/YTDownloadHelper.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/Album.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/Artist.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/Copyright.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/DownloadObject.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/Episodes.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/Followers.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/Image.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/LinkedTrack.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/PagingObjectPlaylistTrack.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/PagingObjectTrack.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/Playlist.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/PlaylistTrack.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/Token.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/Track.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/UserPrivate.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/UserPublic.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/models/YTTrack.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/recyclerView/DownloadRecordAdapter.kt
Normal file → Executable file
1
app/src/main/java/com/shabinder/spotiflyer/recyclerView/SpotifyTrackListAdapter.kt
Normal file → Executable 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
0
app/src/main/java/com/shabinder/spotiflyer/recyclerView/YoutubeTrackListAdapter.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/samples/response examples.txt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/splash/SplashScreen.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/ui/downloadrecord/DownloadRecordFragment.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/ui/downloadrecord/DownloadRecordViewModel.kt
Normal file → Executable file
17
app/src/main/java/com/shabinder/spotiflyer/ui/mainfragment/MainFragment.kt
Normal file → Executable 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 = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
0
app/src/main/java/com/shabinder/spotiflyer/ui/mainfragment/MainViewModel.kt
Normal file → Executable file
24
app/src/main/java/com/shabinder/spotiflyer/ui/spotify/SpotifyFragment.kt
Normal file → Executable 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
|
||||||
|
21
app/src/main/java/com/shabinder/spotiflyer/ui/spotify/SpotifyViewModel.kt
Normal file → Executable 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",
|
||||||
|
0
app/src/main/java/com/shabinder/spotiflyer/ui/youtube/YoutubeFragment.kt
Normal file → Executable file
0
app/src/main/java/com/shabinder/spotiflyer/ui/youtube/YoutubeViewModel.kt
Normal file → Executable file
13
app/src/main/java/com/shabinder/spotiflyer/utils/BindingAdapter.kt
Normal file → Executable 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) {
|
||||||
|
24
app/src/main/java/com/shabinder/spotiflyer/utils/Provider.kt
Normal file → Executable 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()
|
chain.proceed(request)
|
||||||
return chain.proceed(request)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
val retrofit = Retrofit.Builder()
|
val retrofit = Retrofit.Builder()
|
||||||
|
0
app/src/main/java/com/shabinder/spotiflyer/utils/SpotifyInterface.kt
Normal file → Executable file
32
app/src/main/java/com/shabinder/spotiflyer/utils/Utils.kt
Normal 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))
|
||||||
|
}
|
15
app/src/main/java/com/shabinder/spotiflyer/worker/ForegroundService.kt
Normal file → Executable 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])
|
||||||
|
17
app/src/main/res/drawable-v24/ic_launcher_foreground.xml
Normal file → Executable 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
@ -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
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
0
app/src/main/res/drawable/gradient.xml
Normal file → Executable file
17
app/src/main/res/drawable/ic_arrow.xml
Normal file → Executable 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
0
app/src/main/res/drawable/ic_arrow_slim.xml
Normal file → Executable file
0
app/src/main/res/drawable/ic_github.xml
Normal file → Executable file
0
app/src/main/res/drawable/ic_heart.xml
Normal file → Executable file
0
app/src/main/res/drawable/ic_history.xml
Normal file → Executable file
0
app/src/main/res/drawable/ic_instagram.xml
Normal file → Executable file
17
app/src/main/res/drawable/ic_launcher_background.xml
Normal file → Executable 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
0
app/src/main/res/drawable/ic_mug.xml
Normal file → Executable file
17
app/src/main/res/drawable/ic_musicplaceholder.xml
Normal file → Executable 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
0
app/src/main/res/drawable/ic_refreshgradient.xml
Normal file → Executable file
0
app/src/main/res/drawable/ic_share_open.xml
Normal file → Executable file
17
app/src/main/res/drawable/ic_song_placeholder.xml
Normal file → Executable 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
0
app/src/main/res/drawable/ic_tick.xml
Normal file → Executable file
0
app/src/main/res/drawable/ic_youtube.xml
Normal file → Executable file
17
app/src/main/res/drawable/rounded_gradient.xml
Normal file → Executable 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
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
@ -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
@ -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
0
app/src/main/res/font/amita.xml
Normal file → Executable file
17
app/src/main/res/font/averia_libre.xml
Normal file → Executable 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
@ -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
@ -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
@ -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"
|
||||||
|