mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-25 02:14:32 +01:00
Build:0.3.0,UI optimisations ,Anim fixes.
This commit is contained in:
parent
1f548e82e0
commit
ec1402ef2e
@ -25,9 +25,12 @@ import com.arkivanov.decompose.ComponentContext
|
|||||||
import com.arkivanov.decompose.extensions.compose.jetbrains.rootComponent
|
import com.arkivanov.decompose.extensions.compose.jetbrains.rootComponent
|
||||||
import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory
|
import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory
|
||||||
import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
|
import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
|
||||||
|
import com.razorpay.Checkout
|
||||||
|
import com.razorpay.PaymentResultListener
|
||||||
import com.shabinder.android.utils.checkIfLatestVersion
|
import com.shabinder.android.utils.checkIfLatestVersion
|
||||||
import com.shabinder.android.utils.disableDozeMode
|
import com.shabinder.android.utils.disableDozeMode
|
||||||
import com.shabinder.android.utils.requestStoragePermission
|
import com.shabinder.android.utils.requestStoragePermission
|
||||||
|
import com.shabinder.common.database.activityContext
|
||||||
import com.shabinder.common.di.Dir
|
import com.shabinder.common.di.Dir
|
||||||
import com.shabinder.common.di.FetchPlatformQueryResult
|
import com.shabinder.common.di.FetchPlatformQueryResult
|
||||||
import com.shabinder.common.di.createDirectories
|
import com.shabinder.common.di.createDirectories
|
||||||
@ -38,6 +41,7 @@ import com.shabinder.common.root.SpotiFlyerRootContent
|
|||||||
import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks
|
import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks
|
||||||
import com.shabinder.common.ui.SpotiFlyerTheme
|
import com.shabinder.common.ui.SpotiFlyerTheme
|
||||||
import com.shabinder.common.ui.colorOffWhite
|
import com.shabinder.common.ui.colorOffWhite
|
||||||
|
import com.shabinder.common.ui.showPopUpMessage
|
||||||
import com.shabinder.database.Database
|
import com.shabinder.database.Database
|
||||||
import com.tonyodev.fetch2.Status
|
import com.tonyodev.fetch2.Status
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
@ -46,7 +50,7 @@ import org.koin.android.ext.android.inject
|
|||||||
|
|
||||||
const val disableDozeCode = 1223
|
const val disableDozeCode = 1223
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity(), PaymentResultListener {
|
||||||
|
|
||||||
private val database: Database by inject()
|
private val database: Database by inject()
|
||||||
private val fetcher: FetchPlatformQueryResult by inject()
|
private val fetcher: FetchPlatformQueryResult by inject()
|
||||||
@ -77,7 +81,6 @@ class MainActivity : ComponentActivity() {
|
|||||||
insets
|
insets
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
root = SpotiFlyerRootContent(rootComponent(::spotiFlyerRoot),statusBarHeight)
|
root = SpotiFlyerRootContent(rootComponent(::spotiFlyerRoot),statusBarHeight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,6 +93,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
requestStoragePermission()
|
requestStoragePermission()
|
||||||
disableDozeMode(disableDozeCode)
|
disableDozeMode(disableDozeCode)
|
||||||
dir.createDirectories()
|
dir.createDirectories()
|
||||||
|
Checkout.preload(applicationContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun spotiFlyerRoot(componentContext: ComponentContext): SpotiFlyerRoot =
|
private fun spotiFlyerRoot(componentContext: ComponentContext): SpotiFlyerRoot =
|
||||||
@ -208,4 +212,24 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPaymentError(errorCode: Int, response: String?) {
|
||||||
|
try{
|
||||||
|
showPopUpMessage("Payment Failed, Response:$response")
|
||||||
|
}catch (e: Exception){
|
||||||
|
Log.d("Razorpay Payment","Exception in onPaymentSuccess $response")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPaymentSuccess(razorpayPaymentId: String?) {
|
||||||
|
try{
|
||||||
|
showPopUpMessage("Payment Successful, ThankYou!")
|
||||||
|
}catch (e: Exception){
|
||||||
|
showPopUpMessage("Razorpay Payment, Error Occurred.")
|
||||||
|
Log.d("Razorpay Payment","Exception in onPaymentSuccess, ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
activityContext = this
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
@file:Suppress("MayBeConstant", "SpellCheckingInspection")
|
@file:Suppress("MayBeConstant", "SpellCheckingInspection")
|
||||||
|
|
||||||
object Versions {
|
object Versions {
|
||||||
const val versionName = "2.2"
|
const val versionName = "2.2.0"
|
||||||
const val kotlinVersion = "1.4.30"
|
const val kotlinVersion = "1.4.30"
|
||||||
|
|
||||||
const val coroutinesVersion = "1.4.2"
|
const val coroutinesVersion = "1.4.2"
|
||||||
@ -67,7 +67,7 @@ object JetBrains {
|
|||||||
|
|
||||||
object Compose {
|
object Compose {
|
||||||
// __LATEST_COMPOSE_RELEASE_VERSION__
|
// __LATEST_COMPOSE_RELEASE_VERSION__
|
||||||
const val VERSION = "0.3.0-build152"
|
const val VERSION = "0.3.0"
|
||||||
const val gradlePlugin = "org.jetbrains.compose:compose-gradle-plugin:$VERSION"
|
const val gradlePlugin = "org.jetbrains.compose:compose-gradle-plugin:$VERSION"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,7 +122,7 @@ object Extras {
|
|||||||
const val mp3agic = "com.mpatric:mp3agic:0.9.1"
|
const val mp3agic = "com.mpatric:mp3agic:0.9.1"
|
||||||
const val kermit = "co.touchlab:kermit:${Versions.kermit}"
|
const val kermit = "co.touchlab:kermit:${Versions.kermit}"
|
||||||
object Android {
|
object Android {
|
||||||
val razorpay = "com.razorpay:checkout:1.6.4"
|
val razorpay = "com.razorpay:checkout:1.6.5"
|
||||||
val fetch = "androidx.tonyodev.fetch2:xfetch2:3.1.6"
|
val fetch = "androidx.tonyodev.fetch2:xfetch2:3.1.6"
|
||||||
val appUpdator = "com.github.amitbd1508:AppUpdater:4.1.0"
|
val appUpdator = "com.github.amitbd1508:AppUpdater:4.1.0"
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
package com.shabinder.common.ui
|
package com.shabinder.common.ui
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.vectorResource
|
import androidx.compose.ui.res.vectorResource
|
||||||
import androidx.compose.ui.text.font.Font
|
import androidx.compose.ui.text.font.Font
|
||||||
@ -77,3 +79,6 @@ actual fun YoutubeMusicLogo() = vectorResource(R.drawable.ic_youtube_music_logo)
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun GithubLogo() = vectorResource(R.drawable.ic_github)
|
actual fun GithubLogo() = vectorResource(R.drawable.ic_github)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun vectorResource(@DrawableRes id: Int) = ImageVector.Companion.vectorResource(id)
|
@ -42,7 +42,7 @@ fun SpotiFlyerListContent(
|
|||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
content = {
|
content = {
|
||||||
item {
|
item {
|
||||||
CoverImage(result.title, result.coverUrl, coroutineScope,component::loadImage)
|
CoverImage(result.title, result.coverUrl, coroutineScope,component::loadImage)
|
||||||
@ -71,17 +71,14 @@ fun TrackCard(
|
|||||||
downloadTrack:()->Unit,
|
downloadTrack:()->Unit,
|
||||||
loadImage:suspend (String)-> ImageBitmap?
|
loadImage:suspend (String)-> ImageBitmap?
|
||||||
) {
|
) {
|
||||||
/*val status = remember { mutableStateOf(track.downloaded.name()) }
|
|
||||||
LaunchedEffect(track.downloaded.name()){
|
|
||||||
status.value = track.downloaded.name()
|
|
||||||
}*/
|
|
||||||
Row(verticalAlignment = Alignment.CenterVertically,modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)) {
|
Row(verticalAlignment = Alignment.CenterVertically,modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)) {
|
||||||
ImageLoad(
|
ImageLoad(
|
||||||
{loadImage(track.albumArtURL)},
|
track.albumArtURL,
|
||||||
|
loadImage,
|
||||||
"Album Art",
|
"Album Art",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(75.dp)
|
.width(70.dp)
|
||||||
.height(90.dp)
|
.height(70.dp)
|
||||||
.clip(MaterialTheme.shapes.medium)
|
.clip(MaterialTheme.shapes.medium)
|
||||||
)
|
)
|
||||||
Column(modifier = Modifier.padding(horizontal = 8.dp).height(60.dp).weight(1f),verticalArrangement = Arrangement.SpaceEvenly) {
|
Column(modifier = Modifier.padding(horizontal = 8.dp).height(60.dp).weight(1f),verticalArrangement = Arrangement.SpaceEvenly) {
|
||||||
@ -133,11 +130,13 @@ fun CoverImage(
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
ImageLoad(
|
ImageLoad(
|
||||||
{ loadImage(coverURL) },
|
coverURL,
|
||||||
|
loadImage,
|
||||||
"Cover Image",
|
"Cover Image",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(210.dp)
|
.padding(12.dp)
|
||||||
.height(230.dp)
|
.width(190.dp)
|
||||||
|
.height(210.dp)
|
||||||
.clip(MaterialTheme.shapes.medium)
|
.clip(MaterialTheme.shapes.medium)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
|
@ -10,6 +10,7 @@ import androidx.compose.material.*
|
|||||||
import androidx.compose.material.Icon
|
import androidx.compose.material.Icon
|
||||||
import androidx.compose.material.TabRowDefaults.tabIndicatorOffset
|
import androidx.compose.material.TabRowDefaults.tabIndicatorOffset
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.material.TextFieldDefaults.textFieldColors
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.History
|
import androidx.compose.material.icons.outlined.History
|
||||||
import androidx.compose.material.icons.outlined.Info
|
import androidx.compose.material.icons.outlined.Info
|
||||||
@ -17,6 +18,7 @@ import androidx.compose.material.icons.rounded.*
|
|||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ImageBitmap
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
@ -130,10 +132,12 @@ fun SearchPanel(
|
|||||||
BorderStroke(2.dp, Brush.horizontalGradient(listOf(colorPrimary, colorAccent))),
|
BorderStroke(2.dp, Brush.horizontalGradient(listOf(colorPrimary, colorAccent))),
|
||||||
RoundedCornerShape(30.dp)
|
RoundedCornerShape(30.dp)
|
||||||
),
|
),
|
||||||
backgroundColor = Color.Black,
|
|
||||||
shape = RoundedCornerShape(size = 30.dp),
|
shape = RoundedCornerShape(size = 30.dp),
|
||||||
activeColor = transparent,
|
colors = textFieldColors(
|
||||||
inactiveColor = transparent,
|
focusedIndicatorColor = Color.Transparent,
|
||||||
|
unfocusedIndicatorColor = Color.Transparent,
|
||||||
|
backgroundColor = Color.Black
|
||||||
|
)
|
||||||
)
|
)
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
modifier = Modifier.padding(12.dp).wrapContentWidth(),
|
modifier = Modifier.padding(12.dp).wrapContentWidth(),
|
||||||
@ -171,28 +175,28 @@ fun AboutColumn(modifier: Modifier = Modifier) {
|
|||||||
imageVector = SpotifyLogo(),
|
imageVector = SpotifyLogo(),
|
||||||
"Open Spotify",
|
"Open Spotify",
|
||||||
tint = Color.Unspecified,
|
tint = Color.Unspecified,
|
||||||
modifier = Modifier.clickable(
|
modifier = Modifier.clip(SpotiFlyerShapes.small).clickable(
|
||||||
onClick = { openPlatform("com.spotify.music","http://open.spotify.com") })
|
onClick = { openPlatform("com.spotify.music","http://open.spotify.com") })
|
||||||
)
|
)
|
||||||
Spacer(modifier = modifier.padding(start = 16.dp))
|
Spacer(modifier = modifier.padding(start = 16.dp))
|
||||||
Icon(imageVector = GaanaLogo(),
|
Icon(imageVector = GaanaLogo(),
|
||||||
"Open Gaana",
|
"Open Gaana",
|
||||||
tint = Color.Unspecified,
|
tint = Color.Unspecified,
|
||||||
modifier = Modifier.clickable(
|
modifier = Modifier.clip(SpotiFlyerShapes.small).clickable(
|
||||||
onClick = { openPlatform("com.gaana","http://gaana.com") })
|
onClick = { openPlatform("com.gaana","http://gaana.com") })
|
||||||
)
|
)
|
||||||
Spacer(modifier = modifier.padding(start = 16.dp))
|
Spacer(modifier = modifier.padding(start = 16.dp))
|
||||||
Icon(imageVector = YoutubeLogo(),
|
Icon(imageVector = YoutubeLogo(),
|
||||||
"Open Youtube",
|
"Open Youtube",
|
||||||
tint = Color.Unspecified,
|
tint = Color.Unspecified,
|
||||||
modifier = Modifier.clickable(
|
modifier = Modifier.clip(SpotiFlyerShapes.small).clickable(
|
||||||
onClick = { openPlatform("com.google.android.youtube","http://m.youtube.com") })
|
onClick = { openPlatform("com.google.android.youtube","http://m.youtube.com") })
|
||||||
)
|
)
|
||||||
Spacer(modifier = modifier.padding(start = 12.dp))
|
Spacer(modifier = modifier.padding(start = 12.dp))
|
||||||
Icon(imageVector = YoutubeMusicLogo(),
|
Icon(imageVector = YoutubeMusicLogo(),
|
||||||
"Open Youtube Music",
|
"Open Youtube Music",
|
||||||
tint = Color.Unspecified,
|
tint = Color.Unspecified,
|
||||||
modifier = Modifier.clickable(
|
modifier = Modifier.clip(SpotiFlyerShapes.small).clickable(
|
||||||
onClick = { openPlatform("com.google.android.apps.youtube.music","https://music.youtube.com/") })
|
onClick = { openPlatform("com.google.android.apps.youtube.music","https://music.youtube.com/") })
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -251,7 +255,7 @@ fun AboutColumn(modifier: Modifier = Modifier) {
|
|||||||
.clickable(onClick = { giveDonation() }),
|
.clickable(onClick = { giveDonation() }),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Icon(Icons.Rounded.MailOutline,"Support Developer")
|
Icon(Icons.Rounded.CardGiftcard,"Support Developer")
|
||||||
Spacer(modifier = Modifier.padding(start = 16.dp))
|
Spacer(modifier = Modifier.padding(start = 16.dp))
|
||||||
Column {
|
Column {
|
||||||
Text(
|
Text(
|
||||||
@ -296,7 +300,7 @@ fun HistoryColumn(
|
|||||||
onItemClicked: (String) -> Unit
|
onItemClicked: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
content = {
|
content = {
|
||||||
items(list.distinctBy { it.coverUrl }) {
|
items(list.distinctBy { it.coverUrl }) {
|
||||||
DownloadRecordItem(
|
DownloadRecordItem(
|
||||||
@ -318,9 +322,10 @@ fun DownloadRecordItem(
|
|||||||
) {
|
) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically,modifier = Modifier.fillMaxWidth().padding(end = 8.dp)) {
|
Row(verticalAlignment = Alignment.CenterVertically,modifier = Modifier.fillMaxWidth().padding(end = 8.dp)) {
|
||||||
ImageLoad(
|
ImageLoad(
|
||||||
{ loadImage(item.coverUrl) },
|
item.coverUrl,
|
||||||
|
loadImage,
|
||||||
"Album Art",
|
"Album Art",
|
||||||
modifier = Modifier.height(75.dp).width(90.dp)
|
modifier = Modifier.height(70.dp).width(70.dp).clip(SpotiFlyerShapes.medium)
|
||||||
)
|
)
|
||||||
Column(modifier = Modifier.padding(horizontal = 8.dp).height(60.dp).weight(1f),verticalArrangement = Arrangement.SpaceEvenly) {
|
Column(modifier = Modifier.padding(horizontal = 8.dp).height(60.dp).weight(1f),verticalArrangement = Arrangement.SpaceEvenly) {
|
||||||
Text(item.name,maxLines = 1,overflow = TextOverflow.Ellipsis,style = SpotiFlyerTypography.h6,color = colorAccent)
|
Text(item.name,maxLines = 1,overflow = TextOverflow.Ellipsis,style = SpotiFlyerTypography.h6,color = colorAccent)
|
||||||
|
@ -9,18 +9,19 @@ import androidx.compose.runtime.*
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.ImageBitmap
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ImageLoad(loader: suspend () -> ImageBitmap?, desc: String = "Album Art", modifier:Modifier = Modifier, placeholder:ImageVector = PlaceHolderImage()) {
|
fun ImageLoad(link:String,loader:suspend (String) ->ImageBitmap?, desc: String = "Album Art", modifier:Modifier = Modifier, placeholder:ImageVector = PlaceHolderImage()) {
|
||||||
var pic by remember { mutableStateOf<ImageBitmap?>(null) }
|
var pic by remember(link) { mutableStateOf<ImageBitmap?>(null) }
|
||||||
LaunchedEffect(loader){
|
LaunchedEffect(link){
|
||||||
withContext(dispatcherIO) {
|
withContext(dispatcherIO) {
|
||||||
pic = loader()
|
pic = loader(link)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Crossfade(pic){
|
Crossfade(pic){
|
||||||
if(pic == null) Image(placeholder, desc, modifier) else Image(pic!!, desc, modifier)
|
if(it == null) Image(placeholder, desc, modifier,contentScale = ContentScale.Crop) else Image(it, desc, modifier,contentScale = ContentScale.Crop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="36dp"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="40dp"
|
||||||
android:height="32dp" android:viewportWidth="512" android:viewportHeight="512">
|
android:height="38dp" 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"/>
|
||||||
<path android:fillColor="#EC7EBA" android:pathData="m411.51,284.49 l-134.3,134.3c-11.71,11.71 -30.71,11.71 -42.42,0l-12.74,-12.74c10.69,4.06 23.23,1.77 31.84,-6.84l134.29,-134.29c12.51,-12.51 15.19,-31.7 7.57,-46.74 5.86,1.81 11.39,5.03 16.06,9.63 15.61,15.4 15.2,41.18 -0.3,56.68z"/>
|
<path android:fillColor="#EC7EBA" android:pathData="m411.51,284.49 l-134.3,134.3c-11.71,11.71 -30.71,11.71 -42.42,0l-12.74,-12.74c10.69,4.06 23.23,1.77 31.84,-6.84l134.29,-134.29c12.51,-12.51 15.19,-31.7 7.57,-46.74 5.86,1.81 11.39,5.03 16.06,9.63 15.61,15.4 15.2,41.18 -0.3,56.68z"/>
|
||||||
<path android:fillColor="#EC7EBA" android:pathData="m251.88,27.72c-3.46,-3.46 -7.55,-6.29 -12.08,-8.3 4.95,-2.2 10.43,-3.42 16.2,-3.42 11.04,0 21.04,4.48 28.28,11.72s11.72,17.24 11.72,28.28v232l-15.329,15.329c-6.3,6.3 -17.071,1.838 -17.071,-7.071v-240.258c0,-11.04 -4.48,-21.04 -11.72,-28.28z"/>
|
<path android:fillColor="#EC7EBA" android:pathData="m251.88,27.72c-3.46,-3.46 -7.55,-6.29 -12.08,-8.3 4.95,-2.2 10.43,-3.42 16.2,-3.42 11.04,0 21.04,4.48 28.28,11.72s11.72,17.24 11.72,28.28v232l-15.329,15.329c-6.3,6.3 -17.071,1.838 -17.071,-7.071v-240.258c0,-11.04 -4.48,-21.04 -11.72,-28.28z"/>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
android:width="38dp" android:height="38dp"
|
android:width="40dp" android:height="40dp"
|
||||||
android:viewportWidth="512" android:viewportHeight="512">
|
android:viewportWidth="512" android:viewportHeight="512">
|
||||||
<path android:pathData="m512,256c0,141.387 -114.613,256 -256,256s-256,-114.613 -256,-256 114.613,-256 256,-256 256,114.613 256,256zM512,256">
|
<path android:pathData="m512,256c0,141.387 -114.613,256 -256,256s-256,-114.613 -256,-256 114.613,-256 256,-256 256,114.613 256,256zM512,256">
|
||||||
<aapt:attr name="android:fillColor">
|
<aapt:attr name="android:fillColor">
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="38dp"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="34dp"
|
||||||
android:height="38dp" android:viewportWidth="512" android:viewportHeight="512">
|
android:height="34dp" android:viewportWidth="512" android:viewportHeight="512">
|
||||||
<path android:fillColor="#4EA4FF" android:pathData="M255.968,5.329C114.624,5.329 0,120.401 0,262.353c0,113.536 73.344,209.856 175.104,243.872c12.8,2.368 17.472,-5.568 17.472,-12.384c0,-6.112 -0.224,-22.272 -0.352,-43.712c-71.2,15.52 -86.24,-34.464 -86.24,-34.464c-11.616,-29.696 -28.416,-37.6 -28.416,-37.6c-23.264,-15.936 1.728,-15.616 1.728,-15.616c25.696,1.824 39.2,26.496 39.2,26.496c22.848,39.264 59.936,27.936 74.528,21.344c2.304,-16.608 8.928,-27.936 16.256,-34.368c-56.832,-6.496 -116.608,-28.544 -116.608,-127.008c0,-28.064 9.984,-51.008 26.368,-68.992c-2.656,-6.496 -11.424,-32.64 2.496,-68c0,0 21.504,-6.912 70.4,26.336c20.416,-5.696 42.304,-8.544 64.096,-8.64c21.728,0.128 43.648,2.944 64.096,8.672c48.864,-33.248 70.336,-26.336 70.336,-26.336c13.952,35.392 5.184,61.504 2.56,68c16.416,17.984 26.304,40.928 26.304,68.992c0,98.72 -59.84,120.448 -116.864,126.816c9.184,7.936 17.376,23.616 17.376,47.584c0,34.368 -0.32,62.08 -0.32,70.496c0,6.88 4.608,14.88 17.6,12.352C438.72,472.145 512,375.857 512,262.353C512,120.401 397.376,5.329 255.968,5.329z"/>
|
<path android:fillColor="#4EA4FF" android:pathData="M255.968,5.329C114.624,5.329 0,120.401 0,262.353c0,113.536 73.344,209.856 175.104,243.872c12.8,2.368 17.472,-5.568 17.472,-12.384c0,-6.112 -0.224,-22.272 -0.352,-43.712c-71.2,15.52 -86.24,-34.464 -86.24,-34.464c-11.616,-29.696 -28.416,-37.6 -28.416,-37.6c-23.264,-15.936 1.728,-15.616 1.728,-15.616c25.696,1.824 39.2,26.496 39.2,26.496c22.848,39.264 59.936,27.936 74.528,21.344c2.304,-16.608 8.928,-27.936 16.256,-34.368c-56.832,-6.496 -116.608,-28.544 -116.608,-127.008c0,-28.064 9.984,-51.008 26.368,-68.992c-2.656,-6.496 -11.424,-32.64 2.496,-68c0,0 21.504,-6.912 70.4,26.336c20.416,-5.696 42.304,-8.544 64.096,-8.64c21.728,0.128 43.648,2.944 64.096,8.672c48.864,-33.248 70.336,-26.336 70.336,-26.336c13.952,35.392 5.184,61.504 2.56,68c16.416,17.984 26.304,40.928 26.304,68.992c0,98.72 -59.84,120.448 -116.864,126.816c9.184,7.936 17.376,23.616 17.376,47.584c0,34.368 -0.32,62.08 -0.32,70.496c0,6.88 4.608,14.88 17.6,12.352C438.72,472.145 512,375.857 512,262.353C512,120.401 397.376,5.329 255.968,5.329z"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
android:width="36dp" android:height="36dp"
|
android:width="40dp" android:height="40dp"
|
||||||
android:viewportWidth="512" android:viewportHeight="512">
|
android:viewportWidth="512" android:viewportHeight="512">
|
||||||
<path android:pathData="m512,256c0,141.387 -114.613,256 -256,256s-256,-114.613 -256,-256 114.613,-256 256,-256 256,114.613 256,256zM512,256">
|
<path android:pathData="m512,256c0,141.387 -114.613,256 -256,256s-256,-114.613 -256,-256 114.613,-256 256,-256 256,114.613 256,256zM512,256">
|
||||||
<aapt:attr name="android:fillColor">
|
<aapt:attr name="android:fillColor">
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.shabinder.common.database
|
package com.shabinder.common.database
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import co.touchlab.kermit.LogcatLogger
|
import co.touchlab.kermit.LogcatLogger
|
||||||
import co.touchlab.kermit.Logger
|
import co.touchlab.kermit.Logger
|
||||||
@ -8,6 +9,12 @@ import com.squareup.sqldelight.android.AndroidSqliteDriver
|
|||||||
|
|
||||||
lateinit var appContext: Context
|
lateinit var appContext: Context
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As MainActivity is God Activity , hence its active almost throughout App's lifetime
|
||||||
|
* */
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
lateinit var activityContext: Context
|
||||||
|
|
||||||
actual fun createDatabase(): Database {
|
actual fun createDatabase(): Database {
|
||||||
val driver = AndroidSqliteDriver(Database.Schema, appContext, "Database.db")
|
val driver = AndroidSqliteDriver(Database.Schema, appContext, "Database.db")
|
||||||
return Database(driver)
|
return Database(driver)
|
||||||
|
@ -34,6 +34,7 @@ kotlin {
|
|||||||
implementation(Ktor.clientAndroid)
|
implementation(Ktor.clientAndroid)
|
||||||
implementation(Extras.Android.fetch)
|
implementation(Extras.Android.fetch)
|
||||||
implementation(Koin.android)
|
implementation(Koin.android)
|
||||||
|
implementation(Extras.Android.razorpay)
|
||||||
//api(files("$rootDir/libs/mobile-ffmpeg.aar"))
|
//api(files("$rootDir/libs/mobile-ffmpeg.aar"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.shabinder.common.di
|
package com.shabinder.common.di
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
@ -7,22 +8,25 @@ import androidx.core.content.ContextCompat
|
|||||||
import com.github.kiulian.downloader.model.YoutubeVideo
|
import com.github.kiulian.downloader.model.YoutubeVideo
|
||||||
import com.github.kiulian.downloader.model.formats.Format
|
import com.github.kiulian.downloader.model.formats.Format
|
||||||
import com.github.kiulian.downloader.model.quality.AudioQuality
|
import com.github.kiulian.downloader.model.quality.AudioQuality
|
||||||
import com.shabinder.common.database.appContext
|
import com.razorpay.Checkout
|
||||||
|
import com.shabinder.common.database.activityContext
|
||||||
import com.shabinder.common.di.worker.ForegroundService
|
import com.shabinder.common.di.worker.ForegroundService
|
||||||
import com.shabinder.common.models.TrackDetails
|
import com.shabinder.common.models.TrackDetails
|
||||||
|
import com.shabinder.common.ui.R
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
actual fun openPlatform(packageID:String, platformLink:String){
|
actual fun openPlatform(packageID:String, platformLink:String){
|
||||||
val manager: PackageManager = appContext.packageManager
|
val manager: PackageManager = activityContext.packageManager
|
||||||
try {
|
try {
|
||||||
val intent = manager.getLaunchIntentForPackage(packageID)
|
val intent = manager.getLaunchIntentForPackage(packageID)
|
||||||
?: throw PackageManager.NameNotFoundException()
|
?: throw PackageManager.NameNotFoundException()
|
||||||
intent.addCategory(Intent.CATEGORY_LAUNCHER)
|
intent.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
appContext.startActivity(intent)
|
activityContext.startActivity(intent)
|
||||||
} catch (e: PackageManager.NameNotFoundException) {
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
val uri: Uri =
|
val uri: Uri =
|
||||||
Uri.parse(platformLink)
|
Uri.parse(platformLink)
|
||||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||||
appContext.startActivity(intent)
|
activityContext.startActivity(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,18 +38,44 @@ actual fun shareApp(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
val shareIntent = Intent.createChooser(sendIntent, null)
|
val shareIntent = Intent.createChooser(sendIntent, null)
|
||||||
appContext.startActivity(shareIntent)
|
activityContext.startActivity(shareIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun giveDonation(){
|
actual fun giveDonation() = startPayment()
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private fun startPayment(mainActivity: Activity = activityContext as Activity) {
|
||||||
|
/*
|
||||||
|
* You need to pass current activity in order to let Razorpay create CheckoutActivity
|
||||||
|
* */
|
||||||
|
val co = Checkout().apply {
|
||||||
|
setKeyID("rzp_live_3ZQeoFYOxjmXye")
|
||||||
|
setImage(R.drawable.ic_spotiflyer_logo)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val preFill = JSONObject()
|
||||||
|
|
||||||
|
val options = JSONObject().apply {
|
||||||
|
put("name","SpotiFlyer")
|
||||||
|
put("description","Thanks For the Donation!")
|
||||||
|
//You can omit the image option to fetch the image from dashboard
|
||||||
|
//put("image","https://github.com/Shabinder/SpotiFlyer/raw/master/app/SpotifyDownload.png")
|
||||||
|
put("currency","INR")
|
||||||
|
put("amount","4900")
|
||||||
|
put("prefill",preFill)
|
||||||
|
}
|
||||||
|
|
||||||
|
co.open(mainActivity,options)
|
||||||
|
}catch (e: Exception){
|
||||||
|
//showPop("Error in payment: "+ e.message)
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
actual fun queryActiveTracks() {
|
actual fun queryActiveTracks() {
|
||||||
val serviceIntent = Intent(appContext, ForegroundService::class.java).apply {
|
val serviceIntent = Intent(activityContext, ForegroundService::class.java).apply {
|
||||||
action = "query"
|
action = "query"
|
||||||
}
|
}
|
||||||
ContextCompat.startForegroundService(appContext, serviceIntent)
|
ContextCompat.startForegroundService(activityContext, serviceIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
actual suspend fun downloadTracks(
|
actual suspend fun downloadTracks(
|
||||||
@ -54,9 +84,9 @@ actual suspend fun downloadTracks(
|
|||||||
saveFileWithMetaData:suspend (mp3ByteArray:ByteArray, trackDetails: TrackDetails) -> Unit
|
saveFileWithMetaData:suspend (mp3ByteArray:ByteArray, trackDetails: TrackDetails) -> Unit
|
||||||
){
|
){
|
||||||
if(!list.isNullOrEmpty()){
|
if(!list.isNullOrEmpty()){
|
||||||
val serviceIntent = Intent(appContext, ForegroundService::class.java)
|
val serviceIntent = Intent(activityContext, ForegroundService::class.java)
|
||||||
serviceIntent.putParcelableArrayListExtra("object",ArrayList<TrackDetails>(list))
|
serviceIntent.putParcelableArrayListExtra("object",ArrayList<TrackDetails>(list))
|
||||||
appContext.let { ContextCompat.startForegroundService(it, serviceIntent) }
|
activityContext.let { ContextCompat.startForegroundService(it, serviceIntent) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ import androidx.core.app.NotificationCompat
|
|||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.github.kiulian.downloader.YoutubeDownloader
|
import com.github.kiulian.downloader.YoutubeDownloader
|
||||||
|
import com.github.kiulian.downloader.model.formats.Format
|
||||||
import com.shabinder.common.di.Dir
|
import com.shabinder.common.di.Dir
|
||||||
import com.shabinder.common.di.FetchPlatformQueryResult
|
import com.shabinder.common.di.FetchPlatformQueryResult
|
||||||
import com.shabinder.common.di.getData
|
import com.shabinder.common.di.getData
|
||||||
@ -178,37 +179,37 @@ class ForegroundService : Service(),CoroutineScope{
|
|||||||
private fun downloadTrack(videoID:String, track: TrackDetails){
|
private fun downloadTrack(videoID:String, track: TrackDetails){
|
||||||
launch {
|
launch {
|
||||||
try {
|
try {
|
||||||
/*val audioData = ytDownloader.getVideo(videoID).getData()
|
|
||||||
|
|
||||||
audioData?.let {
|
|
||||||
val url: String = it.url()
|
|
||||||
logger.d("DHelper Link Found") { url }
|
|
||||||
}*/
|
|
||||||
val url = fetcher.youtubeMp3.getMp3DownloadLink(videoID)
|
val url = fetcher.youtubeMp3.getMp3DownloadLink(videoID)
|
||||||
if (url == null){
|
if (url == null){
|
||||||
sendTrackBroadcast(Status.FAILED.name,track)
|
val audioData:Format = ytDownloader.getVideo(videoID).getData() ?: throw Exception("Java YT Dependency Error")
|
||||||
allTracksStatus[track.title] = DownloadStatus.Failed
|
val ytUrl: String = audioData.url()
|
||||||
} else{
|
enqueueDownload(ytUrl,track)
|
||||||
val request= Request(url, track.outputFilePath).apply{
|
} else enqueueDownload(url,track)
|
||||||
priority = Priority.NORMAL
|
}catch (e: Exception){
|
||||||
networkType = NetworkType.ALL
|
|
||||||
}
|
|
||||||
fetch.enqueue(request,
|
|
||||||
{ request1 ->
|
|
||||||
requestMap[request1] = track
|
|
||||||
logger.d(tag){"Enqueuing Download"}
|
|
||||||
},
|
|
||||||
{ error ->
|
|
||||||
logger.d(tag){"Enqueuing Error:${error.throwable.toString()}"}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}catch (e: java.lang.Exception){
|
|
||||||
logger.d("Service YT Error"){e.message.toString()}
|
logger.d("Service YT Error"){e.message.toString()}
|
||||||
|
sendTrackBroadcast(Status.FAILED.name,track)
|
||||||
|
allTracksStatus[track.title] = DownloadStatus.Failed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun enqueueDownload(url:String,track:TrackDetails){
|
||||||
|
val request= Request(url, track.outputFilePath).apply{
|
||||||
|
priority = Priority.NORMAL
|
||||||
|
networkType = NetworkType.ALL
|
||||||
|
}
|
||||||
|
fetch.enqueue(request,
|
||||||
|
{ request1 ->
|
||||||
|
requestMap[request1] = track
|
||||||
|
logger.d(tag){"Enqueuing Download"}
|
||||||
|
},
|
||||||
|
{ error ->
|
||||||
|
logger.d(tag){"Enqueuing Error:${error.throwable.toString()}"}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch Listener/ Responsible for Fetch Behaviour
|
* Fetch Listener/ Responsible for Fetch Behaviour
|
||||||
**/
|
**/
|
||||||
|
@ -49,7 +49,7 @@ suspend fun downloadFile(url: String): Flow<DownloadResult> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun getNameURL(url: String): String {
|
fun getNameURL(url: String): String {
|
||||||
return url.substring(url.lastIndexOf('/') + 1, url.length)
|
return url.substring(url.lastIndexOf('/',url.lastIndexOf('/')-1) + 1, url.length).replace('/','_')
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Call this function at startup!
|
* Call this function at startup!
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (c) 2021 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 android:height="150dp" android:viewportHeight="512"
|
||||||
|
android:viewportWidth="512" android:width="150dp"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:pathData="M256,256m-256,0a256,256 0,1 1,512 0a256,256 0,1 1,-512 0">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient android:endX="437.019" android:endY="74.981"
|
||||||
|
android:startX="74.981" android:startY="437.019" android:type="linear">
|
||||||
|
<item android:color="#FF736BFD" android:offset="0"/>
|
||||||
|
<item android:color="#FFF54187" android:offset="1"/>
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M377,356.7c-68.9,-45.4 -155.6,-56.4 -257.6,-32.7c-20.5,4.8 -13.6,35.8 7.3,31.2C290.7,317 351.6,386 368.2,386C384,386 390.2,365.4 377,356.7z"/>
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M112.1,275.1C203.9,253.4 308.1,266 384,308c18.5,10.2 34,-17.8 15.5,-28c-82.7,-45.7 -195.6,-59.5 -294.7,-36C84.2,248.8 91.5,280 112.1,275.1L112.1,275.1z"/>
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M100,191.9c96.6,-29.6 232.2,-13.4 308.7,36.9c17.6,11.5 35.3,-15.1 17.6,-26.7c-84.9,-55.8 -229.2,-73.3 -335.6,-40.8C70.4,167.5 79.9,198.1 100,191.9L100,191.9z"/>
|
||||||
|
<path android:pathData="M507.8,438.2c-1.6,97.2 -141.9,97.1 -143.5,0C365.9,341 506.2,341 507.8,438.2z">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient android:endX="384.197" android:endY="490.009"
|
||||||
|
android:startX="487.832" android:startY="386.374" android:type="linear">
|
||||||
|
<item android:color="#FF736BFD" android:offset="0"/>
|
||||||
|
<item android:color="#FFF54187" android:offset="1"/>
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
<path android:fillColor="#FF000000"
|
||||||
|
android:pathData="M486.8,456.8c-0.6,-2.4 -6.9,-1 -8.5,-1.4c11.5,-82 -82.4,-86.7 -87.1,-22.2c0.3,1.8 -1,6.7 2.2,6.6c0,0 8.6,0 8.6,0c3.1,0.1 2,-4.7 2.2,-6.6c0.1,-23.3 35,-23.3 35.2,0c0,0 0,6.9 0,6.9c-0.1,2.8 4.4,2.8 4.3,0c5,-35.2 -43.8,-40.1 -43.8,-4.7h-4.3c-1.6,-53.7 77.2,-55.9 78.4,-2.2c0,0 0,24.4 0,24.4c-0.1,2.9 3.8,2.1 5.6,2.2l-20.7,21l-20.7,-21c1.8,-0.1 5.6,0.7 5.6,-2.2c0,0 0,-8.8 0,-8.8c0,-2.8 -4.4,-2.8 -4.3,0c0,0 0,6.6 0,6.6c-2.2,0.2 -11.3,-1.3 -8,3.7c0,0 25.9,26.3 25.9,26.3c0.8,0.9 2.2,0.9 3.1,0C460.6,484.4 489.4,458.3 486.8,456.8z"
|
||||||
|
android:strokeColor="#000" android:strokeWidth=".75"/>
|
||||||
|
<path android:fillColor="#00000000"
|
||||||
|
android:pathData="M510,437.5c-1.7,96.2 -142.1,96.2 -143.8,0C367.9,341.3 508.4,341.3 510,437.5z"
|
||||||
|
android:strokeColor="#000" android:strokeWidth="6"/>
|
||||||
|
</vector>
|
Loading…
Reference in New Issue
Block a user