Scrollbars and various Bug Fixes

This commit is contained in:
shabinder 2021-05-08 20:42:09 +05:30
parent d90469d0fd
commit 603314fcd2
20 changed files with 492 additions and 190 deletions

View File

@ -48,6 +48,7 @@
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" android:theme="@style/Theme.AppCompat.Light.NoActionBar"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:largeHeap="true"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"

View File

@ -236,7 +236,13 @@ class MainActivity : ComponentActivity(), PaymentResultListener {
ContextCompat.startForegroundService(this@MainActivity, serviceIntent) ContextCompat.startForegroundService(this@MainActivity, serviceIntent)
} }
override fun giveDonation() = startPayment(this@MainActivity) override fun giveDonation() {
try {
startPayment(this@MainActivity)
}catch (e:Exception) {
openPlatform("",platformLink = "https://razorpay.com/payment-button/pl_GnKuuDBdBu0ank/view/?utm_source=payment_button&utm_medium=button&utm_campaign=payment_button")
}
}
override fun shareApp() { override fun shareApp() {
val sendIntent: Intent = Intent().apply { val sendIntent: Intent = Intent().apply {

View File

@ -18,7 +18,7 @@
object Versions { object Versions {
// App's Version (To be bumped at each update) // App's Version (To be bumped at each update)
const val versionName = "2.3.0" const val versionName = "2.3.5"
// Kotlin // Kotlin
const val kotlinVersion = "1.4.32" const val kotlinVersion = "1.4.32"
@ -45,7 +45,7 @@ object Versions {
const val slf4j = "1.7.30" const val slf4j = "1.7.30"
// Android // Android
const val versionCode = 17 const val versionCode = 18
const val minSdkVersion = 21 const val minSdkVersion = 21
const val compileSdkVersion = 29 const val compileSdkVersion = 29
const val targetSdkVersion = 29 const val targetSdkVersion = 29
@ -142,7 +142,7 @@ object Extras {
const val jaudioTagger = "com.github.Shabinder:JAudioTagger-Android:1.0" const val jaudioTagger = "com.github.Shabinder:JAudioTagger-Android:1.0"
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.5" val razorpay = "com.razorpay:checkout:1.6.7"
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"
} }

View File

@ -0,0 +1,33 @@
package com.shabinder.common.uikit
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
actual val MARGIN_SCROLLBAR: Dp = 0.dp
actual interface ScrollbarAdapter
@Composable
actual fun rememberScrollbarAdapter(
scrollState: ScrollState
): ScrollbarAdapter = object : ScrollbarAdapter {}
@Composable
actual fun rememberScrollbarAdapter(
scrollState: LazyListState,
itemCount: Int,
averageItemSize: Dp
): ScrollbarAdapter =
object : ScrollbarAdapter {}
@Composable
actual fun VerticalScrollbar(
modifier: Modifier,
adapter: ScrollbarAdapter
) {
}

View File

@ -0,0 +1,30 @@
package com.shabinder.common.uikit
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
expect val MARGIN_SCROLLBAR: Dp
expect interface ScrollbarAdapter
@Composable
expect fun rememberScrollbarAdapter(
scrollState: LazyListState,
itemCount: Int,
averageItemSize: Dp
): ScrollbarAdapter
@Composable
expect fun rememberScrollbarAdapter(
scrollState: ScrollState
): ScrollbarAdapter
@Composable
expect fun VerticalScrollbar(
modifier: Modifier,
adapter: ScrollbarAdapter
)

View File

@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
@ -29,6 +30,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.ExtendedFloatingActionButton import androidx.compose.material.ExtendedFloatingActionButton
import androidx.compose.material.Icon import androidx.compose.material.Icon
@ -77,6 +79,9 @@ fun SpotiFlyerListContent(
Text("Loading..", style = appNameStyle, color = colorPrimary) Text("Loading..", style = appNameStyle, color = colorPrimary)
} }
} else { } else {
val listState = rememberLazyListState()
LazyColumn( LazyColumn(
verticalArrangement = Arrangement.spacedBy(12.dp), verticalArrangement = Arrangement.spacedBy(12.dp),
content = { content = {
@ -91,12 +96,23 @@ fun SpotiFlyerListContent(
) )
} }
}, },
state = listState,
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
) )
DownloadAllButton( DownloadAllButton(
onClick = { component.onDownloadAllClicked(model.trackList) }, onClick = { component.onDownloadAllClicked(model.trackList) },
modifier = Modifier.padding(bottom = 24.dp).align(Alignment.BottomCenter) modifier = Modifier.padding(bottom = 24.dp).align(Alignment.BottomCenter)
) )
VerticalScrollbar(
modifier = Modifier.padding(end = 2.dp).align(Alignment.CenterEnd).fillMaxHeight(),
adapter = rememberScrollbarAdapter(
scrollState = listState,
itemCount = model.trackList.size,
averageItemSize = 72.dp
)
)
} }
} }
} }

View File

@ -23,9 +23,11 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
@ -35,6 +37,7 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
@ -125,7 +128,7 @@ fun HomeTabBar(
TabRow( TabRow(
selectedTabIndex = selectedIndex, selectedTabIndex = selectedIndex,
indicator = indicator, indicator = indicator as @Composable (List<TabPosition>) -> Unit,
modifier = modifier, modifier = modifier,
) { ) {
categories.forEachIndexed { index, category -> categories.forEachIndexed { index, category ->
@ -219,160 +222,169 @@ fun SearchPanel(
@Composable @Composable
fun AboutColumn(modifier: Modifier = Modifier) { fun AboutColumn(modifier: Modifier = Modifier) {
// TODO Make Scrollable
Column(modifier.fillMaxSize().padding(8.dp).verticalScroll(rememberScrollState())) {
Card(
modifier = modifier.fillMaxWidth(),
border = BorderStroke(1.dp, Color.Gray)
) {
Column(modifier.padding(12.dp)) {
Text(
text = "Supported Platforms",
style = SpotiFlyerTypography.body1,
color = colorAccent
)
Spacer(modifier = Modifier.padding(top = 12.dp))
Row(horizontalArrangement = Arrangement.Center, modifier = modifier.fillMaxWidth()) {
Icon(
SpotifyLogo(),
"Open Spotify",
tint = Color.Unspecified,
modifier = Modifier.clip(SpotiFlyerShapes.small).clickable(
onClick = { methods.value.openPlatform("com.spotify.music", "http://open.spotify.com") }
)
)
Spacer(modifier = modifier.padding(start = 16.dp))
Icon(
GaanaLogo(),
"Open Gaana",
tint = Color.Unspecified,
modifier = Modifier.clip(SpotiFlyerShapes.small).clickable(
onClick = { methods.value.openPlatform("com.gaana", "http://gaana.com") }
)
)
Spacer(modifier = modifier.padding(start = 16.dp))
Icon(
YoutubeLogo(),
"Open Youtube",
tint = Color.Unspecified,
modifier = Modifier.clip(SpotiFlyerShapes.small).clickable(
onClick = { methods.value.openPlatform("com.google.android.youtube", "http://m.youtube.com") }
)
)
Spacer(modifier = modifier.padding(start = 12.dp))
Icon(
YoutubeMusicLogo(),
"Open Youtube Music",
tint = Color.Unspecified,
modifier = Modifier.clip(SpotiFlyerShapes.small).clickable(
onClick = { methods.value.openPlatform("com.google.android.apps.youtube.music", "https://music.youtube.com/") }
)
)
}
}
}
Spacer(modifier = Modifier.padding(top = 8.dp))
Card(
modifier = modifier.fillMaxWidth(),
border = BorderStroke(1.dp, Color.Gray) // Gray
) {
Column(modifier.padding(12.dp)) {
Text(
text = "Support Development",
style = SpotiFlyerTypography.body1,
color = colorAccent
)
Spacer(modifier = Modifier.padding(top = 6.dp))
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().clickable(
onClick = { methods.value.openPlatform("", "http://github.com/Shabinder/SpotiFlyer") }
)
.padding(vertical = 6.dp)
) {
Icon(GithubLogo(), "Open Project Repo", tint = Color(0xFFCCCCCC))
Spacer(modifier = Modifier.padding(start = 16.dp))
Column {
Text(
text = "GitHub",
style = SpotiFlyerTypography.h6
)
Text(
text = "Star / Fork the project on Github.",
style = SpotiFlyerTypography.subtitle2
)
}
}
Row(
modifier = modifier.fillMaxWidth().padding(vertical = 6.dp)
.clickable(onClick = { methods.value.openPlatform("", "http://github.com/Shabinder/SpotiFlyer") }),
verticalAlignment = Alignment.CenterVertically
) {
Icon(Icons.Rounded.Flag, "Help Translate", Modifier.size(32.dp))
Spacer(modifier = Modifier.padding(start = 16.dp))
Column {
Text(
text = "Translate",
style = SpotiFlyerTypography.h6
)
Text(
text = "Help us translate this app in your local language.",
style = SpotiFlyerTypography.subtitle2
)
}
}
var isDonationDialogVisible by remember { mutableStateOf(false) } Box {
val stateVertical = rememberScrollState(0)
DonationDialog( Column(modifier.fillMaxSize().padding(8.dp).verticalScroll(stateVertical)) {
isDonationDialogVisible Card(
) { modifier = modifier.fillMaxWidth(),
isDonationDialogVisible = false border = BorderStroke(1.dp, Color.Gray)
} ) {
Column(modifier.padding(12.dp)) {
Row( Text(
modifier = modifier.fillMaxWidth().padding(vertical = 6.dp) text = "Supported Platforms",
.clickable(onClick = { isDonationDialogVisible = true }), style = SpotiFlyerTypography.body1,
verticalAlignment = Alignment.CenterVertically color = colorAccent
) { )
Icon(Icons.Rounded.CardGiftcard, "Support Developer") Spacer(modifier = Modifier.padding(top = 12.dp))
Spacer(modifier = Modifier.padding(start = 16.dp)) Row(horizontalArrangement = Arrangement.Center, modifier = modifier.fillMaxWidth()) {
Column { Icon(
Text( SpotifyLogo(),
text = "Donate", "Open Spotify",
style = SpotiFlyerTypography.h6 tint = Color.Unspecified,
modifier = Modifier.clip(SpotiFlyerShapes.small).clickable(
onClick = { methods.value.openPlatform("com.spotify.music", "http://open.spotify.com") }
)
) )
Text( Spacer(modifier = modifier.padding(start = 16.dp))
text = "If you think I deserve to get paid for my work, you can support me here.", Icon(
//text = "SpotiFlyer will always be, Free and Open-Source. You can however show us that you care by sending a small donation.", GaanaLogo(),
style = SpotiFlyerTypography.subtitle2 "Open Gaana",
tint = Color.Unspecified,
modifier = Modifier.clip(SpotiFlyerShapes.small).clickable(
onClick = { methods.value.openPlatform("com.gaana", "http://gaana.com") }
)
) )
} Spacer(modifier = modifier.padding(start = 16.dp))
} Icon(
Row( YoutubeLogo(),
modifier = modifier.fillMaxWidth().padding(vertical = 6.dp) "Open Youtube",
.clickable( tint = Color.Unspecified,
onClick = { modifier = Modifier.clip(SpotiFlyerShapes.small).clickable(
methods.value.shareApp() onClick = { methods.value.openPlatform("com.google.android.youtube", "http://m.youtube.com") }
} )
),
verticalAlignment = Alignment.CenterVertically
) {
Icon(Icons.Rounded.Share, "Share SpotiFlyer App")
Spacer(modifier = Modifier.padding(start = 16.dp))
Column {
Text(
text = "Share",
style = SpotiFlyerTypography.h6
) )
Text( Spacer(modifier = modifier.padding(start = 12.dp))
text = "Share this app with your friends and family.", Icon(
style = SpotiFlyerTypography.subtitle2 YoutubeMusicLogo(),
"Open Youtube Music",
tint = Color.Unspecified,
modifier = Modifier.clip(SpotiFlyerShapes.small).clickable(
onClick = { methods.value.openPlatform("com.google.android.apps.youtube.music", "https://music.youtube.com/") }
)
) )
} }
} }
} }
Spacer(modifier = Modifier.padding(top = 8.dp))
Card(
modifier = modifier.fillMaxWidth(),
border = BorderStroke(1.dp, Color.Gray) // Gray
) {
Column(modifier.padding(12.dp)) {
Text(
text = "Support Development",
style = SpotiFlyerTypography.body1,
color = colorAccent
)
Spacer(modifier = Modifier.padding(top = 6.dp))
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().clickable(
onClick = { methods.value.openPlatform("", "http://github.com/Shabinder/SpotiFlyer") }
)
.padding(vertical = 6.dp)
) {
Icon(GithubLogo(), "Open Project Repo", tint = Color(0xFFCCCCCC))
Spacer(modifier = Modifier.padding(start = 16.dp))
Column {
Text(
text = "GitHub",
style = SpotiFlyerTypography.h6
)
Text(
text = "Star / Fork the project on Github.",
style = SpotiFlyerTypography.subtitle2
)
}
}
Row(
modifier = modifier.fillMaxWidth().padding(vertical = 6.dp)
.clickable(onClick = { methods.value.openPlatform("", "http://github.com/Shabinder/SpotiFlyer") }),
verticalAlignment = Alignment.CenterVertically
) {
Icon(Icons.Rounded.Flag, "Help Translate", Modifier.size(32.dp))
Spacer(modifier = Modifier.padding(start = 16.dp))
Column {
Text(
text = "Translate",
style = SpotiFlyerTypography.h6
)
Text(
text = "Help us translate this app in your local language.",
style = SpotiFlyerTypography.subtitle2
)
}
}
var isDonationDialogVisible by remember { mutableStateOf(false) }
DonationDialog(
isDonationDialogVisible
) {
isDonationDialogVisible = false
}
Row(
modifier = modifier.fillMaxWidth().padding(vertical = 6.dp)
.clickable(onClick = { isDonationDialogVisible = true }),
verticalAlignment = Alignment.CenterVertically
) {
Icon(Icons.Rounded.CardGiftcard, "Support Developer")
Spacer(modifier = Modifier.padding(start = 16.dp))
Column {
Text(
text = "Donate",
style = SpotiFlyerTypography.h6
)
Text(
text = "If you think I deserve to get paid for my work, you can support me here.",
//text = "SpotiFlyer will always be, Free and Open-Source. You can however show us that you care by sending a small donation.",
style = SpotiFlyerTypography.subtitle2
)
}
}
Row(
modifier = modifier.fillMaxWidth().padding(vertical = 6.dp)
.clickable(
onClick = {
methods.value.shareApp()
}
),
verticalAlignment = Alignment.CenterVertically
) {
Icon(Icons.Rounded.Share, "Share SpotiFlyer App")
Spacer(modifier = Modifier.padding(start = 16.dp))
Column {
Text(
text = "Share",
style = SpotiFlyerTypography.h6
)
Text(
text = "Share this app with your friends and family.",
style = SpotiFlyerTypography.subtitle2
)
}
}
}
}
} }
VerticalScrollbar(
modifier = Modifier.padding(end = 2.dp).align(Alignment.CenterEnd).fillMaxHeight(),
adapter = rememberScrollbarAdapter(stateVertical)
)
} }
} }
@ -392,19 +404,35 @@ fun HistoryColumn(
Text("No History Available", style = SpotiFlyerTypography.h4.copy(fontWeight = FontWeight.Light), textAlign = TextAlign.Center) Text("No History Available", style = SpotiFlyerTypography.h4.copy(fontWeight = FontWeight.Light), textAlign = TextAlign.Center)
} }
} else { } else {
LazyColumn( Box {
verticalArrangement = Arrangement.spacedBy(12.dp),
content = { val listState = rememberLazyListState()
items(it.distinctBy { record -> record.coverUrl }) { record -> val itemList = it.distinctBy { record -> record.coverUrl }
DownloadRecordItem(
item = record, LazyColumn(
loadImage, verticalArrangement = Arrangement.spacedBy(12.dp),
onItemClicked content = {
) items(itemList) { record ->
} DownloadRecordItem(
}, item = record,
modifier = Modifier.padding(top = 8.dp).fillMaxSize() loadImage,
) onItemClicked
)
}
},
state = listState,
modifier = Modifier.padding(top = 8.dp).fillMaxSize()
)
VerticalScrollbar(
modifier = Modifier.padding(end = 2.dp).align(Alignment.CenterEnd).fillMaxHeight(),
adapter = rememberScrollbarAdapter(
scrollState = listState,
itemCount = itemList.size,
averageItemSize = 70.dp
)
)
}
} }
} }
} }

View File

@ -67,14 +67,6 @@ actual fun DownloadImageTick() {
) )
} }
@Composable
actual fun DonationDialog(
isVisible:Boolean,
onDismiss:()->Unit
){
}
actual fun montserratFont() = FontFamily( actual fun montserratFont() = FontFamily(
Font("font/montserrat_light.ttf", FontWeight.Light), Font("font/montserrat_light.ttf", FontWeight.Light),
Font("font/montserrat_regular.ttf", FontWeight.Normal), Font("font/montserrat_regular.ttf", FontWeight.Normal),

View File

@ -0,0 +1,46 @@
package com.shabinder.common.uikit
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.ScrollbarAdapter
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
actual val MARGIN_SCROLLBAR: Dp = 8.dp
actual typealias ScrollbarAdapter = androidx.compose.foundation.ScrollbarAdapter
@OptIn(ExperimentalFoundationApi::class)
@Composable
actual fun rememberScrollbarAdapter(
scrollState: LazyListState,
itemCount: Int,
averageItemSize: Dp
): ScrollbarAdapter =
androidx.compose.foundation.rememberScrollbarAdapter(
scrollState = scrollState,
itemCount = itemCount,
averageItemSize = averageItemSize
)
@Composable
actual fun rememberScrollbarAdapter(
scrollState: ScrollState
): ScrollbarAdapter = remember(scrollState) {
ScrollbarAdapter(scrollState)
}
@Composable
actual fun VerticalScrollbar(
modifier: Modifier,
adapter: ScrollbarAdapter
) {
androidx.compose.foundation.VerticalScrollbar(
modifier = modifier,
adapter = adapter
)
}

View File

@ -0,0 +1,98 @@
package com.shabinder.common.uikit
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.Card
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import com.shabinder.common.models.methods
@OptIn(ExperimentalAnimationApi::class)
@Composable
actual fun DonationDialog(
isVisible:Boolean,
onDismiss:()->Unit
){
AnimatedVisibility(
isVisible
) {
Dialog(onDismiss) {
Card(
modifier = Modifier.fillMaxSize(),
border = BorderStroke(1.dp, Color.Gray) // Gray
) {
Column(Modifier.padding(16.dp)) {
Text(
"Support Us",
style = SpotiFlyerTypography.h5,
textAlign = TextAlign.Center,
color = colorAccent,
modifier = Modifier
)
Spacer(modifier = Modifier.padding(vertical = 4.dp))
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().clickable(
onClick = {
onDismiss()
methods.value.openPlatform("", "https://www.paypal.com/paypalme/shabinder")
}
)
.padding(vertical = 6.dp)
) {
Icon(PaypalLogo(), "Paypal Logo", tint = Color(0xFFCCCCCC))
Spacer(modifier = Modifier.padding(start = 16.dp))
Column {
Text(
text = "Paypal",
style = SpotiFlyerTypography.h6
)
Text(
text = "International Donations (Outside India).",
style = SpotiFlyerTypography.subtitle2
)
}
}
Row(
modifier = Modifier.fillMaxWidth().padding(top = 6.dp)
.clickable(onClick = {
onDismiss()
methods.value.giveDonation()
}),
verticalAlignment = Alignment.CenterVertically
) {
Icon(RazorPay(), "Indian Rupee Logo", Modifier.size(32.dp), tint = Color(0xFFCCCCCC))
Spacer(modifier = Modifier.padding(start = 16.dp))
Column {
Text(
text = "RazorPay",
style = SpotiFlyerTypography.h6
)
Text(
text = "Indian Donations (UPI / PayTM / PhonePe / Cards).",
style = SpotiFlyerTypography.subtitle2
)
}
}
}
}
}
}
}

View File

@ -21,8 +21,8 @@ plugins {
kotlin("plugin.serialization") kotlin("plugin.serialization")
} }
val statelyVersion = "1.1.6" val statelyVersion = "1.1.7"
val statelyIsoVersion = "1.1.6-a1" val statelyIsoVersion = "1.1.7-a1"
kotlin { kotlin {
sourceSets { sourceSets {

View File

@ -161,6 +161,9 @@ actual class Dir actual constructor(
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
null null
} catch (e: OutOfMemoryError) {
e.printStackTrace()
null
} }
} }

View File

@ -212,10 +212,10 @@ class ForegroundService : Service(), CoroutineScope {
is DownloadResult.Error -> { is DownloadResult.Error -> {
launch { launch {
logger.d(tag) { it.message } logger.d(tag) { it.message }
logger.d(tag) { "${track.title} Requesting Download thru Android DM" } /*logger.d(tag) { "${track.title} Requesting Download thru Android DM" }
downloadUsingDM(url, track.outputFilePath, track) downloadUsingDM(url, track.outputFilePath, track)*/
removeFromNotification("Downloading ${track.title}") removeFromNotification("Downloading ${track.title}")
downloaded++ failed++
} }
updateNotification() updateNotification()
sendTrackBroadcast(Status.FAILED.name,track) sendTrackBroadcast(Status.FAILED.name,track)
@ -247,15 +247,16 @@ class ForegroundService : Service(), CoroutineScope {
removeFromNotification("Processing ${track.title}") removeFromNotification("Processing ${track.title}")
} }
logger.d(tag) { "${track.title} Download Completed" } logger.d(tag) { "${track.title} Download Completed" }
downloaded++
} catch ( } catch (
e: KotlinNullPointerException e: Exception
) { ) {
// Try downloading using android DM // Try downloading using android DM
logger.d(tag) { "${track.title} Download Failed! Error:Fetch!!!!" } logger.d(tag) { "${track.title} Download Failed! Error:Fetch!!!!" }
logger.d(tag) { "${track.title} Requesting Download thru Android DM" } failed++
downloadUsingDM(url, track.outputFilePath, track) /*logger.d(tag) { "${track.title} Requesting Download thru Android DM" }
downloadUsingDM(url, track.outputFilePath, track)*/
} }
downloaded++
removeFromNotification("Downloading ${track.title}") removeFromNotification("Downloading ${track.title}")
} }
} }
@ -263,7 +264,7 @@ class ForegroundService : Service(), CoroutineScope {
} }
/** /**
* If fetch Fails , Android Download Manager To RESCUE!! * If Custom Downloader Fails , Android Download Manager To RESCUE!!
**/ **/
private fun downloadUsingDM(url: String, outputDir: String, track: TrackDetails) { private fun downloadUsingDM(url: String, outputDir: String, track: TrackDetails) {
launch { launch {

View File

@ -61,9 +61,21 @@ compose.desktop {
mainClass = "MainKt" mainClass = "MainKt"
description = "Music Downloader for Spotify, Gaana, Youtube Music." description = "Music Downloader for Spotify, Gaana, Youtube Music."
nativeDistributions { nativeDistributions {
modules("java.sql", "java.security.jgss") modules("java.sql", "java.security.jgss", "jdk.crypto.ec")
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "SpotiFlyer" packageName = "SpotiFlyer"
copyright = "© 2021 Shabinder. All rights reserved."
vendor = "Shabinder"
val iconsRoot = project.file("src/jvmMain/resources/drawable")
macOS {
iconFile.set(iconsRoot.resolve("spotiflyer.icns"))
}
windows {
iconFile.set(iconsRoot.resolve("spotiflyer.ico"))
}
linux {
iconFile.set(iconsRoot.resolve("spotiflyer.png"))
}
} }
} }
} }

View File

@ -14,12 +14,14 @@
* * along with this program. If not, see <https://www.gnu.org/licenses/>. * * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import androidx.compose.desktop.AppManager
import androidx.compose.desktop.DesktopMaterialTheme import androidx.compose.desktop.DesktopMaterialTheme
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Surface import androidx.compose.material.Surface
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.IntSize
import com.arkivanov.decompose.ComponentContext import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.extensions.compose.jetbrains.rememberRootComponent import com.arkivanov.decompose.extensions.compose.jetbrains.rememberRootComponent
import com.arkivanov.mvikotlin.core.lifecycle.LifecycleRegistry import com.arkivanov.mvikotlin.core.lifecycle.LifecycleRegistry
@ -31,7 +33,6 @@ import com.shabinder.common.di.FetchPlatformQueryResult
import com.shabinder.common.di.initKoin import com.shabinder.common.di.initKoin
import com.shabinder.common.di.isInternetAccessible import com.shabinder.common.di.isInternetAccessible
import com.shabinder.common.models.Actions import com.shabinder.common.models.Actions
import com.shabinder.common.models.AllPlatforms
import com.shabinder.common.models.PlatformActions import com.shabinder.common.models.PlatformActions
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.root.SpotiFlyerRoot import com.shabinder.common.root.SpotiFlyerRoot
@ -41,8 +42,12 @@ import com.shabinder.common.uikit.SpotiFlyerShapes
import com.shabinder.common.uikit.SpotiFlyerTypography import com.shabinder.common.uikit.SpotiFlyerTypography
import com.shabinder.common.uikit.colorOffWhite import com.shabinder.common.uikit.colorOffWhite
import com.shabinder.database.Database import com.shabinder.database.Database
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import java.awt.Desktop
import java.net.URI
import javax.swing.JFileChooser
import javax.swing.JFileChooser.APPROVE_OPTION
import javax.swing.JFileChooser.CANCEL_OPTION
private val koin = initKoin(enableNetworkLogs = true).koin private val koin = initKoin(enableNetworkLogs = true).koin
private lateinit var showToast: (String)->Unit private lateinit var showToast: (String)->Unit
@ -52,7 +57,7 @@ fun main() {
val lifecycle = LifecycleRegistry() val lifecycle = LifecycleRegistry()
lifecycle.resume() lifecycle.resume()
Window("SpotiFlyer") { Window("SpotiFlyer",size = IntSize(450,800)) {
Surface( Surface(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
color = Color.Black, color = Color.Black,
@ -89,19 +94,39 @@ private fun spotiFlyerRoot(componentContext: ComponentContext): SpotiFlyerRoot =
} }
override fun setDownloadDirectoryAction() { override fun setDownloadDirectoryAction() {
showToast("TODO: Still needs to be Implemented") val fileChooser = JFileChooser().apply {
fileSelectionMode = JFileChooser.DIRECTORIES_ONLY
}
when (fileChooser.showOpenDialog(AppManager.focusedWindow?.window)) {
APPROVE_OPTION -> {
val directory = fileChooser.selectedFile
if(directory.canWrite()){
directories.setDownloadDirectory(directory.absolutePath)
showPopUpMessage("Set New Download Directory:\n${directory.absolutePath}")
} else {
showPopUpMessage("Cant Write to Selected Directory!")
}
}
else -> {
showPopUpMessage("No Directory Selected")
}
}
} }
override fun queryActiveTracks() {} override fun queryActiveTracks() {/**/}
override fun giveDonation() { override fun giveDonation() {
openLink("https://razorpay.com/payment-button/pl_GnKuuDBdBu0ank/view/?utm_source=payment_button&utm_medium=button&utm_campaign=payment_button")
} }
override fun shareApp() {} override fun shareApp() = openLink("https://github.com/Shabinder/SpotiFlyer")
override fun openPlatform(packageID: String, platformLink: String) { override fun openPlatform(packageID: String, platformLink: String) = openLink(platformLink)
showToast("TODO: Still needs to be Implemented")
fun openLink(link:String) {
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
Desktop.getDesktop().browse(URI(link))
}
} }
override fun writeMp3Tags(trackDetails: TrackDetails) {/*IMPLEMENTED*/} override fun writeMp3Tags(trackDetails: TrackDetails) {/*IMPLEMENTED*/}

View File

@ -0,0 +1,6 @@
<vector android:height="24dp" android:viewportHeight="456"
android:viewportWidth="456" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFFFFF" android:pathData="M61.179,282h-41.2c-6,0 -10.9,4.9 -10.9,10.9v152.2c0,6 4.9,10.9 10.9,10.9h41.2c6,0 10.9,-4.9 10.9,-10.9V292.9C72.079,286.9 67.179,282 61.179,282z"/>
<path android:fillColor="#FFFFFF" android:pathData="M443.179,294.4c-0.3,-0.4 -0.6,-0.8 -0.8,-1.2c-6.1,-6.8 -16.4,-7.7 -23.6,-2.1c-20,16.3 -49.2,39.8 -68.1,55.1c-16.7,13.3 -37.3,21 -58.7,21.8l-51.2,1.7c-9.4,0.3 -18.2,-4.5 -23,-12.6l-5.7,-9.7c-1.5,-2.5 -2.5,-5.3 -3.1,-8.2c-2.6,-13.9 6.5,-27.4 20.4,-30l52.9,-10c8.5,-1.7 14.3,-9.7 13.3,-18.3c-1,-8.2 -8,-14.3 -16.2,-14.4c-0.3,0 -0.7,0 -0.8,0c-0.4,0 -0.9,0 -1.3,0l-71.2,-2.9c-24.7,-0.9 -46,3.9 -71.2,16.1l-42.8,20.7v114l35.9,-6.6c0.1,-0.1 0.2,-0.1 0.3,-0.1c13.9,-2 23.1,-2.9 38.2,-2.2l107.5,5c33.7,1.4 66.8,-9.7 92.7,-31.3l74.4,-61.7C447.979,311.7 448.879,301.3 443.179,294.4z"/>
<path android:fillColor="#FFFFFF" android:pathData="M307.379,0c-61.2,0.1 -110.7,49.7 -110.8,110.8c0,0.1 0,0.1 0,0.1c0,61.2 49.7,110.8 110.9,110.8s110.8,-49.7 110.8,-110.9S368.579,0 307.379,0zM333.079,80h13.4c5.5,0 10,4.5 10,10s-4.5,10 -10,10h-13.4c-2,7.8 -6,14.9 -11.7,20.6c-7.5,7.5 -17.5,11.9 -28.1,12.5l37.7,35.7c4,3.8 4.2,10.1 0.4,14.1s-10.1,4.2 -14.1,0.4l-55.9,-52.9c-1.9,-1.9 -3.1,-4.5 -3.1,-7.2c-0.1,-5.6 4.4,-10.1 10,-10.2h22.4c6.2,0.1 12.2,-2.3 16.7,-6.7c1.8,-1.9 3.3,-4 4.6,-6.3h-43.7c-5.5,0 -10,-4.5 -10,-10s4.5,-10 10,-10h43.7c-3.7,-8 -11.9,-14 -21.3,-14h-22.4c-5.5,0 -10,-4.5 -10,-10s4.5,-10 10,-10h78.2c5.5,0 10,4.5 10,10s-4.5,10 -10,10h-19.2C330.079,70.3 331.979,75 333.079,80z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:viewportHeight="435.505"
android:viewportWidth="435.505" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFFFFF" android:pathData="M403.496,101.917c-4.104,-5.073 -8.877,-9.705 -14.166,-13.839c0.707,13.117 -0.508,27.092 -3.668,41.884c-8.627,40.413 -29.256,74.754 -59.656,99.304c-30.375,24.533 -68.305,37.502 -109.686,37.502h-60.344l-19.533,91.512c-3.836,17.959 -19.943,30.99 -38.303,30.99H70.938l-4.898,22.484c-1.258,5.79 0.17,11.839 3.887,16.453c3.715,4.614 9.324,7.298 15.25,7.298h66.498c9.24,0 17.225,-6.459 19.152,-15.495L193.667,313h76.188c36.854,0 70.527,-11.464 97.384,-33.152c26.869,-21.697 45.129,-52.186 52.807,-88.162C427.822,155.309 422.253,125.106 403.496,101.917z"/>
<path android:fillColor="#FFFFFF" android:pathData="M117.292,354.191l22.84,-107.008h76.188c36.852,0 70.527,-11.465 97.383,-33.154c26.867,-21.697 45.129,-52.186 52.809,-88.161c7.773,-36.378 2.207,-66.58 -16.553,-89.769C331.952,13.832 301.17,0 269.633,0H103.639c-9.209,0 -17.174,6.417 -19.135,15.414L12.505,345.938c-1.26,5.789 0.168,11.838 3.887,16.453c3.713,4.613 9.32,7.296 15.248,7.296h66.5C107.38,369.687 115.36,363.229 117.292,354.191zM178.235,75.291h52.229c12.287,0 23.274,5.149 30.145,14.129c7.297,9.539 9.431,22.729 5.853,36.188c-0.047,0.171 -0.088,0.342 -0.131,0.516c-6.57,27.73 -33.892,50.291 -60.898,50.291h-50.05L178.235,75.291z"/>
</vector>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB