mirror of
https://github.com/emptyynes/EmptyPlayer.git
synced 2025-01-22 08:22:26 +03:00
kinda works
This commit is contained in:
parent
fdfb0aa679
commit
b78a1cb407
8 changed files with 95 additions and 65 deletions
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="KotlinJpsPluginSettings">
|
<component name="KotlinJpsPluginSettings">
|
||||||
<option name="version" value="1.9.0" />
|
<option name="version" value="2.0.20" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
|
@ -1,6 +1,8 @@
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android.application)
|
alias(libs.plugins.android.application)
|
||||||
alias(libs.plugins.kotlin.android)
|
alias(libs.plugins.kotlin.android)
|
||||||
|
alias(libs.plugins.compose.compiler)
|
||||||
|
id("org.jetbrains.kotlin.plugin.serialization") version "2.0.20"
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
@ -10,7 +12,7 @@ android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "usr.empty.player"
|
applicationId = "usr.empty.player"
|
||||||
minSdk = 34
|
minSdk = 34
|
||||||
targetSdk = 34
|
targetSdk = 35
|
||||||
versionCode = 1
|
versionCode = 1
|
||||||
versionName = "0.0.1α"
|
versionName = "0.0.1α"
|
||||||
|
|
||||||
|
@ -63,11 +65,6 @@ dependencies {
|
||||||
implementation(libs.androidx.media3.common)
|
implementation(libs.androidx.media3.common)
|
||||||
implementation(libs.androidx.media3.session)
|
implementation(libs.androidx.media3.session)
|
||||||
|
|
||||||
androidTestImplementation(libs.androidx.junit)
|
|
||||||
androidTestImplementation(libs.androidx.espresso.core)
|
|
||||||
androidTestImplementation(platform(libs.androidx.compose.bom))
|
|
||||||
androidTestImplementation(libs.androidx.ui.test.junit4)
|
|
||||||
|
|
||||||
debugImplementation(libs.androidx.ui.tooling)
|
debugImplementation(libs.androidx.ui.tooling)
|
||||||
debugImplementation(libs.androidx.ui.test.manifest)
|
debugImplementation(libs.androidx.ui.test.manifest)
|
||||||
}
|
}
|
|
@ -6,15 +6,17 @@ import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.util.Log
|
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
@ -26,12 +28,14 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.mutableStateListOf
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.RectangleShape
|
import androidx.compose.ui.graphics.RectangleShape
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import usr.empty.player.ui.theme.PlayerTheme
|
import usr.empty.player.ui.theme.PlayerTheme
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,6 +76,7 @@ fun uriToPath(uri: Uri): String {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MainLayout(modifier: Modifier = Modifier) {
|
fun MainLayout(modifier: Modifier = Modifier) {
|
||||||
|
val context = LocalContext.current
|
||||||
val notas = remember { mutableStateListOf<NotaDescriptor>() }
|
val notas = remember { mutableStateListOf<NotaDescriptor>() }
|
||||||
|
|
||||||
val pickAudioLauncher = rememberLauncherForActivityResult(
|
val pickAudioLauncher = rememberLauncherForActivityResult(
|
||||||
|
@ -92,26 +97,59 @@ fun MainLayout(modifier: Modifier = Modifier) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(modifier.fillMaxSize()) {
|
Column(modifier.fillMaxSize()) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.Absolute.SpaceEvenly,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
) {
|
||||||
Button(shape = RectangleShape, colors = ButtonDefaults.buttonColors(
|
Button(shape = RectangleShape, colors = ButtonDefaults.buttonColors(
|
||||||
containerColor = MaterialTheme.colorScheme.secondaryContainer, contentColor = MaterialTheme.colorScheme.secondary
|
containerColor = MaterialTheme.colorScheme.secondaryContainer, contentColor = MaterialTheme.colorScheme.secondary
|
||||||
), modifier = Modifier.align(Alignment.CenterHorizontally), onClick = {
|
), modifier = Modifier, onClick = {
|
||||||
pickAudioLauncher.launch("audio/*")
|
pickAudioLauncher.launch("audio/*")
|
||||||
}) {
|
}) {
|
||||||
Text("add track")
|
Text("add track")
|
||||||
}
|
}
|
||||||
|
// VerticalDivider()
|
||||||
|
Button(shape = RectangleShape, colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.secondaryContainer, contentColor = MaterialTheme.colorScheme.secondary
|
||||||
|
), modifier = Modifier, onClick = {
|
||||||
|
context.startService(Intent(context, PlayerService::class.java).apply {
|
||||||
|
putExtra("check", "empty")
|
||||||
|
putExtra("type", "pause")
|
||||||
|
})
|
||||||
|
}) {
|
||||||
|
Text("| pause |")
|
||||||
|
}
|
||||||
|
Button(shape = RectangleShape, colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.secondaryContainer, contentColor = MaterialTheme.colorScheme.secondary
|
||||||
|
), modifier = Modifier, onClick = {
|
||||||
|
context.startService(Intent(context, PlayerService::class.java).apply {
|
||||||
|
putExtra("check", "empty")
|
||||||
|
putExtra("type", "play")
|
||||||
|
})
|
||||||
|
}) {
|
||||||
|
Text("| play >")
|
||||||
|
}
|
||||||
|
}
|
||||||
NotaList(notas)
|
NotaList(notas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NotaList(notas: List<NotaDescriptor>, modifier: Modifier = Modifier) {
|
fun NotaList(notas: List<NotaDescriptor>, modifier: Modifier = Modifier) {
|
||||||
|
val context = LocalContext.current
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
) {
|
) {
|
||||||
items(notas) { nota ->
|
items(notas) { nota ->
|
||||||
Column(modifier = Modifier
|
Column(modifier = Modifier
|
||||||
.fillParentMaxWidth()
|
.fillParentMaxWidth()
|
||||||
.clickable { }
|
.clickable {
|
||||||
|
context.startService(Intent(context, PlayerService::class.java).apply {
|
||||||
|
putExtra("check", "empty")
|
||||||
|
putExtra("type", "nota")
|
||||||
|
putExtra("nota", Json.encodeToString(nota))
|
||||||
|
})
|
||||||
|
}
|
||||||
.padding(4.dp)
|
.padding(4.dp)
|
||||||
.padding(start = 16.dp)) {
|
.padding(start = 16.dp)) {
|
||||||
Text(
|
Text(
|
||||||
|
@ -121,7 +159,6 @@ fun NotaList(notas: List<NotaDescriptor>, modifier: Modifier = Modifier) {
|
||||||
nota.artist, fontSize = 12.sp
|
nota.artist, fontSize = 12.sp
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Log.d("nya", nota.toString())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
13
app/src/main/java/usr/empty/player/Nota.kt
Normal file
13
app/src/main/java/usr/empty/player/Nota.kt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package usr.empty.player
|
||||||
|
|
||||||
|
import androidx.media3.common.MediaItem
|
||||||
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
|
|
||||||
|
|
||||||
|
class Nota(val descriptor: NotaDescriptor) {
|
||||||
|
val mediaSource = MediaItem.fromUri(descriptor.source)
|
||||||
|
|
||||||
|
fun prepare(player: ExoPlayer) {
|
||||||
|
player.setMediaItem(mediaSource)
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,11 +8,14 @@ import androidx.media3.session.MediaSession
|
||||||
import androidx.media3.session.MediaSessionService
|
import androidx.media3.session.MediaSessionService
|
||||||
import com.google.common.util.concurrent.Futures
|
import com.google.common.util.concurrent.Futures
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import java.util.concurrent.ConcurrentLinkedDeque
|
||||||
|
|
||||||
|
|
||||||
class PlayerService : MediaSessionService() {
|
class PlayerService : MediaSessionService() {
|
||||||
private var mediaSession: MediaSession? = null
|
private lateinit var mediaSession: MediaSession
|
||||||
var player: ExoPlayer? = null
|
lateinit var player: ExoPlayer
|
||||||
|
private var virtualQueue = ConcurrentLinkedDeque<Nota>()
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
@ -20,26 +23,35 @@ class PlayerService : MediaSessionService() {
|
||||||
player = this
|
player = this
|
||||||
mediaSession = MediaSession.Builder(this@PlayerService, this).setCallback(MediaSessionCallback()).build()
|
mediaSession = MediaSession.Builder(this@PlayerService, this).setCallback(MediaSessionCallback()).build()
|
||||||
}
|
}
|
||||||
Log.d("meow", "memememe")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
Log.d("nya", "start!!!")
|
||||||
intent?.run {
|
intent?.run {
|
||||||
|
if (getStringExtra("check") != "empty") return@run
|
||||||
|
handleCommand(getStringExtra("type")!!, this)
|
||||||
}
|
}
|
||||||
return super.onStartCommand(intent, flags, startId)
|
return super.onStartCommand(intent, flags, startId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun start() {
|
private fun handleCommand(type: String, intent: Intent) {
|
||||||
|
when (type) {
|
||||||
|
"nota" -> {
|
||||||
|
virtualQueue.add(Nota(Json.decodeFromString<NotaDescriptor>(intent.getStringExtra("nota")!!)))
|
||||||
|
// virtualQueue.first.prepare(player)
|
||||||
|
virtualQueue.last.prepare(player)
|
||||||
|
player.prepare()
|
||||||
|
player.play()
|
||||||
|
Log.d("nya", virtualQueue.last.mediaSource.toString())
|
||||||
|
}
|
||||||
|
"pause" -> player.pause()
|
||||||
|
"play" -> player.play()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
player?.release()
|
player.release()
|
||||||
mediaSession?.release()
|
mediaSession.release()
|
||||||
player = null
|
|
||||||
mediaSession = null
|
|
||||||
Log.d("meow", "owowowow")
|
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
package usr.empty.player
|
|
||||||
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
import org.junit.Assert.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
|
||||||
*
|
|
||||||
* See [testing documentation](http://d.android.com/tools/testing).
|
|
||||||
*/
|
|
||||||
class ExampleUnitTest {
|
|
||||||
@Test
|
|
||||||
fun addition_isCorrect() {
|
|
||||||
assertEquals(4, 2 + 2)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,3 +21,4 @@ kotlin.code.style=official
|
||||||
# resources declared in the library itself and none from the library's dependencies,
|
# resources declared in the library itself and none from the library's dependencies,
|
||||||
# thereby reducing the size of the R class for that library
|
# thereby reducing the size of the R class for that library
|
||||||
android.nonTransitiveRClass=true
|
android.nonTransitiveRClass=true
|
||||||
|
org.gradle.configuration-cache=true
|
|
@ -1,28 +1,19 @@
|
||||||
[versions]
|
[versions]
|
||||||
agp = "8.6.0"
|
agp = "8.6.1"
|
||||||
core = "1.6.1"
|
kotlin = "2.0.0"
|
||||||
kotlin = "1.9.0"
|
|
||||||
coreKtx = "1.13.1"
|
coreKtx = "1.13.1"
|
||||||
junit = "4.13.2"
|
kotlinxSerializationJson = "1.7.3"
|
||||||
junitVersion = "1.2.1"
|
lifecycleRuntimeKtx = "2.8.6"
|
||||||
espressoCore = "3.6.1"
|
|
||||||
kotlinxSerializationJson = "1.7.1"
|
|
||||||
lifecycleRuntimeKtx = "2.6.1"
|
|
||||||
activityCompose = "1.9.2"
|
activityCompose = "1.9.2"
|
||||||
composeBom = "2024.04.01"
|
composeBom = "2024.09.02"
|
||||||
media3Exoplayer = "1.4.1"
|
media3Exoplayer = "1.4.1"
|
||||||
junitJupiter = "5.8.1"
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-core = { module = "androidx.test:core", version.ref = "core" }
|
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
androidx-media3-common = { module = "androidx.media3:media3-common", version.ref = "media3Exoplayer" }
|
androidx-media3-common = { module = "androidx.media3:media3-common", version.ref = "media3Exoplayer" }
|
||||||
androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3Exoplayer" }
|
androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3Exoplayer" }
|
||||||
androidx-media3-session = { module = "androidx.media3:media3-session", version.ref = "media3Exoplayer" }
|
androidx-media3-session = { module = "androidx.media3:media3-session", version.ref = "media3Exoplayer" }
|
||||||
androidx-media3-ui = { module = "androidx.media3:media3-ui", version.ref = "media3Exoplayer" }
|
androidx-media3-ui = { module = "androidx.media3:media3-ui", version.ref = "media3Exoplayer" }
|
||||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
|
||||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
|
||||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
|
||||||
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
|
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
|
||||||
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
|
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
|
||||||
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
|
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
|
||||||
|
@ -31,15 +22,11 @@ androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
|
||||||
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
|
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
|
||||||
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
|
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
|
||||||
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
||||||
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
|
||||||
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||||
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
||||||
junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junitJupiter" }
|
|
||||||
mockito-core = { module = "org.mockito:mockito-core", version = "5.10.0" }
|
|
||||||
mockito-kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version = "5.4.0" }
|
|
||||||
mockk = { module = "io.mockk:mockk", version = "1.13.10" }
|
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||||
|
|
||||||
|
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||||
|
|
Loading…
Reference in a new issue