Skip to content

Commit

Permalink
New Release!
Browse files Browse the repository at this point in the history
[All Versions] Now the app supports shuffling of the current playing
playlist.
  • Loading branch information
Carlos Pérez committed Jul 12, 2022
1 parent 3fce12b commit 4ac56f5
Show file tree
Hide file tree
Showing 29 changed files with 387 additions and 66 deletions.
7 changes: 7 additions & 0 deletions android/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ android {
applicationId "tech.logica10.soniclair"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 27
versionName "0.0.1-beta-transcoding"
versionCode 29
versionName "0.0.6"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,26 @@ class BackendPlugin : Plugin(), IBroadcastObserver {
}
}

@PluginMethod
fun shufflePlaylist(call: PluginCall){
try{
if (webSocketConnected) {
val command = constructWebsocketCommand("shufflePlaylist", "")
val message = constructWebsocketMessage(gson!!.toJson(command))
mWebSocket!!.send(gson!!.toJson(message))
call.resolve(okResponse(""))
return
}
if(mBound){
binder!!.shuffle()
}
call.resolve(okResponse(""))
} catch(e: Exception){
call.resolve(errorResponse(e.message))
}

}

@PluginMethod
fun getOfflineMode(call: PluginCall) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package tech.logica10.soniclair

import tech.logica10.soniclair.models.Song

class CurrentState(val playing: Boolean,
val position: Float,
val currentTrack: Song
class CurrentState(
val playing: Boolean,
val position: Float,
val currentTrack: Song,
val shuffling: Boolean
)
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,11 @@ class MessageServer(port: Int) : WebSocketServer(InetSocketAddress(port)), IBroa
)
}
}
"shufflePlaylist"->{
if(mBound){
binder!!.shuffle()
}
}
"seek" -> {
if (command.data.isBlank()) {
conn.send(constructMessage("The parameter time is empty", "error"))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,54 +1,125 @@
package tech.logica10.soniclair

import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.support.v4.media.session.MediaSessionCompat
import android.util.Log
import android.view.KeyEvent
import tech.logica10.soniclair.services.MusicService

class SonicLairSessionCallbacks : MediaSessionCompat.Callback() {
private var mBound = false
private var binder: MusicService.LocalBinder? = null

private val connection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(
className: ComponentName,
service: IBinder
) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
Log.i("ServiceBinder", "Binding service")
binder = service as MusicService.LocalBinder
mBound = true
}

override fun onServiceDisconnected(arg0: ComponentName) {
Log.i("ServiceBinder", "Unbinding service")
mBound = false
}
}

override fun onPlay() {
super.onPlay()
Globals.NotifyObservers("SLPAUSE", null)
if (mBound) {
binder!!.play()
}
}

override fun onPause() {
super.onPause()
Globals.NotifyObservers("SLPAUSE", null)
if (mBound) {
binder!!.pause()
}
}

override fun onSkipToNext() {
super.onSkipToNext()
Globals.NotifyObservers("SLNEXT", null)
Log.i("MediaSessionCallbacks", "OnSkipToNext")
if (mBound) {
binder!!.next()
}
}

override fun onSkipToPrevious() {
super.onSkipToPrevious()
Globals.NotifyObservers("SLPREV", null)
if (mBound) {
binder!!.prev()
}
}

override fun onMediaButtonEvent(mediaButtonIntent: Intent): Boolean {
val ke = mediaButtonIntent.getParcelableExtra<KeyEvent>(Intent.EXTRA_KEY_EVENT)
if (ke != null && ke.action == KeyEvent.ACTION_DOWN) {
when (ke.keyCode) {
KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_MEDIA_PAUSE, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> {
Globals.NotifyObservers("SLPAUSE", null)
if (mBound) {
binder!!.playpause()
}
}
KeyEvent.KEYCODE_MEDIA_NEXT -> {
Globals.NotifyObservers("SLNEXT", null)
Log.i("MediaSessionCallbacks", "OnMediaButtonNext")
if (mBound) {
binder!!.next()
}
}
KeyEvent.KEYCODE_MEDIA_PREVIOUS -> {
Globals.NotifyObservers("SLPREV", null)
if (mBound) {
binder!!.prev()
}
}
}
}
return true
}

override fun onPlayFromMediaId(mediaId: String, extras: Bundle) {
Globals.NotifyObservers("SLPLAYID", mediaId)

val id = mediaId.subSequence(1, mediaId.length).toString()
when (mediaId.subSequence(0, 1)) {
"s" -> {
if (mBound) {
binder!!.playRadio(id)
} else {
val intent = Intent(App.context, MusicService::class.java)
intent.action = Constants.SERVICE_PLAY_RADIO
intent.putExtra("id", id)
App.context.startService(intent)
}
}
"a" -> {
if (mBound) {
binder!!.playAlbum(id, 0)
} else {
val intent = Intent(App.context, MusicService::class.java)
intent.action = Constants.SERVICE_PLAY_ALBUM
intent.putExtra("id", id)
intent.putExtra("track", 0)
App.context.startService(intent)
}
}
"p" -> {
if (mBound) {
binder!!.playPlaylist(id, 0)
} else{
val intent = Intent(App.context, MusicService::class.java)
intent.action = Constants.SERVICE_PLAY_PLAYLIST
intent.putExtra("id", id)
intent.putExtra("track", 0)
App.context.startService(intent)
}
}
}
}

override fun onPlayFromSearch(query: String?, extras: Bundle?) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ class TvActivity : AppCompatActivity() {
.commit()
}

fun shuffle(){
if(mBound){
binder!!.shuffle()
}
}

fun playRadio(id: String) {
if (mBound) {
CoroutineScope(Dispatchers.IO).launch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class NowPlayingFragment(val bind: TvActivity.TvActivityBind, val client: Subson
private lateinit var secondLine: TextView
private lateinit var image: ImageView
private lateinit var btnPlay: ImageButton
private lateinit var btnShuffle: ImageButton
private lateinit var sbProgress: SeekBar
private lateinit var playlistRecyclerView: RecyclerView
private lateinit var playlistAdapter: SoniclairPlaylistItemAdapter
Expand All @@ -48,6 +49,9 @@ class NowPlayingFragment(val bind: TvActivity.TvActivityBind, val client: Subson
inner class NowPlayingObserver : IBroadcastObserver {
override fun update(action: String?, value: String?) {
when (action) {
"MSplaylistUpdated" -> {
getCurrentState()
}
"MScurrentTrack" -> {
getCurrentState()
}
Expand Down Expand Up @@ -111,6 +115,10 @@ class NowPlayingFragment(val bind: TvActivity.TvActivityBind, val client: Subson
btnNext.setOnClickListener {
bind.next()
}
btnShuffle = view.findViewById<ImageButton>(R.id.btn_shuffle)
btnShuffle.setOnClickListener {
bind.shuffle()
}
firstLine = view.findViewById(R.id.tv_now_playing_first_line)
secondLine = view.findViewById(R.id.tv_now_playing_second_line)
image = view.findViewById(R.id.img_now_playing_album_art)
Expand Down Expand Up @@ -174,6 +182,24 @@ class NowPlayingFragment(val bind: TvActivity.TvActivityBind, val client: Subson
)
)
}
if(currentState.shuffling){
btnShuffle.setImageDrawable(
ResourcesCompat.getDrawable(
resources,
R.drawable.ic_shuffle_fill_primary,
null
)
)
}
else{
btnShuffle.setImageDrawable(
ResourcesCompat.getDrawable(
resources,
R.drawable.ic_shuffle_fill,
null
)
)
}
if (currentPlaylist != null && currentPlaylist.entry.any()) {
val list = currentPlaylist.entry
for (song in list) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Playlist(
val duration: Int,
val created: String,
val coverArt: String?,
val entry: List<Song>
var entry: List<Song>
) : ICardViewModel {
override fun firstLine(): String {
return name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class MusicService : Service(), IBroadcastObserver, MediaPlayer.EventListener {
val args = mutableListOf("-vvv")
private var mLibVLC: LibVLC? = null
private var currentTrack: Song? = null
private var shuffling: Boolean = false
private val mAudioManager: AudioManager =
App.context.getSystemService(AUDIO_SERVICE) as AudioManager
private val mPlaybackAttributes: AudioAttributes = AudioAttributes.Builder()
Expand All @@ -77,6 +78,7 @@ class MusicService : Service(), IBroadcastObserver, MediaPlayer.EventListener {
.setDescription("Currently playing notification")
.build()
private var playlist: Playlist = getDefaultPlaylist()
private var originalPlaylist: List<Song> = listOf()
private var prevAction: NotificationCompat.Action? = null
private var pauseAction: NotificationCompat.Action? = null
private var playAction: NotificationCompat.Action? = null
Expand Down Expand Up @@ -223,6 +225,26 @@ class MusicService : Service(), IBroadcastObserver, MediaPlayer.EventListener {

}

private fun shufflePlaylist() {
if (shuffling) {
this.playlist.entry = this.originalPlaylist.toList()
} else {
this.playlist.entry = shuffle(this.playlist.entry)
}
shuffling = !shuffling
notifyListeners("playlistUpdated", null);
}

private fun shuffle(list: List<Song>): List<Song> {
val ret = list.shuffled().toMutableList()
if (currentTrack != null) {
val index = ret.indexOf(currentTrack)
ret[index] = ret[0]
ret[0] = currentTrack!!
}
return ret
}


private fun updateNotification(albumArtBitmap: Bitmap?, play: Boolean = false) {
val notificationBuilder = getNotificationBuilder()
Expand Down Expand Up @@ -551,6 +573,7 @@ class MusicService : Service(), IBroadcastObserver, MediaPlayer.EventListener {
songs[0].albumId,
songs
)
originalPlaylist = playlist.entry.toList()
currentTrack = songs[0]
if (connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
?.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) == true
Expand Down Expand Up @@ -586,7 +609,7 @@ class MusicService : Service(), IBroadcastObserver, MediaPlayer.EventListener {
playlist = getDefaultPlaylist()
try {
playlist = subsonicClient.getPlaylist(id)

originalPlaylist = playlist.entry.toList()
currentTrack = playlist.entry[track]

if (connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
Expand Down Expand Up @@ -629,6 +652,8 @@ class MusicService : Service(), IBroadcastObserver, MediaPlayer.EventListener {
songs
)

originalPlaylist = playlist.entry.toList()

currentTrack = songs[track]

if (connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
Expand Down Expand Up @@ -854,7 +879,8 @@ class MusicService : Service(), IBroadcastObserver, MediaPlayer.EventListener {
return CurrentState(
this@MusicService.mMediaPlayer!!.isPlaying,
this@MusicService.mMediaPlayer!!.position,
this@MusicService.currentTrack ?: Song("", "", "", 0, 0, "", "", "", "")
this@MusicService.currentTrack ?: Song("", "", "", 0, 0, "", "", "", ""),
this@MusicService.shuffling
)
}

Expand All @@ -874,6 +900,10 @@ class MusicService : Service(), IBroadcastObserver, MediaPlayer.EventListener {
this@MusicService.pause()
}

fun shuffle(){
this@MusicService.shufflePlaylist()
}

fun playpause() {
if (mMediaPlayer!!.isPlaying) {
this@MusicService.pause()
Expand Down
4 changes: 2 additions & 2 deletions android/app/src/main/res/drawable/ic_pause_icon.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<vector android:height="40dp" android:viewportHeight="24"
android:viewportWidth="24" android:width="40dp" xmlns:android="http://schemas.android.com/apk/res/android">
<vector android:height="35dp" android:viewportHeight="24"
android:viewportWidth="24" android:width="35dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#fff" android:pathData="M6,5h2v14L6,19L6,5zM16,5h2v14h-2L16,5z"/>
</vector>
4 changes: 2 additions & 2 deletions android/app/src/main/res/drawable/ic_play.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<vector android:height="40dp" android:viewportHeight="24"
android:viewportWidth="24" android:width="40dp" xmlns:android="http://schemas.android.com/apk/res/android">
<vector android:height="35dp" android:viewportHeight="24"
android:viewportWidth="24" android:width="35dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#fff" android:pathData="M19.376,12.416L8.777,19.482A0.5,0.5 0,0 1,8 19.066V4.934a0.5,0.5 0,0 1,0.777 -0.416l10.599,7.066a0.5,0.5 0,0 1,0 0.832z"/>
</vector>
Loading

1 comment on commit 4ac56f5

@vercel
Copy link

@vercel vercel bot commented on 4ac56f5 Jul 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

soniclair – ./

soniclair-thelinkin3000.vercel.app
soniclair-git-main-thelinkin3000.vercel.app
soniclair.vercel.app

Please sign in to comment.