19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/PRIVACY.md:
--------------------------------------------------------------------------------
1 | # Privacy Policy
2 |
3 | Odeon is an application I maintain on my spare time. It's not a corporate product that tries to make
4 | money using your personal data. It's goal is to be useful to its users, nothing more.
5 |
6 | The only data Odeon collects are to do its job: find, manage and play music files stored on your
7 | device's storage. Because Odeon does not interact with any remote server, any personal data used by
8 | the app is not shared with anyone else.
9 |
10 | ## Personal data that Odeon collects
11 |
12 | Here is an exhaustive list of data that Odeon collects. These data are only stored on the device and
13 | are not shared with other applications.
14 |
15 | - The list of all music files stored on the device's storage. This includes their title, artist
16 | name, album, and the date at which they were added to the device.
17 | - The number of times each file has been played. This information is used to determine which are
18 | your favorite songs.
19 |
20 | ## Notable integrations with the Android system
21 |
22 | In order to provide the best user-experience, Odeon relies on features of the Android system that
23 | may allow other apps to control playback and list available media.
24 |
25 | The Google Assistant and Android Auto are such applications. If you use one of these applications,
26 | they might collect information on your music library.
27 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /debug
3 | /staging
4 | /release
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # Uncomment this to preserve the line number information for
9 | # debugging stack traces.
10 | #-keepattributes SourceFile,LineNumberTable
11 |
12 | # If you keep the line number information, uncomment this to
13 | # hide the original source file name.
14 | #-renamesourcefileattribute SourceFile
15 |
16 | # Keep Glide definitions
17 | -keep public class * implements com.bumptech.glide.module.GlideModule
18 | -keep public class * extends com.bumptech.glide.module.AppGlideModule
19 | -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
20 | **[] $VALUES;
21 | public *;
22 | }
23 |
24 | # Suppress warnings that occur during obfuscation.
25 | -dontwarn com.google.errorprone.annotations.*
--------------------------------------------------------------------------------
/app/src/debug/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | @color/mtrl_orange_a200
20 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/fr/nihilus/music/OdeonApplication.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music
18 |
19 | import android.app.Application
20 | import android.os.StrictMode
21 | import com.google.android.material.color.DynamicColors
22 | import dagger.hilt.android.HiltAndroidApp
23 | import timber.log.Timber
24 |
25 | /**
26 | * An Android Application component that can inject dependencies into Activities and Services.
27 | * This class also performs general configuration tasks.
28 | */
29 | @HiltAndroidApp
30 | class OdeonApplication : Application() {
31 |
32 | override fun onCreate() {
33 | super.onCreate()
34 | DynamicColors.applyToActivitiesIfAvailable(this)
35 |
36 | if (BuildConfig.DEBUG) {
37 | // Print logs to Logcat
38 | Timber.plant(Timber.DebugTree())
39 | StrictMode.enableDefaults()
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/fr/nihilus/music/dagger/AppModule.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.dagger
18 |
19 | import dagger.Module
20 | import dagger.Provides
21 | import dagger.hilt.InstallIn
22 | import dagger.hilt.components.SingletonComponent
23 | import fr.nihilus.music.BuildConfig
24 | import javax.inject.Named
25 |
26 | /**
27 | * The main module for this application.
28 | * It defines dependencies that cannot be instantiated with a constructor,
29 | * such as implementations for abstract types or calls to factory methods.
30 | *
31 | * All dependencies defined here can be used in both app modules: client and service.
32 | */
33 | @Module
34 | @InstallIn(SingletonComponent::class)
35 | internal object AppModule {
36 |
37 | @Provides @Named("APP_VERSION_NAME")
38 | fun providesVersionName() = BuildConfig.VERSION_NAME
39 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/fr/nihilus/music/view/PlayPauseButton.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.view
18 |
19 | import android.content.Context
20 | import android.util.AttributeSet
21 | import androidx.appcompat.widget.AppCompatImageView
22 |
23 | /**
24 | * Extension of ImageView specialized for a play/pause button.
25 | *
26 | * The drawable displayed by this ImageView must be a LevelListDrawable with 2 levels:
27 | * - (0) is the drawable shown while playback is paused (play icon)
28 | * - (1) is the drawable shown while playing (pause icon)
29 | */
30 | class PlayPauseButton
31 | @JvmOverloads constructor(
32 | context: Context,
33 | attrs: AttributeSet? = null,
34 | defStyleAttr: Int = 0
35 | ) : AppCompatImageView(context, attrs, defStyleAttr) {
36 |
37 | /**
38 | * Whether this button should display its "playing" state.
39 | */
40 | var isPlaying: Boolean by PlayPauseDelegate()
41 | }
--------------------------------------------------------------------------------
/app/src/main/res/anim/linear_out_slow_in.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
22 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/color/activation_state_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
21 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_chevron_down_24dp.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_chevron_up_24dp.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_level_repeat.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
22 |
25 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_repeat_24dp.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_skip_next_24dp.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
24 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_skip_previous_24dp.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
24 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/level_chevron_up_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
22 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/level_play_pause.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
22 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/navigation/main_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | Pochette d\'album
20 | Activer la lecture aléatoire
21 | Play ou pause
22 | Suivant
23 | Précédent
24 | Vous ne pourrez pas lire les morceaux stockées sur votre appareil à moins que vous n\'accordiez l\'autorisation d\'y accéder.
25 | Répéter la lecture
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/values-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | 64dp
20 |
--------------------------------------------------------------------------------
/app/src/main/res/values-pl/strings.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 | Okładka albumu
19 | Włącz/wyłącz tryb losowy
20 | Odtwarzaj bądź pauzuj
21 | Przejdź do poprzedniego
22 | Przejdź do następnego
23 | Nie będziesz mógł odtwarzać utworów jeśli nie przyznasz aplikacji uprawnień do odczytu pamięci telefonu.
24 | Włącz/wyłącz tryb powtarzania
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | @color/mtrl_deep_purple_500
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 | 64dp
19 | 0dp
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 | Album art
19 | Toggle shuffle mode
20 | Play or pause
21 | Skip to previous
22 | Skip to next
23 | You won\'t be able to play tracks stored on the device\'s storage unless you grant permission to access it.
24 | Toggle repeat mode
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/web_hi_res_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/app/src/main/web_hi_res_512.png
--------------------------------------------------------------------------------
/app/src/staging/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | @color/mtrl_orange_a200
20 |
--------------------------------------------------------------------------------
/app/staging-rules.pro:
--------------------------------------------------------------------------------
1 | # Preserve the line number information for debugging stack traces.
2 | -keepattributes SourceFile,LineNumberTable
3 |
4 | # If you keep the line number information, uncomment this to
5 | # hide the original source file name.
6 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/build-logic/gradle.properties:
--------------------------------------------------------------------------------
1 | # Gradle properties are not passed to to included builds
2 | # See https://github.com/gradle/gradle/issues/2534
3 | org.gradle.caching=true
4 | org.gradle.configuration-cache=true
5 |
--------------------------------------------------------------------------------
/build-logic/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | @file:Suppress("UnstableApiUsage")
18 |
19 | rootProject.name = "build-logic"
20 |
21 | dependencyResolutionManagement {
22 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
23 | repositories {
24 | gradlePluginPortal()
25 | google()
26 | mavenCentral()
27 | }
28 | versionCatalogs {
29 | create("libs") {
30 | from(files("../gradle/libs.versions.toml"))
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/build-logic/src/main/kotlin/AndroidVersion.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | internal object AndroidVersion {
18 | const val COMPILE = 34
19 | const val TARGET = 33
20 | const val MINIMUM = 24
21 | }
22 |
--------------------------------------------------------------------------------
/build-logic/src/main/kotlin/JvmToolchain.kt:
--------------------------------------------------------------------------------
1 | import org.gradle.api.Project
2 | import org.gradle.api.plugins.JavaPluginExtension
3 | import org.gradle.jvm.toolchain.JavaLanguageVersion
4 | import org.gradle.kotlin.dsl.configure
5 |
6 | /*
7 | * Copyright 2023 Thibault Seisel
8 | *
9 | * Licensed under the Apache License, Version 2.0 (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | */
21 |
22 | internal fun Project.configureJavaToolchain() {
23 | extensions.configure {
24 | toolchain.languageVersion.set(JavaLanguageVersion.of(11))
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/core/common/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/core/common/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | plugins {
18 | id("odeon.android.library")
19 | id("odeon.android.hilt")
20 | }
21 |
22 | android {
23 | namespace = "fr.nihilus.music.core"
24 | defaultConfig {
25 | testInstrumentationRunner = "fr.nihilus.music.core.instrumentation.runner.HiltJUnitRunner"
26 | }
27 | }
28 |
29 | dependencies {
30 | implementation(libs.bundles.core)
31 | implementation(libs.androidx.lifecycle.process)
32 |
33 | testImplementation(libs.bundles.testing.unit)
34 | testImplementation(libs.androidx.lifecycle.runtime.testing)
35 |
36 | androidTestImplementation(projects.core.instrumentation)
37 | androidTestImplementation(libs.bundles.testing.instrumented)
38 | androidTestImplementation(libs.hilt.android.testing)
39 | kaptAndroidTest(libs.hilt.compiler)
40 | }
41 |
--------------------------------------------------------------------------------
/core/common/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/core/common/consumer-rules.pro
--------------------------------------------------------------------------------
/core/common/src/debug/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | Odéon Dev
20 |
--------------------------------------------------------------------------------
/core/common/src/debug/res/values/flags.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | true
20 |
--------------------------------------------------------------------------------
/core/common/src/debug/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | Odeon Dev
20 | fr.nihilus.music.debug.provider
21 |
--------------------------------------------------------------------------------
/core/common/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
19 |
20 |
21 |
25 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/core/common/src/main/kotlin/fr/nihilus/music/core/collections/ListDiff.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.collections
18 |
19 | class ListDiff(
20 | val additions: List,
21 | val deletions: List
22 | ) {
23 | operator fun component1() = additions
24 | operator fun component2() = deletions
25 | }
26 |
27 | fun diffList(
28 | original: List,
29 | modified: List,
30 | equalizer: (a: E, b: E) -> Boolean = { a, b -> a == b }
31 | ): ListDiff {
32 | val additions =
33 | modified.filter { potentiallyAdded -> original.none { equalizer(it, potentiallyAdded) } }
34 | val removals = original.filter { potentiallyRemoved ->
35 | modified.none {
36 | equalizer(
37 | it,
38 | potentiallyRemoved
39 | )
40 | }
41 | }
42 | return ListDiff(additions, removals)
43 | }
44 |
--------------------------------------------------------------------------------
/core/common/src/main/kotlin/fr/nihilus/music/core/context/AppCoroutineScope.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.context
18 |
19 | import kotlinx.coroutines.CoroutineScope
20 | import javax.inject.Qualifier
21 |
22 | /**
23 | * Qualifier for a provided [CoroutineScope] that is active for the lifetime of the whole
24 | * application.
25 | */
26 | @Qualifier
27 | @MustBeDocumented
28 | @Retention(AnnotationRetention.BINARY)
29 | @Target(AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD)
30 | annotation class AppCoroutineScope
31 |
--------------------------------------------------------------------------------
/core/common/src/main/kotlin/fr/nihilus/music/core/flow/FlowMaterialize.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.flow
18 |
19 | import kotlinx.coroutines.flow.Flow
20 | import kotlinx.coroutines.flow.catch
21 | import kotlinx.coroutines.flow.map
22 |
23 | sealed class Materialized {
24 | class Value(val value: T) : Materialized()
25 | class Error(val error: Throwable) : Materialized()
26 | }
27 |
28 | fun Flow.materialize(): Flow> = this
29 | .map> { Materialized.Value(it) }
30 | .catch { emit(Materialized.Error(it)) }
31 |
32 | fun Flow>.dematerialize(): Flow = map {
33 | when (it) {
34 | is Materialized.Value -> it.value
35 | is Materialized.Error -> throw it.error
36 | }
37 | }
--------------------------------------------------------------------------------
/core/common/src/main/kotlin/fr/nihilus/music/core/lifecycle/ApplicationLifecycle.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.lifecycle
18 |
19 | import javax.inject.Qualifier
20 |
21 | /**
22 | * Denotes that a provided value is tied to the lifecycle of the whole application.
23 | * This is currently only used to provide an instance of [androidx.lifecycle.LifecycleOwner].
24 | */
25 | @Qualifier
26 | @MustBeDocumented
27 | @Retention(AnnotationRetention.BINARY)
28 | @Target(AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD)
29 | annotation class ApplicationLifecycle
30 |
--------------------------------------------------------------------------------
/core/common/src/main/kotlin/fr/nihilus/music/core/os/Clock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.os
18 |
19 | import dagger.Reusable
20 | import javax.inject.Inject
21 |
22 | /**
23 | * A service that provides functions for reading and measuring time.
24 | */
25 | interface Clock {
26 |
27 | /**
28 | * The current Epoch Time.
29 | * This is the number of seconds that have elapsed since `00:00:00 Thursday, 1 January 1970 UTC`.
30 | */
31 | val currentEpochTime: Long
32 | }
33 |
34 | /**
35 | * Implementation of the [Clock] service that delegates to the device's system clock.
36 | */
37 | @Reusable
38 | internal class DeviceClock @Inject constructor() : Clock {
39 | override val currentEpochTime: Long
40 | get() = System.currentTimeMillis() / 1000L
41 | }
--------------------------------------------------------------------------------
/core/common/src/main/kotlin/fr/nihilus/music/core/provider/AndroidResourcesExt.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.provider
18 |
19 | import android.content.ContentResolver
20 | import android.content.res.Resources
21 | import android.net.Uri
22 | import androidx.annotation.DrawableRes
23 |
24 | /**
25 | * Retrieve the [Uri] of a given drawable resource.
26 | */
27 | fun Resources.getResourceUri(@DrawableRes drawableResId: Int): Uri = Uri.Builder()
28 | .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
29 | .authority(getResourcePackageName(drawableResId))
30 | .appendPath(getResourceTypeName(drawableResId))
31 | .appendPath(getResourceName(drawableResId))
32 | .build()
33 |
--------------------------------------------------------------------------------
/core/common/src/main/kotlin/fr/nihilus/music/core/settings/SettingsModule.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.settings
18 |
19 | import dagger.Binds
20 | import dagger.Module
21 | import dagger.hilt.InstallIn
22 | import dagger.hilt.components.SingletonComponent
23 |
24 | /**
25 | * Provides the implementation of the [Settings] store.
26 | */
27 | @Module
28 | @InstallIn(SingletonComponent::class)
29 | @Suppress("unused")
30 | abstract class SettingsModule {
31 |
32 | @Binds
33 | internal abstract fun bindsSettings(settings: SharedPreferencesSettings): Settings
34 | }
35 |
--------------------------------------------------------------------------------
/core/common/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | Odéon
20 |
--------------------------------------------------------------------------------
/core/common/src/main/res/values-v29/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 | @string/pref_theme_system_value
21 |
--------------------------------------------------------------------------------
/core/common/src/main/res/values/flags.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | false
20 |
--------------------------------------------------------------------------------
/core/common/src/main/res/values/public.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/core/common/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 | Odeon
19 | fr.nihilus.music.provider
20 |
21 |
--------------------------------------------------------------------------------
/core/compose/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/core/compose/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | plugins {
18 | id("odeon.android.library")
19 | id("odeon.android.compose")
20 | }
21 |
22 | android {
23 | namespace = "fr.nihilus.music.core.compose"
24 | }
25 |
26 | dependencies {
27 | implementation(projects.core.ui)
28 | api(libs.compose.material3)
29 | }
30 |
--------------------------------------------------------------------------------
/core/compose/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/core/compose/src/main/kotlin/fr/nihilus/music/core/compose/theme/Shapes.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.compose.theme
18 |
19 | import androidx.compose.foundation.shape.RoundedCornerShape
20 | import androidx.compose.material3.Shapes
21 | import androidx.compose.ui.unit.dp
22 |
23 | internal val OdeonShapes = Shapes(
24 | small = RoundedCornerShape(4.dp),
25 | medium = RoundedCornerShape(8.dp),
26 | large = RoundedCornerShape(16.dp)
27 | )
28 |
--------------------------------------------------------------------------------
/core/database/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/core/database/src/main/kotlin/fr/nihilus/music/core/database/playlists/PlaylistConverters.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.database.playlists
18 |
19 | import android.net.Uri
20 | import androidx.core.net.toUri
21 | import androidx.room.TypeConverter
22 |
23 | internal class PlaylistConverters {
24 |
25 | @TypeConverter
26 | fun fromString(str: String?): Uri? = str?.toUri()
27 |
28 | @TypeConverter
29 | fun toUriString(uri: Uri?): String? = uri?.toString()
30 | }
31 |
--------------------------------------------------------------------------------
/core/instrumentation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/core/instrumentation/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | plugins {
18 | id("odeon.android.library")
19 | }
20 |
21 | android {
22 | namespace = "fr.nihilus.music.core.instrumentation"
23 | useLibrary("android.test.mock")
24 | }
25 |
26 | dependencies {
27 | implementation(libs.androidx.test.runner)
28 | implementation(libs.androidx.test.rules)
29 | implementation(libs.hilt.android.testing)
30 | }
31 |
--------------------------------------------------------------------------------
/core/instrumentation/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/core/instrumentation/src/main/kotlin/fr/nihilus/music/core/instrumentation/runner/HiltJUnitRunner.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.instrumentation.runner
18 |
19 | import android.app.Application
20 | import android.content.Context
21 | import androidx.test.runner.AndroidJUnitRunner
22 | import dagger.hilt.android.testing.HiltTestApplication
23 |
24 | /**
25 | * A custom test runner that replaces the default test [Application] with [HiltTestApplication].
26 | * This is necessary so that singleton-scoped dependencies could be injected.
27 | */
28 | class HiltJUnitRunner : AndroidJUnitRunner() {
29 | override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application =
30 | super.newApplication(cl, HiltTestApplication::class.java.name, context)
31 | }
32 |
--------------------------------------------------------------------------------
/core/testing/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/core/testing/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | plugins {
18 | id("odeon.android.library")
19 | }
20 |
21 | android {
22 | namespace = "fr.nihilus.music.core.test"
23 | }
24 |
25 | dependencies {
26 | implementation(projects.core.common)
27 | implementation(libs.bundles.testing.unit)
28 | }
29 |
--------------------------------------------------------------------------------
/core/testing/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/core/testing/src/main/kotlin/fr/nihilus/music/core/test/Assertions.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.test
18 |
19 | import org.junit.AssumptionViolatedException
20 |
21 | /**
22 | * Make the current test fail.
23 | * @param message Description of the assertion that failed.
24 | */
25 | fun fail(message: String): Nothing {
26 | throw AssertionError(message)
27 | }
28 |
29 | /**
30 | * Denote that the current test is not relevant because an assumption is invalid.
31 | * @param message Description of the assumption that failed.
32 | */
33 | fun failAssumption(message: String): Nothing {
34 | throw AssumptionViolatedException(message)
35 | }
36 |
37 | /**
38 | * Replaces the body of a function that should not be called from test code.
39 | */
40 | fun stub(): Nothing = fail("Unexpected call to a stubbed method.")
--------------------------------------------------------------------------------
/core/testing/src/main/kotlin/fr/nihilus/music/core/test/coroutines/flow/Flows.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.test.coroutines.flow
18 |
19 | import kotlinx.coroutines.awaitCancellation
20 | import kotlinx.coroutines.flow.Flow
21 | import kotlinx.coroutines.flow.flow
22 |
23 | /**
24 | * Creates a flow that produces values from the specified vararg-arguments,
25 | * then suspends indefinitely after emitting all elements.
26 | *
27 | * This is useful when simulating flows that occasionally emit elements but never terminates
28 | * such as a hot stream of events.
29 | *
30 | * @param elements The elements that are immediately emitted by the resulting flow.
31 | */
32 | fun infiniteFlowOf(vararg elements: T): Flow = flow {
33 | for (element in elements) {
34 | emit(element)
35 | }
36 |
37 | awaitCancellation()
38 | }
39 |
--------------------------------------------------------------------------------
/core/testing/src/main/kotlin/fr/nihilus/music/core/test/os/TestClock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.test.os
18 |
19 | import fr.nihilus.music.core.os.Clock
20 |
21 | /**
22 | * A [Clock] implementation used for testing.
23 | * This clock is stopped: its [current time][currentEpochTime] is fixed and can only be updated manually.
24 | * For consistency reasons, you cannot go back in time.
25 | *
26 | * @param startTime The initial epoch time. Should be positive or zero.
27 | */
28 | class TestClock(startTime: Long) : Clock {
29 | init {
30 | require(startTime >= 0L) { "Invalid epoch time: $startTime" }
31 | }
32 |
33 | override var currentEpochTime: Long = startTime
34 | set(value) {
35 | require(value >= field) { "Attempt to go back in time!" }
36 | field = value
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/core/ui/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/core/ui/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | plugins {
18 | id("odeon.android.library")
19 | id("odeon.android.hilt")
20 | alias(libs.plugins.ksp)
21 | }
22 |
23 | android {
24 | namespace = "fr.nihilus.music.core.ui"
25 | buildFeatures.buildConfig = true
26 | }
27 |
28 | dependencies {
29 | implementation(projects.core.common)
30 | implementation(projects.core.database)
31 | implementation(projects.media)
32 |
33 | implementation(libs.bundles.core)
34 | implementation(libs.bundles.android.ui)
35 | implementation(libs.bundles.androidx.lifecycle)
36 | implementation(libs.androidx.media)
37 | implementation(libs.identikon)
38 |
39 | ksp(libs.glide.ksp)
40 |
41 | testImplementation(projects.core.testing)
42 | testImplementation(libs.bundles.testing.unit)
43 |
44 | androidTestImplementation(libs.bundles.testing.instrumented)
45 | }
46 |
--------------------------------------------------------------------------------
/core/ui/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/core/ui/consumer-rules.pro
--------------------------------------------------------------------------------
/core/ui/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/core/ui/src/main/kotlin/fr/nihilus/music/core/ui/actions/ExcludeTrackAction.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.ui.actions
18 |
19 | import fr.nihilus.music.core.media.MediaId
20 | import fr.nihilus.music.media.tracks.TrackRepository
21 | import javax.inject.Inject
22 |
23 | /**
24 | * An action to exclude tracks from the music library.
25 | * A track marked as excluded is no longer part of media collections.
26 | */
27 | class ExcludeTrackAction @Inject constructor(
28 | private val repository: TrackRepository,
29 | ) {
30 | suspend operator fun invoke(trackMediaId: MediaId) {
31 | val trackId = requireNotNull(trackMediaId.track) {
32 | "Attempt to exclude a media that's not a track: $trackMediaId"
33 | }
34 | repository.excludeTrack(trackId)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/core/ui/src/main/kotlin/fr/nihilus/music/core/ui/base/BaseActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.ui.base
18 |
19 | import androidx.appcompat.app.AppCompatActivity
20 |
21 | /**
22 | * Base Activity class.
23 | * Makes it easier to add common behavior to all activities.
24 | */
25 | abstract class BaseActivity : AppCompatActivity()
--------------------------------------------------------------------------------
/core/ui/src/main/kotlin/fr/nihilus/music/core/ui/base/BaseDialogFragment.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.ui.base
18 |
19 | import androidx.appcompat.app.AppCompatDialogFragment
20 |
21 | abstract class BaseDialogFragment : AppCompatDialogFragment()
--------------------------------------------------------------------------------
/core/ui/src/main/kotlin/fr/nihilus/music/core/ui/base/BaseFragment.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.ui.base
18 |
19 | import androidx.annotation.ContentView
20 | import androidx.annotation.LayoutRes
21 | import androidx.fragment.app.Fragment
22 |
23 | /**
24 | * Base Fragment class.
25 | * Makes it easier to add common behavior to all fragments.
26 | */
27 | abstract class BaseFragment : Fragment {
28 |
29 | /** No-arg Fragment constructor. */
30 | constructor() : super()
31 |
32 | /**
33 | * Alternate constructor that can be used to provide a default layout that will be inflated by [onCreateView].
34 | * @param contentLayoutId identifier of a layout resource to be inflated as this fragment's view.
35 | */
36 | @ContentView
37 | constructor(@LayoutRes contentLayoutId: Int) : super(contentLayoutId)
38 | }
--------------------------------------------------------------------------------
/core/ui/src/main/kotlin/fr/nihilus/music/core/ui/dagger/CoreUiModule.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.ui.dagger
18 |
19 | import dagger.Binds
20 | import dagger.Module
21 | import dagger.hilt.InstallIn
22 | import dagger.hilt.components.SingletonComponent
23 | import fr.nihilus.music.core.ui.client.BrowserClient
24 | import fr.nihilus.music.core.ui.client.BrowserClientImpl
25 |
26 | /**
27 | * Provides an implementation of [BrowserClient] that connects to MusicService
28 | * to read media hierarchy and send playback commands.
29 | */
30 | @Module
31 | @InstallIn(SingletonComponent::class)
32 | @Suppress("unused")
33 | abstract class CoreUiModule {
34 |
35 | @Binds
36 | internal abstract fun bindsBrowserClient(impl: BrowserClientImpl): BrowserClient
37 | }
38 |
--------------------------------------------------------------------------------
/core/ui/src/main/kotlin/fr/nihilus/music/core/ui/glide/palette/AlbumArt.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.core.ui.glide.palette
18 |
19 | import android.graphics.Bitmap
20 |
21 | data class AlbumArt(val bitmap: Bitmap, val palette: AlbumPalette)
--------------------------------------------------------------------------------
/core/ui/src/main/res/animator/card_state_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/drawable/ic_audiotrack_24dp.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
26 |
27 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/drawable/ic_play_arrow_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
24 |
25 |
29 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/drawable/ic_shuffle_24dp.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
26 |
27 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/drawable/ui_ic_arrow_back_24dp.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
24 |
27 |
28 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/drawable/ui_ic_clear_24dp.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
24 |
27 |
28 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/drawable/ui_ic_delete_24dp.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
26 |
27 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/font/quicksand.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/core/ui/src/main/res/font/quicksand.ttf
--------------------------------------------------------------------------------
/core/ui/src/main/res/font/quicksand_bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/core/ui/src/main/res/font/quicksand_bold.ttf
--------------------------------------------------------------------------------
/core/ui/src/main/res/font/quicksand_light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/core/ui/src/main/res/font/quicksand_light.ttf
--------------------------------------------------------------------------------
/core/ui/src/main/res/font/quicksand_medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/core/ui/src/main/res/font/quicksand_medium.ttf
--------------------------------------------------------------------------------
/core/ui/src/main/res/font/quicksand_semibold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/core/ui/src/main/res/font/quicksand_semibold.ttf
--------------------------------------------------------------------------------
/core/ui/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | OK
20 | Annuler
21 | Supprimer
22 | Paramètres
23 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/values-night-v29/themes.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
23 |
24 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | #1DFFFFFF
20 |
21 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/values-pl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | OK
20 | Anuluj
21 | Usuń
22 | Ustawienia
23 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/values-v29/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | @android:color/transparent
20 | @android:color/transparent
21 |
22 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/values-w600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/values/attrs_album_palette.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/values/attrs_ratioimageview.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | 8dp
20 | 8dp
21 | @dimen/grid_2
22 |
23 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/values/layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
23 | 8dp
24 | 16dp
25 | 24dp
26 | 32dp
27 |
28 |
29 | 4dp
30 | 12dp
31 |
32 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/values/motion.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | 300
20 | 225
21 | 175
22 |
23 |
--------------------------------------------------------------------------------
/core/ui/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | OK
20 | Cancel
21 | Delete
22 | Settings
23 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/200110.txt:
--------------------------------------------------------------------------------
1 | * Better user experience with tabs instead of Navigation Drawer menu.
2 | * It's now easier to find media with the new search bar. You could also ask the Google Assistant with voice commands such as "Play Daft Punk on Odeon".
3 | * Free some device space by listing and deleting songs that you may have not listened for some time.
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/200204.txt:
--------------------------------------------------------------------------------
1 | * Fix display of album artworks in the whole application on Android 10.
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/200205.txt:
--------------------------------------------------------------------------------
1 | * Polish translation (thanks to @Atrate).
2 | * Fix a bug where the shuffle mode toggle would not work.
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/200206.txt:
--------------------------------------------------------------------------------
1 | * Fix a crash when deleting tracks from search results
2 | * Fix a potential crash when updating notification with a track with no album art
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/201005.txt:
--------------------------------------------------------------------------------
1 | * Full supports for Android 10.
2 | * Odeon can now play M4A and FLAC files (the latter only on Android Oreo and newer).
3 | * App is now movable to SD card.
4 | * A more pleasant and ergonomic search screen. Result are now grouped by media category.
5 | * A lot of visual improvements for a more friendly look.
6 | * And of course a lot of bug fixes!
7 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | Odeon has all features you'd expect from a music player in a clean and simple interface:
2 |
3 |
Browse your music by title, artists and albums.
4 |
Control playback via the interface, the lock screen or headset buttons.
5 |
Create and edit playlists.
6 |
Play tracks that have been added recently or the ones you like the most.
7 |
Delete tracks you like to free-up the device's storage.
8 |
Control your music safely while driving with Android Auto.
9 |
Tell the Google Assistant what to play.
10 |
Enable Night Mode to reduce eye-strain and save your battery life.
11 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/fastlane/metadata/android/en-US/images/icon.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | Play and manage locally stored music files
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/title.txt:
--------------------------------------------------------------------------------
1 | Odeon
--------------------------------------------------------------------------------
/fastlane/metadata/android/fr-FR/changelogs/200110.txt:
--------------------------------------------------------------------------------
1 | * Passez plus rapidement des chansons aux artistes grâce à la nouvelle présentation de la page d'accueil sous forme d'onglets.
2 | * Trouvez plus rapidement votre morceau préférée grâce à la barre de recherche. Vous pouvez même demander à Google Assistant de jouer un morceau pour vous ! Dites "Joue du Daft Punk sur Odéon" !
3 | * Vous avez beaucoup de morceaux mais ne savez pas lesquels vous n'écoutez plus ? Vous pouvez désormais les trouver et les supprimer avec la nouvelle fonctionnalité "Nettoyage".
--------------------------------------------------------------------------------
/fastlane/metadata/android/fr-FR/changelogs/200204.txt:
--------------------------------------------------------------------------------
1 | * Correction d'un bug d'affichage des pochettes d'album sur Android 10.
--------------------------------------------------------------------------------
/fastlane/metadata/android/fr-FR/changelogs/200205.txt:
--------------------------------------------------------------------------------
1 | * Traduction de l'application en Polonais
2 | * On a réparé le bouton pour activer/désactiver la lecture aléatoire !
--------------------------------------------------------------------------------
/fastlane/metadata/android/fr-FR/changelogs/200206.txt:
--------------------------------------------------------------------------------
1 | * Correction d'un plantage après suppression d'un morceau depuis les résultats de recherche
2 | * Correction d'un plantage potentiel à la mise à jour de la notification avec un morceau sans pochette d'album
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/fr-FR/changelogs/201005.txt:
--------------------------------------------------------------------------------
1 | * L'application est maintenant adaptée pour Android 10.
2 | * Odeon peut maintenant lire les fichiers M4A et FLAC (sur Android Oreo et supérieur).
3 | * Possibilité de déplacer l'application sur la carte SD.
4 | * L'écran de recherche et maintenant bien plus agréable. Les résultats sont regroupés par catégorie.
5 | * De nombreuses améliorations graphiques pour un look plus décontracté.
6 | * Et bien sûr, des corrections de bug!
7 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/fr-FR/full_description.txt:
--------------------------------------------------------------------------------
1 | Odeon apporte toutes les fonctionnalités essentielles d'un lecteur musical dans une interface simple et épurée :
2 |
3 |
Listez vos morceaux par titre, artiste et album.
4 |
Contrôler la lecture via l'application, l'écran de verrouillage ou votre casque audio.
5 |
Créez vos propres listes de lecture.
6 |
Ecoutez les morceaux que vous avez ajouté recemment ou ceux que vous aimez le plus.
7 |
Supprimez les morceaux que vous n'écoutez plus pour faire de la place sur votre appareil.
8 |
Contrôlez votre musique en conduisant avec Android Auto.
9 |
Dites à l'Assistant Google ce que vous voulez jouer.
10 |
Utilisez le thème sombre pour reposer vos yeux et augmenter la durée de vie de la batterie.
11 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/fr-FR/short_description.txt:
--------------------------------------------------------------------------------
1 | Ecouter et gérer les morceaux de musique stockés sur l'appareil
--------------------------------------------------------------------------------
/fastlane/metadata/android/fr-FR/title.txt:
--------------------------------------------------------------------------------
1 | Odéon
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/images/screenshot_album_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/images/screenshot_album_detail.png
--------------------------------------------------------------------------------
/images/screenshot_albums.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/images/screenshot_albums.png
--------------------------------------------------------------------------------
/images/screenshot_home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/images/screenshot_home.png
--------------------------------------------------------------------------------
/images/screenshot_player.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/images/screenshot_player.png
--------------------------------------------------------------------------------
/lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/media/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/media/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | plugins {
18 | id("odeon.android.library")
19 | id("odeon.android.hilt")
20 | }
21 |
22 | android {
23 | namespace = "fr.nihilus.music.media"
24 | }
25 |
26 | dependencies {
27 | implementation(projects.core.common)
28 | implementation(projects.core.database)
29 | implementation(libs.bundles.core)
30 | implementation(libs.identikon)
31 |
32 | testImplementation(projects.core.testing)
33 | testImplementation(libs.bundles.testing.unit)
34 | }
35 |
--------------------------------------------------------------------------------
/media/consumer-rules.pro:
--------------------------------------------------------------------------------
1 | # Proguard rules to be included in the final application.
--------------------------------------------------------------------------------
/media/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
19 |
20 |
21 |
24 |
28 |
29 |
--------------------------------------------------------------------------------
/media/src/main/kotlin/fr/nihilus/music/media/artists/Artist.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.media.artists
18 |
19 | /**
20 | * The metadata of an artist that produced tracks that are saved on the device's storage.
21 | */
22 | data class Artist(
23 | /**
24 | * The unique identifier of this artist on the device's media storage index.
25 | */
26 | val id: Long,
27 | /**
28 | * The full name of this artist as it should be displayed to the user.
29 | */
30 | val name: String,
31 | /**
32 | * The number of album this artist as recorded.
33 | */
34 | val albumCount: Int,
35 | /**
36 | * The number of tracks that have been produced by this artist, all albums combined.
37 | */
38 | val trackCount: Int,
39 | /**
40 | * An optional Uri-formatted String pointing to an artwork representing this artist.
41 | */
42 | val iconUri: String?
43 | )
--------------------------------------------------------------------------------
/media/src/main/kotlin/fr/nihilus/music/media/dagger/MediaSourceModule.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.media.dagger
18 |
19 | import dagger.Binds
20 | import dagger.Module
21 | import dagger.hilt.InstallIn
22 | import dagger.hilt.components.SingletonComponent
23 | import fr.nihilus.music.media.browser.BrowserTree
24 | import fr.nihilus.music.media.browser.BrowserTreeImpl
25 | import fr.nihilus.music.media.usage.UsageManager
26 | import fr.nihilus.music.media.usage.UsageManagerImpl
27 |
28 | @Module
29 | @InstallIn(SingletonComponent::class)
30 | internal abstract class MediaSourceModule {
31 |
32 | @Binds
33 | abstract fun bindsBrowserTree(impl: BrowserTreeImpl): BrowserTree
34 |
35 | @Binds
36 | abstract fun bindsUsageManager(impl: UsageManagerImpl): UsageManager
37 | }
38 |
--------------------------------------------------------------------------------
/media/src/main/kotlin/fr/nihilus/music/media/provider/MediaStoreModule.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.media.provider
18 |
19 | import android.content.ContentResolver
20 | import android.content.Context
21 | import dagger.Module
22 | import dagger.Provides
23 | import dagger.hilt.InstallIn
24 | import dagger.hilt.android.qualifiers.ApplicationContext
25 | import dagger.hilt.components.SingletonComponent
26 |
27 | /**
28 | * Provides an instance of [ContentResolver].
29 | */
30 | @Module
31 | @InstallIn(SingletonComponent::class)
32 | internal object MediaStoreModule {
33 |
34 | @Provides
35 | fun providesContentResolver(
36 | @ApplicationContext context: Context
37 | ): ContentResolver = context.contentResolver
38 | }
39 |
--------------------------------------------------------------------------------
/media/src/main/kotlin/fr/nihilus/music/media/usage/DisposableTrack.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.media.usage
18 |
19 | import fr.nihilus.music.core.files.FileSize
20 |
21 | /**
22 | * Information on a track that could be deleted from the device's storage to free-up space.
23 | *
24 | * @property trackId Unique identifier of the related track.
25 | * @property title The display title of the related track.
26 | * @property fileSize The size of the file stored on the device's storage.
27 | * @property lastPlayedTime The epoch time at which that track has been played for the last time,
28 | * or `null` if it has never been played.
29 | */
30 | data class DisposableTrack(
31 | val trackId: Long,
32 | val title: String,
33 | val fileSize: FileSize,
34 | val lastPlayedTime: Long?
35 | )
36 |
--------------------------------------------------------------------------------
/media/src/main/res/drawable/svc_ic_most_rated_128dp.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
22 |
23 |
26 |
27 |
32 |
33 |
--------------------------------------------------------------------------------
/media/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | #9575cd
20 | #FFD54F
21 |
--------------------------------------------------------------------------------
/media/src/test/kotlin/fr/nihilus/music/media/browser/SamplePlaylists.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.media.browser
18 |
19 | import fr.nihilus.music.core.database.playlists.Playlist
20 | import fr.nihilus.music.core.database.playlists.PlaylistTrack
21 |
22 | internal val SAMPLE_PLAYLISTS = listOf(
23 | Playlist(1, "Zen", 1551434321, null),
24 | Playlist(2, "Sport", 1551435123, null),
25 | Playlist(3, "Metal", 1551436125, null)
26 | )
27 |
28 | internal val SAMPLE_MEMBERS = listOf(
29 | PlaylistTrack(1L, 309L),
30 | PlaylistTrack(2L, 477L),
31 | PlaylistTrack(2L, 48L),
32 | PlaylistTrack(2L, 125L),
33 | PlaylistTrack(3L, 75L),
34 | PlaylistTrack(3L, 161L)
35 | )
36 |
--------------------------------------------------------------------------------
/media/src/test/kotlin/fr/nihilus/music/media/playlists/PlaylistFixtures.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.media.playlists
18 |
19 | import androidx.core.net.toUri
20 | import fr.nihilus.music.core.database.playlists.Playlist
21 |
22 | internal val PLAYLIST_FAVORITES = Playlist(
23 | id = 1,
24 | title = "My Favorites",
25 | created = 1551434321,
26 | iconUri = "content://fr.nihilus.music.test.provider/icons/my_favorites.png".toUri()
27 | )
28 |
29 | internal val PLAYLIST_ZEN = Playlist(
30 | id = 2,
31 | title = "Zen",
32 | created = 1551435123,
33 | iconUri = null
34 | )
35 |
36 | internal val PLAYLIST_SPORT = Playlist(
37 | id = 3,
38 | title = "Sport",
39 | created = 1551436125,
40 | iconUri = null
41 | )
--------------------------------------------------------------------------------
/release/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/release/debug.keystore
--------------------------------------------------------------------------------
/service/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/service/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | plugins {
18 | id("odeon.android.library")
19 | id("odeon.android.hilt")
20 | }
21 |
22 | android {
23 | namespace = "fr.nihilus.music.service"
24 | buildFeatures.buildConfig = true
25 | }
26 |
27 | dependencies {
28 | implementation(projects.core.common)
29 | implementation(projects.core.database)
30 | implementation(projects.media)
31 |
32 | implementation(libs.bundles.core)
33 | implementation(libs.androidx.media)
34 | implementation(libs.androidx.media3.exoplayer)
35 | implementation(libs.glide)
36 |
37 | testImplementation(projects.core.testing)
38 | testImplementation(libs.bundles.testing.unit)
39 |
40 | androidTestImplementation(libs.bundles.testing.instrumented)
41 | }
42 |
--------------------------------------------------------------------------------
/service/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/service/consumer-rules.pro
--------------------------------------------------------------------------------
/service/src/main/kotlin/fr/nihilus/music/service/ServiceCoroutineScope.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.service
18 |
19 | import javax.inject.Qualifier
20 |
21 | @Qualifier
22 | @MustBeDocumented
23 | @Retention(AnnotationRetention.BINARY)
24 | @Target(AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD)
25 | annotation class ServiceCoroutineScope
26 |
--------------------------------------------------------------------------------
/service/src/main/res/drawable/svc_ic_blank_24.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
23 |
--------------------------------------------------------------------------------
/service/src/main/res/drawable/svc_ic_pause_48dp.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
26 |
27 |
--------------------------------------------------------------------------------
/service/src/main/res/drawable/svc_ic_play_arrow_48dp.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
26 |
27 |
--------------------------------------------------------------------------------
/service/src/main/res/drawable/svc_ic_skip_next_36dp.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
26 |
27 |
--------------------------------------------------------------------------------
/service/src/main/res/drawable/svc_ic_skip_previous_36dp.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
26 |
27 |
--------------------------------------------------------------------------------
/service/src/main/res/drawable/svc_notif_pause.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
24 |
25 |
28 |
29 |
--------------------------------------------------------------------------------
/service/src/main/res/drawable/svc_notif_play_arrow.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
24 |
25 |
28 |
--------------------------------------------------------------------------------
/service/src/main/res/values/untranslatable.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 | Caller has a valid certificate, but its package doesn\'t match any expected package for the
22 | given certificate. To allow this caller, add the following to the allowed callers list:\n
23 | \n\t%3$s\n\n
25 | ]]>
26 |
27 |
--------------------------------------------------------------------------------
/service/src/main/res/xml/svc_automotive_app_desc.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
18 |
19 | pluginManagement {
20 | repositories {
21 | gradlePluginPortal()
22 | google()
23 | mavenCentral()
24 | }
25 | }
26 |
27 | @Suppress("UnstableApiUsage")
28 | dependencyResolutionManagement {
29 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
30 | repositories {
31 | google()
32 | mavenCentral()
33 | }
34 | }
35 |
36 | rootProject.name = "android-odeon"
37 | includeBuild("build-logic")
38 | include(":app")
39 | include(":core:common", ":core:testing", ":core:database", ":core:ui", ":core:compose", ":core:instrumentation", ":media")
40 | include(":service")
41 | include(":ui:cleanup", ":ui:settings", ":ui:library")
42 |
--------------------------------------------------------------------------------
/ui/cleanup/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/ui/cleanup/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | plugins {
18 | id("odeon.android.library")
19 | id("odeon.android.hilt")
20 | id("odeon.android.compose")
21 | }
22 |
23 | android {
24 | namespace = "fr.nihilus.music.ui.cleanup"
25 | }
26 |
27 | dependencies {
28 | implementation(projects.core.common)
29 | implementation(projects.core.ui)
30 | implementation(projects.core.compose)
31 | implementation(projects.media)
32 |
33 | implementation(libs.bundles.core)
34 | implementation(libs.bundles.android.ui)
35 | implementation(libs.bundles.androidx.lifecycle)
36 |
37 | implementation(libs.androidx.activity.compose)
38 | implementation(libs.androidx.lifecycle.runtime.compose)
39 | implementation(libs.compose.material3)
40 | implementation(libs.compose.material.icons.core)
41 |
42 | testImplementation(projects.core.testing)
43 | testImplementation(libs.bundles.testing.unit)
44 | }
45 |
--------------------------------------------------------------------------------
/ui/cleanup/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thibseisel/android-odeon/f097bcda052665dc791bd3c26880adb0545514dc/ui/cleanup/consumer-rules.pro
--------------------------------------------------------------------------------
/ui/cleanup/sampledata/track_usage.json:
--------------------------------------------------------------------------------
1 | {
2 | "data": [
3 | {
4 | "usage_info": "Never played",
5 | "file_size": "12.76 Mo"
6 | },
7 | {
8 | "usage_info": "Last played 3 months ago",
9 | "file_size": "9.87 Mo"
10 | },
11 | {
12 | "usage_info": "Last played 2 weeks ago",
13 | "file_size": "16.34 Mo"
14 | }
15 | ]
16 | }
--------------------------------------------------------------------------------
/ui/cleanup/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ui/cleanup/src/main/kotlin/fr/nihilus/music/ui/cleanup/CleanupState.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Thibault Seisel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fr.nihilus.music.ui.cleanup
18 |
19 | import fr.nihilus.music.core.files.FileSize
20 | import fr.nihilus.music.core.media.MediaId
21 | import fr.nihilus.music.media.tracks.DeleteTracksResult
22 |
23 | internal data class CleanupState(
24 | val tracks: List