diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt index 43107430..5bb2b7ac 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt @@ -280,21 +280,21 @@ open class BugReportActivity : AbsThemeActivity() { RESULT_BAD_CREDENTIALS -> MaterialAlertDialogBuilder(context) .setTitle(R.string.bug_report_failed) .setMessage(R.string.bug_report_failed_wrong_credentials) - .setPositiveButton(R.string.ok, null) + .setPositiveButton(android.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(R.string.ok, null).show() + .setPositiveButton(android.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(R.string.ok, null) + .setPositiveButton(android.R.string.ok, null) else -> MaterialAlertDialogBuilder(context) .setTitle(R.string.bug_report_failed) .setMessage(R.string.bug_report_failed_unknown) - .setPositiveButton(R.string.ok) { _, _ -> tryToFinishActivity() } + .setPositiveButton(android.R.string.ok) { _, _ -> tryToFinishActivity() } .setNegativeButton(android.R.string.cancel) { _, _ -> tryToFinishActivity() } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt b/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt index 9c22d4da..17868e7e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt +++ b/app/src/main/java/code/name/monkey/retromusic/db/PlayCountDao.kt @@ -18,4 +18,7 @@ interface PlayCountDao { @Query("SELECT * FROM PlayCountEntity ORDER BY play_count DESC") fun playCountSongs(): List + + @Query("DELETE FROM SongEntity WHERE id =:songId") + fun deleteSong(songId: Int) } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.java index c78834bc..1e2099cc 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.java +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.java @@ -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(R.string.ok) + .positiveText(android.R.string.ok) .build(); } if (savedInstanceState == null) { diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsAsyncTask.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsAsyncTask.java deleted file mode 100644 index 5cc00d76..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsAsyncTask.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.dialogs; - -import android.app.Activity; -import android.app.Dialog; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Build; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.FragmentActivity; - -import com.google.android.material.dialog.MaterialAlertDialogBuilder; - -import java.lang.ref.WeakReference; -import java.util.Collections; -import java.util.List; - -import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.activities.saf.SAFGuideActivity; -import code.name.monkey.retromusic.misc.DialogAsyncTask; -import code.name.monkey.retromusic.model.Song; -import code.name.monkey.retromusic.util.SAFUtil; - -/** - * Created by hemanths on 2019-07-31. - */ -public class DeleteSongsAsyncTask extends DialogAsyncTask { - - private WeakReference activityWeakReference; - private WeakReference dialogReference; - - public DeleteSongsAsyncTask(@NonNull DeleteSongsDialog dialog) { - super(dialog.getActivity()); - this.dialogReference = new WeakReference<>(dialog); - this.activityWeakReference = new WeakReference<>(dialog.getActivity()); - } - - @NonNull - @Override - protected Dialog createDialog(@NonNull Context context) { - return new MaterialAlertDialogBuilder(context, - R.style.ThemeOverlay_MaterialComponents_Dialog_Alert) - .setTitle(R.string.deleting_songs) - .setView(R.layout.loading) - .setCancelable(false) - .create(); - } - - @Nullable - @Override - protected Void doInBackground(@NonNull LoadingInfo... loadingInfos) { - try { - LoadingInfo info = loadingInfos[0]; - DeleteSongsDialog dialog = this.dialogReference.get(); - FragmentActivity fragmentActivity = this.activityWeakReference.get(); - - if (dialog == null || fragmentActivity == null) { - return null; - } - - if (!info.isIntent) { - if (!SAFUtil.isSAFRequiredForSongs(info.songs)) { - dialog.deleteSongs(info.songs, null); - } else { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - if (SAFUtil.isSDCardAccessGranted(fragmentActivity)) { - dialog.deleteSongs(info.songs, null); - } else { - dialog.startActivityForResult(new Intent(fragmentActivity, SAFGuideActivity.class), - SAFGuideActivity.REQUEST_CODE_SAF_GUIDE); - } - } else { - Log.i("Hmm", "doInBackground: kitkat delete songs"); - } - } - } else { - switch (info.requestCode) { - case SAFUtil.REQUEST_SAF_PICK_TREE: - if (info.resultCode == Activity.RESULT_OK) { - SAFUtil.saveTreeUri(fragmentActivity, info.intent); - if (dialog.songsToRemove != null) { - dialog.deleteSongs(dialog.songsToRemove, null); - } - } - break; - case SAFUtil.REQUEST_SAF_PICK_FILE: - if (info.resultCode == Activity.RESULT_OK) { - dialog.deleteSongs(Collections.singletonList(dialog.currentSong), - Collections.singletonList(info.intent.getData())); - } - break; - } - } - } catch (Exception e) { - e.printStackTrace(); - } - - return null; - } - - public static class LoadingInfo { - - public Intent intent; - - public boolean isIntent; - - public int requestCode; - - public int resultCode; - - public List safUris; - - public List songs; - - public LoadingInfo(List songs, List safUris) { - this.isIntent = false; - this.songs = songs; - this.safUris = safUris; - } - - public LoadingInfo(int requestCode, int resultCode, Intent intent) { - this.isIntent = true; - this.requestCode = requestCode; - this.resultCode = resultCode; - this.intent = intent; - } - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.kt index c9fdae70..4398a6c6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeleteSongsDialog.kt @@ -1,50 +1,45 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - package code.name.monkey.retromusic.dialogs import android.app.Dialog -import android.content.Intent -import android.net.Uri import android.os.Bundle import androidx.core.text.HtmlCompat import androidx.fragment.app.DialogFragment import code.name.monkey.retromusic.EXTRA_SONG import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.activities.saf.SAFGuideActivity 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.helper.MusicPlayerRemote import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.MusicUtil -import code.name.monkey.retromusic.util.SAFUtil +import org.koin.androidx.viewmodel.ext.android.sharedViewModel class DeleteSongsDialog : DialogFragment() { - @JvmField - var currentSong: Song? = null + private val libraryViewModel by sharedViewModel() - @JvmField - var songsToRemove: List? = null + companion object { + fun create(song: Song): DeleteSongsDialog { + val list = ArrayList() + list.add(song) + return create(list) + } - private var deleteSongsAsyncTask: DeleteSongsAsyncTask? = null + fun create(songs: List): DeleteSongsDialog { + val dialog = DeleteSongsDialog() + val args = Bundle() + args.putParcelableArrayList(EXTRA_SONG, ArrayList(songs)) + dialog.arguments = args + return dialog + } + } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val songs = extraNotNull>(EXTRA_SONG).value val pair = if (songs.size > 1) { Pair( - R.string.delete_songs_title, HtmlCompat.fromHtml( + R.string.delete_songs_title, + HtmlCompat.fromHtml( String.format(getString(R.string.delete_x_songs), songs.size), HtmlCompat.FROM_HTML_MODE_LEGACY ) @@ -62,63 +57,15 @@ class DeleteSongsDialog : DialogFragment() { return materialDialog(pair.first) .setMessage(pair.second) .setCancelable(false) - .setNegativeButton(android.R.string.cancel, null) .setPositiveButton(R.string.action_delete) { _, _ -> - if ((songs.size == 1) && MusicPlayerRemote.isPlaying(songs[0])) { + if (songs.isNotEmpty() and (songs.size == 1) and MusicPlayerRemote.isPlaying(songs.first())) { MusicPlayerRemote.playNextSong() } - songsToRemove = songs - deleteSongsAsyncTask = DeleteSongsAsyncTask(this@DeleteSongsDialog) - deleteSongsAsyncTask?.execute(DeleteSongsAsyncTask.LoadingInfo(songs, null)) + MusicUtil.deleteTracks(requireActivity(), songs) + libraryViewModel.deleteTracks(songs) + } .create() .colorButtons() } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - when (requestCode) { - SAFGuideActivity.REQUEST_CODE_SAF_GUIDE -> { - SAFUtil.openTreePicker(this) - } - SAFUtil.REQUEST_SAF_PICK_TREE, - SAFUtil.REQUEST_SAF_PICK_FILE -> { - if (deleteSongsAsyncTask != null) { - deleteSongsAsyncTask?.cancel(true) - } - deleteSongsAsyncTask = DeleteSongsAsyncTask(this) - deleteSongsAsyncTask?.execute( - DeleteSongsAsyncTask.LoadingInfo( - requestCode, - resultCode, - data - ) - ) - } - } - } - - fun deleteSongs(songs: List, safUris: List?) { - MusicUtil.deleteTracks(requireActivity(), songs, safUris, Runnable { - dismiss() - }) - } - - companion object { - - fun create(song: Song): DeleteSongsDialog { - val list = ArrayList() - list.add(song) - return create(list) - } - - fun create(songs: List): DeleteSongsDialog { - val dialog = DeleteSongsDialog() - val args = Bundle() - args.putParcelableArrayList(EXTRA_SONG, ArrayList(songs)) - dialog.arguments = args - return dialog - } - } -} - +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistDialog.kt new file mode 100644 index 00000000..359ef1c5 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistDialog.kt @@ -0,0 +1,24 @@ +package code.name.monkey.retromusic.dialogs + +import android.app.Dialog +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.extensions.colorButtons +import code.name.monkey.retromusic.extensions.materialDialog +import code.name.monkey.retromusic.fragments.LibraryViewModel +import org.koin.androidx.viewmodel.ext.android.sharedViewModel + +class ImportPlaylistDialog : DialogFragment() { + private val libraryViewModel by sharedViewModel() + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return materialDialog(R.string.import_playlist) + .setMessage(R.string.import_playlist_message) + .setPositiveButton(R.string.import_label) { _, _ -> + libraryViewModel.importPlaylists() + } + .create() + .colorButtons() + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/SongDetailDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/SongDetailDialog.kt index bed9c1b7..3409b698 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/SongDetailDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/SongDetailDialog.kt @@ -144,7 +144,7 @@ class SongDetailDialog : DialogFragment() { } } return materialDialog(R.string.action_details) - .setPositiveButton(R.string.ok, null) + .setPositiveButton(android.R.string.ok, null) .setView(dialogView) .create() .colorButtons() diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt index cdee7637..e3c15fb2 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt @@ -30,12 +30,16 @@ class LibraryViewModel( val paletteColorLiveData: LiveData = paletteColor + init { + fetchHomeSections() + } + private fun loadLibraryContent() = viewModelScope.launch(IO) { + fetchHomeSections() fetchSongs() fetchAlbums() fetchArtists() fetchGenres() - fetchHomeSections() fetchPlaylists() } @@ -70,7 +74,6 @@ class LibraryViewModel( } fun getHome(): LiveData> { - fetchHomeSections() return home } @@ -132,11 +135,10 @@ class LibraryViewModel( } override fun onMediaStoreChanged() { - loadLibraryContent() println("onMediaStoreChanged") + loadLibraryContent() } - override fun onServiceConnected() { println("onServiceConnected") } @@ -204,6 +206,30 @@ class LibraryViewModel( suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long = repository.createPlaylist(playlistEntity) + fun importPlaylists() = viewModelScope.launch(IO) { + val playlists = repository.fetchLegacyPlaylist() + playlists.forEach { playlist -> + val playlistEntity = repository.checkPlaylistExists(playlist.name).firstOrNull(); + if (playlistEntity != null) { + val songEntities = playlist.getSongs().map { + it.toSongEntity(playlistEntity.playListId) + } + repository.insertSongs(songEntities) + } else { + val playListId = createPlaylist(PlaylistEntity(playlist.name)) + val songEntities = playlist.getSongs().map { + it.toSongEntity(playListId.toInt()) + } + repository.insertSongs(songEntities) + } + forceReload(Playlists) + } + } + + fun deleteTracks(songs: List) = viewModelScope.launch(IO) { + repository.deleteSongs(songs) + } + } enum class ReloadType { 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 f49876f3..086e0a09 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,19 @@ import android.os.Bundle import android.view.Menu import android.view.MenuInflater import android.view.MenuItem +import androidx.core.text.HtmlCompat import androidx.navigation.fragment.findNavController import androidx.navigation.ui.NavigationUI +import code.name.monkey.appthemehelper.ThemeStore 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.dialogs.CreatePlaylistDialog +import code.name.monkey.retromusic.dialogs.ImportPlaylistDialog import code.name.monkey.retromusic.extensions.findNavController import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import kotlinx.android.synthetic.main.fragment_library.* +import java.lang.String class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { @@ -31,6 +35,17 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { ) } setupNavigationController() + setupTitle() + } + + private fun setupTitle() { + val color = ThemeStore.accentColor(requireContext()) + val hexColor = String.format("#%06X", 0xFFFFFF and color) + val appName = HtmlCompat.fromHtml( + "Retro Music", + HtmlCompat.FROM_HTML_MODE_COMPACT + ) + appNameText.text = appName } private fun setupNavigationController() { @@ -61,7 +76,10 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { null, navOptions ) - R.id.action_import_playlist -> findNavController(R.id.fragment_container).navigate(R.id.action_import_playlist) + R.id.action_import_playlist -> ImportPlaylistDialog().show( + childFragmentManager, + "ImportPlaylist" + ) R.id.action_add_to_playlist -> CreatePlaylistDialog.create(emptyList()).show( childFragmentManager, "ShowCreatePlaylistDialog" diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt index 413edb83..533aa0f7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt @@ -20,7 +20,6 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment updateCategories(categoryAdapter.categoryInfos) } + .setPositiveButton(android.R.string.ok) { _, _ -> updateCategories(categoryAdapter.categoryInfos) } .setView(view) .create() .colorButtons() diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt index 32ca1ffe..06aff1c7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/Repository.kt @@ -96,6 +96,7 @@ interface Repository { suspend fun playCountSongs(): List suspend fun blackListPaths(): List suspend fun lyrics(artist: String, title: String): Result + suspend fun deleteSongs(songs: List) } class RealRepository( @@ -119,6 +120,8 @@ class RealRepository( Error } + override suspend fun deleteSongs(songs: List) = roomRepository.deleteSongs(songs) + override suspend fun fetchAlbums(): List = albumRepository.albums() override suspend fun albumByIdAsync(albumId: Int): Album = albumRepository.album(albumId) diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt index 8267b36a..24c9e65b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/RoomRepository.kt @@ -38,6 +38,7 @@ interface RoomRepository { suspend fun clearBlacklist() suspend fun insertBlacklistPathAsync(blackListStoreEntity: BlackListStoreEntity) suspend fun blackListPaths(): List + suspend fun deleteSongs(songs: List) } class RealRoomRepository( @@ -153,6 +154,12 @@ class RealRoomRepository( override suspend fun blackListPaths(): List = blackListStoreDao.blackListPaths() + override suspend fun deleteSongs(songs: List) { + songs.forEach { + playCountDao.deleteSong(it.id) + } + } + override suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity) = blackListStoreDao.deleteBlacklistPath(blackListStoreEntity) diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt index cbf6b4f4..41df3e29 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt @@ -155,7 +155,6 @@ class RealSongRepository(private val context: Context) : SongRepository { val uri = if (VersionUtils.hasQ()) { - MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) } else { MediaStore.Audio.Media.EXTERNAL_CONTENT_URI diff --git a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt index 8659a0ba..a29663a1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt @@ -4,11 +4,13 @@ import android.content.ContentUris import android.content.ContentValues import android.content.Context import android.content.Intent +import android.database.Cursor import android.net.Uri import android.os.Environment import android.provider.BaseColumns import android.provider.MediaStore import android.text.TextUtils +import android.util.Log import android.widget.Toast import androidx.core.content.FileProvider import androidx.fragment.app.FragmentActivity @@ -20,6 +22,7 @@ import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics import code.name.monkey.retromusic.repository.RealPlaylistRepository +import code.name.monkey.retromusic.repository.RealSongRepository import code.name.monkey.retromusic.repository.SongRepository import code.name.monkey.retromusic.service.MusicService import org.jaudiotagger.audio.AudioFileIO @@ -421,6 +424,78 @@ object MusicUtil : KoinComponent { .show() callback?.run() } + } } + + fun deleteTracks(context: Context, songs: List) { + val projection = arrayOf( + BaseColumns._ID, MediaStore.MediaColumns.DATA + ) + val selection = StringBuilder() + selection.append(BaseColumns._ID + " IN (") + for (i in songs.indices) { + selection.append(songs[i].id) + if (i < songs.size - 1) { + selection.append(",") + } + } + selection.append(")") + var deletedCount = 0 + try { + val cursor: Cursor? = context.contentResolver.query( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection.toString(), + null, null + ) + if (cursor != null) { + // Step 1: Remove selected tracks from the current playlist, as well + // as from the album art cache + cursor.moveToFirst() + while (!cursor.isAfterLast) { + val id: Int = cursor.getInt(0) + val song: Song = RealSongRepository(context).song(id) + removeFromQueue(song) + cursor.moveToNext() + } + + + // Step 2: Remove files from card + cursor.moveToFirst() + while (!cursor.isAfterLast) { + val id: Int = cursor.getInt(0) + val name: String = cursor.getString(1) + try { // File.delete can throw a security exception + val f = File(name) + if (f.delete()) { + // Step 3: Remove selected track from the database + context.contentResolver.delete( + ContentUris.withAppendedId( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + id.toLong() + ), null, null + ) + deletedCount++ + } else { + // I'm not sure if we'd ever get here (deletion would + // have to fail, but no exception thrown) + Log.e("MusicUtils", "Failed to delete file $name") + } + cursor.moveToNext() + } catch (ex: SecurityException) { + cursor.moveToNext() + } catch (e: NullPointerException) { + Log.e("MusicUtils", "Failed to find file $name") + } + } + cursor.close() + } + Toast.makeText( + context, + context.getString(R.string.deleted_x_songs, deletedCount), + Toast.LENGTH_SHORT + ).show() + } catch (ignored: SecurityException) { + } + } + } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/RingtoneManager.kt b/app/src/main/java/code/name/monkey/retromusic/util/RingtoneManager.kt index 89d98e26..00052977 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/RingtoneManager.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/RingtoneManager.kt @@ -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(R.string.ok) { _, _ -> + .setPositiveButton(android.R.string.ok) { _, _ -> val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS) intent.data = Uri.parse("package:" + context.applicationContext.packageName) context.startActivity(intent) diff --git a/app/src/main/res/layout/fragment_library.xml b/app/src/main/res/layout/fragment_library.xml index 186b93eb..59a58832 100644 --- a/app/src/main/res/layout/fragment_library.xml +++ b/app/src/main/res/layout/fragment_library.xml @@ -31,7 +31,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:text="@string/app_name" + android:id="@+id/appNameText" android:textAppearance="@style/TextViewHeadline6" android:textStyle="bold" /> diff --git a/app/src/main/res/layout/item_list_no_image.xml b/app/src/main/res/layout/item_list_no_image.xml index 456468b2..bf6ffc26 100644 --- a/app/src/main/res/layout/item_list_no_image.xml +++ b/app/src/main/res/layout/item_list_no_image.xml @@ -18,7 +18,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="2dp" - android:background="?rectSelector" + android:background="?attr/rectSelector" android:minHeight="64dp" android:padding="14dp" tools:ignore="UnusedAttribute"> diff --git a/app/src/main/res/layout/section_recycler_view.xml b/app/src/main/res/layout/section_recycler_view.xml index 4f4d6e74..a86a9cc0 100644 --- a/app/src/main/res/layout/section_recycler_view.xml +++ b/app/src/main/res/layout/section_recycler_view.xml @@ -5,8 +5,7 @@ android:id="@+id/recentArtistContainer" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical" - android:paddingBottom="12dp"> + android:orientation="vertical" > Hello blank fragment Done - Ok Import playlist + It imports all playlists listed in the Android Media Store with songs, if the playlists already exists, the songs will get merged. + Import