diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
index c9ab7ca..a3378ad 100644
Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ
diff --git a/app/build.gradle b/app/build.gradle
index 83e0f6a..9835795 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -46,5 +46,6 @@ dependencies {
kapt "android.arch.lifecycle:compiler:1.1.1"
// Test helpers for LiveData
testImplementation "android.arch.core:core-testing:1.1.1"
+ // For Bubbles that contain messages in MessageListActivity; remove when I create my own bubble
implementation 'com.github.lguipeng:BubbleView:1.0.1'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7e4e2a8..1106d15 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -43,7 +43,6 @@
-
\ No newline at end of file
diff --git a/app/src/main/java/com/example/markmoussa/meshchatapplication/Conversation.kt b/app/src/main/java/com/example/markmoussa/meshchatapplication/Conversation.kt
index c54383f..9393e67 100644
--- a/app/src/main/java/com/example/markmoussa/meshchatapplication/Conversation.kt
+++ b/app/src/main/java/com/example/markmoussa/meshchatapplication/Conversation.kt
@@ -1,5 +1,6 @@
package com.example.markmoussa.meshchatapplication
+import com.hypelabs.hype.Instance
import java.util.*
/**
@@ -8,4 +9,4 @@ import java.util.*
// This version with a constructor used simply so we can generate dummy data to populate conversations
-class Conversation(val user: User?, val timeStamp: Date?, val messageList: Store?, val currentlyOnline: Boolean)
\ No newline at end of file
+class Conversation(val user: User?, val timeStamp: Date?, val messageList: Store?, val instance: Instance?, val currentlyOnline: Boolean)
\ No newline at end of file
diff --git a/app/src/main/java/com/example/markmoussa/meshchatapplication/ConversationListActivity.kt b/app/src/main/java/com/example/markmoussa/meshchatapplication/ConversationListActivity.kt
index a1aac6a..abf75cc 100644
--- a/app/src/main/java/com/example/markmoussa/meshchatapplication/ConversationListActivity.kt
+++ b/app/src/main/java/com/example/markmoussa/meshchatapplication/ConversationListActivity.kt
@@ -4,11 +4,11 @@ package com.example.markmoussa.meshchatapplication
* Created by markmoussa on 2/24/18.
*/
-import android.arch.lifecycle.Lifecycle
import android.arch.lifecycle.LifecycleObserver
-import android.arch.lifecycle.OnLifecycleEvent
import android.arch.lifecycle.ProcessLifecycleOwner
+import android.content.Context
import android.content.Intent
+import android.content.SharedPreferences
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v4.widget.SwipeRefreshLayout
@@ -25,7 +25,7 @@ import com.hypelabs.hype.Message
class ConversationListActivity : AppCompatActivity(), Store.Delegate, LifecycleObserver {
var mConversationList: MutableList = mutableListOf()
- lateinit var lifeCycleObserver: LifecycleObserverActivity
+ private lateinit var lifeCycleObserver: LifecycleObserverActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -33,13 +33,14 @@ class ConversationListActivity : AppCompatActivity(), Store.Delegate, LifecycleO
val hypeFramework = applicationContext as HypeLifeCycle
+ // This tells us
ProcessLifecycleOwner.get().lifecycle.addObserver(LifecycleObserverActivity(this).also { lifeCycleObserver = it})
populateConversationList()
var mConversationListRecycler: RecyclerView? = null
var mConversationListAdapter: ConversationListAdapter? = null
- mConversationListRecycler = findViewById(R.id.reyclerview_conversation_list)
+ mConversationListRecycler = findViewById(R.id.reyclerview_conversation_list)
mConversationListRecycler!!.layoutManager = LinearLayoutManager(this)
mConversationListAdapter = ConversationListAdapter(this, mConversationList)
mConversationListRecycler.adapter = mConversationListAdapter
@@ -49,13 +50,13 @@ class ConversationListActivity : AppCompatActivity(), Store.Delegate, LifecycleO
ItemClickSupport.addTo(mConversationListRecycler).setOnItemClickListener(object : ItemClickSupport.OnItemClickListener {
override fun onItemClicked(recyclerView: RecyclerView, position: Int, v: View) {
// when item (conversation) is clicked, go to that conversation's message list
- Log.i("TEST: ", "This is a test, item number " + position.toString() + " picked.")
+// Log.i("TEST: ", "This is a test, item number " + position.toString() + " picked.")
val userIdentifier = mConversationList[position].user?.userIdentifier
val contactStore = hypeFramework.getAllMessages()[userIdentifier]
contactStore?.delegate = this@ConversationListActivity
val intent = Intent(this@ConversationListActivity, MessageListActivity::class.java)
intent.putExtra("userIdentifier", userIdentifier)
- if(userIdentifier in hypeFramework.getAllOnlinePeers()) {
+ if(userIdentifier in hypeFramework.getOnlinePeers()) {
intent.putExtra("online", true)
} else {
intent.putExtra("online", false)
@@ -96,43 +97,60 @@ class ConversationListActivity : AppCompatActivity(), Store.Delegate, LifecycleO
}
}
- override fun onCreateOptionsMenu(menu: Menu?): Boolean {
- menuInflater.inflate(R.menu.menu_conversation_list, menu)
- return true
- }
-
- override fun onOptionsItemSelected(item: MenuItem?): Boolean {
- when(item!!.itemId) {
- R.id.newMessageMenuButton -> {
- val intent = Intent(this, NewMessageActivity::class.java)
- startActivity(intent)
- return true
- }
- else -> return super.onOptionsItemSelected(item)
+// override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+// menuInflater.inflate(R.menu.menu_conversation_list, menu)
+// return true
+// }
+//
+// override fun onOptionsItemSelected(item: MenuItem?): Boolean {
+// when(item!!.itemId) {
+// R.id.newMessageMenuButton -> {
+// val intent = Intent(this, NewMessageActivity::class.java)
+// startActivity(intent)
+// return true
+// }
+// else -> return super.onOptionsItemSelected(item)
+// }
+// }
+
+ // This function initializes conversation list for the first time.
+ // Making separate function because this one returns the list, populateConversationList
+ // modifies it (so that the changes can be detected by the adapter)
+ private fun initializeConversationList(): MutableList {
+ val hypeFramework = applicationContext as HypeLifeCycle
+ val messageList = hypeFramework.getAllMessages()
+ val contactsList = hypeFramework.getAllContacts()
+ val onlinePeers = hypeFramework.getOnlinePeers()
+ val conversationList = mutableListOf()
+ for(x in messageList) {
+ conversationList.add(Conversation(contactsList[x.key], null, x.value, if(contactsList.containsKey(x.key)) onlinePeers[x.key] else null, onlinePeers.containsKey(x.key)))
}
+ return conversationList
}
-
private fun populateConversationList() {
// creating conversations list
mConversationList.clear()
val hypeFramework = applicationContext as HypeLifeCycle
var currentlyOnline: Boolean
+ val contactsList = hypeFramework.getAllContacts()
+ val onlinePeers = hypeFramework.getOnlinePeers()
+ Log.d("ConversationListActivit", "Length of hypeFramework.getAllMessages(): ${hypeFramework.getAllMessages().size}")
for(x in hypeFramework.getAllMessages()) {
- currentlyOnline = x.key in hypeFramework.getAllOnlinePeers()
- val nickname: String?
- if(x.key in hypeFramework.getAllContacts()) {
- // I get the actual user here. Consider just passing that into the conversation instead of
- // creating a brand new one
- nickname = hypeFramework.getAllContacts()[x.key]!!.nickname
- Log.d("ConversationListActivit", "Nickname is: $nickname")
- } else {
- nickname = null
- }
- mConversationList.add(Conversation(User(nickname, null, x.key), null, x.value, currentlyOnline))
+ currentlyOnline = onlinePeers.containsKey(x.key)
+// val nickname: String?
+// if(contactsList.containsKey(x.key)) {
+// // I get the actual user here. Consider just passing that into the conversation instead of
+// // creating a brand new one
+// nickname = contactsList[x.key]!!.nickname
+//// Log.d("ConversationListActivit", "Nickname is: $nickname")
+// } else {
+// nickname = null
+// }
+ mConversationList.add(Conversation(contactsList[x.key], null, x.value, if(currentlyOnline) onlinePeers[x.key] else null, currentlyOnline))
}
// Debugging
- Log.d("ConversationListActivit", "populateConversationList() returned: ")
+// Log.d("ConversationListActivit", "populateConversationList() returned: ")
for(x in mConversationList) {
Log.d("ConversationListActivit", "User nickname: ${x.user?.nickname}, User Identifier: ${x.user?.userIdentifier}, user online: ${x.currentlyOnline}")
}
@@ -142,7 +160,7 @@ class ConversationListActivity : AppCompatActivity(), Store.Delegate, LifecycleO
// TODO: Add option to delete conversation
- override fun onMessageAdded(store: Store, message: Message) {
+ override fun onMessageAdded(store: Store, message: Pair) {
updateInterface()
}
@@ -160,6 +178,19 @@ class ConversationListActivity : AppCompatActivity(), Store.Delegate, LifecycleO
}
}
+ override fun onBackPressed() {
+ val sharedPreferences: SharedPreferences = applicationContext.getSharedPreferences("sp", Context.MODE_PRIVATE)
+ if(sharedPreferences.contains("USERNAME") && sharedPreferences.getString("USERNAME", null).isNotEmpty()) {
+ val intent = Intent(this, MainActivity::class.java)
+ intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
+ intent.putExtra("Exit me", true)
+ startActivity(intent)
+ finish()
+ } else {
+ super.onBackPressed()
+ }
+ }
+
}
diff --git a/app/src/main/java/com/example/markmoussa/meshchatapplication/ConversationListAdapter.kt b/app/src/main/java/com/example/markmoussa/meshchatapplication/ConversationListAdapter.kt
index 9a7c8c2..2a83c27 100644
--- a/app/src/main/java/com/example/markmoussa/meshchatapplication/ConversationListAdapter.kt
+++ b/app/src/main/java/com/example/markmoussa/meshchatapplication/ConversationListAdapter.kt
@@ -2,6 +2,7 @@ package com.example.markmoussa.meshchatapplication
import android.content.Context
import android.support.v7.widget.RecyclerView
+import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -57,8 +58,13 @@ class ConversationListAdapter(private val mContext: Context, private val mConver
} else {
usernameText.text = conversation.user.userIdentifier.toString()
}
- if(conversation.messageList != null) {
- messagePreviewText.text = conversation.messageList.getMessageStringAtIndex(conversation.messageList.lastReadIndex)
+ if(!(conversation.messageList?.getMessages()!!.isEmpty())) {
+
+ var messagePreview = conversation.messageList.getMessageStringAtIndex(conversation.messageList.getMessages().size - 1)
+ if(!(messagePreview.isNullOrEmpty()) && messagePreview!!.length > 40) {
+ messagePreview = messagePreview.substring(0, 33) + "..."
+ }
+ messagePreviewText.text = messagePreview
} else {
messagePreviewText.text = ""
}
@@ -66,11 +72,11 @@ class ConversationListAdapter(private val mContext: Context, private val mConver
//timeText.text = DateUtils.formatDateTime(message.getCreatedAt(), HOUR_IN_MILLIS, FORMAT_SHOW_TIME)
timestampText.text = Date().toString()
// TODO: Figure out how to pull profile pic, or if not, then what profile pic should be (if there should be one at all)
- if(conversation.user.profileUrl != null) {
+ if(conversation.user.profileUri != null) {
// do nothing
}
val hypeFramework = mContext.applicationContext as HypeLifeCycle
- if(conversation.user.userIdentifier in hypeFramework.getAllOnlinePeers()) {
+ if(conversation.user.userIdentifier in hypeFramework.getOnlinePeers()) {
onlineStatusIcon.setImageResource(android.R.drawable.presence_online)
} else {
onlineStatusIcon.setImageResource(android.R.drawable.presence_offline)
diff --git a/app/src/main/java/com/example/markmoussa/meshchatapplication/HypeLifeCycle.kt b/app/src/main/java/com/example/markmoussa/meshchatapplication/HypeLifeCycle.kt
index f3ffef2..8693d36 100644
--- a/app/src/main/java/com/example/markmoussa/meshchatapplication/HypeLifeCycle.kt
+++ b/app/src/main/java/com/example/markmoussa/meshchatapplication/HypeLifeCycle.kt
@@ -7,10 +7,6 @@ package com.example.markmoussa.meshchatapplication
import android.app.Application
import android.content.Context
import android.content.SharedPreferences
-import android.graphics.Bitmap
-import android.graphics.BitmapFactory
-import android.net.Uri
-import android.util.Base64
import android.util.Log
import com.hypelabs.hype.Error
import com.hypelabs.hype.Hype
@@ -20,10 +16,7 @@ import com.hypelabs.hype.MessageInfo
import com.hypelabs.hype.MessageObserver
import com.hypelabs.hype.NetworkObserver
import com.hypelabs.hype.StateObserver
-import org.json.JSONObject
import java.io.*
-import java.nio.charset.Charset
-import java.util.*
import kotlin.collections.HashMap
import kotlin.properties.Delegates
@@ -31,15 +24,16 @@ import kotlin.properties.Delegates
class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Application() {
// TODO: DO THIS SECOND - Figure out why these observables aren't working sometimes (such as messageDatabase in setMessageDatabase()
- // The onlinePeers object keeps track of message storage associated with each instance (peer)
- private var onlinePeers: MutableList by Delegates.observable(mutableListOf()) {
- _, _, _ -> updateOnlinePeersFile()
- }
+ // TODO: Consider merging messageDatabase and contactsDatabase (can do HashMap>)
+ // The onlinePeers object keeps track of message storage associated with each instance (peer) via their userIdentifiers
+ private var onlinePeers: HashMap = hashMapOf()
+ // The messageDatabase keeps track of the users and their previous messages via saving their userIdentifiers and a Store
private var messageDatabase: HashMap by Delegates.observable(hashMapOf()) {
_, _, _ -> updateMessageDatabase()
}
+ // contactsDatabase saves previously before seen users to save sending data back and forth via their userIdentifiers and User objects
private var contactsDatabase: HashMap by Delegates.observable(hashMapOf()) {
_, _, _ -> updateContactsDatabase()
}
@@ -56,7 +50,15 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati
// Generate an app identifier in the HypeLabs dashboard (https://hypelabs.io/apps/),
// by creating a new app. Copy the given identifier here.
+
+ // ChatApplication
Hype.setAppIdentifier("f370ac17")
+
+ // MeshNetworkApplication
+ // Hype.setAppIdentifier("9a96baaa")
+
+ // MeshNetworkApp2
+ Hype.setAppIdentifier("b056a7af")
val sharedPreferences: SharedPreferences = applicationContext.getSharedPreferences("sp", Context.MODE_PRIVATE)
val userIdentifier = sharedPreferences.getInt("USER_IDENTIFIER", Hype.DefaultUserIdentifier)
Hype.setUserIdentifier(userIdentifier)
@@ -70,10 +72,14 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati
}
override fun onHypeStart() {
+
+ // TODO: When you stop and start Hype again, for some reason the other users can't find you again
+ // it looks like this is due to Hype not having time to "lose" the instance before refinding it
+
Log.i(TAG, "Hype started!")
Log.i(TAG, "Loading store from file")
- readOnlinePeers()
- readMessageDatabase()
+ messageDatabase = readMessageDatabase()
+ contactsDatabase = readContactsDatabase()
}
override fun onHypeStop(error: Error?) {
@@ -85,7 +91,7 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati
}
Log.i(TAG, String.format("Hype stopped [%s]", description))
- readOnlinePeers()
+ onlinePeers.clear()
}
override fun onHypeFailedStarting(error: Error) {
@@ -144,10 +150,10 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati
var store = getAllMessages()[instance.userIdentifier]
if(store == null) {
- store = Store(instance)
+ store = Store(instance.userIdentifier)
}
// Storing the message triggers a reload update in the MessageList activity
- store.add(message, this)
+ store.add(Pair(message.data.toString(charset("UTF-8")), false), this)
setMessageDatabase(instance.userIdentifier, store)
}
@@ -175,7 +181,14 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati
override fun onHypeRequestAccessToken(i: Int): String {
// Access the app settings (https://hypelabs.io/apps/) to find an access token to use here.
- return "903cbdd53f59e2f771cbf2a9429c91"
+ // This one is for chatApplication
+// return "903cbdd53f59e2f771cbf2a9429c91"
+
+ // MeshNetworkApplication
+// return "4e5936b294a88cf2"
+
+ // MeshNetworkApp2
+ return "4e5936b294a88cf2"
}
override fun onCreate() {
@@ -189,14 +202,27 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati
// setting onlinePeers to read file here instead of at the top because readOnlinePeers() needs
// dirPath in order to proceed, and dirPath is still null when onlinePeers is instantiated
- onlinePeers = readOnlinePeers()
- messageDatabase = readMessageDatabase()
+// onlinePeers = readOnlinePeers()
+// messageDatabase = readMessageDatabase()
+// contactsDatabase = readContactsDatabase()
}
- fun getAllOnlinePeers(): MutableList {
+ fun getOnlinePeers(): HashMap {
return onlinePeers
}
+ // adds online peer to onlinePeers and triggers updating online peers file in memory
+ private fun setOnlinePeers(userIdentifier: Long, instance: Instance, addOrRemove: Boolean) {
+ // true = add, false = remove
+ if(addOrRemove) {
+ if(!(onlinePeers.contains(userIdentifier))) {
+ onlinePeers[userIdentifier] = instance
+ }
+ } else {
+ onlinePeers.remove(userIdentifier)
+ }
+ }
+
fun getAllMessages(): HashMap {
return messageDatabase
}
@@ -209,17 +235,7 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati
this.messageDatabase = messageDatabase
}
- // adds online peer to onlinePeers and triggers updating online peers file in memory
- private fun setAllOnlinePeers(userIdentifier: Long, addOrRemove: Boolean) {
- // true = add, false = remove
- if(addOrRemove) {
- if(!(onlinePeers.contains(userIdentifier))) {
- onlinePeers.add(userIdentifier)
- }
- } else {
- onlinePeers.remove(userIdentifier)
- }
- }
+
// adds message to store and triggers updating store file in memory
fun setMessageDatabase(userIdentifier: Long, store: Store) {
@@ -228,58 +244,35 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati
// TODO: Figure out why and delete manual call once fixed
updateMessageDatabase()
// debugging
- Log.d("HypeLifeCycle ", "new messageDatabase (from file) is: ${messageDatabase.entries.toString()}")
+ Log.d("HypeLifeCycle ", "new messageDatabase (from variable) is: ${messageDatabase.entries.toString()}")
for(x in messageDatabase.values) {
for(y in x.getMessages()) {
- Log.d("HypeLifeCycle", "Store contents (from new messageDatabase (from file)): ${y.data.toString(charset("UTF-8"))}")
+ Log.d("HypeLifeCycle", "Store contents (from new messageDatabase (from variable)): ${y.first}")
}
}
}
// adds contact to contactsDatabase and triggers updating the contacts file in memory
fun setContactsDatabase(userIdentifier: Long, user: User) {
- contactsDatabase[userIdentifier] = user
- }
+ // TODO: Hackish fix since I can't send over userIdentifier without the bytes going over its limit
+ // Fix once Hype's SDK allows for greater than 255 bytes sent on announcement
+ val newUser = User(user.nickname, user.profileUri, userIdentifier)
+ contactsDatabase[userIdentifier] = newUser
- private fun readOnlinePeers(): MutableList {
- val storeFile = File(dirPath, "storeFile")
- if(!(storeFile.exists()) || storeFile.length() == 0.toLong()) {
- storeFile.createNewFile()
- return mutableListOf()
- } else {
- try {
- val fis = FileInputStream(storeFile)
- val ois = ObjectInputStream(fis)
- val result: MutableList = ois.readObject() as MutableList
- ois.close()
- Log.d("HypeLifeCycle: ", "readOnlinePeers() returned: " + result.toString())
- return result
- } catch (e: Exception) {
- e.printStackTrace()
- }
- }
- return mutableListOf()
- }
-
- fun updateOnlinePeersFile() {
- try {
- val storeFile = File(dirPath, "storeFile")
- if(!(storeFile.exists())) {
- storeFile.createNewFile()
- }
- val fos = FileOutputStream(storeFile)
- val oos = ObjectOutputStream(fos)
- oos.writeObject(onlinePeers)
- oos.close()
- } catch(e: Exception) {
- e.printStackTrace()
- }
+ // TODO: For some reason, observable delegate not calling updateContactsDatabase() when message database is changed
+ // TODO: Figure out why and delete manual call once fixed
+ updateContactsDatabase()
}
private fun readMessageDatabase(): HashMap {
val messageDatabaseFile = File(dirPath, "messageDatabase")
if(!(messageDatabaseFile.exists()) || messageDatabaseFile.length() == 0.toLong()) {
messageDatabaseFile.createNewFile()
+ if(!(messageDatabaseFile.exists())) {
+ Log.d("HypeLifeCycle", "File for message database does not exist; creating new one (from read)")
+ } else {
+ Log.d("HypeLifeCycle", "messageDatabaseFile.length() == 0")
+ }
return hashMapOf()
} else {
try {
@@ -287,11 +280,13 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati
val ois = ObjectInputStream(fis)
val result = ois.readObject() as HashMap
ois.close()
+
// debugging
Log.d("HypeLifeCycle ", "reading messageDatabase (from file) is: ${result.entries.toString()}")
+
for(x in result.values) {
for(y in x.getMessages()) {
- Log.d("HypeLifeCycle", "Store contents (from reading messageDatabase (from file)): ${y.data.toString(charset("UTF-8"))}")
+ Log.d("HypeLifeCycle", "Store contents (from reading messageDatabase (from file)): ${y.first}")
}
}
return result
@@ -310,16 +305,23 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati
val messageDatabaseFile = File(dirPath, "messageDatabase")
if(!(messageDatabaseFile.exists())) {
messageDatabaseFile.createNewFile()
+ Log.d("HypeLifeCycle", "File for message database does not exist; creating new one (from update)")
}
- // TODO: DO THIS FIRST - figure out how to serialize messageDatabase
- // TODO: since Instance from Hype SDK not serializable, it won't let me serialize all of messageDatabase
- // by that logic, I should probably check up on contactsDatabase as well
+ // since Instance from Hype SDK not serializable, it won't let me serialize all of messageDatabase
val fos = FileOutputStream(messageDatabaseFile)
val oos = ObjectOutputStream(fos)
oos.writeObject(messageDatabase)
// debugging
Log.d("HypeLifeCycle", "Right after writing the file, the new file is: ${readMessageDatabase()}")
oos.close()
+
+ // Checking if the file is empty, meaning the messageDatabase didn't write properly
+ // debugging
+ if(messageDatabaseFile.length() == 0.toLong()) {
+ Log.d("HypeLifeCycle", "The messageDatabaseFile is still empty after writing; this means there's a problem in updateMessageDatabase()")
+ }
+ oos.close()
+
} catch(e: Exception) {
e.printStackTrace()
}
@@ -329,6 +331,7 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati
val contactsFile = File(dirPath, "contactsFile")
if(!(contactsFile.exists()) || contactsFile.length() == 0.toLong()) {
contactsFile.createNewFile()
+ Log.d("HypeLifeCycle", "File for contacts database does not exist; creating new one (from read)")
return hashMapOf()
} else {
try {
@@ -350,10 +353,12 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati
val contactsFile = File(dirPath, "contactsFile")
if(!(contactsFile.exists())) {
contactsFile.createNewFile()
+ Log.d("HypeLifeCycle", "File for contacts database does not exist; creating new one (from update)")
}
val fos = FileOutputStream(contactsFile)
val oos = ObjectOutputStream(fos)
oos.writeObject(contactsDatabase)
+ Log.d("HypeLifeCycle", "Right after writing the contacts file, the new file is: ${readContactsDatabase()}")
oos.close()
} catch(e: Exception) {
@@ -364,12 +369,13 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati
private fun addToResolvedInstancesMap(instance: Instance) {
// Instances should be strongly kept by some data structure. Their identifiers
// are useful for keeping track of which instances are ready to communicate.
- getAllOnlinePeers().add(instance.userIdentifier)
- setAllOnlinePeers(instance.userIdentifier, true)
- Log.d("HypeLifeCycle ", "New onlinePeers: " + getAllOnlinePeers().toString())
+ getOnlinePeers().put(instance.userIdentifier, instance)
+ setOnlinePeers(instance.userIdentifier, instance, true)
+ Log.d("HypeLifeCycle ", "New onlinePeers: " + getOnlinePeers().toString())
if(getAllMessages()[instance.userIdentifier] == null) {
- setMessageDatabase(instance.userIdentifier, Store(instance))
- Log.d("HypeLifeCycle ", "New messageDatabase: " + getAllMessages().toString())
+ Log.d("HypeLifeCycle", "Could not find userIdentifier in getAllMessages() (aka messageDatabase), therefore starting a brand new Store")
+ setMessageDatabase(instance.userIdentifier, Store(instance.userIdentifier))
+ Log.d("HypeLifeCycle ", "New messageDatabase (from variable): " + getAllMessages().toString())
}
if(!(readContactsDatabase().containsKey(instance.userIdentifier))) {
// restoring User object from serialized byteArray
@@ -380,21 +386,20 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati
// and adding the userIdentifier exceeds the limit)
Log.d("HypeLifeCycle ", "NEWUSER OBJECT: ${newUser.toString()}")
setContactsDatabase(instance.userIdentifier, newUser)
+ } else {
+ Log.d("HypeLifeCycle", "User recognized in ContactsDatabase, no need to set anything new")
}
-// // Notify the conversationList activity to refresh the UI
-// val conversationListActivity = ConversationListActivity()
-// conversationListActivity.notifyOnlinePeersChanged()
}
fun removeFromResolvedInstancesMap(instance: Instance) {
// Cleaning up is always a good idea. It's not possible to communicate with instances
// that were previously lost.
-// getAllOnlinePeers().remove(instance.userIdentifier)
+// getOnlinePeers().remove(instance.userIdentifier)
// debugging
Log.d("HypeLifeCycle", "Lost instance")
- setAllOnlinePeers(instance.userIdentifier, false)
+ setOnlinePeers(instance.userIdentifier, instance,false)
// Notify the conversationList activity to refresh the UI
// val conversationListActivity = ConversationListActivity()
diff --git a/app/src/main/java/com/example/markmoussa/meshchatapplication/LifecycleObserverActivity.kt b/app/src/main/java/com/example/markmoussa/meshchatapplication/LifecycleObserverActivity.kt
index a16a242..cd51b1e 100644
--- a/app/src/main/java/com/example/markmoussa/meshchatapplication/LifecycleObserverActivity.kt
+++ b/app/src/main/java/com/example/markmoussa/meshchatapplication/LifecycleObserverActivity.kt
@@ -27,9 +27,18 @@ class LifecycleObserverActivity(context: Context) : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded() {
Log.i("DEBUG ", "ON APP BACKGROUNDED CALLED")
- val hypeFramework = mContext as HypeLifeCycle
- hypeFramework.requestHypeToStop()
+ // Commenting this out because if Hype stops when app backgrounded, messages would only get sent
+ // when the user has the app open
+ val hypeFramework = mContext as HypeLifeCycle
+ hypeFramework.requestHypeToStop()
+ }
+
+ @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
+ fun onAppDestroyed() {
+ // Commenting this part out for demo tomorrow
+// val hypeFramework = mContext as HypeLifeCycle
+// hypeFramework.requestHypeToStop()
}
diff --git a/app/src/main/java/com/example/markmoussa/meshchatapplication/MainActivity.kt b/app/src/main/java/com/example/markmoussa/meshchatapplication/MainActivity.kt
index e2878b7..c85b593 100644
--- a/app/src/main/java/com/example/markmoussa/meshchatapplication/MainActivity.kt
+++ b/app/src/main/java/com/example/markmoussa/meshchatapplication/MainActivity.kt
@@ -5,7 +5,9 @@ package com.example.markmoussa.meshchatapplication
*/
import android.Manifest
+import android.content.Context
import android.content.Intent
+import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
@@ -33,5 +35,16 @@ class MainActivity : AppCompatActivity() {
val intent = Intent(this, SignUpActivity::class.java)
startActivity(intent)
}
+
+ val sharedPreferences: SharedPreferences = applicationContext.getSharedPreferences("sp", Context.MODE_PRIVATE)
+ if(sharedPreferences.contains("USERNAME") && sharedPreferences.getString("USERNAME", null).isNotEmpty()) {
+ val intent = Intent(this, ConversationListActivity::class.java)
+ startActivity(intent)
+ }
+
+ // Companion code to onBackPressed for having the back button exit app instead of going back to SignUpActivity
+ if(intent.getBooleanExtra("Exit me", false)){
+ finish()
+ }
}
}
diff --git a/app/src/main/java/com/example/markmoussa/meshchatapplication/MessageListActivity.kt b/app/src/main/java/com/example/markmoussa/meshchatapplication/MessageListActivity.kt
index d57542d..493351e 100644
--- a/app/src/main/java/com/example/markmoussa/meshchatapplication/MessageListActivity.kt
+++ b/app/src/main/java/com/example/markmoussa/meshchatapplication/MessageListActivity.kt
@@ -7,6 +7,7 @@ package com.example.markmoussa.meshchatapplication
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v4.widget.SwipeRefreshLayout
+import android.support.v7.app.AlertDialog
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.util.Log
@@ -18,29 +19,36 @@ import java.io.UnsupportedEncodingException
class MessageListActivity : AppCompatActivity(), Store.Delegate {
- private var mMessageList: MutableList = mutableListOf()
+ private var mMessageList: MutableList> = mutableListOf()
private lateinit var mMessageAdapter: MessageListAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_message_list)
- mMessageAdapter = MessageListAdapter(this, mMessageList)
- var mMessageRecycler: RecyclerView? = null
- mMessageRecycler = findViewById(R.id.recyclerview_message_list) as RecyclerView
- mMessageRecycler.layoutManager = LinearLayoutManager(this)
- mMessageRecycler.adapter = mMessageAdapter
- // getting the messages
- notifyMessageListChanged()
val hypeFramework = applicationContext as HypeLifeCycle
val userIdentifier = intent.getLongExtra("userIdentifier", 0)
- // Setting actionbar with name of user
+ val contactsList = hypeFramework.getAllContacts()
+ // Setting profileUri to default user image in case it doesn't exist
+ // TODO: This way of setting the default profile pic might not be the best but it works; look into making more efficient later
+ var profileUri: String? = "/Users/markmoussa/AndroidStudioProjects/MeshChatApplication/app/src/main/res/drawable/default_user_image.png"
+ // Setting actionbar with name of user and getting profile pic path
if(userIdentifier != 0.toLong()) {
- if(userIdentifier in hypeFramework.getAllContacts()) {
+ if(userIdentifier in contactsList) {
val actionBar = supportActionBar
- actionBar!!.title = hypeFramework.getAllContacts()[userIdentifier]!!.nickname
+ actionBar!!.title = contactsList[userIdentifier]!!.nickname
+
+ profileUri = contactsList[userIdentifier]?.profileUri
}
}
+ mMessageAdapter = MessageListAdapter(this, mMessageList, profileUri)
+ var mMessageRecycler: RecyclerView? = null
+ mMessageRecycler = findViewById(R.id.recyclerview_message_list)
+ mMessageRecycler.layoutManager = LinearLayoutManager(this)
+ mMessageRecycler.adapter = mMessageAdapter
+ // getting the messages
+ notifyMessageListChanged()
+
// hackish fix at the messages not appearing when notifyDataSetChanged() called. Need to fix later
// also need to fix same thing for ConversationListActivity
@@ -54,7 +62,6 @@ class MessageListActivity : AppCompatActivity(), Store.Delegate {
override fun onStart() {
super.onStart()
// checking to see which user chat they want, or if it's a new message
- // TODO: made a new separate class for new messages for now, condense that into this class when I have everything set up
val hypeFramework = applicationContext as HypeLifeCycle
val userIdentifier = intent.getLongExtra("userIdentifier", 0)
@@ -63,13 +70,13 @@ class MessageListActivity : AppCompatActivity(), Store.Delegate {
// debugging
Log.d("MessageListActivity ", "Store is this: ")
for(x in store.getMessages()) {
- Log.i("DBEUG", x.data.toString())
+ Log.i("DEBUG", x.first)
}
store.delegate = this
store.lastReadIndex = store.getMessages().size
- val chatBox = findViewById(R.id.edittext_chatbox) as EditText
- val sendButton = findViewById