mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-12-22 12:47:54 +01:00
Dep Updates and Analytics & Crashlytics Changed
This commit is contained in:
parent
ad94224d5c
commit
9d1e29b7e7
@ -14,7 +14,6 @@
|
|||||||
* * 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 Extras.Android.Acra
|
|
||||||
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
|
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
|
||||||
import org.jetbrains.compose.compose
|
import org.jetbrains.compose.compose
|
||||||
|
|
||||||
@ -73,7 +72,6 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
useIR = true
|
|
||||||
jvmTarget = "1.8"
|
jvmTarget = "1.8"
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
@ -123,10 +121,8 @@ dependencies {
|
|||||||
|
|
||||||
// Extras
|
// Extras
|
||||||
with(Extras.Android) {
|
with(Extras.Android) {
|
||||||
implementation(Acra.notification)
|
implementation(countly)
|
||||||
implementation(Acra.http)
|
|
||||||
implementation(appUpdator)
|
implementation(appUpdator)
|
||||||
implementation(matomo)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
with(Versions.androidxLifecycle) {
|
with(Versions.androidxLifecycle) {
|
||||||
@ -138,7 +134,7 @@ dependencies {
|
|||||||
// implementation("com.jakewharton.timber:timber:4.7.1")
|
// implementation("com.jakewharton.timber:timber:4.7.1")
|
||||||
implementation("dev.icerock.moko:parcelize:${Versions.mokoParcelize}")
|
implementation("dev.icerock.moko:parcelize:${Versions.mokoParcelize}")
|
||||||
implementation("com.github.shabinder:storage-chooser:2.0.4.45")
|
implementation("com.github.shabinder:storage-chooser:2.0.4.45")
|
||||||
implementation("com.google.accompanist:accompanist-insets:0.12.0")
|
implementation("com.google.accompanist:accompanist-insets:0.16.1")
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
testImplementation("junit:junit:4.13.2")
|
testImplementation("junit:junit:4.13.2")
|
||||||
|
@ -40,6 +40,8 @@
|
|||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<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.INTERNET"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".App"
|
android:name=".App"
|
||||||
@ -73,5 +75,16 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<service android:name=".service.ForegroundService"/>
|
<service android:name=".service.ForegroundService"/>
|
||||||
|
<service android:name="org.openudid.OpenUDID_service">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="org.openudid.GETUDID" />
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<receiver android:name="ly.count.android.sdk.ReferrerReceiver" android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.android.vending.INSTALL_REFERRER" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
@ -17,22 +17,12 @@
|
|||||||
package com.shabinder.spotiflyer
|
package com.shabinder.spotiflyer
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
|
||||||
import com.shabinder.common.di.initKoin
|
import com.shabinder.common.di.initKoin
|
||||||
import com.shabinder.common.translations.Strings
|
|
||||||
import com.shabinder.spotiflyer.di.appModule
|
import com.shabinder.spotiflyer.di.appModule
|
||||||
import org.acra.config.httpSender
|
|
||||||
import org.acra.config.notification
|
|
||||||
import org.acra.data.StringFormat
|
|
||||||
import org.acra.ktx.initAcra
|
|
||||||
import org.acra.sender.HttpSender
|
|
||||||
import org.koin.android.ext.koin.androidContext
|
import org.koin.android.ext.koin.androidContext
|
||||||
import org.koin.android.ext.koin.androidLogger
|
import org.koin.android.ext.koin.androidLogger
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.logger.Level
|
import org.koin.core.logger.Level
|
||||||
import org.matomo.sdk.Matomo
|
|
||||||
import org.matomo.sdk.Tracker
|
|
||||||
import org.matomo.sdk.TrackerBuilder
|
|
||||||
|
|
||||||
class App : Application(), KoinComponent {
|
class App : Application(), KoinComponent {
|
||||||
|
|
||||||
@ -40,21 +30,6 @@ class App : Application(), KoinComponent {
|
|||||||
const val SIGNATURE_HEX = "53304f6d75736a2f30484230334c454b714753525763724259444d3d0a"
|
const val SIGNATURE_HEX = "53304f6d75736a2f30484230334c454b714753525763724259444d3d0a"
|
||||||
}
|
}
|
||||||
|
|
||||||
val tracker: Tracker by lazy {
|
|
||||||
TrackerBuilder.createDefault(
|
|
||||||
"https://matomo.spotiflyer.ml/matomo.php", 1
|
|
||||||
)
|
|
||||||
.build(Matomo.getInstance(this)).apply {
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
/*Timber.plant(DebugTree())
|
|
||||||
addTrackingCallback {
|
|
||||||
Timber.d(it.toMap().toString())
|
|
||||||
it
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
@ -66,35 +41,4 @@ class App : Application(), KoinComponent {
|
|||||||
modules(appModule(loggingEnabled))
|
modules(appModule(loggingEnabled))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("SpellCheckingInspection")
|
|
||||||
override fun attachBaseContext(base: Context?) {
|
|
||||||
super.attachBaseContext(base)
|
|
||||||
// Crashlytics
|
|
||||||
initAcra {
|
|
||||||
buildConfigClass = BuildConfig::class.java
|
|
||||||
reportFormat = StringFormat.JSON
|
|
||||||
/*
|
|
||||||
* Prompt User Before Sending Any Crash Report
|
|
||||||
* Obeying `F-Droid Inclusion Privacy Rules`
|
|
||||||
* */
|
|
||||||
notification {
|
|
||||||
title = Strings.acraNotificationTitle()
|
|
||||||
text = Strings.acraNotificationText()
|
|
||||||
channelName = "SpotiFlyer_Crashlytics"
|
|
||||||
channelDescription = "Notification Channel to send Spotiflyer Crashes."
|
|
||||||
sendOnClick = true
|
|
||||||
}
|
|
||||||
// Send Crash Report to self hosted Acrarium (FOSS)
|
|
||||||
httpSender {
|
|
||||||
uri = "https://acrarium.spotiflyer.ml/acrarium/report"
|
|
||||||
basicAuthLogin = "sDj2xCKQIxw0dujf"
|
|
||||||
basicAuthPassword = "O83du0TsgsDJ69zN"
|
|
||||||
httpMethod = HttpSender.Method.POST
|
|
||||||
connectionTimeout = 15000
|
|
||||||
socketTimeout = 20000
|
|
||||||
compress = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,7 @@
|
|||||||
package com.shabinder.spotiflyer
|
package com.shabinder.spotiflyer
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.ClipData
|
import android.content.*
|
||||||
import android.content.ClipboardManager
|
|
||||||
import android.content.ComponentName
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.ServiceConnection
|
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.media.MediaScannerConnection
|
import android.media.MediaScannerConnection
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
@ -40,13 +35,7 @@ import androidx.compose.foundation.layout.Spacer
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Surface
|
import androidx.compose.material.Surface
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.State
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
@ -65,14 +54,11 @@ import com.google.accompanist.insets.statusBarsPadding
|
|||||||
import com.shabinder.common.di.ConnectionLiveData
|
import com.shabinder.common.di.ConnectionLiveData
|
||||||
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.analytics.AnalyticsManager
|
||||||
import com.shabinder.common.di.observeAsState
|
import com.shabinder.common.di.observeAsState
|
||||||
import com.shabinder.common.di.preference.PreferenceManager
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import com.shabinder.common.models.Actions
|
import com.shabinder.common.models.*
|
||||||
import com.shabinder.common.models.DownloadStatus
|
|
||||||
import com.shabinder.common.models.PlatformActions
|
|
||||||
import com.shabinder.common.models.PlatformActions.Companion.SharedPreferencesKey
|
import com.shabinder.common.models.PlatformActions.Companion.SharedPreferencesKey
|
||||||
import com.shabinder.common.models.TrackDetails
|
|
||||||
import com.shabinder.common.models.methods
|
|
||||||
import com.shabinder.common.root.SpotiFlyerRoot
|
import com.shabinder.common.root.SpotiFlyerRoot
|
||||||
import com.shabinder.common.root.SpotiFlyerRoot.Analytics
|
import com.shabinder.common.root.SpotiFlyerRoot.Analytics
|
||||||
import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks
|
import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks
|
||||||
@ -84,17 +70,14 @@ import com.shabinder.spotiflyer.service.ForegroundService
|
|||||||
import com.shabinder.spotiflyer.ui.AnalyticsDialog
|
import com.shabinder.spotiflyer.ui.AnalyticsDialog
|
||||||
import com.shabinder.spotiflyer.ui.NetworkDialog
|
import com.shabinder.spotiflyer.ui.NetworkDialog
|
||||||
import com.shabinder.spotiflyer.ui.PermissionDialog
|
import com.shabinder.spotiflyer.ui.PermissionDialog
|
||||||
import com.shabinder.spotiflyer.utils.checkAppSignature
|
import com.shabinder.spotiflyer.utils.*
|
||||||
import com.shabinder.spotiflyer.utils.checkIfLatestVersion
|
|
||||||
import com.shabinder.spotiflyer.utils.checkPermissions
|
|
||||||
import com.shabinder.spotiflyer.utils.disableDozeMode
|
|
||||||
import com.shabinder.spotiflyer.utils.requestStoragePermission
|
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.conflate
|
import kotlinx.coroutines.flow.conflate
|
||||||
import kotlinx.coroutines.flow.emitAll
|
import kotlinx.coroutines.flow.emitAll
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
|
import org.koin.core.parameter.parametersOf
|
||||||
import org.matomo.sdk.extra.TrackHelper
|
import org.matomo.sdk.extra.TrackHelper
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@ -104,12 +87,13 @@ class MainActivity : ComponentActivity() {
|
|||||||
private val fetcher: FetchPlatformQueryResult by inject()
|
private val fetcher: FetchPlatformQueryResult by inject()
|
||||||
private val dir: Dir by inject()
|
private val dir: Dir by inject()
|
||||||
private val preferenceManager: PreferenceManager by inject()
|
private val preferenceManager: PreferenceManager by inject()
|
||||||
|
private val analyticsManager: AnalyticsManager by inject { parametersOf(this) }
|
||||||
private lateinit var root: SpotiFlyerRoot
|
private lateinit var root: SpotiFlyerRoot
|
||||||
private val callBacks: SpotiFlyerRootCallBacks get() = root.callBacks
|
private val callBacks: SpotiFlyerRootCallBacks get() = root.callBacks
|
||||||
private val trackStatusFlow = MutableSharedFlow<HashMap<String, DownloadStatus>>(1)
|
private val trackStatusFlow = MutableSharedFlow<HashMap<String, DownloadStatus>>(1)
|
||||||
private var permissionGranted = mutableStateOf(true)
|
private var permissionGranted = mutableStateOf(true)
|
||||||
private val internetAvailability by lazy { ConnectionLiveData(applicationContext) }
|
private val internetAvailability by lazy { ConnectionLiveData(applicationContext) }
|
||||||
private val tracker get() = (application as App).tracker
|
|
||||||
private val visibleChild get(): SpotiFlyerRoot.Child = root.routerState.value.activeChild.instance
|
private val visibleChild get(): SpotiFlyerRoot.Child = root.routerState.value.activeChild.instance
|
||||||
|
|
||||||
// Variable for storing instance of our service class
|
// Variable for storing instance of our service class
|
||||||
@ -186,11 +170,10 @@ class MainActivity : ComponentActivity() {
|
|||||||
* and Track Downloads for all other releases like F-Droid,
|
* and Track Downloads for all other releases like F-Droid,
|
||||||
* for `Github Downloads` we will track Downloads using : https://tooomm.github.io/github-release-stats/?username=Shabinder&repository=SpotiFlyer
|
* for `Github Downloads` we will track Downloads using : https://tooomm.github.io/github-release-stats/?username=Shabinder&repository=SpotiFlyer
|
||||||
* */
|
* */
|
||||||
if (isGithubRelease) { checkIfLatestVersion() }
|
if (isGithubRelease) {
|
||||||
if (preferenceManager.isAnalyticsEnabled && !isGithubRelease) {
|
checkIfLatestVersion()
|
||||||
// Download/App Install Event for F-Droid builds
|
|
||||||
TrackHelper.track().download().with(tracker)
|
|
||||||
}
|
}
|
||||||
|
// TODO Track Download Event
|
||||||
handleIntentFromExternalActivity()
|
handleIntentFromExternalActivity()
|
||||||
|
|
||||||
initForegroundService()
|
initForegroundService()
|
||||||
@ -297,14 +280,19 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showPopUpMessage(string: String, long: Boolean) = this@MainActivity.showPopUpMessage(string, long)
|
override fun showPopUpMessage(string: String, long: Boolean) =
|
||||||
|
this@MainActivity.showPopUpMessage(string, long)
|
||||||
|
|
||||||
override fun setDownloadDirectoryAction(callBack: (String) -> Unit) = setUpOnPrefClickListener(callBack)
|
override fun setDownloadDirectoryAction(callBack: (String) -> Unit) =
|
||||||
|
setUpOnPrefClickListener(callBack)
|
||||||
|
|
||||||
override fun queryActiveTracks() = this@MainActivity.queryActiveTracks()
|
override fun queryActiveTracks() = this@MainActivity.queryActiveTracks()
|
||||||
|
|
||||||
override fun giveDonation() {
|
override fun giveDonation() {
|
||||||
openPlatform("", platformLink = "https://razorpay.com/payment-button/pl_GnKuuDBdBu0ank/view/?utm_source=payment_button&utm_medium=button&utm_campaign=payment_button")
|
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() {
|
||||||
@ -341,7 +329,8 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun writeMp3Tags(trackDetails: TrackDetails) { /*IMPLEMENTED*/ }
|
override fun writeMp3Tags(trackDetails: TrackDetails) { /*IMPLEMENTED*/
|
||||||
|
}
|
||||||
|
|
||||||
override val isInternetAvailable get() = internetAvailability.value ?: true
|
override val isInternetAvailable get() = internetAvailability.value ?: true
|
||||||
}
|
}
|
||||||
@ -351,35 +340,19 @@ class MainActivity : ComponentActivity() {
|
|||||||
* */
|
* */
|
||||||
override val analytics = object : Analytics {
|
override val analytics = object : Analytics {
|
||||||
override fun appLaunchEvent() {
|
override fun appLaunchEvent() {
|
||||||
if (preferenceManager.isAnalyticsEnabled) {
|
analyticsManager.sendEvent("app_launch")
|
||||||
TrackHelper.track()
|
|
||||||
.event("events", "App_Launch")
|
|
||||||
.name("App Launch").with(tracker)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun homeScreenVisit() {
|
override fun homeScreenVisit() {
|
||||||
if (preferenceManager.isAnalyticsEnabled) {
|
analyticsManager.sendView("home_screen")
|
||||||
// HomeScreen Visit Event
|
|
||||||
TrackHelper.track().screen("/main_activity/home_screen")
|
|
||||||
.title("HomeScreen").with(tracker)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun listScreenVisit() {
|
override fun listScreenVisit() {
|
||||||
if (preferenceManager.isAnalyticsEnabled) {
|
analyticsManager.sendView("list_screen")
|
||||||
// ListScreen Visit Event
|
|
||||||
TrackHelper.track().screen("/main_activity/list_screen")
|
|
||||||
.title("ListScreen").with(tracker)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun donationDialogVisit() {
|
override fun donationDialogVisit() {
|
||||||
if (preferenceManager.isAnalyticsEnabled) {
|
analyticsManager.sendEvent("open_donation_dialog")
|
||||||
// Donation Dialog Open Event
|
|
||||||
TrackHelper.track().screen("/main_activity/donation_dialog")
|
|
||||||
.title("DonationDialog").with(tracker)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -469,7 +442,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
while (!this@MainActivity::root.isInitialized) {
|
while (!this@MainActivity::root.isInitialized) {
|
||||||
delay(100)
|
delay(100)
|
||||||
}
|
}
|
||||||
if (methods.value.isInternetAvailable)callBacks.searchLink(link)
|
if (methods.value.isInternetAvailable) callBacks.searchLink(link)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -481,6 +454,16 @@ class MainActivity : ComponentActivity() {
|
|||||||
unbindService()
|
unbindService()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
analyticsManager.onStart()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
analyticsManager.onStop()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val disableDozeCode = 1223
|
const val disableDozeCode = 1223
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,9 @@ object Versions {
|
|||||||
|
|
||||||
const val versionCode = 22
|
const val versionCode = 22
|
||||||
// Kotlin
|
// Kotlin
|
||||||
const val kotlinVersion = "1.5.10"
|
const val kotlinVersion = "1.5.21"
|
||||||
|
|
||||||
const val coroutinesVersion = "1.5.0"
|
const val coroutinesVersion = "1.5.1"
|
||||||
|
|
||||||
// Code Formatting
|
// Code Formatting
|
||||||
const val ktLint = "10.1.0"
|
const val ktLint = "10.1.0"
|
||||||
@ -41,24 +41,24 @@ object Versions {
|
|||||||
const val mokoParcelize = "0.7.1"
|
const val mokoParcelize = "0.7.1"
|
||||||
|
|
||||||
// Internet
|
// Internet
|
||||||
const val ktor = "1.6.0"
|
const val ktor = "1.6.2"
|
||||||
|
|
||||||
const val kotlinxSerialization = "1.2.1"
|
const val kotlinxSerialization = "1.2.2"
|
||||||
|
|
||||||
// Database
|
// Database
|
||||||
const val sqlDelight = "1.5.0"
|
const val sqlDelight = "1.5.1"
|
||||||
|
|
||||||
const val sqliteJdbcDriver = "3.34.0"
|
const val sqliteJdbcDriver = "3.34.0"
|
||||||
const val slf4j = "1.7.31"
|
const val slf4j = "1.7.31"
|
||||||
|
|
||||||
// Internationalisation
|
// Internationalisation
|
||||||
const val i18n4k = "0.1.2"
|
const val i18n4k = "0.1.3"
|
||||||
|
|
||||||
// Android
|
// Android
|
||||||
const val minSdkVersion = 21
|
const val minSdkVersion = 21
|
||||||
const val compileSdkVersion = 30
|
const val compileSdkVersion = 30
|
||||||
const val targetSdkVersion = 29
|
const val targetSdkVersion = 29
|
||||||
const val androidxLifecycle = "2.3.1"
|
const val androidxLifecycle = "2.4.0-alpha03"
|
||||||
}
|
}
|
||||||
|
|
||||||
object HostOS {
|
object HostOS {
|
||||||
@ -81,8 +81,8 @@ object Koin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object Androidx {
|
object Androidx {
|
||||||
const val androidxActivity = "androidx.activity:activity-compose:1.3.0-beta02"
|
const val androidxActivity = "androidx.activity:activity-compose:1.3.1"
|
||||||
const val core = "androidx.core:core-ktx:1.5.0"
|
const val core = "androidx.core:core-ktx:1.6.0"
|
||||||
const val palette = "androidx.palette:palette-ktx:1.0.0"
|
const val palette = "androidx.palette:palette-ktx:1.0.0"
|
||||||
const val coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.coroutinesVersion}"
|
const val coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.coroutinesVersion}"
|
||||||
|
|
||||||
@ -98,6 +98,7 @@ object KTLint {
|
|||||||
|
|
||||||
object JetBrains {
|
object JetBrains {
|
||||||
object Kotlin {
|
object Kotlin {
|
||||||
|
const val coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1-native-mt"
|
||||||
const val gradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlinVersion}"
|
const val gradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlinVersion}"
|
||||||
const val serialization = "org.jetbrains.kotlin:kotlin-serialization:${Versions.kotlinVersion}"
|
const val serialization = "org.jetbrains.kotlin:kotlin-serialization:${Versions.kotlinVersion}"
|
||||||
const val testCommon = "org.jetbrains.kotlin:kotlin-test-common:${Versions.kotlinVersion}"
|
const val testCommon = "org.jetbrains.kotlin:kotlin-test-common:${Versions.kotlinVersion}"
|
||||||
@ -107,15 +108,16 @@ object JetBrains {
|
|||||||
|
|
||||||
object Compose {
|
object Compose {
|
||||||
// __LATEST_COMPOSE_RELEASE_VERSION__
|
// __LATEST_COMPOSE_RELEASE_VERSION__
|
||||||
const val VERSION = "0.4.0"
|
private const val VERSION = "1.0.0-alpha3"
|
||||||
const val gradlePlugin = "org.jetbrains.compose:compose-gradle-plugin:$VERSION"
|
const val gradlePlugin = "org.jetbrains.compose:compose-gradle-plugin:$VERSION"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
object Mosaic {
|
object Mosaic {
|
||||||
const val gradlePlugin = "com.jakewharton.mosaic:mosaic-gradle-plugin:${Versions.mosaic}"
|
const val gradlePlugin = "com.jakewharton.mosaic:mosaic-gradle-plugin:${Versions.mosaic}"
|
||||||
}
|
}
|
||||||
|
|
||||||
object Decompose {
|
object Decompose {
|
||||||
private const val VERSION = "0.2.6"
|
private const val VERSION = "0.3.1"
|
||||||
const val decompose = "com.arkivanov.decompose:decompose:$VERSION"
|
const val decompose = "com.arkivanov.decompose:decompose:$VERSION"
|
||||||
const val decomposeIosX64 = "com.arkivanov.decompose:decompose-iosx64:$VERSION"
|
const val decomposeIosX64 = "com.arkivanov.decompose:decompose-iosx64:$VERSION"
|
||||||
const val decomposeIosArm64 = "com.arkivanov.decompose:decompose-iosarm64:$VERSION"
|
const val decomposeIosArm64 = "com.arkivanov.decompose:decompose-iosarm64:$VERSION"
|
||||||
@ -164,16 +166,13 @@ 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 {
|
||||||
object Acra {
|
// Self Hosted Analytics & Crashlytics (FOSS)
|
||||||
// Self Hosted Crashlytics (FOSS)
|
val countly = "ly.count.android:sdk:20.11.8"
|
||||||
private const val VERSION = "5.8.3"
|
|
||||||
val http = "ch.acra:acra-http:$VERSION"
|
|
||||||
val notification = "ch.acra:acra-notification:$VERSION"
|
|
||||||
}
|
|
||||||
// Self Hosted Analytics (FOSS)
|
|
||||||
val matomo = "org.matomo.sdk:tracker:4.1.2"
|
|
||||||
val appUpdator = "com.github.amitbd1508:AppUpdater:4.1.0"
|
val appUpdator = "com.github.amitbd1508:AppUpdater:4.1.0"
|
||||||
}
|
}
|
||||||
|
object Desktop {
|
||||||
|
val countly = "ly.count.sdk:java:20.11.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object Serialization {
|
object Serialization {
|
||||||
|
@ -37,7 +37,6 @@ android {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
named("main") {
|
named("main") {
|
||||||
manifest.srcFile("src/androidMain/AndroidManifest.xml")
|
manifest.srcFile("src/androidMain/AndroidManifest.xml")
|
||||||
java.srcDirs("src/androidMain/kotlin")
|
|
||||||
res.srcDirs("src/androidMain/res")
|
res.srcDirs("src/androidMain/res")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ kotlin {
|
|||||||
|
|
||||||
implementation(Extras.kermit)
|
implementation(Extras.kermit)
|
||||||
implementation("dev.icerock.moko:parcelize:${Versions.mokoParcelize}")
|
implementation("dev.icerock.moko:parcelize:${Versions.mokoParcelize}")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0-native-mt") {
|
implementation(JetBrains.Kotlin.coroutines) {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
isForce = true
|
isForce = true
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ kotlin {
|
|||||||
}
|
}
|
||||||
named("androidMain") {
|
named("androidMain") {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("androidx.appcompat:appcompat:1.3.0")
|
implementation(Androidx.androidxActivity)
|
||||||
implementation(Androidx.core)
|
implementation(Androidx.core)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ kotlin {
|
|||||||
implementation(Serialization.json)
|
implementation(Serialization.json)
|
||||||
implementation("co.touchlab:stately-common:1.1.7")
|
implementation("co.touchlab:stately-common:1.1.7")
|
||||||
implementation("dev.icerock.moko:parcelize:${Versions.mokoParcelize}")
|
implementation("dev.icerock.moko:parcelize:${Versions.mokoParcelize}")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0-native-mt") {
|
implementation(JetBrains.Kotlin.coroutines) {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
isForce = true
|
isForce = true
|
||||||
}
|
}
|
||||||
@ -75,7 +75,7 @@ kotlin {
|
|||||||
|
|
||||||
named("androidMain") {
|
named("androidMain") {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("androidx.appcompat:appcompat:1.3.0")
|
implementation(Androidx.androidxActivity)
|
||||||
implementation(Androidx.core)
|
implementation(Androidx.core)
|
||||||
implementation(compose.runtime)
|
implementation(compose.runtime)
|
||||||
implementation(compose.material)
|
implementation(compose.material)
|
||||||
|
@ -42,6 +42,7 @@ kotlin {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation(compose.materialIconsExtended)
|
implementation(compose.materialIconsExtended)
|
||||||
implementation(Extras.mp3agic)
|
implementation(Extras.mp3agic)
|
||||||
|
implementation(Extras.Android.countly)
|
||||||
// implementation(files("$rootDir/libs/mobile-ffmpeg.aar"))
|
// implementation(files("$rootDir/libs/mobile-ffmpeg.aar"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,6 +50,7 @@ kotlin {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation(compose.materialIconsExtended)
|
implementation(compose.materialIconsExtended)
|
||||||
implementation(Extras.mp3agic)
|
implementation(Extras.mp3agic)
|
||||||
|
implementation(Extras.Desktop.countly)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jsMain {
|
jsMain {
|
||||||
|
@ -0,0 +1,71 @@
|
|||||||
|
package com.shabinder.common.di.analytics
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.Application
|
||||||
|
import ly.count.android.sdk.Countly
|
||||||
|
import ly.count.android.sdk.CountlyConfig
|
||||||
|
import ly.count.android.sdk.DeviceId
|
||||||
|
import org.koin.dsl.bind
|
||||||
|
import org.koin.dsl.module
|
||||||
|
|
||||||
|
internal class AndroidAnalyticsManager(private val mainActivity: Activity) : AnalyticsManager {
|
||||||
|
|
||||||
|
init {
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun init() {
|
||||||
|
Countly.sharedInstance().init(
|
||||||
|
CountlyConfig(
|
||||||
|
mainActivity.applicationContext as Application,
|
||||||
|
COUNTLY_CONFIG.APP_KEY,
|
||||||
|
COUNTLY_CONFIG.SERVER_URL
|
||||||
|
).apply {
|
||||||
|
setIdMode(DeviceId.Type.OPEN_UDID)
|
||||||
|
setViewTracking(true)
|
||||||
|
enableCrashReporting()
|
||||||
|
setLoggingEnabled(true)
|
||||||
|
setRecordAllThreadsWithCrash()
|
||||||
|
setRequiresConsent(true)
|
||||||
|
setShouldIgnoreAppCrawlers(true)
|
||||||
|
setEventQueueSizeToSend(5)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
Countly.sharedInstance().onStart(mainActivity)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
Countly.sharedInstance().onStop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun giveConsent() {
|
||||||
|
Countly.sharedInstance().consent().giveConsentAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isTracking(): Boolean = Countly.sharedInstance().consent().getConsent(Countly.CountlyFeatureNames.events)
|
||||||
|
|
||||||
|
override fun revokeConsent() {
|
||||||
|
Countly.sharedInstance().consent().removeConsentAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sendView(name: String, extras: Map<String, Any>) {
|
||||||
|
Countly.sharedInstance().views().recordView(name, extras)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sendEvent(eventName: String, extras: Map<String, Any>) {
|
||||||
|
Countly.sharedInstance().events().recordEvent(eventName, extras)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sendCrashReport(error: Throwable, extras: Map<String, Any>) {
|
||||||
|
Countly.sharedInstance().crashes().recordUnhandledException(error, extras)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun analyticsModule() = module {
|
||||||
|
factory { (mainActivity: Activity) ->
|
||||||
|
AndroidAnalyticsManager(mainActivity)
|
||||||
|
} bind AnalyticsManager::class
|
||||||
|
}
|
@ -20,6 +20,7 @@ import co.touchlab.kermit.Kermit
|
|||||||
import com.russhwolf.settings.Settings
|
import com.russhwolf.settings.Settings
|
||||||
import com.shabinder.common.database.databaseModule
|
import com.shabinder.common.database.databaseModule
|
||||||
import com.shabinder.common.database.getLogger
|
import com.shabinder.common.database.getLogger
|
||||||
|
import com.shabinder.common.di.analytics.analyticsModule
|
||||||
import com.shabinder.common.di.preference.PreferenceManager
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import com.shabinder.common.di.providers.providersModule
|
import com.shabinder.common.di.providers.providersModule
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
@ -39,6 +40,7 @@ fun initKoin(enableNetworkLogs: Boolean = false, appDeclaration: KoinAppDeclarat
|
|||||||
appDeclaration()
|
appDeclaration()
|
||||||
modules(
|
modules(
|
||||||
commonModule(enableNetworkLogs = enableNetworkLogs),
|
commonModule(enableNetworkLogs = enableNetworkLogs),
|
||||||
|
analyticsModule(),
|
||||||
providersModule(),
|
providersModule(),
|
||||||
databaseModule()
|
databaseModule()
|
||||||
)
|
)
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.shabinder.common.di.analytics
|
||||||
|
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
|
interface AnalyticsManager {
|
||||||
|
fun init()
|
||||||
|
fun onStart()
|
||||||
|
fun onStop()
|
||||||
|
fun giveConsent()
|
||||||
|
fun isTracking(): Boolean
|
||||||
|
fun revokeConsent()
|
||||||
|
fun sendView(name: String, extras: Map<String, Any> = emptyMap())
|
||||||
|
fun sendEvent(eventName: String, extras: Map<String, Any> = emptyMap())
|
||||||
|
fun sendCrashReport(error: Throwable, extras: Map<String, Any> = emptyMap())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("ClassName", "SpellCheckingInspection")
|
||||||
|
object COUNTLY_CONFIG {
|
||||||
|
const val APP_KEY = "27820f304468cc651ef47d787f0cb5fe11c577df"
|
||||||
|
const val SERVER_URL = "https://counlty.shabinder.in"
|
||||||
|
}
|
||||||
|
|
||||||
|
expect fun analyticsModule(): Module
|
@ -14,8 +14,8 @@ class PreferenceManager(settings: Settings) : Settings by settings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ANALYTICS */
|
/* ANALYTICS */
|
||||||
val isAnalyticsEnabled get() = getBooleanOrNull(ANALYTICS_KEY) ?: false
|
// val isAnalyticsEnabled get() = getBooleanOrNull(ANALYTICS_KEY) ?: false
|
||||||
fun toggleAnalytics(enabled: Boolean) = putBoolean(ANALYTICS_KEY, enabled)
|
// fun toggleAnalytics(enabled: Boolean) = putBoolean(ANALYTICS_KEY, enabled)
|
||||||
|
|
||||||
/* DOWNLOAD DIRECTORY */
|
/* DOWNLOAD DIRECTORY */
|
||||||
val downloadDir get() = getStringOrNull(DIR_KEY)
|
val downloadDir get() = getStringOrNull(DIR_KEY)
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
package com.shabinder.common.di.analytics
|
||||||
|
|
||||||
|
import com.shabinder.common.di.Dir
|
||||||
|
import ly.count.sdk.java.Config
|
||||||
|
import ly.count.sdk.java.Config.DeviceIdStrategy
|
||||||
|
import ly.count.sdk.java.Config.Feature
|
||||||
|
import ly.count.sdk.java.ConfigCore.LoggingLevel
|
||||||
|
import ly.count.sdk.java.Countly
|
||||||
|
import org.koin.dsl.bind
|
||||||
|
import org.koin.dsl.module
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
internal class DesktopAnalyticsManager(
|
||||||
|
private val dir: Dir
|
||||||
|
) : AnalyticsManager {
|
||||||
|
|
||||||
|
init {
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun init() {
|
||||||
|
|
||||||
|
val config: Config = Config(COUNTLY_CONFIG.SERVER_URL, COUNTLY_CONFIG.APP_KEY).apply {
|
||||||
|
eventsBufferSize = 2
|
||||||
|
loggingLevel = LoggingLevel.DEBUG
|
||||||
|
setDeviceIdStrategy(DeviceIdStrategy.UUID)
|
||||||
|
enableFeatures(*featuresSet)
|
||||||
|
setRequiresConsent(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
Countly.init(File(dir.defaultDir()), config)
|
||||||
|
|
||||||
|
Countly.session().begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun giveConsent() {
|
||||||
|
Countly.onConsent(*featuresSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isTracking(): Boolean = Countly.isTracking(Feature.Events)
|
||||||
|
|
||||||
|
override fun revokeConsent() {
|
||||||
|
Countly.onConsentRemoval(*featuresSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sendView(name: String, extras: Map<String, Any>) {
|
||||||
|
Countly.api().view(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sendEvent(eventName: String, extras: Map<String, Any>) {
|
||||||
|
Countly.api().event(eventName)
|
||||||
|
.setSegmentation(extras.filterValues { it is String } as? Map<String, String> ?: emptyMap()).record()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sendCrashReport(error: Throwable, extras: Map<String, Any>) {
|
||||||
|
Countly.api().addCrashReport(
|
||||||
|
error,
|
||||||
|
extras.getOrDefault("fatal", true) as Boolean,
|
||||||
|
error.javaClass.simpleName,
|
||||||
|
extras.filterValues { it is String } as? Map<String, String> ?: emptyMap()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val featuresSet = arrayOf(
|
||||||
|
Feature.Events,
|
||||||
|
Feature.Sessions,
|
||||||
|
Feature.CrashReporting,
|
||||||
|
Feature.Views,
|
||||||
|
Feature.UserProfiles,
|
||||||
|
Feature.Location,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {}
|
||||||
|
|
||||||
|
override fun onStop() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun analyticsModule() = module {
|
||||||
|
single { DesktopAnalyticsManager(get()) } bind AnalyticsManager::class
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.shabinder.common.di.analytics
|
||||||
|
|
||||||
|
import org.koin.dsl.bind
|
||||||
|
import org.koin.dsl.module
|
||||||
|
|
||||||
|
// TODO("Not yet implemented")
|
||||||
|
private val webAnalytics =
|
||||||
|
object : AnalyticsManager {
|
||||||
|
override fun init() {}
|
||||||
|
|
||||||
|
override fun onStart() {}
|
||||||
|
|
||||||
|
override fun onStop() {}
|
||||||
|
|
||||||
|
override fun giveConsent() {}
|
||||||
|
|
||||||
|
override fun isTracking(): Boolean = false
|
||||||
|
|
||||||
|
override fun revokeConsent() {}
|
||||||
|
|
||||||
|
override fun sendView(name: String, extras: Map<String, Any>) {}
|
||||||
|
|
||||||
|
override fun sendEvent(eventName: String, extras: Map<String, Any>) {}
|
||||||
|
|
||||||
|
override fun sendCrashReport(error: Throwable, extras: Map<String, Any>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun analyticsModule() = module {
|
||||||
|
single { webAnalytics } bind AnalyticsManager::class
|
||||||
|
}
|
@ -50,7 +50,7 @@ dependencies {
|
|||||||
implementation(Ktor.clientSerialization)
|
implementation(Ktor.clientSerialization)
|
||||||
implementation(Serialization.json)
|
implementation(Serialization.json)
|
||||||
// testDeps
|
// testDeps
|
||||||
testImplementation(kotlin("test-junit"))
|
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:1.5.21")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.test {
|
tasks.test {
|
||||||
|
@ -26,7 +26,7 @@ dependencies {
|
|||||||
implementation(Ktor.clientSerialization)
|
implementation(Ktor.clientSerialization)
|
||||||
implementation(Serialization.json)
|
implementation(Serialization.json)
|
||||||
// testDeps
|
// testDeps
|
||||||
testImplementation(kotlin("test-junit"))
|
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:1.5.21")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.test {
|
tasks.test {
|
||||||
|
@ -27,7 +27,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(kotlin("stdlib-js"))
|
implementation("org.jetbrains.kotlin:kotlin-stdlib-js:1.5.21")
|
||||||
implementation(Koin.core)
|
implementation(Koin.core)
|
||||||
implementation(Extras.kermit)
|
implementation(Extras.kermit)
|
||||||
implementation(Decompose.decompose)
|
implementation(Decompose.decompose)
|
||||||
@ -44,11 +44,11 @@ dependencies {
|
|||||||
implementation("co.touchlab:stately-common:1.1.7")
|
implementation("co.touchlab:stately-common:1.1.7")
|
||||||
implementation("dev.icerock.moko:parcelize:${Versions.mokoParcelize}")
|
implementation("dev.icerock.moko:parcelize:${Versions.mokoParcelize}")
|
||||||
// implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1")
|
// implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1") {
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.2") {
|
||||||
// https://youtrack.jetbrains.com/issue/KTOR-2670
|
// https://youtrack.jetbrains.com/issue/KTOR-2670
|
||||||
isForce = true
|
isForce = true
|
||||||
}
|
}
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0-native-mt") {
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1-native-mt") {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
isForce = true
|
isForce = true
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user