Skip to content

Commit

Permalink
feat: now playing history (#298)
Browse files Browse the repository at this point in the history
  • Loading branch information
David Ly committed Jul 15, 2023
1 parent 0cfd350 commit a376952
Show file tree
Hide file tree
Showing 29 changed files with 2,463 additions and 48 deletions.
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ dependencies {
implementation(projects.ui.collections)
implementation(projects.ui.history)
implementation(projects.ui.image)
implementation(projects.ui.nowplaying)
implementation(projects.ui.settings)
testImplementation(projects.testData)
androidTestImplementation(projects.testData)
Expand Down
23 changes: 21 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@
<application
android:name=".MusicSearchApplication"
android:allowBackup="true"
android:enableOnBackInvokedCallback="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MusicSearch">
android:theme="@style/Theme.MusicSearch"
tools:targetApi="tiramisu">

<activity
android:name="ly.david.mbjc.ui.MainActivity"
android:exported="true"
android:configChanges="colorMode|density|fontScale|fontWeightAdjustment|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode"
android:exported="true"
android:theme="@style/Theme.MusicSearch">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down Expand Up @@ -53,6 +55,23 @@

</intent-filter>
</activity>

<service
android:name=".services.NowPlayingNotificationListener"
android:exported="false"
android:label="@string/app_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>

<meta-data
android:name="android.service.notification.default_filter_types"
android:value="ongoing|silent|alerting" />
<meta-data
android:name="android.service.notification.disabled_filter_types"
android:value="conversations" />
</service>
</application>

<uses-permission android:name="android.permission.INTERNET" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package ly.david.mbjc.services

import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import ly.david.data.common.ApplicationScope
import ly.david.data.room.history.nowplaying.NowPlayingHistoryDao
import ly.david.data.room.history.nowplaying.NowPlayingHistoryRoomModel

private const val ANDROID_SYSTEM_INTELLIGENCE_PACKAGE_NAME = "com.google.android.as"
private const val ANDROID_TITLE_KEY = "android.title"

@AndroidEntryPoint
class NowPlayingNotificationListener : NotificationListenerService() {

@Inject
@ApplicationScope
lateinit var coroutineScope: CoroutineScope

@Inject
lateinit var nowPlayingHistoryDao: NowPlayingHistoryDao

override fun onNotificationPosted(sbn: StatusBarNotification?) {
super.onNotificationPosted(sbn)

// Expected format: Better Call Saul Main Title Theme (Extended) by Little Barrie
val titleAndArtist = sbn?.notification?.extras?.getString(ANDROID_TITLE_KEY) ?: return
val packageName = sbn.packageName

if (packageName == ANDROID_SYSTEM_INTELLIGENCE_PACKAGE_NAME) {
coroutineScope.launch {
nowPlayingHistoryDao.insert(
NowPlayingHistoryRoomModel(
raw = titleAndArtist,
)
)
}
}
}
}
41 changes: 23 additions & 18 deletions app/src/main/java/ly/david/mbjc/ui/navigation/NavigationGraph.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,14 @@ import ly.david.mbjc.ui.series.SeriesScaffold
import ly.david.mbjc.ui.work.WorkScaffold
import ly.david.ui.common.R
import ly.david.ui.history.HistoryScaffold
import ly.david.ui.nowplaying.NowPlayingHistoryScaffold
import ly.david.ui.settings.SettingsScaffold
import ly.david.ui.settings.licenses.LicensesScaffold

private const val ID = "id"
private const val TITLE = "title"
private const val QUERY = "query"
private const val TYPE = "type"

private fun String.encodeUtf8(): String {
return URLEncoder.encode(this, StandardCharsets.UTF_8.toString())
Expand Down Expand Up @@ -94,7 +97,9 @@ internal fun NavigationGraph(
}

val searchMusicBrainz: (String, MusicBrainzEntity) -> Unit = { query, type ->
val route = Destination.LOOKUP.route + "?query=$query&type=${type.resourceUri}"
val route = Destination.LOOKUP.route +
"?$QUERY=${query.encodeUtf8()}" +
"&$TYPE=${type.resourceUri}"
navController.navigate(route)
}

Expand All @@ -106,23 +111,23 @@ internal fun NavigationGraph(
}

composable(
route = "${Destination.LOOKUP.route}?query={query}&type={type}",
route = "${Destination.LOOKUP.route}?$QUERY={query}&$TYPE={type}",
arguments = listOf(
navArgument("query") {
navArgument(QUERY) {
type = NavType.StringType
},
navArgument("type") {
navArgument(TYPE) {
type = NavType.StringType
}
),
deepLinks = listOf(
navDeepLink {
uriPattern = "$uriPrefix${Destination.LOOKUP.route}?query={query}&type={type}"
uriPattern = "$uriPrefix${Destination.LOOKUP.route}?$QUERY={query}&$TYPE={type}"
}
)
) { entry ->
val query = entry.arguments?.getString("query")?.decodeUtf8()
val type = entry.arguments?.getString("type")?.toMusicBrainzEntity()
val query = entry.arguments?.getString(QUERY)?.decodeUtf8()
val type = entry.arguments?.getString(TYPE)?.toMusicBrainzEntity()

SearchScaffold(
modifier = modifier,
Expand Down Expand Up @@ -355,17 +360,7 @@ internal fun NavigationGraph(
}

val onSettingsClick: (Destination) -> Unit = { destination ->
when (destination) {
Destination.SETTINGS_LICENSES,
Destination.EXPERIMENTAL_SPOTIFY,
-> {
navController.goTo(destination)
}

else -> {
// Nothing.
}
}
navController.goTo(destination)
}

composable(
Expand All @@ -385,6 +380,16 @@ internal fun NavigationGraph(
)
}

composable(
Destination.SETTINGS_NOWPLAYING.route
) {
NowPlayingHistoryScaffold(
modifier = modifier,
onBack = navController::navigateUp,
searchMusicBrainz = searchMusicBrainz,
)
}

composable(
Destination.SETTINGS_LICENSES.route
) {
Expand Down
Loading

0 comments on commit a376952

Please sign in to comment.