├── .gitignore
├── .idea
├── .gitignore
├── .name
├── compiler.xml
├── deploymentTargetSelector.xml
├── gradle.xml
├── kotlinc.xml
├── migrations.xml
├── misc.xml
└── other.xml
├── README.md
├── app
├── .gitignore
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── harshRajpurohit
│ │ └── musicPlayer
│ │ ├── AboutActivity.kt
│ │ ├── ApplicationClass.kt
│ │ ├── FavouriteActivity.kt
│ │ ├── FavouriteAdapter.kt
│ │ ├── FeedbackActivity.kt
│ │ ├── MainActivity.kt
│ │ ├── Music.kt
│ │ ├── MusicAdapter.kt
│ │ ├── MusicService.kt
│ │ ├── NotificationReceiver.kt
│ │ ├── NowPlaying.kt
│ │ ├── PlayNext.kt
│ │ ├── PlayerActivity.kt
│ │ ├── PlaylistActivity.kt
│ │ ├── PlaylistDetails.kt
│ │ ├── PlaylistViewAdapter.kt
│ │ ├── SelectionActivity.kt
│ │ └── SettingsActivity.kt
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ ├── about_icon.xml
│ ├── add_icon.xml
│ ├── back_icon.xml
│ ├── booster_icon.xml
│ ├── circle_icon.xml
│ ├── custom_search_view.xml
│ ├── delete_icon.xml
│ ├── equalizer_icon.xml
│ ├── exit_icon.xml
│ ├── favourite_empty_icon.xml
│ ├── favourite_icon.xml
│ ├── feedback_icon.xml
│ ├── gradient_black.xml
│ ├── gradient_blue.xml
│ ├── gradient_green.xml
│ ├── gradient_pink.xml
│ ├── gradient_purple.xml
│ ├── ic_launcher_background.xml
│ ├── ic_launcher_foreground.xml
│ ├── music_icon.xml
│ ├── music_player_icon_slash_screen.png
│ ├── next_icon.xml
│ ├── pause_icon.xml
│ ├── play_icon.xml
│ ├── play_next_icon.xml
│ ├── playlist_icon.xml
│ ├── previous_icon.xml
│ ├── remove_icon.xml
│ ├── repeat_icon.xml
│ ├── scroll_bar_icon.xml
│ ├── search_icon.xml
│ ├── settings_icon.xml
│ ├── share_icon.xml
│ ├── shuffle_icon.xml
│ ├── sort_icon.xml
│ ├── splash_screen.xml
│ ├── timer_icon.xml
│ └── volume_icon.xml
│ ├── layout
│ ├── activity_about.xml
│ ├── activity_favourite.xml
│ ├── activity_feedback.xml
│ ├── activity_main.xml
│ ├── activity_play_next.xml
│ ├── activity_player.xml
│ ├── activity_playlist.xml
│ ├── activity_playlist_details.xml
│ ├── activity_selection.xml
│ ├── activity_settings.xml
│ ├── add_playlist_dialog.xml
│ ├── audio_booster.xml
│ ├── bottom_sheet_dialog.xml
│ ├── details_view.xml
│ ├── favourite_view.xml
│ ├── fragment_now_playing.xml
│ ├── more_features.xml
│ ├── music_view.xml
│ ├── nav_header.xml
│ └── playlist_view.xml
│ ├── menu
│ ├── nav_menu.xml
│ └── search_view_menu.xml
│ ├── mipmap-anydpi-v26
│ ├── music_player_icon.xml
│ └── music_player_icon_round.xml
│ ├── mipmap-hdpi
│ ├── music_player_icon.png
│ ├── music_player_icon_foreground.png
│ └── music_player_icon_round.png
│ ├── mipmap-mdpi
│ ├── music_player_icon.png
│ ├── music_player_icon_foreground.png
│ └── music_player_icon_round.png
│ ├── mipmap-xhdpi
│ ├── music_player_icon.png
│ ├── music_player_icon_foreground.png
│ └── music_player_icon_round.png
│ ├── mipmap-xxhdpi
│ ├── music_player_icon.png
│ ├── music_player_icon_foreground.png
│ └── music_player_icon_round.png
│ ├── mipmap-xxxhdpi
│ ├── music_player_icon.png
│ ├── music_player_icon_foreground.png
│ └── music_player_icon_round.png
│ ├── values-night
│ └── themes.xml
│ ├── values
│ ├── colors.xml
│ ├── custom_styles.xml
│ ├── music_player_icon_background.xml
│ ├── strings.xml
│ └── themes.xml
│ └── xml
│ ├── backup_rules.xml
│ └── data_extraction_rules.xml
├── build.gradle.kts
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── music_player_screenshots
├── Music Player v2.0.1 04-07-2024.apk
├── screen_1.png
├── screen_2.png
├── screen_3.png
├── screen_4.png
├── screen_5.png
├── screen_6.png
├── screen_7.png
└── screen_8.png
└── settings.gradle.kts
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | Music Player
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/deploymentTargetSelector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/migrations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/other.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 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MusicPlayer
2 |
3 |  
4 |
5 | **A Simple Yet Feature-Rich Music Player Application based on Native MediaPlayer.**
6 |
7 | ---
8 |
9 | ## 📦 APK Download
10 |
11 | Try it yourself and I’d love to hear your feedback 🙂:
12 |
13 | - [Download APK v2.0.0](https://drive.google.com/file/d/1HVmzkB4hSVR9_EcPAaj-VuQ4wbKfjsPj/view?usp=sharing)
14 |
15 | ---
16 |
17 | ## 📸 Screenshots
18 |
19 | **Actual app looks even better! 😃**
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | ---
33 |
34 | ## ✨ Features
35 |
36 | - **Play/Pause Audio** using earphones.
37 | - **Play Next** feature—schedule upcoming songs.
38 | - **Dark Theme** with black theme option in settings.
39 | - **Custom Color Gradient** for each song based on album art.
40 | - **Favorite Songs** for easy access.
41 | - **Create & Manage Playlists**.
42 | - **Sleep Timer** for auto-shutdown.
43 | - **Audio Booster** and **Built-in Equalizer**.
44 | - **Custom Themes** for personalization.
45 | - **Swipe to Refresh** UI.
46 | - **Background Playback** with custom notifications.
47 | - Android 10 **notification with seek bar**.
48 | - Clean and modern UI with **Material Design Widgets**.
49 | - **And much more...**
50 |
51 | ---
52 |
53 | ## 🎥 YouTube Course
54 |
55 | Watch the full YouTube playlist:
56 | [Watch on YouTube](https://youtube.com/playlist?list=PL8kbUJtS6hyaRM3LhIYOqIXK7LIoEJ4Qf)
57 |
58 | ---
59 |
60 | ## 💡 Note
61 |
62 | This project is much more improved and optimized than the YouTube course project, with new features and better performance.
63 |
64 | ---
65 |
66 | ## 💬 Feedback and Suggestions
67 |
68 | For any feedback or suggestions, feel free to contact me via email:
69 | 📧 [rajpurohitharsh2020@gmail.com](mailto:rajpurohitharsh2020@gmail.com)
70 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.android.application)
3 | alias(libs.plugins.jetbrains.kotlin.android)
4 | }
5 |
6 | android {
7 | namespace = "com.harshRajpurohit.musicPlayer"
8 | compileSdk = 34
9 |
10 | defaultConfig {
11 | applicationId = "com.harshRajpurohit.musicPlayer"
12 | minSdk = 21
13 | targetSdk = 34
14 | versionCode = 11
15 | versionName = "2.0.1"
16 |
17 | // For showing build version name
18 | buildConfigField("String", "VERSION_NAME", "\"$versionName\"")
19 | }
20 |
21 | buildTypes {
22 | release {
23 | isMinifyEnabled = false
24 | proguardFiles(
25 | getDefaultProguardFile("proguard-android-optimize.txt"),
26 | "proguard-rules.pro"
27 | )
28 | }
29 | }
30 | compileOptions {
31 | sourceCompatibility = JavaVersion.VERSION_1_8
32 | targetCompatibility = JavaVersion.VERSION_1_8
33 | }
34 | kotlinOptions {
35 | jvmTarget = "1.8"
36 | }
37 |
38 | buildFeatures{
39 | // For viewBinding
40 | viewBinding = true
41 |
42 | // For showing build version name
43 | buildConfig = true
44 | }
45 | }
46 |
47 | dependencies {
48 | implementation(libs.androidx.core.ktx)
49 | implementation(libs.androidx.appcompat)
50 | implementation(libs.material)
51 | implementation(libs.androidx.activity)
52 | implementation(libs.androidx.constraintlayout)
53 |
54 | // Pull to Refresh
55 | implementation(libs.legacy.support)
56 |
57 | // Glide for image loading
58 | implementation(libs.glide)
59 |
60 | // For storing objects in shared preferences
61 | implementation(libs.gson)
62 |
63 | // Notification
64 | implementation(libs.androidx.media)
65 |
66 | // Vertical Seekbar
67 | implementation(libs.verticalseekbar)
68 |
69 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
28 |
29 |
32 |
33 |
38 |
39 |
44 |
45 |
50 |
51 |
56 |
57 |
62 |
63 |
68 |
69 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
86 |
87 |
88 |
89 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
109 |
110 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/AboutActivity.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.harshRajpurohit.musicPlayer.databinding.ActivityAboutBinding
6 |
7 | class AboutActivity : AppCompatActivity() {
8 |
9 | lateinit var binding: ActivityAboutBinding
10 |
11 | override fun onCreate(savedInstanceState: Bundle?) {
12 | super.onCreate(savedInstanceState)
13 | setTheme(MainActivity.currentThemeNav[MainActivity.themeIndex])
14 | binding = ActivityAboutBinding.inflate(layoutInflater)
15 | setContentView(binding.root)
16 | supportActionBar?.title = "About"
17 | binding.aboutText.text = aboutText()
18 | }
19 | private fun aboutText(): String{
20 | return "Developed By: Harsh H. Rajpurohit" +
21 | "\n\nIf you want to provide feedback, I will love to hear that."
22 | }
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/ApplicationClass.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | import android.app.Application
4 | import android.app.NotificationChannel
5 | import android.app.NotificationManager
6 | import android.os.Build
7 |
8 | class ApplicationClass:Application() {
9 | companion object{
10 | const val CHANNEL_ID = "MusicNotification"
11 | const val PLAY = "play"
12 | const val NEXT = "next"
13 | const val PREVIOUS = "previous"
14 | const val EXIT = "exit"
15 | }
16 | override fun onCreate() {
17 | super.onCreate()
18 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
19 | val notificationChannel = NotificationChannel(CHANNEL_ID, "Now Playing Song", NotificationManager.IMPORTANCE_HIGH)
20 | notificationChannel.description = "Needed to Show Notification for Playing Song"
21 | //for lockscreen -> test this and let me know.
22 | // notificationChannel.importance = NotificationManager.IMPORTANCE_HIGH
23 | // notificationChannel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
24 |
25 | val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
26 | notificationManager.createNotificationChannel(notificationChannel)
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/FavouriteActivity.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import android.view.View
7 | import androidx.appcompat.app.AppCompatActivity
8 | import androidx.recyclerview.widget.GridLayoutManager
9 | import com.harshRajpurohit.musicPlayer.databinding.ActivityFavouriteBinding
10 |
11 | class FavouriteActivity : AppCompatActivity() {
12 |
13 | private lateinit var binding: ActivityFavouriteBinding
14 | private lateinit var adapter: FavouriteAdapter
15 |
16 | companion object{
17 | var favouriteSongs: ArrayList = ArrayList()
18 | var favouritesChanged: Boolean = false
19 | }
20 |
21 | override fun onCreate(savedInstanceState: Bundle?) {
22 | super.onCreate(savedInstanceState)
23 | setTheme(MainActivity.currentTheme[MainActivity.themeIndex])
24 | binding = ActivityFavouriteBinding.inflate(layoutInflater)
25 | setContentView(binding.root)
26 | favouriteSongs = checkPlaylist(favouriteSongs)
27 | binding.backBtnFA.setOnClickListener { finish() }
28 | binding.favouriteRV.setHasFixedSize(true)
29 | binding.favouriteRV.setItemViewCacheSize(13)
30 | binding.favouriteRV.layoutManager = GridLayoutManager(this, 4)
31 | adapter = FavouriteAdapter(this, favouriteSongs)
32 | binding.favouriteRV.adapter = adapter
33 |
34 | favouritesChanged = false
35 |
36 | if(favouriteSongs.size < 1) binding.shuffleBtnFA.visibility = View.INVISIBLE
37 |
38 | if(favouriteSongs.isNotEmpty()) binding.instructionFV.visibility = View.GONE
39 |
40 | binding.shuffleBtnFA.setOnClickListener {
41 | val intent = Intent(this, PlayerActivity::class.java)
42 | intent.putExtra("index", 0)
43 | intent.putExtra("class", "FavouriteShuffle")
44 | startActivity(intent)
45 | }
46 | }
47 |
48 | @SuppressLint("NotifyDataSetChanged")
49 | override fun onResume() {
50 | super.onResume()
51 | if(favouritesChanged) {
52 | adapter.updateFavourites(favouriteSongs)
53 | favouritesChanged = false
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/FavouriteAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Activity
5 | import android.content.Context
6 | import android.content.Intent
7 | import android.graphics.drawable.ColorDrawable
8 | import android.view.LayoutInflater
9 | import android.view.ViewGroup
10 | import androidx.core.content.ContextCompat
11 | import androidx.recyclerview.widget.RecyclerView
12 | import com.bumptech.glide.Glide
13 | import com.bumptech.glide.request.RequestOptions
14 | import com.google.android.material.dialog.MaterialAlertDialogBuilder
15 | import com.google.android.material.snackbar.Snackbar
16 | import com.harshRajpurohit.musicPlayer.databinding.FavouriteViewBinding
17 | import com.harshRajpurohit.musicPlayer.databinding.MoreFeaturesBinding
18 |
19 | class FavouriteAdapter(private val context: Context, private var musicList: ArrayList,val playNext: Boolean = false) : RecyclerView.Adapter() {
20 |
21 | class MyHolder(binding: FavouriteViewBinding) : RecyclerView.ViewHolder(binding.root) {
22 | val image = binding.songImgFV
23 | val name = binding.songNameFV
24 | val root = binding.root
25 | }
26 |
27 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
28 | return MyHolder(FavouriteViewBinding.inflate(LayoutInflater.from(context), parent, false))
29 | }
30 |
31 | @SuppressLint("SetTextI18n")
32 | override fun onBindViewHolder(holder: MyHolder, position: Int) {
33 | holder.name.text = musicList[position].title
34 | Glide.with(context)
35 | .load(musicList[position].artUri)
36 | .apply(RequestOptions().placeholder(R.drawable.music_player_icon_slash_screen).centerCrop())
37 | .into(holder.image)
38 |
39 | //when play next music is clicked
40 | if(playNext){
41 | holder.root.setOnClickListener {
42 | val intent = Intent(context, PlayerActivity::class.java)
43 | intent.putExtra("index", position)
44 | intent.putExtra("class", "PlayNext")
45 | ContextCompat.startActivity(context, intent, null)
46 | }
47 | holder.root.setOnLongClickListener {
48 | val customDialog = LayoutInflater.from(context).inflate(R.layout.more_features, holder.root, false)
49 | val bindingMF = MoreFeaturesBinding.bind(customDialog)
50 | val dialog = MaterialAlertDialogBuilder(context).setView(customDialog)
51 | .create()
52 | dialog.show()
53 | dialog.window?.setBackgroundDrawable(ColorDrawable(0x99000000.toInt()))
54 | bindingMF.AddToPNBtn.text = "Remove"
55 | bindingMF.AddToPNBtn.setOnClickListener {
56 | if(position == PlayerActivity.songPosition)
57 | Snackbar.make((context as Activity).findViewById(R.id.linearLayoutPN),
58 | "Can't Remove Currently Playing Song.", Snackbar.LENGTH_SHORT).show()
59 | else{
60 | if(PlayerActivity.songPosition < position && PlayerActivity.songPosition != 0) --PlayerActivity.songPosition
61 | PlayNext.playNextList.removeAt(position)
62 | PlayerActivity.musicListPA.removeAt(position)
63 | notifyItemRemoved(position)
64 | }
65 | dialog.dismiss()
66 | }
67 | return@setOnLongClickListener true
68 | }
69 | }else{
70 | holder.root.setOnClickListener {
71 | val intent = Intent(context, PlayerActivity::class.java)
72 | intent.putExtra("index", position)
73 | intent.putExtra("class", "FavouriteAdapter")
74 | ContextCompat.startActivity(context, intent, null)
75 | }
76 | }
77 | }
78 |
79 | override fun getItemCount(): Int {
80 | return musicList.size
81 | }
82 |
83 | @SuppressLint("NotifyDataSetChanged")
84 | fun updateFavourites(newList: ArrayList){
85 | musicList = ArrayList()
86 | musicList.addAll(newList)
87 | notifyDataSetChanged()
88 | }
89 |
90 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/FeedbackActivity.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | //Not Used Now
4 |
5 | //import android.content.Context
6 | //import android.net.ConnectivityManager
7 | //import android.os.Bundle
8 | //import android.widget.Toast
9 | //import androidx.appcompat.app.AppCompatActivity
10 | //import com.harshRajpurohit.musicPlayer.databinding.ActivityFeedbackBinding
11 | //import java.util.*
12 | //import javax.mail.*
13 | //import javax.mail.internet.InternetAddress
14 | //import javax.mail.internet.MimeMessage
15 | //
16 | //class FeedbackActivity : AppCompatActivity() {
17 | //
18 | // lateinit var binding: ActivityFeedbackBinding
19 | //
20 | // override fun onCreate(savedInstanceState: Bundle?) {
21 | // super.onCreate(savedInstanceState)
22 | // setTheme(MainActivity.currentThemeNav[MainActivity.themeIndex])
23 | // binding = ActivityFeedbackBinding.inflate(layoutInflater)
24 | // setContentView(binding.root)
25 | // supportActionBar?.title = "Feedback"
26 | // binding.sendFA.setOnClickListener {
27 | // val feedbackMsg = binding.feedbackMsgFA.text.toString() + "\n" + binding.emailFA.text.toString()
28 | // val subject = binding.topicFA.text.toString()
29 | // val userName = "musicworldapp2021@gmail.com"
30 | // val pass = "musicWorldApp2021"
31 | // val cm = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
32 | // if(feedbackMsg.isNotEmpty() && subject.isNotEmpty() && (cm.activeNetworkInfo?.isConnectedOrConnecting == true)){
33 | // Thread{
34 | // try {
35 | // val properties = Properties()
36 | // properties["mail.smtp.auth"] = "true"
37 | // properties["mail.smtp.starttls.enable"] = "true"
38 | // properties["mail.smtp.host"] = "smtp.gmail.com"
39 | // properties["mail.smtp.port"] = "587"
40 | // val session = Session.getInstance(properties, object : Authenticator(){
41 | // override fun getPasswordAuthentication(): PasswordAuthentication {
42 | // return PasswordAuthentication(userName, pass)
43 | // }
44 | // })
45 | // val mail = MimeMessage(session)
46 | // mail.subject = subject
47 | // mail.setText(feedbackMsg)
48 | // mail.setFrom(InternetAddress(userName))
49 | // mail.setRecipients(Message.RecipientType.TO, InternetAddress.parse(userName))
50 | // Transport.send(mail)
51 | // }catch (e: Exception){Toast.makeText(this, e.toString(), Toast.LENGTH_SHORT).show()}
52 | // }.start()
53 | // Toast.makeText(this, "Thanks For Feedback!!", Toast.LENGTH_SHORT).show()
54 | // finish()
55 | // }
56 | // else Toast.makeText(this, "Went Something Wrong!!", Toast.LENGTH_SHORT).show()
57 | // }
58 | // }
59 | //}
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/Music.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | import android.content.Context
4 | import android.graphics.Bitmap
5 | import android.graphics.Color
6 | import android.media.MediaMetadataRetriever
7 | import androidx.appcompat.app.AlertDialog
8 | import com.google.android.material.color.MaterialColors
9 | import java.io.File
10 | import java.util.concurrent.TimeUnit
11 | import kotlin.system.exitProcess
12 |
13 |
14 | data class Music(
15 | val id: String,
16 | val title: String,
17 | val album: String,
18 | val artist: String,
19 | val duration: Long = 0,
20 | val path: String,
21 | val artUri: String
22 | )
23 |
24 | class Playlist {
25 | lateinit var name: String
26 | lateinit var playlist: ArrayList
27 | lateinit var createdBy: String
28 | lateinit var createdOn: String
29 | }
30 |
31 | class MusicPlaylist {
32 | var ref: ArrayList = ArrayList()
33 | }
34 |
35 | fun formatDuration(duration: Long): String {
36 | val minutes = TimeUnit.MINUTES.convert(duration, TimeUnit.MILLISECONDS)
37 | val seconds = (TimeUnit.SECONDS.convert(duration, TimeUnit.MILLISECONDS) -
38 | minutes * TimeUnit.SECONDS.convert(1, TimeUnit.MINUTES))
39 | return String.format("%02d:%02d", minutes, seconds)
40 | }
41 |
42 | fun getImgArt(path: String): ByteArray? {
43 | val retriever = MediaMetadataRetriever()
44 | retriever.setDataSource(path)
45 | return retriever.embeddedPicture
46 | }
47 |
48 | fun setSongPosition(increment: Boolean) {
49 | if (!PlayerActivity.repeat) {
50 | if (increment) {
51 | if (PlayerActivity.musicListPA.size - 1 == PlayerActivity.songPosition)
52 | PlayerActivity.songPosition = 0
53 | else ++PlayerActivity.songPosition
54 | } else {
55 | if (0 == PlayerActivity.songPosition)
56 | PlayerActivity.songPosition = PlayerActivity.musicListPA.size - 1
57 | else --PlayerActivity.songPosition
58 | }
59 | }
60 | }
61 |
62 | fun exitApplication() {
63 | if (PlayerActivity.musicService != null) {
64 | PlayerActivity.musicService!!.audioManager.abandonAudioFocus(PlayerActivity.musicService)
65 | PlayerActivity.musicService!!.stopForeground(true)
66 | PlayerActivity.musicService!!.mediaPlayer!!.release()
67 | PlayerActivity.musicService = null
68 | }
69 | exitProcess(1)
70 | }
71 |
72 | fun favouriteChecker(id: String): Int {
73 | PlayerActivity.isFavourite = false
74 | FavouriteActivity.favouriteSongs.forEachIndexed { index, music ->
75 | if (id == music.id) {
76 | PlayerActivity.isFavourite = true
77 | return index
78 | }
79 | }
80 | return -1
81 | }
82 |
83 | fun checkPlaylist(playlist: ArrayList): ArrayList {
84 | val indicesToRemove = mutableListOf()
85 |
86 | playlist.forEachIndexed { index, music ->
87 | if (!File(music.path).exists()) indicesToRemove.add(index)
88 | }
89 |
90 | indicesToRemove.sortDescending()
91 | indicesToRemove.forEach { index -> playlist.removeAt(index) }
92 | return playlist
93 | }
94 |
95 | fun setDialogBtnBackground(context: Context, dialog: AlertDialog) {
96 | //setting button text
97 | dialog.getButton(android.app.AlertDialog.BUTTON_POSITIVE)?.setTextColor(
98 | MaterialColors.getColor(context, R.attr.dialogTextColor, Color.WHITE)
99 | )
100 | dialog.getButton(android.app.AlertDialog.BUTTON_NEGATIVE)?.setTextColor(
101 | MaterialColors.getColor(context, R.attr.dialogTextColor, Color.WHITE)
102 | )
103 |
104 | //setting button background
105 | dialog.getButton(android.app.AlertDialog.BUTTON_POSITIVE)?.setBackgroundColor(
106 | MaterialColors.getColor(context, R.attr.dialogBtnBackground, Color.RED)
107 | )
108 | dialog.getButton(android.app.AlertDialog.BUTTON_NEGATIVE)?.setBackgroundColor(
109 | MaterialColors.getColor(context, R.attr.dialogBtnBackground, Color.RED)
110 | )
111 | }
112 |
113 | fun getMainColor(img: Bitmap): Int {
114 | val newImg = Bitmap.createScaledBitmap(img, 1, 1, true)
115 | val color = newImg.getPixel(0, 0)
116 | newImg.recycle()
117 | return color
118 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/MusicAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.graphics.Color
6 | import android.graphics.drawable.ColorDrawable
7 | import android.text.SpannableStringBuilder
8 | import android.text.format.DateUtils
9 | import android.view.LayoutInflater
10 | import android.view.ViewGroup
11 | import androidx.appcompat.app.AlertDialog
12 | import androidx.core.content.ContextCompat
13 | import androidx.core.text.bold
14 | import androidx.recyclerview.widget.RecyclerView
15 | import com.bumptech.glide.Glide
16 | import com.bumptech.glide.request.RequestOptions
17 | import com.google.android.material.dialog.MaterialAlertDialogBuilder
18 | import com.google.android.material.snackbar.Snackbar
19 | import com.harshRajpurohit.musicPlayer.MusicAdapter.MyHolder
20 | import com.harshRajpurohit.musicPlayer.databinding.DetailsViewBinding
21 | import com.harshRajpurohit.musicPlayer.databinding.MoreFeaturesBinding
22 | import com.harshRajpurohit.musicPlayer.databinding.MusicViewBinding
23 |
24 | class MusicAdapter(private val context: Context, private var musicList: ArrayList, private val playlistDetails: Boolean = false,
25 | private val selectionActivity: Boolean = false)
26 | : RecyclerView.Adapter() {
27 |
28 | class MyHolder(binding: MusicViewBinding) : RecyclerView.ViewHolder(binding.root) {
29 | val title = binding.songNameMV
30 | val album = binding.songAlbumMV
31 | val image = binding.imageMV
32 | val duration = binding.songDuration
33 | val root = binding.root
34 | }
35 |
36 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
37 | return MyHolder(MusicViewBinding.inflate(LayoutInflater.from(context), parent, false))
38 | }
39 |
40 | override fun onBindViewHolder(holder: MyHolder, position: Int) {
41 | holder.title.text = musicList[position].title
42 | holder.album.text = musicList[position].album
43 | holder.duration.text = formatDuration(musicList[position].duration)
44 | Glide.with(context)
45 | .load(musicList[position].artUri)
46 | .apply(RequestOptions().placeholder(R.drawable.music_player_icon_slash_screen).centerCrop())
47 | .into(holder.image)
48 |
49 | //for play next feature
50 | if(!selectionActivity)
51 | holder.root.setOnLongClickListener {
52 | val customDialog = LayoutInflater.from(context).inflate(R.layout.more_features, holder.root, false)
53 | val bindingMF = MoreFeaturesBinding.bind(customDialog)
54 | val dialog = MaterialAlertDialogBuilder(context).setView(customDialog)
55 | .create()
56 | dialog.show()
57 | dialog.window?.setBackgroundDrawable(ColorDrawable(0x99000000.toInt()))
58 |
59 | bindingMF.AddToPNBtn.setOnClickListener {
60 | try {
61 | if(PlayNext.playNextList.isEmpty()){
62 | PlayNext.playNextList.add(PlayerActivity.musicListPA[PlayerActivity.songPosition])
63 | PlayerActivity.songPosition = 0
64 | }
65 |
66 | PlayNext.playNextList.add(musicList[position])
67 | PlayerActivity.musicListPA = ArrayList()
68 | PlayerActivity.musicListPA.addAll(PlayNext.playNextList)
69 | }catch (e: Exception){
70 | Snackbar.make(context, holder.root,"Play A Song First!!", 3000).show()
71 | }
72 | dialog.dismiss()
73 | }
74 |
75 | bindingMF.infoBtn.setOnClickListener {
76 | dialog.dismiss()
77 | val detailsDialog = LayoutInflater.from(context).inflate(R.layout.details_view, bindingMF.root, false)
78 | val binder = DetailsViewBinding.bind(detailsDialog)
79 | binder.detailsTV.setTextColor(Color.WHITE)
80 | binder.root.setBackgroundColor(Color.TRANSPARENT)
81 | val dDialog = MaterialAlertDialogBuilder(context)
82 | // .setBackground(ColorDrawable(0x99000000.toInt()))
83 | .setView(detailsDialog)
84 | .setPositiveButton("OK"){self, _ -> self.dismiss()}
85 | .setCancelable(false)
86 | .create()
87 | dDialog.show()
88 | dDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(Color.RED)
89 | setDialogBtnBackground(context, dDialog)
90 | dDialog.window?.setBackgroundDrawable(ColorDrawable(0x99000000.toInt()))
91 | val str = SpannableStringBuilder().bold { append("DETAILS\n\nName: ") }
92 | .append(musicList[position].title)
93 | .bold { append("\n\nDuration: ") }.append(DateUtils.formatElapsedTime(musicList[position].duration/1000))
94 | .bold { append("\n\nLocation: ") }.append(musicList[position].path)
95 | binder.detailsTV.text = str
96 | }
97 |
98 | return@setOnLongClickListener true
99 | }
100 |
101 | when{
102 | playlistDetails ->{
103 | holder.root.setOnClickListener {
104 | sendIntent(ref = "PlaylistDetailsAdapter", pos = position)
105 | }
106 | }
107 | selectionActivity ->{
108 | holder.root.setOnClickListener {
109 | if(addSong(musicList[position]))
110 | holder.root.setBackgroundColor(ContextCompat.getColor(context, R.color.cool_pink))
111 | else
112 | holder.root.setBackgroundColor(ContextCompat.getColor(context, R.color.white))
113 |
114 | }
115 | }
116 | else ->{
117 | holder.root.setOnClickListener {
118 | when{
119 | MainActivity.search -> sendIntent(ref = "MusicAdapterSearch", pos = position)
120 | musicList[position].id == PlayerActivity.nowPlayingId ->
121 | sendIntent(ref = "NowPlaying", pos = PlayerActivity.songPosition)
122 | else->sendIntent(ref="MusicAdapter", pos = position) } }
123 | }
124 |
125 | }
126 | }
127 |
128 | override fun getItemCount(): Int {
129 | return musicList.size
130 | }
131 |
132 | fun updateMusicList(searchList : ArrayList){
133 | musicList = ArrayList()
134 | musicList.addAll(searchList)
135 | notifyDataSetChanged()
136 | }
137 | private fun sendIntent(ref: String, pos: Int){
138 | val intent = Intent(context, PlayerActivity::class.java)
139 | intent.putExtra("index", pos)
140 | intent.putExtra("class", ref)
141 | ContextCompat.startActivity(context, intent, null)
142 | }
143 | private fun addSong(song: Music): Boolean{
144 | PlaylistActivity.musicPlaylist.ref[PlaylistDetails.currentPlaylistPos].playlist.forEachIndexed { index, music ->
145 | if(song.id == music.id){
146 | PlaylistActivity.musicPlaylist.ref[PlaylistDetails.currentPlaylistPos].playlist.removeAt(index)
147 | return false
148 | }
149 | }
150 | PlaylistActivity.musicPlaylist.ref[PlaylistDetails.currentPlaylistPos].playlist.add(song)
151 | return true
152 | }
153 | fun refreshPlaylist(){
154 | musicList = ArrayList()
155 | musicList = PlaylistActivity.musicPlaylist.ref[PlaylistDetails.currentPlaylistPos].playlist
156 | notifyDataSetChanged()
157 | }
158 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/MusicService.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.PendingIntent
5 | import android.app.Service
6 | import android.content.Context
7 | import android.content.Intent
8 | import android.graphics.BitmapFactory
9 | import android.media.AudioManager
10 | import android.media.MediaPlayer
11 | import android.media.audiofx.LoudnessEnhancer
12 | import android.os.*
13 | import android.support.v4.media.MediaMetadataCompat
14 | import android.support.v4.media.session.MediaSessionCompat
15 | import android.support.v4.media.session.PlaybackStateCompat
16 | import com.bumptech.glide.Glide
17 | import com.bumptech.glide.request.RequestOptions
18 |
19 | class MusicService : Service(), AudioManager.OnAudioFocusChangeListener {
20 | private var myBinder = MyBinder()
21 | var mediaPlayer: MediaPlayer? = null
22 | private lateinit var mediaSession: MediaSessionCompat
23 | private lateinit var runnable: Runnable
24 | lateinit var audioManager: AudioManager
25 |
26 | override fun onBind(intent: Intent?): IBinder {
27 | mediaSession = MediaSessionCompat(baseContext, "My Music")
28 | return myBinder
29 | }
30 |
31 | inner class MyBinder : Binder() {
32 | fun currentService(): MusicService {
33 | return this@MusicService
34 | }
35 | }
36 |
37 | @SuppressLint("UnspecifiedImmutableFlag")
38 | fun showNotification(playPauseBtn: Int) {
39 | val intent = Intent(baseContext, MainActivity::class.java)
40 |
41 | val flag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
42 | PendingIntent.FLAG_IMMUTABLE
43 | } else {
44 | PendingIntent.FLAG_UPDATE_CURRENT
45 | }
46 |
47 | val contentIntent = PendingIntent.getActivity(this, 0, intent, flag)
48 |
49 | val prevIntent = Intent(
50 | baseContext, NotificationReceiver::class.java
51 | ).setAction(ApplicationClass.PREVIOUS)
52 | val prevPendingIntent = PendingIntent.getBroadcast(baseContext, 0, prevIntent, flag)
53 |
54 | val playIntent =
55 | Intent(baseContext, NotificationReceiver::class.java).setAction(ApplicationClass.PLAY)
56 | val playPendingIntent = PendingIntent.getBroadcast(baseContext, 0, playIntent, flag)
57 |
58 | val nextIntent =
59 | Intent(baseContext, NotificationReceiver::class.java).setAction(ApplicationClass.NEXT)
60 | val nextPendingIntent = PendingIntent.getBroadcast(baseContext, 0, nextIntent, flag)
61 |
62 | val exitIntent =
63 | Intent(baseContext, NotificationReceiver::class.java).setAction(ApplicationClass.EXIT)
64 | val exitPendingIntent = PendingIntent.getBroadcast(baseContext, 0, exitIntent, flag)
65 |
66 | val imgArt = getImgArt(PlayerActivity.musicListPA[PlayerActivity.songPosition].path)
67 | val image = if (imgArt != null) {
68 | BitmapFactory.decodeByteArray(imgArt, 0, imgArt.size)
69 | } else {
70 | BitmapFactory.decodeResource(resources, R.drawable.music_player_icon_slash_screen)
71 | }
72 |
73 | val notification =
74 | androidx.core.app.NotificationCompat.Builder(baseContext, ApplicationClass.CHANNEL_ID)
75 | .setContentIntent(contentIntent)
76 | .setContentTitle(PlayerActivity.musicListPA[PlayerActivity.songPosition].title)
77 | .setContentText(PlayerActivity.musicListPA[PlayerActivity.songPosition].artist)
78 | .setSmallIcon(R.drawable.music_icon).setLargeIcon(image)
79 | .setStyle(androidx.media.app.NotificationCompat.MediaStyle().setMediaSession(mediaSession.sessionToken))
80 | .setPriority(androidx.core.app.NotificationCompat.PRIORITY_HIGH)
81 | .setVisibility(androidx.core.app.NotificationCompat.VISIBILITY_PUBLIC)
82 | .setOnlyAlertOnce(true)
83 | .addAction(R.drawable.previous_icon, "Previous", prevPendingIntent)
84 | .addAction(playPauseBtn, "Play", playPendingIntent)
85 | .addAction(R.drawable.next_icon, "Next", nextPendingIntent)
86 | .addAction(R.drawable.exit_icon, "Exit", exitPendingIntent)
87 | .build()
88 |
89 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
90 |
91 | mediaSession.setMetadata(
92 | MediaMetadataCompat.Builder().putLong(
93 | MediaMetadataCompat.METADATA_KEY_DURATION, mediaPlayer!!.duration.toLong()
94 | ).build()
95 | )
96 |
97 | mediaSession.setPlaybackState(getPlayBackState())
98 | mediaSession.setCallback(object : MediaSessionCompat.Callback() {
99 |
100 | //called when play button is pressed
101 | override fun onPlay() {
102 | super.onPlay()
103 | handlePlayPause()
104 | }
105 |
106 | //called when pause button is pressed
107 | override fun onPause() {
108 | super.onPause()
109 | handlePlayPause()
110 | }
111 |
112 | //called when next button is pressed
113 | override fun onSkipToNext() {
114 | super.onSkipToNext()
115 | prevNextSong(increment = true, context = baseContext)
116 | }
117 |
118 | //called when previous button is pressed
119 | override fun onSkipToPrevious() {
120 | super.onSkipToPrevious()
121 | prevNextSong(increment = false, context = baseContext)
122 | }
123 |
124 | //called when headphones buttons are pressed
125 | //currently only pause or play music on button click
126 | override fun onMediaButtonEvent(mediaButtonEvent: Intent?): Boolean {
127 | handlePlayPause()
128 | return super.onMediaButtonEvent(mediaButtonEvent)
129 | }
130 |
131 | //called when seekbar is changed
132 | override fun onSeekTo(pos: Long) {
133 | super.onSeekTo(pos)
134 | mediaPlayer?.seekTo(pos.toInt())
135 |
136 | mediaSession.setPlaybackState(getPlayBackState())
137 | }
138 | })
139 | }
140 |
141 | startForeground(13, notification)
142 | }
143 |
144 | fun createMediaPlayer() {
145 | try {
146 | if (mediaPlayer == null) mediaPlayer = MediaPlayer()
147 | mediaPlayer?.reset()
148 | mediaPlayer?.setDataSource(PlayerActivity.musicListPA[PlayerActivity.songPosition].path)
149 | mediaPlayer?.prepare()
150 |
151 | PlayerActivity.binding.playPauseBtnPA.setIconResource(R.drawable.pause_icon)
152 | showNotification(R.drawable.pause_icon)
153 | PlayerActivity.binding.tvSeekBarStart.text =
154 | formatDuration(mediaPlayer!!.currentPosition.toLong())
155 | PlayerActivity.binding.tvSeekBarEnd.text =
156 | formatDuration(mediaPlayer!!.duration.toLong())
157 | PlayerActivity.binding.seekBarPA.progress = 0
158 | PlayerActivity.binding.seekBarPA.max = mediaPlayer!!.duration
159 | PlayerActivity.nowPlayingId = PlayerActivity.musicListPA[PlayerActivity.songPosition].id
160 | PlayerActivity.loudnessEnhancer = LoudnessEnhancer(mediaPlayer!!.audioSessionId)
161 | PlayerActivity.loudnessEnhancer.enabled = true
162 | } catch (e: Exception) {
163 | return
164 | }
165 | }
166 |
167 | fun seekBarSetup() {
168 | runnable = Runnable {
169 | PlayerActivity.binding.tvSeekBarStart.text =
170 | formatDuration(mediaPlayer!!.currentPosition.toLong())
171 | PlayerActivity.binding.seekBarPA.progress = mediaPlayer!!.currentPosition
172 | Handler(Looper.getMainLooper()).postDelayed(runnable, 200)
173 | }
174 | Handler(Looper.getMainLooper()).postDelayed(runnable, 0)
175 | }
176 |
177 | fun getPlayBackState(): PlaybackStateCompat {
178 | val playbackSpeed = if (PlayerActivity.isPlaying) 1F else 0F
179 |
180 | return PlaybackStateCompat.Builder().setState(
181 | if (mediaPlayer?.isPlaying == true) PlaybackStateCompat.STATE_PLAYING else PlaybackStateCompat.STATE_PAUSED,
182 | mediaPlayer!!.currentPosition.toLong(), playbackSpeed)
183 | .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE or PlaybackStateCompat.ACTION_SEEK_TO or PlaybackStateCompat.ACTION_SKIP_TO_NEXT or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)
184 | .build()
185 | }
186 |
187 | fun handlePlayPause() {
188 | if (PlayerActivity.isPlaying) pauseMusic()
189 | else playMusic()
190 |
191 | //update playback state for notification
192 | mediaSession.setPlaybackState(getPlayBackState())
193 | }
194 |
195 |
196 |
197 | private fun prevNextSong(increment: Boolean, context: Context){
198 |
199 | setSongPosition(increment = increment)
200 |
201 | PlayerActivity.musicService?.createMediaPlayer()
202 | Glide.with(context)
203 | .load(PlayerActivity.musicListPA[PlayerActivity.songPosition].artUri)
204 | .apply(RequestOptions().placeholder(R.drawable.music_player_icon_slash_screen).centerCrop())
205 | .into(PlayerActivity.binding.songImgPA)
206 |
207 | PlayerActivity.binding.songNamePA.text = PlayerActivity.musicListPA[PlayerActivity.songPosition].title
208 |
209 | Glide.with(context)
210 | .load(PlayerActivity.musicListPA[PlayerActivity.songPosition].artUri)
211 | .apply(RequestOptions().placeholder(R.drawable.music_player_icon_slash_screen).centerCrop())
212 | .into(NowPlaying.binding.songImgNP)
213 |
214 | NowPlaying.binding.songNameNP.text = PlayerActivity.musicListPA[PlayerActivity.songPosition].title
215 |
216 | playMusic()
217 |
218 | PlayerActivity.fIndex = favouriteChecker(PlayerActivity.musicListPA[PlayerActivity.songPosition].id)
219 | if(PlayerActivity.isFavourite) PlayerActivity.binding.favouriteBtnPA.setImageResource(R.drawable.favourite_icon)
220 | else PlayerActivity.binding.favouriteBtnPA.setImageResource(R.drawable.favourite_empty_icon)
221 |
222 | //update playback state for notification
223 | mediaSession.setPlaybackState(getPlayBackState())
224 | }
225 |
226 | override fun onAudioFocusChange(focusChange: Int) {
227 | if (focusChange <= 0) {
228 | pauseMusic()
229 | }
230 | // else{
231 | // playMusic()
232 | // }
233 | }
234 |
235 | private fun playMusic(){
236 | //play music
237 | PlayerActivity.binding.playPauseBtnPA.setIconResource(R.drawable.pause_icon)
238 | NowPlaying.binding.playPauseBtnNP.setIconResource(R.drawable.pause_icon)
239 | PlayerActivity.isPlaying = true
240 | mediaPlayer?.start()
241 | showNotification(R.drawable.pause_icon)
242 | }
243 |
244 | private fun pauseMusic(){
245 | //pause music
246 | PlayerActivity.binding.playPauseBtnPA.setIconResource(R.drawable.play_icon)
247 | NowPlaying.binding.playPauseBtnNP.setIconResource(R.drawable.play_icon)
248 | PlayerActivity.isPlaying = false
249 | mediaPlayer!!.pause()
250 | showNotification(R.drawable.play_icon)
251 | }
252 |
253 |
254 |
255 |
256 | //for making persistent
257 | override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
258 | return START_STICKY
259 | }
260 |
261 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/NotificationReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 | import com.bumptech.glide.Glide
7 | import com.bumptech.glide.request.RequestOptions
8 |
9 | class NotificationReceiver:BroadcastReceiver() {
10 | override fun onReceive(context: Context?, intent: Intent?) {
11 | when(intent?.action){
12 | //only play next or prev song, when music list contains more than one song
13 | ApplicationClass.PREVIOUS -> if(PlayerActivity.musicListPA.size > 1) prevNextSong(increment = false, context = context!!)
14 | ApplicationClass.PLAY -> if(PlayerActivity.isPlaying) pauseMusic() else playMusic()
15 | ApplicationClass.NEXT -> if(PlayerActivity.musicListPA.size > 1) prevNextSong(increment = true, context = context!!)
16 | ApplicationClass.EXIT ->{
17 | exitApplication()
18 | }
19 | }
20 | }
21 | private fun playMusic(){
22 | PlayerActivity.isPlaying = true
23 | PlayerActivity.musicService!!.mediaPlayer!!.start()
24 | PlayerActivity.musicService!!.showNotification(R.drawable.pause_icon)
25 | PlayerActivity.binding.playPauseBtnPA.setIconResource(R.drawable.pause_icon)
26 | //for handling app crash during notification play - pause btn (While app opened through intent)
27 | try{ NowPlaying.binding.playPauseBtnNP.setIconResource(R.drawable.pause_icon) }catch (_: Exception){}
28 | }
29 |
30 | private fun pauseMusic(){
31 | PlayerActivity.isPlaying = false
32 | PlayerActivity.musicService!!.mediaPlayer!!.pause()
33 | PlayerActivity.musicService!!.showNotification(R.drawable.play_icon)
34 | PlayerActivity.binding.playPauseBtnPA.setIconResource(R.drawable.play_icon)
35 | //for handling app crash during notification play - pause btn (While app opened through intent)
36 | try{ NowPlaying.binding.playPauseBtnNP.setIconResource(R.drawable.play_icon) }catch (_: Exception){}
37 | }
38 |
39 | private fun prevNextSong(increment: Boolean, context: Context){
40 | setSongPosition(increment = increment)
41 | PlayerActivity.musicService!!.createMediaPlayer()
42 | Glide.with(context)
43 | .load(PlayerActivity.musicListPA[PlayerActivity.songPosition].artUri)
44 | .apply(RequestOptions().placeholder(R.drawable.music_player_icon_slash_screen).centerCrop())
45 | .into(PlayerActivity.binding.songImgPA)
46 | PlayerActivity.binding.songNamePA.text = PlayerActivity.musicListPA[PlayerActivity.songPosition].title
47 | Glide.with(context)
48 | .load(PlayerActivity.musicListPA[PlayerActivity.songPosition].artUri)
49 | .apply(RequestOptions().placeholder(R.drawable.music_player_icon_slash_screen).centerCrop())
50 | .into(NowPlaying.binding.songImgNP)
51 | NowPlaying.binding.songNameNP.text = PlayerActivity.musicListPA[PlayerActivity.songPosition].title
52 | playMusic()
53 | PlayerActivity.fIndex = favouriteChecker(PlayerActivity.musicListPA[PlayerActivity.songPosition].id)
54 | if(PlayerActivity.isFavourite) PlayerActivity.binding.favouriteBtnPA.setImageResource(R.drawable.favourite_icon)
55 | else PlayerActivity.binding.favouriteBtnPA.setImageResource(R.drawable.favourite_empty_icon)
56 | }
57 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/NowPlaying.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import androidx.core.content.ContextCompat
10 | import androidx.fragment.app.Fragment
11 | import com.bumptech.glide.Glide
12 | import com.bumptech.glide.request.RequestOptions
13 | import com.harshRajpurohit.musicPlayer.databinding.FragmentNowPlayingBinding
14 |
15 | class NowPlaying : Fragment() {
16 |
17 | companion object{
18 | @SuppressLint("StaticFieldLeak")
19 | lateinit var binding: FragmentNowPlayingBinding
20 | }
21 |
22 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
23 | requireContext().theme.applyStyle(MainActivity.currentTheme[MainActivity.themeIndex], true)
24 | val view = inflater.inflate(R.layout.fragment_now_playing, container, false)
25 | binding = FragmentNowPlayingBinding.bind(view)
26 | binding.root.visibility = View.INVISIBLE
27 | binding.playPauseBtnNP.setOnClickListener {
28 | if(PlayerActivity.isPlaying) pauseMusic() else playMusic()
29 | }
30 | binding.nextBtnNP.setOnClickListener {
31 | setSongPosition(increment = true)
32 | PlayerActivity.musicService!!.createMediaPlayer()
33 | Glide.with(requireContext())
34 | .load(PlayerActivity.musicListPA[PlayerActivity.songPosition].artUri)
35 | .apply(RequestOptions().placeholder(R.drawable.music_player_icon_slash_screen).centerCrop())
36 | .into(binding.songImgNP)
37 | binding.songNameNP.text = PlayerActivity.musicListPA[PlayerActivity.songPosition].title
38 | PlayerActivity.musicService!!.showNotification(R.drawable.pause_icon)
39 | playMusic()
40 | }
41 | binding.root.setOnClickListener {
42 | val intent = Intent(requireContext(), PlayerActivity::class.java)
43 | intent.putExtra("index", PlayerActivity.songPosition)
44 | intent.putExtra("class", "NowPlaying")
45 | ContextCompat.startActivity(requireContext(), intent, null)
46 | }
47 | return view
48 | }
49 |
50 | override fun onResume() {
51 | super.onResume()
52 | if(PlayerActivity.musicService != null){
53 | binding.root.visibility = View.VISIBLE
54 | binding.songNameNP.isSelected = true
55 | Glide.with(requireContext())
56 | .load(PlayerActivity.musicListPA[PlayerActivity.songPosition].artUri)
57 | .apply(RequestOptions().placeholder(R.drawable.music_player_icon_slash_screen).centerCrop())
58 | .into(binding.songImgNP)
59 | binding.songNameNP.text = PlayerActivity.musicListPA[PlayerActivity.songPosition].title
60 | if(PlayerActivity.isPlaying) binding.playPauseBtnNP.setIconResource(R.drawable.pause_icon)
61 | else binding.playPauseBtnNP.setIconResource(R.drawable.play_icon)
62 | }
63 | }
64 |
65 | private fun playMusic(){
66 | PlayerActivity.isPlaying = true
67 | PlayerActivity.musicService!!.mediaPlayer!!.start()
68 | binding.playPauseBtnNP.setIconResource(R.drawable.pause_icon)
69 | PlayerActivity.musicService!!.showNotification(R.drawable.pause_icon)
70 | }
71 | private fun pauseMusic(){
72 | PlayerActivity.isPlaying = false
73 | PlayerActivity.musicService!!.mediaPlayer!!.pause()
74 | binding.playPauseBtnNP.setIconResource(R.drawable.play_icon)
75 | PlayerActivity.musicService!!.showNotification(R.drawable.play_icon)
76 | }
77 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/PlayNext.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.appcompat.app.AppCompatActivity
6 | import androidx.recyclerview.widget.GridLayoutManager
7 | import com.harshRajpurohit.musicPlayer.databinding.ActivityPlayNextBinding
8 |
9 | class PlayNext : AppCompatActivity() {
10 |
11 | companion object{
12 | var playNextList: ArrayList = ArrayList()
13 | }
14 |
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 | setTheme(MainActivity.currentTheme[MainActivity.themeIndex])
18 | val binding = ActivityPlayNextBinding.inflate(layoutInflater)
19 | setContentView(binding.root)
20 |
21 | binding.playNextRV.setHasFixedSize(true)
22 | binding.playNextRV.setItemViewCacheSize(13)
23 | binding.playNextRV.layoutManager = GridLayoutManager(this, 4)
24 | binding.playNextRV.adapter = FavouriteAdapter(this, playNextList, playNext = true)
25 |
26 | if(playNextList.isNotEmpty())
27 | binding.instructionPN.visibility = View.GONE
28 |
29 | binding.backBtnPN.setOnClickListener {
30 | finish()
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/PlaylistActivity.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.widget.Toast
7 | import androidx.appcompat.app.AppCompatActivity
8 | import androidx.recyclerview.widget.GridLayoutManager
9 | import com.google.android.material.dialog.MaterialAlertDialogBuilder
10 | import com.harshRajpurohit.musicPlayer.databinding.ActivityPlaylistBinding
11 | import com.harshRajpurohit.musicPlayer.databinding.AddPlaylistDialogBinding
12 | import java.text.SimpleDateFormat
13 | import java.util.*
14 | import kotlin.collections.ArrayList
15 |
16 | class PlaylistActivity : AppCompatActivity() {
17 |
18 | private lateinit var binding: ActivityPlaylistBinding
19 | private lateinit var adapter: PlaylistViewAdapter
20 |
21 | companion object{
22 | var musicPlaylist: MusicPlaylist = MusicPlaylist()
23 | }
24 |
25 | override fun onCreate(savedInstanceState: Bundle?) {
26 | super.onCreate(savedInstanceState)
27 | setTheme(MainActivity.currentTheme[MainActivity.themeIndex])
28 | binding = ActivityPlaylistBinding.inflate(layoutInflater)
29 | setContentView(binding.root)
30 | binding.playlistRV.setHasFixedSize(true)
31 | binding.playlistRV.setItemViewCacheSize(13)
32 | binding.playlistRV.layoutManager = GridLayoutManager(this@PlaylistActivity, 2)
33 | adapter = PlaylistViewAdapter(this, playlistList = musicPlaylist.ref)
34 | binding.playlistRV.adapter = adapter
35 | binding.backBtnPLA.setOnClickListener { finish() }
36 | binding.addPlaylistBtn.setOnClickListener { customAlertDialog() }
37 |
38 | if(musicPlaylist.ref.isNotEmpty()) binding.instructionPA.visibility = View.GONE
39 | }
40 | private fun customAlertDialog(){
41 | val customDialog = LayoutInflater.from(this@PlaylistActivity).inflate(R.layout.add_playlist_dialog, binding.root, false)
42 | val binder = AddPlaylistDialogBinding.bind(customDialog)
43 | val builder = MaterialAlertDialogBuilder(this)
44 | val dialog = builder.setView(customDialog)
45 | .setTitle("Playlist Details")
46 | .setPositiveButton("ADD"){ dialog, _ ->
47 | val playlistName = binder.playlistName.text
48 | val createdBy = binder.yourName.text
49 | if(playlistName != null && createdBy != null)
50 | if(playlistName.isNotEmpty() && createdBy.isNotEmpty())
51 | {
52 | addPlaylist(playlistName.toString(), createdBy.toString())
53 | }
54 | dialog.dismiss()
55 | }.create()
56 | dialog.show()
57 | setDialogBtnBackground(this, dialog)
58 |
59 | }
60 | private fun addPlaylist(name: String, createdBy: String){
61 | var playlistExists = false
62 | for(i in musicPlaylist.ref) {
63 | if (name == i.name){
64 | playlistExists = true
65 | break
66 | }
67 | }
68 | if(playlistExists) Toast.makeText(this, "Playlist Exist!!", Toast.LENGTH_SHORT).show()
69 | else {
70 | val tempPlaylist = Playlist()
71 | tempPlaylist.name = name
72 | tempPlaylist.playlist = ArrayList()
73 | tempPlaylist.createdBy = createdBy
74 | val calendar = Calendar.getInstance().time
75 | val sdf = SimpleDateFormat("dd MMM yyyy", Locale.ENGLISH)
76 | tempPlaylist.createdOn = sdf.format(calendar)
77 | musicPlaylist.ref.add(tempPlaylist)
78 | adapter.refreshPlaylist()
79 | }
80 | }
81 |
82 | override fun onResume() {
83 | super.onResume()
84 | adapter.notifyDataSetChanged()
85 | }
86 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/PlaylistDetails.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import android.view.View
7 | import androidx.appcompat.app.AppCompatActivity
8 | import androidx.recyclerview.widget.LinearLayoutManager
9 | import com.bumptech.glide.Glide
10 | import com.bumptech.glide.request.RequestOptions
11 | import com.google.android.material.dialog.MaterialAlertDialogBuilder
12 | import com.google.gson.GsonBuilder
13 | import com.harshRajpurohit.musicPlayer.databinding.ActivityPlaylistDetailsBinding
14 |
15 | class PlaylistDetails : AppCompatActivity() {
16 |
17 | private lateinit var binding: ActivityPlaylistDetailsBinding
18 | private lateinit var adapter: MusicAdapter
19 |
20 | companion object{
21 | var currentPlaylistPos: Int = -1
22 | }
23 |
24 | override fun onCreate(savedInstanceState: Bundle?) {
25 | super.onCreate(savedInstanceState)
26 | setTheme(MainActivity.currentTheme[MainActivity.themeIndex])
27 | binding = ActivityPlaylistDetailsBinding.inflate(layoutInflater)
28 | setContentView(binding.root)
29 | currentPlaylistPos = intent.extras?.get("index") as Int
30 | try{PlaylistActivity.musicPlaylist.ref[currentPlaylistPos].playlist =
31 | checkPlaylist(playlist = PlaylistActivity.musicPlaylist.ref[currentPlaylistPos].playlist)}
32 | catch(e: Exception){}
33 | binding.playlistDetailsRV.setItemViewCacheSize(10)
34 | binding.playlistDetailsRV.setHasFixedSize(true)
35 | binding.playlistDetailsRV.layoutManager = LinearLayoutManager(this)
36 | adapter = MusicAdapter(this, PlaylistActivity.musicPlaylist.ref[currentPlaylistPos].playlist, playlistDetails = true)
37 | binding.playlistDetailsRV.adapter = adapter
38 | binding.backBtnPD.setOnClickListener { finish() }
39 | binding.shuffleBtnPD.setOnClickListener {
40 | val intent = Intent(this, PlayerActivity::class.java)
41 | intent.putExtra("index", 0)
42 | intent.putExtra("class", "PlaylistDetailsShuffle")
43 | startActivity(intent)
44 | }
45 | binding.addBtnPD.setOnClickListener {
46 | startActivity(Intent(this, SelectionActivity::class.java))
47 | }
48 | binding.removeAllPD.setOnClickListener {
49 | val builder = MaterialAlertDialogBuilder(this)
50 | builder.setTitle("Remove")
51 | .setMessage("Do you want to remove all songs from playlist?")
52 | .setPositiveButton("Yes"){ dialog, _ ->
53 | PlaylistActivity.musicPlaylist.ref[currentPlaylistPos].playlist.clear()
54 | adapter.refreshPlaylist()
55 | dialog.dismiss()
56 | }
57 | .setNegativeButton("No"){dialog, _ ->
58 | dialog.dismiss()
59 | }
60 | val customDialog = builder.create()
61 | customDialog.show()
62 |
63 | setDialogBtnBackground(this, customDialog)
64 | }
65 | }
66 |
67 | @SuppressLint("SetTextI18n")
68 | override fun onResume() {
69 | super.onResume()
70 | binding.playlistNamePD.text = PlaylistActivity.musicPlaylist.ref[currentPlaylistPos].name
71 | binding.moreInfoPD.text = "Total ${adapter.itemCount} Songs.\n\n" +
72 | "Created On:\n${PlaylistActivity.musicPlaylist.ref[currentPlaylistPos].createdOn}\n\n" +
73 | " -- ${PlaylistActivity.musicPlaylist.ref[currentPlaylistPos].createdBy}"
74 | if(adapter.itemCount > 0)
75 | {
76 | Glide.with(this)
77 | .load(PlaylistActivity.musicPlaylist.ref[currentPlaylistPos].playlist[0].artUri)
78 | .apply(RequestOptions().placeholder(R.drawable.music_player_icon_slash_screen).centerCrop())
79 | .into(binding.playlistImgPD)
80 | binding.shuffleBtnPD.visibility = View.VISIBLE
81 | }
82 | adapter.notifyDataSetChanged()
83 | //for storing favourites data using shared preferences
84 | val editor = getSharedPreferences("FAVOURITES", MODE_PRIVATE).edit()
85 | val jsonStringPlaylist = GsonBuilder().create().toJson(PlaylistActivity.musicPlaylist)
86 | editor.putString("MusicPlaylist", jsonStringPlaylist)
87 | editor.apply()
88 | }
89 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/PlaylistViewAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.view.LayoutInflater
6 | import android.view.ViewGroup
7 | import androidx.core.content.ContextCompat
8 | import androidx.recyclerview.widget.RecyclerView
9 | import com.bumptech.glide.Glide
10 | import com.bumptech.glide.request.RequestOptions
11 | import com.google.android.material.dialog.MaterialAlertDialogBuilder
12 | import com.harshRajpurohit.musicPlayer.databinding.PlaylistViewBinding
13 |
14 | class PlaylistViewAdapter(private val context: Context, private var playlistList: ArrayList) : RecyclerView.Adapter() {
15 |
16 | class MyHolder(binding: PlaylistViewBinding) : RecyclerView.ViewHolder(binding.root) {
17 | val image = binding.playlistImg
18 | val name = binding.playlistName
19 | val root = binding.root
20 | val delete = binding.playlistDeleteBtn
21 | }
22 |
23 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
24 | return MyHolder(PlaylistViewBinding.inflate(LayoutInflater.from(context), parent, false))
25 | }
26 |
27 | override fun onBindViewHolder(holder: MyHolder, position: Int) {
28 | if(MainActivity.themeIndex == 4){
29 | holder.root.strokeColor = ContextCompat.getColor(context, R.color.white)
30 | }
31 | holder.name.text = playlistList[position].name
32 | holder.name.isSelected = true
33 | holder.delete.setOnClickListener {
34 | val builder = MaterialAlertDialogBuilder(context)
35 | builder.setTitle(playlistList[position].name)
36 | .setMessage("Do you want to delete playlist?")
37 | .setPositiveButton("Yes"){ dialog, _ ->
38 | PlaylistActivity.musicPlaylist.ref.removeAt(position)
39 | refreshPlaylist()
40 | dialog.dismiss()
41 | }
42 | .setNegativeButton("No"){dialog, _ ->
43 | dialog.dismiss()
44 | }
45 | val customDialog = builder.create()
46 | customDialog.show()
47 |
48 | setDialogBtnBackground(context, customDialog)
49 | }
50 | holder.root.setOnClickListener {
51 | val intent = Intent(context, PlaylistDetails::class.java)
52 | intent.putExtra("index", position)
53 | ContextCompat.startActivity(context, intent, null)
54 | }
55 | if(PlaylistActivity.musicPlaylist.ref[position].playlist.size > 0){
56 | Glide.with(context)
57 | .load(PlaylistActivity.musicPlaylist.ref[position].playlist[0].artUri)
58 | .apply(RequestOptions().placeholder(R.drawable.music_player_icon_slash_screen).centerCrop())
59 | .into(holder.image)
60 | }
61 | }
62 |
63 | override fun getItemCount(): Int {
64 | return playlistList.size
65 | }
66 | fun refreshPlaylist(){
67 | playlistList = ArrayList()
68 | playlistList.addAll(PlaylistActivity.musicPlaylist.ref)
69 | notifyDataSetChanged()
70 | }
71 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/SelectionActivity.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import androidx.appcompat.widget.SearchView
6 | import androidx.core.content.ContextCompat
7 | import androidx.recyclerview.widget.LinearLayoutManager
8 | import com.harshRajpurohit.musicPlayer.databinding.ActivitySelectionBinding
9 |
10 | class SelectionActivity : AppCompatActivity() {
11 |
12 | private lateinit var binding: ActivitySelectionBinding
13 | private lateinit var adapter: MusicAdapter
14 |
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 | binding = ActivitySelectionBinding.inflate(layoutInflater)
18 | setTheme(MainActivity.currentTheme[MainActivity.themeIndex])
19 | setContentView(binding.root)
20 | binding.selectionRV.setItemViewCacheSize(30)
21 | binding.selectionRV.setHasFixedSize(true)
22 | binding.selectionRV.layoutManager = LinearLayoutManager(this)
23 | adapter = MusicAdapter(this, MainActivity.MusicListMA, selectionActivity = true)
24 | binding.selectionRV.adapter = adapter
25 | binding.backBtnSA.setOnClickListener { finish() }
26 | //for search View
27 | binding.searchViewSA.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
28 | override fun onQueryTextSubmit(query: String?): Boolean = true
29 | override fun onQueryTextChange(newText: String?): Boolean {
30 | MainActivity.musicListSearch = ArrayList()
31 | if(newText != null){
32 | val userInput = newText.lowercase()
33 | for (song in MainActivity.MusicListMA)
34 | if(song.title.lowercase().contains(userInput))
35 | MainActivity.musicListSearch.add(song)
36 | MainActivity.search = true
37 | adapter.updateMusicList(searchList = MainActivity.musicListSearch)
38 | }
39 | return true
40 | }
41 | })
42 | }
43 |
44 | override fun onResume() {
45 | super.onResume()
46 | //for black theme checking
47 | if(MainActivity.themeIndex == 4)
48 | {
49 | binding.searchViewSA.backgroundTintList = ContextCompat.getColorStateList(this, R.color.white)
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/harshRajpurohit/musicPlayer/SettingsActivity.kt:
--------------------------------------------------------------------------------
1 | package com.harshRajpurohit.musicPlayer
2 |
3 | import android.graphics.Color
4 | import android.os.Bundle
5 | import androidx.appcompat.app.AppCompatActivity
6 | import com.google.android.material.dialog.MaterialAlertDialogBuilder
7 | import com.harshRajpurohit.musicPlayer.databinding.ActivitySettingsBinding
8 |
9 | class SettingsActivity : AppCompatActivity() {
10 |
11 | lateinit var binding: ActivitySettingsBinding
12 |
13 | override fun onCreate(savedInstanceState: Bundle?) {
14 | super.onCreate(savedInstanceState)
15 | setTheme(MainActivity.currentThemeNav[MainActivity.themeIndex])
16 | binding = ActivitySettingsBinding.inflate(layoutInflater)
17 | setContentView(binding.root)
18 | supportActionBar?.title = "Settings"
19 | when(MainActivity.themeIndex){
20 | 0 -> binding.coolPinkTheme.setBackgroundColor(Color.YELLOW)
21 | 1 -> binding.coolBlueTheme.setBackgroundColor(Color.YELLOW)
22 | 2 -> binding.coolPurpleTheme.setBackgroundColor(Color.YELLOW)
23 | 3 -> binding.coolGreenTheme.setBackgroundColor(Color.YELLOW)
24 | 4 -> binding.coolBlackTheme.setBackgroundColor(Color.YELLOW)
25 | }
26 | binding.coolPinkTheme.setOnClickListener { saveTheme(0) }
27 | binding.coolBlueTheme.setOnClickListener { saveTheme(1) }
28 | binding.coolPurpleTheme.setOnClickListener { saveTheme(2) }
29 | binding.coolGreenTheme.setOnClickListener { saveTheme(3) }
30 | binding.coolBlackTheme.setOnClickListener { saveTheme(4) }
31 | binding.versionName.text = setVersionDetails()
32 | binding.sortBtn.setOnClickListener {
33 | val menuList = arrayOf("Recently Added", "Song Title", "File Size")
34 | var currentSort = MainActivity.sortOrder
35 | val builder = MaterialAlertDialogBuilder(this)
36 | builder.setTitle("Sorting")
37 | .setPositiveButton("OK"){ _, _ ->
38 | val editor = getSharedPreferences("SORTING", MODE_PRIVATE).edit()
39 | editor.putInt("sortOrder", currentSort)
40 | editor.apply()
41 | }
42 | .setSingleChoiceItems(menuList, currentSort){ _,which->
43 | currentSort = which
44 | }
45 | val customDialog = builder.create()
46 | customDialog.show()
47 |
48 | setDialogBtnBackground(this, customDialog)
49 | }
50 | }
51 |
52 | private fun saveTheme(index: Int){
53 | if(MainActivity.themeIndex != index){
54 | val editor = getSharedPreferences("THEMES", MODE_PRIVATE).edit()
55 | editor.putInt("themeIndex", index)
56 | editor.apply()
57 | val builder = MaterialAlertDialogBuilder(this)
58 | builder.setTitle("Apply Theme")
59 | .setMessage("Do you want to apply theme?")
60 | .setPositiveButton("Yes"){ _, _ ->
61 | exitApplication()
62 | }
63 | .setNegativeButton("No"){dialog, _ ->
64 | dialog.dismiss()
65 | }
66 | val customDialog = builder.create()
67 | customDialog.show()
68 |
69 | setDialogBtnBackground(this, customDialog)
70 | }
71 | }
72 | private fun setVersionDetails():String{
73 | return "Version Name: ${BuildConfig.VERSION_NAME}"
74 | }
75 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/about_icon.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/add_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/back_icon.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/booster_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/circle_icon.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/custom_search_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/delete_icon.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/equalizer_icon.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/exit_icon.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/favourite_empty_icon.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/favourite_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/feedback_icon.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/gradient_black.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/gradient_blue.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/gradient_green.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/gradient_pink.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/gradient_purple.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/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/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/music_icon.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/music_player_icon_slash_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/drawable/music_player_icon_slash_screen.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/next_icon.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/pause_icon.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/play_icon.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/play_next_icon.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
13 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/playlist_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/previous_icon.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/remove_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/repeat_icon.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/scroll_bar_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/search_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/settings_icon.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/share_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shuffle_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sort_icon.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/splash_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/timer_icon.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/volume_icon.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_about.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_favourite.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
29 |
30 |
39 |
40 |
41 |
52 |
53 |
69 |
70 |
84 |
85 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_feedback.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
27 |
28 |
35 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
17 |
20 |
21 |
27 |
28 |
29 |
33 |
34 |
45 |
46 |
57 |
58 |
69 |
70 |
71 |
82 |
83 |
84 |
85 |
86 |
93 |
94 |
100 |
101 |
102 |
112 |
113 |
114 |
115 |
123 |
124 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_play_next.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
29 |
30 |
39 |
40 |
41 |
54 |
55 |
66 |
67 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_player.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
18 |
19 |
20 |
30 |
31 |
41 |
42 |
43 |
52 |
53 |
54 |
55 |
65 |
66 |
67 |
78 |
79 |
80 |
87 |
88 |
89 |
95 |
96 |
97 |
107 |
108 |
109 |
115 |
116 |
117 |
118 |
119 |
125 |
126 |
134 |
135 |
141 |
142 |
150 |
151 |
152 |
153 |
158 |
159 |
160 |
170 |
171 |
172 |
181 |
182 |
183 |
192 |
193 |
194 |
203 |
204 |
205 |
206 |
215 |
216 |
217 |
218 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_playlist.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
29 |
30 |
39 |
40 |
41 |
52 |
53 |
69 |
70 |
84 |
85 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_playlist_details.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
20 |
21 |
30 |
31 |
42 |
43 |
44 |
54 |
59 |
68 |
69 |
70 |
81 |
82 |
99 |
100 |
101 |
102 |
109 |
110 |
122 |
123 |
124 |
136 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_selection.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
28 |
29 |
40 |
41 |
42 |
53 |
54 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
24 |
31 |
38 |
45 |
52 |
59 |
60 |
61 |
62 |
69 |
80 |
87 |
88 |
89 |
98 |
99 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/add_playlist_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
25 |
26 |
36 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/audio_booster.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/bottom_sheet_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
22 |
29 |
30 |
31 |
36 |
43 |
50 |
51 |
52 |
57 |
64 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/details_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/favourite_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_now_playing.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
30 |
31 |
42 |
56 |
57 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/more_features.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
63 |
64 |
65 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/music_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
31 |
32 |
44 |
45 |
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/playlist_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
19 |
32 |
33 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/nav_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/search_view_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/music_player_icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/music_player_icon_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/music_player_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/mipmap-hdpi/music_player_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/music_player_icon_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/mipmap-hdpi/music_player_icon_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/music_player_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/mipmap-hdpi/music_player_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/music_player_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/mipmap-mdpi/music_player_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/music_player_icon_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/mipmap-mdpi/music_player_icon_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/music_player_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/mipmap-mdpi/music_player_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/music_player_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/mipmap-xhdpi/music_player_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/music_player_icon_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/mipmap-xhdpi/music_player_icon_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/music_player_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/mipmap-xhdpi/music_player_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/music_player_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/mipmap-xxhdpi/music_player_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/music_player_icon_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/mipmap-xxhdpi/music_player_icon_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/music_player_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/mipmap-xxhdpi/music_player_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/music_player_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/mipmap-xxxhdpi/music_player_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/music_player_icon_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/mipmap-xxxhdpi/music_player_icon_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/music_player_icon_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/app/src/main/res/mipmap-xxxhdpi/music_player_icon_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
11 |
12 | #0091EA
13 | #64DD17
14 | #F50057
15 | #FFD600
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/custom_styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/music_player_icon_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Music Player
3 | Shuffle
4 | Favourites
5 | Playlists
6 | Total Songs
7 | World of Music
8 | Song Name
9 | Back
10 | 00:00
11 | Loading..
12 | Repeat
13 | Equalizer
14 | Timer
15 | Share
16 | Open
17 | Close
18 | Icon
19 | Welcome to\nWorld of Music
20 | Feedback
21 | Settings
22 | About
23 | Exit
24 | Song Album
25 | 15 Minutes
26 | 30 Minutes
27 | 60 Minutes
28 | Search View
29 | Song Image
30 | Playlist Name
31 | Delete
32 | Your Name
33 | Add
34 | Remove All
35 | Search Song
36 | Topic i.e. Suggestion, Error, etc.
37 | Email Address (Optional)
38 | Send
39 | Set Theme
40 | Sort By
41 | Version Name
42 | Play Next
43 | Tip: Long Press On Any Video To Add It Into Play Next. 😊
44 | Tip: Play Music And Click On ❤ To Add It Into Favourites.
45 | Tip: Click On ➕ To Create New Playlist.
46 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | //Theme for Activities
15 |
28 |
41 |
54 |
67 |
68 | //Theme for Navigation Drawer
69 |
82 |
95 |
108 |
121 | //new dark Theme
122 |
134 |
146 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | alias(libs.plugins.android.application) apply false
4 | alias(libs.plugins.jetbrains.kotlin.android) apply false
5 | }
--------------------------------------------------------------------------------
/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=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. For more details, visit
12 | # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | agp = "8.5.0"
3 | kotlin = "1.9.0"
4 | coreKtx = "1.13.1"
5 | appcompat = "1.7.0"
6 | material = "1.12.0"
7 | activity = "1.9.0"
8 | constraintlayout = "2.1.4"
9 |
10 | legacy-support = "1.0.0"
11 | glide = "4.16.0"
12 | media = "1.7.0"
13 | gson = "2.10.1"
14 | verticalseekbar = "1.2.7"
15 |
16 |
17 | [libraries]
18 | androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
19 | androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
20 | material = { group = "com.google.android.material", name = "material", version.ref = "material" }
21 | androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
22 | androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
23 |
24 | legacy-support = { group = "androidx.legacy", name = "legacy-support-v4", version.ref = "legacy-support" }
25 | glide = { group = "com.github.bumptech.glide", name = "glide", version.ref = "glide" }
26 | androidx-media = { group = "androidx.media", name = "media", version.ref = "media" }
27 | gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
28 | verticalseekbar = { group = "com.github.lukelorusso", name = "VerticalSeekBar", version.ref = "verticalseekbar" }
29 |
30 | [plugins]
31 | android-application = { id = "com.android.application", version.ref = "agp" }
32 | jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
33 |
34 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Jul 04 16:27:58 IST 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/music_player_screenshots/Music Player v2.0.1 04-07-2024.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/music_player_screenshots/Music Player v2.0.1 04-07-2024.apk
--------------------------------------------------------------------------------
/music_player_screenshots/screen_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/music_player_screenshots/screen_1.png
--------------------------------------------------------------------------------
/music_player_screenshots/screen_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/music_player_screenshots/screen_2.png
--------------------------------------------------------------------------------
/music_player_screenshots/screen_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/music_player_screenshots/screen_3.png
--------------------------------------------------------------------------------
/music_player_screenshots/screen_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/music_player_screenshots/screen_4.png
--------------------------------------------------------------------------------
/music_player_screenshots/screen_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/music_player_screenshots/screen_5.png
--------------------------------------------------------------------------------
/music_player_screenshots/screen_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/music_player_screenshots/screen_6.png
--------------------------------------------------------------------------------
/music_player_screenshots/screen_7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/music_player_screenshots/screen_7.png
--------------------------------------------------------------------------------
/music_player_screenshots/screen_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarshAndroid/MusicPlayer-Android-Kotlin/cb15fa4656db774c707b98921ad6246b8b7c1ff6/music_player_screenshots/screen_8.png
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google {
4 | content {
5 | includeGroupByRegex("com\\.android.*")
6 | includeGroupByRegex("com\\.google.*")
7 | includeGroupByRegex("androidx.*")
8 | }
9 | }
10 | mavenCentral()
11 | gradlePluginPortal()
12 | }
13 | }
14 | dependencyResolutionManagement {
15 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
16 | repositories {
17 | google()
18 | mavenCentral()
19 | maven(url="https://jitpack.io")
20 | }
21 | }
22 |
23 | rootProject.name = "Music Player"
24 | include(":app")
25 |
--------------------------------------------------------------------------------