diff --git a/app/build.gradle b/app/build.gradle index 3f4414d0..cac506dd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -162,7 +162,6 @@ dependencies { implementation 'com.google.android.play:core:1.8.0' implementation 'me.jorgecastillo:androidcolorx:0.2.0' - debugImplementation 'com.amitshekhar.android:debug-db:1.0.4' implementation 'com.github.dhaval2404:imagepicker:1.7.1' def koin_version = "2.1.5" @@ -177,4 +176,9 @@ dependencies { implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" implementation "androidx.navigation:navigation-ui-ktx:$nav_version" + def room_version = "2.2.5" + 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' } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/App.kt b/app/src/main/java/code/name/monkey/retromusic/App.kt index de916793..a4caf9d1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/App.kt +++ b/app/src/main/java/code/name/monkey/retromusic/App.kt @@ -20,6 +20,7 @@ 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 @@ -32,7 +33,7 @@ class App : MultiDexApplication() { override fun onCreate() { super.onCreate() instance = this - + DebugDB.getAddressLog(); startKoin { androidContext(this@App) modules(appModules) diff --git a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt index f1e52df6..f884f1fa 100644 --- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -1,5 +1,6 @@ package code.name.monkey.retromusic +import code.name.monkey.retromusic.db.PlaylistDatabase import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.albums.AlbumDetailsViewModel import code.name.monkey.retromusic.fragments.artists.ArtistDetailsViewModel @@ -65,6 +66,10 @@ private val dataModule = module { single { androidContext().contentResolver } + + single { + PlaylistDatabase.getDatabase(get()) + } } private val viewModules = module { diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt index 16491acc..87791f4a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt @@ -10,6 +10,7 @@ import android.view.View import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.* import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity +import code.name.monkey.retromusic.db.PlaylistDatabase import code.name.monkey.retromusic.extensions.findNavController import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.helper.MusicPlayerRemote.openAndShuffleQueue @@ -25,6 +26,7 @@ import code.name.monkey.retromusic.util.AppRater.appLaunched import code.name.monkey.retromusic.util.PreferenceUtil import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import org.koin.android.ext.android.get import org.koin.android.ext.android.inject import java.util.* @@ -55,6 +57,12 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis appLaunched(this) addMusicServiceEventListener(libraryViewModel) updateTabs() + + val database: PlaylistDatabase = get() + lifecycleScope.launch { + println("Size:${database.playlistDao().playlistsWithSong()}") + } + } override fun onSupportNavigateUp(): Boolean = diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt new file mode 100644 index 00000000..7c595b3c --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDao.kt @@ -0,0 +1,19 @@ +package code.name.monkey.retromusic.db + +import androidx.room.* + +@Dao +interface PlaylistDao { + @Insert + suspend fun createPlaylist(playlistEntity: PlaylistEntity) + + @Query("SELECT * FROM PlaylistEntity") + suspend fun playlists(): List + + @Transaction + @Query("SELECT * FROM PlaylistEntity") + suspend fun playlistsWithSong(): List + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertSongs(songEntities: List) +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDatabase.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDatabase.kt new file mode 100644 index 00000000..582c705a --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistDatabase.kt @@ -0,0 +1,34 @@ +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 = 4, + 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 + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistEntity.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistEntity.kt new file mode 100644 index 00000000..7a490564 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistEntity.kt @@ -0,0 +1,15 @@ +package code.name.monkey.retromusic.db + +import android.os.Parcelable +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import kotlinx.android.parcel.Parcelize + +@Entity +@Parcelize +class PlaylistEntity( + @PrimaryKey + @ColumnInfo(name = "playlist_name") + val playlistName: String +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt new file mode 100644 index 00000000..c47fac08 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlaylistWithSongs.kt @@ -0,0 +1,12 @@ +package code.name.monkey.retromusic.db + +import androidx.room.Embedded +import androidx.room.Relation + +data class PlaylistWithSongs( + @Embedded val playlistEntity: PlaylistEntity, + @Relation( + parentColumn = "playlist_name", + entityColumn = "playlist_creator_name" + ) val songs: List +) \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt b/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt new file mode 100644 index 00000000..94477b4d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/db/RoomPlaylistRepository.kt @@ -0,0 +1,9 @@ +package code.name.monkey.retromusic.db + +import androidx.annotation.WorkerThread + +class RoomPlaylistRepository(private val playlistDao: PlaylistDao) { + + @WorkerThread + suspend fun getPlaylistWithSongs(): List = playlistDao.playlistsWithSong() +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt new file mode 100644 index 00000000..3f492fc4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/db/SongEntity.kt @@ -0,0 +1,17 @@ +package code.name.monkey.retromusic.db + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity +class SongEntity( + @ColumnInfo(name = "song_id") + val songId: Int, + @ColumnInfo(name = "playlist_creator_name") + val playlistCreatorName: String +) { + @PrimaryKey(autoGenerate = true) + @ColumnInfo(name = "song_key") + var songPrimaryKey: Long = 0 +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt new file mode 100644 index 00000000..b731c198 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToRetroPlaylist.kt @@ -0,0 +1,63 @@ +package code.name.monkey.retromusic.dialogs + +import android.app.Dialog +import android.os.Bundle +import androidx.core.os.bundleOf +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.lifecycleScope +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.db.PlaylistDatabase +import code.name.monkey.retromusic.db.PlaylistEntity +import code.name.monkey.retromusic.db.SongEntity +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.model.Song +import code.name.monkey.retromusic.repository.RealSongRepository +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.koin.android.ext.android.get + +class AddToRetroPlaylist : DialogFragment() { + companion object { + fun getInstance(playlistName: List): AddToRetroPlaylist { + return AddToRetroPlaylist().apply { + arguments = bundleOf("playlist_names" to playlistName) + } + } + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val playlistEntities = extraNotNull>("playlist_names").value + val playlistNames = mutableListOf() + playlistNames.add(requireContext().resources.getString(R.string.action_new_playlist)) + for (p in playlistEntities) { + playlistNames.add(p.playlistName) + } + return materialDialog(R.string.add_playlist_title) + .setItems(playlistNames.toTypedArray()) { _, which -> + val songs = RealSongRepository(requireContext()).songs() + println(songs.size) + if (which == 0) { + CreateRetroPlaylist().show(requireActivity().supportFragmentManager, "Dialog") + } else { + lifecycleScope.launch(Dispatchers.IO) { + println(Thread.currentThread().name) + val database: PlaylistDatabase = get() + val songEntities = songs.withPlaylistIds(playlistEntities[which - 1]) + database.playlistDao().insertSongs(songEntities) + } + } + dismiss() + } + .create().colorButtons() + } +} + +private fun List.withPlaylistIds(playlistEntity: PlaylistEntity): List { + val songEntities = map { + SongEntity(it.id, playlistEntity.playlistName) + } + println(songEntities.size) + return songEntities +} diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt new file mode 100644 index 00000000..c7d9fad0 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreateRetroPlaylist.kt @@ -0,0 +1,43 @@ +package code.name.monkey.retromusic.dialogs + +import android.app.Dialog +import android.os.Bundle +import android.text.TextUtils +import android.view.LayoutInflater +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.lifecycleScope +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.db.PlaylistDatabase +import code.name.monkey.retromusic.db.PlaylistEntity +import code.name.monkey.retromusic.extensions.colorButtons +import code.name.monkey.retromusic.extensions.materialDialog +import com.google.android.material.textfield.TextInputEditText +import com.google.android.material.textfield.TextInputLayout +import kotlinx.android.synthetic.main.dialog_playlist.view.* +import kotlinx.coroutines.launch +import org.koin.android.ext.android.get + +class CreateRetroPlaylist : DialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val view = LayoutInflater.from(requireActivity()).inflate(R.layout.dialog_playlist, null) + val playlistView: TextInputEditText = view.actionNewPlaylist + val playlistContainer: TextInputLayout = view.actionNewPlaylistContainer + return materialDialog(R.string.new_playlist_title) + .setView(view) + .setPositiveButton( + R.string.create_action + ) { _, _ -> + val playlistName = playlistView.text.toString() + if (!TextUtils.isEmpty(playlistName)) { + val database: PlaylistDatabase = get() + lifecycleScope.launch { + database.playlistDao().createPlaylist(PlaylistEntity(playlistName)) + } + } else { + playlistContainer.error = "Playlist is can't be empty" + } + } + .create() + .colorButtons() + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt index 41d40f09..162133d1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt @@ -4,15 +4,20 @@ import android.os.Bundle import android.view.Menu import android.view.MenuInflater import android.view.MenuItem +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.ui.NavigationUI import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.db.PlaylistDatabase +import code.name.monkey.retromusic.dialogs.AddToRetroPlaylist import code.name.monkey.retromusic.extensions.findNavController import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import com.google.android.material.appbar.AppBarLayout import kotlinx.android.synthetic.main.fragment_library.* +import kotlinx.coroutines.launch +import org.koin.android.ext.android.get class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { @@ -55,11 +60,19 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.action_settings -> findNavController().navigate( - R.id.settingsActivity, - null, - navOptions - ) + R.id.action_settings -> + //CreateRetroPlaylist().show(childFragmentManager, "Dialog") + lifecycleScope.launch { + val database = get() + AddToRetroPlaylist.getInstance(database.playlistDao().playlists()) + .show(childFragmentManager, "PlaylistDialog") + } + + /*findNavController().navigate( + R.id.settingsActivity, + null, + navOptions + )*/ } return super.onOptionsItemSelected(item) }