Added the ability to rename connection presets in the Android client.

This commit is contained in:
casey langen 2017-08-26 14:34:31 -07:00
parent 2e222d5f39
commit 1247348924
5 changed files with 133 additions and 25 deletions

View File

@ -20,4 +20,7 @@ public interface ConnectionsDao {
@Query("DELETE FROM Connection WHERE name=:name")
void delete(String name);
@Query("UPDATE Connection SET name=:newName WHERE name=:oldName")
void rename(String oldName, String newName);
}

View File

@ -13,17 +13,18 @@ import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.TextView
import com.uacf.taskrunner.Task
import com.uacf.taskrunner.Tasks
import io.casey.musikcube.remote.Application
import io.casey.musikcube.remote.R
import io.casey.musikcube.remote.db.connections.Connection
import io.casey.musikcube.remote.ui.extension.dialogVisible
import io.casey.musikcube.remote.ui.extension.enableUpNavigation
import io.casey.musikcube.remote.ui.extension.showDialog
import io.casey.musikcube.remote.ui.extension.*
import io.casey.musikcube.remote.websocket.WebSocketService
private val EXTRA_CONNECTION = "extra_connection"
class ConnectionsActivity : WebSocketActivityBase() {
private lateinit var recycler: RecyclerView
private lateinit var emptyText: View
@ -41,7 +42,7 @@ class ConnectionsActivity : WebSocketActivityBase() {
recycler = findViewById(R.id.recycler_view)
emptyText = findViewById(R.id.empty_text)
adapter = Adapter(itemClickListener)
adapter = Adapter(itemClickListener, itemLongClickListener)
val layoutManager = LinearLayoutManager(this)
recycler.layoutManager = layoutManager
recycler.addItemDecoration(DividerItemDecoration(this, layoutManager.orientation))
@ -60,10 +61,14 @@ class ConnectionsActivity : WebSocketActivityBase() {
get() = null
override fun onTaskCompleted(taskName: String, taskId: Long, task: Task<*, *>, result: Any) {
if (taskName == LoadTask.NAME || taskName == DeleteTask.NAME) {
adapter.items = (result!! as List<Connection>)
adapter.notifyDataSetChanged()
updateViewState()
when (taskName) {
LoadTask.NAME,
DeleteTask.NAME,
RenameTask.NAME -> {
adapter.items = (result!! as List<Connection>)
adapter.notifyDataSetChanged()
updateViewState()
}
}
}
@ -73,14 +78,18 @@ class ConnectionsActivity : WebSocketActivityBase() {
emptyText.visibility = if (count == 0) View.VISIBLE else View.GONE
}
fun onConfirmDelete(connection: Connection) {
fun rename(connection: Connection, name: String) {
runner.run(RenameTask.NAME, RenameTask(connection, name))
}
fun delete(connection: Connection) {
runner.run(DeleteTask.NAME, DeleteTask(connection))
}
private val itemClickListener: (View) -> Unit = { view: View ->
val connection = view.tag as Connection
if (view.id == R.id.button_del) {
if (!dialogVisible(ConfirmDeleteDialog.EXTRA_CONNECTION)) {
if (!dialogVisible(ConfirmDeleteDialog.TAG)) {
showDialog(ConfirmDeleteDialog.newInstance(connection), ConfirmDeleteDialog.TAG)
}
}
@ -91,6 +100,13 @@ class ConnectionsActivity : WebSocketActivityBase() {
}
}
private val itemLongClickListener: (View) -> Boolean = { view: View ->
if (!dialogVisible(RenameDialog.TAG)) {
showDialog(RenameDialog.newInstance(view.tag as Connection), RenameDialog.TAG)
}
true
}
companion object {
val EXTRA_SELECTED_CONNECTION = "extra_selected_connection"
fun getStartIntent(context: Context): Intent {
@ -99,14 +115,19 @@ class ConnectionsActivity : WebSocketActivityBase() {
}
}
private class ViewHolder(itemView: View, listener: (View) -> Unit) : RecyclerView.ViewHolder(itemView) {
private class ViewHolder(itemView: View,
clickListener: (View) -> Unit,
longClickListener: (View) -> Boolean)
: RecyclerView.ViewHolder(itemView)
{
var name: TextView = itemView.findViewById(R.id.name)
var address: TextView = itemView.findViewById(R.id.hostname)
var delete: TextView = itemView.findViewById(R.id.button_del)
init {
itemView.setOnClickListener(listener)
delete.setOnClickListener(listener)
itemView.setOnClickListener(clickListener)
itemView.setOnLongClickListener(longClickListener)
delete.setOnClickListener(clickListener)
}
fun rebind(connection: Connection) {
@ -117,7 +138,10 @@ private class ViewHolder(itemView: View, listener: (View) -> Unit) : RecyclerVie
}
}
private class Adapter(val listener: (View) -> Unit) : RecyclerView.Adapter<ViewHolder>() {
private class Adapter(val clickListener: (View) -> Unit,
val longClickListener: (View) -> Boolean)
: RecyclerView.Adapter<ViewHolder>()
{
var items = listOf<Connection>()
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
@ -128,7 +152,7 @@ private class Adapter(val listener: (View) -> Unit) : RecyclerView.Adapter<ViewH
val view = LayoutInflater.from(parent?.context)
.inflate(R.layout.connection_row, parent, false)
return ViewHolder(view, listener)
return ViewHolder(view, clickListener, longClickListener)
}
override fun getItemCount(): Int {
@ -158,6 +182,20 @@ private class DeleteTask(val connection: Connection) : Tasks.Blocking<List<Conne
}
}
private class RenameTask(val connection: Connection, val name:String)
: Tasks.Blocking<List<Connection>, Exception>()
{
override fun exec(context: Context?): List<Connection> {
val dao = Application.connectionsDb?.connectionsDao()!!
dao.rename(connection.name, name)
return dao.query()
}
companion object {
val NAME = "RenameTask"
}
}
class ConfirmDeleteDialog : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val connection = arguments.getParcelable<Connection>(EXTRA_CONNECTION)
@ -168,7 +206,7 @@ class ConfirmDeleteDialog : DialogFragment() {
.setMessage(message)
.setNegativeButton(R.string.button_no, null)
.setPositiveButton(R.string.button_yes) { _, _ ->
(activity as ConnectionsActivity).onConfirmDelete(connection)
(activity as ConnectionsActivity).delete(connection)
}
.create()
@ -178,7 +216,6 @@ class ConfirmDeleteDialog : DialogFragment() {
companion object {
val TAG = "confirm_delete_dialog"
val EXTRA_CONNECTION = "extra_connection"
fun newInstance(connection: Connection): ConfirmDeleteDialog {
val result = ConfirmDeleteDialog()
result.arguments = Bundle()
@ -186,4 +223,51 @@ class ConfirmDeleteDialog : DialogFragment() {
return result
}
}
}
class RenameDialog : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val connection = arguments.getParcelable<Connection>(EXTRA_CONNECTION)
val inflater = LayoutInflater.from(context)
val view = inflater.inflate(R.layout.dialog_edit, null)
val edit = view.findViewById<EditText>(R.id.edit)
edit.setText(connection.name)
edit.selectAll()
val dlg = AlertDialog.Builder(activity)
.setTitle(R.string.settings_save_as_title)
.setNegativeButton(R.string.button_cancel, null)
.setPositiveButton(R.string.button_save) { _, _ ->
val name = edit.text.toString()
(activity as ConnectionsActivity).rename(connection, name)
}
.create()
dlg.setView(view)
dlg.setCancelable(false)
return dlg
}
override fun onResume() {
super.onResume()
showKeyboard()
}
override fun onPause() {
super.onPause()
hideKeyboard()
}
companion object {
val TAG = "rename_dialog"
fun newInstance(connection: Connection): RenameDialog {
val result = RenameDialog()
result.arguments = Bundle()
result.arguments.putParcelable(EXTRA_CONNECTION, connection)
return result
}
}
}

View File

@ -52,6 +52,10 @@ class SettingsActivity : WebSocketActivityBase() {
rebindUi()
}
override fun onPause() {
super.onPause()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.settings_menu, menu)
return true
@ -423,12 +427,12 @@ class SettingsActivity : WebSocketActivityBase() {
override fun onResume() {
super.onResume()
(activity as SettingsActivity).showKeyboard()
showKeyboard()
}
override fun onPause() {
super.onPause()
(activity as SettingsActivity).hideKeyboard()
hideKeyboard()
}
companion object {

View File

@ -13,6 +13,7 @@ import com.uacf.taskrunner.Task
import io.casey.musikcube.remote.Application
import io.casey.musikcube.remote.playback.PlaybackService
import io.casey.musikcube.remote.playback.PlaybackServiceFactory
import io.casey.musikcube.remote.ui.extension.hideKeyboard
import io.casey.musikcube.remote.websocket.Prefs
import io.casey.musikcube.remote.websocket.WebSocketService
import javax.inject.Inject
@ -34,6 +35,8 @@ abstract class WebSocketActivityBase : AppCompatActivity(), Runner.TaskCallbacks
}
override fun onPause() {
hideKeyboard()
super.onPause()
runnerDelegate.onPause()

View File

@ -143,17 +143,31 @@ fun AppCompatActivity.dpToPx(dp: Float): Float {
return dp * this.resources.displayMetrics.density
}
fun AppCompatActivity.showKeyboard() {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
fun showKeyboard(context: Context) {
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY)
}
fun hideKeyboard(context: Context, view: View) {
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
fun AppCompatActivity.showKeyboard() {
showKeyboard(this)
}
fun AppCompatActivity.hideKeyboard(view: View? = null) {
val v = view ?: this.findViewById(android.R.id.content)
if (v != null) {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(v.windowToken, 0)
}
hideKeyboard(this, v)
}
fun DialogFragment.showKeyboard() {
showKeyboard(activity)
}
fun DialogFragment.hideKeyboard() {
hideKeyboard(activity, activity.findViewById(android.R.id.content))
}
fun AppCompatActivity.dialogVisible(tag: String): Boolean {