diff --git a/app/build.gradle b/app/build.gradle
index 83af00b..befdd77 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -47,8 +47,8 @@ android {
applicationId "io.musicorum.mobile"
minSdk 28
targetSdk 34
- versionCode 66
- versionName "1.21-release"
+ versionCode 67
+ versionName "1.22-release"
//compileSdkPreview = "UpsideDownCake"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 58e509b..a53e1ea 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
@@ -32,8 +35,8 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
- android:theme="@style/Theme.Musicorum"
android:testOnly="false"
+ android:theme="@style/Theme.Musicorum"
tools:targetApi="31">
+ android:theme="@style/Theme.Musicorum.SplashScreenTheme"
+ android:windowSoftInputMode="adjustResize">
diff --git a/app/src/main/java/io/musicorum/mobile/MainActivity.kt b/app/src/main/java/io/musicorum/mobile/MainActivity.kt
index 9ddfc7a..11ee40a 100644
--- a/app/src/main/java/io/musicorum/mobile/MainActivity.kt
+++ b/app/src/main/java/io/musicorum/mobile/MainActivity.kt
@@ -21,6 +21,7 @@ import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
@@ -29,7 +30,6 @@ import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.compositionLocalOf
-import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -63,11 +63,12 @@ import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import com.google.firebase.remoteconfig.ktx.remoteConfig
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
import dagger.hilt.android.AndroidEntryPoint
+import io.musicorum.mobile.datastore.ScrobblePreferences
+import io.musicorum.mobile.datastore.UserData
import io.musicorum.mobile.ktor.endpoints.UserEndpoint
import io.musicorum.mobile.models.FetchPeriod
import io.musicorum.mobile.repositories.LocalUserRepository
import io.musicorum.mobile.router.BottomNavBar
-import io.musicorum.mobile.serialization.User
import io.musicorum.mobile.ui.theme.KindaBlack
import io.musicorum.mobile.ui.theme.MusicorumMobileTheme
import io.musicorum.mobile.utils.CrowdinUtils
@@ -100,11 +101,9 @@ import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.map
import kotlinx.serialization.json.Json
-val Context.userData: DataStore by preferencesDataStore(name = "userdata")
-val Context.scrobblePrefs by preferencesDataStore(name = "scrobblePrefs")
-val LocalUser = compositionLocalOf { null }
+val Context.userData: DataStore by preferencesDataStore(UserData.DataStoreName)
+val Context.scrobblePrefs by preferencesDataStore(ScrobblePreferences.DataStoreName)
val LocalNavigation = compositionLocalOf { null }
-val MutableUserState = mutableStateOf(null)
val LocalAnalytics = compositionLocalOf { null }
@AndroidEntryPoint
@@ -130,6 +129,7 @@ class MainActivity : ComponentActivity() {
super.attachBaseContext(Crowdin.wrapContext(newBase))
}
+ @OptIn(ExperimentalMaterial3Api::class)
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
@@ -199,7 +199,9 @@ class MainActivity : ComponentActivity() {
}
if (!BuildConfig.DEBUG) {
try {
- SentryAndroid.init(this)
+ SentryAndroid.init(this) { opts ->
+ opts.isAnrEnabled
+ }
} catch (_: Exception) {
}
}
@@ -214,27 +216,25 @@ class MainActivity : ComponentActivity() {
val systemUiController = rememberSystemUiController()
if (intent?.data == null) {
- if (MutableUserState.value == null) {
- LaunchedEffect(Unit) {
- val sessionKey = ctx.applicationContext.userData.data.map { prefs ->
- prefs[stringPreferencesKey("session_key")]
- }.firstOrNull()
- if (sessionKey == null) {
- navController.navigate("login") {
- popUpTo("home") {
- inclusive = true
- }
+ LaunchedEffect(Unit) {
+ val sessionKey = ctx.applicationContext.userData.data.map { prefs ->
+ prefs[stringPreferencesKey("session_key")]
+ }.firstOrNull()
+ if (sessionKey == null) {
+ navController.navigate("login") {
+ popUpTo("home") {
+ inclusive = true
}
- } else {
+ }
+ } else {
+ val localUser = LocalUserRepository(applicationContext)
+ if (localUser.getUser().username.isEmpty()) {
val userReq = UserEndpoint.getSessionUser(sessionKey)
- val localUser = LocalUserRepository(applicationContext)
- if (localUser.getUser().username.isEmpty()) {
- localUser.create(userReq?.user)
- }
- MutableUserState.value = userReq
+ localUser.create(userReq?.user)
}
}
}
+
}
DisposableEffect(systemUiController, useDarkIcons) {
@@ -255,7 +255,6 @@ class MainActivity : ComponentActivity() {
}
CompositionLocalProvider(
- LocalUser provides MutableUserState.value,
LocalSnackbar provides LocalSnackbarContext(snackHostState),
LocalNavigation provides navController,
LocalAnalytics provides firebaseAnalytics
@@ -350,18 +349,16 @@ class MainActivity : ComponentActivity() {
}
composable("mostListened") {
- MostListened(mostListenedViewModel = mostListenedViewModel)
+ MostListened(viewModel = mostListenedViewModel)
}
composable(
- "user/{username}",
- arguments = listOf(navArgument("username") {
+ "user/{usernameArg}",
+ arguments = listOf(navArgument("usernameArg") {
type = NavType.StringType
})
) {
- User(
- username = it.arguments?.getString("username")!!
- )
+ User()
}
composable(
diff --git a/app/src/main/java/io/musicorum/mobile/database/CachedScrobblesDb.kt b/app/src/main/java/io/musicorum/mobile/database/CachedScrobblesDb.kt
index 075ff4c..3f845ff 100644
--- a/app/src/main/java/io/musicorum/mobile/database/CachedScrobblesDb.kt
+++ b/app/src/main/java/io/musicorum/mobile/database/CachedScrobblesDb.kt
@@ -4,8 +4,8 @@ import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
-import io.musicorum.mobile.database.daos.CachedScrobblesDao
import io.musicorum.mobile.models.CachedScrobble
+import io.musicorum.mobile.repositories.daos.CachedScrobblesDao
import kotlinx.coroutines.InternalCoroutinesApi
import kotlinx.coroutines.internal.synchronized
diff --git a/app/src/main/java/io/musicorum/mobile/database/PendingScrobblesDb.kt b/app/src/main/java/io/musicorum/mobile/database/PendingScrobblesDb.kt
index 1a68dda..496e278 100644
--- a/app/src/main/java/io/musicorum/mobile/database/PendingScrobblesDb.kt
+++ b/app/src/main/java/io/musicorum/mobile/database/PendingScrobblesDb.kt
@@ -4,8 +4,8 @@ import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
-import io.musicorum.mobile.database.daos.PendingScrobblesDao
import io.musicorum.mobile.models.PendingScrobble
+import io.musicorum.mobile.repositories.daos.PendingScrobblesDao
import kotlinx.coroutines.InternalCoroutinesApi
import kotlinx.coroutines.internal.synchronized
diff --git a/app/src/main/java/io/musicorum/mobile/datastore/AnalyticsConsent.kt b/app/src/main/java/io/musicorum/mobile/datastore/AnalyticsConsent.kt
new file mode 100644
index 0000000..25c7541
--- /dev/null
+++ b/app/src/main/java/io/musicorum/mobile/datastore/AnalyticsConsent.kt
@@ -0,0 +1,8 @@
+package io.musicorum.mobile.datastore
+
+import androidx.datastore.preferences.core.booleanPreferencesKey
+
+object AnalyticsConsent {
+ const val DataStoreName = "analyticsConsent"
+ val CONSENT_KEY = booleanPreferencesKey("consent")
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/musicorum/mobile/datastore/LocalUser.kt b/app/src/main/java/io/musicorum/mobile/datastore/LocalUser.kt
new file mode 100644
index 0000000..ae313ee
--- /dev/null
+++ b/app/src/main/java/io/musicorum/mobile/datastore/LocalUser.kt
@@ -0,0 +1,11 @@
+package io.musicorum.mobile.datastore
+
+import androidx.datastore.preferences.core.longPreferencesKey
+import androidx.datastore.preferences.core.stringPreferencesKey
+
+object LocalUser {
+ const val DataStoreName = "partialUser"
+ val USERNAME_KEY = stringPreferencesKey("usernameArg")
+ val PROFILE_ICON_KEY = stringPreferencesKey("profilePictureUrl")
+ val EXPIRES_IN_KEY = longPreferencesKey("expires_in")
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/musicorum/mobile/datastore/ScrobblePreferences.kt b/app/src/main/java/io/musicorum/mobile/datastore/ScrobblePreferences.kt
new file mode 100644
index 0000000..c8d8ed3
--- /dev/null
+++ b/app/src/main/java/io/musicorum/mobile/datastore/ScrobblePreferences.kt
@@ -0,0 +1,13 @@
+package io.musicorum.mobile.datastore
+
+import androidx.datastore.preferences.core.booleanPreferencesKey
+import androidx.datastore.preferences.core.floatPreferencesKey
+import androidx.datastore.preferences.core.stringSetPreferencesKey
+
+object ScrobblePreferences {
+ const val DataStoreName = "scrobblePrefs"
+ val SCROBBLE_POINT_KEY = floatPreferencesKey("scrobblePoint")
+ val ENABLED_KEY = booleanPreferencesKey("enabled")
+ val ALLOWED_APPS_KEY = stringSetPreferencesKey("enabledApps")
+ val UPDATED_NOWPLAYING_KEY = booleanPreferencesKey("updateNowPlaying")
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/musicorum/mobile/datastore/UserData.kt b/app/src/main/java/io/musicorum/mobile/datastore/UserData.kt
new file mode 100644
index 0000000..1c14cbe
--- /dev/null
+++ b/app/src/main/java/io/musicorum/mobile/datastore/UserData.kt
@@ -0,0 +1,8 @@
+package io.musicorum.mobile.datastore
+
+import androidx.datastore.preferences.core.stringPreferencesKey
+
+object UserData {
+ const val DataStoreName = "userdata"
+ val SESSION_KEY = stringPreferencesKey("session_key")
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/musicorum/mobile/ktor/endpoints/ArtistEndpoint.kt b/app/src/main/java/io/musicorum/mobile/ktor/endpoints/ArtistEndpoint.kt
index 6d9d79f..74d4548 100644
--- a/app/src/main/java/io/musicorum/mobile/ktor/endpoints/ArtistEndpoint.kt
+++ b/app/src/main/java/io/musicorum/mobile/ktor/endpoints/ArtistEndpoint.kt
@@ -17,7 +17,7 @@ object ArtistEndpoint {
parameter("method", "artist.getInfo")
parameter("name", artist)
parameter("artist", artist)
- parameter("username", username)
+ parameter("usernameArg", username)
}
return if (res.status.isSuccess()) {
return res.body()
diff --git a/app/src/main/java/io/musicorum/mobile/ktor/endpoints/TrackEndpoint.kt b/app/src/main/java/io/musicorum/mobile/ktor/endpoints/TrackEndpoint.kt
index 900c56b..d9a1fb1 100644
--- a/app/src/main/java/io/musicorum/mobile/ktor/endpoints/TrackEndpoint.kt
+++ b/app/src/main/java/io/musicorum/mobile/ktor/endpoints/TrackEndpoint.kt
@@ -27,7 +27,7 @@ object TrackEndpoint {
val autoCorrectValue = if (autoCorrect == true) 1 else 0
parameter("track", trackName)
parameter("method", "track.getInfo")
- parameter("username", username)
+ parameter("usernameArg", username)
parameter("artist", artist)
parameter("autocorrect", autoCorrectValue)
}
diff --git a/app/src/main/java/io/musicorum/mobile/ktor/endpoints/UserEndpoint.kt b/app/src/main/java/io/musicorum/mobile/ktor/endpoints/UserEndpoint.kt
index 5aa459d..ee4d07e 100644
--- a/app/src/main/java/io/musicorum/mobile/ktor/endpoints/UserEndpoint.kt
+++ b/app/src/main/java/io/musicorum/mobile/ktor/endpoints/UserEndpoint.kt
@@ -91,7 +91,7 @@ object UserEndpoint {
val result = kotlin.runCatching {
val res = KtorConfiguration.lastFmClient.get {
parameter("method", "user.getFriends")
- parameter("username", user)
+ parameter("user", user)
parameter("limit", limit)
headers.remove("Cache-Control")
}
diff --git a/app/src/main/java/io/musicorum/mobile/ktor/endpoints/musicorum/generator/Generator.kt b/app/src/main/java/io/musicorum/mobile/ktor/endpoints/musicorum/generator/Generator.kt
index 23eb696..9b0face 100644
--- a/app/src/main/java/io/musicorum/mobile/ktor/endpoints/musicorum/generator/Generator.kt
+++ b/app/src/main/java/io/musicorum/mobile/ktor/endpoints/musicorum/generator/Generator.kt
@@ -70,7 +70,7 @@ object Generator {
/**
* Generates a grid collage
- * @param username The last.fm username
+ * @param username The last.fm usernameArg
* @param rowCount Row count
* @param colCount Column count
* @param entity Entity, either artist, album or track
diff --git a/app/src/main/java/io/musicorum/mobile/repositories/CachedScrobblesRepository.kt b/app/src/main/java/io/musicorum/mobile/repositories/CachedScrobblesRepository.kt
index 6e9c874..5714928 100644
--- a/app/src/main/java/io/musicorum/mobile/repositories/CachedScrobblesRepository.kt
+++ b/app/src/main/java/io/musicorum/mobile/repositories/CachedScrobblesRepository.kt
@@ -1,7 +1,7 @@
package io.musicorum.mobile.repositories
-import io.musicorum.mobile.database.daos.CachedScrobblesDao
import io.musicorum.mobile.models.CachedScrobble
+import io.musicorum.mobile.repositories.daos.CachedScrobblesDao
class CachedScrobblesRepository(private val cachedScrobblesDao: CachedScrobblesDao) {
diff --git a/app/src/main/java/io/musicorum/mobile/repositories/IPendingScrobbles.kt b/app/src/main/java/io/musicorum/mobile/repositories/IPendingScrobbles.kt
new file mode 100644
index 0000000..feeacc5
--- /dev/null
+++ b/app/src/main/java/io/musicorum/mobile/repositories/IPendingScrobbles.kt
@@ -0,0 +1,12 @@
+package io.musicorum.mobile.repositories
+
+import io.musicorum.mobile.models.PendingScrobble
+import kotlinx.coroutines.flow.Flow
+
+interface IPendingScrobbles {
+ suspend fun getAllScrobblesStream(): Flow>
+
+ suspend fun deleteScrobble(scrobble: PendingScrobble)
+
+ suspend fun insertScrobble(scrobble: PendingScrobble)
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/musicorum/mobile/repositories/LocalUserRepository.kt b/app/src/main/java/io/musicorum/mobile/repositories/LocalUserRepository.kt
index 7e32d4a..acd5c1c 100644
--- a/app/src/main/java/io/musicorum/mobile/repositories/LocalUserRepository.kt
+++ b/app/src/main/java/io/musicorum/mobile/repositories/LocalUserRepository.kt
@@ -5,9 +5,8 @@ import android.util.Log
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
-import androidx.datastore.preferences.core.longPreferencesKey
-import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
+import io.musicorum.mobile.datastore.LocalUser
import io.musicorum.mobile.ktor.endpoints.UserEndpoint
import io.musicorum.mobile.models.PartialUser
import io.musicorum.mobile.serialization.User
@@ -22,9 +21,9 @@ val Context.localUser: DataStore by preferencesDataStore("partialUs
class LocalUserRepository(val context: Context) {
private val userFlow = context.localUser.data.map {
PartialUser(
- it[usernameKey] ?: "",
- it[pfpKey] ?: "",
- it[expiresKey] ?: 0L
+ it[LocalUser.USERNAME_KEY] ?: "",
+ it[LocalUser.PROFILE_ICON_KEY] ?: "",
+ it[LocalUser.EXPIRES_IN_KEY] ?: 0L
)
}
@@ -71,14 +70,11 @@ class LocalUserRepository(val context: Context) {
suspend fun updateUser(partialUser: PartialUser) {
context.localUser.edit {
- it[usernameKey] = partialUser.username
- it[pfpKey] = partialUser.imageUrl
- it[expiresKey] = partialUser.expiresIn
+ it[LocalUser.USERNAME_KEY] = partialUser.username
+ it[LocalUser.PROFILE_ICON_KEY] = partialUser.imageUrl
+ it[LocalUser.EXPIRES_IN_KEY] = partialUser.expiresIn
}
}
- private val usernameKey = stringPreferencesKey("username")
- private val pfpKey = stringPreferencesKey("profilePictureUrl")
- private val expiresKey = longPreferencesKey("expires_in")
private val cacheTime = Date(Date().time + (1000 * 60 * 60 * 48)).time
}
\ No newline at end of file
diff --git a/app/src/main/java/io/musicorum/mobile/repositories/OfflineScrobblesRepository.kt b/app/src/main/java/io/musicorum/mobile/repositories/OfflineScrobblesRepository.kt
deleted file mode 100644
index 9d69983..0000000
--- a/app/src/main/java/io/musicorum/mobile/repositories/OfflineScrobblesRepository.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package io.musicorum.mobile.repositories
-
-import io.musicorum.mobile.database.daos.PendingScrobblesDao
-import io.musicorum.mobile.models.PendingScrobble
-import kotlinx.coroutines.flow.Flow
-
-class OfflineScrobblesRepository(private val scrobblesDao: PendingScrobblesDao) :
- PendingScrobblesRepository {
- override suspend fun getAllScrobblesStream(): Flow> =
- scrobblesDao.getAll()
-
- override suspend fun deleteScrobble(scrobble: PendingScrobble) = scrobblesDao.delete(scrobble)
-
- override suspend fun insertScrobble(scrobble: PendingScrobble) = scrobblesDao.insert(scrobble)
-}
\ No newline at end of file
diff --git a/app/src/main/java/io/musicorum/mobile/repositories/PendingScrobblesRepository.kt b/app/src/main/java/io/musicorum/mobile/repositories/PendingScrobblesRepository.kt
index e905991..cee4181 100644
--- a/app/src/main/java/io/musicorum/mobile/repositories/PendingScrobblesRepository.kt
+++ b/app/src/main/java/io/musicorum/mobile/repositories/PendingScrobblesRepository.kt
@@ -1,12 +1,15 @@
package io.musicorum.mobile.repositories
import io.musicorum.mobile.models.PendingScrobble
+import io.musicorum.mobile.repositories.daos.PendingScrobblesDao
import kotlinx.coroutines.flow.Flow
-interface PendingScrobblesRepository {
- suspend fun getAllScrobblesStream(): Flow>
+class PendingScrobblesRepository(private val scrobblesDao: PendingScrobblesDao) :
+ IPendingScrobbles {
+ override suspend fun getAllScrobblesStream(): Flow> =
+ scrobblesDao.getAll()
- suspend fun deleteScrobble(scrobble: PendingScrobble)
+ override suspend fun deleteScrobble(scrobble: PendingScrobble) = scrobblesDao.delete(scrobble)
- suspend fun insertScrobble(scrobble: PendingScrobble)
+ override suspend fun insertScrobble(scrobble: PendingScrobble) = scrobblesDao.insert(scrobble)
}
\ No newline at end of file
diff --git a/app/src/main/java/io/musicorum/mobile/database/daos/CachedScrobblesDao.kt b/app/src/main/java/io/musicorum/mobile/repositories/daos/CachedScrobblesDao.kt
similarity index 94%
rename from app/src/main/java/io/musicorum/mobile/database/daos/CachedScrobblesDao.kt
rename to app/src/main/java/io/musicorum/mobile/repositories/daos/CachedScrobblesDao.kt
index 9b1d59a..e5fe75c 100644
--- a/app/src/main/java/io/musicorum/mobile/database/daos/CachedScrobblesDao.kt
+++ b/app/src/main/java/io/musicorum/mobile/repositories/daos/CachedScrobblesDao.kt
@@ -1,4 +1,4 @@
-package io.musicorum.mobile.database.daos
+package io.musicorum.mobile.repositories.daos
import androidx.room.Dao
import androidx.room.Delete
diff --git a/app/src/main/java/io/musicorum/mobile/database/daos/PendingScrobblesDao.kt b/app/src/main/java/io/musicorum/mobile/repositories/daos/PendingScrobblesDao.kt
similarity index 92%
rename from app/src/main/java/io/musicorum/mobile/database/daos/PendingScrobblesDao.kt
rename to app/src/main/java/io/musicorum/mobile/repositories/daos/PendingScrobblesDao.kt
index 56a5989..85df167 100644
--- a/app/src/main/java/io/musicorum/mobile/database/daos/PendingScrobblesDao.kt
+++ b/app/src/main/java/io/musicorum/mobile/repositories/daos/PendingScrobblesDao.kt
@@ -1,4 +1,4 @@
-package io.musicorum.mobile.database.daos
+package io.musicorum.mobile.repositories.daos
import androidx.room.Dao
import androidx.room.Delete
diff --git a/app/src/main/java/io/musicorum/mobile/router/BottomNavbar.kt b/app/src/main/java/io/musicorum/mobile/router/BottomNavbar.kt
index 4d4abe9..71d6b7b 100644
--- a/app/src/main/java/io/musicorum/mobile/router/BottomNavbar.kt
+++ b/app/src/main/java/io/musicorum/mobile/router/BottomNavbar.kt
@@ -3,10 +3,10 @@ package io.musicorum.mobile.router
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.rounded.QueueMusic
import androidx.compose.material.icons.rounded.BarChart
import androidx.compose.material.icons.rounded.Home
import androidx.compose.material.icons.rounded.Person
-import androidx.compose.material.icons.rounded.QueueMusic
import androidx.compose.material.icons.rounded.Search
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
@@ -31,7 +31,7 @@ fun BottomNavBar(nav: NavHostController) {
val icons = listOf(
Icons.Rounded.Home,
Icons.Rounded.Search,
- Icons.Rounded.QueueMusic,
+ Icons.AutoMirrored.Rounded.QueueMusic,
Icons.Rounded.BarChart,
Icons.Rounded.Person
)
@@ -44,12 +44,8 @@ fun BottomNavBar(nav: NavHostController) {
val navBackStackEntry by nav.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
- Box(modifier = Modifier
- .background(LighterGray)
- ) {
- NavigationBar(
- containerColor = Color.Transparent
- ) {
+ Box(modifier = Modifier.background(LighterGray)) {
+ NavigationBar(containerColor = Color.Transparent) {
items.forEachIndexed { index, s ->
NavigationBarItem(
selected = currentDestination?.hierarchy?.any { it.route?.lowercase() == s.lowercase() } == true,
diff --git a/app/src/main/java/io/musicorum/mobile/router/Controller.kt b/app/src/main/java/io/musicorum/mobile/router/Controller.kt
index b18042a..4501510 100644
--- a/app/src/main/java/io/musicorum/mobile/router/Controller.kt
+++ b/app/src/main/java/io/musicorum/mobile/router/Controller.kt
@@ -48,12 +48,12 @@ fun NavigationRouter(controller: NavHostController) {
}*/
composable(
- "user/{username}",
- arguments = listOf(navArgument("username") {
+ "user/{usernameArg}",
+ arguments = listOf(navArgument("usernameArg") {
type = NavType.StringType
})
) {
- User(username = it.arguments?.getString("username")!!)
+ User()
}
composable(
diff --git a/app/src/main/java/io/musicorum/mobile/services/NotificationListener.kt b/app/src/main/java/io/musicorum/mobile/services/NotificationListener.kt
index 12301ac..01b774a 100644
--- a/app/src/main/java/io/musicorum/mobile/services/NotificationListener.kt
+++ b/app/src/main/java/io/musicorum/mobile/services/NotificationListener.kt
@@ -22,7 +22,7 @@ import io.ktor.http.isSuccess
import io.musicorum.mobile.database.PendingScrobblesDb
import io.musicorum.mobile.ktor.endpoints.UserEndpoint
import io.musicorum.mobile.models.PendingScrobble
-import io.musicorum.mobile.repositories.OfflineScrobblesRepository
+import io.musicorum.mobile.repositories.PendingScrobblesRepository
import io.musicorum.mobile.scrobblePrefs
import io.musicorum.mobile.userData
import kotlinx.coroutines.CoroutineScope
@@ -48,12 +48,16 @@ class NotificationListener : NotificationListenerService() {
p[stringPreferencesKey("session_key")]
}.first() ?: return@launch
- val scrobbles = offlineScrobblesRepo.getAllScrobblesStream()
- val list = scrobbles.first()
- if (list.isEmpty()) {
+ if (!this@NotificationListener::offlineScrobblesRepo::isInitialized.get()) {
+ Log.w(tag, "Couldn't init offline scrobbles repo, aborting.")
+ return@launch
+ }
+
+ val scrobbles = offlineScrobblesRepo.getAllScrobblesStream().first()
+ if (scrobbles.isEmpty()) {
Log.d(tag, "no scrobbles to sync")
} else {
- for (scrobble in list) {
+ for (scrobble in scrobbles) {
val res = UserEndpoint.scrobble(
track = scrobble.trackName,
artist = scrobble.artistName,
@@ -74,7 +78,7 @@ class NotificationListener : NotificationListenerService() {
Log.d(tag, "internet connection lost")
}
}
- private lateinit var offlineScrobblesRepo: OfflineScrobblesRepository
+ private lateinit var offlineScrobblesRepo: PendingScrobblesRepository
override fun onListenerConnected() {
val networkRequest = NetworkRequest.Builder()
@@ -86,7 +90,7 @@ class NotificationListener : NotificationListenerService() {
val connectivityManager =
getSystemService(ConnectivityManager::class.java) as ConnectivityManager
connectivityManager.requestNetwork(networkRequest, networkCallback)
- offlineScrobblesRepo = OfflineScrobblesRepository(
+ offlineScrobblesRepo = PendingScrobblesRepository(
PendingScrobblesDb.getDatabase(applicationContext).pendingScrobblesDao()
)
}
diff --git a/app/src/main/java/io/musicorum/mobile/utils/HandleAuth.kt b/app/src/main/java/io/musicorum/mobile/utils/HandleAuth.kt
index 0b4a65f..6742325 100644
--- a/app/src/main/java/io/musicorum/mobile/utils/HandleAuth.kt
+++ b/app/src/main/java/io/musicorum/mobile/utils/HandleAuth.kt
@@ -1,14 +1,11 @@
package io.musicorum.mobile.utils
import android.content.Context
-import androidx.datastore.preferences.core.edit
-import androidx.datastore.preferences.core.stringPreferencesKey
import io.musicorum.mobile.ktor.endpoints.AuthEndpoint
import io.musicorum.mobile.ktor.endpoints.UserEndpoint
import io.musicorum.mobile.models.PartialUser
import io.musicorum.mobile.repositories.LocalUserRepository
import io.musicorum.mobile.serialization.User
-import io.musicorum.mobile.userData
import java.util.Date
suspend fun handleAuth(
@@ -32,10 +29,3 @@ suspend fun handleAuth(
return userBlock(user, s)
}
}
-
-suspend fun commitUser(sessionKey: String, context: Context) {
- val dataStoreKey = stringPreferencesKey("session_key")
- context.userData.edit { prefs ->
- prefs[dataStoreKey] = sessionKey
- }
-}
diff --git a/app/src/main/java/io/musicorum/mobile/utils/MessagingService.kt b/app/src/main/java/io/musicorum/mobile/utils/MessagingService.kt
index ba104ec..e10cc26 100644
--- a/app/src/main/java/io/musicorum/mobile/utils/MessagingService.kt
+++ b/app/src/main/java/io/musicorum/mobile/utils/MessagingService.kt
@@ -1,9 +1,12 @@
package io.musicorum.mobile.utils
+import android.Manifest
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
+import android.content.pm.PackageManager
import android.util.Log
+import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat.getSystemService
@@ -41,6 +44,11 @@ class MessagingService : FirebaseMessagingService() {
.build()
with(NotificationManagerCompat.from(this.applicationContext)) {
+ if (ActivityCompat.checkSelfPermission(
+ this@MessagingService.applicationContext,
+ Manifest.permission.POST_NOTIFICATIONS
+ ) != PackageManager.PERMISSION_GRANTED
+ ) return
notify(message.messageId?.toIntOrNull() ?: 0, builder)
}
}
diff --git a/app/src/main/java/io/musicorum/mobile/viewmodels/AlbumViewModel.kt b/app/src/main/java/io/musicorum/mobile/viewmodels/AlbumViewModel.kt
index 969e7c8..0348a03 100644
--- a/app/src/main/java/io/musicorum/mobile/viewmodels/AlbumViewModel.kt
+++ b/app/src/main/java/io/musicorum/mobile/viewmodels/AlbumViewModel.kt
@@ -1,23 +1,26 @@
package io.musicorum.mobile.viewmodels
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import io.musicorum.mobile.ktor.endpoints.AlbumEndpoint
import io.musicorum.mobile.ktor.endpoints.InnerAlbum
import io.musicorum.mobile.ktor.endpoints.musicorum.MusicorumArtistEndpoint
-import io.musicorum.mobile.serialization.User
+import io.musicorum.mobile.repositories.LocalUserRepository
import io.musicorum.mobile.serialization.entities.Artist
import kotlinx.coroutines.launch
-class AlbumViewModel : ViewModel() {
+class AlbumViewModel(application: Application) : AndroidViewModel(application) {
val album by lazy { MutableLiveData() }
val artistImage by lazy { MutableLiveData() }
val errored by lazy { MutableLiveData(false) }
+ val ctx = application
- fun getAlbum(albumName: String, artistName: String, user: User?) {
+ fun getAlbum(albumName: String, artistName: String) {
viewModelScope.launch {
- val res = AlbumEndpoint.getInfo(albumName, artistName, user?.user?.name)
+ val user = LocalUserRepository(ctx).getUser()
+ val res = AlbumEndpoint.getInfo(albumName, artistName, user.username)
album.value = res
if (res == null) errored.value = true
}
diff --git a/app/src/main/java/io/musicorum/mobile/viewmodels/ArtistViewModel.kt b/app/src/main/java/io/musicorum/mobile/viewmodels/ArtistViewModel.kt
index c45f61c..54ba999 100644
--- a/app/src/main/java/io/musicorum/mobile/viewmodels/ArtistViewModel.kt
+++ b/app/src/main/java/io/musicorum/mobile/viewmodels/ArtistViewModel.kt
@@ -1,25 +1,30 @@
package io.musicorum.mobile.viewmodels
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.palette.graphics.Palette
import io.musicorum.mobile.ktor.endpoints.ArtistEndpoint
import io.musicorum.mobile.ktor.endpoints.musicorum.MusicorumArtistEndpoint
+import io.musicorum.mobile.repositories.LocalUserRepository
import io.musicorum.mobile.serialization.TopAlbum
import io.musicorum.mobile.serialization.entities.Artist
import io.musicorum.mobile.serialization.entities.Track
import kotlinx.coroutines.launch
-class ArtistViewModel : ViewModel() {
+class ArtistViewModel(application: Application) : AndroidViewModel(application) {
val artist by lazy { MutableLiveData() }
val palette by lazy { MutableLiveData() }
val topTracks by lazy { MutableLiveData>() }
val topAlbums by lazy { MutableLiveData>() }
+ val ctx = application
- fun fetchArtist(artistName: String, username: String?) {
+ fun fetchArtist(artistName: String) {
viewModelScope.launch {
- val res = ArtistEndpoint.getInfo(artistName, username)
+ val user = LocalUserRepository(ctx).getUser()
+ val res = ArtistEndpoint.getInfo(artistName, user.username)
+
if (res != null) {
val artists = mutableListOf(res.artist)
artists.addAll(res.artist.similar?.artist!!)
diff --git a/app/src/main/java/io/musicorum/mobile/viewmodels/ChartsViewModel.kt b/app/src/main/java/io/musicorum/mobile/viewmodels/ChartsViewModel.kt
index 261297e..f00ed86 100644
--- a/app/src/main/java/io/musicorum/mobile/viewmodels/ChartsViewModel.kt
+++ b/app/src/main/java/io/musicorum/mobile/viewmodels/ChartsViewModel.kt
@@ -1,7 +1,6 @@
package io.musicorum.mobile.viewmodels
import android.app.Application
-import android.content.Context
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.lifecycle.AndroidViewModel
@@ -35,9 +34,10 @@ class ChartsViewModel(application: Application) : AndroidViewModel(application)
}
}
- fun getColor(image: String, ctx: Context) {
+ fun getUserColor() {
viewModelScope.launch {
- val bmp = getBitmap(image, ctx)
+ val user = LocalUserRepository(_application).getUser()
+ val bmp = getBitmap(user.imageUrl, _application)
val palette = createPalette(bmp)
if (palette.vibrantSwatch == null) {
preferredColor.value = Color(palette.getDominantColor(Color.Gray.toArgb()))
@@ -93,4 +93,8 @@ class ChartsViewModel(application: Application) : AndroidViewModel(application)
fetchAll(user.username)
}
}
+
+ init {
+ getUserColor()
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/io/musicorum/mobile/viewmodels/CollageViewModel.kt b/app/src/main/java/io/musicorum/mobile/viewmodels/CollageViewModel.kt
index be36fe1..9b436b9 100644
--- a/app/src/main/java/io/musicorum/mobile/viewmodels/CollageViewModel.kt
+++ b/app/src/main/java/io/musicorum/mobile/viewmodels/CollageViewModel.kt
@@ -1,12 +1,16 @@
package io.musicorum.mobile.viewmodels
+import android.Manifest
import android.app.Application
import android.app.DownloadManager
import android.content.Context
import android.content.Intent
+import android.content.pm.PackageManager
import android.net.Uri
+import android.os.Build
import android.os.Environment
import android.widget.Toast
+import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
@@ -99,9 +103,20 @@ class CollageViewModel(application: Application) : AndroidViewModel(application)
}
}
- fun downloadFile() {
+ fun downloadFile(): Boolean {
val manager = ctx.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
- val uri = imageUrl.value ?: return
+ val uri = imageUrl.value ?: return false
+
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
+ if (ContextCompat.checkSelfPermission(
+ ctx,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE
+ ) == PackageManager.PERMISSION_DENIED
+ ) {
+ return false
+ }
+ }
+
Toast.makeText(ctx, ctx.getString(R.string.starting_download), Toast.LENGTH_SHORT).show()
val request = DownloadManager.Request(Uri.parse(uri))
@@ -111,6 +126,7 @@ class CollageViewModel(application: Application) : AndroidViewModel(application)
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
manager.enqueue(request)
+ return true
}
fun shareFile() {
diff --git a/app/src/main/java/io/musicorum/mobile/viewmodels/HomeViewModel.kt b/app/src/main/java/io/musicorum/mobile/viewmodels/HomeViewModel.kt
index 5aebf32..44686a4 100644
--- a/app/src/main/java/io/musicorum/mobile/viewmodels/HomeViewModel.kt
+++ b/app/src/main/java/io/musicorum/mobile/viewmodels/HomeViewModel.kt
@@ -9,6 +9,8 @@ import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import androidx.palette.graphics.Palette
+import com.google.firebase.crashlytics.ktx.crashlytics
+import com.google.firebase.ktx.Firebase
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import dagger.hilt.android.lifecycle.HiltViewModel
import io.musicorum.mobile.database.CachedScrobblesDb
@@ -20,7 +22,7 @@ import io.musicorum.mobile.models.FetchPeriod
import io.musicorum.mobile.models.PartialUser
import io.musicorum.mobile.repositories.CachedScrobblesRepository
import io.musicorum.mobile.repositories.LocalUserRepository
-import io.musicorum.mobile.repositories.OfflineScrobblesRepository
+import io.musicorum.mobile.repositories.PendingScrobblesRepository
import io.musicorum.mobile.repositories.ScrobbleRepository
import io.musicorum.mobile.serialization.Image
import io.musicorum.mobile.serialization.RecentTracks
@@ -57,6 +59,7 @@ class HomeViewModel @Inject constructor(
val showRewindCard = MutableLiveData(false)
val rewindCardMessage = MutableLiveData("")
private val remoteConfig = FirebaseRemoteConfig.getInstance()
+ val showSettingsBadge = MutableLiveData(false)
fun refresh() {
@@ -109,7 +112,7 @@ class HomeViewModel @Inject constructor(
}
if (res.exceptionOrNull() is UnknownHostException) {
val pendingDao = PendingScrobblesDb.getDatabase(ctx).pendingScrobblesDao()
- val pendingRepo = OfflineScrobblesRepository(pendingDao)
+ val pendingRepo = PendingScrobblesRepository(pendingDao)
val pendingScrobbles = pendingRepo.getAllScrobblesStream().first()
isOffline.value = true
val list = mutableListOf