From 2029bbbbb6583e4bffe872db2d250287d66bd477 Mon Sep 17 00:00:00 2001 From: Daniel Rees Date: Tue, 14 May 2019 12:47:48 -0400 Subject: [PATCH 1/5] Chat example --- ChatExample/.gitignore | 13 ++ ChatExample/app/.gitignore | 1 + ChatExample/app/build.gradle | 40 ++++ ChatExample/app/proguard-rules.pro | 21 +++ .../chatexample/ExampleInstrumentedTest.kt | 24 +++ ChatExample/app/src/main/AndroidManifest.xml | 21 +++ .../github/dsrees/chatexample/MainActivity.kt | 137 ++++++++++++++ .../dsrees/chatexample/MessagesAdapter.kt | 34 ++++ .../drawable-v24/ic_launcher_foreground.xml | 34 ++++ .../res/drawable/ic_launcher_background.xml | 74 ++++++++ .../app/src/main/res/layout/activity_main.xml | 65 +++++++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2963 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4905 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2060 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2783 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4490 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6895 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6387 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10413 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9128 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15132 bytes .../app/src/main/res/values/colors.xml | 6 + .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/styles.xml | 11 ++ .../dsrees/chatexample/ExampleUnitTest.kt | 17 ++ ChatExample/build.gradle | 28 +++ ChatExample/gradle.properties | 21 +++ ChatExample/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54329 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + ChatExample/gradlew | 172 ++++++++++++++++++ ChatExample/gradlew.bat | 84 +++++++++ ChatExample/settings.gradle | 1 + 34 files changed, 823 insertions(+) create mode 100644 ChatExample/.gitignore create mode 100644 ChatExample/app/.gitignore create mode 100644 ChatExample/app/build.gradle create mode 100644 ChatExample/app/proguard-rules.pro create mode 100644 ChatExample/app/src/androidTest/java/com/github/dsrees/chatexample/ExampleInstrumentedTest.kt create mode 100644 ChatExample/app/src/main/AndroidManifest.xml create mode 100644 ChatExample/app/src/main/java/com/github/dsrees/chatexample/MainActivity.kt create mode 100644 ChatExample/app/src/main/java/com/github/dsrees/chatexample/MessagesAdapter.kt create mode 100644 ChatExample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 ChatExample/app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 ChatExample/app/src/main/res/layout/activity_main.xml create mode 100644 ChatExample/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 ChatExample/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 ChatExample/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 ChatExample/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 ChatExample/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 ChatExample/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 ChatExample/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 ChatExample/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 ChatExample/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 ChatExample/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 ChatExample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 ChatExample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 ChatExample/app/src/main/res/values/colors.xml create mode 100644 ChatExample/app/src/main/res/values/strings.xml create mode 100644 ChatExample/app/src/main/res/values/styles.xml create mode 100644 ChatExample/app/src/test/java/com/github/dsrees/chatexample/ExampleUnitTest.kt create mode 100644 ChatExample/build.gradle create mode 100644 ChatExample/gradle.properties create mode 100644 ChatExample/gradle/wrapper/gradle-wrapper.jar create mode 100644 ChatExample/gradle/wrapper/gradle-wrapper.properties create mode 100755 ChatExample/gradlew create mode 100644 ChatExample/gradlew.bat create mode 100644 ChatExample/settings.gradle diff --git a/ChatExample/.gitignore b/ChatExample/.gitignore new file mode 100644 index 0000000..2b75303 --- /dev/null +++ b/ChatExample/.gitignore @@ -0,0 +1,13 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/ChatExample/app/.gitignore b/ChatExample/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/ChatExample/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/ChatExample/app/build.gradle b/ChatExample/app/build.gradle new file mode 100644 index 0000000..2da0ec4 --- /dev/null +++ b/ChatExample/app/build.gradle @@ -0,0 +1,40 @@ +apply plugin: 'com.android.application' + +apply plugin: 'kotlin-android' + +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 28 + defaultConfig { + applicationId "com.github.dsrees.chatexample" + minSdkVersion 26 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.core:core-ktx:1.0.1' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + + implementation 'com.github.dsrees:JavaPhoenixClient:0.2.0' + + + + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + implementation 'androidx.recyclerview:recyclerview:1.0.0' +} diff --git a/ChatExample/app/proguard-rules.pro b/ChatExample/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/ChatExample/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/ChatExample/app/src/androidTest/java/com/github/dsrees/chatexample/ExampleInstrumentedTest.kt b/ChatExample/app/src/androidTest/java/com/github/dsrees/chatexample/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..5909375 --- /dev/null +++ b/ChatExample/app/src/androidTest/java/com/github/dsrees/chatexample/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.github.dsrees.chatexample + +import androidx.test.InstrumentationRegistry +import androidx.test.runner.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getTargetContext() + assertEquals("com.github.dsrees.chatexample", appContext.packageName) + } +} diff --git a/ChatExample/app/src/main/AndroidManifest.xml b/ChatExample/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..20b7abc --- /dev/null +++ b/ChatExample/app/src/main/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ChatExample/app/src/main/java/com/github/dsrees/chatexample/MainActivity.kt b/ChatExample/app/src/main/java/com/github/dsrees/chatexample/MainActivity.kt new file mode 100644 index 0000000..d573175 --- /dev/null +++ b/ChatExample/app/src/main/java/com/github/dsrees/chatexample/MainActivity.kt @@ -0,0 +1,137 @@ +package com.github.dsrees.chatexample + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.util.Log +import android.widget.ArrayAdapter +import android.widget.Button +import android.widget.EditText +import androidx.recyclerview.widget.LinearLayoutManager +import kotlinx.android.synthetic.main.activity_main.* +import org.phoenixframework.Channel +import org.phoenixframework.Socket + +class MainActivity : AppCompatActivity() { + + companion object { + const val TAG = "MainActivity" + } + + private val messagesAdapter = MessagesAdapter() + private val socket = Socket("ws://localhost:4000/socket/websocket") + private val topic = "rooms:lobby" + + private lateinit var lobbyChannel: Channel + + private val username: String + get() = username_input.text.toString() + + private val message: String + get() = message_input.text.toString() + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + + val layoutManager = LinearLayoutManager(this) + layoutManager.stackFromEnd = true + + messages_recycler_view.layoutManager = layoutManager + messages_recycler_view.adapter = messagesAdapter + + socket.onOpen { + this.addText("Socket Opened") + connect_button.text = "Disconnect" + } + + socket.onClose { + this.addText("Socket Closed") + connect_button.text = "Connect" + } + + socket.onError { throwable, response -> + Log.e(TAG, "Socket Errored $response", throwable) + this.addText("Socket Error") + } + + + connect_button.setOnClickListener { + if (socket.isConnected) { + this.disconnectAndLeave() + } else { + this.connectAndJoin() + } + } + + send_button.setOnClickListener { sendMessage() } + } + + + private fun sendMessage() { + val payload = mapOf("user" to username, "body" to message) + + message_input.text.clear() + + + this.lobbyChannel.push("new:msg", payload) + .receive("ok") { + Log.d(TAG, "success $it") + + } + .receive("error") { + Log.d(TAG, "error $it") + } + + } + + + private fun disconnectAndLeave() { + // Be sure the leave the channel or call socket.remove(lobbyChannel) + lobbyChannel.leave() + socket.disconnect { + this.addText("Socket Disconnected") + } + } + + private fun connectAndJoin() { + val channel = socket.channel(topic, mapOf("status" to "joining")) + channel.on("join") { + this.addText("You joined the room") + } + + channel.on("new:msg") { message -> + val payload = message.payload + val username = payload["user"] as? String + val body = payload["body"] as? String + + + if (username != null && body != null) { + this.addText("[$username] $body") + } + } + + channel.on("user:entered") { + this.addText("[anonymous entered]") + } + + this.lobbyChannel = channel + this.lobbyChannel + .join() + .receive("ok") { + this.addText("Joined Channel") + } + .receive("error") { + this.addText("Failed to join channel: ${it.payload}") + } + + + this.socket.connect() + } + + private fun addText(message: String) { + this.messagesAdapter.add(message) + } + +} diff --git a/ChatExample/app/src/main/java/com/github/dsrees/chatexample/MessagesAdapter.kt b/ChatExample/app/src/main/java/com/github/dsrees/chatexample/MessagesAdapter.kt new file mode 100644 index 0000000..1cce6dd --- /dev/null +++ b/ChatExample/app/src/main/java/com/github/dsrees/chatexample/MessagesAdapter.kt @@ -0,0 +1,34 @@ +package com.github.dsrees.chatexample + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView + +class MessagesAdapter : RecyclerView.Adapter() { + + private var messages: MutableList = mutableListOf() + + fun add(message: String) { + messages.add(message) + notifyItemInserted(messages.size) + } + + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val view = LayoutInflater.from(parent.context).inflate(android.R.layout.simple_list_item_1, parent, false) + return ViewHolder(view) + } + + override fun getItemCount(): Int = messages.size + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.label.text = messages[position] + } + + inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val label: TextView = itemView.findViewById(android.R.id.text1) + } + +} \ No newline at end of file diff --git a/ChatExample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/ChatExample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..6348baa --- /dev/null +++ b/ChatExample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/ChatExample/app/src/main/res/drawable/ic_launcher_background.xml b/ChatExample/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..a0ad202 --- /dev/null +++ b/ChatExample/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ChatExample/app/src/main/res/layout/activity_main.xml b/ChatExample/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..bc78d34 --- /dev/null +++ b/ChatExample/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,65 @@ + + + +