Playlist editing polish: "EDIT" button in "view playlist" toolbar, some

better error handling, toasts, and icon color updates.
This commit is contained in:
casey langen 2017-12-01 19:41:11 -08:00
parent 5796b1e46d
commit cc42d9250b
10 changed files with 116 additions and 21 deletions

View File

@ -2,6 +2,7 @@
musikcube:
* added support for Ubuntu Artsy
* added preliminary audio encoders (MP3, OGG/Vorbis)
* fixed and exposed album-level artwork. previously it was track-only.
* fixed notification icon color
@ -9,10 +10,10 @@ musikdroid:
* gapless playback (for supported media)! enable in settings > playback
engine > "ExoPlayer Gapless (experimental)"
* playlist create / rename / update / delete support
* album art is now displayed in album rows when browsing
* context menus on most screens with the ability to switch between related
content (e.g. albums by this artist, artists in this genre, etc)
* preliminary playlist creation support. more to come in the future
* added a simple "spotlight" tutorial for new users that explains switching
between remote and streaming playback modes.
* major refactor to the entire code base, including the following:

View File

@ -203,6 +203,9 @@ fun showErrorSnackbar(view: View, stringId: Int) =
fun AppCompatActivity.showErrorSnackbar(stringId: Int) =
showErrorSnackbar(this.findViewById<View>(android.R.id.content), stringId)
fun AppCompatActivity.showSnackbar(stringId: Int) =
showSnackbar(this.findViewById<View>(android.R.id.content), stringId)
fun AppCompatActivity.showSnackbar(viewId: Int, stringId: Int) =
showSnackbar(this.findViewById<View>(viewId), stringId)

View File

@ -88,7 +88,11 @@ class ItemContextMenuMixin(private val activity: AppCompatActivity,
pendingCode = -1
completion = null
}
else if (result == Activity.RESULT_OK && request == REQUEST_EDIT_PLAYLIST) {
showSnackbar(
activity.findViewById(android.R.id.content),
R.string.playlist_edit_add_success)
}
super.onActivityResult(request, result, data)
}
@ -235,7 +239,8 @@ class ItemContextMenuMixin(private val activity: AppCompatActivity,
ConfirmDeletePlaylistDialog.show(activity, this, playlistName, playlistId)
}
R.id.menu_playlist_edit -> {
activity.startActivity(EditPlaylistActivity.getStartIntent(activity, playlistName, playlistId))
activity.startActivityForResult(EditPlaylistActivity.getStartIntent(
activity, playlistName, playlistId), REQUEST_EDIT_PLAYLIST)
}
R.id.menu_playlist_rename -> {
EnterPlaylistNameDialog.showForRename(activity, this, playlistName, playlistId)
@ -548,6 +553,7 @@ class ItemContextMenuMixin(private val activity: AppCompatActivity,
}
companion object {
private val REQUEST_ADD_TO_PLAYLIST = 128
private val REQUEST_ADD_TO_PLAYLIST = 32
private val REQUEST_EDIT_PLAYLIST = 33
}
}

View File

@ -1,8 +1,11 @@
package io.casey.musikcube.remote.ui.tracks.activity
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.helper.ItemTouchHelper
import android.view.Menu
@ -12,6 +15,7 @@ import io.casey.musikcube.remote.framework.ViewModel
import io.casey.musikcube.remote.ui.shared.activity.BaseActivity
import io.casey.musikcube.remote.ui.shared.extension.setupDefaultRecyclerView
import io.casey.musikcube.remote.ui.shared.extension.showErrorSnackbar
import io.casey.musikcube.remote.ui.shared.fragment.BaseDialogFragment
import io.casey.musikcube.remote.ui.shared.mixin.DataProviderMixin
import io.casey.musikcube.remote.ui.shared.mixin.ViewModelMixin
import io.casey.musikcube.remote.ui.tracks.adapter.EditPlaylistAdapter
@ -38,6 +42,15 @@ class EditPlaylistActivity: BaseActivity() {
touchHelper.attachToRecyclerView(recycler)
adapter = EditPlaylistAdapter(viewModel, touchHelper)
setupDefaultRecyclerView(recycler, adapter)
setResult(RESULT_CANCELED)
}
override fun onBackPressed() {
if (viewModel.modified) {
ConfirmDiscardChangesDialog.show(this)
return
}
super.onBackPressed()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
@ -47,18 +60,7 @@ class EditPlaylistActivity: BaseActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.action_save) {
viewModel.save().subscribeBy(
onNext = { playlistId ->
if (playlistId != -1L) {
finish()
}
else {
showErrorSnackbar(R.string.playlist_edit_save_failed)
}
},
onError = {
showErrorSnackbar(R.string.playlist_edit_save_failed)
})
saveAndFinish()
}
return super.onOptionsItemSelected(item)
}
@ -80,6 +82,26 @@ class EditPlaylistActivity: BaseActivity() {
return EditPlaylistViewModel(intent.extras.getLong(EXTRA_PLAYLIST_ID, -1L)) as T
}
private fun saveAndFinish() {
if (viewModel.modified) {
viewModel.save().subscribeBy(
onNext = { playlistId ->
if (playlistId != -1L) {
setResult(RESULT_OK)
finish()
} else {
showErrorSnackbar(R.string.playlist_edit_save_failed)
}
},
onError = {
showErrorSnackbar(R.string.playlist_edit_save_failed)
})
}
else {
finish()
}
}
private val touchHelperCallback = object:ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP or ItemTouchHelper.DOWN,
ItemTouchHelper.LEFT)
@ -98,6 +120,31 @@ class EditPlaylistActivity: BaseActivity() {
}
}
class ConfirmDiscardChangesDialog : BaseDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val editActivity = activity as EditPlaylistActivity
val dlg = AlertDialog.Builder(activity)
.setTitle(R.string.playlist_edit_save_changes_title)
.setMessage(R.string.playlist_edit_save_changes_message)
.setNegativeButton(R.string.button_discard, { _, _ -> editActivity.finish() })
.setPositiveButton(R.string.button_save, { _, _ -> editActivity.saveAndFinish() })
.create()
return dlg
}
companion object {
val TAG = "confirm_discard_playlist_changes"
fun show(activity: AppCompatActivity) {
dismiss(activity, TAG)
val result = ConfirmDiscardChangesDialog()
result.show(activity.supportFragmentManager, TAG)
}
}
}
companion object {
private val EXTRA_PLAYLIST_ID = "extra_playlist_id"
private val EXTRA_PLAYLIST_NAME = "extra_playlist_name"

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
import io.casey.musikcube.remote.R
@ -27,7 +28,6 @@ import io.casey.musikcube.remote.util.Debouncer
import io.casey.musikcube.remote.util.Strings
import io.reactivex.Observable
import io.reactivex.rxkotlin.subscribeBy
import java.util.*
class TrackListActivity : BaseActivity(), Filterable {
private lateinit var tracks: TrackListSlidingWindow
@ -86,12 +86,31 @@ class TrackListActivity : BaseActivity(), Filterable {
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
if (Messages.Category.PLAYLISTS != categoryType) {
if (Messages.Category.PLAYLISTS == categoryType) {
menuInflater.inflate(R.menu.view_playlist_menu, menu)
}
else {
initSearchMenu(menu, this)
}
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.action_edit) {
val name = intent.getStringExtra(EXTRA_CATEGORY_VALUE)
startActivityForResult(EditPlaylistActivity.getStartIntent(
this, name, categoryId), REQUEST_CODE_EDIT_PLAYLIST)
}
return super.onOptionsItemSelected(item)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_CODE_EDIT_PLAYLIST && resultCode == RESULT_OK) {
showSnackbar(R.string.playlist_edit_save_success)
}
super.onActivityResult(requestCode, resultCode, data)
}
override fun onPause() {
super.onPause()
tracks.pause()
@ -232,6 +251,8 @@ class TrackListActivity : BaseActivity(), Filterable {
private val EXTRA_CATEGORY_TYPE = "extra_category_type"
private val EXTRA_SELECTED_ID = "extra_selected_id"
private val EXTRA_TITLE_ID = "extra_title_id"
private val EXTRA_CATEGORY_VALUE = "extra_category_value"
private val REQUEST_CODE_EDIT_PLAYLIST = 72
fun getStartIntent(context: Context, type: String, id: Long): Intent =
getStartIntent(context, type, id, "")
@ -245,6 +266,7 @@ class TrackListActivity : BaseActivity(), Filterable {
val intent = Intent(context, TrackListActivity::class.java)
.putExtra(EXTRA_CATEGORY_TYPE, type)
.putExtra(EXTRA_SELECTED_ID, id)
.putExtra(EXTRA_CATEGORY_VALUE, categoryValue)
if (Strings.notEmpty(categoryValue)) {
intent.putExtra(

View File

@ -1,4 +1,4 @@
<vector android:height="16dp" android:viewportHeight="24.0"
android:viewportWidth="24.0" android:width="16dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="?attr/colorControlNormal" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
<path android:fillColor="@color/theme_red" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>

View File

@ -4,6 +4,6 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="?attr/colorControlNormal"
android:fillColor="@color/theme_yellow"
android:pathData="M3,15h18v-2L3,13v2zM3,19h18v-2L3,17v2zM3,11h18L21,9L3,9v2zM3,5v2h18L21,5L3,5z"/>
</vector>

View File

@ -4,6 +4,6 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="?attr/colorControlNormal"
android:fillColor="@color/theme_red"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8.46,11.88l1.41,-1.41L12,12.59l2.12,-2.12 1.41,1.41L13.41,14l2.12,2.12 -1.41,1.41L12,15.41l-2.12,2.12 -1.41,-1.41L10.59,14l-2.13,-2.12zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z"/>
</vector>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_edit"
app:showAsAction="always"
android:title="@string/button_edit"/>
</menu>

View File

@ -33,6 +33,7 @@
<string name="button_repeat_list">repeat list</string>
<string name="button_repeat_track">repeat song</string>
<string name="button_save">save</string>
<string name="button_edit">edit</string>
<string name="button_create">create</string>
<string name="button_settings">settings</string>
<string name="button_close">close</string>
@ -47,6 +48,7 @@
<string name="button_save_as">save as</string>
<string name="button_load">load</string>
<string name="button_rename">rename</string>
<string name="button_discard">discard</string>
<string name="button_learn_more">learn more</string>
<string name="invalid_password_dialog_title">invalid password</string>
<string name="invalid_password_dialog_message">the server rejected your password.\n\nchange the password in the settings screen.</string>
@ -147,6 +149,9 @@
<string name="playlist_not_deleted">could not delete playlist \'%s\'</string>
<string name="playlist_edit_activity">editing playlist \'%s\'</string>
<string name="playlist_edit_save_failed">could not save playlist</string>
<string name="playlist_edit_save_success">playlist saved</string>
<string name="playlist_edit_save_changes_title">save changes?</string>
<string name="playlist_edit_save_changes_message">do you want to save the changes you made to this playlist?</string>
<string name="remove_from_playlist_dialog_title">confirm</string>
<string name="remove_from_playlist_dialog_message">are you sure you want to remove \`%s\` from this playlist?</string>
<string name="spotlight_playback_mode_title">playback mode</string>