Repackage to prepare for merge

This commit is contained in:
JFronny 2022-05-14 13:27:14 +02:00
parent b977cde1af
commit 7c6514d010
No known key found for this signature in database
GPG key ID: E76429612C2929F4
455 changed files with 2251 additions and 2302 deletions

View file

@ -1,50 +0,0 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.helper
import android.content.Context
import android.view.ViewGroup
import io.github.muntashirakon.music.R
object HorizontalAdapterHelper {
const val LAYOUT_RES = R.layout.item_image
private const val TYPE_FIRST = 1
private const val TYPE_MIDDLE = 2
private const val TYPE_LAST = 3
fun applyMarginToLayoutParams(
context: Context,
layoutParams: ViewGroup.MarginLayoutParams,
viewType: Int
) {
val listMargin = context.resources
.getDimensionPixelSize(R.dimen.now_playing_top_margin)
if (viewType == TYPE_FIRST) {
layoutParams.leftMargin = listMargin
} else if (viewType == TYPE_LAST) {
layoutParams.rightMargin = listMargin
}
}
fun getItemViewType(position: Int, itemCount: Int): Int {
return when (position) {
0 -> TYPE_FIRST
itemCount - 1 -> TYPE_LAST
else -> TYPE_MIDDLE
}
}
}

View file

@ -1,22 +0,0 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package io.github.muntashirakon.music.helper;
public interface M3UConstants {
String EXTENSION = "m3u";
String HEADER = "#EXTM3U";
String ENTRY = "#EXTINF:";
String DURATION_SEPARATOR = ",";
}

View file

@ -1,70 +0,0 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.helper
import io.github.muntashirakon.music.db.PlaylistWithSongs
import io.github.muntashirakon.music.db.toSongs
import io.github.muntashirakon.music.model.Playlist
import io.github.muntashirakon.music.model.Song
import java.io.BufferedWriter
import java.io.File
import java.io.FileWriter
import java.io.IOException
object M3UWriter : M3UConstants {
@JvmStatic
@Throws(IOException::class)
fun write(
dir: File,
playlist: Playlist
): File? {
if (!dir.exists()) dir.mkdirs()
val file = File(dir, playlist.name + "." + M3UConstants.EXTENSION)
val songs = playlist.getSongs()
if (songs.isNotEmpty()) {
val bw = BufferedWriter(FileWriter(file))
bw.write(M3UConstants.HEADER)
for (song in songs) {
bw.newLine()
bw.write(M3UConstants.ENTRY + song.duration + M3UConstants.DURATION_SEPARATOR + song.artistName + " - " + song.title)
bw.newLine()
bw.write(song.data)
}
bw.close()
}
return file
}
@JvmStatic
@Throws(IOException::class)
fun writeIO(dir: File, playlistWithSongs: PlaylistWithSongs): File {
if (!dir.exists()) dir.mkdirs()
val fileName = "${playlistWithSongs.playlistEntity.playlistName}.${M3UConstants.EXTENSION}"
val file = File(dir, fileName)
val songs: List<Song> = playlistWithSongs.songs.toSongs()
if (songs.isNotEmpty()) {
val bufferedWriter = BufferedWriter(FileWriter(file))
bufferedWriter.write(M3UConstants.HEADER)
songs.forEach {
bufferedWriter.newLine()
bufferedWriter.write(M3UConstants.ENTRY + it.duration + M3UConstants.DURATION_SEPARATOR + it.artistName + " - " + it.title)
bufferedWriter.newLine()
bufferedWriter.write(it.data)
}
bufferedWriter.close()
}
return file
}
}

View file

@ -1,472 +0,0 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.helper
import android.annotation.TargetApi
import android.app.Activity
import android.content.*
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.IBinder
import android.provider.DocumentsContract
import android.widget.Toast
import androidx.core.content.ContextCompat
import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.repository.SongRepository
import io.github.muntashirakon.music.service.MusicService
import io.github.muntashirakon.music.util.PreferenceUtil
import java.io.File
import java.util.*
import org.koin.core.KoinComponent
import org.koin.core.inject
object MusicPlayerRemote : KoinComponent {
val TAG: String = MusicPlayerRemote::class.java.simpleName
private val mConnectionMap = WeakHashMap<Context, ServiceBinder>()
var musicService: MusicService? = null
private val songRepository by inject<SongRepository>()
@JvmStatic
val isPlaying: Boolean
get() = musicService != null && musicService!!.isPlaying
fun isPlaying(song: Song): Boolean {
return if (!isPlaying) {
false
} else song.id == currentSong.id
}
val currentSong: Song
get() = if (musicService != null) {
musicService!!.currentSong
} else Song.emptySong
/**
* Async
*/
var position: Int
get() = if (musicService != null) {
musicService!!.position
} else -1
set(position) {
if (musicService != null) {
musicService!!.position = position
}
}
@JvmStatic
val playingQueue: List<Song>
get() = if (musicService != null) {
musicService?.playingQueue as List<Song>
} else listOf<Song>()
val songProgressMillis: Int
get() = if (musicService != null) {
musicService!!.songProgressMillis
} else -1
val songDurationMillis: Int
get() = if (musicService != null) {
musicService!!.songDurationMillis
} else -1
val repeatMode: Int
get() = if (musicService != null) {
musicService!!.repeatMode
} else MusicService.REPEAT_MODE_NONE
@JvmStatic
val shuffleMode: Int
get() = if (musicService != null) {
musicService!!.shuffleMode
} else MusicService.SHUFFLE_MODE_NONE
val audioSessionId: Int
get() = if (musicService != null) {
musicService!!.audioSessionId
} else -1
val isServiceConnected: Boolean
get() = musicService != null
fun bindToService(context: Context, callback: ServiceConnection): ServiceToken? {
var realActivity: Activity? = (context as Activity).parent
if (realActivity == null) {
realActivity = context
}
val contextWrapper = ContextWrapper(realActivity)
val intent = Intent(contextWrapper, MusicService::class.java)
try {
contextWrapper.startService(intent)
} catch (ignored: IllegalStateException) {
ContextCompat.startForegroundService(context, intent)
}
val binder = ServiceBinder(callback)
if (contextWrapper.bindService(
Intent().setClass(contextWrapper, MusicService::class.java),
binder,
Context.BIND_AUTO_CREATE
)
) {
mConnectionMap[contextWrapper] = binder
return ServiceToken(contextWrapper)
}
return null
}
fun unbindFromService(token: ServiceToken?) {
if (token == null) {
return
}
val mContextWrapper = token.mWrappedContext
val mBinder = mConnectionMap.remove(mContextWrapper) ?: return
mContextWrapper.unbindService(mBinder)
if (mConnectionMap.isEmpty()) {
musicService = null
}
}
private fun getFilePathFromUri(context: Context, uri: Uri): String? {
var cursor: Cursor? = null
val column = "_data"
val projection = arrayOf(column)
try {
cursor = context.contentResolver.query(uri, projection, null, null, null)
if (cursor != null && cursor.moveToFirst()) {
val columnIndex = cursor.getColumnIndexOrThrow(column)
return cursor.getString(columnIndex)
}
} catch (e: Exception) {
println(e.message)
} finally {
cursor?.close()
}
return null
}
fun getQueueDurationSongs(): Int {
return musicService?.playingQueue?.size ?: -1
}
/**
* Async
*/
fun playSongAt(position: Int) {
musicService?.playSongAt(position)
}
fun pauseSong() {
musicService?.pause()
}
/**
* Async
*/
fun playNextSong() {
musicService?.playNextSong(true)
}
/**
* Async
*/
fun playPreviousSong() {
musicService?.playPreviousSong(true)
}
/**
* Async
*/
fun back() {
musicService?.back(true)
}
fun resumePlaying() {
musicService?.play()
}
/**
* Async
*/
@JvmStatic
fun openQueue(queue: List<Song>, startPosition: Int, startPlaying: Boolean) {
if (!tryToHandleOpenPlayingQueue(
queue,
startPosition,
startPlaying
) && musicService != null
) {
musicService?.openQueue(queue, startPosition, startPlaying)
if (PreferenceUtil.isShuffleModeOn)
setShuffleMode(MusicService.SHUFFLE_MODE_NONE)
}
}
/**
* Async
*/
@JvmStatic
fun openAndShuffleQueue(queue: List<Song>, startPlaying: Boolean) {
var startPosition = 0
if (queue.isNotEmpty()) {
startPosition = Random().nextInt(queue.size)
}
if (!tryToHandleOpenPlayingQueue(
queue,
startPosition,
startPlaying
) && musicService != null
) {
openQueue(queue, startPosition, startPlaying)
setShuffleMode(MusicService.SHUFFLE_MODE_SHUFFLE)
}
}
private fun tryToHandleOpenPlayingQueue(
queue: List<Song>,
startPosition: Int,
startPlaying: Boolean
): Boolean {
if (playingQueue === queue) {
if (startPlaying) {
playSongAt(startPosition)
} else {
position = startPosition
}
return true
}
return false
}
fun getQueueDurationMillis(position: Int): Long {
return if (musicService != null) {
musicService!!.getQueueDurationMillis(position)
} else -1
}
fun seekTo(millis: Int): Int {
return if (musicService != null) {
musicService!!.seek(millis)
} else -1
}
fun cycleRepeatMode(): Boolean {
if (musicService != null) {
musicService?.cycleRepeatMode()
return true
}
return false
}
fun toggleShuffleMode(): Boolean {
if (musicService != null) {
musicService?.toggleShuffle()
return true
}
return false
}
fun setShuffleMode(shuffleMode: Int): Boolean {
if (musicService != null) {
musicService!!.shuffleMode = shuffleMode
return true
}
return false
}
fun playNext(song: Song): Boolean {
if (musicService != null) {
if (playingQueue.size > 0) {
musicService?.addSong(position + 1, song)
} else {
val queue = ArrayList<Song>()
queue.add(song)
openQueue(queue, 0, false)
}
Toast.makeText(
musicService,
musicService!!.resources.getString(io.github.muntashirakon.music.R.string.added_title_to_playing_queue),
Toast.LENGTH_SHORT
).show()
return true
}
return false
}
fun playNext(songs: List<Song>): Boolean {
if (musicService != null) {
if (playingQueue.size > 0) {
musicService?.addSongs(position + 1, songs)
} else {
openQueue(songs, 0, false)
}
val toast =
if (songs.size == 1) musicService!!.resources.getString(io.github.muntashirakon.music.R.string.added_title_to_playing_queue) else musicService!!.resources.getString(
io.github.muntashirakon.music.R.string.added_x_titles_to_playing_queue,
songs.size
)
Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show()
return true
}
return false
}
fun enqueue(song: Song): Boolean {
if (musicService != null) {
if (playingQueue.size > 0) {
musicService?.addSong(song)
} else {
val queue = ArrayList<Song>()
queue.add(song)
openQueue(queue, 0, false)
}
Toast.makeText(
musicService,
musicService!!.resources.getString(io.github.muntashirakon.music.R.string.added_title_to_playing_queue),
Toast.LENGTH_SHORT
).show()
return true
}
return false
}
fun enqueue(songs: List<Song>): Boolean {
if (musicService != null) {
if (playingQueue.size > 0) {
musicService?.addSongs(songs)
} else {
openQueue(songs, 0, false)
}
val toast =
if (songs.size == 1) musicService!!.resources.getString(io.github.muntashirakon.music.R.string.added_title_to_playing_queue) else musicService!!.resources.getString(
io.github.muntashirakon.music.R.string.added_x_titles_to_playing_queue,
songs.size
)
Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show()
return true
}
return false
}
@JvmStatic
fun removeFromQueue(song: Song): Boolean {
if (musicService != null) {
musicService!!.removeSong(song)
return true
}
return false
}
fun removeFromQueue(position: Int): Boolean {
if (musicService != null && position >= 0 && position < playingQueue.size) {
musicService!!.removeSong(position)
return true
}
return false
}
fun moveSong(from: Int, to: Int): Boolean {
if (musicService != null && from >= 0 && to >= 0 && from < playingQueue.size && to < playingQueue.size) {
musicService!!.moveSong(from, to)
return true
}
return false
}
fun clearQueue(): Boolean {
if (musicService != null) {
musicService!!.clearQueue()
return true
}
return false
}
@JvmStatic
fun playFromUri(uri: Uri) {
if (musicService != null) {
var songs: List<Song>? = null
if (uri.scheme != null && uri.authority != null) {
if (uri.scheme == ContentResolver.SCHEME_CONTENT) {
var songId: String? = null
if (uri.authority == "com.android.providers.media.documents") {
songId = getSongIdFromMediaProvider(uri)
} else if (uri.authority == "media") {
songId = uri.lastPathSegment
}
if (songId != null) {
songs = songRepository.songs(songId)
}
}
}
if (songs == null) {
var songFile: File? = null
if (uri.authority != null && uri.authority == "com.android.externalstorage.documents") {
songFile = File(
Environment.getExternalStorageDirectory(),
uri.path?.split(":".toRegex(), 2)?.get(1)
)
}
if (songFile == null) {
val path = getFilePathFromUri(musicService!!, uri)
if (path != null)
songFile = File(path)
}
if (songFile == null && uri.path != null) {
songFile = File(uri.path)
}
if (songFile != null) {
songs = songRepository.songsByFilePath(songFile.absolutePath)
}
}
if (songs != null && songs.isNotEmpty()) {
openQueue(songs, 0, true)
} else {
// TODO the file is not listed in the media store
println("The file is not listed in the media store")
}
}
}
@TargetApi(Build.VERSION_CODES.KITKAT)
private fun getSongIdFromMediaProvider(uri: Uri): String {
return DocumentsContract.getDocumentId(uri).split(":".toRegex())
.dropLastWhile { it.isEmpty() }.toTypedArray()[1]
}
class ServiceBinder internal constructor(private val mCallback: ServiceConnection?) :
ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as MusicService.MusicBinder
musicService = binder.service
mCallback?.onServiceConnected(className, service)
}
override fun onServiceDisconnected(className: ComponentName) {
mCallback?.onServiceDisconnected(className)
musicService = null
}
}
class ServiceToken internal constructor(internal var mWrappedContext: ContextWrapper)
}

View file

@ -1,84 +0,0 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.helper
import android.os.Handler
import android.os.Message
class MusicProgressViewUpdateHelper : Handler {
private var callback: Callback? = null
private var intervalPlaying: Int = 0
private var intervalPaused: Int = 0
fun start() {
queueNextRefresh(1)
}
fun stop() {
removeMessages(CMD_REFRESH_PROGRESS_VIEWS)
}
constructor(callback: Callback) {
this.callback = callback
this.intervalPlaying = UPDATE_INTERVAL_PLAYING
this.intervalPaused = UPDATE_INTERVAL_PAUSED
}
constructor(callback: Callback, intervalPlaying: Int, intervalPaused: Int) {
this.callback = callback
this.intervalPlaying = intervalPlaying
this.intervalPaused = intervalPaused
}
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
if (msg.what == CMD_REFRESH_PROGRESS_VIEWS) {
queueNextRefresh(refreshProgressViews().toLong())
}
}
private fun refreshProgressViews(): Int {
val progressMillis = MusicPlayerRemote.songProgressMillis
val totalMillis = MusicPlayerRemote.songDurationMillis
if (totalMillis > 0)
callback?.onUpdateProgressViews(progressMillis, totalMillis)
if (!MusicPlayerRemote.isPlaying) {
return intervalPaused
}
val remainingMillis = intervalPlaying - progressMillis % intervalPlaying
return Math.max(MIN_INTERVAL, remainingMillis)
}
private fun queueNextRefresh(delay: Long) {
val message = obtainMessage(CMD_REFRESH_PROGRESS_VIEWS)
removeMessages(CMD_REFRESH_PROGRESS_VIEWS)
sendMessageDelayed(message, delay)
}
interface Callback {
fun onUpdateProgressViews(progress: Int, total: Int)
}
companion object {
private const val CMD_REFRESH_PROGRESS_VIEWS = 1
private const val MIN_INTERVAL = 20
private const val UPDATE_INTERVAL_PLAYING = 1000
private const val UPDATE_INTERVAL_PAUSED = 500
}
}

View file

@ -1,27 +0,0 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.helper
import android.view.View
class PlayPauseButtonOnClickHandler : View.OnClickListener {
override fun onClick(v: View) {
if (MusicPlayerRemote.isPlaying) {
MusicPlayerRemote.pauseSong()
} else {
MusicPlayerRemote.resumePlaying()
}
}
}

View file

@ -1,147 +0,0 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.helper
import android.app.SearchManager
import android.os.Bundle
import android.provider.MediaStore
import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.repository.RealSongRepository
import java.util.*
import org.koin.core.KoinComponent
import org.koin.core.inject
object SearchQueryHelper : KoinComponent {
private const val TITLE_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.TITLE + ") = ?"
private const val ALBUM_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ALBUM + ") = ?"
private const val ARTIST_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ARTIST + ") = ?"
private const val AND = " AND "
private val songRepository by inject<RealSongRepository>()
var songs = ArrayList<Song>()
@JvmStatic
fun getSongs(extras: Bundle): List<Song> {
val query = extras.getString(SearchManager.QUERY, null)
val artistName = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST, null)
val albumName = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM, null)
val titleName = extras.getString(MediaStore.EXTRA_MEDIA_TITLE, null)
var songs = listOf<Song>()
if (artistName != null && albumName != null && titleName != null) {
songs = songRepository.songs(
songRepository.makeSongCursor(
ARTIST_SELECTION + AND + ALBUM_SELECTION + AND + TITLE_SELECTION,
arrayOf(
artistName.toLowerCase(Locale.getDefault()),
albumName.toLowerCase(Locale.getDefault()),
titleName.toLowerCase(Locale.getDefault())
)
)
)
}
if (songs.isNotEmpty()) {
return songs
}
if (artistName != null && titleName != null) {
songs = songRepository.songs(
songRepository.makeSongCursor(
ARTIST_SELECTION + AND + TITLE_SELECTION,
arrayOf(
artistName.toLowerCase(Locale.getDefault()),
titleName.toLowerCase(Locale.getDefault())
)
)
)
}
if (songs.isNotEmpty()) {
return songs
}
if (albumName != null && titleName != null) {
songs = songRepository.songs(
songRepository.makeSongCursor(
ALBUM_SELECTION + AND + TITLE_SELECTION,
arrayOf(
albumName.toLowerCase(Locale.getDefault()),
titleName.toLowerCase(Locale.getDefault())
)
)
)
}
if (songs.isNotEmpty()) {
return songs
}
if (artistName != null) {
songs = songRepository.songs(
songRepository.makeSongCursor(
ARTIST_SELECTION,
arrayOf(artistName.toLowerCase(Locale.getDefault()))
)
)
}
if (songs.isNotEmpty()) {
return songs
}
if (albumName != null) {
songs = songRepository.songs(
songRepository.makeSongCursor(
ALBUM_SELECTION,
arrayOf(albumName.toLowerCase(Locale.getDefault()))
)
)
}
if (songs.isNotEmpty()) {
return songs
}
if (titleName != null) {
songs = songRepository.songs(
songRepository.makeSongCursor(
TITLE_SELECTION,
arrayOf(titleName.toLowerCase(Locale.getDefault()))
)
)
}
if (songs.isNotEmpty()) {
return songs
}
songs = songRepository.songs(
songRepository.makeSongCursor(
ARTIST_SELECTION,
arrayOf(query.toLowerCase(Locale.getDefault()))
)
)
if (songs.isNotEmpty()) {
return songs
}
songs = songRepository.songs(
songRepository.makeSongCursor(
ALBUM_SELECTION,
arrayOf(query.toLowerCase(Locale.getDefault()))
)
)
if (songs.isNotEmpty()) {
return songs
}
songs = songRepository.songs(
songRepository.makeSongCursor(
TITLE_SELECTION,
arrayOf(query.toLowerCase(Locale.getDefault()))
)
)
return if (songs.isNotEmpty()) {
songs
} else ArrayList()
}
}

View file

@ -1,31 +0,0 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.helper
import io.github.muntashirakon.music.model.Song
object ShuffleHelper {
fun makeShuffleList(listToShuffle: MutableList<Song>, current: Int) {
if (listToShuffle.isEmpty()) return
if (current >= 0) {
val song = listToShuffle.removeAt(current)
listToShuffle.shuffle()
listToShuffle.add(0, song)
} else {
listToShuffle.shuffle()
}
}
}

View file

@ -1,208 +0,0 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.helper
import android.provider.MediaStore
class SortOrder {
/**
* Artist sort order entries.
*/
interface ArtistSortOrder {
companion object {
/* Artist sort order A-Z */
const val ARTIST_A_Z = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER
/* Artist sort order Z-A */
const val ARTIST_Z_A = "$ARTIST_A_Z DESC"
/* Artist sort order number of songs */
const val ARTIST_NUMBER_OF_SONGS = MediaStore.Audio.Artists.NUMBER_OF_TRACKS + " DESC"
/* Artist sort order number of albums */
const val ARTIST_NUMBER_OF_ALBUMS = MediaStore.Audio.Artists.NUMBER_OF_ALBUMS + " DESC"
}
}
/**
* Album sort order entries.
*/
interface AlbumSortOrder {
companion object {
/* Album sort order A-Z */
const val ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER
/* Album sort order Z-A */
const val ALBUM_Z_A = "$ALBUM_A_Z DESC"
/* Album sort order songs */
const val ALBUM_NUMBER_OF_SONGS = MediaStore.Audio.Albums.NUMBER_OF_SONGS + " DESC"
/* Album sort order artist */
const val ALBUM_ARTIST = (MediaStore.Audio.Artists.DEFAULT_SORT_ORDER +
", " + MediaStore.Audio.Albums.DEFAULT_SORT_ORDER)
/* Album sort order year */
const val ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC"
}
}
/**
* Song sort order entries.
*/
interface SongSortOrder {
companion object {
/* Song sort order A-Z */
const val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER
/* Song sort order Z-A */
const val SONG_Z_A = "$SONG_A_Z DESC"
/* Song sort order artist */
const val SONG_ARTIST = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER
/* Song sort order album */
const val SONG_ALBUM = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER
/* Song sort order year */
const val SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC"
/* Song sort order duration */
const val SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC"
/* Song sort order date */
const val SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC"
/* Song sort modified date */
const val SONG_DATE_MODIFIED = MediaStore.Audio.Media.DATE_MODIFIED + " DESC"
/* Song sort order composer*/
const val COMPOSER = MediaStore.Audio.Media.COMPOSER
}
}
/**
* Album song sort order entries.
*/
interface AlbumSongSortOrder {
companion object {
/* Album song sort order A-Z */
const val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER
/* Album song sort order Z-A */
const val SONG_Z_A = "$SONG_A_Z DESC"
/* Album song sort order track list */
const val SONG_TRACK_LIST = (MediaStore.Audio.Media.TRACK + ", " +
MediaStore.Audio.Media.DEFAULT_SORT_ORDER)
/* Album song sort order duration */
const val SONG_DURATION = SongSortOrder.SONG_DURATION
}
}
/**
* Artist song sort order entries.
*/
interface ArtistSongSortOrder {
companion object {
/* Artist song sort order A-Z */
const val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER
/* Artist song sort order Z-A */
const val SONG_Z_A = "$SONG_A_Z DESC"
/* Artist song sort order album */
const val SONG_ALBUM = MediaStore.Audio.Media.ALBUM
/* Artist song sort order year */
const val SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC"
/* Artist song sort order duration */
const val SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC"
/* Artist song sort order date */
const val SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC"
}
}
/**
* Artist album sort order entries.
*/
interface ArtistAlbumSortOrder {
companion object {
/* Artist album sort order A-Z */
const val ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER
/* Artist album sort order Z-A */
const val ALBUM_Z_A = "$ALBUM_A_Z DESC"
/* Artist album sort order year */
const val ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC"
/* Artist album sort order year */
const val ALBUM_YEAR_ASC = MediaStore.Audio.Media.YEAR + " ASC"
}
}
/**
* Genre sort order entries.
*/
interface GenreSortOrder {
companion object {
/* Genre sort order A-Z */
const val GENRE_A_Z = MediaStore.Audio.Genres.DEFAULT_SORT_ORDER
/* Genre sort order Z-A */
const val ALBUM_Z_A = "$GENRE_A_Z DESC"
}
}
/**
* Playlist sort order entries.
*/
interface PlaylistSortOrder {
companion object {
/* Playlist sort order A-Z */
const val PLAYLIST_A_Z = MediaStore.Audio.Playlists.DEFAULT_SORT_ORDER
/* Playlist sort order Z-A */
const val PLAYLIST_Z_A = "$PLAYLIST_A_Z DESC"
/* Playlist sort order number of songs */
const val PLAYLIST_SONG_COUNT = "playlist_song_count"
/* Playlist sort order number of songs */
const val PLAYLIST_SONG_COUNT_DESC = "$PLAYLIST_SONG_COUNT DESC"
}
}
}

View file

@ -1,319 +0,0 @@
package io.github.muntashirakon.music.helper;
import android.graphics.Bitmap;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Blur using Java code.
*
* <p>This is a compromise between Gaussian Blur and Box blur It creates much better looking blurs
* than Box Blur, but is 7x faster than my Gaussian Blur implementation.
*
* <p>I called it Stack Blur because this describes best how this filter works internally: it
* creates a kind of moving stack of colors whilst scanning through the image. Thereby it just has
* to add one new block of color to the right side of the stack and remove the leftmost color. The
* remaining colors on the topmost layer of the stack are either added on or reduced by one,
* depending on if they are on the right or on the left side of the stack.
*
* @author Enrique López Mañas <eenriquelopez@gmail.com> http://www.neo-tech.es
* <p>Author of the original algorithm: Mario Klingemann <mario.quasimondo.com>
* <p>Based heavily on http://vitiy.info/Code/stackblur.cpp See
* http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp/
* @copyright: Enrique López Mañas
* @license: Apache License 2.0
*/
public class StackBlur {
static final int EXECUTOR_THREADS = Runtime.getRuntime().availableProcessors();
static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(EXECUTOR_THREADS);
private static final short[] stackblur_mul = {
512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512,
454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512,
482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456,
437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512,
497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328,
320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456,
446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335,
329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512,
505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405,
399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328,
324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271,
268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456,
451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388,
385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335,
332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292,
289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259
};
private static final byte[] stackblur_shr = {
9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
};
public static Bitmap blur(Bitmap original, float radius) {
int w = original.getWidth();
int h = original.getHeight();
int[] currentPixels = new int[w * h];
original.getPixels(currentPixels, 0, w, 0, 0, w, h);
int cores = EXECUTOR_THREADS;
ArrayList<BlurTask> horizontal = new ArrayList<BlurTask>(cores);
ArrayList<BlurTask> vertical = new ArrayList<BlurTask>(cores);
for (int i = 0; i < cores; i++) {
horizontal.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 1));
vertical.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 2));
}
try {
EXECUTOR.invokeAll(horizontal);
} catch (InterruptedException e) {
return null;
}
try {
EXECUTOR.invokeAll(vertical);
} catch (InterruptedException e) {
return null;
}
return Bitmap.createBitmap(currentPixels, w, h, Bitmap.Config.ARGB_8888);
}
private static void blurIteration(
int[] src, int w, int h, int radius, int cores, int core, int step) {
int x, y, xp, yp, i;
int sp;
int stack_start;
int stack_i;
int src_i;
int dst_i;
long sum_r, sum_g, sum_b, sum_in_r, sum_in_g, sum_in_b, sum_out_r, sum_out_g, sum_out_b;
int wm = w - 1;
int hm = h - 1;
int div = (radius * 2) + 1;
int mul_sum = stackblur_mul[radius];
byte shr_sum = stackblur_shr[radius];
int[] stack = new int[div];
if (step == 1) {
int minY = core * h / cores;
int maxY = (core + 1) * h / cores;
for (y = minY; y < maxY; y++) {
sum_r =
sum_g = sum_b = sum_in_r = sum_in_g = sum_in_b = sum_out_r = sum_out_g = sum_out_b = 0;
src_i = w * y; // start of line (0,y)
for (i = 0; i <= radius; i++) {
stack_i = i;
stack[stack_i] = src[src_i];
sum_r += ((src[src_i] >>> 16) & 0xff) * (i + 1);
sum_g += ((src[src_i] >>> 8) & 0xff) * (i + 1);
sum_b += (src[src_i] & 0xff) * (i + 1);
sum_out_r += ((src[src_i] >>> 16) & 0xff);
sum_out_g += ((src[src_i] >>> 8) & 0xff);
sum_out_b += (src[src_i] & 0xff);
}
for (i = 1; i <= radius; i++) {
if (i <= wm) src_i += 1;
stack_i = i + radius;
stack[stack_i] = src[src_i];
sum_r += ((src[src_i] >>> 16) & 0xff) * (radius + 1 - i);
sum_g += ((src[src_i] >>> 8) & 0xff) * (radius + 1 - i);
sum_b += (src[src_i] & 0xff) * (radius + 1 - i);
sum_in_r += ((src[src_i] >>> 16) & 0xff);
sum_in_g += ((src[src_i] >>> 8) & 0xff);
sum_in_b += (src[src_i] & 0xff);
}
sp = radius;
xp = radius;
if (xp > wm) xp = wm;
src_i = xp + y * w; // img.pix_ptr(xp, y);
dst_i = y * w; // img.pix_ptr(0, y);
for (x = 0; x < w; x++) {
src[dst_i] =
(int)
((src[dst_i] & 0xFFFFFFFF)
| ((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16)
| ((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8)
| ((((sum_b * mul_sum) >>> shr_sum) & 0xff)));
dst_i += 1;
sum_r -= sum_out_r;
sum_g -= sum_out_g;
sum_b -= sum_out_b;
stack_start = sp + div - radius;
if (stack_start >= div) stack_start -= div;
stack_i = stack_start;
sum_out_r -= ((stack[stack_i] >>> 16) & 0xff);
sum_out_g -= ((stack[stack_i] >>> 8) & 0xff);
sum_out_b -= (stack[stack_i] & 0xff);
if (xp < wm) {
src_i += 1;
++xp;
}
stack[stack_i] = src[src_i];
sum_in_r += ((src[src_i] >>> 16) & 0xff);
sum_in_g += ((src[src_i] >>> 8) & 0xff);
sum_in_b += (src[src_i] & 0xff);
sum_r += sum_in_r;
sum_g += sum_in_g;
sum_b += sum_in_b;
++sp;
if (sp >= div) sp = 0;
stack_i = sp;
sum_out_r += ((stack[stack_i] >>> 16) & 0xff);
sum_out_g += ((stack[stack_i] >>> 8) & 0xff);
sum_out_b += (stack[stack_i] & 0xff);
sum_in_r -= ((stack[stack_i] >>> 16) & 0xff);
sum_in_g -= ((stack[stack_i] >>> 8) & 0xff);
sum_in_b -= (stack[stack_i] & 0xff);
}
}
}
// step 2
else if (step == 2) {
int minX = core * w / cores;
int maxX = (core + 1) * w / cores;
for (x = minX; x < maxX; x++) {
sum_r =
sum_g = sum_b = sum_in_r = sum_in_g = sum_in_b = sum_out_r = sum_out_g = sum_out_b = 0;
src_i = x; // x,0
for (i = 0; i <= radius; i++) {
stack_i = i;
stack[stack_i] = src[src_i];
sum_r += ((src[src_i] >>> 16) & 0xff) * (i + 1);
sum_g += ((src[src_i] >>> 8) & 0xff) * (i + 1);
sum_b += (src[src_i] & 0xff) * (i + 1);
sum_out_r += ((src[src_i] >>> 16) & 0xff);
sum_out_g += ((src[src_i] >>> 8) & 0xff);
sum_out_b += (src[src_i] & 0xff);
}
for (i = 1; i <= radius; i++) {
if (i <= hm) src_i += w; // +stride
stack_i = i + radius;
stack[stack_i] = src[src_i];
sum_r += ((src[src_i] >>> 16) & 0xff) * (radius + 1 - i);
sum_g += ((src[src_i] >>> 8) & 0xff) * (radius + 1 - i);
sum_b += (src[src_i] & 0xff) * (radius + 1 - i);
sum_in_r += ((src[src_i] >>> 16) & 0xff);
sum_in_g += ((src[src_i] >>> 8) & 0xff);
sum_in_b += (src[src_i] & 0xff);
}
sp = radius;
yp = radius;
if (yp > hm) yp = hm;
src_i = x + yp * w; // img.pix_ptr(x, yp);
dst_i = x; // img.pix_ptr(x, 0);
for (y = 0; y < h; y++) {
src[dst_i] =
(int)
((src[dst_i] & 0xFFFFFFFF)
| ((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16)
| ((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8)
| ((((sum_b * mul_sum) >>> shr_sum) & 0xff)));
dst_i += w;
sum_r -= sum_out_r;
sum_g -= sum_out_g;
sum_b -= sum_out_b;
stack_start = sp + div - radius;
if (stack_start >= div) stack_start -= div;
stack_i = stack_start;
sum_out_r -= ((stack[stack_i] >>> 16) & 0xff);
sum_out_g -= ((stack[stack_i] >>> 8) & 0xff);
sum_out_b -= (stack[stack_i] & 0xff);
if (yp < hm) {
src_i += w; // stride
++yp;
}
stack[stack_i] = src[src_i];
sum_in_r += ((src[src_i] >>> 16) & 0xff);
sum_in_g += ((src[src_i] >>> 8) & 0xff);
sum_in_b += (src[src_i] & 0xff);
sum_r += sum_in_r;
sum_g += sum_in_g;
sum_b += sum_in_b;
++sp;
if (sp >= div) sp = 0;
stack_i = sp;
sum_out_r += ((stack[stack_i] >>> 16) & 0xff);
sum_out_g += ((stack[stack_i] >>> 8) & 0xff);
sum_out_b += (stack[stack_i] & 0xff);
sum_in_r -= ((stack[stack_i] >>> 16) & 0xff);
sum_in_g -= ((stack[stack_i] >>> 8) & 0xff);
sum_in_b -= (stack[stack_i] & 0xff);
}
}
}
}
private static class BlurTask implements Callable<Void> {
private final int[] _src;
private final int _w;
private final int _h;
private final int _radius;
private final int _totalCores;
private final int _coreIndex;
private final int _round;
public BlurTask(int[] src, int w, int h, int radius, int totalCores, int coreIndex, int round) {
_src = src;
_w = w;
_h = h;
_radius = radius;
_totalCores = totalCores;
_coreIndex = coreIndex;
_round = round;
}
@Override
public Void call() throws Exception {
blurIteration(_src, _w, _h, _radius, _totalCores, _coreIndex, _round);
return null;
}
}
}

View file

@ -1,94 +0,0 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.helper
/**
* Simple thread safe stop watch.
*
* @author Karim Abou Zeid (kabouzeid)
*/
class StopWatch {
/**
* The time the stop watch was last started.
*/
private var startTime: Long = 0
/**
* The time elapsed before the current [.startTime].
*/
private var previousElapsedTime: Long = 0
/**
* Whether the stop watch is currently running or not.
*/
private var isRunning: Boolean = false
/**
* @return the total elapsed time in milliseconds
*/
val elapsedTime: Long
get() = synchronized(this) {
var currentElapsedTime: Long = 0
if (isRunning) {
currentElapsedTime = System.currentTimeMillis() - startTime
}
return previousElapsedTime + currentElapsedTime
}
/**
* Starts or continues the stop watch.
*
* @see .pause
* @see .reset
*/
fun start() {
synchronized(this) {
startTime = System.currentTimeMillis()
isRunning = true
}
}
/**
* Pauses the stop watch. It can be continued later from [.start].
*
* @see .start
* @see .reset
*/
fun pause() {
synchronized(this) {
previousElapsedTime += System.currentTimeMillis() - startTime
isRunning = false
}
}
/**
* Stops and resets the stop watch to zero milliseconds.
*
* @see .start
* @see .pause
*/
fun reset() {
synchronized(this) {
startTime = 0
previousElapsedTime = 0
isRunning = false
}
}
override fun toString(): String {
return String.format("%d millis", elapsedTime)
}
}

View file

@ -1,67 +0,0 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.helper.menu
import android.view.MenuItem
import androidx.fragment.app.FragmentActivity
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.model.Genre
import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.repository.GenreRepository
import io.github.muntashirakon.music.repository.RealRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.core.KoinComponent
import org.koin.core.get
import org.koin.core.inject
object GenreMenuHelper : KoinComponent {
private val genreRepository by inject<GenreRepository>()
fun handleMenuClick(activity: FragmentActivity, genre: Genre, item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_play -> {
MusicPlayerRemote.openQueue(getGenreSongs(genre), 0, true)
return true
}
R.id.action_play_next -> {
MusicPlayerRemote.playNext(getGenreSongs(genre))
return true
}
R.id.action_add_to_playlist -> {
CoroutineScope(Dispatchers.IO).launch {
val playlists = get<RealRepository>().fetchPlaylists()
withContext(Dispatchers.Main) {
AddToPlaylistDialog.create(playlists, getGenreSongs(genre))
.show(activity.supportFragmentManager, "ADD_PLAYLIST")
}
}
return true
}
R.id.action_add_to_current_playing -> {
MusicPlayerRemote.enqueue(getGenreSongs(genre))
return true
}
}
return false
}
private fun getGenreSongs(genre: Genre): List<Song> {
return genreRepository.songs(genre.id)
}
}

View file

@ -1,83 +0,0 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.helper.menu
import android.view.MenuItem
import androidx.fragment.app.FragmentActivity
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.db.PlaylistWithSongs
import io.github.muntashirakon.music.db.toSongs
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
import io.github.muntashirakon.music.dialogs.DeletePlaylistDialog
import io.github.muntashirakon.music.dialogs.RenamePlaylistDialog
import io.github.muntashirakon.music.dialogs.SavePlaylistDialog
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.repository.RealRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.core.KoinComponent
import org.koin.core.get
object PlaylistMenuHelper : KoinComponent {
fun handleMenuClick(
activity: FragmentActivity,
playlistWithSongs: PlaylistWithSongs,
item: MenuItem
): Boolean {
when (item.itemId) {
R.id.action_play -> {
MusicPlayerRemote.openQueue(playlistWithSongs.songs.toSongs(), 0, true)
return true
}
R.id.action_play_next -> {
MusicPlayerRemote.playNext(playlistWithSongs.songs.toSongs())
return true
}
R.id.action_add_to_playlist -> {
CoroutineScope(Dispatchers.IO).launch {
val playlists = get<RealRepository>().fetchPlaylists()
withContext(Dispatchers.Main) {
AddToPlaylistDialog.create(playlists, playlistWithSongs.songs.toSongs())
.show(activity.supportFragmentManager, "ADD_PLAYLIST")
}
}
return true
}
R.id.action_add_to_current_playing -> {
MusicPlayerRemote.enqueue(playlistWithSongs.songs.toSongs())
return true
}
R.id.action_rename_playlist -> {
RenamePlaylistDialog.create(playlistWithSongs.playlistEntity)
.show(activity.supportFragmentManager, "RENAME_PLAYLIST")
return true
}
R.id.action_delete_playlist -> {
DeletePlaylistDialog.create(playlistWithSongs.playlistEntity)
.show(activity.supportFragmentManager, "DELETE_PLAYLIST")
return true
}
R.id.action_save_playlist -> {
SavePlaylistDialog.create(playlistWithSongs)
.show(activity.supportFragmentManager, "SavePlaylist")
return true
}
}
return false
}
}

View file

@ -1,143 +0,0 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.helper.menu
import android.content.Intent
import android.view.MenuItem
import android.view.View
import android.widget.PopupMenu
import androidx.core.os.bundleOf
import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController
import io.github.muntashirakon.music.EXTRA_ALBUM_ID
import io.github.muntashirakon.music.EXTRA_ARTIST_ID
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.activities.tageditor.AbsTagEditorActivity
import io.github.muntashirakon.music.activities.tageditor.SongTagEditorActivity
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
import io.github.muntashirakon.music.dialogs.DeleteSongsDialog
import io.github.muntashirakon.music.dialogs.SongDetailDialog
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.interfaces.IPaletteColorHolder
import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.repository.RealRepository
import io.github.muntashirakon.music.util.MusicUtil
import io.github.muntashirakon.music.util.RingtoneManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.core.KoinComponent
import org.koin.core.get
object SongMenuHelper : KoinComponent {
const val MENU_RES = R.menu.menu_item_song
fun handleMenuClick(activity: FragmentActivity, song: Song, menuItemId: Int): Boolean {
when (menuItemId) {
R.id.action_set_as_ringtone -> {
if (RingtoneManager.requiresDialog(activity)) {
RingtoneManager.getDialog(activity)
} else {
val ringtoneManager = RingtoneManager(activity)
ringtoneManager.setRingtone(song)
}
return true
}
R.id.action_share -> {
activity.startActivity(
Intent.createChooser(
MusicUtil.createShareSongFileIntent(song, activity),
null
)
)
return true
}
R.id.action_delete_from_device -> {
DeleteSongsDialog.create(song).show(activity.supportFragmentManager, "DELETE_SONGS")
return true
}
R.id.action_add_to_playlist -> {
CoroutineScope(Dispatchers.IO).launch {
val playlists = get<RealRepository>().fetchPlaylists()
withContext(Dispatchers.Main) {
AddToPlaylistDialog.create(playlists, song)
.show(activity.supportFragmentManager, "ADD_PLAYLIST")
}
}
return true
}
R.id.action_play_next -> {
MusicPlayerRemote.playNext(song)
return true
}
R.id.action_add_to_current_playing -> {
MusicPlayerRemote.enqueue(song)
return true
}
R.id.action_tag_editor -> {
val tagEditorIntent = Intent(activity, SongTagEditorActivity::class.java)
tagEditorIntent.putExtra(AbsTagEditorActivity.EXTRA_ID, song.id)
if (activity is IPaletteColorHolder)
tagEditorIntent.putExtra(
AbsTagEditorActivity.EXTRA_PALETTE,
(activity as IPaletteColorHolder).paletteColor
)
activity.startActivity(tagEditorIntent)
return true
}
R.id.action_details -> {
SongDetailDialog.create(song).show(activity.supportFragmentManager, "SONG_DETAILS")
return true
}
R.id.action_go_to_album -> {
activity.findNavController(R.id.fragment_container).navigate(
R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to song.albumId)
)
return true
}
R.id.action_go_to_artist -> {
activity.findNavController(R.id.fragment_container).navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to song.artistId)
)
return true
}
}
return false
}
abstract class OnClickSongMenu(private val activity: FragmentActivity) :
View.OnClickListener, PopupMenu.OnMenuItemClickListener {
open val menuRes: Int
get() = MENU_RES
abstract val song: Song
override fun onClick(v: View) {
val popupMenu = PopupMenu(activity, v)
popupMenu.inflate(menuRes)
popupMenu.setOnMenuItemClickListener(this)
popupMenu.show()
}
override fun onMenuItemClick(item: MenuItem): Boolean {
return handleMenuClick(activity, song, item.itemId)
}
}
}

View file

@ -1,64 +0,0 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music.helper.menu
import androidx.fragment.app.FragmentActivity
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
import io.github.muntashirakon.music.dialogs.DeleteSongsDialog
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.repository.RealRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.core.KoinComponent
import org.koin.core.get
object SongsMenuHelper : KoinComponent {
fun handleMenuClick(
activity: FragmentActivity,
songs: List<Song>,
menuItemId: Int
): Boolean {
when (menuItemId) {
R.id.action_play_next -> {
MusicPlayerRemote.playNext(songs)
return true
}
R.id.action_add_to_current_playing -> {
MusicPlayerRemote.enqueue(songs)
return true
}
R.id.action_add_to_playlist -> {
CoroutineScope(Dispatchers.IO).launch {
val playlists = get<RealRepository>().fetchPlaylists()
withContext(Dispatchers.Main) {
AddToPlaylistDialog.create(playlists, songs)
.show(activity.supportFragmentManager, "ADD_PLAYLIST")
}
}
return true
}
R.id.action_delete_from_device -> {
DeleteSongsDialog.create(songs)
.show(activity.supportFragmentManager, "DELETE_SONGS")
return true
}
}
return false
}
}