Merge branch 'room-playlist' of https://github.com/h4h13/RetroMusicPlayer into room-playlist
This commit is contained in:
commit
3265580275
126 changed files with 1023 additions and 718 deletions
|
@ -34,7 +34,7 @@ android {
|
|||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
Properties properties = getProperties('/Users/h4h13/Documents/Github/retro.properties')
|
||||
Properties properties = getProperties('/Users/apple/Documents/Github/retro.properties ')
|
||||
storeFile file(getProperty(properties, 'storeFile'))
|
||||
keyAlias getProperty(properties, 'keyAlias')
|
||||
storePassword getProperty(properties, 'storePassword')
|
||||
|
@ -129,6 +129,7 @@ dependencies {
|
|||
implementation "com.afollestad.material-dialogs:core:$material_dialog_version"
|
||||
implementation "com.afollestad.material-dialogs:commons:$material_dialog_version"
|
||||
implementation 'com.afollestad:material-cab:0.1.12'
|
||||
implementation 'com.afollestad:recyclical:1.1.1'
|
||||
|
||||
implementation 'com.github.bumptech.glide:glide:3.8.0'
|
||||
implementation 'com.github.bumptech.glide:okhttp3-integration:1.5.0'
|
||||
|
@ -180,5 +181,8 @@ dependencies {
|
|||
implementation "androidx.room:room-runtime:$room_version"
|
||||
kapt "androidx.room:room-compiler:$room_version"
|
||||
implementation "androidx.room:room-ktx:$room_version"
|
||||
|
||||
|
||||
|
||||
debugImplementation 'com.amitshekhar.android:debug-db:1.0.6'
|
||||
}
|
BIN
app/src/debug/res/font/google_sans_bold.ttf
Normal file
BIN
app/src/debug/res/font/google_sans_bold.ttf
Normal file
Binary file not shown.
BIN
app/src/debug/res/font/google_sans_medium.ttf
Normal file
BIN
app/src/debug/res/font/google_sans_medium.ttf
Normal file
Binary file not shown.
BIN
app/src/debug/res/font/google_sans_regular.ttf
Normal file
BIN
app/src/debug/res/font/google_sans_regular.ttf
Normal file
Binary file not shown.
|
@ -1,13 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<font-family xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<font
|
||||
android:font="@font/regular"
|
||||
android:font="@font/google_sans_regular"
|
||||
android:fontWeight="400" />
|
||||
<font
|
||||
android:font="@font/medium"
|
||||
android:font="@font/google_sans_medium"
|
||||
android:fontWeight="600" />
|
||||
<font
|
||||
android:font="@font/bold"
|
||||
android:font="@font/google_sans_bold"
|
||||
android:fontWeight="700" />
|
||||
</font-family>
|
|
@ -255,11 +255,9 @@
|
|||
<meta-data
|
||||
android:name="com.bumptech.glide.integration.okhttp3.OkHttpGlideModule"
|
||||
android:value="GlideModule" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.android.vending.splits.required"
|
||||
android:value="true" />
|
||||
<meta-data
|
||||
android:name="preloaded_fonts"
|
||||
android:resource="@array/preloaded_fonts" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 51 KiB |
|
@ -20,7 +20,6 @@ import code.name.monkey.appthemehelper.ThemeStore
|
|||
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||
import code.name.monkey.retromusic.Constants.PRO_VERSION_PRODUCT_ID
|
||||
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager
|
||||
import com.amitshekhar.DebugDB
|
||||
import com.anjlab.android.iab.v3.BillingProcessor
|
||||
import com.anjlab.android.iab.v3.TransactionDetails
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
|
@ -33,7 +32,7 @@ class App : MultiDexApplication() {
|
|||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
instance = this
|
||||
DebugDB.getAddressLog();
|
||||
|
||||
startKoin {
|
||||
androidContext(this@App)
|
||||
modules(appModules)
|
||||
|
|
|
@ -23,3 +23,6 @@ const val SUGGESTIONS = 5
|
|||
const val FAVOURITES = 4
|
||||
const val GENRES = 6
|
||||
const val PLAYLISTS = 7
|
||||
const val HISTORY_PLAYLIST = 8
|
||||
const val LAST_ADDED_PLAYLIST = 9
|
||||
const val TOP_PLAYED_PLAYLIST = 10
|
|
@ -1,9 +1,12 @@
|
|||
package code.name.monkey.retromusic
|
||||
|
||||
import code.name.monkey.retromusic.db.PlaylistDatabase
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import code.name.monkey.retromusic.db.BlackListStoreEntity
|
||||
import code.name.monkey.retromusic.db.PlaylistDao
|
||||
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
||||
import code.name.monkey.retromusic.repository.RealRoomPlaylistRepository
|
||||
import code.name.monkey.retromusic.repository.RoomPlaylistRepository
|
||||
import code.name.monkey.retromusic.db.RetroDatabase
|
||||
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||
import code.name.monkey.retromusic.fragments.albums.AlbumDetailsViewModel
|
||||
import code.name.monkey.retromusic.fragments.artists.ArtistDetailsViewModel
|
||||
|
@ -13,11 +16,42 @@ import code.name.monkey.retromusic.fragments.search.SearchViewModel
|
|||
import code.name.monkey.retromusic.model.Genre
|
||||
import code.name.monkey.retromusic.network.networkModule
|
||||
import code.name.monkey.retromusic.repository.*
|
||||
import code.name.monkey.retromusic.util.FilePathUtil
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
private val roomModule = module {
|
||||
|
||||
single {
|
||||
Room.databaseBuilder(androidContext(), RetroDatabase::class.java, "playlist.db")
|
||||
.allowMainThreadQueries()
|
||||
.addCallback(object : RoomDatabase.Callback() {
|
||||
override fun onOpen(db: SupportSQLiteDatabase) {
|
||||
super.onOpen(db)
|
||||
GlobalScope.launch(IO) {
|
||||
FilePathUtil.blacklistFilePaths().map {
|
||||
get<PlaylistDao>().insertBlacklistPath(BlackListStoreEntity(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.fallbackToDestructiveMigration()
|
||||
.build()
|
||||
}
|
||||
|
||||
factory {
|
||||
get<RetroDatabase>().playlistDao()
|
||||
}
|
||||
|
||||
single {
|
||||
RealRoomRepository(get())
|
||||
} bind RoomPlaylistRepository::class
|
||||
}
|
||||
private val mainModule = module {
|
||||
single {
|
||||
androidContext().contentResolver
|
||||
|
@ -70,14 +104,6 @@ private val dataModule = module {
|
|||
get()
|
||||
)
|
||||
}
|
||||
|
||||
single {
|
||||
PlaylistDatabase.getDatabase(get()).playlistDao()
|
||||
}
|
||||
|
||||
single {
|
||||
RealRoomPlaylistRepository(get())
|
||||
} bind RoomPlaylistRepository::class
|
||||
}
|
||||
|
||||
private val viewModules = module {
|
||||
|
@ -119,4 +145,4 @@ private val viewModules = module {
|
|||
}
|
||||
}
|
||||
|
||||
val appModules = listOf(mainModule, dataModule, viewModules, networkModule)
|
||||
val appModules = listOf(mainModule, dataModule, viewModules, networkModule, roomModule)
|
|
@ -218,7 +218,7 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
|
|||
.build()
|
||||
.transform(BlurTransformation.Builder(this).build())
|
||||
.into(object : RetroMusicColoredTarget(image) {
|
||||
override fun onColorReady(color: MediaNotificationProcessor) {
|
||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
|
|||
if (intent.action != null && (intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH)
|
||||
) {
|
||||
val songs: List<Song> =
|
||||
getSongs(this, intent.extras!!)
|
||||
getSongs(intent.extras!!)
|
||||
if (shuffleMode == MusicService.SHUFFLE_MODE_SHUFFLE) {
|
||||
openAndShuffleQueue(songs, true)
|
||||
} else {
|
||||
|
|
|
@ -104,7 +104,7 @@ open class PlayingQueueActivity : AbsMusicServiceActivity() {
|
|||
}
|
||||
}
|
||||
})
|
||||
val fastScroller = ThemedFastScroller.create(recyclerView)
|
||||
ThemedFastScroller.create(recyclerView)
|
||||
}
|
||||
|
||||
private fun checkForPadding() {
|
||||
|
|
|
@ -108,7 +108,7 @@ class PurchaseActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler {
|
|||
super.onDestroy()
|
||||
}
|
||||
|
||||
private class RestorePurchaseAsyncTask internal constructor(purchaseActivity: PurchaseActivity) :
|
||||
private class RestorePurchaseAsyncTask(purchaseActivity: PurchaseActivity) :
|
||||
AsyncTask<Void, Void, Boolean>() {
|
||||
|
||||
private val buyActivityWeakReference: WeakReference<PurchaseActivity> = WeakReference(
|
||||
|
|
|
@ -110,7 +110,7 @@ class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingH
|
|||
}
|
||||
if (requestCode == TEZ_REQUEST_CODE) {
|
||||
// Process based on the data in response.
|
||||
Log.d("result", data!!.getStringExtra("Status"))
|
||||
//Log.d("result", data!!.getStringExtra("Status"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,7 @@ class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingH
|
|||
}
|
||||
}
|
||||
|
||||
private class SkuDetailsLoadAsyncTask internal constructor(supportDevelopmentActivity: SupportDevelopmentActivity) :
|
||||
private class SkuDetailsLoadAsyncTask(supportDevelopmentActivity: SupportDevelopmentActivity) :
|
||||
AsyncTask<Void, Void, List<SkuDetails>>() {
|
||||
|
||||
private val weakReference: WeakReference<SupportDevelopmentActivity> = WeakReference(
|
||||
|
|
|
@ -160,7 +160,7 @@ class UserInfoActivity : AbsBaseActivity() {
|
|||
}
|
||||
|
||||
private fun saveImage(bitmap: Bitmap, fileName: String) {
|
||||
CoroutineScope(Dispatchers.IO).launch() {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val appDir = applicationContext.filesDir
|
||||
val file = File(appDir, fileName)
|
||||
var successful = false
|
||||
|
|
|
@ -28,7 +28,7 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior
|
|||
import kotlinx.android.synthetic.main.sliding_music_panel_layout.*
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
||||
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
||||
companion object {
|
||||
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
|
||||
}
|
||||
|
|
|
@ -280,22 +280,22 @@ open class BugReportActivity : AbsThemeActivity() {
|
|||
RESULT_BAD_CREDENTIALS -> MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.bug_report_failed)
|
||||
.setMessage(R.string.bug_report_failed_wrong_credentials)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
RESULT_INVALID_TOKEN -> MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.bug_report_failed)
|
||||
.setMessage(R.string.bug_report_failed_invalid_token)
|
||||
.setPositiveButton(android.R.string.ok, null).show()
|
||||
.setPositiveButton(R.string.ok, null).show()
|
||||
RESULT_ISSUES_NOT_ENABLED -> MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.bug_report_failed)
|
||||
.setMessage(R.string.bug_report_failed_issues_not_available)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
|
||||
else -> MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.bug_report_failed)
|
||||
.setMessage(R.string.bug_report_failed_unknown)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ -> tryToFinishActivity() }
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> { tryToFinishActivity() } }
|
||||
.setPositiveButton(R.string.ok) { _, _ -> tryToFinishActivity() }
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> tryToFinishActivity() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,9 +44,9 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
|||
window.enterTransition = slide
|
||||
}
|
||||
|
||||
override fun loadImageFromFile(selectedFileUri: Uri?) {
|
||||
override fun loadImageFromFile(selectedFile: Uri?) {
|
||||
|
||||
Glide.with(this@AlbumTagEditorActivity).load(selectedFileUri).asBitmap()
|
||||
Glide.with(this@AlbumTagEditorActivity).load(selectedFile).asBitmap()
|
||||
.transcode(BitmapPaletteTranscoder(this), BitmapPaletteWrapper::class.java)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
|
||||
.into(object : SimpleTarget<BitmapPaletteWrapper>() {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package code.name.monkey.retromusic.adapter
|
||||
|
||||
import android.graphics.Color
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -22,14 +23,14 @@ class GenreAdapter(
|
|||
var dataSet: List<Genre>,
|
||||
private val mItemLayoutRes: Int
|
||||
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() {
|
||||
|
||||
|
||||
val colors = listOf<Int>(Color.RED, Color.BLUE)
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
return ViewHolder(LayoutInflater.from(activity).inflate(mItemLayoutRes, parent, false))
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val genre = dataSet[position]
|
||||
|
||||
holder.title?.text = genre.name
|
||||
holder.text?.text = String.format(
|
||||
Locale.getDefault(),
|
||||
|
|
|
@ -40,8 +40,8 @@ class HomeAdapter(
|
|||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val layout = LayoutInflater.from(activity)
|
||||
.inflate(R.layout.section_recycler_view, parent, false)
|
||||
val layout =
|
||||
LayoutInflater.from(activity).inflate(R.layout.section_recycler_view, parent, false)
|
||||
return when (viewType) {
|
||||
RECENT_ARTISTS, TOP_ARTISTS -> ArtistViewHolder(layout)
|
||||
GENRES -> GenreViewHolder(layout)
|
||||
|
@ -64,7 +64,7 @@ class HomeAdapter(
|
|||
when (getItemViewType(position)) {
|
||||
RECENT_ALBUMS -> {
|
||||
val viewHolder = holder as AlbumViewHolder
|
||||
viewHolder.bindView(home.arrayList as List<Album>, R.string.recent_albums)
|
||||
viewHolder.bindView(home)
|
||||
viewHolder.clickableArea.setOnClickListener {
|
||||
activity.findNavController(R.id.fragment_container).navigate(
|
||||
R.id.detailListFragment,
|
||||
|
@ -74,7 +74,7 @@ class HomeAdapter(
|
|||
}
|
||||
TOP_ALBUMS -> {
|
||||
val viewHolder = holder as AlbumViewHolder
|
||||
viewHolder.bindView(home.arrayList as List<Album>, R.string.top_albums)
|
||||
viewHolder.bindView(home)
|
||||
viewHolder.clickableArea.setOnClickListener {
|
||||
activity.findNavController(R.id.fragment_container).navigate(
|
||||
R.id.detailListFragment,
|
||||
|
@ -84,7 +84,7 @@ class HomeAdapter(
|
|||
}
|
||||
RECENT_ARTISTS -> {
|
||||
val viewHolder = holder as ArtistViewHolder
|
||||
viewHolder.bindView(home.arrayList, R.string.recent_artists)
|
||||
viewHolder.bindView(home)
|
||||
viewHolder.clickableArea.setOnClickListener {
|
||||
activity.findNavController(R.id.fragment_container).navigate(
|
||||
R.id.detailListFragment,
|
||||
|
@ -94,7 +94,7 @@ class HomeAdapter(
|
|||
}
|
||||
TOP_ARTISTS -> {
|
||||
val viewHolder = holder as ArtistViewHolder
|
||||
viewHolder.bindView(home.arrayList, R.string.top_artists)
|
||||
viewHolder.bindView(home)
|
||||
viewHolder.clickableArea.setOnClickListener {
|
||||
activity.findNavController(R.id.fragment_container).navigate(
|
||||
R.id.detailListFragment,
|
||||
|
@ -104,15 +104,21 @@ class HomeAdapter(
|
|||
}
|
||||
SUGGESTIONS -> {
|
||||
val viewHolder = holder as SuggestionsViewHolder
|
||||
viewHolder.bindView(home.arrayList)
|
||||
viewHolder.bindView(home)
|
||||
}
|
||||
FAVOURITES -> {
|
||||
val viewHolder = holder as PlaylistViewHolder
|
||||
viewHolder.bindView(home.arrayList, R.string.favorites)
|
||||
viewHolder.bindView(home)
|
||||
viewHolder.clickableArea.setOnClickListener {
|
||||
activity.findNavController(R.id.fragment_container).navigate(
|
||||
R.id.detailListFragment,
|
||||
bundleOf("type" to FAVOURITES)
|
||||
)
|
||||
}
|
||||
}
|
||||
GENRES -> {
|
||||
val viewHolder = holder as GenreViewHolder
|
||||
viewHolder.bind(home.arrayList, R.string.genres)
|
||||
viewHolder.bind(home)
|
||||
}
|
||||
PLAYLISTS -> {
|
||||
|
||||
|
@ -130,22 +136,22 @@ class HomeAdapter(
|
|||
}
|
||||
|
||||
private inner class AlbumViewHolder(view: View) : AbsHomeViewItem(view) {
|
||||
fun bindView(albums: List<Album>, titleRes: Int) {
|
||||
title.text = activity.getString(titleRes)
|
||||
fun bindView(home: Home) {
|
||||
title.setText(home.titleRes)
|
||||
recyclerView.apply {
|
||||
adapter = albumAdapter(albums)
|
||||
adapter = albumAdapter(home.arrayList as List<Album>)
|
||||
layoutManager = gridLayoutManager()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) {
|
||||
fun bindView(artists: List<Any>, titleRes: Int) {
|
||||
fun bindView(home: Home) {
|
||||
title.setText(home.titleRes)
|
||||
recyclerView.apply {
|
||||
layoutManager = linearLayoutManager()
|
||||
adapter = artistsAdapter(artists as List<Artist>)
|
||||
adapter = artistsAdapter(home.arrayList as List<Artist>)
|
||||
}
|
||||
title.text = activity.getString(titleRes)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,8 +167,7 @@ class HomeAdapter(
|
|||
R.id.image8
|
||||
)
|
||||
|
||||
fun bindView(songs: List<Any>) {
|
||||
songs as List<Song>
|
||||
fun bindView(home: Home) {
|
||||
val color = ThemeStore.accentColor(activity)
|
||||
itemView.findViewById<TextView>(R.id.message).setTextColor(color)
|
||||
itemView.findViewById<MaterialCardView>(R.id.card6).apply {
|
||||
|
@ -170,9 +175,9 @@ class HomeAdapter(
|
|||
}
|
||||
images.forEachIndexed { index, id ->
|
||||
itemView.findViewById<View>(id).setOnClickListener {
|
||||
MusicPlayerRemote.playNext(songs[index])
|
||||
MusicPlayerRemote.playNext(home.arrayList[index] as Song)
|
||||
}
|
||||
SongGlideRequest.Builder.from(Glide.with(activity), songs[index])
|
||||
SongGlideRequest.Builder.from(Glide.with(activity), home.arrayList[index] as Song)
|
||||
.asBitmap()
|
||||
.build()
|
||||
.into(itemView.findViewById(id))
|
||||
|
@ -182,35 +187,37 @@ class HomeAdapter(
|
|||
}
|
||||
|
||||
private inner class PlaylistViewHolder(view: View) : AbsHomeViewItem(view) {
|
||||
fun bindView(songs: List<Any>, titleRes: Int) {
|
||||
arrow.hide()
|
||||
fun bindView(home: Home) {
|
||||
title.setText(home.titleRes)
|
||||
recyclerView.apply {
|
||||
val songAdapter = SongAdapter(
|
||||
activity,
|
||||
songs as MutableList<Song>,
|
||||
home.arrayList as MutableList<Song>,
|
||||
R.layout.item_album_card, null
|
||||
)
|
||||
layoutManager = linearLayoutManager()
|
||||
adapter = songAdapter
|
||||
}
|
||||
title.text = activity.getString(titleRes)
|
||||
}
|
||||
}
|
||||
|
||||
private inner class GenreViewHolder(itemView: View) : AbsHomeViewItem(itemView) {
|
||||
fun bind(genres: List<Any>, titleRes: Int) {
|
||||
fun bind(home: Home) {
|
||||
arrow.hide()
|
||||
title.text = activity.getString(titleRes)
|
||||
title.setText(home.titleRes)
|
||||
val genreAdapter = GenreAdapter(
|
||||
activity,
|
||||
home.arrayList as List<Genre>,
|
||||
R.layout.item_grid_genre
|
||||
)
|
||||
recyclerView.apply {
|
||||
layoutManager = GridLayoutManager(activity, 3, GridLayoutManager.HORIZONTAL, false)
|
||||
val genreAdapter =
|
||||
GenreAdapter(activity, genres as List<Genre>, R.layout.item_grid_genre)
|
||||
adapter = genreAdapter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open inner class AbsHomeViewItem(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
open class AbsHomeViewItem(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
val recyclerView: RecyclerView = itemView.findViewById(R.id.recyclerView)
|
||||
val title: AppCompatTextView = itemView.findViewById(R.id.title)
|
||||
val arrow: ImageView = itemView.findViewById(R.id.arrow)
|
||||
|
|
|
@ -3,7 +3,6 @@ package code.name.monkey.retromusic.adapter.album
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.retromusic.fragments.albums.AlbumClickListener
|
||||
import code.name.monkey.retromusic.glide.AlbumGlideRequest
|
||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
||||
|
@ -30,8 +29,8 @@ class HorizontalAlbumAdapter(
|
|||
}
|
||||
|
||||
override fun setColors(color: MediaNotificationProcessor, holder: ViewHolder) {
|
||||
holder.title?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorPrimary))
|
||||
holder.text?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorSecondary))
|
||||
//holder.title?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorPrimary))
|
||||
//holder.text?.setTextColor(ATHUtil.resolveColor(activity, android.R.attr.textColorSecondary))
|
||||
}
|
||||
|
||||
override fun loadAlbumCover(album: Album, holder: ViewHolder) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import androidx.fragment.app.FragmentActivity
|
|||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.R.menu
|
||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||
import code.name.monkey.retromusic.db.toSongs
|
||||
import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog
|
||||
import code.name.monkey.retromusic.interfaces.CabHolder
|
||||
import code.name.monkey.retromusic.model.PlaylistSong
|
||||
|
@ -56,7 +57,7 @@ class OrderablePlaylistSongAdapter(
|
|||
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Song>) {
|
||||
when (menuItem.itemId) {
|
||||
R.id.action_remove_from_playlist -> {
|
||||
RemoveSongFromPlaylistDialog.create(selection.to(playlist.playListId))
|
||||
RemoveSongFromPlaylistDialog.create(selection.toSongs(playlist.playListId))
|
||||
.show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
|
||||
return
|
||||
}
|
||||
|
|
|
@ -169,7 +169,7 @@ class PlayingQueueAdapter(
|
|||
holder: ViewHolder?,
|
||||
position: Int, @SwipeableItemResults result: Int
|
||||
): SwipeResultAction {
|
||||
return if (result === SwipeableItemConstants.RESULT_CANCELED) {
|
||||
return if (result == SwipeableItemConstants.RESULT_CANCELED) {
|
||||
SwipeResultActionDefault()
|
||||
} else {
|
||||
SwipedResultActionRemoveItem(this, position, activity)
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package code.name.monkey.retromusic.db
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity
|
||||
class BlackListStoreEntity(
|
||||
@PrimaryKey
|
||||
val path: String
|
||||
)
|
|
@ -0,0 +1,32 @@
|
|||
package code.name.monkey.retromusic.db
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity
|
||||
class HistoryEntity(
|
||||
@PrimaryKey
|
||||
val id: Int,
|
||||
val title: String,
|
||||
@ColumnInfo(name = "track_number")
|
||||
val trackNumber: Int,
|
||||
val year: Int,
|
||||
val duration: Long,
|
||||
val data: String,
|
||||
@ColumnInfo(name = "date_modified")
|
||||
val dateModified: Long,
|
||||
@ColumnInfo(name = "album_id")
|
||||
val albumId: Int,
|
||||
@ColumnInfo(name = "album_name")
|
||||
val albumName: String,
|
||||
@ColumnInfo(name = "artist_id")
|
||||
val artistId: Int,
|
||||
@ColumnInfo(name = "artist_name")
|
||||
val artistName: String,
|
||||
val composer: String?,
|
||||
@ColumnInfo(name = "album_artist")
|
||||
val albumArtist: String?,
|
||||
@ColumnInfo(name = "time_played")
|
||||
val timePlayed: Long
|
||||
)
|
|
@ -0,0 +1,34 @@
|
|||
package code.name.monkey.retromusic.db
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity
|
||||
class PlayCountEntity(
|
||||
@PrimaryKey
|
||||
val id: Int,
|
||||
val title: String,
|
||||
@ColumnInfo(name = "track_number")
|
||||
val trackNumber: Int,
|
||||
val year: Int,
|
||||
val duration: Long,
|
||||
val data: String,
|
||||
@ColumnInfo(name = "date_modified")
|
||||
val dateModified: Long,
|
||||
@ColumnInfo(name = "album_id")
|
||||
val albumId: Int,
|
||||
@ColumnInfo(name = "album_name")
|
||||
val albumName: String,
|
||||
@ColumnInfo(name = "artist_id")
|
||||
val artistId: Int,
|
||||
@ColumnInfo(name = "artist_name")
|
||||
val artistName: String,
|
||||
val composer: String?,
|
||||
@ColumnInfo(name = "album_artist")
|
||||
val albumArtist: String?,
|
||||
@ColumnInfo(name = "time_played")
|
||||
val timePlayed: Long,
|
||||
@ColumnInfo(name = "play_count")
|
||||
var playCount: Int
|
||||
)
|
|
@ -1,5 +1,6 @@
|
|||
package code.name.monkey.retromusic.db
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.*
|
||||
|
||||
@Dao
|
||||
|
@ -8,37 +9,84 @@ interface PlaylistDao {
|
|||
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long
|
||||
|
||||
@Query("UPDATE PlaylistEntity SET playlist_name = :name WHERE playlist_id = :playlistId")
|
||||
suspend fun renamePlaylistEntity(playlistId: Int, name: String)
|
||||
suspend fun renamePlaylist(playlistId: Int, name: String)
|
||||
|
||||
@Query("SELECT * FROM PlaylistEntity WHERE playlist_name = :name")
|
||||
suspend fun checkPlaylistExists(name: String): List<PlaylistEntity>
|
||||
fun isPlaylistExists(name: String): List<PlaylistEntity>
|
||||
|
||||
@Query("SELECT * FROM PlaylistEntity")
|
||||
suspend fun playlists(): List<PlaylistEntity>
|
||||
|
||||
@Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId")
|
||||
suspend fun deleteSongsFromPlaylist(playlistId: Int)
|
||||
suspend fun deleteSongsInPlaylist(playlistId: Int)
|
||||
|
||||
@Query("DELETE FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId")
|
||||
suspend fun removeSongFromPlaylist(playlistId: Int, songId: Int)
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM PlaylistEntity")
|
||||
suspend fun playlistsWithSong(): List<PlaylistWithSongs>
|
||||
suspend fun playlistsWithSongs(): List<PlaylistWithSongs>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertSongs(songEntities: List<SongEntity>)
|
||||
suspend fun insertSongsToPlaylist(songEntities: List<SongEntity>)
|
||||
|
||||
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistName AND id = :songId")
|
||||
suspend fun checkSongExistsWithPlaylistName(playlistName: String, songId: Int): List<SongEntity>
|
||||
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId AND id = :songId")
|
||||
suspend fun isSongExistsInPlaylist(playlistId: Int, songId: Int): List<SongEntity>
|
||||
|
||||
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id = :playlistId")
|
||||
suspend fun getSongs(playlistId: Int): List<SongEntity>
|
||||
suspend fun songsFromPlaylist(playlistId: Int): List<SongEntity>
|
||||
|
||||
@Delete
|
||||
suspend fun deletePlaylistEntity(playlistEntity: PlaylistEntity)
|
||||
suspend fun deletePlaylist(playlistEntity: PlaylistEntity)
|
||||
|
||||
@Delete
|
||||
suspend fun deletePlaylistEntities(playlistEntities: List<PlaylistEntity>)
|
||||
suspend fun deletePlaylists(playlistEntities: List<PlaylistEntity>)
|
||||
|
||||
@Delete
|
||||
suspend fun removeSongsFromPlaylist(songs: List<SongEntity>)
|
||||
suspend fun deleteSongsInPlaylist(songs: List<SongEntity>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertSongInHistory(historyEntity: HistoryEntity)
|
||||
|
||||
@Query("SELECT * FROM HistoryEntity WHERE id = :songId LIMIT 1")
|
||||
suspend fun isSongPresentInHistory(songId: Int): HistoryEntity?
|
||||
|
||||
@Update
|
||||
suspend fun updateHistorySong(historyEntity: HistoryEntity)
|
||||
|
||||
@Query("SELECT * FROM HistoryEntity ORDER BY time_played DESC")
|
||||
fun historySongs(): LiveData<List<HistoryEntity>>
|
||||
|
||||
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
|
||||
fun favoritesSongsLiveData(playlistId: Int): LiveData<List<SongEntity>>
|
||||
|
||||
@Query("SELECT * FROM SongEntity WHERE playlist_creator_id= :playlistId")
|
||||
fun favoritesSongs(playlistId: Int): List<SongEntity>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
|
||||
@Update
|
||||
fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
|
||||
@Delete
|
||||
fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
|
||||
@Query("SELECT * FROM PlayCountEntity WHERE id =:songId")
|
||||
fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity>
|
||||
|
||||
@Query("SELECT * FROM PlayCountEntity ORDER BY play_count DESC")
|
||||
fun playCountSongs(): List<PlayCountEntity>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insertBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>)
|
||||
|
||||
@Delete
|
||||
suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
|
||||
|
||||
@Query("DELETE FROM BlackListStoreEntity")
|
||||
suspend fun clearBlacklist()
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package code.name.monkey.retromusic.db
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
|
||||
@Database(
|
||||
entities = [PlaylistEntity::class, SongEntity::class],
|
||||
version = 8,
|
||||
exportSchema = false
|
||||
)
|
||||
abstract class PlaylistDatabase : RoomDatabase() {
|
||||
abstract fun playlistDao(): PlaylistDao
|
||||
|
||||
companion object {
|
||||
@Volatile
|
||||
private var INSTANCE: PlaylistDatabase? = null
|
||||
|
||||
fun getDatabase(
|
||||
context: Context
|
||||
): PlaylistDatabase {
|
||||
return INSTANCE ?: synchronized(this) {
|
||||
val instance = Room.databaseBuilder(
|
||||
context.applicationContext,
|
||||
PlaylistDatabase::class.java,
|
||||
"playlists.db"
|
||||
).fallbackToDestructiveMigration().build()
|
||||
INSTANCE = instance
|
||||
instance
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package code.name.monkey.retromusic.db
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
|
||||
@Database(
|
||||
entities = [PlaylistEntity::class, SongEntity::class, HistoryEntity::class, PlayCountEntity::class, BlackListStoreEntity::class],
|
||||
version = 18,
|
||||
exportSchema = false
|
||||
)
|
||||
abstract class RetroDatabase : RoomDatabase() {
|
||||
abstract fun playlistDao(): PlaylistDao
|
||||
}
|
|
@ -4,7 +4,6 @@ import android.os.Parcelable
|
|||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
@Parcelize
|
||||
|
@ -37,27 +36,5 @@ class SongEntity(
|
|||
@ColumnInfo(name = "song_key")
|
||||
var songPrimaryKey: Long = 0
|
||||
|
||||
fun toSong(): Song {
|
||||
return Song(
|
||||
id,
|
||||
title,
|
||||
trackNumber,
|
||||
year,
|
||||
duration,
|
||||
data,
|
||||
dateModified,
|
||||
albumId,
|
||||
albumName,
|
||||
artistId,
|
||||
artistName,
|
||||
composer,
|
||||
albumArtist
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun List<SongEntity>.toSongs(): List<Song> {
|
||||
return map {
|
||||
it.toSong()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package code.name.monkey.retromusic.db
|
||||
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
|
||||
fun List<SongEntity>.toSongs(): List<Song> {
|
||||
return map {
|
||||
it.toSong()
|
||||
}
|
||||
}
|
||||
|
||||
fun SongEntity.toSong(): Song {
|
||||
return Song(
|
||||
id,
|
||||
title,
|
||||
trackNumber,
|
||||
year,
|
||||
duration,
|
||||
data,
|
||||
dateModified,
|
||||
albumId,
|
||||
albumName,
|
||||
artistId,
|
||||
artistName,
|
||||
composer,
|
||||
albumArtist
|
||||
)
|
||||
}
|
||||
|
||||
fun PlayCountEntity.toSong(): Song {
|
||||
return Song(
|
||||
id,
|
||||
title,
|
||||
trackNumber,
|
||||
year,
|
||||
duration,
|
||||
data,
|
||||
dateModified,
|
||||
albumId,
|
||||
albumName,
|
||||
artistId,
|
||||
artistName,
|
||||
composer,
|
||||
albumArtist
|
||||
)
|
||||
}
|
||||
|
||||
fun HistoryEntity.toSong(): Song {
|
||||
return Song(
|
||||
id,
|
||||
title,
|
||||
trackNumber,
|
||||
year,
|
||||
duration,
|
||||
data,
|
||||
dateModified,
|
||||
albumId,
|
||||
albumName,
|
||||
artistId,
|
||||
artistName,
|
||||
composer,
|
||||
albumArtist
|
||||
)
|
||||
}
|
||||
|
||||
fun Song.toPlayCount(): PlayCountEntity {
|
||||
return PlayCountEntity(
|
||||
id,
|
||||
title,
|
||||
trackNumber,
|
||||
year,
|
||||
duration,
|
||||
data,
|
||||
dateModified,
|
||||
albumId,
|
||||
albumName,
|
||||
artistId,
|
||||
artistName,
|
||||
composer,
|
||||
albumArtist,
|
||||
System.currentTimeMillis(),
|
||||
1
|
||||
)
|
||||
}
|
|
@ -13,7 +13,7 @@ import code.name.monkey.retromusic.extensions.colorButtons
|
|||
import code.name.monkey.retromusic.extensions.extraNotNull
|
||||
import code.name.monkey.retromusic.extensions.materialDialog
|
||||
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||
import code.name.monkey.retromusic.fragments.ReloadType
|
||||
import code.name.monkey.retromusic.fragments.ReloadType.Playlists
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.repository.RealRepository
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
|
@ -59,7 +59,7 @@ class AddToRetroPlaylist : BottomSheetDialogFragment() {
|
|||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val songEntities = songs.toSongEntity(playlistEntities[which - 1])
|
||||
repository.insertSongs(songEntities)
|
||||
libraryViewModel.forceReload(ReloadType.Playlists)
|
||||
libraryViewModel.forceReload(Playlists)
|
||||
}
|
||||
}
|
||||
dismiss()
|
||||
|
|
|
@ -76,7 +76,7 @@ public class BlacklistFolderChooserDialog extends DialogFragment implements Mate
|
|||
return new MaterialDialog.Builder(requireActivity())
|
||||
.title(R.string.md_error_label)
|
||||
.content(R.string.md_storage_perm_error)
|
||||
.positiveText(android.R.string.ok)
|
||||
.positiveText(R.string.ok)
|
||||
.build();
|
||||
}
|
||||
if (savedInstanceState == null) {
|
||||
|
|
|
@ -42,24 +42,25 @@ class DeleteSongsDialog : DialogFragment() {
|
|||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val songs = extraNotNull<List<Song>>(EXTRA_SONG).value
|
||||
var title = 0
|
||||
var message: CharSequence = ""
|
||||
if (songs.size > 1) {
|
||||
title = R.string.delete_songs_title
|
||||
message = HtmlCompat.fromHtml(
|
||||
val pair = if (songs.size > 1) {
|
||||
Pair(
|
||||
R.string.delete_songs_title, HtmlCompat.fromHtml(
|
||||
String.format(getString(R.string.delete_x_songs), songs.size),
|
||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||
)
|
||||
)
|
||||
} else {
|
||||
title = R.string.delete_song_title
|
||||
message = HtmlCompat.fromHtml(
|
||||
Pair(
|
||||
R.string.delete_song_title,
|
||||
HtmlCompat.fromHtml(
|
||||
String.format(getString(R.string.delete_song_x), songs[0].title),
|
||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return materialDialog(title)
|
||||
.setMessage(message)
|
||||
return materialDialog(pair.first)
|
||||
.setMessage(pair.second)
|
||||
.setCancelable(false)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.action_delete) { _, _ ->
|
||||
|
|
|
@ -66,7 +66,8 @@ class RemoveSongFromPlaylistDialog : DialogFragment() {
|
|||
.setMessage(pair.second)
|
||||
.setPositiveButton(R.string.remove_action) { _, _ ->
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
repository.removeSongFromPlaylist(songs)
|
||||
//repository.removeSongFromPlaylist(songs)
|
||||
repository.deleteSongsInPlaylist(songs)
|
||||
libraryViewModel.forceReload(Playlists)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,4 @@ class RetroSingleCheckedListAdapter(
|
|||
context: Context,
|
||||
resource: Int = R.layout.dialog_list_item,
|
||||
objects: MutableList<String>
|
||||
) : ArrayAdapter<String>(context, resource, objects) {
|
||||
|
||||
}
|
||||
) : ArrayAdapter<String>(context, resource, objects)
|
|
@ -158,7 +158,7 @@ class SleepTimerDialog : DialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private inner class TimerUpdater internal constructor() :
|
||||
private inner class TimerUpdater() :
|
||||
CountDownTimer(
|
||||
PreferenceUtil.nextSleepTimerElapsedRealTime - SystemClock.elapsedRealtime(),
|
||||
1000
|
||||
|
|
|
@ -21,8 +21,6 @@ import android.os.Bundle
|
|||
import android.text.Spanned
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.NonNull
|
||||
import androidx.core.text.HtmlCompat
|
||||
|
@ -41,12 +39,6 @@ import org.jaudiotagger.tag.TagException
|
|||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
inline fun ViewGroup.forEach(action: (View) -> Unit) {
|
||||
for (i in 0 until childCount) {
|
||||
action(getChildAt(i))
|
||||
}
|
||||
}
|
||||
|
||||
class SongDetailDialog : DialogFragment() {
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
|
@ -152,7 +144,7 @@ class SongDetailDialog : DialogFragment() {
|
|||
}
|
||||
}
|
||||
return materialDialog(R.string.action_details)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.setView(dialogView)
|
||||
.create()
|
||||
.colorButtons()
|
||||
|
|
|
@ -15,13 +15,8 @@
|
|||
package code.name.monkey.retromusic.extensions
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||
import code.name.monkey.retromusic.R
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
|
||||
fun AppCompatActivity.applyToolbar(toolbar: MaterialToolbar) {
|
||||
|
@ -30,41 +25,6 @@ fun AppCompatActivity.applyToolbar(toolbar: MaterialToolbar) {
|
|||
setSupportActionBar(toolbar)
|
||||
}
|
||||
|
||||
fun FragmentActivity?.addFragment(
|
||||
@IdRes idRes: Int = R.id.container,
|
||||
fragment: Fragment,
|
||||
tag: String? = null,
|
||||
addToBackStack: Boolean = false
|
||||
) {
|
||||
val compatActivity = this as? AppCompatActivity ?: return
|
||||
compatActivity.supportFragmentManager.beginTransaction()
|
||||
.apply {
|
||||
add(fragment, tag)
|
||||
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
|
||||
if (addToBackStack) {
|
||||
addToBackStack(null)
|
||||
}
|
||||
commitNow()
|
||||
}
|
||||
}
|
||||
|
||||
fun AppCompatActivity.replaceFragment(
|
||||
@IdRes id: Int = R.id.container,
|
||||
fragment: Fragment,
|
||||
tag: String? = null,
|
||||
addToBackStack: Boolean = false
|
||||
) {
|
||||
val compatActivity = this ?: return
|
||||
compatActivity.supportFragmentManager.beginTransaction()
|
||||
.apply {
|
||||
replace(id, fragment, tag)
|
||||
if (addToBackStack) {
|
||||
addToBackStack(null)
|
||||
}
|
||||
commit()
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> Activity.extra(key: String, default: T? = null) = lazy {
|
||||
val value = intent?.extras?.get(key)
|
||||
if (value is T) value else default
|
||||
|
|
|
@ -23,6 +23,7 @@ import android.widget.CheckBox
|
|||
import android.widget.SeekBar
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.fragment.app.Fragment
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
|
@ -130,6 +131,12 @@ fun MaterialButton.applyColor(color: Int) {
|
|||
iconTint = textColorColorStateList
|
||||
}
|
||||
|
||||
fun MaterialButton.applyOutlineColor(color: Int) {
|
||||
val textColorColorStateList = ColorStateList.valueOf(color)
|
||||
setTextColor(textColorColorStateList)
|
||||
iconTint = textColorColorStateList
|
||||
}
|
||||
|
||||
fun TextInputLayout.accentColor() {
|
||||
val accentColor = ThemeStore.accentColor(context)
|
||||
val colorState = ColorStateList.valueOf(accentColor)
|
||||
|
@ -141,3 +148,7 @@ fun TextInputLayout.accentColor() {
|
|||
fun TextInputEditText.accentColor() {
|
||||
|
||||
}
|
||||
|
||||
fun AppCompatImageView.accentColor(): Int {
|
||||
return ThemeStore.accentColor(context)
|
||||
}
|
|
@ -51,7 +51,8 @@ val FragmentManager.currentNavigationFragment: Fragment?
|
|||
get() = primaryNavigationFragment?.childFragmentManager?.fragments?.first()
|
||||
|
||||
fun AppCompatActivity.currentFragment(navHostId: Int): Fragment? {
|
||||
val navHostFragment: NavHostFragment = supportFragmentManager.findFragmentById(navHostId) as NavHostFragment
|
||||
val navHostFragment: NavHostFragment =
|
||||
supportFragmentManager.findFragmentById(navHostId) as NavHostFragment
|
||||
navHostFragment.targetFragment
|
||||
return navHostFragment.childFragmentManager.fragments.first()
|
||||
}
|
||||
|
|
|
@ -14,13 +14,10 @@
|
|||
|
||||
package code.name.monkey.retromusic.extensions
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.SeekBar
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.LayoutRes
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.TintHelper
|
||||
|
|
|
@ -3,6 +3,8 @@ package code.name.monkey.retromusic.fragments
|
|||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
|
@ -10,15 +12,14 @@ import code.name.monkey.retromusic.*
|
|||
import code.name.monkey.retromusic.adapter.album.AlbumAdapter
|
||||
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
|
||||
import code.name.monkey.retromusic.adapter.song.SongAdapter
|
||||
import code.name.monkey.retromusic.db.toSong
|
||||
import code.name.monkey.retromusic.fragments.albums.AlbumClickListener
|
||||
import code.name.monkey.retromusic.fragments.artists.ArtistClickListener
|
||||
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
||||
import code.name.monkey.retromusic.model.Album
|
||||
import code.name.monkey.retromusic.model.Artist
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.repository.RealRepository
|
||||
import kotlinx.android.synthetic.main.fragment_playlist_detail.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -48,32 +49,86 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
|||
RECENT_ALBUMS -> {
|
||||
loadAlbums(R.string.recent_albums, RECENT_ALBUMS)
|
||||
}
|
||||
FAVOURITES -> {
|
||||
loadFavorite()
|
||||
FAVOURITES -> loadFavorite()
|
||||
HISTORY_PLAYLIST -> loadHistory()
|
||||
LAST_ADDED_PLAYLIST -> lastAddedSongs()
|
||||
TOP_PLAYED_PLAYLIST -> topPlayed()
|
||||
}
|
||||
}
|
||||
|
||||
private fun lastAddedSongs() {
|
||||
toolbar.setTitle(R.string.last_added)
|
||||
val songAdapter = SongAdapter(
|
||||
requireActivity(),
|
||||
mutableListOf(),
|
||||
R.layout.item_list, null
|
||||
)
|
||||
recyclerView.apply {
|
||||
adapter = songAdapter
|
||||
layoutManager = linearLayoutManager()
|
||||
}
|
||||
lifecycleScope.launch(IO) {
|
||||
val songs = repository.recentSongs()
|
||||
withContext(Main) { songAdapter.swapDataSet(songs) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun topPlayed() {
|
||||
toolbar.setTitle(R.string.my_top_tracks)
|
||||
val songAdapter = SongAdapter(
|
||||
requireActivity(),
|
||||
mutableListOf(),
|
||||
R.layout.item_list, null
|
||||
)
|
||||
recyclerView.apply {
|
||||
adapter = songAdapter
|
||||
layoutManager = linearLayoutManager()
|
||||
}
|
||||
lifecycleScope.launch(IO) {
|
||||
val songs = repository.recentSongs()
|
||||
withContext(Main) { songAdapter.swapDataSet(songs) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadHistory() {
|
||||
toolbar.setTitle(R.string.history)
|
||||
|
||||
val songAdapter = SongAdapter(
|
||||
requireActivity(),
|
||||
mutableListOf(),
|
||||
R.layout.item_list, null
|
||||
)
|
||||
recyclerView.apply {
|
||||
adapter = songAdapter
|
||||
layoutManager = linearLayoutManager()
|
||||
}
|
||||
repository.historySong().observe(viewLifecycleOwner, Observer {
|
||||
val songs = it.map { historyEntity -> historyEntity.toSong() }
|
||||
songAdapter.swapDataSet(songs)
|
||||
})
|
||||
}
|
||||
|
||||
private fun loadFavorite() {
|
||||
toolbar.setTitle(R.string.favorites)
|
||||
CoroutineScope(IO).launch {
|
||||
val songs = repository.favoritePlaylistHome()
|
||||
withContext(Main) {
|
||||
recyclerView.apply {
|
||||
adapter = SongAdapter(
|
||||
val songAdapter = SongAdapter(
|
||||
requireActivity(),
|
||||
songs.arrayList as MutableList<Song>,
|
||||
mutableListOf(),
|
||||
R.layout.item_list, null
|
||||
)
|
||||
recyclerView.apply {
|
||||
adapter = songAdapter
|
||||
layoutManager = linearLayoutManager()
|
||||
}
|
||||
}
|
||||
}
|
||||
repository.favorites().observe(viewLifecycleOwner, Observer {
|
||||
println(it.size)
|
||||
val songs = it.map { songEntity -> songEntity.toSong() }
|
||||
songAdapter.swapDataSet(songs)
|
||||
})
|
||||
}
|
||||
|
||||
private fun loadArtists(title: Int, type: Int) {
|
||||
toolbar.setTitle(title)
|
||||
CoroutineScope(IO).launch {
|
||||
lifecycleScope.launch(IO) {
|
||||
val artists =
|
||||
if (type == TOP_ARTISTS) repository.topArtists() else repository.recentArtists()
|
||||
withContext(Main) {
|
||||
|
@ -87,7 +142,7 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
|||
|
||||
private fun loadAlbums(title: Int, type: Int) {
|
||||
toolbar.setTitle(title)
|
||||
CoroutineScope(IO).launch {
|
||||
lifecycleScope.launch(IO) {
|
||||
val albums =
|
||||
if (type == TOP_ALBUMS) repository.topAlbums() else repository.recentAlbums()
|
||||
withContext(Main) {
|
||||
|
|
|
@ -5,7 +5,9 @@ import androidx.lifecycle.MutableLiveData
|
|||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
||||
import code.name.monkey.retromusic.db.toPlayCount
|
||||
import code.name.monkey.retromusic.fragments.ReloadType.*
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
||||
import code.name.monkey.retromusic.model.*
|
||||
import code.name.monkey.retromusic.repository.RealRepository
|
||||
|
@ -15,7 +17,7 @@ import kotlinx.coroutines.async
|
|||
import kotlinx.coroutines.launch
|
||||
|
||||
class LibraryViewModel(
|
||||
private val realRepository: RealRepository
|
||||
private val repository: RealRepository
|
||||
) : ViewModel(), MusicServiceEventListener {
|
||||
|
||||
private val paletteColor = MutableLiveData<Int>()
|
||||
|
@ -49,37 +51,37 @@ class LibraryViewModel(
|
|||
artists.value = loadArtists.await()
|
||||
playlists.value = loadPlaylists.await()
|
||||
roomPlaylists.value = loadPlaylistsWithSongs.await()
|
||||
//genres.value = loadGenres.await()
|
||||
genres.value = loadGenres.await()
|
||||
}
|
||||
|
||||
private val loadHome: Deferred<List<Home>>
|
||||
get() = viewModelScope.async { realRepository.homeSections() }
|
||||
get() = viewModelScope.async { repository.homeSections() }
|
||||
|
||||
private val loadSongs: Deferred<List<Song>>
|
||||
get() = viewModelScope.async(IO) { realRepository.allSongs() }
|
||||
get() = viewModelScope.async(IO) { repository.allSongs() }
|
||||
|
||||
private val loadAlbums: Deferred<List<Album>>
|
||||
get() = viewModelScope.async(IO) {
|
||||
realRepository.allAlbums()
|
||||
repository.allAlbums()
|
||||
}
|
||||
|
||||
private val loadArtists: Deferred<List<Artist>>
|
||||
get() = viewModelScope.async(IO) {
|
||||
realRepository.albumArtists()
|
||||
repository.albumArtists()
|
||||
}
|
||||
|
||||
private val loadPlaylists: Deferred<List<Playlist>>
|
||||
get() = viewModelScope.async(IO) {
|
||||
realRepository.allPlaylists()
|
||||
repository.allPlaylists()
|
||||
}
|
||||
private val loadPlaylistsWithSongs: Deferred<List<PlaylistWithSongs>>
|
||||
get() = viewModelScope.async(IO) {
|
||||
realRepository.playlistWithSongs()
|
||||
repository.playlistWithSongs()
|
||||
}
|
||||
|
||||
private val loadGenres: Deferred<List<Genre>>
|
||||
get() = viewModelScope.async(IO) {
|
||||
realRepository.allGenres()
|
||||
repository.allGenres()
|
||||
}
|
||||
|
||||
|
||||
|
@ -119,6 +121,22 @@ class LibraryViewModel(
|
|||
|
||||
override fun onPlayingMetaChanged() {
|
||||
println("onPlayingMetaChanged")
|
||||
viewModelScope.launch(IO) {
|
||||
val entity = repository.songPresentInHistory(MusicPlayerRemote.currentSong)
|
||||
if (entity != null) {
|
||||
repository.updateHistorySong(MusicPlayerRemote.currentSong)
|
||||
} else {
|
||||
repository.addSongToHistory(MusicPlayerRemote.currentSong)
|
||||
}
|
||||
val songs = repository.checkSongExistInPlayCount(MusicPlayerRemote.currentSong.id)
|
||||
if (songs.isNotEmpty()) {
|
||||
repository.updateSongInPlayCount(songs.first().apply {
|
||||
playCount += playCount + 1
|
||||
})
|
||||
} else {
|
||||
repository.insertSongInPlayCount(MusicPlayerRemote.currentSong.toPlayCount())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPlayStateChanged() {
|
||||
|
|
|
@ -26,6 +26,7 @@ import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
|
|||
import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist
|
||||
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
|
||||
import code.name.monkey.retromusic.extensions.applyColor
|
||||
import code.name.monkey.retromusic.extensions.applyOutlineColor
|
||||
import code.name.monkey.retromusic.extensions.show
|
||||
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
||||
import code.name.monkey.retromusic.glide.AlbumGlideRequest
|
||||
|
@ -240,7 +241,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
|
||||
private fun setColors(color: MediaNotificationProcessor) {
|
||||
shuffleAction.applyColor(color.backgroundColor)
|
||||
playAction.applyColor(color.backgroundColor)
|
||||
playAction.applyOutlineColor(color.backgroundColor)
|
||||
}
|
||||
|
||||
override fun onAlbumClick(albumId: Int, view: View) {
|
||||
|
|
|
@ -27,7 +27,7 @@ class AlbumDetailsViewModel(
|
|||
fun getAlbum(): LiveData<Album> = _album
|
||||
fun getArtist(): LiveData<Artist> = _artist
|
||||
fun getAlbumInfo(): LiveData<LastFmAlbum> = _lastFmAlbum
|
||||
fun getMoreAlbums(): LiveData<List<Album>> = _moreAlbums;
|
||||
fun getMoreAlbums(): LiveData<List<Album>> = _moreAlbums
|
||||
|
||||
init {
|
||||
loadAlbumDetails()
|
||||
|
|
|
@ -22,6 +22,7 @@ import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
|
|||
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
|
||||
import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist
|
||||
import code.name.monkey.retromusic.extensions.applyColor
|
||||
import code.name.monkey.retromusic.extensions.applyOutlineColor
|
||||
import code.name.monkey.retromusic.extensions.show
|
||||
import code.name.monkey.retromusic.extensions.showToast
|
||||
import code.name.monkey.retromusic.fragments.albums.AlbumClickListener
|
||||
|
@ -72,7 +73,6 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
|||
setupRecyclerView()
|
||||
postponeEnterTransition()
|
||||
detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer {
|
||||
|
||||
showArtist(it)
|
||||
startPostponedEnterTransition()
|
||||
})
|
||||
|
@ -191,7 +191,7 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
|
|||
|
||||
private fun setColors(color: MediaNotificationProcessor) {
|
||||
shuffleAction.applyColor(color.backgroundColor)
|
||||
playAction.applyColor(color.backgroundColor)
|
||||
playAction.applyOutlineColor(color.backgroundColor)
|
||||
}
|
||||
|
||||
override fun onAlbumClick(albumId: Int, view: View) {
|
||||
|
|
|
@ -6,8 +6,8 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
|
||||
import code.name.monkey.retromusic.model.Artist
|
||||
import code.name.monkey.retromusic.repository.RealRepository
|
||||
import code.name.monkey.retromusic.network.model.LastFmArtist
|
||||
import code.name.monkey.retromusic.repository.RealRepository
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package code.name.monkey.retromusic.fragments.base
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ContentUris
|
||||
import android.content.Intent
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.os.AsyncTask
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore
|
||||
|
@ -22,29 +20,34 @@ import code.name.monkey.retromusic.EXTRA_ARTIST_ID
|
|||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity
|
||||
import code.name.monkey.retromusic.activities.tageditor.SongTagEditorActivity
|
||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||
import code.name.monkey.retromusic.dialogs.*
|
||||
import code.name.monkey.retromusic.extensions.hide
|
||||
import code.name.monkey.retromusic.extensions.whichFragment
|
||||
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||
import code.name.monkey.retromusic.fragments.ReloadType.Playlists
|
||||
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.interfaces.PaletteColorHolder
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.model.lyrics.Lyrics
|
||||
import code.name.monkey.retromusic.repository.RealRepository
|
||||
import code.name.monkey.retromusic.service.MusicService
|
||||
import code.name.monkey.retromusic.util.*
|
||||
import kotlinx.android.synthetic.main.shadow_statusbar_toolbar.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.android.ext.android.get
|
||||
import org.koin.android.ext.android.inject
|
||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||
import java.io.FileNotFoundException
|
||||
|
||||
abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragment(layout),
|
||||
Toolbar.OnMenuItemClickListener, PaletteColorHolder, PlayerAlbumCoverFragment.Callbacks {
|
||||
|
||||
private var updateIsFavoriteTask: AsyncTask<*, *, *>? = null
|
||||
private var updateLyricsAsyncTask: AsyncTask<*, *, *>? = null
|
||||
private var playerAlbumCoverFragment: PlayerAlbumCoverFragment? = null
|
||||
protected val libraryViewModel by sharedViewModel<LibraryViewModel>()
|
||||
|
||||
|
@ -70,7 +73,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
|||
return true
|
||||
}
|
||||
R.id.action_add_to_playlist -> {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
lifecycleScope.launch(IO) {
|
||||
val playlists = get<RealRepository>().roomPlaylists()
|
||||
withContext(Dispatchers.Main) {
|
||||
AddToRetroPlaylist.create(playlists, song)
|
||||
|
@ -159,7 +162,18 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
|||
}
|
||||
|
||||
protected open fun toggleFavorite(song: Song) {
|
||||
MusicUtil.toggleFavorite(requireActivity(), song)
|
||||
lifecycleScope.launch(IO) {
|
||||
val playlist: PlaylistEntity = repository.favoritePlaylist().first()
|
||||
val songEntity = song.toSongEntity(playlist.playListId)
|
||||
val isFavorite = repository.isFavoriteSong(songEntity).isNotEmpty()
|
||||
if (isFavorite) {
|
||||
repository.removeSongFromPlaylist(songEntity)
|
||||
} else {
|
||||
repository.insertSongs(listOf(song.toSongEntity(playlist.playListId)))
|
||||
libraryViewModel.forceReload(Playlists)
|
||||
}
|
||||
requireContext().sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED))
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun playerToolbar(): Toolbar?
|
||||
|
@ -182,84 +196,62 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
|||
updateLyrics()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
if (updateIsFavoriteTask != null && !updateIsFavoriteTask!!.isCancelled) {
|
||||
updateIsFavoriteTask!!.cancel(true)
|
||||
}
|
||||
if (updateLyricsAsyncTask != null && !updateLyricsAsyncTask!!.isCancelled) {
|
||||
updateLyricsAsyncTask!!.cancel(true)
|
||||
}
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
fun updateIsFavorite() {
|
||||
if (updateIsFavoriteTask != null) {
|
||||
updateIsFavoriteTask!!.cancel(false)
|
||||
}
|
||||
updateIsFavoriteTask = object : AsyncTask<Song, Void, Boolean>() {
|
||||
override fun doInBackground(vararg params: Song): Boolean {
|
||||
return MusicUtil.isFavorite(requireActivity(), params[0])
|
||||
}
|
||||
|
||||
override fun onPostExecute(isFavorite: Boolean) {
|
||||
val res = if (isFavorite)
|
||||
R.drawable.ic_favorite
|
||||
else
|
||||
R.drawable.ic_favorite_border
|
||||
|
||||
lifecycleScope.launch(IO) {
|
||||
val playlist: PlaylistEntity = repository.favoritePlaylist().first()
|
||||
val song = MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId)
|
||||
val isFavorite = repository.isFavoriteSong(song).isNotEmpty()
|
||||
withContext(Dispatchers.Main) {
|
||||
val icon = if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
|
||||
val drawable =
|
||||
RetroUtil.getTintedVectorDrawable(requireContext(), res, toolbarIconColor())
|
||||
if (playerToolbar() != null && playerToolbar()!!.menu.findItem(R.id.action_toggle_favorite) != null)
|
||||
playerToolbar()!!.menu.findItem(R.id.action_toggle_favorite).setIcon(drawable)
|
||||
.title =
|
||||
if (isFavorite) getString(R.string.action_remove_from_favorites) else getString(
|
||||
R.string.action_add_to_favorites
|
||||
)
|
||||
RetroUtil.getTintedVectorDrawable(requireContext(), icon, toolbarIconColor())
|
||||
if (playerToolbar() != null) {
|
||||
playerToolbar()?.menu?.findItem(R.id.action_toggle_favorite)
|
||||
?.setIcon(drawable)?.title =
|
||||
if (isFavorite) getString(R.string.action_remove_from_favorites)
|
||||
else getString(R.string.action_add_to_favorites)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.execute(MusicPlayerRemote.currentSong)
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private fun updateLyrics() {
|
||||
if (updateLyricsAsyncTask != null) updateLyricsAsyncTask!!.cancel(false)
|
||||
|
||||
updateLyricsAsyncTask = object : AsyncTask<Song, Void, Lyrics>() {
|
||||
override fun onPreExecute() {
|
||||
super.onPreExecute()
|
||||
setLyrics(null)
|
||||
}
|
||||
|
||||
override fun doInBackground(vararg params: Song): Lyrics? {
|
||||
try {
|
||||
var data: String? =
|
||||
LyricUtil.getStringFromFile(params[0].title, params[0].artistName)
|
||||
return if (TextUtils.isEmpty(data)) {
|
||||
data = MusicUtil.getLyrics(params[0])
|
||||
return if (TextUtils.isEmpty(data)) {
|
||||
lifecycleScope.launch(IO) {
|
||||
val song = MusicPlayerRemote.currentSong
|
||||
val lyrics = try {
|
||||
var data: String? = LyricUtil.getStringFromFile(song.title, song.artistName)
|
||||
if (TextUtils.isEmpty(data)) {
|
||||
data = MusicUtil.getLyrics(song)
|
||||
if (TextUtils.isEmpty(data)) {
|
||||
null
|
||||
} else {
|
||||
Lyrics.parse(params[0], data)
|
||||
Lyrics.parse(song, data)
|
||||
}
|
||||
} else Lyrics.parse(params[0], data!!)
|
||||
} else Lyrics.parse(song, data!!)
|
||||
} catch (err: FileNotFoundException) {
|
||||
return null
|
||||
null
|
||||
}
|
||||
withContext(Main) {
|
||||
setLyrics(lyrics)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPostExecute(l: Lyrics?) {
|
||||
setLyrics(l)
|
||||
}
|
||||
|
||||
override fun onCancelled(s: Lyrics?) {
|
||||
onPostExecute(null)
|
||||
}
|
||||
}.execute(MusicPlayerRemote.currentSong)
|
||||
}
|
||||
|
||||
open fun setLyrics(l: Lyrics?) {
|
||||
}
|
||||
|
||||
private val repository by inject<RealRepository>()
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
lifecycleScope.launch(IO) {
|
||||
if (repository.checkPlaylistExists(getString(R.string.favorites)).isEmpty()) {
|
||||
repository.createPlaylist(PlaylistEntity(getString(R.string.favorites)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
if (PreferenceUtil.isFullScreenMode &&
|
||||
|
@ -267,8 +259,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
|||
) {
|
||||
view.findViewById<View>(R.id.status_bar).visibility = View.GONE
|
||||
}
|
||||
playerAlbumCoverFragment =
|
||||
childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment?
|
||||
playerAlbumCoverFragment = whichFragment(R.id.playerAlbumCoverFragment)
|
||||
playerAlbumCoverFragment?.setCallbacks(this)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||
|
|
|
@ -290,7 +290,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
|||
}
|
||||
}
|
||||
if (startIndex > -1) {
|
||||
MusicPlayerRemote.INSTANCE.openQueue(songs, startIndex, true);
|
||||
MusicPlayerRemote.openQueue(songs, startIndex, true);
|
||||
} else {
|
||||
final File finalFile = file1;
|
||||
Snackbar.make(coordinatorLayout, Html.fromHtml(
|
||||
|
|
|
@ -36,7 +36,7 @@ class GenreDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_
|
|||
mainActivity.addMusicServiceEventListener(detailsViewModel)
|
||||
mainActivity.setSupportActionBar(toolbar)
|
||||
mainActivity.hideBottomBarVisibility(false)
|
||||
|
||||
progressIndicator.hide()
|
||||
setupRecyclerView()
|
||||
detailsViewModel.getSongs().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
|
||||
songs(it)
|
||||
|
|
|
@ -21,10 +21,11 @@ import android.view.View
|
|||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import code.name.monkey.retromusic.EXTRA_PLAYLIST
|
||||
import code.name.monkey.retromusic.HISTORY_PLAYLIST
|
||||
import code.name.monkey.retromusic.LAST_ADDED_PLAYLIST
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.TOP_PLAYED_PLAYLIST
|
||||
import code.name.monkey.retromusic.adapter.HomeAdapter
|
||||
import code.name.monkey.retromusic.extensions.findActivityNavController
|
||||
import code.name.monkey.retromusic.fragments.LibraryViewModel
|
||||
|
@ -32,9 +33,6 @@ import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
|||
import code.name.monkey.retromusic.glide.ProfileBannerGlideRequest
|
||||
import code.name.monkey.retromusic.glide.UserProfileGlideRequest
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.model.smartplaylist.HistoryPlaylist
|
||||
import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist
|
||||
import code.name.monkey.retromusic.model.smartplaylist.TopTracksPlaylist
|
||||
import code.name.monkey.retromusic.repository.Repository
|
||||
import code.name.monkey.retromusic.util.NavigationUtil
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
|
@ -74,15 +72,15 @@ class HomeFragment :
|
|||
|
||||
lastAdded.setOnClickListener {
|
||||
findActivityNavController(R.id.fragment_container).navigate(
|
||||
R.id.playlistDetailsFragment,
|
||||
bundleOf(EXTRA_PLAYLIST to LastAddedPlaylist())
|
||||
R.id.detailListFragment,
|
||||
bundleOf("type" to LAST_ADDED_PLAYLIST)
|
||||
)
|
||||
}
|
||||
|
||||
topPlayed.setOnClickListener {
|
||||
findActivityNavController(R.id.fragment_container).navigate(
|
||||
R.id.playlistDetailsFragment,
|
||||
bundleOf(EXTRA_PLAYLIST to TopTracksPlaylist())
|
||||
R.id.detailListFragment,
|
||||
bundleOf("type" to TOP_PLAYED_PLAYLIST)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -96,9 +94,9 @@ class HomeFragment :
|
|||
}
|
||||
|
||||
history.setOnClickListener {
|
||||
requireActivity().findNavController(R.id.fragment_container).navigate(
|
||||
R.id.playlistDetailsFragment,
|
||||
bundleOf(EXTRA_PLAYLIST to HistoryPlaylist())
|
||||
findActivityNavController(R.id.fragment_container).navigate(
|
||||
R.id.detailListFragment,
|
||||
bundleOf("type" to HISTORY_PLAYLIST)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,7 @@ package code.name.monkey.retromusic.fragments.player.fit
|
|||
import android.animation.ObjectAnimator
|
||||
import android.graphics.PorterDuff
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AccelerateInterpolator
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import android.view.animation.LinearInterpolator
|
||||
|
@ -26,7 +24,6 @@ import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler
|
|||
import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener
|
||||
import code.name.monkey.retromusic.service.MusicService
|
||||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||
import kotlinx.android.synthetic.main.fragment_fit_playback_controls.*
|
||||
|
|
|
@ -127,7 +127,7 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
|
|||
return String(Character.toChars(unicode))
|
||||
}
|
||||
|
||||
public override fun onPause() {
|
||||
override fun onPause() {
|
||||
if (recyclerViewDragDropManager != null) {
|
||||
recyclerViewDragDropManager!!.cancelDrag()
|
||||
}
|
||||
|
|
|
@ -31,7 +31,8 @@ class PlaylistDetailsViewModel(
|
|||
loadPlaylistSongs(playlist)
|
||||
}
|
||||
|
||||
private fun loadPlaylistSongs(playlist: PlaylistWithSongs) = viewModelScope.launch(Dispatchers.IO) {
|
||||
private fun loadPlaylistSongs(playlist: PlaylistWithSongs) =
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val songs: List<Song> = realRepository.playlistSongs(playlist)
|
||||
withContext(Main) { _playListSongs.postValue(songs) }
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
package code.name.monkey.retromusic.glide.artistimage
|
||||
|
||||
import android.content.Context
|
||||
import code.name.monkey.retromusic.deezer.DeezerApiService
|
||||
import code.name.monkey.retromusic.deezer.Data
|
||||
import code.name.monkey.retromusic.deezer.DeezerApiService
|
||||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import com.bumptech.glide.Priority
|
||||
|
@ -69,13 +69,13 @@ class ArtistImageFetcher(
|
|||
val response = deezerApiService.getArtistImage(artists[0]).execute()
|
||||
|
||||
if (!response.isSuccessful) {
|
||||
throw IOException("Request failed with code: " + response.code());
|
||||
throw IOException("Request failed with code: " + response.code())
|
||||
}
|
||||
|
||||
if (isCancelled) return null
|
||||
|
||||
return try {
|
||||
val deezerResponse = response.body();
|
||||
val deezerResponse = response.body()
|
||||
val imageUrl = deezerResponse?.data?.get(0)?.let { getHighestQuality(it) }
|
||||
// Fragile way to detect a place holder image returned from Deezer:
|
||||
// ex: "https://e-cdns-images.dzcdn.net/images/artist//250x250-000000-80-0-0.jpg"
|
||||
|
|
|
@ -21,7 +21,7 @@ import code.name.monkey.retromusic.R
|
|||
|
||||
object HorizontalAdapterHelper {
|
||||
|
||||
const val LAYOUT_RES = R.layout.item_image
|
||||
const val LAYOUT_RES = R.layout.item_album_card
|
||||
|
||||
private const val TYPE_FIRST = 1
|
||||
private const val TYPE_MIDDLE = 2
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
*/
|
||||
package code.name.monkey.retromusic.helper
|
||||
|
||||
import android.content.Context
|
||||
import code.name.monkey.retromusic.model.Playlist
|
||||
import java.io.BufferedWriter
|
||||
import java.io.File
|
||||
|
@ -24,14 +23,13 @@ object M3UWriter : M3UConstants {
|
|||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun write(
|
||||
context: Context,
|
||||
dir: File,
|
||||
playlist: Playlist
|
||||
): File? {
|
||||
if (!dir.exists()) dir.mkdirs()
|
||||
val file = File(dir, playlist.name + "." + M3UConstants.EXTENSION)
|
||||
val songs = playlist.getSongs()
|
||||
if (songs.size > 0) {
|
||||
if (songs.isNotEmpty()) {
|
||||
val bw = BufferedWriter(FileWriter(file))
|
||||
bw.write(M3UConstants.HEADER)
|
||||
for (song in songs) {
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
package code.name.monkey.retromusic.helper
|
||||
|
||||
import android.app.SearchManager
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
|
@ -33,7 +32,7 @@ object SearchQueryHelper : KoinComponent {
|
|||
var songs = ArrayList<Song>()
|
||||
|
||||
@JvmStatic
|
||||
fun getSongs(context: Context, extras: Bundle): List<Song> {
|
||||
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)
|
||||
|
@ -45,9 +44,9 @@ object SearchQueryHelper : KoinComponent {
|
|||
songRepository.makeSongCursor(
|
||||
ARTIST_SELECTION + AND + ALBUM_SELECTION + AND + TITLE_SELECTION,
|
||||
arrayOf(
|
||||
artistName.toLowerCase(),
|
||||
albumName.toLowerCase(),
|
||||
titleName.toLowerCase()
|
||||
artistName.toLowerCase(Locale.getDefault()),
|
||||
albumName.toLowerCase(Locale.getDefault()),
|
||||
titleName.toLowerCase(Locale.getDefault())
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -59,7 +58,10 @@ object SearchQueryHelper : KoinComponent {
|
|||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
ARTIST_SELECTION + AND + TITLE_SELECTION,
|
||||
arrayOf(artistName.toLowerCase(), titleName.toLowerCase())
|
||||
arrayOf(
|
||||
artistName.toLowerCase(Locale.getDefault()),
|
||||
titleName.toLowerCase(Locale.getDefault())
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -70,7 +72,10 @@ object SearchQueryHelper : KoinComponent {
|
|||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
ALBUM_SELECTION + AND + TITLE_SELECTION,
|
||||
arrayOf(albumName.toLowerCase(), titleName.toLowerCase())
|
||||
arrayOf(
|
||||
albumName.toLowerCase(Locale.getDefault()),
|
||||
titleName.toLowerCase(Locale.getDefault())
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -81,7 +86,7 @@ object SearchQueryHelper : KoinComponent {
|
|||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
ARTIST_SELECTION,
|
||||
arrayOf(artistName.toLowerCase())
|
||||
arrayOf(artistName.toLowerCase(Locale.getDefault()))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -92,7 +97,7 @@ object SearchQueryHelper : KoinComponent {
|
|||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
ALBUM_SELECTION,
|
||||
arrayOf(albumName.toLowerCase())
|
||||
arrayOf(albumName.toLowerCase(Locale.getDefault()))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -103,7 +108,7 @@ object SearchQueryHelper : KoinComponent {
|
|||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
TITLE_SELECTION,
|
||||
arrayOf(titleName.toLowerCase())
|
||||
arrayOf(titleName.toLowerCase(Locale.getDefault()))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -113,7 +118,7 @@ object SearchQueryHelper : KoinComponent {
|
|||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
ARTIST_SELECTION,
|
||||
arrayOf(query.toLowerCase())
|
||||
arrayOf(query.toLowerCase(Locale.getDefault()))
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -123,7 +128,7 @@ object SearchQueryHelper : KoinComponent {
|
|||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
ALBUM_SELECTION,
|
||||
arrayOf(query.toLowerCase())
|
||||
arrayOf(query.toLowerCase(Locale.getDefault()))
|
||||
)
|
||||
)
|
||||
if (songs.isNotEmpty()) {
|
||||
|
@ -132,7 +137,7 @@ object SearchQueryHelper : KoinComponent {
|
|||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
TITLE_SELECTION,
|
||||
arrayOf(query.toLowerCase())
|
||||
arrayOf(query.toLowerCase(Locale.getDefault()))
|
||||
)
|
||||
)
|
||||
return if (songs.isNotEmpty()) {
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
package code.name.monkey.retromusic.helper.menu
|
||||
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
|
@ -90,7 +89,6 @@ object PlaylistMenuHelper : KoinComponent {
|
|||
}
|
||||
|
||||
private fun getPlaylistSongs(
|
||||
activity: Activity,
|
||||
playlist: Playlist
|
||||
): List<Song> {
|
||||
return if (playlist is AbsCustomPlaylist) {
|
||||
|
@ -100,7 +98,7 @@ object PlaylistMenuHelper : KoinComponent {
|
|||
}
|
||||
}
|
||||
|
||||
private class SavePlaylistAsyncTask internal constructor(context: Context) :
|
||||
private class SavePlaylistAsyncTask(context: Context) :
|
||||
WeakContextAsyncTask<Playlist, String, String>(context) {
|
||||
|
||||
override fun doInBackground(vararg params: Playlist): String {
|
||||
|
|
|
@ -11,20 +11,20 @@ public class Lrc {
|
|||
private long time;
|
||||
private String text;
|
||||
|
||||
public void setTime(long time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(long time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
}
|
|
@ -23,6 +23,9 @@ import android.text.TextUtils;
|
|||
* 一行歌词实体
|
||||
*/
|
||||
class LrcEntry implements Comparable<LrcEntry> {
|
||||
public static final int GRAVITY_CENTER = 0;
|
||||
public static final int GRAVITY_LEFT = 1;
|
||||
public static final int GRAVITY_RIGHT = 2;
|
||||
private long time;
|
||||
private String text;
|
||||
private String secondText;
|
||||
|
@ -31,9 +34,6 @@ class LrcEntry implements Comparable<LrcEntry> {
|
|||
* 歌词距离视图顶部的距离
|
||||
*/
|
||||
private float offset = Float.MIN_VALUE;
|
||||
public static final int GRAVITY_CENTER = 0;
|
||||
public static final int GRAVITY_LEFT = 1;
|
||||
public static final int GRAVITY_RIGHT = 2;
|
||||
|
||||
LrcEntry(long time, String text) {
|
||||
this.time = time;
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.io.InputStreamReader;
|
|||
import java.lang.reflect.Field;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -77,7 +78,7 @@ class LrcUtils {
|
|||
|
||||
List<LrcEntry> entryList = new ArrayList<>();
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(lrcFile), "utf-8"));
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(lrcFile), StandardCharsets.UTF_8));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
List<LrcEntry> list = parseLine(line);
|
||||
|
|
|
@ -35,6 +35,8 @@ import android.view.View;
|
|||
import android.view.animation.LinearInterpolator;
|
||||
import android.widget.Scroller;
|
||||
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -510,6 +512,7 @@ public class LrcView extends View {
|
|||
if (i > 0) {
|
||||
y += ((mLrcEntryList.get(i - 1).getHeight() + mLrcEntryList.get(i).getHeight()) >> 1) + mDividerHeight;
|
||||
}
|
||||
mLrcPaint.setTypeface(ResourcesCompat.getFont(getContext(), R.font.sans));
|
||||
if (i == mCurrentLine) {
|
||||
mLrcPaint.setTextSize(mCurrentTextSize);
|
||||
mLrcPaint.setColor(mCurrentTextColor);
|
||||
|
|
|
@ -14,10 +14,13 @@
|
|||
|
||||
package code.name.monkey.retromusic.model
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import code.name.monkey.retromusic.HomeSection
|
||||
|
||||
class Home(
|
||||
val arrayList: List<Any>,
|
||||
@HomeSection
|
||||
val homeSection: Int
|
||||
val homeSection: Int,
|
||||
@StringRes
|
||||
val titleRes: Int
|
||||
)
|
|
@ -14,6 +14,7 @@
|
|||
package code.name.monkey.retromusic.model
|
||||
|
||||
import android.os.Parcelable
|
||||
import code.name.monkey.retromusic.db.HistoryEntity
|
||||
import code.name.monkey.retromusic.db.SongEntity
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
|
@ -33,6 +34,25 @@ open class Song(
|
|||
val composer: String?,
|
||||
val albumArtist: String?
|
||||
) : Parcelable {
|
||||
fun toHistoryEntity(timePlayed: Long): HistoryEntity {
|
||||
return HistoryEntity(
|
||||
id,
|
||||
title,
|
||||
trackNumber,
|
||||
year,
|
||||
duration,
|
||||
data,
|
||||
dateModified,
|
||||
albumId,
|
||||
albumName,
|
||||
artistId,
|
||||
artistName,
|
||||
composer,
|
||||
albumArtist,
|
||||
timePlayed
|
||||
)
|
||||
}
|
||||
|
||||
fun toSongEntity(playListId: Int): SongEntity {
|
||||
return SongEntity(
|
||||
playListId,
|
||||
|
|
|
@ -106,7 +106,7 @@ class AlbumCoverStylePreferenceDialog : DialogFragment(),
|
|||
override fun onPageScrollStateChanged(state: Int) {
|
||||
}
|
||||
|
||||
private class AlbumCoverStyleAdapter internal constructor(private val context: Context) :
|
||||
private class AlbumCoverStyleAdapter(private val context: Context) :
|
||||
PagerAdapter() {
|
||||
|
||||
override fun instantiateItem(collection: ViewGroup, position: Int): Any {
|
||||
|
|
|
@ -72,9 +72,7 @@ class LibraryPreferenceDialog : DialogFragment() {
|
|||
categoryAdapter.categoryInfos = PreferenceUtil.defaultCategories
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(
|
||||
android.R.string.ok
|
||||
) { _, _ -> updateCategories(categoryAdapter.categoryInfos) }
|
||||
.setPositiveButton(R.string.ok) { _, _ -> updateCategories(categoryAdapter.categoryInfos) }
|
||||
.setView(view)
|
||||
.create()
|
||||
.colorButtons()
|
||||
|
|
|
@ -108,7 +108,7 @@ public class SongPlayCountStore extends SQLiteOpenHelper {
|
|||
*/
|
||||
@NonNull
|
||||
private static String getColumnNameForWeek(final int week) {
|
||||
return SongPlayCountColumns.WEEK_PLAY_COUNT + String.valueOf(week);
|
||||
return SongPlayCountColumns.WEEK_PLAY_COUNT + week;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,10 +15,9 @@
|
|||
package code.name.monkey.retromusic.repository
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.LiveData
|
||||
import code.name.monkey.retromusic.*
|
||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
||||
import code.name.monkey.retromusic.db.SongEntity
|
||||
import code.name.monkey.retromusic.db.*
|
||||
import code.name.monkey.retromusic.model.*
|
||||
import code.name.monkey.retromusic.model.smartplaylist.NotPlayedPlaylist
|
||||
import code.name.monkey.retromusic.network.LastFMService
|
||||
|
@ -32,91 +31,65 @@ import kotlinx.coroutines.flow.flow
|
|||
interface Repository {
|
||||
|
||||
fun songsFlow(): Flow<Result<List<Song>>>
|
||||
|
||||
fun albumsFlow(): Flow<Result<List<Album>>>
|
||||
|
||||
fun artistsFlow(): Flow<Result<List<Artist>>>
|
||||
|
||||
fun playlistsFlow(): Flow<Result<List<Playlist>>>
|
||||
|
||||
fun genresFlow(): Flow<Result<List<Genre>>>
|
||||
|
||||
|
||||
suspend fun allAlbums(): List<Album>
|
||||
|
||||
suspend fun albumById(albumId: Int): Album
|
||||
|
||||
suspend fun allSongs(): List<Song>
|
||||
|
||||
suspend fun allArtists(): List<Artist>
|
||||
|
||||
suspend fun albumArtists(): List<Artist>
|
||||
|
||||
suspend fun allPlaylists(): List<Playlist>
|
||||
|
||||
suspend fun allGenres(): List<Genre>
|
||||
|
||||
suspend fun search(query: String?): MutableList<Any>
|
||||
|
||||
suspend fun getPlaylistSongs(playlist: Playlist): List<Song>
|
||||
|
||||
suspend fun getGenre(genreId: Int): List<Song>
|
||||
|
||||
suspend fun artistInfo(name: String, lang: String?, cache: String?): LastFmArtist
|
||||
|
||||
suspend fun albumInfo(artist: String, album: String): LastFmAlbum
|
||||
|
||||
suspend fun artistById(artistId: Int): Artist
|
||||
|
||||
suspend fun recentArtists(): List<Artist>
|
||||
|
||||
suspend fun topArtists(): List<Artist>
|
||||
|
||||
suspend fun topAlbums(): List<Album>
|
||||
|
||||
suspend fun recentAlbums(): List<Album>
|
||||
|
||||
suspend fun recentArtistsHome(): Home
|
||||
|
||||
suspend fun topArtistsHome(): Home
|
||||
|
||||
suspend fun topAlbumsHome(): Home
|
||||
|
||||
suspend fun recentAlbumsHome(): Home
|
||||
|
||||
suspend fun favoritePlaylistHome(): Home
|
||||
|
||||
suspend fun suggestionsHome(): Home
|
||||
|
||||
suspend fun genresHome(): Home
|
||||
|
||||
suspend fun playlists(): Home
|
||||
|
||||
suspend fun homeSections(): List<Home>
|
||||
|
||||
suspend fun homeSectionsFlow(): Flow<Result<List<Home>>>
|
||||
|
||||
suspend fun playlist(playlistId: Int): Playlist
|
||||
|
||||
suspend fun playlistWithSongs(): List<PlaylistWithSongs>
|
||||
|
||||
suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List<Song>
|
||||
|
||||
suspend fun insertSongs(songs: List<SongEntity>)
|
||||
|
||||
suspend fun checkPlaylistExists(playlistName: String): List<PlaylistEntity>
|
||||
|
||||
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long
|
||||
|
||||
suspend fun roomPlaylists(): List<PlaylistEntity>
|
||||
|
||||
suspend fun deleteRoomPlaylist(playlists: List<PlaylistEntity>)
|
||||
|
||||
suspend fun renameRoomPlaylist(playlistId: Int, name: String)
|
||||
|
||||
suspend fun removeSongFromPlaylist(songs: List<SongEntity>)
|
||||
|
||||
suspend fun deleteSongsInPlaylist(songs: List<SongEntity>)
|
||||
suspend fun removeSongFromPlaylist(songEntity: SongEntity)
|
||||
suspend fun deleteSongsFromPlaylist(playlists: List<PlaylistEntity>)
|
||||
suspend fun favoritePlaylist(): List<PlaylistEntity>
|
||||
suspend fun isFavoriteSong(songEntity: SongEntity): List<SongEntity>
|
||||
suspend fun addSongToHistory(currentSong: Song)
|
||||
suspend fun songPresentInHistory(currentSong: Song): HistoryEntity?
|
||||
suspend fun updateHistorySong(currentSong: Song)
|
||||
suspend fun favoritePlaylistSongs(): List<SongEntity>
|
||||
suspend fun recentSongs(): List<Song>
|
||||
suspend fun topPlayedSongs(): List<Song>
|
||||
suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity>
|
||||
suspend fun playCountSongs(): List<PlayCountEntity>
|
||||
fun historySong(): LiveData<List<HistoryEntity>>
|
||||
fun favorites(): LiveData<List<SongEntity>>
|
||||
}
|
||||
|
||||
class RealRepository(
|
||||
|
@ -129,8 +102,8 @@ class RealRepository(
|
|||
private val lastAddedRepository: LastAddedRepository,
|
||||
private val playlistRepository: PlaylistRepository,
|
||||
private val searchRepository: RealSearchRepository,
|
||||
private val playedTracksRepository: TopPlayedRepository,
|
||||
private val roomPlaylistRepository: RoomPlaylistRepository
|
||||
private val topPlayedRepository: TopPlayedRepository,
|
||||
private val roomRepository: RoomPlaylistRepository
|
||||
) : Repository {
|
||||
|
||||
override suspend fun allAlbums(): List<Album> = albumRepository.albums()
|
||||
|
@ -147,9 +120,9 @@ class RealRepository(
|
|||
|
||||
override suspend fun recentAlbums(): List<Album> = lastAddedRepository.recentAlbums()
|
||||
|
||||
override suspend fun topArtists(): List<Artist> = playedTracksRepository.topArtists()
|
||||
override suspend fun topArtists(): List<Artist> = topPlayedRepository.topArtists()
|
||||
|
||||
override suspend fun topAlbums(): List<Album> = playedTracksRepository.topAlbums()
|
||||
override suspend fun topAlbums(): List<Album> = topPlayedRepository.topAlbums()
|
||||
|
||||
override suspend fun allPlaylists(): List<Playlist> = playlistRepository.playlists()
|
||||
|
||||
|
@ -214,13 +187,14 @@ class RealRepository(
|
|||
|
||||
override suspend fun homeSections(): List<Home> {
|
||||
val homeSections = mutableListOf<Home>()
|
||||
val sections = listOf(
|
||||
val sections: List<Home> = listOf(
|
||||
suggestionsHome(),
|
||||
topArtistsHome(),
|
||||
topAlbumsHome(),
|
||||
recentArtistsHome(),
|
||||
recentAlbumsHome(),
|
||||
suggestionsHome(),
|
||||
favoritePlaylistHome()
|
||||
favoritePlaylistHome(),
|
||||
genresHome()
|
||||
)
|
||||
for (section in sections) {
|
||||
if (section.arrayList.isNotEmpty()) {
|
||||
|
@ -230,16 +204,12 @@ class RealRepository(
|
|||
return homeSections
|
||||
}
|
||||
|
||||
override suspend fun playlists(): Home {
|
||||
val playlist = playlistRepository.playlists()
|
||||
return Home(playlist, TOP_ALBUMS)
|
||||
}
|
||||
|
||||
override suspend fun playlist(playlistId: Int) =
|
||||
playlistRepository.playlist(playlistId)
|
||||
|
||||
override suspend fun playlistWithSongs(): List<PlaylistWithSongs> =
|
||||
roomPlaylistRepository.playlistWithSongs()
|
||||
roomRepository.playlistWithSongs()
|
||||
|
||||
override suspend fun playlistSongs(playlistWithSongs: PlaylistWithSongs): List<Song> {
|
||||
return playlistWithSongs.songs.map {
|
||||
|
@ -248,71 +218,118 @@ class RealRepository(
|
|||
}
|
||||
|
||||
override suspend fun insertSongs(songs: List<SongEntity>) =
|
||||
roomPlaylistRepository.insertSongs(songs)
|
||||
roomRepository.insertSongs(songs)
|
||||
|
||||
override suspend fun checkPlaylistExists(playlistName: String): List<PlaylistEntity> =
|
||||
roomPlaylistRepository.checkPlaylistExists(playlistName)
|
||||
roomRepository.checkPlaylistExists(playlistName)
|
||||
|
||||
override suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long =
|
||||
roomPlaylistRepository.createPlaylist(playlistEntity)
|
||||
roomRepository.createPlaylist(playlistEntity)
|
||||
|
||||
override suspend fun roomPlaylists(): List<PlaylistEntity> = roomPlaylistRepository.playlists()
|
||||
override suspend fun roomPlaylists(): List<PlaylistEntity> = roomRepository.playlists()
|
||||
|
||||
override suspend fun deleteRoomPlaylist(playlists: List<PlaylistEntity>) =
|
||||
roomPlaylistRepository.deletePlaylistEntities(playlists)
|
||||
roomRepository.deletePlaylistEntities(playlists)
|
||||
|
||||
override suspend fun renameRoomPlaylist(playlistId: Int, name: String) =
|
||||
roomPlaylistRepository.renamePlaylistEntity(playlistId, name)
|
||||
roomRepository.renamePlaylistEntity(playlistId, name)
|
||||
|
||||
override suspend fun removeSongFromPlaylist(songs: List<SongEntity>) =
|
||||
roomPlaylistRepository.removeSongsFromPlaylist(songs)
|
||||
override suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) =
|
||||
roomRepository.deleteSongsInPlaylist(songs)
|
||||
|
||||
override suspend fun removeSongFromPlaylist(songEntity: SongEntity) =
|
||||
roomRepository.removeSongFromPlaylist(songEntity)
|
||||
|
||||
override suspend fun deleteSongsFromPlaylist(playlists: List<PlaylistEntity>) =
|
||||
roomPlaylistRepository.deleteSongsFromPlaylist(playlists)
|
||||
roomRepository.deleteSongsFromPlaylist(playlists)
|
||||
|
||||
override suspend fun favoritePlaylist(): List<PlaylistEntity> =
|
||||
roomRepository.favoritePlaylist(context.getString(R.string.favorites))
|
||||
|
||||
override suspend fun isFavoriteSong(songEntity: SongEntity): List<SongEntity> =
|
||||
roomRepository.isFavoriteSong(songEntity)
|
||||
|
||||
override suspend fun addSongToHistory(currentSong: Song) =
|
||||
roomRepository.addSongToHistory(currentSong)
|
||||
|
||||
override suspend fun songPresentInHistory(currentSong: Song): HistoryEntity? =
|
||||
roomRepository.songPresentInHistory(currentSong)
|
||||
|
||||
override suspend fun updateHistorySong(currentSong: Song) =
|
||||
roomRepository.updateHistorySong(currentSong)
|
||||
|
||||
override suspend fun favoritePlaylistSongs(): List<SongEntity> =
|
||||
roomRepository.favoritePlaylistSongs(context.getString(R.string.favorites))
|
||||
|
||||
override suspend fun recentSongs(): List<Song> = lastAddedRepository.recentSongs()
|
||||
|
||||
override suspend fun topPlayedSongs(): List<Song> = topPlayedRepository.topTracks()
|
||||
|
||||
override suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity) =
|
||||
roomRepository.insertSongInPlayCount(playCountEntity)
|
||||
|
||||
override suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity) =
|
||||
roomRepository.updateSongInPlayCount(playCountEntity)
|
||||
|
||||
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
|
||||
roomRepository.deleteSongInPlayCount(playCountEntity)
|
||||
|
||||
override suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity> =
|
||||
roomRepository.checkSongExistInPlayCount(songId)
|
||||
|
||||
override suspend fun playCountSongs(): List<PlayCountEntity> =
|
||||
roomRepository.playCountSongs()
|
||||
|
||||
override fun historySong(): LiveData<List<HistoryEntity>> =
|
||||
roomRepository.historySongs()
|
||||
|
||||
override fun favorites(): LiveData<List<SongEntity>> =
|
||||
roomRepository.favoritePlaylistLiveData(context.getString(R.string.favorites))
|
||||
|
||||
override suspend fun suggestionsHome(): Home {
|
||||
val songs =
|
||||
NotPlayedPlaylist().songs().shuffled().takeIf {
|
||||
it.size > 9
|
||||
} ?: emptyList()
|
||||
println(songs.size)
|
||||
return Home(songs, SUGGESTIONS)
|
||||
return Home(songs, SUGGESTIONS, R.string.suggestion_songs)
|
||||
}
|
||||
|
||||
override suspend fun genresHome(): Home {
|
||||
val genres = genreRepository.genres().shuffled()
|
||||
return Home(genres, GENRES)
|
||||
return Home(genres, GENRES, R.string.genres)
|
||||
}
|
||||
|
||||
override suspend fun playlists(): Home {
|
||||
val playlist = playlistRepository.playlists()
|
||||
return Home(playlist, PLAYLISTS, R.string.playlists)
|
||||
}
|
||||
|
||||
override suspend fun recentArtistsHome(): Home {
|
||||
val artists = lastAddedRepository.recentArtists().take(5)
|
||||
return Home(artists, RECENT_ARTISTS)
|
||||
return Home(artists, RECENT_ARTISTS, R.string.recent_artists)
|
||||
}
|
||||
|
||||
override suspend fun recentAlbumsHome(): Home {
|
||||
val albums = lastAddedRepository.recentAlbums().take(5)
|
||||
return Home(albums, RECENT_ALBUMS)
|
||||
return Home(albums, RECENT_ALBUMS, R.string.recent_albums)
|
||||
}
|
||||
|
||||
override suspend fun topAlbumsHome(): Home {
|
||||
val albums = playedTracksRepository.topAlbums().take(5)
|
||||
return Home(albums, TOP_ALBUMS)
|
||||
val albums = topPlayedRepository.topAlbums().take(5)
|
||||
return Home(albums, TOP_ALBUMS, R.string.top_albums)
|
||||
}
|
||||
|
||||
override suspend fun topArtistsHome(): Home {
|
||||
val artists = playedTracksRepository.topArtists().take(5)
|
||||
return Home(artists, TOP_ARTISTS)
|
||||
val artists = topPlayedRepository.topArtists().take(5)
|
||||
return Home(artists, TOP_ARTISTS, R.string.top_artists)
|
||||
}
|
||||
|
||||
override suspend fun favoritePlaylistHome(): Home {
|
||||
val playlists =
|
||||
playlistRepository.favoritePlaylist(context.getString(R.string.favorites)).take(5)
|
||||
val songs = if (playlists.isNotEmpty())
|
||||
PlaylistSongsLoader.getPlaylistSongList(context, playlists[0])
|
||||
else emptyList()
|
||||
|
||||
return Home(songs, FAVOURITES)
|
||||
val songs = favoritePlaylistSongs().map {
|
||||
it.toSong()
|
||||
}
|
||||
println(songs.size)
|
||||
return Home(songs, FAVOURITES, R.string.favorites)
|
||||
}
|
||||
|
||||
override fun songsFlow(): Flow<Result<List<Song>>> = flow {
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package code.name.monkey.retromusic.repository
|
||||
|
||||
import androidx.annotation.WorkerThread
|
||||
import code.name.monkey.retromusic.db.PlaylistDao
|
||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
||||
import code.name.monkey.retromusic.db.SongEntity
|
||||
import androidx.lifecycle.LiveData
|
||||
import code.name.monkey.retromusic.db.*
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
|
||||
|
||||
interface RoomPlaylistRepository {
|
||||
|
@ -16,11 +15,25 @@ interface RoomPlaylistRepository {
|
|||
suspend fun getSongs(playlistEntity: PlaylistEntity): List<SongEntity>
|
||||
suspend fun deletePlaylistEntities(playlistEntities: List<PlaylistEntity>)
|
||||
suspend fun renamePlaylistEntity(playlistId: Int, name: String)
|
||||
suspend fun removeSongsFromPlaylist(songs: List<SongEntity>)
|
||||
suspend fun deleteSongsInPlaylist(songs: List<SongEntity>)
|
||||
suspend fun deleteSongsFromPlaylist(playlists: List<PlaylistEntity>)
|
||||
suspend fun favoritePlaylist(favorite: String): List<PlaylistEntity>
|
||||
suspend fun isFavoriteSong(songEntity: SongEntity): List<SongEntity>
|
||||
suspend fun removeSongFromPlaylist(songEntity: SongEntity)
|
||||
suspend fun addSongToHistory(currentSong: Song)
|
||||
suspend fun songPresentInHistory(song: Song): HistoryEntity?
|
||||
suspend fun updateHistorySong(song: Song)
|
||||
suspend fun favoritePlaylistSongs(favorite: String): List<SongEntity>
|
||||
suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity>
|
||||
suspend fun playCountSongs(): List<PlayCountEntity>
|
||||
fun historySongs(): LiveData<List<HistoryEntity>>
|
||||
fun favoritePlaylistLiveData(favorite: String): LiveData<List<SongEntity>>
|
||||
}
|
||||
|
||||
class RealRoomPlaylistRepository(
|
||||
class RealRoomRepository(
|
||||
private val playlistDao: PlaylistDao
|
||||
) : RoomPlaylistRepository {
|
||||
@WorkerThread
|
||||
|
@ -29,14 +42,14 @@ class RealRoomPlaylistRepository(
|
|||
|
||||
@WorkerThread
|
||||
override suspend fun checkPlaylistExists(playlistName: String): List<PlaylistEntity> =
|
||||
playlistDao.checkPlaylistExists(playlistName)
|
||||
playlistDao.isPlaylistExists(playlistName)
|
||||
|
||||
@WorkerThread
|
||||
override suspend fun playlists(): List<PlaylistEntity> = playlistDao.playlists()
|
||||
|
||||
@WorkerThread
|
||||
override suspend fun playlistWithSongs(): List<PlaylistWithSongs> =
|
||||
playlistDao.playlistsWithSong()
|
||||
playlistDao.playlistsWithSongs()
|
||||
|
||||
@WorkerThread
|
||||
override suspend fun insertSongs(songs: List<SongEntity>) {
|
||||
|
@ -46,26 +59,77 @@ class RealRoomPlaylistRepository(
|
|||
}.first()
|
||||
println("Existing ${existingSongs.size}")
|
||||
tempList.removeAll(existingSongs)*/
|
||||
playlistDao.insertSongs(songs)
|
||||
playlistDao.insertSongsToPlaylist(songs)
|
||||
}
|
||||
|
||||
override suspend fun getSongs(playlistEntity: PlaylistEntity): List<SongEntity> {
|
||||
return playlistDao.getSongs(playlistEntity.playListId)
|
||||
return playlistDao.songsFromPlaylist(playlistEntity.playListId)
|
||||
}
|
||||
|
||||
override suspend fun deletePlaylistEntities(playlistEntities: List<PlaylistEntity>) =
|
||||
playlistDao.deletePlaylistEntities(playlistEntities)
|
||||
playlistDao.deletePlaylists(playlistEntities)
|
||||
|
||||
override suspend fun renamePlaylistEntity(playlistId: Int, name: String) =
|
||||
playlistDao.renamePlaylistEntity(playlistId, name)
|
||||
playlistDao.renamePlaylist(playlistId, name)
|
||||
|
||||
override suspend fun removeSongsFromPlaylist(songs: List<SongEntity>) =
|
||||
playlistDao.removeSongsFromPlaylist(songs)
|
||||
override suspend fun deleteSongsInPlaylist(songs: List<SongEntity>) =
|
||||
playlistDao.deleteSongsInPlaylist(songs)
|
||||
|
||||
override suspend fun deleteSongsFromPlaylist(playlists: List<PlaylistEntity>) {
|
||||
playlists.forEach {
|
||||
playlistDao.deleteSongsFromPlaylist(it.playListId)
|
||||
playlistDao.deleteSongsInPlaylist(it.playListId)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun favoritePlaylist(favorite: String): List<PlaylistEntity> =
|
||||
playlistDao.isPlaylistExists(favorite)
|
||||
|
||||
override suspend fun isFavoriteSong(songEntity: SongEntity): List<SongEntity> =
|
||||
playlistDao.isSongExistsInPlaylist(
|
||||
songEntity.playlistCreatorId,
|
||||
songEntity.id
|
||||
)
|
||||
|
||||
override suspend fun removeSongFromPlaylist(songEntity: SongEntity) =
|
||||
playlistDao.removeSongFromPlaylist(songEntity.playlistCreatorId, songEntity.id)
|
||||
|
||||
override suspend fun addSongToHistory(currentSong: Song) =
|
||||
playlistDao.insertSongInHistory(currentSong.toHistoryEntity(System.currentTimeMillis()))
|
||||
|
||||
override suspend fun songPresentInHistory(song: Song): HistoryEntity? =
|
||||
playlistDao.isSongPresentInHistory(song.id)
|
||||
|
||||
override suspend fun updateHistorySong(song: Song) =
|
||||
playlistDao.updateHistorySong(song.toHistoryEntity(System.currentTimeMillis()))
|
||||
|
||||
override fun historySongs(): LiveData<List<HistoryEntity>> {
|
||||
return playlistDao.historySongs()
|
||||
}
|
||||
|
||||
override fun favoritePlaylistLiveData(favorite: String): LiveData<List<SongEntity>> =
|
||||
playlistDao.favoritesSongsLiveData(
|
||||
playlistDao.isPlaylistExists(favorite).first().playListId
|
||||
)
|
||||
|
||||
override suspend fun favoritePlaylistSongs(favorite: String): List<SongEntity> {
|
||||
return if (playlistDao.isPlaylistExists(favorite).isNotEmpty())
|
||||
playlistDao.favoritesSongs(
|
||||
playlistDao.isPlaylistExists(favorite).first().playListId
|
||||
) else emptyList()
|
||||
}
|
||||
|
||||
override suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity) =
|
||||
playlistDao.insertSongInPlayCount(playCountEntity)
|
||||
|
||||
override suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity) =
|
||||
playlistDao.updateSongInPlayCount(playCountEntity)
|
||||
|
||||
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
|
||||
playlistDao.deleteSongInPlayCount(playCountEntity)
|
||||
|
||||
override suspend fun checkSongExistInPlayCount(songId: Int): List<PlayCountEntity> =
|
||||
playlistDao.checkSongExistInPlayCount(songId)
|
||||
|
||||
override suspend fun playCountSongs(): List<PlayCountEntity> =
|
||||
playlistDao.playCountSongs()
|
||||
}
|
|
@ -116,13 +116,13 @@ class RealTopPlayedRepository(
|
|||
|
||||
private fun makeTopTracksCursorImpl(): SortedLongCursor? {
|
||||
// first get the top results ids from the internal database
|
||||
val songs =
|
||||
val cursor =
|
||||
SongPlayCountStore.getInstance(context).getTopPlayedResults(NUMBER_OF_TOP_TRACKS)
|
||||
|
||||
songs.use { localSongs ->
|
||||
cursor.use { songs ->
|
||||
return makeSortedCursor(
|
||||
localSongs,
|
||||
localSongs.getColumnIndex(SongPlayCountStore.SongPlayCountColumns.ID)
|
||||
songs,
|
||||
songs.getColumnIndex(SongPlayCountStore.SongPlayCountColumns.ID)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@ import android.graphics.BitmapFactory
|
|||
import android.graphics.Color
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import android.text.Html
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.media.app.NotificationCompat.MediaStyle
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.activities.MainActivity
|
||||
|
@ -132,9 +132,19 @@ class PlayingNotificationImpl : PlayingNotification() {
|
|||
.setLargeIcon(bitmapFinal)
|
||||
.setContentIntent(clickIntent)
|
||||
.setDeleteIntent(deleteIntent)
|
||||
.setContentTitle(Html.fromHtml("<b>" + song.title + "</b>"))
|
||||
.setContentTitle(
|
||||
HtmlCompat.fromHtml(
|
||||
"<b>" + song.title + "</b>",
|
||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||
)
|
||||
)
|
||||
.setContentText(song.artistName)
|
||||
.setSubText(Html.fromHtml("<b>" + song.albumName + "</b>"))
|
||||
.setSubText(
|
||||
HtmlCompat.fromHtml(
|
||||
"<b>" + song.albumName + "</b>",
|
||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||
)
|
||||
)
|
||||
.setOngoing(isPlaying)
|
||||
.setShowWhen(false)
|
||||
.addAction(toggleFavorite)
|
||||
|
|
|
@ -162,7 +162,6 @@ public class AutoGeneratedPlaylistBitmap {
|
|||
|
||||
|
||||
}
|
||||
;
|
||||
Log.d(TAG, "getBitmapCollection: smalltime = " + (System.currentTimeMillis() - start));
|
||||
if (round)
|
||||
return BitmapEditor.getRoundedCornerBitmap(bitmap, bitmap.getWidth() / 40);
|
||||
|
|
|
@ -83,16 +83,16 @@ public final class BitmapEditor {
|
|||
int wh = w * h;
|
||||
int div = radius + radius + 1;
|
||||
|
||||
int r[] = new int[wh];
|
||||
int g[] = new int[wh];
|
||||
int b[] = new int[wh];
|
||||
int a[] = new int[wh];
|
||||
int[] r = new int[wh];
|
||||
int[] g = new int[wh];
|
||||
int[] b = new int[wh];
|
||||
int[] a = new int[wh];
|
||||
int rsum, gsum, bsum, asum, x, y, i, p, yp, yi, yw;
|
||||
int vmin[] = new int[Math.max(w, h)];
|
||||
int[] vmin = new int[Math.max(w, h)];
|
||||
|
||||
int divsum = (div + 1) >> 1;
|
||||
divsum *= divsum;
|
||||
int dv[] = new int[256 * divsum];
|
||||
int[] dv = new int[256 * divsum];
|
||||
for (i = 0; i < 256 * divsum; i++) {
|
||||
dv[i] = (i / divsum);
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ public final class BitmapEditor {
|
|||
public static boolean PerceivedBrightness(int will_White, int[] c) {
|
||||
double TBT = Math.sqrt(c[0] * c[0] * .241 + c[1] * c[1] * .691 + c[2] * c[2] * .068);
|
||||
// Log.d("themee",TBT+"");
|
||||
return (TBT > will_White) ? false : true;
|
||||
return !(TBT > will_White);
|
||||
}
|
||||
|
||||
public static int[] getAverageColorRGB(Bitmap bitmap) {
|
||||
|
@ -404,15 +404,15 @@ public final class BitmapEditor {
|
|||
int wh = w * h;
|
||||
int div = radius + radius + 1;
|
||||
|
||||
int r[] = new int[wh];
|
||||
int g[] = new int[wh];
|
||||
int b[] = new int[wh];
|
||||
int[] r = new int[wh];
|
||||
int[] g = new int[wh];
|
||||
int[] b = new int[wh];
|
||||
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
|
||||
int vmin[] = new int[Math.max(w, h)];
|
||||
int[] vmin = new int[Math.max(w, h)];
|
||||
|
||||
int divsum = (div + 1) >> 1;
|
||||
divsum *= divsum;
|
||||
int dv[] = new int[256 * divsum];
|
||||
int[] dv = new int[256 * divsum];
|
||||
for (i = 0; i < 256 * divsum; i++) {
|
||||
dv[i] = (i / divsum);
|
||||
}
|
||||
|
@ -635,8 +635,7 @@ public final class BitmapEditor {
|
|||
|
||||
public static boolean TrueIfBitmapBigger(Bitmap bitmap, int size) {
|
||||
int sizeBitmap = (bitmap.getHeight() > bitmap.getWidth()) ? bitmap.getHeight() : bitmap.getWidth();
|
||||
if (sizeBitmap > size) return true;
|
||||
return false;
|
||||
return sizeBitmap > size;
|
||||
}
|
||||
|
||||
public static Bitmap GetRoundedBitmapWithBlurShadow(Bitmap original, int paddingTop, int paddingBottom, int paddingLeft, int paddingRight) {
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package code.name.monkey.retromusic.util
|
||||
|
||||
import android.os.Environment
|
||||
import java.io.File
|
||||
|
||||
object FilePathUtil {
|
||||
fun blacklistFilePaths(): List<String> {
|
||||
return listOf<File>(
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS),
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_RINGTONES),
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_NOTIFICATIONS)
|
||||
).map {
|
||||
FileUtil.safeGetCanonicalPath(it)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -245,13 +245,9 @@ public final class FileUtil {
|
|||
.equals(android.os.Environment.MEDIA_MOUNTED);
|
||||
Boolean isSDSupportedDevice = Environment.isExternalStorageRemovable();
|
||||
|
||||
if (isSDSupportedDevice && isSDPresent) {
|
||||
// yes SD-card is present
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
// Sorry
|
||||
}
|
||||
return isSDSupportedDevice && isSDPresent;
|
||||
}
|
||||
|
||||
public static File safeGetCanonicalFile(File file) {
|
||||
|
|
|
@ -26,7 +26,7 @@ import java.io.FileWriter;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Created by hefuyi on 2016/11/8.
|
||||
|
@ -102,7 +102,7 @@ public class LyricUtil {
|
|||
}
|
||||
|
||||
private static String getLrcOriginalPath(String filePath) {
|
||||
return filePath.replace(filePath.substring(filePath.lastIndexOf(".") + 1, filePath.length()), "lrc");
|
||||
return filePath.replace(filePath.substring(filePath.lastIndexOf(".") + 1), "lrc");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -110,16 +110,9 @@ public class LyricUtil {
|
|||
if (str == null || str.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
byte[] encode = str.getBytes("UTF-8");
|
||||
byte[] encode = str.getBytes(StandardCharsets.UTF_8);
|
||||
// base64 解密
|
||||
return new String(Base64.decode(encode, 0, encode.length, Base64.DEFAULT), "UTF-8");
|
||||
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
return new String(Base64.decode(encode, 0, encode.length, Base64.DEFAULT), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
|
|
@ -310,7 +310,7 @@ object MusicUtil : KoinComponent {
|
|||
context: Context,
|
||||
playlist: Playlist
|
||||
): Boolean {
|
||||
return playlist.name != null && playlist.name == context.getString(R.string.favorites)
|
||||
return playlist.name == context.getString(R.string.favorites)
|
||||
}
|
||||
|
||||
fun toggleFavorite(context: Context, song: Song) {
|
||||
|
@ -349,7 +349,7 @@ object MusicUtil : KoinComponent {
|
|||
BaseColumns._ID, MediaStore.MediaColumns.DATA
|
||||
)
|
||||
// Split the query into multiple batches, and merge the resulting cursors
|
||||
var batchStart = 0
|
||||
var batchStart: Int
|
||||
var batchEnd = 0
|
||||
val batchSize =
|
||||
1000000 / 10 // 10^6 being the SQLite limite on the query lenth in bytes, 10 being the max number of digits in an int, used to store the track ID
|
||||
|
|
|
@ -195,7 +195,7 @@ public class PlaylistsUtil {
|
|||
final int playlistId = songs.get(0).getPlaylistId();
|
||||
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
|
||||
"external", playlistId);
|
||||
String selectionArgs[] = new String[songs.size()];
|
||||
String[] selectionArgs = new String[songs.size()];
|
||||
for (int i = 0; i < selectionArgs.length; i++) {
|
||||
selectionArgs[i] = String.valueOf(songs.get(i).getIdInPlayList());
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ public class PlaylistsUtil {
|
|||
}
|
||||
|
||||
public static File savePlaylist(Context context, Playlist playlist) throws IOException {
|
||||
return M3UWriter.write(context, new File(Environment.getExternalStorageDirectory(), "Playlists"), playlist);
|
||||
return M3UWriter.write(new File(Environment.getExternalStorageDirectory(), "Playlists"), playlist);
|
||||
}
|
||||
|
||||
public static boolean doesPlaylistExist(@NonNull final Context context, final int playlistId) {
|
||||
|
|
|
@ -93,7 +93,7 @@ object PreferenceUtil {
|
|||
}
|
||||
}
|
||||
|
||||
val languageCode get() = sharedPreferences.getString(LANGUAGE_NAME, "auto")
|
||||
val languageCode: String get() = sharedPreferences.getString(LANGUAGE_NAME, "auto") ?: "auto"
|
||||
|
||||
var userName
|
||||
get() = sharedPreferences.getString(
|
||||
|
@ -528,7 +528,7 @@ object PreferenceUtil {
|
|||
get() {
|
||||
val folderPath = FoldersFragment.getDefaultStartDirectory().path
|
||||
val filePath: String = sharedPreferences.getStringOrDefault(START_DIRECTORY, folderPath)
|
||||
return File(filePath) ?: File(FoldersFragment.getDefaultStartDirectory().path)
|
||||
return File(filePath)
|
||||
}
|
||||
set(value) = sharedPreferences.edit {
|
||||
putString(
|
||||
|
|
|
@ -70,7 +70,7 @@ public class RetroUtil {
|
|||
}
|
||||
|
||||
public static String formatValue(float value) {
|
||||
String arr[] = {"", "K", "M", "B", "T", "P", "E"};
|
||||
String[] arr = {"", "K", "M", "B", "T", "P", "E"};
|
||||
int index = 0;
|
||||
while ((value / 1000) >= 1) {
|
||||
value = value / 1000;
|
||||
|
|
|
@ -77,7 +77,7 @@ class RingtoneManager(val context: Context) {
|
|||
return MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.dialog_title_set_ringtone)
|
||||
.setMessage(R.string.dialog_message_set_ringtone)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)
|
||||
intent.data = Uri.parse("package:" + context.applicationContext.packageName)
|
||||
context.startActivity(intent)
|
||||
|
|
|
@ -36,11 +36,62 @@ public class ImageUtils {
|
|||
private static final int ALPHA_TOLERANCE = 50;
|
||||
// Size of the smaller bitmap we're actually going to scan.
|
||||
private static final int COMPACT_BITMAP_SIZE = 64; // pixels
|
||||
private final Matrix mTempMatrix = new Matrix();
|
||||
private int[] mTempBuffer;
|
||||
private Bitmap mTempCompactBitmap;
|
||||
private Canvas mTempCompactBitmapCanvas;
|
||||
private Paint mTempCompactBitmapPaint;
|
||||
private final Matrix mTempMatrix = new Matrix();
|
||||
|
||||
/**
|
||||
* Classifies a color as grayscale or not. Grayscale here means "very close to a perfect
|
||||
* gray"; if all three channels are approximately equal, this will return true.
|
||||
* <p>
|
||||
* Note that really transparent colors are always grayscale.
|
||||
*/
|
||||
public static boolean isGrayscale(int color) {
|
||||
int alpha = 0xFF & (color >> 24);
|
||||
if (alpha < ALPHA_TOLERANCE) {
|
||||
return true;
|
||||
}
|
||||
int r = 0xFF & (color >> 16);
|
||||
int g = 0xFF & (color >> 8);
|
||||
int b = 0xFF & color;
|
||||
return Math.abs(r - g) < TOLERANCE
|
||||
&& Math.abs(r - b) < TOLERANCE
|
||||
&& Math.abs(g - b) < TOLERANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a drawable to a bitmap, scaled to fit within maxWidth and maxHeight.
|
||||
*/
|
||||
public static Bitmap buildScaledBitmap(Drawable drawable, int maxWidth,
|
||||
int maxHeight) {
|
||||
if (drawable == null) {
|
||||
return null;
|
||||
}
|
||||
int originalWidth = drawable.getIntrinsicWidth();
|
||||
int originalHeight = drawable.getIntrinsicHeight();
|
||||
if ((originalWidth <= maxWidth) && (originalHeight <= maxHeight) &&
|
||||
(drawable instanceof BitmapDrawable)) {
|
||||
return ((BitmapDrawable) drawable).getBitmap();
|
||||
}
|
||||
if (originalHeight <= 0 || originalWidth <= 0) {
|
||||
return null;
|
||||
}
|
||||
// create a new bitmap, scaling down to fit the max dimensions of
|
||||
// a large notification icon if necessary
|
||||
float ratio = Math.min((float) maxWidth / (float) originalWidth,
|
||||
(float) maxHeight / (float) originalHeight);
|
||||
ratio = Math.min(1.0f, ratio);
|
||||
int scaledWidth = (int) (ratio * originalWidth);
|
||||
int scaledHeight = (int) (ratio * originalHeight);
|
||||
Bitmap result = Bitmap.createBitmap(scaledWidth, scaledHeight, Config.ARGB_8888);
|
||||
// and paint our app bitmap on it
|
||||
Canvas canvas = new Canvas(result);
|
||||
drawable.setBounds(0, 0, scaledWidth, scaledHeight);
|
||||
drawable.draw(canvas);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect
|
||||
|
@ -93,55 +144,4 @@ public class ImageUtils {
|
|||
mTempBuffer = new int[size];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Classifies a color as grayscale or not. Grayscale here means "very close to a perfect
|
||||
* gray"; if all three channels are approximately equal, this will return true.
|
||||
* <p>
|
||||
* Note that really transparent colors are always grayscale.
|
||||
*/
|
||||
public static boolean isGrayscale(int color) {
|
||||
int alpha = 0xFF & (color >> 24);
|
||||
if (alpha < ALPHA_TOLERANCE) {
|
||||
return true;
|
||||
}
|
||||
int r = 0xFF & (color >> 16);
|
||||
int g = 0xFF & (color >> 8);
|
||||
int b = 0xFF & color;
|
||||
return Math.abs(r - g) < TOLERANCE
|
||||
&& Math.abs(r - b) < TOLERANCE
|
||||
&& Math.abs(g - b) < TOLERANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a drawable to a bitmap, scaled to fit within maxWidth and maxHeight.
|
||||
*/
|
||||
public static Bitmap buildScaledBitmap(Drawable drawable, int maxWidth,
|
||||
int maxHeight) {
|
||||
if (drawable == null) {
|
||||
return null;
|
||||
}
|
||||
int originalWidth = drawable.getIntrinsicWidth();
|
||||
int originalHeight = drawable.getIntrinsicHeight();
|
||||
if ((originalWidth <= maxWidth) && (originalHeight <= maxHeight) &&
|
||||
(drawable instanceof BitmapDrawable)) {
|
||||
return ((BitmapDrawable) drawable).getBitmap();
|
||||
}
|
||||
if (originalHeight <= 0 || originalWidth <= 0) {
|
||||
return null;
|
||||
}
|
||||
// create a new bitmap, scaling down to fit the max dimensions of
|
||||
// a large notification icon if necessary
|
||||
float ratio = Math.min((float) maxWidth / (float) originalWidth,
|
||||
(float) maxHeight / (float) originalHeight);
|
||||
ratio = Math.min(1.0f, ratio);
|
||||
int scaledWidth = (int) (ratio * originalWidth);
|
||||
int scaledHeight = (int) (ratio * originalHeight);
|
||||
Bitmap result = Bitmap.createBitmap(scaledWidth, scaledHeight, Config.ARGB_8888);
|
||||
// and paint our app bitmap on it
|
||||
Canvas canvas = new Canvas(result);
|
||||
drawable.setBounds(0, 0, scaledWidth, scaledHeight);
|
||||
drawable.draw(canvas);
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package code.name.monkey.retromusic.views
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import code.name.monkey.retromusic.extensions.accentColor
|
||||
|
||||
class AccentIcon @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = -1
|
||||
) : AppCompatImageView(context, attrs, defStyleAttr) {
|
||||
init {
|
||||
imageTintList = ColorStateList.valueOf(accentColor())
|
||||
}
|
||||
}
|
|
@ -39,7 +39,7 @@ class ColorIconsImageView @JvmOverloads constructor(
|
|||
val attributes =
|
||||
context.obtainStyledAttributes(attrs, R.styleable.ColorIconsImageView, 0, 0)
|
||||
val color =
|
||||
attributes.getColor(R.styleable.ColorIconsImageView_iconBackgroundColor, Color.RED);
|
||||
attributes.getColor(R.styleable.ColorIconsImageView_iconBackgroundColor, Color.RED)
|
||||
setIconBackgroundColor(color)
|
||||
attributes.recycle()
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ class RetroShapeableImageView @JvmOverloads constructor(
|
|||
val typedArray =
|
||||
context.obtainStyledAttributes(attrs, R.styleable.RetroShapeableImageView, defStyle, -1)
|
||||
val cornerSize =
|
||||
typedArray.getDimension(R.styleable.RetroShapeableImageView_retroCornerSize, 0f);
|
||||
typedArray.getDimension(R.styleable.RetroShapeableImageView_retroCornerSize, 0f)
|
||||
updateCornerSize(cornerSize)
|
||||
typedArray.recycle()
|
||||
}
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@color/md_white_1000"
|
||||
android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22 0.03 -1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z" />
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM7.07,18.28c0.43,-0.9 3.05,-1.78 4.93,-1.78s4.51,0.88 4.93,1.78C15.57,19.36 13.86,20 12,20s-3.57,-0.64 -4.93,-1.72zM18.36,16.83c-1.43,-1.74 -4.9,-2.33 -6.36,-2.33s-4.93,0.59 -6.36,2.33C4.62,15.49 4,13.82 4,12c0,-4.41 3.59,-8 8,-8s8,3.59 8,8c0,1.82 -0.62,3.49 -1.64,4.83zM12,6c-1.94,0 -3.5,1.56 -3.5,3.5S10.06,13 12,13s3.5,-1.56 3.5,-3.5S13.94,6 12,6zM12,11c-0.83,0 -1.5,-0.67 -1.5,-1.5S11.17,8 12,8s1.5,0.67 1.5,1.5S12.83,11 12,11z" />
|
||||
</vector>
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
app:fontProviderAuthority="com.google.android.gms.fonts"
|
||||
app:fontProviderPackage="com.google.android.gms"
|
||||
app:fontProviderQuery="Pacifico"
|
||||
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
|
||||
</font-family>
|
|
@ -87,7 +87,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:padding="0dp"
|
||||
android:textAppearance="@style/TextViewHeadline5"
|
||||
android:textAppearance="@style/TextViewHeadline6"
|
||||
android:textColor="@color/md_white_1000"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/userImage"
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:padding="0dp"
|
||||
android:textAppearance="@style/TextViewHeadline5"
|
||||
android:textAppearance="@style/TextViewHeadline6"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/userImage"
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
android:layout_height="match_parent"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
app:lrcLabel="@string/no_lyrics_found"
|
||||
app:lrcNormalTextSize="32sp"
|
||||
app:lrcPadding="16dp"
|
||||
app:lrcNormalTextSize="24sp"
|
||||
app:lrcPadding="24dp"
|
||||
app:lrcTextGravity="left"
|
||||
app:lrcTextSize="32sp" />
|
||||
app:lrcTextSize="28sp" />
|
||||
|
||||
<com.google.android.material.bottomappbar.BottomAppBar
|
||||
android:id="@+id/appBarLayout"
|
||||
|
|
|
@ -8,14 +8,17 @@
|
|||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/playAction"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:text="@string/action_play_all"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:backgroundTint="?attr/colorSurface"
|
||||
app:icon="@drawable/ic_play_arrow"
|
||||
app:cornerRadius="8dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/shuffleAction"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
@ -23,14 +26,17 @@
|
|||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/shuffleAction"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:text="@string/shuffle"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:backgroundTint="?attr/colorSurface"
|
||||
app:icon="@drawable/ic_shuffle"
|
||||
app:cornerRadius="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/playAction"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
app:layout_constraintStart_toEndOf="@id/artistImage"
|
||||
app:layout_constraintTop_toTopOf="@id/artistImage"
|
||||
tools:ignore="MissingPrefix"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
tools:text="@tools:sample/full_names" />
|
||||
|
||||
<code.name.monkey.retromusic.views.BaselineGridTextView
|
||||
android:id="@+id/albumText"
|
||||
|
@ -100,7 +100,7 @@
|
|||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="@style/TextViewHeadline6"
|
||||
android:textAppearance="@style/TextViewSubtitle1"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
@ -108,7 +108,7 @@
|
|||
app:layout_constraintTop_toBottomOf="@id/albumTitle"
|
||||
app:lineHeightHint="24sp"
|
||||
tools:ignore="MissingPrefix"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
tools:text="@tools:sample/full_names" />
|
||||
|
||||
<include
|
||||
layout="@layout/fragment_album_content"
|
||||
|
|
|
@ -8,13 +8,17 @@
|
|||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/playAction"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:text="@string/action_play_all"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:backgroundTint="?attr/colorSurface"
|
||||
app:icon="@drawable/ic_play_arrow"
|
||||
app:cornerRadius="8dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/shuffleAction"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
@ -22,13 +26,17 @@
|
|||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/shuffleAction"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:text="@string/shuffle"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:backgroundTint="?attr/colorSurface"
|
||||
app:icon="@drawable/ic_shuffle"
|
||||
app:cornerRadius="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/playAction"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:textAppearance="@style/TextViewHeadline6"
|
||||
android:textAppearance="@style/TextViewSubtitle1"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:padding="0dp"
|
||||
android:textAppearance="@style/TextViewHeadline5"
|
||||
android:textAppearance="@style/TextViewHeadline6"
|
||||
android:textColor="@color/md_white_1000"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/userImage"
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:padding="0dp"
|
||||
android:textAppearance="@style/TextViewHeadline5"
|
||||
android:textAppearance="@style/TextViewHeadline6"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/userImage"
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?colorSurface"
|
||||
android:orientation="vertical">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="0dp"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<include layout="@layout/status_bar" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/mainContent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:liftOnScroll="true">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_scrollFlags="scroll|enterAlways">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorSurface"
|
||||
app:popupTheme="?attr/toolbarPopupTheme"
|
||||
app:title="@string/app_name"
|
||||
app:titleTextAppearance="@style/ToolbarTextAppearanceNormal.Library"
|
||||
app:titleTextColor="?attr/colorControlNormal"
|
||||
tools:ignore="UnusedAttribute" />
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/cab_stub"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/toolbar_height" />
|
||||
</FrameLayout>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/fragment_container"
|
||||
android:name="code.name.monkey.retromusic.fragments.main.MainFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:defaultNavHost="true"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
app:navGraph="@navigation/main_graph" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</LinearLayout>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue