History playlist add

This commit is contained in:
Hemanth S 2020-08-21 19:49:15 +05:30
parent f013cf296d
commit b22b3a627f
46 changed files with 303 additions and 220 deletions

View file

@ -53,6 +53,7 @@ object Constants {
)
const val NUMBER_OF_TOP_TRACKS = 99
}
const val HISTORY = 8
const val EXTRA_GENRE = "extra_genre"
const val EXTRA_PLAYLIST = "extra_playlist"
const val EXTRA_PLAYLIST_ID = "extra_playlist_id"

View file

@ -22,4 +22,4 @@ const val TOP_ARTISTS = 0
const val SUGGESTIONS = 5
const val FAVOURITES = 4
const val GENRES = 6
const val PLAYLISTS = 7
const val PLAYLISTS = 7

View file

@ -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(

View file

@ -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(

View file

@ -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

View file

@ -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
}

View file

@ -120,7 +120,7 @@ class OrderablePlaylistSongAdapter(
override fun onSongMenuItemClick(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_remove_from_playlist -> {
RemoveSongFromPlaylistDialog.create( song.toSongEntity(playlistId))
RemoveSongFromPlaylistDialog.create(song.toSongEntity(playlistId))
.show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
return true
}

View file

@ -0,0 +1,51 @@
package code.name.monkey.retromusic.db
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import code.name.monkey.retromusic.model.Song
@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
) {
fun toSong(): Song {
return Song(
id,
title,
trackNumber,
year,
duration,
data,
dateModified,
albumId,
albumName,
artistId,
artistName,
composer,
albumArtist
)
}
}

View file

@ -1,5 +1,6 @@
package code.name.monkey.retromusic.db
import androidx.lifecycle.LiveData
import androidx.room.*
@Dao
@ -44,4 +45,16 @@ interface PlaylistDao {
@Delete
suspend fun removeSongsFromPlaylist(songs: List<SongEntity>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun addSong(historyEntity: HistoryEntity)
@Query("SELECT * FROM HistoryEntity WHERE id = :songId LIMIT 1")
suspend fun songPresentInHistory(songId: Int): HistoryEntity?
@Update
suspend fun updateHistorySong(historyEntity: HistoryEntity)
@Query("SELECT * FROM HistoryEntity ORDER BY time_played DESC")
fun historySongs(): LiveData<List<HistoryEntity>>
}

View file

@ -13,5 +13,5 @@ data class PlaylistWithSongs(
entityColumn = "playlist_creator_id"
)
val songs: List<SongEntity>
):Parcelable
) : Parcelable

View file

@ -4,8 +4,8 @@ import androidx.room.Database
import androidx.room.RoomDatabase
@Database(
entities = [PlaylistEntity::class, SongEntity::class],
version = 8,
entities = [PlaylistEntity::class, SongEntity::class, HistoryEntity::class],
version = 16,
exportSchema = false
)
abstract class RetroDatabase : RoomDatabase() {

View file

@ -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)

View file

@ -158,7 +158,7 @@ class SleepTimerDialog : DialogFragment() {
}
}
private inner class TimerUpdater internal constructor() :
private inner class TimerUpdater() :
CountDownTimer(
PreferenceUtil.nextSleepTimerElapsedRealTime - SystemClock.elapsedRealtime(),
1000

View file

@ -54,7 +54,7 @@ fun AppCompatActivity.replaceFragment(
tag: String? = null,
addToBackStack: Boolean = false
) {
val compatActivity = this ?: return
val compatActivity = this
compatActivity.supportFragmentManager.beginTransaction()
.apply {
replace(id, fragment, tag)

View file

@ -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()
}

View file

@ -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

View file

@ -3,6 +3,7 @@ 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
@ -48,12 +49,29 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
RECENT_ALBUMS -> {
loadAlbums(R.string.recent_albums, RECENT_ALBUMS)
}
FAVOURITES -> {
loadFavorite()
}
FAVOURITES -> loadFavorite()
HISTORY -> loadHistory()
}
}
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)
lifecycleScope.launch(IO) {

View file

@ -6,6 +6,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import code.name.monkey.retromusic.db.PlaylistWithSongs
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 +16,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>()
@ -53,33 +54,33 @@ class LibraryViewModel(
}
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 +120,14 @@ 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)
}
}
}
override fun onPlayStateChanged() {

View file

@ -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()

View file

@ -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

View file

@ -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(

View file

@ -21,9 +21,9 @@ 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
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.HomeAdapter
import code.name.monkey.retromusic.extensions.findActivityNavController
@ -32,7 +32,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
@ -96,9 +95,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)
)
}

View file

@ -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.*

View file

@ -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()
}

View file

@ -31,10 +31,11 @@ class PlaylistDetailsViewModel(
loadPlaylistSongs(playlist)
}
private fun loadPlaylistSongs(playlist: PlaylistWithSongs) = viewModelScope.launch(Dispatchers.IO) {
val songs: List<Song> = realRepository.playlistSongs(playlist)
withContext(Main) { _playListSongs.postValue(songs) }
}
private fun loadPlaylistSongs(playlist: PlaylistWithSongs) =
viewModelScope.launch(Dispatchers.IO) {
val songs: List<Song> = realRepository.playlistSongs(playlist)
withContext(Main) { _playListSongs.postValue(songs) }
}
override fun onMediaStoreChanged() {
/*if (playlist !is AbsCustomPlaylist) {

View file

@ -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"

View file

@ -72,7 +72,7 @@ object PlaylistMenuHelper : KoinComponent {
return true
}
R.id.action_rename_playlist -> {
RenameRetroPlaylistDialog.create(playlistWithSongs.playlistEntity )
RenameRetroPlaylistDialog.create(playlistWithSongs.playlistEntity)
.show(activity.supportFragmentManager, "RENAME_PLAYLIST")
return true
}
@ -100,7 +100,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 {

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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);

View file

@ -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,

View file

@ -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 {

View file

@ -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;
}
/**

View file

@ -15,7 +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.HistoryEntity
import code.name.monkey.retromusic.db.PlaylistEntity
import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.db.SongEntity
@ -32,97 +34,56 @@ 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 removeSongsFromPlaylist(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)
fun historySong(): LiveData<List<HistoryEntity>>
}
class RealRepository(
@ -136,7 +97,7 @@ class RealRepository(
private val playlistRepository: PlaylistRepository,
private val searchRepository: RealSearchRepository,
private val playedTracksRepository: TopPlayedRepository,
private val roomPlaylistRepository: RoomPlaylistRepository
private val roomRepository: RoomPlaylistRepository
) : Repository {
override suspend fun allAlbums(): List<Album> = albumRepository.albums()
@ -241,7 +202,7 @@ class RealRepository(
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 {
@ -250,37 +211,49 @@ 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 removeSongsFromPlaylist(songs: List<SongEntity>) =
roomPlaylistRepository.removeSongsFromPlaylist(songs)
roomRepository.removeSongsFromPlaylist(songs)
override suspend fun removeSongFromPlaylist(songEntity: SongEntity) =
roomPlaylistRepository.removeSongFromPlaylist(songEntity)
roomRepository.removeSongFromPlaylist(songEntity)
override suspend fun deleteSongsFromPlaylist(playlists: List<PlaylistEntity>) =
roomPlaylistRepository.deleteSongsFromPlaylist(playlists)
roomRepository.deleteSongsFromPlaylist(playlists)
override suspend fun favoritePlaylist(): List<PlaylistEntity> =
roomPlaylistRepository.favoritePlaylist(context.getString(R.string.favorites))
roomRepository.favoritePlaylist(context.getString(R.string.favorites))
override suspend fun isFavoriteSong(songEntity: SongEntity): List<SongEntity> =
roomPlaylistRepository.isFavoriteSong(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 fun historySong(): LiveData<List<HistoryEntity>> =
roomRepository.historySongs()
override suspend fun suggestionsHome(): Home {
val songs =

View file

@ -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 {
@ -21,6 +20,10 @@ interface RoomPlaylistRepository {
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)
fun historySongs(): LiveData<List<HistoryEntity>>
}
class RealRoomRepository(
@ -83,4 +86,17 @@ class RealRoomRepository(
override suspend fun removeSongFromPlaylist(songEntity: SongEntity) =
playlistDao.removeSong(songEntity.playlistCreatorId, songEntity.id)
override suspend fun addSongToHistory(currentSong: Song) =
playlistDao.addSong(currentSong.toHistoryEntity(System.currentTimeMillis()))
override suspend fun songPresentInHistory(song: Song): HistoryEntity? =
playlistDao.songPresentInHistory(song.id)
override suspend fun updateHistorySong(song: Song) =
playlistDao.updateHistorySong(song.toHistoryEntity(System.currentTimeMillis()))
override fun historySongs(): LiveData<List<HistoryEntity>> {
return playlistDao.historySongs()
}
}

View file

@ -162,7 +162,6 @@ public class AutoGeneratedPlaylistBitmap {
}
;
Log.d(TAG, "getBitmapCollection: smalltime = " + (System.currentTimeMillis() - start));
if (round)
return BitmapEditor.getRoundedCornerBitmap(bitmap, bitmap.getWidth() / 40);

View file

@ -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) {

View file

@ -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
}
// yes SD-card is present
// Sorry
return isSDSupportedDevice && isSDPresent;
}
public static File safeGetCanonicalFile(File file) {

View 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");
// base64 解密
return new String(Base64.decode(encode, 0, encode.length, Base64.DEFAULT), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
byte[] encode = str.getBytes(StandardCharsets.UTF_8);
// base64 解密
return new String(Base64.decode(encode, 0, encode.length, Base64.DEFAULT), StandardCharsets.UTF_8);
}
@NonNull

View file

@ -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());
}

View file

@ -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(

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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()
}

View file

@ -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()
}

View file

@ -38,6 +38,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:layoutAnimation="@anim/layout_animation_fall_down"
android:overScrollMode="never"
android:scrollbars="none"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
@ -72,10 +73,10 @@
</LinearLayout>
<com.google.android.material.progressindicator.ProgressIndicator
android:layout_width="100dp"
android:id="@+id/progressIndicator"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
android:gravity="center" />
android:gravity="center"
android:indeterminate="true" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>