+
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id('com.android.application')
id('kotlin-android')
id('kotlin-kapt')
id('dagger.hilt.android.plugin')
id('org.jlleitschuh.gradle.ktlint')
}

Expand Down Expand Up @@ -105,6 +106,11 @@ dependencies {
// AndroidX Compose SwipeRefresh
implementation "com.google.accompanist:accompanist-swiperefresh:0.14.0"

// AndroidX Hilt (dependency injection)
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-compiler:$hilt_version"
implementation "androidx.hilt:hilt-navigation-compose:1.0.0-alpha03"

// Coil (image loading)
implementation("io.coil-kt:coil:$coil_version")
implementation("io.coil-kt:coil-compose:$coil_version")
Expand Down
6 changes: 5 additions & 1 deletion app/src/main/java/me/vanpetegem/accentor/Accentor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@ import coil.ImageLoaderFactory
import coil.decode.GifDecoder
import coil.decode.ImageDecoderDecoder
import com.github.kittinunf.fuel.core.FuelManager
import dagger.hilt.android.HiltAndroidApp
import java.io.File
import javax.inject.Inject
import me.vanpetegem.accentor.data.preferences.PreferencesDataSource
import okhttp3.Cache
import okhttp3.OkHttpClient

@HiltAndroidApp
class Accentor : Application(), ImageLoaderFactory {
@Inject lateinit var preferences: PreferencesDataSource

override fun onCreate() {
super.onCreate()
version = applicationContext.packageManager.getPackageInfo(packageName, 0).versionName
Expand All @@ -21,7 +26,6 @@ class Accentor : Application(), ImageLoaderFactory {
}

override fun newImageLoader(): ImageLoader {
val preferences = PreferencesDataSource(applicationContext)
return ImageLoader.Builder(applicationContext)
.okHttpClient {
OkHttpClient.Builder()
Expand Down
292 changes: 151 additions & 141 deletions app/src/main/java/me/vanpetegem/accentor/data/AccentorDatabase.kt

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ package me.vanpetegem.accentor.data.albums
import android.util.SparseArray
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations.map
import dagger.Reusable
import java.time.LocalDate
import javax.inject.Inject
import me.vanpetegem.accentor.api.album.index
import me.vanpetegem.accentor.data.authentication.AuthenticationRepository
import me.vanpetegem.accentor.util.Result

class AlbumRepository(
@Reusable
class AlbumRepository @Inject constructor(
private val albumDao: AlbumDao,
private val authenticationRepository: AuthenticationRepository
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ package me.vanpetegem.accentor.data.artists
import android.util.SparseArray
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations.map
import dagger.Reusable
import javax.inject.Inject
import me.vanpetegem.accentor.api.artist.index
import me.vanpetegem.accentor.data.authentication.AuthenticationRepository
import me.vanpetegem.accentor.util.Result

class ArtistRepository(
@Reusable
class ArtistRepository @Inject constructor(
private val artistDao: ArtistDao,
private val authenticationRepository: AuthenticationRepository
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import android.content.Context
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.Observer
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import me.vanpetegem.accentor.util.intLiveData
import me.vanpetegem.accentor.util.stringLiveData

Expand All @@ -13,7 +15,7 @@ const val USER_ID_KEY = "user_id"
const val DEVICE_ID_KEY = "device_id"
const val SECRET_KEY = "secret"

class AuthenticationDataSource(context: Context) {
class AuthenticationDataSource @Inject constructor(@ApplicationContext context: Context) {
private val sharedPreferences =
context.getSharedPreferences("me.vanpetegem.accentor.authenticationData", Context.MODE_PRIVATE)

Expand Down Expand Up @@ -62,6 +64,8 @@ class AuthenticationDataSource(context: Context) {
addSource(userIdData, observer)
addSource(deviceIdData, observer)
addSource(secretData, observer)
// If we don't do this, the value will start out as null even if we have data in the prefs.
observer.onChanged(null)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ package me.vanpetegem.accentor.data.authentication

import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import javax.inject.Inject
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.withContext
import me.vanpetegem.accentor.api.auth.create
import me.vanpetegem.accentor.api.auth.destroy
import me.vanpetegem.accentor.util.Result

class AuthenticationRepository(
class AuthenticationRepository @Inject constructor(
private val prefsSource: AuthenticationDataSource
) {
val authData: LiveData<AuthenticationData> = prefsSource.authData
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package me.vanpetegem.accentor.data.codecconversions
import android.util.SparseArray
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations.map
import javax.inject.Inject
import me.vanpetegem.accentor.api.codecconversion.index
import me.vanpetegem.accentor.data.authentication.AuthenticationRepository
import me.vanpetegem.accentor.util.Result

class CodecConversionRepository(
class CodecConversionRepository @Inject constructor(
private val codecConversionDao: CodecConversionDao,
private val authenticationRepository: AuthenticationRepository
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ package me.vanpetegem.accentor.data.preferences

import android.content.Context
import androidx.lifecycle.LiveData
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import me.vanpetegem.accentor.util.intLiveData
import me.vanpetegem.accentor.util.longLiveData

const val CONVERSION_ID_KEY = "conversion_id"
const val IMAGE_CACHE_SIZE_KEY = "image_cache_size"
const val MUSIC_CACHE_SIZE_KEY = "music_cache_size"

class PreferencesDataSource(context: Context) {
class PreferencesDataSource @Inject constructor(@ApplicationContext private val context: Context) {
private val sharedPreferences = context.getSharedPreferences("me.vanpetegem.accentor.preferences", Context.MODE_PRIVATE)

private val conversionIdData = sharedPreferences.intLiveData(CONVERSION_ID_KEY)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package me.vanpetegem.accentor.data.tracks

import androidx.lifecycle.LiveData
import dagger.Reusable
import javax.inject.Inject
import me.vanpetegem.accentor.api.track.index
import me.vanpetegem.accentor.data.albums.Album
import me.vanpetegem.accentor.data.artists.Artist
import me.vanpetegem.accentor.data.authentication.AuthenticationRepository
import me.vanpetegem.accentor.util.Result

class TrackRepository(
@Reusable
class TrackRepository @Inject constructor(
private val trackDao: TrackDao,
private val authenticationRepository: AuthenticationRepository
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import android.util.SparseArray
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations.map
import androidx.lifecycle.Transformations.switchMap
import javax.inject.Inject
import me.vanpetegem.accentor.api.user.index
import me.vanpetegem.accentor.data.authentication.AuthenticationRepository
import me.vanpetegem.accentor.util.Result

class UserRepository(
class UserRepository @Inject constructor(
private val userDao: UserDao,
private val authenticationRepository: AuthenticationRepository
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,20 @@ import androidx.media2.session.MediaController
import androidx.media2.session.SessionCommand
import androidx.media2.session.SessionCommandGroup
import androidx.media2.session.SessionToken
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.guava.await
import me.vanpetegem.accentor.data.AccentorDatabase
import me.vanpetegem.accentor.data.albums.Album
import me.vanpetegem.accentor.data.albums.AlbumRepository
import me.vanpetegem.accentor.data.authentication.AuthenticationDataSource
import me.vanpetegem.accentor.data.authentication.AuthenticationRepository
import me.vanpetegem.accentor.data.tracks.Track
import me.vanpetegem.accentor.data.tracks.TrackRepository

class MediaSessionConnection(application: Application) : AndroidViewModel(application) {

private val authenticationDataSource = AuthenticationDataSource(application)

@HiltViewModel
class MediaSessionConnection @Inject constructor(
application: Application,
private val albumRepository: AlbumRepository,
private val trackRepository: TrackRepository,
) : AndroidViewModel(application) {
private val mediaController: MediaController = MediaController.Builder(application)
.setSessionToken(SessionToken(application, ComponentName(application, MusicService::class.java)))
.setControllerCallback(
Expand Down Expand Up @@ -127,7 +128,19 @@ class MediaSessionConnection(application: Application) : AndroidViewModel(applic

private val _queue = MutableLiveData<List<MediaItem>>().apply { postValue(ArrayList()) }
private val _queueIds: LiveData<List<Int>> = map(_queue) { it.map { item -> item.metadata?.mediaId!!.toInt() } }
val queue: LiveData<List<Triple<Boolean, Track?, Album?>>>
val queue: LiveData<List<Triple<Boolean, Track?, Album?>>> = switchMap(_queueIds) { q ->
switchMap(queuePosition) { qPos ->
switchMap(trackRepository.findByIds(q)) { tracks ->
map(albumRepository.findByIds(tracks.map { it.albumId })) { albums ->
q.mapIndexed { pos, id ->
val track = tracks.find { it.id == id }
val album = albums.find { it.id == track?.albumId }
Triple(qPos == pos + 1, track, album)
}
}
}
}
}

val _queuePosition: MutableLiveData<Int> = MutableLiveData<Int>().apply {
postValue(0)
Expand All @@ -141,30 +154,6 @@ class MediaSessionConnection(application: Application) : AndroidViewModel(applic
}
}

private val albumRepository: AlbumRepository
private val trackRepository: TrackRepository

init {
val database = AccentorDatabase.getDatabase(application)
val trackDao = database.trackDao()
val albumDao = database.albumDao()
albumRepository = AlbumRepository(albumDao, AuthenticationRepository(authenticationDataSource))
trackRepository = TrackRepository(trackDao, AuthenticationRepository(authenticationDataSource))
queue = switchMap(_queueIds) { q ->
switchMap(queuePosition) { qPos ->
switchMap(trackRepository.findByIds(q)) { tracks ->
map(albumRepository.findByIds(tracks.map { it.albumId })) { albums ->
q.mapIndexed { pos, id ->
val track = tracks.find { it.id == id }
val album = albums.find { it.id == track?.albumId }
Triple(qPos == pos + 1, track, album)
}
}
}
}
}
}

suspend fun stop() = mediaController.sendCustomCommand(SessionCommand("STOP", null), null).await()

suspend fun play(tracks: List<Pair<Track, Album>>) {
Expand Down
21 changes: 10 additions & 11 deletions app/src/main/java/me/vanpetegem/accentor/media/MusicService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,33 @@ import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
import com.google.android.exoplayer2.upstream.cache.CacheDataSource
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor
import com.google.android.exoplayer2.upstream.cache.SimpleCache
import dagger.hilt.android.AndroidEntryPoint
import java.io.File
import java.util.concurrent.Executors
import javax.inject.Inject
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import me.vanpetegem.accentor.R
import me.vanpetegem.accentor.data.AccentorDatabase
import me.vanpetegem.accentor.data.albums.Album
import me.vanpetegem.accentor.data.albums.AlbumDao
import me.vanpetegem.accentor.data.authentication.AuthenticationDataSource
import me.vanpetegem.accentor.data.codecconversions.CodecConversionDao
import me.vanpetegem.accentor.data.preferences.PreferencesDataSource
import me.vanpetegem.accentor.data.tracks.Track
import me.vanpetegem.accentor.data.tracks.TrackDao
import me.vanpetegem.accentor.userAgent

@AndroidEntryPoint
class MusicService : MediaSessionService() {
private val mainScope = MainScope()

private lateinit var authenticationDataSource: AuthenticationDataSource
private lateinit var preferencesDataSource: PreferencesDataSource
private lateinit var codecConversionDao: CodecConversionDao
@Inject lateinit var authenticationDataSource: AuthenticationDataSource
@Inject lateinit var preferencesDataSource: PreferencesDataSource
@Inject lateinit var codecConversionDao: CodecConversionDao
@Inject lateinit var trackDao: TrackDao
@Inject lateinit var albumDao: AlbumDao

private lateinit var notificationManager: NotificationManagerCompat
private lateinit var notificationBuilder: NotificationBuilder
Expand Down Expand Up @@ -95,13 +101,6 @@ class MusicService : MediaSessionService() {
override fun onCreate() {
super.onCreate()

authenticationDataSource = AuthenticationDataSource(application)
preferencesDataSource = PreferencesDataSource(application)
val database = AccentorDatabase.getDatabase(application)
val trackDao = database.trackDao()
val albumDao = database.albumDao()
codecConversionDao = database.codecConversionDao()

sessionPlayerConnector = SessionPlayerConnector(exoPlayer)
sessionCallback = SessionCallbackBuilder(baseContext, sessionPlayerConnector).setMediaItemProvider(
object : SessionCallbackBuilder.MediaItemProvider {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import coil.compose.rememberImagePainter
import kotlinx.coroutines.Dispatchers.IO
Expand All @@ -45,7 +45,7 @@ import me.vanpetegem.accentor.data.albums.Album
import me.vanpetegem.accentor.media.MediaSessionConnection

@Composable
public fun AlbumCard(album: Album, navController: NavController, hideArtist: Int? = null, mediaSessionConnection: MediaSessionConnection = viewModel()) {
public fun AlbumCard(album: Album, navController: NavController, hideArtist: Int? = null, mediaSessionConnection: MediaSessionConnection = hiltViewModel()) {
val scope = rememberCoroutineScope()
Card(modifier = Modifier.padding(8.dp).clickable { navController.navigate("albums/${album.id}") }) {
Column {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ package me.vanpetegem.accentor.ui.albums
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import me.vanpetegem.accentor.ui.util.FastScrollableGrid

@Composable
fun AlbumGrid(navController: NavController, albumsViewModel: AlbumsViewModel = viewModel()) {
fun AlbumGrid(navController: NavController, albumsViewModel: AlbumsViewModel = hiltViewModel()) {
val albums by albumsViewModel.allAlbums.observeAsState()
if (albums != null) {
FastScrollableGrid(albums!!, { it.firstCharacter().uppercase() }) { album -> AlbumCard(album, navController) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import coil.compose.rememberImagePainter
import java.time.LocalDate
Expand All @@ -41,8 +41,8 @@ import me.vanpetegem.accentor.ui.tracks.TrackRow
fun AlbumView(
id: Int,
navController: NavController,
albumViewModel: AlbumViewModel = viewModel(),
mediaSessionConnection: MediaSessionConnection = viewModel()
albumViewModel: AlbumViewModel = hiltViewModel(),
mediaSessionConnection: MediaSessionConnection = hiltViewModel()
) {
val scope = rememberCoroutineScope()
val albumState by albumViewModel.getAlbum(id).observeAsState()
Expand Down Expand Up @@ -106,7 +106,7 @@ fun AlbumView(
}

@Composable
fun AlbumViewDropdown(id: Int, navController: NavController, dismiss: (() -> Unit), albumViewModel: AlbumViewModel = viewModel()) {
fun AlbumViewDropdown(id: Int, navController: NavController, dismiss: (() -> Unit), albumViewModel: AlbumViewModel = hiltViewModel()) {
val albumState by albumViewModel.getAlbum(id).observeAsState()
if (albumState != null) {
val album = albumState!!
Expand Down
Loading
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载