diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1106d15..397095d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -40,8 +40,10 @@ - - + + 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 abf75cc..24f3b3c 100644 --- a/app/src/main/java/com/example/markmoussa/meshchatapplication/ConversationListActivity.kt +++ b/app/src/main/java/com/example/markmoussa/meshchatapplication/ConversationListActivity.kt @@ -135,7 +135,6 @@ class ConversationListActivity : AppCompatActivity(), Store.Delegate, LifecycleO 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 = onlinePeers.containsKey(x.key) // val nickname: String? 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 2a83c27..b815ba8 100644 --- a/app/src/main/java/com/example/markmoussa/meshchatapplication/ConversationListAdapter.kt +++ b/app/src/main/java/com/example/markmoussa/meshchatapplication/ConversationListAdapter.kt @@ -53,6 +53,10 @@ class ConversationListAdapter(private val mContext: Context, private val mConver onlineStatusIcon = itemView.findViewById(R.id.onlineStatusIcon) as ImageView } internal fun bind(conversation: Conversation) { + if(conversation.user == null) { + Log.e("ConvoListAdapter", "Problem with User being null here") + return + } if(conversation.user!!.nickname != null) { usernameText.text = conversation.user.nickname } else { 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 8693d36..5c8dd7f 100644 --- a/app/src/main/java/com/example/markmoussa/meshchatapplication/HypeLifeCycle.kt +++ b/app/src/main/java/com/example/markmoussa/meshchatapplication/HypeLifeCycle.kt @@ -4,9 +4,12 @@ package com.example.markmoussa.meshchatapplication // ALL CREDIT FOR THIS FILE GOES DIRECTLY TO HYPELABS // link: https://github.com/Hype-Labs/HypeChatDemo.android -import android.app.Application +import android.app.* import android.content.Context +import android.content.Intent import android.content.SharedPreferences +import android.os.Build +import android.support.v4.app.NotificationCompat import android.util.Log import com.hypelabs.hype.Error import com.hypelabs.hype.Hype @@ -21,6 +24,8 @@ import kotlin.collections.HashMap 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() @@ -52,13 +57,32 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati // by creating a new app. Copy the given identifier here. // ChatApplication - Hype.setAppIdentifier("f370ac17") +// Hype.setAppIdentifier("f370ac17") // MeshNetworkApplication - // Hype.setAppIdentifier("9a96baaa") + Hype.setAppIdentifier("9a96baaa") // MeshNetworkApp2 - Hype.setAppIdentifier("b056a7af") +// Hype.setAppIdentifier("b056a7af") + + // MeshNetwork3 +// Hype.setAppIdentifier("d74214ee") + + // MeshNetwork4 +// Hype.setAppIdentifier("ba3ae1ae") + + //MeshNetworkApplication5 +// Hype.setAppIdentifier("9cb5496c") + + // PleaseWork +// Hype.setAppIdentifier("f26a3372") + + // PleaseIBegYou +// Hype.setAppIdentifier("ad9b29f5") + + //ChatAppEgyptianMarkos +// Hype.setAppIdentifier("aba7c2aa") + val sharedPreferences: SharedPreferences = applicationContext.getSharedPreferences("sp", Context.MODE_PRIVATE) val userIdentifier = sharedPreferences.getInt("USER_IDENTIFIER", Hype.DefaultUserIdentifier) Hype.setUserIdentifier(userIdentifier) @@ -155,6 +179,7 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati // Storing the message triggers a reload update in the MessageList activity store.add(Pair(message.data.toString(charset("UTF-8")), false), this) setMessageDatabase(instance.userIdentifier, store) + sendNotification(message, instance) } @@ -181,14 +206,33 @@ 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. + // This one is for chatApplication // return "903cbdd53f59e2f771cbf2a9429c91" // MeshNetworkApplication -// return "4e5936b294a88cf2" + return "4e5936b294a88cf2" // MeshNetworkApp2 - return "4e5936b294a88cf2" +// return "4e5936b294a88cf2" + + //MeshNetwork3 +// return "9f05c13eb9276473" + + //MeshNetwork4 +// return "bf80129c2ae5e7df" + + // MeshNetworkApplication5 +// return "9f05c13eb9276473" + + // PleaseWork +// return "bf80129c2ae5e7df" + + // PleaseIBegYou +// return "bf80129c2ae5e7df" + + //ChatAppEgyptianMarkos + return "bf80129c2ae5e7df" } override fun onCreate() { @@ -379,6 +423,10 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati } if(!(readContactsDatabase().containsKey(instance.userIdentifier))) { // restoring User object from serialized byteArray + if(instance.announcement == null) { + Log.d("Announcement null", "The Instance announcement is null") + } + Log.d("Instance announcement: ", "${instance.announcement.toString(charset("UTF-8"))}") val bis = ByteArrayInputStream(instance.announcement) val ois = ObjectInputStream(bis) val newUser: User = ois.readObject() as User @@ -406,6 +454,40 @@ class HypeLifeCycle : StateObserver, NetworkObserver, MessageObserver, Applicati // conversationListActivity.notifyOnlinePeersChanged() } + private fun sendNotification(message: Message, instance: Instance) { + if(!(LifecycleObserverActivity.isAppInForeground)) { + val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + if(Build.VERSION.SDK_INT >= 26) { + val notificationChannel = NotificationChannel("hypeMessageReceived", "Message Received", NotificationManager.IMPORTANCE_DEFAULT) + notificationManager.createNotificationChannel(notificationChannel) + } + // change messageReceivedNotificationID to something more robust in the future + val messageReceivedNotificationID = 1234321 + val notificationBuilder = NotificationCompat.Builder(applicationContext, "hypeMessageReceived") + + var contentText: String? = message.data.toString(charset("UTF-8")) + + if(message.data.toString(charset("UTF-8")).length > 25) { + contentText = message.data.toString(charset("UTF-8")).substring(0, 25) + "..." + } + val nickname = getAllContacts()[instance.userIdentifier]?.nickname + val contentTitle: String? = if(nickname.isNullOrEmpty()) instance.userIdentifier.toString() else nickname + val notification = notificationBuilder.setAutoCancel(true) + .setDefaults(Notification.DEFAULT_ALL) + .setWhen(System.currentTimeMillis()) + .setSmallIcon(R.drawable.ic_launcher_foreground) + .setTicker("New message received!") + .setContentTitle(contentTitle) + .setContentText(contentText) + + val intent = Intent(this, MessageListActivity::class.java) + intent.putExtra("userIdentifier", instance.userIdentifier) + val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + notification.setContentIntent(pendingIntent) + notificationManager.notify(messageReceivedNotificationID, notificationBuilder.build()) + } + } + companion object { private const val TAG = "HypeServices" 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 cd51b1e..a3d22ca 100644 --- a/app/src/main/java/com/example/markmoussa/meshchatapplication/LifecycleObserverActivity.kt +++ b/app/src/main/java/com/example/markmoussa/meshchatapplication/LifecycleObserverActivity.kt @@ -6,6 +6,7 @@ import android.arch.lifecycle.LifecycleObserver import android.arch.lifecycle.OnLifecycleEvent import android.arch.lifecycle.ProcessLifecycleOwner import android.content.Context +import android.content.SharedPreferences import android.util.Log class LifecycleObserverActivity(context: Context) : LifecycleObserver { @@ -20,25 +21,37 @@ class LifecycleObserverActivity(context: Context) : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_START) fun onAppForegrounded() { Log.i("DEBUG ", "ON APP FOREGROUNDED CALLED") - val hypeFramework = mContext as HypeLifeCycle - hypeFramework.requestHypeToStart() + isAppInForeground = true + // Don't want to start Hype immediately if it's their first time opening the app (because they need to sign up first) + val sharedPreferences: SharedPreferences = mContext.getSharedPreferences("sp", Context.MODE_PRIVATE) + if(sharedPreferences.contains("USERNAME") && sharedPreferences.getString("USERNAME", null).isNotEmpty()) { + val hypeFramework = mContext as HypeLifeCycle + hypeFramework.requestHypeToStart() + } } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun onAppBackgrounded() { - Log.i("DEBUG ", "ON APP BACKGROUNDED CALLED") +// Log.i("DEBUG ", "ON APP BACKGROUNDED CALLED") + isAppInForeground = false // 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() +// val hypeFramework = mContext as HypeLifeCycle +// hypeFramework.requestHypeToStop() } @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun onAppDestroyed() { + Log.i("DEBUG ", "ON APP DESTROYED CALLED") + isAppInForeground = false // Commenting this part out for demo tomorrow -// val hypeFramework = mContext as HypeLifeCycle -// hypeFramework.requestHypeToStop() + val hypeFramework = mContext as HypeLifeCycle + hypeFramework.requestHypeToStop() + } + + companion object { + var isAppInForeground: Boolean = true } 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 493351e..c2ffedd 100644 --- a/app/src/main/java/com/example/markmoussa/meshchatapplication/MessageListActivity.kt +++ b/app/src/main/java/com/example/markmoussa/meshchatapplication/MessageListActivity.kt @@ -48,6 +48,7 @@ class MessageListActivity : AppCompatActivity(), Store.Delegate { mMessageRecycler.adapter = mMessageAdapter // getting the messages notifyMessageListChanged() + mMessageRecycler.scrollToPosition(mMessageList.size - 1) // hackish fix at the messages not appearing when notifyDataSetChanged() called. Need to fix later @@ -68,10 +69,10 @@ class MessageListActivity : AppCompatActivity(), Store.Delegate { if(userIdentifier in hypeFramework.getAllMessages()) { val store = getStore() // debugging - Log.d("MessageListActivity ", "Store is this: ") - for(x in store.getMessages()) { - Log.i("DEBUG", x.first) - } +// Log.d("MessageListActivity ", "Store is this: ") +// for(x in store.getMessages()) { +// Log.i("DEBUG", x.first) +// } store.delegate = this store.lastReadIndex = store.getMessages().size diff --git a/app/src/main/java/com/example/markmoussa/meshchatapplication/MessageListAdapter.kt b/app/src/main/java/com/example/markmoussa/meshchatapplication/MessageListAdapter.kt index 1f87e23..61dcaf6 100644 --- a/app/src/main/java/com/example/markmoussa/meshchatapplication/MessageListAdapter.kt +++ b/app/src/main/java/com/example/markmoussa/meshchatapplication/MessageListAdapter.kt @@ -76,7 +76,6 @@ class MessageListAdapter(private val mContext: Context, private val mMessageList // UserMessage is specific to SendBird, fix later internal fun bind(message: String) { messageText.text = message - Log.i("DEBUG ", "Message text from adapter: ${messageText.text}") // Format the stored timestamp into a readable String using method. // Utils specific to SendBird, fix later @@ -92,7 +91,6 @@ class MessageListAdapter(private val mContext: Context, private val mMessageList internal fun bind(message: String) { messageText.text = message - Log.i("DEBUG ", "Message text from adapter: ${messageText.text}") if(profileUri == null) { profileImage.setImageResource(R.drawable.default_user_image) } else { diff --git a/app/src/main/res/layout/item_message_sent.xml b/app/src/main/res/layout/item_message_sent.xml index 0c99ee1..b8dc24f 100644 --- a/app/src/main/res/layout/item_message_sent.xml +++ b/app/src/main/res/layout/item_message_sent.xml @@ -13,16 +13,21 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="8dp" + android:layout_marginTop="8dp" android:text="11:40" android:textSize="12sp" app:layout_constraintBottom_toBottomOf="@+id/bubbleTextView" - app:layout_constraintEnd_toStartOf="@+id/bubbleTextView" /> + app:layout_constraintEnd_toStartOf="@+id/bubbleTextView" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="1.0" /> + app:layout_constraintTop_toTopOf="parent" /> \ No newline at end of file