SpotiFlyer/android/src/main/java/com/shabinder/spotiflyer/MainActivity.kt

321 lines
13 KiB
Kotlin
Raw Normal View History

2021-02-25 14:28:33 +01:00
package com.shabinder.spotiflyer
2021-01-26 13:54:28 +01:00
2021-02-10 18:25:36 +01:00
import android.annotation.SuppressLint
2021-02-22 18:38:33 +01:00
import android.content.BroadcastReceiver
2021-02-10 18:25:36 +01:00
import android.content.Context
import android.content.Intent
2021-02-22 18:38:33 +01:00
import android.content.IntentFilter
2021-02-10 18:25:36 +01:00
import android.os.Build
2021-01-26 13:54:28 +01:00
import android.os.Bundle
2021-02-10 18:25:36 +01:00
import android.os.PowerManager
2021-02-22 18:38:33 +01:00
import android.util.Log
2021-02-10 18:25:36 +01:00
import androidx.activity.ComponentActivity
2021-02-11 21:51:11 +01:00
import androidx.activity.compose.setContent
2021-02-26 11:29:10 +01:00
import androidx.compose.animation.*
2021-02-25 16:23:10 +01:00
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.SdStorage
import androidx.compose.material.icons.rounded.SystemSecurityUpdate
2021-02-25 14:28:33 +01:00
import androidx.compose.runtime.*
2021-02-25 16:23:10 +01:00
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
2021-02-24 18:02:01 +01:00
import androidx.compose.ui.platform.LocalView
2021-02-25 16:23:10 +01:00
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
2021-02-24 18:02:01 +01:00
import androidx.compose.ui.unit.dp
2021-02-25 16:23:10 +01:00
import androidx.compose.ui.unit.sp
2021-02-24 18:02:01 +01:00
import androidx.core.view.WindowCompat
2021-02-22 18:38:33 +01:00
import androidx.lifecycle.lifecycleScope
2021-02-07 17:19:48 +01:00
import com.arkivanov.decompose.ComponentContext
2021-02-25 14:28:33 +01:00
import com.arkivanov.decompose.extensions.compose.jetbrains.rememberRootComponent
2021-02-07 17:19:48 +01:00
import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory
import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
import com.razorpay.Checkout
import com.razorpay.PaymentResultListener
import com.shabinder.common.database.activityContext
2021-02-25 16:23:10 +01:00
import com.shabinder.common.di.*
2021-02-21 15:21:43 +01:00
import com.shabinder.common.models.DownloadStatus
2021-02-22 18:38:33 +01:00
import com.shabinder.common.models.TrackDetails
2021-02-07 17:19:48 +01:00
import com.shabinder.common.root.SpotiFlyerRoot
2021-02-10 18:25:36 +01:00
import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks
2021-02-25 16:23:10 +01:00
import com.shabinder.common.uikit.*
2021-02-07 17:19:48 +01:00
import com.shabinder.database.Database
2021-02-26 00:59:54 +01:00
import com.shabinder.spotiflyer.utils.*
2021-02-22 18:38:33 +01:00
import com.tonyodev.fetch2.Status
2021-02-10 18:25:36 +01:00
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
2021-02-07 17:19:48 +01:00
import org.koin.android.ext.android.inject
import com.shabinder.common.uikit.showPopUpMessage as uikitShowPopUpMessage
2021-01-26 13:54:28 +01:00
2021-02-10 18:25:36 +01:00
const val disableDozeCode = 1223
2021-02-07 17:19:48 +01:00
2021-02-26 10:41:25 +01:00
@ExperimentalAnimationApi
class MainActivity : ComponentActivity(), PaymentResultListener {
2021-02-10 18:25:36 +01:00
private val fetcher: FetchPlatformQueryResult by inject()
private val dir: Dir by inject()
private lateinit var root: SpotiFlyerRoot
private val callBacks: SpotiFlyerRootCallBacks
get() = root.callBacks
private val trackStatusFlow = MutableSharedFlow<HashMap<String, DownloadStatus>>(1)
2021-02-25 16:23:10 +01:00
private var permissionGranted = mutableStateOf(true)
2021-02-22 18:38:33 +01:00
private lateinit var updateUIReceiver: BroadcastReceiver
private lateinit var queryReceiver: BroadcastReceiver
2021-02-07 17:19:48 +01:00
2021-01-26 13:54:28 +01:00
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
2021-02-24 18:02:01 +01:00
// This app draws behind the system bars, so we want to handle fitting system windows
WindowCompat.setDecorFitsSystemWindows(window, false)
2021-01-26 13:54:28 +01:00
setContent {
2021-02-07 17:19:48 +01:00
SpotiFlyerTheme {
Surface(contentColor = colorOffWhite) {
2021-02-24 18:02:01 +01:00
var statusBarHeight by remember { mutableStateOf(27.dp) }
2021-02-25 16:23:10 +01:00
permissionGranted = remember { mutableStateOf(true) }
2021-02-24 18:02:01 +01:00
val view = LocalView.current
LaunchedEffect(view){
2021-02-26 10:41:25 +01:00
permissionGranted.value = checkPermissions()
2021-02-24 18:02:01 +01:00
view.setOnApplyWindowInsetsListener { _, insets ->
statusBarHeight = insets.systemWindowInsetTop.dp
insets
}
}
2021-02-25 16:23:10 +01:00
2021-02-26 10:41:25 +01:00
root = SpotiFlyerRootContent(rememberRootComponent(::spotiFlyerRoot),statusBarHeight)
2021-02-25 16:23:10 +01:00
2021-02-26 00:59:54 +01:00
NetworkDialog()
2021-02-26 10:41:25 +01:00
PermissionDialog()
}
2021-02-07 17:19:48 +01:00
}
2021-01-26 13:54:28 +01:00
}
2021-02-10 18:25:36 +01:00
initialise()
2021-01-26 13:54:28 +01:00
}
2021-02-07 17:19:48 +01:00
2021-02-10 18:25:36 +01:00
private fun initialise() {
checkIfLatestVersion()
dir.createDirectories()
Checkout.preload(applicationContext)
2021-02-26 11:29:10 +01:00
handleIntentFromExternalActivity()
2021-02-10 18:25:36 +01:00
}
2021-02-07 17:19:48 +01:00
2021-02-26 10:41:25 +01:00
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
permissionGranted.value = checkPermissions()
}
2021-02-07 17:19:48 +01:00
private fun spotiFlyerRoot(componentContext: ComponentContext): SpotiFlyerRoot =
SpotiFlyerRoot(
componentContext,
dependencies = object : SpotiFlyerRoot.Dependencies{
override val storeFactory = LoggingStoreFactory(DefaultStoreFactory)
override val database = this@MainActivity.dir.db
2021-02-07 17:19:48 +01:00
override val fetchPlatformQueryResult = this@MainActivity.fetcher
override val directories: Dir = this@MainActivity.dir
override val showPopUpMessage: (String) -> Unit = ::uikitShowPopUpMessage
override val downloadProgressReport: MutableSharedFlow<HashMap<String, DownloadStatus>> = trackStatusFlow
2021-02-07 17:19:48 +01:00
}
)
2021-02-10 18:25:36 +01:00
@SuppressLint("ObsoleteSdkInt")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == disableDozeCode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val pm =
getSystemService(Context.POWER_SERVICE) as PowerManager
val isIgnoringBatteryOptimizations =
pm.isIgnoringBatteryOptimizations(packageName)
if (isIgnoringBatteryOptimizations) {
// Ignoring battery optimization
2021-02-25 16:23:10 +01:00
permissionGranted.value = true
2021-02-10 18:25:36 +01:00
} else {
disableDozeMode(disableDozeCode)//Again Ask For Permission!!
}
}
}
}
2021-02-22 18:38:33 +01:00
private fun initializeBroadcast(){
val intentFilter = IntentFilter().apply {
addAction(Status.QUEUED.name)
addAction(Status.FAILED.name)
addAction(Status.DOWNLOADING.name)
addAction(Status.COMPLETED.name)
2021-02-22 18:38:33 +01:00
addAction("Progress")
addAction("Converting")
}
updateUIReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
//Update Flow with latest details
if (intent != null) {
val trackDetails = intent.getParcelableExtra<TrackDetails?>("track")
trackDetails?.let { track ->
lifecycleScope.launch {
val latestMap = trackStatusFlow.replayCache.getOrElse(0
) { hashMapOf() }.apply {
2021-02-22 18:38:33 +01:00
this[track.title] = when (intent.action) {
Status.QUEUED.name -> DownloadStatus.Queued
Status.FAILED.name -> DownloadStatus.Failed
Status.DOWNLOADING.name -> DownloadStatus.Downloading()
"Progress" -> DownloadStatus.Downloading(intent.getIntExtra("progress", 0))
"Converting" -> DownloadStatus.Converting
Status.COMPLETED.name -> DownloadStatus.Downloaded
2021-02-22 18:38:33 +01:00
else -> DownloadStatus.NotDownloaded
}
}
trackStatusFlow.emit(latestMap)
Log.i("Track Update",track.title + track.downloaded.toString())
2021-02-22 18:38:33 +01:00
}
}
}
}
}
val queryFilter = IntentFilter().apply { addAction("query_result") }
queryReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
//UI update here
if (intent != null){
@Suppress("UNCHECKED_CAST")
val trackList = intent.getSerializableExtra("tracks") as? HashMap<String, DownloadStatus>?
trackList?.let { list ->
Log.i("Service Response", "${list.size} Tracks Active")
lifecycleScope.launch {
trackStatusFlow.emit(list)
2021-02-22 18:38:33 +01:00
}
}
}
}
}
registerReceiver(updateUIReceiver, intentFilter)
registerReceiver(queryReceiver, queryFilter)
}
override fun onResume() {
super.onResume()
initializeBroadcast()
}
override fun onPause() {
super.onPause()
unregisterReceiver(updateUIReceiver)
unregisterReceiver(queryReceiver)
}
2021-02-10 18:25:36 +01:00
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
handleIntentFromExternalActivity(intent)
}
private fun handleIntentFromExternalActivity(intent: Intent? = getIntent()) {
if (intent?.action == Intent.ACTION_SEND) {
if ("text/plain" == intent.type) {
intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
val filterLinkRegex = """http.+\w""".toRegex()
val string = it.replace("\n".toRegex(), " ")
val link = filterLinkRegex.find(string)?.value.toString()
2021-02-26 11:29:10 +01:00
Log.i("Intent",link)
lifecycleScope.launch {
while(!this@MainActivity::root.isInitialized){
delay(100)
}
if(isInternetAvailable)callBacks.searchLink(link)
}
2021-02-10 18:25:36 +01:00
}
}
}
}
override fun onPaymentError(errorCode: Int, response: String?) {
try{
uikitShowPopUpMessage("Payment Failed, Response:$response")
}catch (e: Exception){
Log.d("Razorpay Payment","Exception in onPaymentSuccess $response")
}
}
override fun onPaymentSuccess(razorpayPaymentId: String?) {
try{
uikitShowPopUpMessage("Payment Successful, ThankYou!")
}catch (e: Exception){
uikitShowPopUpMessage("Razorpay Payment, Error Occurred.")
Log.d("Razorpay Payment","Exception in onPaymentSuccess, ${e.message}")
}
}
2021-02-25 16:23:10 +01:00
@Composable
2021-02-26 10:41:25 +01:00
private fun PermissionDialog(){
var askForPermission by remember { mutableStateOf(false) }
LaunchedEffect(Unit){
delay(2000)
askForPermission = true
}
2021-02-26 11:29:10 +01:00
AnimatedVisibility(
askForPermission && !permissionGranted.value
){
2021-02-26 10:41:25 +01:00
AlertDialog(
onDismissRequest = {},
buttons = {
TextButton({
requestStoragePermission()
disableDozeMode(disableDozeCode)
},Modifier.padding(bottom = 16.dp,start = 16.dp,end = 16.dp).fillMaxWidth().background(colorPrimary,shape = SpotiFlyerShapes.medium).padding(horizontal = 8.dp),
){
Text("Grant Permissions",color = Color.Black,fontSize = 18.sp,textAlign = TextAlign.Center)
2021-02-25 16:23:10 +01:00
}
2021-02-26 10:41:25 +01:00
},title = {Text("Required Permissions:",style = SpotiFlyerTypography.h5,textAlign = TextAlign.Center)},
backgroundColor = Color.DarkGray,
text = {
Column{
Spacer(modifier = Modifier.padding(8.dp))
Row(verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().padding(vertical = 6.dp)
) {
Icon(Icons.Rounded.SdStorage,"Storage Permission.")
Spacer(modifier = Modifier.padding(start = 16.dp))
Column {
Text(
text = "Storage Permission.",
style = SpotiFlyerTypography.h6.copy(fontWeight = FontWeight.SemiBold)
)
Text(
text = "To download your favourite songs to this device.",
style = SpotiFlyerTypography.subtitle2,
)
}
}
Row(
modifier = Modifier.fillMaxWidth().padding(top = 6.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(Icons.Rounded.SystemSecurityUpdate,"Allow Background Running")
Spacer(modifier = Modifier.padding(start = 16.dp))
Column {
Text(
text = "Background Running.",
style = SpotiFlyerTypography.h6.copy(fontWeight = FontWeight.SemiBold)
)
Text(
text = "To download all songs in background without any System Interruptions",
style = SpotiFlyerTypography.subtitle2,
)
}
2021-02-25 16:23:10 +01:00
}
}
}
2021-02-26 10:41:25 +01:00
)
}
2021-02-25 16:23:10 +01:00
}
init {
activityContext = this
}
2021-02-07 17:19:48 +01:00
}