Added a bunch of annoying scaffholding for saving and showing connection

presets. Still some work to go.
This commit is contained in:
casey langen 2017-08-22 00:47:23 -07:00
parent 525fed1035
commit b04edf6a2e
16 changed files with 248 additions and 26 deletions

View File

@ -56,8 +56,9 @@
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize" />
<activity android:name=".ui.activity.ConnectionsActivity"
android:screenOrientation="portrait"
<activity
android:name=".ui.activity.ConnectionsActivity"
android:label="@string/connections_title"
android:windowSoftInputMode="adjustResize" />
<service android:name=".playback.SystemService">

View File

@ -3,10 +3,11 @@ package io.casey.musikcube.remote
import android.arch.persistence.room.Room
import com.crashlytics.android.Crashlytics
import com.facebook.stetho.Stetho
import io.casey.musikcube.remote.db.connections.ConnectionsDb
import io.casey.musikcube.remote.db.offline.OfflineDb
import io.casey.musikcube.remote.injection.DaggerMainComponent
import io.casey.musikcube.remote.injection.MainComponent
import io.casey.musikcube.remote.injection.MainModule
import io.casey.musikcube.remote.offline.OfflineDb
import io.casey.musikcube.remote.playback.StreamProxy
import io.casey.musikcube.remote.util.NetworkUtil
import io.fabric.sdk.android.Fabric
@ -33,6 +34,11 @@ class Application : android.app.Application() {
applicationContext,
OfflineDb::class.java,
"offline").build()
connectionsDb = Room.databaseBuilder(
applicationContext,
ConnectionsDb::class.java,
"connections").build()
}
companion object {
@ -43,5 +49,8 @@ class Application : android.app.Application() {
var offlineDb: OfflineDb? = null
private set
var connectionsDb: ConnectionsDb? = null
private set
}
}

View File

@ -0,0 +1,15 @@
package io.casey.musikcube.remote.db.connections
import android.arch.persistence.room.Entity
import android.arch.persistence.room.PrimaryKey
@Entity
class Connection {
@PrimaryKey var name: String = ""
var hostname: String = ""
var password: String = ""
var httpPort: Int = 7905
var wssPort: Int = 7906
var ssl: Boolean = false
var noValidate: Boolean = true
}

View File

@ -0,0 +1,20 @@
package io.casey.musikcube.remote.db.connections;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.OnConflictStrategy;
import android.arch.persistence.room.Query;
import java.util.List;
@Dao
public interface ConnectionsDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertConnection(Connection... connections);
@Query("SELECT * FROM Connection ORDER BY LOWER(name)")
List<Connection> queryConnections();
@Query("SELECT * FROM Connection WHERE name=:name")
Connection queryConnection(String name);
}

View File

@ -0,0 +1,9 @@
package io.casey.musikcube.remote.db.connections
import android.arch.persistence.room.Database
import android.arch.persistence.room.RoomDatabase
@Database(entities = arrayOf(Connection::class), version = 1)
abstract class ConnectionsDb : RoomDatabase() {
abstract fun connectionsDao(): ConnectionsDao
}

View File

@ -1,4 +1,4 @@
package io.casey.musikcube.remote.offline
package io.casey.musikcube.remote.db.offline
import android.arch.persistence.room.Database
import android.arch.persistence.room.RoomDatabase

View File

@ -1,4 +1,4 @@
package io.casey.musikcube.remote.offline
package io.casey.musikcube.remote.db.offline
import android.arch.persistence.room.Entity
import android.arch.persistence.room.PrimaryKey

View File

@ -1,4 +1,4 @@
package io.casey.musikcube.remote.offline;
package io.casey.musikcube.remote.db.offline;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Insert;

View File

@ -2,7 +2,7 @@ package io.casey.musikcube.remote.injection
import dagger.Component
import io.casey.musikcube.remote.MainActivity
import io.casey.musikcube.remote.offline.OfflineDb
import io.casey.musikcube.remote.db.offline.OfflineDb
import io.casey.musikcube.remote.playback.RemotePlaybackService
import io.casey.musikcube.remote.playback.StreamingPlaybackService
import io.casey.musikcube.remote.ui.activity.*

View File

@ -1,7 +1,7 @@
package io.casey.musikcube.remote.playback
import io.casey.musikcube.remote.Application
import io.casey.musikcube.remote.offline.OfflineTrack
import io.casey.musikcube.remote.db.offline.OfflineTrack
import io.casey.musikcube.remote.util.Preconditions
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers

View File

@ -1,16 +1,93 @@
package io.casey.musikcube.remote.ui.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
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.websocket.WebSocketService
/**
* Created by casey on 8/21/2017.
*/
class ConnectionsActivity : WebSocketActivityBase() {
private lateinit var recycler: RecyclerView
private lateinit var adapter: Adapter
class ConnectionsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
Application.mainComponent.inject(this);
Application.mainComponent.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_conneections)
recycler = findViewById(R.id.recycler_view)
recycler.layoutManager = LinearLayoutManager(this)
adapter = Adapter()
recycler.adapter = adapter
}
override fun onResume() {
super.onResume()
runner.run(LoadTask.NAME, LoadTask())
}
override val webSocketServiceClient: WebSocketService.Client?
get() = null
override val playbackServiceEventListener: (() -> Unit)?
get() = null
override fun onTaskCompleted(taskName: String, taskId: Long, task: Task<*, *>, result: Any) {
if (taskName == LoadTask.NAME) {
adapter.items = (result!! as List<Connection>)
adapter.notifyDataSetChanged()
}
}
companion object {
fun getStartIntent(context: Context): Intent {
return Intent(context, ConnectionsActivity::class.java)
}
}
}
private class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var name: TextView = itemView.findViewById(R.id.name)
var address: TextView = itemView.findViewById(R.id.hostname)
fun rebind(connection: Connection) {
name.text = connection.name
address.text = connection.hostname
}
}
private class Adapter : RecyclerView.Adapter<ViewHolder>() {
var items = listOf<Connection>()
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
holder?.rebind(items[position])
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(parent?.context)
.inflate(R.layout.connection_row, parent, false))
}
override fun getItemCount(): Int {
return items.size
}
}
private class LoadTask : Tasks.Blocking<List<Connection>, Exception>() {
override fun exec(context: Context?): List<Connection> {
return Application.connectionsDb?.connectionsDao()?.queryConnections()!!
}
companion object {
val NAME = "LoadTask"
}
}

View File

@ -8,12 +8,13 @@ import android.net.Uri
import android.os.Bundle
import android.support.v4.app.DialogFragment
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
import android.widget.*
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.playback.PlayerWrapper
import io.casey.musikcube.remote.playback.StreamProxy
import io.casey.musikcube.remote.ui.extension.enableUpNavigation
@ -22,11 +23,10 @@ import io.casey.musikcube.remote.ui.extension.setTextAndMoveCursorToEnd
import io.casey.musikcube.remote.websocket.Prefs
import io.casey.musikcube.remote.websocket.WebSocketService
import java.util.*
import javax.inject.Inject
import io.casey.musikcube.remote.websocket.Prefs.Default as Defaults
import io.casey.musikcube.remote.websocket.Prefs.Key as Keys
class SettingsActivity : AppCompatActivity() {
class SettingsActivity : WebSocketActivityBase() {
private lateinit var addressText: EditText
private lateinit var portText: EditText
private lateinit var httpPortText: EditText
@ -40,8 +40,6 @@ class SettingsActivity : AppCompatActivity() {
private lateinit var cacheSpinner: Spinner
private lateinit var prefs: SharedPreferences
@Inject lateinit var wss: WebSocketService
override fun onCreate(savedInstanceState: Bundle?) {
Application.mainComponent.inject(this)
super.onCreate(savedInstanceState)
@ -58,12 +56,26 @@ class SettingsActivity : AppCompatActivity() {
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
finish()
return true
} else if (item.itemId == R.id.action_save) {
save()
return true
when (item.itemId) {
android.R.id.home -> {
finish()
return true
}
R.id.action_save -> {
save()
return true
}
R.id.action_save_as -> {
saveAs()
return true
}
R.id.action_connections -> {
startActivity(ConnectionsActivity.getStartIntent(this))
return true
}
}
return super.onOptionsItemSelected(item)
@ -158,6 +170,23 @@ class SettingsActivity : AppCompatActivity() {
this.certCheckbox = findViewById<CheckBox>(R.id.cert_validation)
}
private fun saveAs() {
try {
val connection = Connection()
connection.name = "foo"
connection.hostname = addressText.text.toString()
connection.wssPort = portText.text.toString().toInt()
connection.httpPort = httpPortText.text.toString().toInt()
connection.password = passwordText.text.toString()
connection.ssl = sslCheckbox.isChecked
connection.noValidate = certCheckbox.isChecked
runner.run("${SaveAsTask.NAME}.${connection.name}", SaveAsTask(connection))
}
catch (ex: NumberFormatException) {
/* TODO dialog */
}
}
private fun save() {
val addr = addressText.text.toString()
val port = portText.text.toString()
@ -188,6 +217,12 @@ class SettingsActivity : AppCompatActivity() {
finish()
}
override val webSocketServiceClient: WebSocketService.Client?
get() = null
override val playbackServiceEventListener: (() -> Unit)?
get() = null
class SslAlertDialog : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dlg = AlertDialog.Builder(activity)
@ -251,3 +286,19 @@ class SettingsActivity : AppCompatActivity() {
}
}
}
private class SaveAsTask : Tasks.Blocking<Unit, Exception> {
var connection: Connection
constructor(connection: Connection) {
this.connection = connection
}
override fun exec(context: Context?) {
Application.connectionsDb?.connectionsDao()?.insertConnection(connection)
}
companion object {
val NAME = "SaveAsTask"
}
}

View File

@ -1,6 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="name"/>
<TextView
android:id="@+id/hostname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="address"/>
</LinearLayout>

View File

@ -8,4 +8,14 @@
app:showAsAction="always"
android:title="@string/button_save"/>
<item
android:id="@+id/action_save_as"
app:showAsAction="never"
android:title="@string/menu_save_as"/>
<item
android:id="@+id/action_connections"
app:showAsAction="never"
android:title="@string/menu_connections"/>
</menu>

View File

@ -10,6 +10,7 @@
<string name="genres_title">genres</string>
<string name="artists_title">artists</string>
<string name="playlists_title">playlists</string>
<string name="connections_title">connections</string>
<string name="button_pause">pause</string>
<string name="button_play">play</string>
<string name="button_prev">prev</string>
@ -57,6 +58,8 @@
<string name="menu_playlists">playlists</string>
<string name="menu_remote_toggle">remote playback</string>
<string name="menu_offline_tracks">offline songs</string>
<string name="menu_save_as">save as</string>
<string name="menu_connections">connections</string>
<string name="unknown_value">&lt;unknown&gt;</string>
<string name="snackbar_streaming_enabled">switched to streaming mode</string>
<string name="snackbar_remote_enabled">switched to remote control mode</string>