├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── ids.xml
│ │ │ │ ├── themes_light.xml
│ │ │ │ ├── themes_inverted.xml
│ │ │ │ ├── preloaded_fonts.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── attrs.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── font_certs.xml
│ │ │ ├── drawable
│ │ │ │ ├── saxo.jpg
│ │ │ │ ├── cover1.jpg
│ │ │ │ ├── cover2.png
│ │ │ │ ├── next.xml
│ │ │ │ ├── previous.xml
│ │ │ │ ├── volume_available.xml
│ │ │ │ ├── ic_invert_theme.xml
│ │ │ │ ├── favorite_border.xml
│ │ │ │ ├── repeat.xml
│ │ │ │ ├── pause.xml
│ │ │ │ ├── play_icon.xml
│ │ │ │ ├── playlist.xml
│ │ │ │ ├── ic_shuffle_bordered.xml
│ │ │ │ ├── ic_overflow_menu.xml
│ │ │ │ ├── shuffle.xml
│ │ │ │ ├── ic_sound_bars.xml
│ │ │ │ ├── ic_if_speaker.xml
│ │ │ │ └── ic_launcher_background.xml
│ │ │ ├── font
│ │ │ │ ├── roboto_light.ttf
│ │ │ │ └── roboto.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── layout
│ │ │ │ ├── fragment_playlist.xml
│ │ │ │ ├── fragment_favorites.xml
│ │ │ │ ├── fragment_artist_info.xml
│ │ │ │ ├── tabs_main.xml
│ │ │ │ ├── fragment_artists.xml
│ │ │ │ ├── fragment_fragment_album.xml
│ │ │ │ ├── current_songs_item.xml
│ │ │ │ ├── artist_track_item.xml
│ │ │ │ ├── artist_item.xml
│ │ │ │ ├── album_item.xml
│ │ │ │ ├── activity_player.xml
│ │ │ │ ├── fragment_tracks.xml
│ │ │ │ ├── track.xml
│ │ │ │ ├── controls.xml
│ │ │ │ ├── fragment_album_details.xml
│ │ │ │ └── fragment_info.xml
│ │ │ ├── menu
│ │ │ │ ├── artist_sorting.xml
│ │ │ │ ├── track_sorting.xml
│ │ │ │ ├── menu_player.xml
│ │ │ │ └── album_sorting.xml
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ └── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ ├── ic_launcher-web.png
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── revosleap
│ │ │ │ └── proxima
│ │ │ │ ├── callbacks
│ │ │ │ ├── BXColor.kt
│ │ │ │ └── PlayerAdapter.kt
│ │ │ │ ├── models
│ │ │ │ ├── PlayList.kt
│ │ │ │ ├── Song.kt
│ │ │ │ ├── Album.kt
│ │ │ │ └── Artist.kt
│ │ │ │ ├── utils
│ │ │ │ ├── utils
│ │ │ │ │ ├── Universal.kt
│ │ │ │ │ ├── UniversalUtils.kt
│ │ │ │ │ ├── AlbumProvider.kt
│ │ │ │ │ ├── AudioUtils.kt
│ │ │ │ │ ├── WrappedAsyncTaskLoader.kt
│ │ │ │ │ ├── PlayListProvider.kt
│ │ │ │ │ ├── PreferenceHelper.kt
│ │ │ │ │ ├── GetAudio.kt
│ │ │ │ │ ├── EqualizerUtils.kt
│ │ │ │ │ ├── GlideLoader.kt
│ │ │ │ │ ├── ArtistProvider.kt
│ │ │ │ │ └── SongProvider.kt
│ │ │ │ ├── playback
│ │ │ │ │ ├── PlaybackInfoListener.kt
│ │ │ │ │ └── BXNotificationManager.kt
│ │ │ │ └── adapters
│ │ │ │ │ ├── ArtistTabAdapter.kt
│ │ │ │ │ └── MainTabsAdapter.kt
│ │ │ │ ├── ui
│ │ │ │ ├── viewholders
│ │ │ │ │ └── TrackViewHolder.kt
│ │ │ │ └── fragments
│ │ │ │ │ ├── FragmentPlaylist.kt
│ │ │ │ │ ├── FragmentFavorites.kt
│ │ │ │ │ ├── FragmentArtistInfo.kt
│ │ │ │ │ ├── FragmentArtistAlbum.kt
│ │ │ │ │ ├── FragmentArtistTrack.kt
│ │ │ │ │ ├── FragmentArtists.kt
│ │ │ │ │ ├── FragmentAlbum.kt
│ │ │ │ │ ├── FragmentAlbumInfo.kt
│ │ │ │ │ ├── FragmentTracks.kt
│ │ │ │ │ └── FragmentInfo.kt
│ │ │ │ └── services
│ │ │ │ └── MusicPlayerService.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── revosleap
│ │ │ └── proxima
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── revosleap
│ │ └── proxima
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── alpha_02.png
├── alpha_03.png
├── alpha_04.png
├── alpha_05.png
├── home_alpha_01.png
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .idea
├── caches
│ └── build_file_checksums.ser
├── vcs.xml
├── misc.xml
├── runConfigurations.xml
├── gradle.xml
└── codeStyles
│ └── Project.xml
├── .gitignore
├── gradle.properties
├── README.md
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/alpha_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/alpha_02.png
--------------------------------------------------------------------------------
/alpha_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/alpha_03.png
--------------------------------------------------------------------------------
/alpha_04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/alpha_04.png
--------------------------------------------------------------------------------
/alpha_05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/alpha_05.png
--------------------------------------------------------------------------------
/home_alpha_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/home_alpha_01.png
--------------------------------------------------------------------------------
/app/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/saxo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/app/src/main/res/drawable/saxo.jpg
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cover1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/app/src/main/res/drawable/cover1.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cover2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/app/src/main/res/drawable/cover2.png
--------------------------------------------------------------------------------
/app/src/main/res/font/roboto_light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/app/src/main/res/font/roboto_light.ttf
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/themes_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carloscj6/BXPlayer/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/themes_inverted.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/callbacks/BXColor.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.callbacks
2 |
3 | interface BXColor {
4 | fun songColor(color:Int)
5 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/libraries
5 | /.idea/modules.xml
6 | /.idea/workspace.xml
7 | .DS_Store
8 | /build
9 | /captures
10 | .externalNativeBuild
11 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/models/PlayList.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.models
2 |
3 | class PlayList {
4 | var title:String=""
5 | var path:String=""
6 | var dateAdded:Long=0L
7 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/preloaded_fonts.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - @font/roboto
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 256dp
4 |
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Feb 01 17:16:18 EAT 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_playlist.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_favorites.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/next.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/previous.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/font/roboto.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/artist_sorting.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/models/Song.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.models
2 |
3 | import java.io.Serializable
4 |
5 | class Song : Serializable {
6 | var path: String? = ""
7 | var title: String? = ""
8 | var artist: String? = ""
9 | var albumName: String? = ""
10 | var artistId: Int = 0
11 | var songYear: Int = 0
12 | var duration: Long = 0L
13 | var trackNumber:Int=0
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/test/java/com/revosleap/proxima/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * @see [Testing documentation](http://d.android.com/tools/testing)
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, (2 + 2).toLong())
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/main/res/menu/track_sorting.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_player.xml:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/album_sorting.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/volume_available.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/utils/Universal.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.utils.utils
2 |
3 | object Universal {
4 | const val infoAction = "com.revosleap.startInfo"
5 | const val SORT_BY_YEAR = "year"
6 | const val SORT_BY_ARTIST = "artist"
7 | const val SORT_BY_TITLE = "title"
8 | const val SORT_BY_NAME = "name"
9 | const val SORT_BY_SONGS = "songs"
10 | const val ALBUM_BUNDLE= "album.bundle"
11 | const val SONGS_BUNDLE="songs.bundle"
12 | const val ALBUMS_BUNDLE="albums.bundle"
13 | const val ALBUM_INFO_TAG ="album.fragment_info"
14 | }
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | BX Player
3 |
4 | Settings
5 | Play a song first!
6 | Equalizer
7 | Artist
8 | Date
9 | Title
10 | Release
11 | Name
12 | Songs
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/models/Album.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.models
2 |
3 | import java.io.Serializable
4 |
5 | class Album:Serializable {
6 | val songs: MutableList = mutableListOf()
7 |
8 | val title: String
9 | get() = firstSong.albumName!!
10 |
11 | val artistId: Int
12 | get() = firstSong.artistId
13 |
14 | val artistName: String?
15 | get() = firstSong.artist
16 |
17 | val year: Int
18 | get() = firstSong.songYear
19 |
20 | val songCount: Int
21 | get() = songs.size
22 |
23 | private val firstSong: Song
24 | get() = songs[0]
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_invert_theme.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/ui/viewholders/TrackViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.ui.viewholders
2 |
3 | import android.support.v7.widget.RecyclerView
4 | import android.view.View
5 | import android.widget.ImageView
6 | import android.widget.TextView
7 |
8 | import com.revosleap.proxima.R
9 |
10 | class TrackViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
11 | private var trackImage: ImageView = itemView.findViewById(R.id.imageView2)
12 | var title: TextView
13 | var artist: TextView
14 |
15 | init {
16 | title = itemView.findViewById(R.id.textViewTitleTrack)
17 | artist = itemView.findViewById(R.id.textViewArtistTrack)
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/favorite_border.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/models/Artist.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.models
2 |
3 | import java.io.Serializable
4 |
5 | class Artist:Serializable {
6 | val albums: MutableList = mutableListOf()
7 |
8 | val id: Int
9 | get() = firstAlbum.artistId
10 |
11 | val name: String?
12 | get() = firstAlbum.artistName
13 |
14 | private val firstAlbum: Album
15 | get() = if (albums.isEmpty()) Album() else albums[0]
16 |
17 | val songCount: Int
18 | get() {
19 | var songCount = 0
20 | for (album in albums) {
21 | songCount += album.songCount
22 | }
23 | return songCount
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/repeat.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/ui/fragments/FragmentPlaylist.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.ui.fragments
2 |
3 |
4 | import android.os.Bundle
5 | import android.support.v4.app.Fragment
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 |
10 | import com.revosleap.proxima.R
11 |
12 |
13 | /**
14 | * A simple [Fragment] subclass.
15 | */
16 | class FragmentPlaylist : Fragment() {
17 |
18 |
19 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
20 | savedInstanceState: Bundle?): View? {
21 | // Inflate the constControls for this fragment
22 | return inflater.inflate(R.layout.fragment_playlist, container, false)
23 | }
24 |
25 | }// Required empty public constructor
26 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/revosleap/proxima/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima
2 |
3 | import android.support.test.InstrumentationRegistry
4 | import android.support.test.runner.AndroidJUnit4
5 | import org.junit.Assert.assertEquals
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * @see [Testing documentation](http://d.android.com/tools/testing)
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getTargetContext()
20 |
21 | assertEquals("com.revosleap.proxima", appContext.packageName)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/ui/fragments/FragmentFavorites.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.ui.fragments
2 |
3 |
4 | import android.os.Bundle
5 | import android.support.v4.app.Fragment
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 |
10 | import com.revosleap.proxima.R
11 |
12 |
13 | /**
14 | * A simple [Fragment] subclass.
15 | */
16 | class FragmentFavorites : Fragment() {
17 |
18 |
19 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
20 | savedInstanceState: Bundle?): View? {
21 | // Inflate the constControls for this fragment
22 | return inflater.inflate(R.layout.fragment_favorites, container, false)
23 | }
24 |
25 | }// Required empty public constructor
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/playback/PlaybackInfoListener.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.utils.playback
2 |
3 | import android.support.annotation.IntDef
4 |
5 |
6 | abstract class PlaybackInfoListener {
7 |
8 | open fun onPositionChanged(position: Int) {}
9 |
10 | open fun onStateChanged(@State state: Int) {}
11 |
12 | open fun onPlaybackCompleted() {}
13 |
14 | @IntDef(State.INVALID, State.PLAYING, State.PAUSED, State.COMPLETED, State.RESUMED)
15 | @Retention(AnnotationRetention.SOURCE)
16 | annotation class State {
17 | companion object {
18 |
19 | const val INVALID = -1
20 | const val PLAYING = 0
21 | const val PAUSED = 1
22 | const val COMPLETED = 2
23 | const val RESUMED = 3
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | android.debug.obsoleteApi=true
11 | android.enableR8 = true
12 | # When configured, Gradle will run in incubating parallel mode.
13 | # This option should only be used with decoupled projects. More details, visit
14 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
15 | # org.gradle.parallel=true
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/pause.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 | #EC407A
7 |
8 | #000000
9 | #FFFFFF
10 |
11 | #FAFAFA
12 | #060606
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/play_icon.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -keep public class * implements com.bumptech.glide.module.GlideModule
2 |
3 |
4 | # Add project specific ProGuard rules here.
5 | # You can control the set of applied configuration files using the
6 | # proguardFiles setting in build.gradle.
7 | #
8 | # For more details, see
9 | # http://developer.android.com/guide/developing/tools/proguard.html
10 |
11 | # If your project uses WebView with JS, uncomment the following
12 | # and specify the fully qualified class name to the JavaScript interface
13 | # class:
14 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
15 | # public *;
16 | #}
17 |
18 | # Uncomment this to preserve the line number information for
19 | # debugging stack traces.
20 | #-keepattributes SourceFile,LineNumberTable
21 |
22 | # If you keep the line number information, uncomment this to
23 | # hide the original source file name.
24 | #-renamesourcefileattribute SourceFile
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BXPlayer
2 | Music player Slowly coming to life.
3 | ## Screenshots
4 |
5 |
6 |
7 | License
8 | -------
9 | Copyright (C) 2019 Carlos Anyona
10 |
11 | This program is free software: you can redistribute it and/or modify
12 | it under the terms of the GNU Affero General Public License as published
13 | by the Free Software Foundation, either version 3 of the License, or
14 | (at your option) any later version.
15 |
16 | This program is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU Affero General Public License for more details.
20 |
21 | You should have received a copy of the GNU Affero General Public License
22 | along with this program. If not, see .
23 |
24 | Check full license [here](/LICENSE)
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/utils/UniversalUtils.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.utils.utils
2 |
3 | object UniversalUtils {
4 | fun formatTime(ms: Long): String {
5 | val totalSecs = ms / 1000
6 | val hours = totalSecs / 3600
7 | val minutes = totalSecs / 60 % 60
8 | val secs = totalSecs % 60
9 | val minutesString = when {
10 | minutes == 0L -> "00"
11 | minutes < 10 -> "0$minutes"
12 | else -> "" + minutes
13 | }
14 | val secsString = when {
15 | secs == 0L -> "00"
16 | secs < 10 -> "0$secs"
17 | else -> "" + secs
18 | }
19 | return when {
20 | hours > 0 -> "$hours:$minutesString:$secsString"
21 | minutes > 0 -> "$minutes:$secsString"
22 | else -> "0:$secsString"
23 | }
24 | }
25 |
26 | fun formatTrack(trackNumber: Int): Int {
27 | var formatted = trackNumber
28 | if (trackNumber >= 1000) {
29 | formatted = trackNumber % 1000
30 | }
31 | return formatted
32 | }
33 |
34 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_artist_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/tabs_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
17 |
18 |
19 |
20 |
21 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/utils/AlbumProvider.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.utils.utils
2 |
3 | import com.revosleap.proxima.models.Album
4 | import com.revosleap.proxima.models.Song
5 | import java.util.*
6 |
7 | object AlbumProvider {
8 | fun retrieveAlbums(songs: MutableList?): MutableList {
9 | val albums = mutableListOf()
10 | if (songs != null) {
11 | for (song in songs) {
12 | getAlbum(albums, song.albumName!!).songs.add(song)
13 | }
14 | }
15 | if (albums.size > 1) {
16 | sortAlbums(albums)
17 | }
18 | return albums
19 | }
20 |
21 | private fun sortAlbums(albums: MutableList) {
22 | albums.sortWith(Comparator { obj1, obj2 -> Integer.compare(obj1.year, obj2.year) })
23 | }
24 |
25 | private fun getAlbum(albums: MutableList, albumName: String): Album {
26 | for (album in albums) {
27 | if (!album.songs.isEmpty() && album.songs[0].albumName == albumName) {
28 | return album
29 | }
30 | }
31 | val album = Album()
32 | albums.add(album)
33 | return album
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/playlist.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_artists.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
21 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/adapters/ArtistTabAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.utils.adapters
2 |
3 | import android.os.Bundle
4 | import android.support.v4.app.Fragment
5 | import android.support.v4.app.FragmentManager
6 | import android.support.v4.app.FragmentStatePagerAdapter
7 | import com.revosleap.proxima.ui.fragments.FragmentArtistAlbum
8 | import com.revosleap.proxima.ui.fragments.FragmentArtistTrack
9 | import com.revosleap.proxima.utils.utils.Universal
10 |
11 | class ArtistTabAdapter(fm: FragmentManager,songString: String?,albumString: String?)
12 | : FragmentStatePagerAdapter(fm) {
13 | val album= albumString
14 | val song= songString
15 | val bundle = Bundle()
16 | private val fragmentArtistAlbum = FragmentArtistAlbum()
17 | private val fragmentArtistTrack = FragmentArtistTrack()
18 |
19 | override fun getItem(position: Int): Fragment? {
20 | bundle.putString(Universal.SONGS_BUNDLE,song)
21 | bundle.putString(Universal.ALBUMS_BUNDLE,album)
22 | return when (position) {
23 | 0 -> {
24 | fragmentArtistTrack.arguments = bundle
25 | fragmentArtistTrack
26 | }
27 | 1 -> {
28 | fragmentArtistAlbum.arguments= bundle
29 | fragmentArtistAlbum
30 | }
31 | else -> null
32 | }
33 |
34 | }
35 |
36 | override fun getCount(): Int {
37 | return 2
38 | }
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/adapters/MainTabsAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.utils.adapters
2 |
3 | import android.support.v4.app.Fragment
4 | import android.support.v4.app.FragmentManager
5 | import android.support.v4.app.FragmentStatePagerAdapter
6 | import com.revosleap.proxima.callbacks.BXColor
7 | import com.revosleap.proxima.ui.activities.PlayerActivity
8 | import com.revosleap.proxima.ui.fragments.*
9 |
10 | class MainTabsAdapter(fm: FragmentManager, size: Int, playerActivity: PlayerActivity) : FragmentStatePagerAdapter(fm), BXColor {
11 | private val faveFrag = FragmentFavorites()
12 | private val playlist = FragmentPlaylist()
13 | private val tracks = FragmentTracks()
14 | private val albums = FragmentAlbum()
15 | private val artists = FragmentArtists()
16 | private val player=playerActivity
17 | override fun songColor(color: Int) {
18 | tracks.songColor(color)
19 | albums.songColor(color)
20 | artists.songColor(color)
21 | }
22 |
23 | private val fragmentCount = size
24 | override fun getItem(position: Int): Fragment? {
25 | player.setColorCallback(this)
26 | return when (position) {
27 | 0 -> faveFrag
28 | 1 -> playlist
29 | 2 -> tracks
30 | 3 -> albums
31 | 4 -> artists
32 | else -> null
33 | }
34 | }
35 |
36 | override fun getCount(): Int {
37 | return fragmentCount
38 | }
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/callbacks/PlayerAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.callbacks
2 |
3 |
4 | import android.app.Activity
5 | import android.media.MediaPlayer
6 | import com.revosleap.proxima.models.Album
7 | import com.revosleap.proxima.models.Song
8 | import com.revosleap.proxima.utils.playback.PlaybackInfoListener
9 |
10 |
11 | interface PlayerAdapter {
12 |
13 | fun isMediaPlayer(): Boolean
14 |
15 | fun isPlaying(): Boolean
16 |
17 | fun isReset(): Boolean
18 |
19 | fun getCurrentSong(): Song?
20 |
21 | fun getCurrentSongs():MutableList?
22 |
23 | fun getPlayerPosition(): Int
24 |
25 | fun getSelectedAlbum(): Album?
26 |
27 | fun initMediaPlayer()
28 |
29 | fun shufflePlayList()
30 |
31 | fun release()
32 |
33 | fun resumeOrPause()
34 |
35 | fun reset()
36 |
37 | fun instantReset()
38 |
39 | fun skip(isNext: Boolean)
40 |
41 | fun openEqualizer(activity: Activity)
42 |
43 | fun seekTo(position: Int)
44 |
45 | fun setPlaybackInfoListener(playbackInfoListener: PlaybackInfoListener)
46 |
47 | fun registerNotificationActionsReceiver(isRegister: Boolean)
48 |
49 | fun setCurrentSong(song: Song, songs: MutableList)
50 |
51 | fun onPauseActivity()
52 |
53 | fun onResumeActivity()
54 |
55 | fun setSelectedAlbum(album: Album)
56 |
57 | fun getMediaPlayer(): MediaPlayer?
58 |
59 | @PlaybackInfoListener.State
60 | fun getState(): Int
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/utils/AudioUtils.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.utils.utils
2 |
3 | import android.content.Context
4 | import android.graphics.Bitmap
5 | import android.graphics.BitmapFactory
6 | import android.media.MediaMetadataRetriever
7 | import com.revosleap.proxima.R
8 | import java.io.ByteArrayInputStream
9 | import java.io.InputStream
10 | import java.util.*
11 | import java.util.concurrent.TimeUnit
12 |
13 | object AudioUtils {
14 | @Throws(IllegalStateException::class)
15 | fun cover(path: String, context: Context): Bitmap {
16 | val retriever = MediaMetadataRetriever()
17 | val inputStream: InputStream?
18 | retriever.setDataSource(path)
19 | return if (retriever.embeddedPicture != null) {
20 | inputStream = ByteArrayInputStream(retriever.embeddedPicture)
21 | val image = BitmapFactory.decodeStream(inputStream)
22 | retriever.release()
23 | image
24 | } else {
25 | BitmapFactory.decodeResource(context.resources,
26 | R.drawable.cover2)
27 | }
28 | }
29 |
30 | fun formatDuration(duration: Int): String {
31 | return String.format(Locale.getDefault(), "%02d:%02d",
32 | TimeUnit.MILLISECONDS.toMinutes(duration.toLong()),
33 | TimeUnit.MILLISECONDS.toSeconds(duration.toLong()) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration.toLong())))
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/utils/WrappedAsyncTaskLoader.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.utils.utils
2 |
3 | import android.content.Context
4 | import android.support.v4.content.AsyncTaskLoader
5 |
6 | internal abstract class WrappedAsyncTaskLoader
7 | /**
8 | * Constructor of `WrappedAsyncTaskLoader`
9 | *
10 | * @param context The [Context] to use.
11 | */
12 | (context: Context) : AsyncTaskLoader(context) {
13 |
14 | private var mData: D? = null
15 |
16 | /**
17 | * {@inheritDoc}
18 | */
19 | override fun deliverResult(data: D?) {
20 | if (!isReset) {
21 | this.mData = data
22 | super.deliverResult(data)
23 | }
24 | }
25 |
26 | /**
27 | * {@inheritDoc}
28 | */
29 | override fun onStartLoading() {
30 | super.onStartLoading()
31 |
32 | if (this.mData != null) {
33 | deliverResult(this.mData)
34 | } else if (takeContentChanged() || this.mData == null) {
35 | forceLoad()
36 | }
37 | }
38 |
39 | /**
40 | * {@inheritDoc}
41 | */
42 | override fun onStopLoading() {
43 | super.onStopLoading()
44 | // Attempt to cancel the current load task if possible
45 | cancelLoad()
46 | }
47 |
48 | /**
49 | * {@inheritDoc}
50 | */
51 | override fun onReset() {
52 | super.onReset()
53 | // Ensure the loader is stopped
54 | onStopLoading()
55 | this.mData = null
56 | }
57 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/utils/PlayListProvider.kt:
--------------------------------------------------------------------------------
1 | //package com.revosleap.proxima.utils.utils
2 | //
3 | //import android.content.Context
4 | //import android.database.Cursor
5 | //import android.provider.MediaStore
6 | //import com.revosleap.proxima.models.Album
7 | //import com.revosleap.proxima.models.PlayList
8 | //
9 | //
10 | //object PlayListProvider {
11 | // private const val AUDIO_ID= 0
12 | // private const val CONTENT_DIRECTORY= 1
13 | // private const val PLAYLIST_ID= 2
14 | // private const val _ID = 3
15 | //
16 | //
17 | // private val BASE_PROJECTION = arrayOf(
18 | // MediaStore.Audio.PlaylistsColumns.NAME,
19 | // MediaStore.Audio.PlaylistsColumns.DATA,
20 | // MediaStore.Audio.PlaylistsColumns.DATE_ADDED
21 | // )
22 | // fun getAllPlayLists(cursor: Cursor?):MutableList{
23 | // val playLists= mutableListOf()
24 | // if (cursor!=null && cursor.moveToFirst()){
25 | //
26 | // }
27 | // }
28 | // private fun getPlayListFromCursor(cursor: Cursor):Album{
29 | // val album= Album()
30 | // album.title =
31 | // }
32 | // private fun makePlaylistCursor(context: Context, sortOrder: String?): Cursor? {
33 | // try {
34 | // return context.contentResolver.query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
35 | // BASE_PROJECTION, null, null, sortOrder)
36 | // } catch (e: SecurityException) {
37 | // return null
38 | // }
39 | //
40 | // }
41 | //}
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_fragment_album.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
24 |
25 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/current_songs_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
21 |
22 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_shuffle_bordered.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/services/MusicPlayerService.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.services
2 |
3 | import android.app.Service
4 | import android.content.Intent
5 | import android.os.Binder
6 | import android.os.IBinder
7 | import com.revosleap.proxima.utils.playback.BXNotificationManager
8 | import com.revosleap.proxima.utils.playback.MediaPlayerHolder
9 |
10 | class MusicPlayerService : Service() {
11 | private val binder= MusicBinder()
12 | var mediaPlayerHolder: MediaPlayerHolder? = null
13 | private set
14 | var musicNotificationManager: BXNotificationManager? = null
15 | private set
16 | var isRestoredFromPause = false
17 |
18 | override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
19 | mediaPlayerHolder?.registerNoisyReceiver()
20 | return START_NOT_STICKY
21 | }
22 |
23 | override fun onBind(intent: Intent): IBinder {
24 | if (mediaPlayerHolder == null) {
25 | mediaPlayerHolder = MediaPlayerHolder(this)
26 | musicNotificationManager = BXNotificationManager(this)
27 | mediaPlayerHolder!!.registerNotificationActionsReceiver(true)
28 | }
29 | return binder
30 | }
31 |
32 | override fun onDestroy() {
33 | mediaPlayerHolder!!.registerNotificationActionsReceiver(false)
34 | musicNotificationManager = null
35 | mediaPlayerHolder!!.release()
36 | super.onDestroy()
37 | }
38 | inner class MusicBinder:Binder(){
39 | val serviceInstance: MusicPlayerService
40 | get() = this@MusicPlayerService
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/utils/PreferenceHelper.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.utils.utils
2 |
3 | import android.content.Context
4 | import android.preference.PreferenceManager
5 |
6 | class PreferenceHelper(context: Context) {
7 | companion object {
8 | private const val SORTING_TOKEN = "player.trackSorting"
9 | private const val ALBUM_SORTING = "player.albumSorting"
10 | private const val ARTIST_SORTING = "player.artistSorting"
11 | private const val CURRENT_PLAYING = "player.currentPlaying"
12 | private const val CURRENT_PLAYING_INDEX = "player.currentPlayingIndex"
13 | private const val CURRENT_PLAYING_POSITION="current.song.position"
14 | }
15 |
16 | private val preferences = PreferenceManager.getDefaultSharedPreferences(context)
17 |
18 | var sortingStyle = preferences.getString(SORTING_TOKEN, "")!!
19 | set(value) = preferences.edit().putString(SORTING_TOKEN, value).apply()
20 |
21 | var albumSorting = preferences.getString(ALBUM_SORTING, "")!!
22 | set(value) = preferences.edit().putString(ALBUM_SORTING, value).apply()
23 |
24 | var artistSorting = preferences.getString(ARTIST_SORTING, "")!!
25 | set(value) = preferences.edit().putString(ARTIST_SORTING, value).apply()
26 |
27 | var playingList = preferences.getString(CURRENT_PLAYING, "")!!
28 | set(value) = preferences.edit().putString(CURRENT_PLAYING, value).apply()
29 |
30 | var currentIndex = preferences.getInt(CURRENT_PLAYING_INDEX, 0)
31 | set(value) = preferences.edit().putInt(CURRENT_PLAYING_INDEX, value).apply()
32 |
33 | var currentPosition = preferences.getInt(CURRENT_PLAYING_INDEX, 0)
34 | set(value) = preferences.edit().putInt(CURRENT_PLAYING_POSITION, value).apply()
35 |
36 | }
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android-extensions'
3 | apply plugin: 'kotlin-android'
4 |
5 | android {
6 | compileSdkVersion 28
7 | defaultConfig {
8 | applicationId "com.revosleap.proxima"
9 | minSdkVersion 21
10 | targetSdkVersion 28
11 | versionCode 2
12 | versionName "0.0.2-alpha"
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | }
22 |
23 | dependencies {
24 | implementation fileTree(dir: 'libs', include: ['*.jar'])
25 | implementation 'com.android.support:appcompat-v7:28.0.0'
26 | implementation 'com.android.support:support-v4:28.0.0'
27 | testImplementation 'junit:junit:4.12'
28 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
29 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
30 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
31 | implementation 'com.android.support:design:28.0.0'
32 | implementation 'com.android.support:palette-v7:28.0.0'
33 | implementation 'com.revosleap.layout:blurrylayout:1.0.2'
34 | implementation "org.jetbrains.anko:anko-commons:$anko_version"
35 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
36 | //noinspection GradleDependency
37 | implementation 'com.github.bumptech.glide:glide:3.8.0'
38 | implementation "com.revosleap.adapter:SimpleAdapter:$simple_adapter_version"
39 | implementation 'com.google.code.gson:gson:2.8.5'
40 |
41 | }
42 | repositories {
43 | mavenCentral()
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_overflow_menu.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/artist_track_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
32 |
33 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/utils/GetAudio.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.utils.utils
2 |
3 | import android.content.Context
4 | import android.provider.MediaStore
5 | import com.revosleap.proxima.models.Song
6 | import org.jetbrains.anko.toast
7 | import java.util.*
8 |
9 | class GetAudio {
10 | fun geAllAudio(context: Context): MutableList {
11 |
12 | val temAudioList = ArrayList()
13 | val uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
14 | val order = MediaStore.Audio.Media.TITLE
15 |
16 | val projection = arrayOf(MediaStore.Audio.AudioColumns.DATA, MediaStore.Audio.AudioColumns.ALBUM, MediaStore.Audio.ArtistColumns.ARTIST, MediaStore.Audio.AudioColumns.TITLE, MediaStore.Audio.AudioColumns.DURATION)
17 | val cursor = context.contentResolver.query(uri, projection, null, null, order)
18 | if (cursor != null) {
19 | while (cursor.moveToNext()) {
20 |
21 | val model = Song()
22 | val path = cursor.getString(0)
23 | val album = cursor.getString(1)
24 | val artist = cursor.getString(2)
25 | val name = cursor.getString(3)
26 | val duration = cursor.getString(4)
27 |
28 | try {
29 | model.title = name
30 | model.albumName = album
31 | model.artist = artist
32 | model.path = path
33 | model.duration = duration.toLong()
34 | } catch (e: Exception) {
35 | e.printStackTrace()
36 | }
37 |
38 | if(duration.toLong() >= 30000){
39 | temAudioList.add(model)
40 | }
41 |
42 | }
43 | cursor.close()
44 | } else
45 | context.toast("No Audio Files Found")
46 | return temAudioList
47 |
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shuffle.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
35 |
39 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_sound_bars.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/artist_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
23 |
24 |
25 |
41 |
42 |
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/utils/EqualizerUtils.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.utils.utils
2 |
3 | import android.app.Activity
4 | import android.content.ActivityNotFoundException
5 | import android.content.Context
6 | import android.content.Intent
7 | import android.media.MediaPlayer
8 | import android.media.audiofx.AudioEffect
9 | import android.widget.Toast
10 | import com.revosleap.proxima.R
11 |
12 | object EqualizerUtils {
13 | fun hasEqualizer(context: Context): Boolean {
14 | val effects = Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL)
15 | val pm = context.packageManager
16 | val ri = pm.resolveActivity(effects, 0)
17 | return ri != null
18 | }
19 |
20 | internal fun openAudioEffectSession(context: Context, sessionId: Int) {
21 | val intent = Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION)
22 | intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, sessionId)
23 | intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName)
24 | intent.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC)
25 | context.sendBroadcast(intent)
26 | }
27 |
28 | internal fun closeAudioEffectSession(context: Context, sessionId: Int) {
29 | val audioEffectsIntent = Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)
30 | audioEffectsIntent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, sessionId)
31 | audioEffectsIntent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName)
32 | context.sendBroadcast(audioEffectsIntent)
33 | }
34 |
35 | internal fun openEqualizer(activity: Activity, mediaPlayer: MediaPlayer) {
36 | val sessionId = mediaPlayer.audioSessionId
37 |
38 | if (sessionId == AudioEffect.ERROR_BAD_VALUE) {
39 | notifyNoSessionId(activity)
40 | } else {
41 | try {
42 | val effects = Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL)
43 | effects.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, sessionId)
44 | effects.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC)
45 | activity.startActivityForResult(effects, 0)
46 | } catch (notFound: ActivityNotFoundException) {
47 | notFound.printStackTrace()
48 | }
49 |
50 | }
51 | }
52 |
53 | fun notifyNoSessionId(context: Context) {
54 | Toast.makeText(context, context.getString(R.string.bad_id), Toast.LENGTH_SHORT).show()
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/album_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
26 |
27 |
28 |
43 |
56 |
57 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
23 |
28 |
29 |
30 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
46 |
49 |
50 |
53 |
54 |
57 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/utils/GlideLoader.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.utils.utils
2 |
3 |
4 | import android.content.Context
5 | import android.util.Log
6 |
7 | import com.bumptech.glide.Glide
8 | import com.bumptech.glide.GlideBuilder
9 | import com.bumptech.glide.Priority
10 | import com.bumptech.glide.load.data.DataFetcher
11 | import com.bumptech.glide.load.model.GenericLoaderFactory
12 | import com.bumptech.glide.load.model.ModelLoader
13 | import com.bumptech.glide.load.model.ModelLoaderFactory
14 | import com.bumptech.glide.load.model.stream.StreamModelLoader
15 | import com.bumptech.glide.module.GlideModule
16 |
17 | import java.io.IOException
18 | import java.io.InputStream
19 |
20 | class GlideLoader : GlideModule {
21 |
22 |
23 | override fun applyOptions(context: Context, builder: GlideBuilder) {
24 |
25 | }
26 |
27 | override fun registerComponents(context: Context, glide: Glide) {
28 | glide.register(InputStream::class.java, InputStream::class.java, PassthroughStreamLoader.Factory())
29 | }
30 |
31 | class PassthroughStreamLoader : StreamModelLoader {
32 | override fun getResourceFetcher(model: InputStream, width: Int, height: Int): DataFetcher {
33 | return object : DataFetcher {
34 | @Throws(Exception::class)
35 | override fun loadData(priority: Priority): InputStream {
36 | return model
37 | }
38 |
39 | override fun cleanup() {
40 | try {
41 | model.close()
42 | } catch (e: IOException) {
43 | Log.w("PassthroughDataFetcher", "Cannot clean up after stream", e)
44 | }
45 |
46 | }
47 |
48 | override fun getId(): String {
49 | return System.currentTimeMillis().toString() // There's no way to have a meaningful value here,
50 | // which means that caching of straight-loaded InputStreams is not possible.
51 | }
52 |
53 | override fun cancel() {
54 | // do nothing
55 | }
56 | }
57 | }
58 |
59 | class Factory : ModelLoaderFactory {
60 | override fun build(context: Context, factories: GenericLoaderFactory): ModelLoader {
61 | return PassthroughStreamLoader()
62 | }
63 |
64 | override fun teardown() {
65 | // nothing to do
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/utils/ArtistProvider.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.utils.utils
2 |
3 | import android.content.Context
4 | import android.provider.MediaStore
5 | import com.revosleap.proxima.models.Album
6 | import com.revosleap.proxima.models.Artist
7 | import java.util.*
8 |
9 | object ArtistProvider {
10 | val ARTISTS_LOADER = 0
11 |
12 | private val songLoaderSortOrder: String
13 | get() = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER + ", " + MediaStore.Audio.Albums.DEFAULT_SORT_ORDER + ", " + MediaStore.Audio.Media.DEFAULT_SORT_ORDER
14 |
15 | @Throws(Exception::class)
16 | private fun sortArtists(artists: MutableList) {
17 | artists.sortWith(Comparator { obj1, obj2 -> obj1.name?.compareTo(obj2.name!!, ignoreCase = true)!! })
18 | }
19 |
20 | @Throws(Exception::class)
21 | fun getAllArtists(context: Context): MutableList {
22 | val songs = SongProvider.getAllDeviceSongs(context)
23 | // sortArtists(artists);
24 | return retrieveArtists(AlbumProvider.retrieveAlbums(songs))
25 | }
26 |
27 | fun getArtist(artists: MutableList, selectedArtist: String): Artist? {
28 | var returnerArtist: Artist? = null
29 | for (artist in artists) {
30 | if (artist.name == selectedArtist) {
31 | returnerArtist = artist
32 | }
33 | }
34 | return returnerArtist
35 | }
36 |
37 | private fun retrieveArtists(albums: MutableList?): MutableList {
38 | val artists = mutableListOf()
39 | if (albums != null) {
40 | for (album in albums) {
41 | getOrCreateArtist(artists, album.artistId).albums.add(album)
42 | }
43 | }
44 | return artists
45 | }
46 |
47 | private fun getOrCreateArtist(artists: MutableList, artistId: Int): Artist {
48 | for (artist in artists) {
49 | if (!artist.albums.isEmpty() && !artist.albums[0].songs.isEmpty()
50 | && artist.albums[0].songs[0].artistId == artistId) {
51 | return artist
52 | }
53 | }
54 | val artist = Artist()
55 | artists.add(artist)
56 | return artist
57 | }
58 |
59 | internal class AsyncArtistLoader(context: Context) : WrappedAsyncTaskLoader>(context) {
60 |
61 | override fun loadInBackground(): MutableList? {
62 | try {
63 | return getAllArtists(context)
64 | } catch (e: Exception) {
65 | e.printStackTrace()
66 | }
67 |
68 | return null
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_player.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
20 |
21 |
22 |
33 |
34 |
43 |
44 |
50 |
51 |
52 |
53 |
59 |
60 |
61 |
62 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_tracks.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
26 |
27 |
39 |
40 |
53 |
54 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/utils/SongProvider.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.utils.utils
2 |
3 | import android.content.Context
4 | import android.database.Cursor
5 | import android.provider.MediaStore
6 | import com.revosleap.proxima.models.Album
7 | import com.revosleap.proxima.models.Song
8 |
9 | object SongProvider {
10 | private val TITLE = 0
11 | private val TRACK = 1
12 | private val YEAR = 2
13 | private val DURATION = 3
14 | private val PATH = 4
15 | private val ALBUM = 5
16 | private val ARTIST_ID = 6
17 | private val ARTIST = 7
18 |
19 | private val BASE_PROJECTION = arrayOf(MediaStore.Audio.AudioColumns.TITLE, // 0
20 | MediaStore.Audio.AudioColumns.TRACK, // 1
21 | MediaStore.Audio.AudioColumns.YEAR, // 2
22 | MediaStore.Audio.AudioColumns.DURATION, // 3
23 | MediaStore.Audio.AudioColumns.DATA, // 4
24 | MediaStore.Audio.AudioColumns.ALBUM, // 5
25 | MediaStore.Audio.AudioColumns.ARTIST_ID, // 6
26 | MediaStore.Audio.AudioColumns.ARTIST)// 7
27 |
28 | private val mAllDeviceSongs = mutableListOf()
29 |
30 | fun getAllDeviceSongs(context: Context): MutableList {
31 | return getSongs(makeSongCursor(context, null))
32 | }
33 |
34 | fun getAllArtistSongs(albums: MutableList): MutableList {
35 | val songsList = mutableListOf()
36 | for (album in albums) {
37 | songsList.addAll(album.songs)
38 | }
39 | return songsList
40 | }
41 |
42 | private fun getSongs(cursor: Cursor?): MutableList {
43 | val songs = mutableListOf()
44 | if (cursor != null && cursor.moveToFirst()) {
45 | do {
46 | val song = getSongFromCursorImpl(cursor)
47 | if (song.duration >= 30000) {
48 | songs.add(song)
49 | mAllDeviceSongs.add(song)
50 | }
51 | } while (cursor.moveToNext())
52 | }
53 |
54 | cursor?.close()
55 | if (songs.size > 1) {
56 | songs.sortWith(compareBy { it.title })
57 | }
58 | return songs
59 | }
60 |
61 |
62 | private fun getSongFromCursorImpl(cursor: Cursor): Song {
63 | val song = Song()
64 | song.title = cursor.getString(TITLE)
65 | song.trackNumber = UniversalUtils.formatTrack(cursor.getInt(TRACK))
66 | song.songYear = cursor.getInt(YEAR)
67 | song.duration = cursor.getLong(DURATION)
68 | song.path = cursor.getString(PATH)
69 | song.albumName = cursor.getString(ALBUM)
70 | song.artistId = cursor.getInt(ARTIST_ID)
71 | song.artist = cursor.getString(ARTIST)
72 |
73 | return song
74 | }
75 |
76 | internal fun makeSongCursor(context: Context, sortOrder: String?): Cursor? {
77 | try {
78 | return context.contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
79 | BASE_PROJECTION, null, null, sortOrder)
80 | } catch (e: SecurityException) {
81 | return null
82 | }
83 |
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/ui/fragments/FragmentArtistInfo.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.ui.fragments
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.support.design.widget.TabLayout
6 | import android.support.v4.app.Fragment
7 | import android.view.LayoutInflater
8 | import android.view.View
9 | import android.view.ViewGroup
10 | import com.google.gson.Gson
11 | import com.google.gson.reflect.TypeToken
12 | import com.revosleap.proxima.R
13 | import com.revosleap.proxima.models.Album
14 | import com.revosleap.proxima.models.Song
15 | import com.revosleap.proxima.ui.activities.PlayerActivity
16 | import com.revosleap.proxima.utils.adapters.ArtistTabAdapter
17 | import com.revosleap.proxima.utils.utils.Universal
18 | import kotlinx.android.synthetic.main.fragment_artist_info.*
19 | import java.lang.reflect.Type
20 |
21 | class FragmentArtistInfo : Fragment() {
22 | private var playerActivity: PlayerActivity? = null
23 | private var artistTabAdapter: ArtistTabAdapter? = null
24 | private var songs = mutableListOf()
25 | private var albums = mutableListOf()
26 | private var songString: String? = null
27 | private var albumString: String? = null
28 |
29 | override fun onAttach(context: Context?) {
30 | super.onAttach(context)
31 | playerActivity = activity as PlayerActivity
32 | }
33 |
34 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?)
35 | : View? {
36 | setHasOptionsMenu(true)
37 | getItems()
38 | return inflater.inflate(R.layout.fragment_artist_info, container, false)
39 | }
40 |
41 |
42 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
43 | super.onViewCreated(view, savedInstanceState)
44 | setTabs()
45 | val params = linearLayout.layoutParams as ViewGroup.MarginLayoutParams
46 | params.bottomMargin = playerActivity?.controls()!!.height
47 | linearLayout.layoutParams = params
48 | }
49 |
50 |
51 | private fun setTabs() {
52 | artistTabAdapter = ArtistTabAdapter(playerActivity?.supportFragmentManager!!, songString, albumString)
53 | tabLayoutArtist.apply {
54 | addTab(newTab().setText("Tracks (${songs.size})"))
55 | addTab(newTab().setText("Albums (${albums.size})"))
56 | tabGravity = TabLayout.GRAVITY_FILL
57 | }
58 | viewPagerArtist.apply {
59 | adapter = artistTabAdapter
60 | addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabLayoutArtist))
61 | }
62 | tabLayoutArtist.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(viewPagerArtist))
63 | }
64 |
65 | private fun getItems() {
66 | songString = arguments?.getString(Universal.SONGS_BUNDLE)
67 | albumString = arguments?.getString(Universal.ALBUMS_BUNDLE)
68 | val gson = Gson()
69 | val type: Type = object : TypeToken>() {}.type
70 | val albumType: Type = object : TypeToken>() {}.type
71 | val songs = gson.fromJson>(songString, type)
72 | val artAlbums = gson.fromJson>(albumString, albumType)
73 | if (songs != null && songs.size > 0 && artAlbums != null && artAlbums.size > 0) {
74 | this.songs = songs
75 | albums = artAlbums
76 | }
77 |
78 |
79 | }
80 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/font_certs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - @array/com_google_android_gms_fonts_certs_dev
5 | - @array/com_google_android_gms_fonts_certs_prod
6 |
7 |
8 | -
9 | MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
10 |
11 |
12 |
13 | -
14 | MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/track.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
27 |
28 |
29 |
30 |
51 |
52 |
71 |
72 |
82 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/ui/fragments/FragmentArtistAlbum.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.ui.fragments
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.support.v4.app.Fragment
6 | import android.support.v7.widget.LinearLayoutManager
7 | import android.view.LayoutInflater
8 | import android.view.View
9 | import android.view.ViewGroup
10 | import com.google.gson.Gson
11 | import com.google.gson.reflect.TypeToken
12 | import com.revosleap.proxima.R
13 | import com.revosleap.proxima.models.Album
14 | import com.revosleap.proxima.ui.activities.PlayerActivity
15 | import com.revosleap.proxima.utils.utils.Universal
16 | import com.revosleap.simpleadapter.SimpleAdapter
17 | import com.revosleap.simpleadapter.SimpleCallbacks
18 | import kotlinx.android.synthetic.main.fragment_fragment_album.*
19 | import kotlinx.android.synthetic.main.track.view.*
20 | import java.lang.reflect.Type
21 |
22 | class FragmentArtistAlbum : Fragment(), SimpleCallbacks {
23 | private var simpleAdapter: SimpleAdapter? = null
24 | private var albums = mutableListOf()
25 | private var playerActivity: PlayerActivity? = null
26 |
27 | override fun onAttach(context: Context?) {
28 | super.onAttach(context)
29 | playerActivity = activity as PlayerActivity
30 |
31 | }
32 |
33 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?)
34 | : View? {
35 | getAlbums()
36 | simpleAdapter = SimpleAdapter(R.layout.track, this)
37 | return inflater.inflate(R.layout.fragment_fragment_album, container, false)
38 | }
39 |
40 | override fun bindView(view: View, item: Any, position: Int) {
41 | item as Album
42 | val title = view.textViewArtistTrack
43 | val subTitle = view.textViewTitleTrack
44 | title.text = item.title
45 | subTitle.text = item.year.toString()
46 |
47 | }
48 |
49 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
50 | super.onViewCreated(view, savedInstanceState)
51 | recyclerViewAlbum.apply {
52 | adapter = simpleAdapter
53 | layoutManager = LinearLayoutManager(playerActivity)
54 | hasFixedSize()
55 | }
56 | simpleAdapter?.addManyItems(albums.toMutableList())
57 | buttonListSortAlbums.visibility= View.GONE
58 | }
59 |
60 | private fun getAlbums() {
61 | val albumString = arguments?.getString(Universal.ALBUMS_BUNDLE)
62 | val gson = Gson()
63 | val albumType: Type = object : TypeToken>() {}.type
64 | val artAlbums = gson.fromJson>(albumString, albumType)
65 | if (artAlbums != null && artAlbums.size > 0) {
66 | albums = artAlbums
67 | }
68 | }
69 |
70 | private fun goToInfo(position: Int) {
71 | val gson = Gson()
72 | val gsonString = gson.toJson(albums[position].songs)
73 | val albumInfo = FragmentAlbumInfo()
74 | val bundle = Bundle()
75 | bundle.putString(Universal.ALBUM_BUNDLE, gsonString)
76 | albumInfo.arguments = bundle
77 | playerActivity?.supportFragmentManager!!
78 | .beginTransaction()
79 | .replace(R.id.frame_current, albumInfo, Universal.ALBUM_INFO_TAG)
80 | .addToBackStack(null)
81 | .commit()
82 | playerActivity?.replaceFragment()
83 | }
84 |
85 | override fun onViewClicked(view: View, item: Any, position: Int) {
86 | goToInfo(position)
87 | }
88 |
89 | override fun onViewLongClicked(it: View?, item: Any, position: Int) {
90 |
91 | }
92 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/controls.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
23 |
24 |
25 |
26 |
44 |
45 |
61 |
62 |
79 |
80 |
98 |
99 |
115 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_album_details.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
12 |
13 |
16 |
17 |
25 |
34 |
39 |
48 |
56 |
57 |
62 |
63 |
64 |
67 |
79 |
92 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_if_speaker.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
9 |
12 |
15 |
18 |
21 |
24 |
27 |
30 |
33 |
36 |
39 |
40 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/ui/fragments/FragmentArtistTrack.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.ui.fragments
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.support.v4.app.Fragment
6 | import android.support.v7.widget.LinearLayoutManager
7 | import android.view.LayoutInflater
8 | import android.view.View
9 | import android.view.ViewGroup
10 | import com.google.gson.Gson
11 | import com.google.gson.reflect.TypeToken
12 | import com.revosleap.proxima.R
13 | import com.revosleap.proxima.callbacks.PlayerAdapter
14 | import com.revosleap.proxima.models.Song
15 | import com.revosleap.proxima.services.MusicPlayerService
16 | import com.revosleap.proxima.ui.activities.PlayerActivity
17 | import com.revosleap.proxima.utils.playback.BXNotificationManager
18 | import com.revosleap.proxima.utils.playback.PlaybackInfoListener
19 | import com.revosleap.proxima.utils.utils.Universal
20 | import com.revosleap.proxima.utils.utils.UniversalUtils
21 | import com.revosleap.simpleadapter.SimpleAdapter
22 | import com.revosleap.simpleadapter.SimpleCallbacks
23 | import kotlinx.android.synthetic.main.artist_track_item.view.*
24 | import kotlinx.android.synthetic.main.fragment_tracks.*
25 | import java.lang.reflect.Type
26 |
27 | class FragmentArtistTrack : Fragment(), SimpleCallbacks {
28 | private var playerActivity: PlayerActivity? = null
29 | private var simpleAdapter: SimpleAdapter? = null
30 | private var songs = mutableListOf()
31 | private var mPlayerAdapter: PlayerAdapter? = null
32 | private var mMusicService: MusicPlayerService? = null
33 | private var mMusicNotificationManager: BXNotificationManager? = null
34 | private var mPlaybackListener: PlaybackListener? = null
35 |
36 | override fun onAttach(context: Context?) {
37 | super.onAttach(context)
38 | playerActivity = activity as PlayerActivity
39 | getService()
40 | }
41 |
42 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?)
43 | : View? {
44 | simpleAdapter = SimpleAdapter(R.layout.artist_track_item, this)
45 | getMusicList()
46 | return inflater.inflate(R.layout.fragment_tracks, container, false)
47 | }
48 |
49 | override fun bindView(view: View, item: Any, position: Int) {
50 | item as Song
51 | val trackNo = view.textViewTrackNumber
52 | val trackTitle = view.textViewSongTitle
53 | val trackDuration = view.textViewSongDuration
54 | trackNo.text = item.trackNumber.toString()
55 | trackTitle.text = item.title
56 | trackDuration.text = UniversalUtils.formatTime(item.duration)
57 |
58 | }
59 |
60 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
61 | super.onViewCreated(view, savedInstanceState)
62 | trackRecycler.apply {
63 | adapter = simpleAdapter
64 | layoutManager = LinearLayoutManager(playerActivity)
65 | hasFixedSize()
66 | }
67 | simpleAdapter?.addManyItems(songs.toMutableList())
68 | buttonListShuffle.visibility= View.GONE
69 | buttonListSort.visibility= View.GONE
70 | buttonListPlayAll.visibility= View.GONE
71 | }
72 |
73 |
74 | override fun onResume() {
75 | super.onResume()
76 | getService()
77 | }
78 |
79 | override fun onViewClicked(view: View, item: Any, position: Int) {
80 | onSongSelected(songs[position], songs)
81 | }
82 |
83 | override fun onViewLongClicked(it: View?, item: Any, position: Int) {
84 |
85 | }
86 |
87 | private fun onSongSelected(song: Song, songs: MutableList) {
88 | mPlayerAdapter!!.setCurrentSong(song, songs)
89 | mPlayerAdapter!!.initMediaPlayer()
90 | mPlayerAdapter!!.getMediaPlayer()?.start()
91 | mMusicService!!.startForeground(BXNotificationManager.NOTIFICATION_ID,
92 | mMusicNotificationManager!!.createNotification())
93 |
94 |
95 | }
96 |
97 |
98 | fun getMusicList() {
99 | val songString = arguments?.getString(Universal.SONGS_BUNDLE)
100 | val gson = Gson()
101 | val type: Type = object : TypeToken>() {}.type
102 | val songs = gson.fromJson>(songString, type)
103 | if (songs != null && songs.size > 0) {
104 | this.songs = songs
105 | }
106 | }
107 |
108 | private fun getService() {
109 | mMusicService = playerActivity?.getPlayerService()
110 | if (mMusicService != null) {
111 | mPlayerAdapter = mMusicService!!.mediaPlayerHolder
112 | mMusicNotificationManager = mMusicService!!.musicNotificationManager
113 | }
114 | if (mPlaybackListener == null) {
115 | mPlaybackListener = PlaybackListener()
116 | mPlayerAdapter?.setPlaybackInfoListener(mPlaybackListener!!)
117 | }
118 | }
119 |
120 | private fun updatePlayingInfo(restore: Boolean, startPlay: Boolean) {
121 | if (startPlay) {
122 | mPlayerAdapter!!.getMediaPlayer()?.start()
123 | mMusicService!!.startForeground(BXNotificationManager.NOTIFICATION_ID,
124 | mMusicNotificationManager!!.createNotification())
125 |
126 | }
127 | val currentSong = mPlayerAdapter?.getCurrentSong()
128 | playerActivity?.updatePlaying(currentSong!!)
129 |
130 | if (restore) {
131 |
132 | if (mMusicService!!.isRestoredFromPause) {
133 | mMusicService!!.stopForeground(false)
134 | mMusicService!!.musicNotificationManager?.notificationManager!!
135 | .notify(BXNotificationManager.NOTIFICATION_ID,
136 | mMusicService!!.musicNotificationManager?.notificationBuilder?.build())
137 | mMusicService!!.isRestoredFromPause = false
138 | }
139 |
140 | }
141 | }
142 |
143 | internal inner class PlaybackListener : PlaybackInfoListener() {
144 | override fun onPositionChanged(position: Int) {
145 |
146 | }
147 |
148 | override fun onStateChanged(@State state: Int) {
149 | if (mPlayerAdapter?.getState() != State.RESUMED && mPlayerAdapter?.getState() != State.PAUSED) {
150 | updatePlayingInfo(false, startPlay = true)
151 | }
152 | }
153 |
154 | override fun onPlaybackCompleted() {
155 |
156 | }
157 | }
158 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/ui/fragments/FragmentArtists.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.ui.fragments
2 |
3 |
4 | import android.content.Context
5 | import android.os.Bundle
6 | import android.support.v4.app.Fragment
7 | import android.support.v7.widget.LinearLayoutManager
8 | import android.view.LayoutInflater
9 | import android.view.View
10 | import android.view.ViewGroup
11 | import android.widget.PopupMenu
12 | import com.google.gson.Gson
13 | import com.revosleap.proxima.R
14 | import com.revosleap.proxima.callbacks.BXColor
15 | import com.revosleap.proxima.models.Artist
16 | import com.revosleap.proxima.models.Song
17 | import com.revosleap.proxima.ui.activities.PlayerActivity
18 | import com.revosleap.proxima.utils.utils.ArtistProvider
19 | import com.revosleap.proxima.utils.utils.PreferenceHelper
20 | import com.revosleap.proxima.utils.utils.Universal
21 | import com.revosleap.simpleadapter.SimpleAdapter
22 | import com.revosleap.simpleadapter.SimpleCallbacks
23 | import kotlinx.android.synthetic.main.artist_item.view.*
24 | import kotlinx.android.synthetic.main.fragment_artists.*
25 | import org.jetbrains.anko.AnkoLogger
26 |
27 |
28 | class FragmentArtists : Fragment(), SimpleCallbacks, AnkoLogger, BXColor {
29 | private var preferenceHelper: PreferenceHelper? = null
30 | private var simpleAdapter: SimpleAdapter? = null
31 | private var artistList = mutableListOf()
32 | private var viewColors = 0
33 | private var playerActivity: PlayerActivity? = null
34 |
35 | override fun onAttach(context: Context?) {
36 | super.onAttach(context)
37 | playerActivity = activity as PlayerActivity
38 | }
39 |
40 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
41 | savedInstanceState: Bundle?): View? {
42 | simpleAdapter = SimpleAdapter(R.layout.artist_item, this)
43 | artistList = ArtistProvider.getAllArtists(activity!!)
44 | preferenceHelper = PreferenceHelper(activity!!)
45 | return inflater.inflate(R.layout.fragment_artists, container, false)
46 | }
47 |
48 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
49 | super.onViewCreated(view, savedInstanceState)
50 | getSongs()
51 | artistrecycler.apply {
52 | adapter = simpleAdapter
53 | layoutManager = LinearLayoutManager(activity)
54 | hasFixedSize()
55 | }
56 | buttonListSortArtists.setOnClickListener {
57 | sortArtists(it)
58 | }
59 | if (viewColors != 0) {
60 | buttonListSortArtists?.setColorFilter(viewColors)
61 | }
62 | }
63 |
64 | override fun bindView(view: View, item: Any, position: Int) {
65 | item as Artist
66 | val artistName = view.textViewArtistName
67 | val artistInfo = view.textViewArtistInfo
68 | artistName.text = item.name
69 | var album = "Album"
70 | var track = "Track"
71 | if (item.albums.size > 1) {
72 | album = "Albums"
73 | }
74 | if (item.songCount > 1) {
75 | track = "Tracks"
76 | }
77 | val info = item.songCount.toString() + " $track | " + item.albums.size + " $album"
78 | artistInfo.text = info
79 | }
80 |
81 | override fun onViewClicked(view: View, item: Any, position: Int) {
82 | viewDetails(position)
83 | }
84 |
85 | override fun onViewLongClicked(it: View?, item: Any, position: Int) {
86 |
87 | }
88 |
89 | override fun songColor(color: Int) {
90 | viewColors = color
91 |
92 | }
93 |
94 | private fun viewDetails(position: Int) {
95 | val fragmentArtistInfo = FragmentArtistInfo()
96 | val artist = artistList[position]
97 | val albums = artist.albums
98 | val songs = mutableListOf()
99 | albums.forEach {
100 | it.songs.forEach { song ->
101 | songs.add(song)
102 | }
103 | }
104 | val gson = Gson()
105 | val albumString = gson.toJson(albums)
106 | val songString = gson.toJson(songs)
107 | val bundle = Bundle()
108 | bundle.putString(Universal.ALBUMS_BUNDLE, albumString)
109 | bundle.putString(Universal.SONGS_BUNDLE, songString)
110 | fragmentArtistInfo.arguments = bundle
111 | playerActivity?.supportFragmentManager!!
112 | .beginTransaction()
113 | .replace(R.id.frame_current, fragmentArtistInfo, Universal.ALBUM_INFO_TAG)
114 | .addToBackStack(null)
115 | .commit()
116 | playerActivity?.replaceFragment()
117 |
118 | }
119 |
120 | private fun sortArtists(view: View) {
121 | val menu = PopupMenu(activity!!, view)
122 | menu.inflate(R.menu.artist_sorting)
123 | menu.show()
124 | menu.setOnMenuItemClickListener { item ->
125 | when (item?.itemId) {
126 | R.id.item_name -> {
127 | preferenceHelper?.artistSorting = Universal.SORT_BY_NAME
128 | val sorted = artistList.sortedWith(compareBy { it.name })
129 | artistList = sorted.toMutableList()
130 | simpleAdapter?.changeItems(artistList.toMutableList())
131 | }
132 | R.id.item_songs -> {
133 | preferenceHelper?.artistSorting = Universal.SORT_BY_SONGS
134 | val sorted = artistList.sortedWith(compareBy { it.songCount })
135 | artistList = sorted.toMutableList()
136 | artistList.reverse()
137 | simpleAdapter?.changeItems(artistList.toMutableList())
138 | }
139 | }
140 | true
141 | }
142 | }
143 |
144 | private fun getSongs() {
145 | val sorting = preferenceHelper?.artistSorting
146 | if (sorting?.isEmpty()!!) {
147 | simpleAdapter?.addManyItems(artistList.toMutableList())
148 | }
149 | if (sorting == Universal.SORT_BY_SONGS) {
150 | val sorted = artistList.sortedWith(compareBy { it.songCount })
151 | artistList = sorted.toMutableList()
152 | artistList.reverse()
153 | simpleAdapter?.changeItems(artistList.toMutableList())
154 | }
155 | if (sorting == Universal.SORT_BY_NAME) {
156 | val sorted = artistList.sortedWith(compareBy { it.name })
157 | artistList = sorted.toMutableList()
158 | simpleAdapter?.changeItems(artistList.toMutableList())
159 | }
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/ui/fragments/FragmentAlbum.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.ui.fragments
2 |
3 |
4 | import android.content.Context
5 | import android.os.Bundle
6 | import android.support.v4.app.Fragment
7 | import android.support.v7.widget.GridLayoutManager
8 | import android.view.LayoutInflater
9 | import android.view.View
10 | import android.view.ViewGroup
11 | import android.widget.PopupMenu
12 | import com.google.gson.Gson
13 | import com.revosleap.proxima.R
14 | import com.revosleap.proxima.callbacks.BXColor
15 | import com.revosleap.proxima.models.Album
16 | import com.revosleap.proxima.models.Song
17 | import com.revosleap.proxima.ui.activities.PlayerActivity
18 | import com.revosleap.proxima.utils.utils.AlbumProvider
19 | import com.revosleap.proxima.utils.utils.PreferenceHelper
20 | import com.revosleap.proxima.utils.utils.SongProvider
21 | import com.revosleap.proxima.utils.utils.Universal
22 | import com.revosleap.simpleadapter.SimpleAdapter
23 | import com.revosleap.simpleadapter.SimpleCallbacks
24 | import kotlinx.android.synthetic.main.album_item.view.*
25 | import kotlinx.android.synthetic.main.fragment_fragment_album.*
26 | import org.jetbrains.anko.AnkoLogger
27 | import org.jetbrains.anko.info
28 |
29 |
30 | class FragmentAlbum : Fragment(), SimpleCallbacks, AnkoLogger, BXColor {
31 | private var musicList = mutableListOf()
32 | private var albumList = mutableListOf()
33 | var simpleAdapter: SimpleAdapter? = null
34 | private var preferenceHelper: PreferenceHelper? = null
35 | private var playerActivity: PlayerActivity? = null
36 | private var viewColor = 0
37 |
38 | override fun onAttach(context: Context?) {
39 | super.onAttach(context)
40 | playerActivity = activity!! as PlayerActivity
41 | }
42 |
43 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
44 | savedInstanceState: Bundle?): View? {
45 | simpleAdapter = SimpleAdapter(R.layout.album_item, this)
46 | musicList = SongProvider.getAllDeviceSongs(activity!!)
47 | info(musicList.size)
48 | preferenceHelper = PreferenceHelper(activity!!)
49 | return inflater.inflate(R.layout.fragment_fragment_album, container, false)
50 | }
51 |
52 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
53 | super.onViewCreated(view, savedInstanceState)
54 | getAlbumList()
55 | simpleAdapter?.setHasStableIds(true)
56 | recyclerViewAlbum.apply {
57 | adapter = simpleAdapter
58 | layoutManager = GridLayoutManager(activity!!, 2)
59 | hasFixedSize()
60 | }
61 | buttonListSortAlbums.setOnClickListener {
62 | sortAlbums(it)
63 | }
64 | if (viewColor != 0) {
65 | buttonListSortAlbums?.setColorFilter(viewColor)
66 | }
67 | }
68 |
69 | override fun bindView(view: View, item: Any, position: Int) {
70 | item as Album
71 | val albumTitle = view.textViewAlbumName
72 | val albumArtist = view.textViewAlbumArtist
73 | val artist = item.artistName + " (" + item.songs.size + ")"
74 | albumTitle.text = item.title
75 | albumArtist.text = artist
76 | }
77 |
78 | override fun onViewClicked(view: View, item: Any, position: Int) {
79 | goToInfo(position)
80 | }
81 |
82 | override fun onViewLongClicked(it: View?, item: Any, position: Int) {
83 |
84 | }
85 |
86 | override fun songColor(color: Int) {
87 | viewColor = color
88 |
89 | }
90 |
91 | private fun goToInfo(position: Int) {
92 | val gson = Gson()
93 | val gsonString = gson.toJson(albumList[position].songs)
94 | val albumInfo = FragmentAlbumInfo()
95 | val bundle = Bundle()
96 | bundle.putString(Universal.ALBUM_BUNDLE, gsonString)
97 | albumInfo.arguments = bundle
98 | playerActivity?.supportFragmentManager!!
99 | .beginTransaction()
100 | .replace(R.id.frame_current, albumInfo, Universal.ALBUM_INFO_TAG)
101 | .addToBackStack(null)
102 | .commit()
103 | playerActivity?.replaceFragment()
104 | }
105 |
106 | private fun sortAlbums(view: View) {
107 | val menu = PopupMenu(activity!!, view)
108 | menu.inflate(R.menu.album_sorting)
109 | menu.show()
110 | menu.setOnMenuItemClickListener { item ->
111 | when (item?.itemId) {
112 | R.id.item_artist -> {
113 | preferenceHelper?.sortingStyle = Universal.SORT_BY_ARTIST
114 | val sorted = albumList.sortedWith(compareBy { it.artistName })
115 | simpleAdapter?.changeItems(sorted.toMutableList())
116 | albumList = sorted.toMutableList()
117 | }
118 | R.id.item_release -> {
119 | preferenceHelper?.sortingStyle = Universal.SORT_BY_YEAR
120 | val sorted = albumList.sortedWith(compareBy { it.year })
121 | simpleAdapter?.changeItems(sorted.toMutableList())
122 | albumList = sorted.toMutableList()
123 | }
124 | R.id.item_title -> {
125 | preferenceHelper?.sortingStyle = Universal.SORT_BY_TITLE
126 | val sorted = albumList.sortedWith(compareBy { it.title })
127 | simpleAdapter?.changeItems(sorted.toMutableList())
128 | albumList = sorted.toMutableList()
129 | }
130 |
131 | }
132 | true
133 | }
134 | }
135 |
136 | private fun getAlbumList() {
137 | val sortOrder = preferenceHelper?.albumSorting
138 | albumList = AlbumProvider.retrieveAlbums(musicList)
139 | if (sortOrder!!.isEmpty()) {
140 | simpleAdapter?.addManyItems(albumList.toMutableList())
141 |
142 | }
143 | if (sortOrder == Universal.SORT_BY_ARTIST) {
144 | val sorted = albumList.sortedWith(compareBy { it.artistName })
145 | simpleAdapter?.changeItems(sorted.toMutableList())
146 | albumList = sorted.toMutableList()
147 | }
148 | if (sortOrder == Universal.SORT_BY_TITLE) {
149 | val sorted = albumList.sortedWith(compareBy { it.title })
150 | simpleAdapter?.changeItems(sorted.toMutableList())
151 | albumList = sorted.toMutableList()
152 | }
153 | if (sortOrder == Universal.SORT_BY_YEAR) {
154 | val dateSorted = albumList.sortedWith(compareBy { it.year })
155 | simpleAdapter?.changeItems(dateSorted.toMutableList())
156 | albumList = dateSorted.toMutableList()
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/ui/fragments/FragmentAlbumInfo.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.ui.fragments
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.support.v4.app.Fragment
6 | import android.support.v7.widget.LinearLayoutManager
7 | import android.view.LayoutInflater
8 | import android.view.View
9 | import android.view.ViewGroup
10 | import com.google.gson.Gson
11 | import com.google.gson.reflect.TypeToken
12 | import com.revosleap.proxima.R
13 | import com.revosleap.proxima.models.Song
14 | import com.revosleap.proxima.services.MusicPlayerService
15 | import com.revosleap.proxima.ui.activities.PlayerActivity
16 | import com.revosleap.proxima.utils.playback.BXNotificationManager
17 | import com.revosleap.proxima.utils.playback.PlaybackInfoListener
18 | import com.revosleap.proxima.callbacks.PlayerAdapter
19 | import com.revosleap.proxima.utils.utils.Universal
20 | import com.revosleap.simpleadapter.SimpleAdapter
21 | import com.revosleap.simpleadapter.SimpleCallbacks
22 | import kotlinx.android.synthetic.main.fragment_album_details.*
23 | import kotlinx.android.synthetic.main.track.view.*
24 | import java.lang.reflect.Type
25 |
26 | class FragmentAlbumInfo : Fragment(), SimpleCallbacks {
27 | private var albumString: String? = null
28 | private var playerActivity: PlayerActivity? = null
29 | private var songs = mutableListOf()
30 | private var simpleAdapter: SimpleAdapter? = null
31 | private var mPlayerAdapter: PlayerAdapter? = null
32 | private var mMusicService: MusicPlayerService? = null
33 | private var mMusicNotificationManager: BXNotificationManager? = null
34 | private var mPlaybackListener: PlaybackListener? = null
35 | override fun onAttach(context: Context?) {
36 | super.onAttach(context)
37 | playerActivity = activity!! as PlayerActivity
38 | getService()
39 | }
40 |
41 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
42 | savedInstanceState: Bundle?): View? {
43 | albumString = arguments?.getString(Universal.ALBUM_BUNDLE)
44 | simpleAdapter = SimpleAdapter(R.layout.track, this)
45 | getMusicList()
46 | return inflater.inflate(R.layout.fragment_album_details, container, false)
47 | }
48 |
49 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
50 | super.onViewCreated(view, savedInstanceState)
51 | recyclerViewAlbum.apply {
52 | adapter = simpleAdapter
53 | layoutManager = LinearLayoutManager(playerActivity)
54 | hasFixedSize()
55 | }
56 | simpleAdapter?.addManyItems(songs.toMutableList())
57 | setButtons()
58 | val params = cordinator.layoutParams as ViewGroup.MarginLayoutParams
59 | params.bottomMargin = playerActivity?.controls()!!.height
60 | cordinator.layoutParams = params
61 | textViewAlbumArtist.text = songs[0].artist
62 | textViewAlbumName.text=songs[0].albumName
63 | }
64 |
65 | override fun onResume() {
66 | super.onResume()
67 | getService()
68 | }
69 |
70 | override fun bindView(view: View, item: Any, position: Int) {
71 | item as Song
72 | val titleText = view.textViewTitleTrack
73 | val artistText = view.textViewArtistTrack
74 | titleText.text = item.artist
75 | artistText.text = item.title
76 | }
77 |
78 | override fun onViewClicked(view: View, item: Any, position: Int) {
79 | onSongSelected(songs[position], songs)
80 | }
81 |
82 | override fun onViewLongClicked(it: View?, item: Any, position: Int) {
83 |
84 | }
85 | private fun setButtons(){
86 | buttonListPlayAll.setOnClickListener {
87 | onSongSelected(songs[0],songs)
88 | }
89 | buttonListShuffle.setOnClickListener {
90 | songs.shuffle()
91 | onSongSelected(songs[0],songs)
92 | }
93 | }
94 | private fun onSongSelected(song: Song, songs: MutableList) {
95 | mPlayerAdapter!!.setCurrentSong(song, songs)
96 | mPlayerAdapter!!.initMediaPlayer()
97 | mPlayerAdapter!!.getMediaPlayer()?.start()
98 | mMusicService!!.startForeground(BXNotificationManager.NOTIFICATION_ID,
99 | mMusicNotificationManager!!.createNotification())
100 |
101 |
102 | }
103 |
104 | private fun getMusicList() {
105 | if (albumString != null) {
106 | val gson = Gson()
107 | val type: Type = object : TypeToken>() {}.type
108 | val songs = gson.fromJson>(albumString, type)
109 | if (songs != null && songs.size > 0) {
110 | this.songs = songs
111 | }
112 | }
113 | }
114 |
115 | private fun getService() {
116 | mMusicService = playerActivity?.getPlayerService()
117 | if (mMusicService != null) {
118 | mPlayerAdapter = mMusicService!!.mediaPlayerHolder
119 | mMusicNotificationManager = mMusicService!!.musicNotificationManager
120 | }
121 | if (mPlaybackListener == null) {
122 | mPlaybackListener = PlaybackListener()
123 | mPlayerAdapter?.setPlaybackInfoListener(mPlaybackListener!!)
124 | }
125 | }
126 |
127 | private fun updatePlayingInfo(restore: Boolean, startPlay: Boolean) {
128 | if (startPlay) {
129 | mPlayerAdapter!!.getMediaPlayer()?.start()
130 | mMusicService!!.startForeground(BXNotificationManager.NOTIFICATION_ID,
131 | mMusicNotificationManager!!.createNotification())
132 |
133 | }
134 | val currentSong = mPlayerAdapter?.getCurrentSong()
135 | playerActivity?.updatePlaying(currentSong!!)
136 |
137 | if (restore) {
138 |
139 | if (mMusicService!!.isRestoredFromPause) {
140 | mMusicService!!.stopForeground(false)
141 | mMusicService!!.musicNotificationManager?.notificationManager!!
142 | .notify(BXNotificationManager.NOTIFICATION_ID,
143 | mMusicService!!.musicNotificationManager?.notificationBuilder?.build())
144 | mMusicService!!.isRestoredFromPause = false
145 | }
146 |
147 | }
148 | }
149 |
150 | internal inner class PlaybackListener : PlaybackInfoListener() {
151 | override fun onPositionChanged(position: Int) {
152 |
153 | }
154 |
155 | override fun onStateChanged(@State state: Int) {
156 | if (mPlayerAdapter?.getState() != State.RESUMED && mPlayerAdapter?.getState() != State.PAUSED) {
157 | updatePlayingInfo(false, startPlay = true)
158 | }
159 | }
160 |
161 | override fun onPlaybackCompleted() {
162 |
163 | }
164 | }
165 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/utils/playback/BXNotificationManager.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.utils.playback
2 |
3 | import android.app.Notification
4 | import android.app.NotificationChannel
5 | import android.app.NotificationManager
6 | import android.app.PendingIntent
7 | import android.content.Context
8 | import android.content.Intent
9 | import android.graphics.Bitmap
10 | import android.graphics.Canvas
11 | import android.graphics.Color
12 | import android.media.session.MediaSessionManager
13 | import android.os.Build
14 | import android.os.RemoteException
15 | import android.support.annotation.RequiresApi
16 | import android.support.v4.app.NotificationCompat
17 | import android.support.v4.media.MediaMetadataCompat
18 | import android.support.v4.media.session.MediaControllerCompat
19 | import android.support.v4.media.session.MediaSessionCompat
20 |
21 | import com.revosleap.proxima.models.Song
22 | import com.revosleap.proxima.utils.utils.AudioUtils
23 | import com.revosleap.proxima.ui.activities.PlayerActivity
24 | import com.revosleap.proxima.R
25 | import com.revosleap.proxima.services.MusicPlayerService
26 | import com.revosleap.proxima.utils.utils.Universal
27 |
28 | class BXNotificationManager internal constructor(private val musicPlayerService: MusicPlayerService) {
29 | private val channelId = "com.revosleap.proxima.channelId"
30 | private val requestCode = 100
31 | val notificationManager: NotificationManager = musicPlayerService.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
32 | private var mediaSession: MediaSessionCompat? = null
33 | private var mediaSessionManager: MediaSessionManager? = null
34 | private var transportControls: MediaControllerCompat.TransportControls? = null
35 | var notificationBuilder: NotificationCompat.Builder? = null
36 | private set
37 | private val context: Context
38 |
39 | init {
40 | context = musicPlayerService.application
41 | }
42 |
43 | private fun playerAction(action: String): PendingIntent {
44 |
45 | val pauseIntent = Intent()
46 | pauseIntent.action = action
47 |
48 | return PendingIntent.getBroadcast(musicPlayerService, requestCode, pauseIntent, PendingIntent.FLAG_UPDATE_CURRENT)
49 | }
50 |
51 | private fun notificationAction(action: String): NotificationCompat.Action {
52 |
53 | val icon: Int
54 |
55 | icon = when (action) {
56 | PREV_ACTION -> R.drawable.previous
57 | PLAY_PAUSE_ACTION ->
58 |
59 | if (musicPlayerService.mediaPlayerHolder?.getState() != PlaybackInfoListener.State.PAUSED)
60 | R.drawable.pause
61 | else
62 | R.drawable.play_icon
63 | NEXT_ACTION -> R.drawable.next
64 | else -> R.drawable.previous
65 | }
66 | return NotificationCompat.Action.Builder(icon, action, playerAction(action)).build()
67 | }
68 |
69 | fun createNotification(): Notification {
70 |
71 | val song = musicPlayerService.mediaPlayerHolder?.getCurrentSong()
72 |
73 | notificationBuilder = NotificationCompat.Builder(musicPlayerService, channelId)
74 |
75 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
76 | createNotificationChannel()
77 | }
78 |
79 | val openPlayerIntent = Intent(musicPlayerService, PlayerActivity::class.java)
80 | openPlayerIntent.action =Universal.infoAction
81 | openPlayerIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
82 | val contentIntent = PendingIntent.getActivity(musicPlayerService, requestCode,
83 | openPlayerIntent, 0)
84 | updateMetaData(song!!)
85 | val artist = song.artist
86 | val songTitle = song.title
87 | notificationBuilder!!
88 | .setShowWhen(false)
89 | .setSmallIcon(R.drawable.ic_if_speaker)
90 | .setLargeIcon(AudioUtils.cover(song.path!!,context))
91 | .setColor(context.resources.getColor(R.color.colorAccentLight))
92 | .setContentTitle(songTitle)
93 | .setContentText(artist)
94 | .setContentIntent(contentIntent)
95 | .addAction(notificationAction(PREV_ACTION))
96 | .addAction(notificationAction(PLAY_PAUSE_ACTION))
97 | .addAction(notificationAction(NEXT_ACTION))
98 | .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
99 |
100 | notificationBuilder!!.setStyle(android.support.v4.media.app.NotificationCompat.MediaStyle()
101 | .setShowActionsInCompactView(0, 1, 2)
102 | .setMediaSession(mediaSession!!.sessionToken))
103 | return notificationBuilder!!.build()
104 | }
105 |
106 | @RequiresApi(26)
107 | private fun createNotificationChannel() {
108 |
109 | if (notificationManager.getNotificationChannel(channelId) == null) {
110 | val notificationChannel = NotificationChannel(channelId,
111 | musicPlayerService.getString(R.string.app_name),
112 | NotificationManager.IMPORTANCE_LOW)
113 |
114 | notificationChannel.description = musicPlayerService.getString(R.string.app_name)
115 |
116 | notificationChannel.enableLights(false)
117 | notificationChannel.enableVibration(false)
118 | notificationChannel.setShowBadge(false)
119 |
120 | notificationManager.createNotificationChannel(notificationChannel)
121 | }
122 | }
123 |
124 | private fun updateMetaData(mSelectedSong: Song) {
125 | mediaSession = MediaSessionCompat(context, "BXPlayer")
126 | mediaSession!!.setMetadata(MediaMetadataCompat.Builder()
127 | .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, AudioUtils.cover(mSelectedSong.path!!,context))
128 | .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, mSelectedSong.artist)
129 | .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, mSelectedSong.albumName)
130 | .putString(MediaMetadataCompat.METADATA_KEY_TITLE, mSelectedSong.title)
131 | .build())
132 | }
133 |
134 | @Throws(RemoteException::class)
135 | private fun initMediaSession(model: Song) {
136 | if (mediaSessionManager != null) return //mediaSessionManager exists
137 |
138 | mediaSessionManager = context.getSystemService(Context.MEDIA_SESSION_SERVICE) as MediaSessionManager
139 | // Create a new MediaSession
140 | mediaSession = MediaSessionCompat(context.applicationContext, "AudioPlayer")
141 | //Get MediaSessions transport controls
142 | transportControls = mediaSession!!.controller.transportControls
143 | //set MediaSession -> ready to receive media commands
144 | mediaSession!!.isActive = true
145 | //indicate that the MediaSession handles transport control commands
146 | // through its MediaSessionCompat.Callback.
147 | mediaSession!!.setFlags(MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
148 | updateMetaData(model)
149 | //Set mediaSession's MetaData
150 |
151 |
152 | }
153 |
154 | private fun getLargeIcon(image: Bitmap): Bitmap {
155 |
156 | // final VectorDrawable vectorDrawable = (VectorDrawable) musicPlayerService.getDrawable(R.drawable.cover2);
157 |
158 | val largeIconSize = context.resources.getDimensionPixelSize(R.dimen.notification_large_dim)
159 | val map = Bitmap.createBitmap(largeIconSize, largeIconSize, Bitmap.Config.ARGB_8888)
160 | val canvas = Canvas(map)
161 | canvas.drawColor(Color.TRANSPARENT)
162 | val bitmap = image.copy(Bitmap.Config.ARGB_8888, true)
163 | val height = bitmap.height
164 | val width = bitmap.width
165 | bitmap.width = width * 5 / 10
166 | bitmap.height = height * 5 / 10
167 | canvas.drawBitmap(map, 2f, 2f, null)
168 |
169 | return Bitmap.createScaledBitmap(image, 50, 50, true)
170 | }
171 |
172 | interface BitmapColors {
173 | fun setColors(color: Int)
174 | }
175 |
176 | companion object {
177 | const val NOTIFICATION_ID = 101
178 | internal const val PLAY_PAUSE_ACTION = "com.revosleap.proxima.PLAYPAUSE"
179 | const internal val NEXT_ACTION = "com.revosleap.proxima.NEXT"
180 | const internal val PREV_ACTION = "com.revosleap.proxima.PREV"
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/ui/fragments/FragmentTracks.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.ui.fragments
2 |
3 | import android.content.ComponentName
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.content.ServiceConnection
7 | import android.os.Bundle
8 | import android.os.Handler
9 | import android.os.IBinder
10 | import android.support.v4.app.Fragment
11 | import android.support.v7.widget.LinearLayoutManager
12 | import android.view.LayoutInflater
13 | import android.view.MenuItem
14 | import android.view.View
15 | import android.view.ViewGroup
16 | import android.widget.PopupMenu
17 | import com.revosleap.proxima.R
18 | import com.revosleap.proxima.callbacks.BXColor
19 | import com.revosleap.proxima.models.Song
20 | import com.revosleap.proxima.services.MusicPlayerService
21 | import com.revosleap.proxima.ui.activities.PlayerActivity
22 | import com.revosleap.proxima.utils.playback.BXNotificationManager
23 | import com.revosleap.proxima.utils.playback.PlaybackInfoListener
24 | import com.revosleap.proxima.callbacks.PlayerAdapter
25 | import com.revosleap.proxima.utils.utils.GetAudio
26 | import com.revosleap.proxima.utils.utils.PreferenceHelper
27 | import com.revosleap.proxima.utils.utils.Universal
28 | import com.revosleap.simpleadapter.SimpleAdapter
29 | import com.revosleap.simpleadapter.SimpleCallbacks
30 | import kotlinx.android.synthetic.main.fragment_tracks.*
31 | import kotlinx.android.synthetic.main.track.view.*
32 |
33 |
34 | class FragmentTracks : Fragment(), SimpleCallbacks,BXColor {
35 | private var serviceBound = false
36 | private var list = mutableListOf()
37 | private var mMusicService: MusicPlayerService? = null
38 | private var mIsBound: Boolean = false
39 | private var simpleAdapter: SimpleAdapter? = null
40 | private var mPlayerAdapter: PlayerAdapter? = null
41 | private var mMusicNotificationManager: BXNotificationManager? = null
42 | private var mPlaybackListener: PlaybackListener? = null
43 | private var preferenceHelper: PreferenceHelper? = null
44 | private var playerActivity:PlayerActivity?=null
45 | private var viewColor =0
46 | private val mConnection = object : ServiceConnection {
47 | override fun onServiceConnected(name: ComponentName, service: IBinder) {
48 | mMusicService = (service as MusicPlayerService.MusicBinder).serviceInstance
49 | mPlayerAdapter = mMusicService!!.mediaPlayerHolder
50 | mMusicNotificationManager = mMusicService!!.musicNotificationManager
51 | if (mPlaybackListener == null) {
52 | mPlaybackListener = PlaybackListener()
53 | mPlayerAdapter!!.setPlaybackInfoListener(mPlaybackListener!!)
54 | }
55 | }
56 |
57 | override fun onServiceDisconnected(name: ComponentName) {
58 | mMusicService = null
59 | }
60 | }
61 |
62 | override fun onAttach(context: Context?) {
63 | super.onAttach(context)
64 | playerActivity= activity!! as PlayerActivity
65 | doBindService()
66 | }
67 |
68 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
69 | savedInstanceState: Bundle?): View? {
70 | val view = inflater.inflate(R.layout.fragment_tracks, container, false)
71 | list = GetAudio().geAllAudio(activity!!.baseContext)
72 | simpleAdapter = SimpleAdapter(R.layout.track, this)
73 | preferenceHelper = PreferenceHelper(activity!!)
74 | return view
75 | }
76 |
77 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
78 | super.onViewCreated(view, savedInstanceState)
79 | getSongList()
80 | trackRecycler.apply {
81 | adapter = simpleAdapter
82 | layoutManager = LinearLayoutManager(activity)
83 | hasFixedSize()
84 | }
85 | buttonListPlayAll.setOnClickListener {
86 | onSongSelected(list[0], list)
87 | }
88 | buttonListShuffle.setOnClickListener {
89 | list.shuffle()
90 | onSongSelected(list[0], list)
91 | }
92 | buttonListSort.setOnClickListener {
93 | getSorting(it)
94 | }
95 | if (viewColor!=0){
96 | setColors(viewColor)
97 | }
98 | }
99 |
100 | override fun onResume() {
101 | super.onResume()
102 | if (viewColor!=0){
103 | setColors(viewColor)
104 | }
105 | }
106 |
107 | override fun onSaveInstanceState(outState: Bundle) {
108 | super.onSaveInstanceState(outState)
109 | outState.putBoolean("serviceStatus", serviceBound)
110 | }
111 |
112 | override fun onDestroy() {
113 | super.onDestroy()
114 | super.onDestroy()
115 | mPlaybackListener = null
116 | doUnbindService()
117 | }
118 | override fun songColor(color: Int) {
119 | viewColor = color
120 | setColors(color)
121 |
122 | }
123 | private fun setColors(color: Int){
124 | buttonListSort?.setColorFilter(color)
125 | buttonListShuffle?.setColorFilter(color)
126 | buttonListPlayAll?.setColorFilter(color)
127 | }
128 | private fun onSongSelected(song: Song, songs:MutableList) {
129 | mPlayerAdapter!!.setCurrentSong(song, songs)
130 | mPlayerAdapter!!.initMediaPlayer()
131 | mPlayerAdapter!!.getMediaPlayer()?.start()
132 | mMusicService!!.startForeground(BXNotificationManager.NOTIFICATION_ID,
133 | mMusicNotificationManager!!.createNotification())
134 |
135 |
136 | }
137 |
138 | override fun bindView(view: View, item: Any, position: Int) {
139 | item as Song
140 | val title = view.textViewTitleTrack
141 | val artist = view.textViewArtistTrack
142 | val image = view.imageView2
143 | artist.text = item.title
144 | title.text = item.artist
145 |
146 | }
147 |
148 | override fun onViewClicked(view: View, item: Any, position: Int) {
149 | onSongSelected(list[position], list)
150 | }
151 |
152 | override fun onViewLongClicked(it: View?, item: Any, position: Int) {
153 |
154 | }
155 |
156 | private fun getSongList() {
157 | val sortOrder = preferenceHelper?.sortingStyle
158 | if (sortOrder!!.isEmpty()) {
159 | simpleAdapter?.addManyItems(list.toMutableList())
160 | }
161 | if (sortOrder == Universal.SORT_BY_ARTIST) {
162 | val sorted = list.sortedWith(compareBy { it.artist })
163 | simpleAdapter?.changeItems(sorted.toMutableList())
164 | list = sorted.toMutableList()
165 | }
166 | if (sortOrder == Universal.SORT_BY_TITLE) {
167 | val sorted = list.sortedWith(compareBy { it.title })
168 | simpleAdapter?.changeItems(sorted.toMutableList())
169 | list = sorted.toMutableList()
170 | }
171 | if (sortOrder == Universal.SORT_BY_YEAR) {
172 | val dateSorted = list.sortedWith(compareBy { it.songYear })
173 | simpleAdapter?.changeItems(dateSorted.toMutableList())
174 | list = dateSorted.toMutableList()
175 | }
176 | }
177 |
178 | private fun getSorting(view: View) {
179 | val menu = PopupMenu(activity!!, view)
180 | menu.menuInflater.inflate(R.menu.track_sorting, menu.menu)
181 | menu.show()
182 | menu.setOnMenuItemClickListener(object : PopupMenu.OnMenuItemClickListener {
183 | override fun onMenuItemClick(p0: MenuItem?): Boolean {
184 | when (p0?.itemId) {
185 | R.id.item_artist -> {
186 | preferenceHelper?.sortingStyle = Universal.SORT_BY_ARTIST
187 | val sorted = list.sortedWith(compareBy { it.artist })
188 | simpleAdapter?.changeItems(sorted.toMutableList())
189 | list = sorted.toMutableList()
190 | }
191 | R.id.item_date -> {
192 | preferenceHelper?.sortingStyle = Universal.SORT_BY_YEAR
193 | val dateSorted = list.sortedWith(compareBy { it.songYear })
194 | simpleAdapter?.changeItems(dateSorted.toMutableList())
195 | list = dateSorted.toMutableList()
196 | }
197 | R.id.item_title -> {
198 | preferenceHelper?.sortingStyle = Universal.SORT_BY_TITLE
199 | val sorted = list.sortedWith(compareBy { it.title })
200 | simpleAdapter?.changeItems(sorted.toMutableList())
201 | list = sorted.toMutableList()
202 | }
203 |
204 |
205 | }
206 | return true
207 | }
208 | })
209 | }
210 |
211 | private fun doBindService() {
212 | activity!!.bindService(Intent(activity,
213 | MusicPlayerService::class.java), mConnection, Context.BIND_AUTO_CREATE)
214 | mIsBound = true
215 |
216 | val startNotStickyIntent = Intent(activity, MusicPlayerService::class.java)
217 | activity!!.startService(startNotStickyIntent)
218 | }
219 |
220 | private fun doUnbindService() {
221 | if (mIsBound) {
222 | // Detach our existing connection.
223 | activity!!.unbindService(mConnection)
224 | mIsBound = false
225 | }
226 | }
227 |
228 | internal inner class PlaybackListener : PlaybackInfoListener() {
229 |
230 | override fun onPositionChanged(position: Int) {
231 |
232 | }
233 |
234 | override fun onStateChanged(@State state: Int) {
235 | if (mPlayerAdapter?.getState() != State.RESUMED && mPlayerAdapter?.getState() != State.PAUSED) {
236 | updatePlayingInfo(false, startPlay = true)
237 | }
238 | }
239 |
240 | override fun onPlaybackCompleted() {
241 |
242 | }
243 | }
244 |
245 | private fun updatePlayingInfo(restore: Boolean, startPlay: Boolean) {
246 | if (startPlay) {
247 | mPlayerAdapter!!.getMediaPlayer()?.start()
248 | Handler().postDelayed({
249 | mMusicService!!.startForeground(BXNotificationManager.NOTIFICATION_ID,
250 | mMusicNotificationManager!!.createNotification())
251 | }, 250)
252 | }
253 | val song =mPlayerAdapter?.getCurrentSong()!!
254 | playerActivity?.updatePlaying(song)
255 | if (restore) {
256 | Handler().postDelayed({
257 | //stop foreground if coming from pause state
258 | if (mMusicService!!.isRestoredFromPause) {
259 | mMusicService!!.stopForeground(false)
260 | mMusicService!!.musicNotificationManager?.notificationManager!!
261 | .notify(BXNotificationManager.NOTIFICATION_ID,
262 | mMusicService!!.musicNotificationManager?.notificationBuilder?.build())
263 | mMusicService!!.isRestoredFromPause = false
264 | }
265 | }, 250)
266 | }
267 | }
268 | // val retriever = MediaMetadataRetriever()
269 | // val inputStream: InputStream?
270 | // retriever.setDataSource(path)
271 | // if (retriever.embeddedPicture != null) {
272 | // inputStream = ByteArrayInputStream(retriever.embeddedPicture)
273 | // Glide.with(holder.itemView.context).load(inputStream)
274 | // .into(holder.trackImage)
275 | // }
276 |
277 | }
278 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
32 |
33 |
46 |
47 |
54 |
55 |
56 |
57 |
73 |
74 |
87 |
88 |
100 |
101 |
115 |
116 |
128 |
129 |
130 |
142 |
143 |
156 |
157 |
167 |
168 |
179 |
180 |
192 |
193 |
205 |
206 |
218 |
219 |
231 |
232 |
244 |
245 |
--------------------------------------------------------------------------------
/app/src/main/java/com/revosleap/proxima/ui/fragments/FragmentInfo.kt:
--------------------------------------------------------------------------------
1 | package com.revosleap.proxima.ui.fragments
2 |
3 |
4 | import android.content.Context
5 | import android.content.res.ColorStateList
6 | import android.graphics.Bitmap
7 | import android.graphics.BitmapFactory
8 | import android.media.MediaMetadataRetriever
9 | import android.os.Build
10 | import android.os.Bundle
11 | import android.os.Handler
12 | import android.support.v4.app.Fragment
13 | import android.support.v7.graphics.Palette
14 | import android.support.v7.widget.LinearLayoutManager
15 | import android.view.LayoutInflater
16 | import android.view.View
17 | import android.view.ViewGroup
18 | import android.widget.SeekBar
19 | import android.widget.Toast
20 | import com.revosleap.proxima.R
21 | import com.revosleap.proxima.callbacks.BXColor
22 | import com.revosleap.proxima.callbacks.PlayerAdapter
23 | import com.revosleap.proxima.models.Song
24 | import com.revosleap.proxima.services.MusicPlayerService
25 | import com.revosleap.proxima.ui.activities.PlayerActivity
26 | import com.revosleap.proxima.utils.playback.BXNotificationManager
27 | import com.revosleap.proxima.utils.playback.PlaybackInfoListener
28 | import com.revosleap.proxima.utils.utils.EqualizerUtils
29 | import com.revosleap.proxima.utils.utils.UniversalUtils
30 | import com.revosleap.simpleadapter.SimpleAdapter
31 | import com.revosleap.simpleadapter.SimpleCallbacks
32 | import kotlinx.android.synthetic.main.current_songs_item.view.*
33 | import kotlinx.android.synthetic.main.fragment_info.*
34 | import org.jetbrains.anko.startService
35 | import java.io.ByteArrayInputStream
36 | import java.io.InputStream
37 |
38 |
39 | class FragmentInfo : Fragment(), View.OnClickListener, BXColor, SimpleCallbacks {
40 | private var mUserIsSeeking: Boolean = false
41 | private var mSelectedArtist: String? = null
42 | private var mPlayerAdapter: PlayerAdapter? = null
43 | private var mMusicService: MusicPlayerService? = null
44 | private var mMusicNotificationManager: BXNotificationManager? = null
45 | private var mPlaybackListener: PlaybackListener? = null
46 | private var playerActivity: PlayerActivity? = null
47 | private var simpleAdapter: SimpleAdapter? = null
48 | private var currentPlayList = mutableListOf()
49 | var isPlayListShown = false
50 | override fun onAttach(context: Context?) {
51 | super.onAttach(context)
52 | getService()
53 | playerActivity = activity!! as PlayerActivity
54 | playerActivity?.setColorCallback(this)
55 | }
56 |
57 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
58 | savedInstanceState: Bundle?): View? {
59 | simpleAdapter = SimpleAdapter(R.layout.current_songs_item, this)
60 | return inflater.inflate(R.layout.fragment_info, container, false)
61 | }
62 |
63 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
64 | super.onViewCreated(view, savedInstanceState)
65 | setClickListeners()
66 | initializeSeekBar()
67 | showPlaylist()
68 | mPlaybackListener?.onStateChanged(PlaybackInfoListener.State.PLAYING)
69 | }
70 |
71 | override fun onResume() {
72 | super.onResume()
73 | getService()
74 | activity?.startService()
75 | mPlayerAdapter!!.getMediaPlayer()?.start()
76 | mMusicService!!.startForeground(BXNotificationManager.NOTIFICATION_ID,
77 | mMusicNotificationManager!!.createNotification())
78 | }
79 |
80 | override fun bindView(view: View, item: Any, position: Int) {
81 | item as Song
82 | val title = view.textViewTitleCurrent
83 | val artist = view.textViewCurrentArtist
84 | title.text = item.title
85 | artist.text = item.artist
86 | }
87 |
88 | override fun onViewClicked(view: View, item: Any, position: Int) {
89 | onSongSelected(currentPlayList[position], currentPlayList)
90 | }
91 |
92 | override fun onViewLongClicked(it: View?, item: Any, position: Int) {
93 |
94 | }
95 |
96 | private fun onSongSelected(song: Song, songs: MutableList) {
97 | mPlayerAdapter?.setCurrentSong(song, songs)
98 | mPlayerAdapter?.initMediaPlayer()
99 | mPlayerAdapter?.getMediaPlayer()?.start()
100 | mMusicService?.startForeground(BXNotificationManager.NOTIFICATION_ID,
101 | mMusicNotificationManager?.createNotification())
102 |
103 |
104 | }
105 |
106 | override fun songColor(color: Int) {
107 | buttonInfoPlaylist?.setColorFilter(color)
108 | buttonInfoPlay?.setColorFilter(color)
109 | buttonInfoAll?.setColorFilter(color)
110 | buttonInfoFave?.setColorFilter(color)
111 | buttonInfoVol?.setColorFilter(color)
112 | seekBarInfo?.progressBackgroundTintList = ColorStateList.valueOf(color)
113 | buttonInfoShuffle?.setColorFilter(color)
114 | buttonInfoNext?.setColorFilter(color)
115 | buttonInfoPrev?.setColorFilter(color)
116 | }
117 |
118 | private fun getBxColor(bitmap: Bitmap) {
119 | var color: Int
120 | color = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
121 | activity?.resources!!.getColor(R.color.colorAccent, null)
122 | } else activity?.resources!!.getColor(R.color.colorAccent)
123 | Palette.from(bitmap).generate { palette ->
124 | val vibrant = palette?.lightVibrantSwatch
125 | try {
126 | color = vibrant?.rgb!!
127 | songColor(color)
128 | playerActivity?.setViewColors(color)
129 | } catch (e: Exception) {
130 | }
131 | }
132 |
133 |
134 | }
135 |
136 | private fun showPlaylist() {
137 | recyclerViewCurrent.apply {
138 | adapter = simpleAdapter
139 | layoutManager = LinearLayoutManager(playerActivity)
140 | hasFixedSize()
141 | }
142 |
143 |
144 | }
145 |
146 | private fun getService() {
147 | val playerActivity = activity as PlayerActivity
148 | mMusicService = playerActivity.getPlayerService()
149 | if (mMusicService != null) {
150 | mPlayerAdapter = mMusicService!!.mediaPlayerHolder
151 | mMusicNotificationManager = mMusicService!!.musicNotificationManager
152 | }
153 | if (mPlaybackListener == null) {
154 | mPlaybackListener = PlaybackListener()
155 | mPlayerAdapter?.setPlaybackInfoListener(mPlaybackListener!!)
156 | }
157 | }
158 |
159 | private fun initializeSeekBar() {
160 | seekBarInfo.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
161 | var userSelectedPosition = 0
162 |
163 | override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
164 | if (fromUser) {
165 | userSelectedPosition = progress
166 |
167 | }
168 | textViewProgress?.text = UniversalUtils.formatTime(progress.toLong())
169 | }
170 |
171 | override fun onStartTrackingTouch(seekBar: SeekBar) {
172 | mUserIsSeeking = true
173 | }
174 |
175 | override fun onStopTrackingTouch(seekBar: SeekBar) {
176 | if (mUserIsSeeking) {
177 | // mSongPosition.setTextColor(currentPositionColor);
178 | }
179 | mUserIsSeeking = false
180 | mPlayerAdapter!!.seekTo(userSelectedPosition)
181 | }
182 | })
183 | }
184 |
185 | private fun updatePlayingStatus() {
186 | val drawable = if (mPlayerAdapter?.getState() != PlaybackInfoListener.State.PAUSED)
187 | R.drawable.pause
188 | else
189 | R.drawable.play_icon
190 | try {
191 | buttonInfoPlay.setImageDrawable(activity?.getDrawable(drawable))
192 |
193 | } catch (e: Exception) {
194 | e.printStackTrace()
195 | }
196 |
197 | }
198 |
199 | private fun updatePlayingInfo(restore: Boolean, startPlay: Boolean) {
200 |
201 |
202 | if (startPlay) {
203 | mPlayerAdapter?.getMediaPlayer()?.start()
204 | Handler().postDelayed({
205 | mMusicService!!.startForeground(BXNotificationManager.NOTIFICATION_ID,
206 | mMusicNotificationManager!!.createNotification())
207 | }, 250)
208 | }
209 | currentPlayList = mPlayerAdapter?.getCurrentSongs()!!
210 | simpleAdapter?.addManyItems(currentPlayList.toMutableList())
211 | val selectedSong = mPlayerAdapter?.getCurrentSong()
212 | mSelectedArtist = selectedSong?.artist
213 | val duration = selectedSong?.duration
214 | seekBarInfo?.max = duration?.toInt()!!
215 | textViewDuration?.text = UniversalUtils.formatTime(duration)
216 | textViewInfoTitle?.text = selectedSong.title
217 | textViewInfoArtist?.text = selectedSong.artist
218 | val retriever = MediaMetadataRetriever()
219 | val inputStream: InputStream?
220 | retriever.setDataSource(selectedSong.path)
221 |
222 | if (retriever.embeddedPicture != null) {
223 | inputStream = ByteArrayInputStream(retriever.embeddedPicture)
224 | val image = BitmapFactory.decodeStream(inputStream)
225 | imageViewInfo?.setImageBitmap(image)
226 | try {
227 | playerActivity?.updatePlaying(selectedSong)
228 | getBxColor(image)
229 | } catch (e: Exception) {
230 | }
231 |
232 | } else {
233 | val image = BitmapFactory.decodeResource(playerActivity?.resources!!, R.drawable.cover2)
234 | imageViewInfo?.setImageBitmap(image)
235 | try {
236 | playerActivity?.updatePlaying(selectedSong)
237 | getBxColor(image)
238 | } catch (e: Exception) {
239 | }
240 | }
241 |
242 |
243 | if (restore) {
244 | seekBarInfo?.progress = mPlayerAdapter?.getPlayerPosition()!!
245 | updatePlayingStatus()
246 |
247 | }
248 |
249 | }
250 |
251 | override fun onClick(v: View) {
252 | when (v.id) {
253 | R.id.buttonInfoPlaylist -> {
254 | showThisPlayList()
255 | }
256 | R.id.buttonInfoFave -> {
257 | }
258 | R.id.buttonInfoVol -> {
259 | }
260 | R.id.buttonInfoShuffle -> {
261 | mPlayerAdapter?.shufflePlayList()
262 | }
263 | R.id.buttonInfoPrev -> skipPrev()
264 | R.id.buttonInfoPlay -> resumeOrPause()
265 | R.id.buttonInfoNext -> skipNext()
266 | R.id.buttonInfoAll -> {
267 | }
268 | }
269 | }
270 |
271 | private fun showThisPlayList() {
272 | val song = mPlayerAdapter?.getCurrentSong()!!
273 | val position = currentPlayList.indexOf(song)
274 | if (!isPlayListShown) {
275 | recyclerViewCurrent?.visibility = View.VISIBLE
276 | constraintLayout2?.visibility = View.GONE
277 | recyclerViewCurrent.scrollToPosition(position)
278 | isPlayListShown = true
279 | playerActivity?.togglePlaylist(true)
280 | }
281 | }
282 |
283 | fun togglePlayList() {
284 | if (isPlayListShown) {
285 | recyclerViewCurrent?.visibility = View.GONE
286 | constraintLayout2?.visibility = View.VISIBLE
287 | isPlayListShown = false
288 | playerActivity?.togglePlaylist(false)
289 | }
290 | }
291 |
292 | private fun setClickListeners() {
293 | buttonInfoAll.setOnClickListener(this)
294 | buttonInfoFave.setOnClickListener(this)
295 | buttonInfoNext.setOnClickListener(this)
296 | buttonInfoPlay.setOnClickListener(this)
297 | buttonInfoPlaylist.setOnClickListener(this)
298 | buttonInfoPrev.setOnClickListener(this)
299 | buttonInfoShuffle.setOnClickListener(this)
300 | buttonInfoVol.setOnClickListener(this)
301 | }
302 |
303 | internal inner class PlaybackListener : PlaybackInfoListener() {
304 |
305 | override fun onPositionChanged(position: Int) {
306 | if (!mUserIsSeeking) {
307 | seekBarInfo?.progress = position
308 | }
309 | }
310 |
311 | override fun onStateChanged(@State state: Int) {
312 | updatePlayingStatus()
313 | if (mPlayerAdapter?.getState() != PlaybackInfoListener.State.RESUMED && mPlayerAdapter?.getState() != PlaybackInfoListener.State.PAUSED) {
314 | updatePlayingInfo(restore = false, startPlay = true)
315 | }
316 | if (state == PlaybackInfoListener.State.PLAYING) {
317 | updatePlayingInfo(restore = true, startPlay = false)
318 |
319 | }
320 | }
321 |
322 | override fun onPlaybackCompleted() {
323 | //updateResetStatus(true);
324 | }
325 | }
326 |
327 | private fun checkIsPlayer(): Boolean {
328 |
329 | val isPlayer = mPlayerAdapter?.isMediaPlayer()
330 | if (!isPlayer!!) {
331 | EqualizerUtils.notifyNoSessionId(activity!!)
332 | }
333 | return isPlayer
334 | }
335 |
336 | private fun skipPrev() {
337 | if (checkIsPlayer()) {
338 | mPlayerAdapter?.instantReset()
339 | }
340 | }
341 |
342 | private fun resumeOrPause() {
343 | if (checkIsPlayer()) {
344 | mPlayerAdapter?.resumeOrPause()
345 | }
346 | }
347 |
348 | private fun skipNext() {
349 | if (checkIsPlayer()) {
350 | mPlayerAdapter!!.skip(true)
351 | }
352 | }
353 |
354 | fun openEqualizer() {
355 | if (EqualizerUtils.hasEqualizer(activity!!)) {
356 | if (checkIsPlayer()) {
357 | mPlayerAdapter?.openEqualizer(activity!!)
358 | }
359 | } else {
360 | Toast.makeText(activity, "No equalizer found", Toast.LENGTH_SHORT).show()
361 | }
362 | }
363 |
364 |
365 | }
366 |
--------------------------------------------------------------------------------