diff --git a/app/build.gradle b/app/build.gradle index 797b552..e453caa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,6 +20,13 @@ android { versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + /** Replace with your api_token + * eg: Your api token is 6nt5d1nJHkqbkphf + * Following line should be replaced by + * buildConfigField 'String', 'API_DEVELOPER_TOKEN', "\"6nt5d1nJHkqbkphf\""*/ + + buildConfigField 'String', 'API_DEVELOPER_TOKEN', "\"${api_developer_token}\"" } buildTypes { release { diff --git a/app/src/main/java/com/cnx/pingme/MainActivity.kt b/app/src/main/java/com/cnx/pingme/MainActivity.kt index 00af904..8e7d0ab 100644 --- a/app/src/main/java/com/cnx/pingme/MainActivity.kt +++ b/app/src/main/java/com/cnx/pingme/MainActivity.kt @@ -27,20 +27,19 @@ import javax.inject.Inject import kotlin.collections.ArrayList - - -class MainActivity : AppCompatActivity(), HasSupportFragmentInjector { +class MainActivity : AppCompatActivity(), HasSupportFragmentInjector { @Inject lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector - override fun supportFragmentInjector(): AndroidInjector = dispatchingAndroidInjector + override fun supportFragmentInjector(): AndroidInjector = dispatchingAndroidInjector - @Inject lateinit var viewModelFactory: ViewModelProvider.Factory - private lateinit var drawerLayout : DrawerLayout + @Inject + lateinit var viewModelFactory: ViewModelProvider.Factory + private lateinit var drawerLayout: DrawerLayout private lateinit var chatViewModel: ChatViewModel - private var userSession : String = SESSION_BOB - private lateinit var chatRVAdapter : ChatAdapter + private var userSession: String = SESSION_BOB + private lateinit var chatRVAdapter: ChatAdapter private var messages = ArrayList() @@ -49,7 +48,6 @@ class MainActivity : AppCompatActivity(), HasSupportFragmentInjector { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) - chatViewModel = injectViewModel(viewModelFactory) chatViewModel.userSessionLd.postValue(userSession) getChats() @@ -67,12 +65,14 @@ class MainActivity : AppCompatActivity(), HasSupportFragmentInjector { fabSend.setOnClickListener { - if(!TextUtils.isEmpty(etMessage.editableText)) { + if (!TextUtils.isEmpty(etMessage.editableText)) { - val message = MessageModel(UUID.randomUUID().toString(),userSession, - CHATBOT_ID, USER_NAME,"", - etMessage.editableText.toString().trim(),true) + val message = MessageModel( + UUID.randomUUID().toString(), userSession, + CHATBOT_ID, USER_NAME, "", + etMessage.editableText.toString().trim(), true + ) etMessage.setText("") chatViewModel.sendAndReceiveChat(message) @@ -87,8 +87,10 @@ class MainActivity : AppCompatActivity(), HasSupportFragmentInjector { drawerLayout = findViewById(R.id.drawer_layout) - var actionBarToggle = object : ActionBarDrawerToggle(this - ,drawerLayout , toolbar, R.string.opened, R.string.closed) { + var actionBarToggle = object : ActionBarDrawerToggle( + this + , drawerLayout, toolbar, R.string.opened, R.string.closed + ) { override fun onDrawerOpened(drawerView: View) { super.onDrawerOpened(drawerView) @@ -107,13 +109,21 @@ class MainActivity : AppCompatActivity(), HasSupportFragmentInjector { when (it.itemId) { - R.id.tom -> { userSession = SESSION_TOM ; ivProfile.setImageResource(R.drawable.pic_tom) } + R.id.tom -> { + userSession = SESSION_TOM; ivProfile.setImageResource(R.drawable.pic_tom) + } - R.id.bob -> { userSession = SESSION_BOB ; ivProfile.setImageResource(R.drawable.pic_bob)} + R.id.bob -> { + userSession = SESSION_BOB; ivProfile.setImageResource(R.drawable.pic_bob) + } - R.id.jennifer -> { userSession = SESSION_JENNI ; ivProfile.setImageResource(R.drawable.pic_jennifer)} + R.id.jennifer -> { + userSession = SESSION_JENNI; ivProfile.setImageResource(R.drawable.pic_jennifer) + } - R.id.mark -> { userSession = SESSION_MARK ; ivProfile.setImageResource(R.drawable.pic_mark)} + R.id.mark -> { + userSession = SESSION_MARK; ivProfile.setImageResource(R.drawable.pic_mark) + } } @@ -121,12 +131,11 @@ class MainActivity : AppCompatActivity(), HasSupportFragmentInjector { toolbar.title = userSession tvSelectedName.text = userSession - return@setNavigationItemSelectedListener true + return@setNavigationItemSelectedListener true } } - private fun getChats() { chatViewModel.chatList.observe(this, Observer { @@ -134,16 +143,15 @@ class MainActivity : AppCompatActivity(), HasSupportFragmentInjector { chatRVAdapter.submitList(it) if (it.size > 0) - rvMsg.smoothScrollToPosition(it.size -1) + rvMsg.smoothScrollToPosition(it.size - 1) }) - chatViewModel.userSessionLd.observe(this, Observer { + chatViewModel.userSessionLd.observe(this, Observer { userSession = it }) } - private fun hideKeyboard() { val view = this.currentFocus @@ -152,5 +160,4 @@ class MainActivity : AppCompatActivity(), HasSupportFragmentInjector { imm?.hideSoftInputFromWindow(view.windowToken, 0) } } - } diff --git a/app/src/main/java/com/cnx/pingme/PingMeApp.kt b/app/src/main/java/com/cnx/pingme/PingMeApp.kt index f96b6f1..7f7145c 100644 --- a/app/src/main/java/com/cnx/pingme/PingMeApp.kt +++ b/app/src/main/java/com/cnx/pingme/PingMeApp.kt @@ -11,7 +11,7 @@ import dagger.android.HasActivityInjector import javax.inject.Inject -class PingMeApp : Application() , HasActivityInjector { +class PingMeApp : Application(), HasActivityInjector { @Inject public lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector @@ -20,10 +20,9 @@ class PingMeApp : Application() , HasActivityInjector { lateinit var workManager: WorkManager companion object { - var appInstance : PingMeApp? = null + var appInstance: PingMeApp? = null } - override fun onCreate() { super.onCreate() @@ -36,5 +35,4 @@ class PingMeApp : Application() , HasActivityInjector { override fun activityInjector() = dispatchingAndroidInjector - -} \ No newline at end of file +} diff --git a/app/src/main/java/com/cnx/pingme/api/BaseDataSource.kt b/app/src/main/java/com/cnx/pingme/api/BaseDataSource.kt index 0e3a20b..488abbb 100644 --- a/app/src/main/java/com/cnx/pingme/api/BaseDataSource.kt +++ b/app/src/main/java/com/cnx/pingme/api/BaseDataSource.kt @@ -26,6 +26,5 @@ abstract class BaseDataSource { Timber.e(message) return Result.error("Network call has failed for a following reason: $message") } - } diff --git a/app/src/main/java/com/cnx/pingme/api/ChatService.kt b/app/src/main/java/com/cnx/pingme/api/ChatService.kt index 1309acb..1dc386a 100644 --- a/app/src/main/java/com/cnx/pingme/api/ChatService.kt +++ b/app/src/main/java/com/cnx/pingme/api/ChatService.kt @@ -19,5 +19,4 @@ interface ChatService { suspend fun getChats(@Query("externalID") externalId : String, @Query("message") message : String, @Query("chatBotID") chatBotID : Int = CHATBOT_ID,@Query("apiKey") apiKey : String = apiKeyValue ) : Response - } diff --git a/app/src/main/java/com/cnx/pingme/api/OfflineChatService.kt b/app/src/main/java/com/cnx/pingme/api/OfflineChatService.kt index 781ab01..7fdae7b 100644 --- a/app/src/main/java/com/cnx/pingme/api/OfflineChatService.kt +++ b/app/src/main/java/com/cnx/pingme/api/OfflineChatService.kt @@ -1,5 +1,6 @@ package com.cnx.pingme.api +import com.cnx.pingme.BuildConfig import com.cnx.pingme.utils.APIKEY import com.cnx.pingme.utils.CHATBOT_ID import retrofit2.Call @@ -10,10 +11,9 @@ import retrofit2.http.Query * previous versions as work manager is itself executing * this call in background so need of couroutine calling this function anymore */ - /** This apikey value can be changed to show error */ -const val apiKeyValue = "6nt5d1nJHkqbkphe" +const val apiKeyValue = BuildConfig.API_DEVELOPER_TOKEN interface OfflineChatService { @@ -21,9 +21,9 @@ interface OfflineChatService { const val ENDPOINT = "https://www.personalityforge.com/" } - @GET("api/chat/") - fun getChats(@Query("externalID") externalId : String, @Query("message") message : String, - @Query("chatBotID") chatBotID : Int = CHATBOT_ID, @Query(APIKEY) apiKey : String = apiKeyValue - ) : Call -} \ No newline at end of file + fun getChats( + @Query("externalID") externalId: String, @Query("message") message: String, + @Query("chatBotID") chatBotID: Int = CHATBOT_ID, @Query(APIKEY) apiKey: String = apiKeyValue + ): Call +} diff --git a/app/src/main/java/com/cnx/pingme/api/ResponseModels.kt b/app/src/main/java/com/cnx/pingme/api/ResponseModels.kt index 45b57ef..176e5a0 100644 --- a/app/src/main/java/com/cnx/pingme/api/ResponseModels.kt +++ b/app/src/main/java/com/cnx/pingme/api/ResponseModels.kt @@ -34,4 +34,4 @@ data class MessageModel( var message: String?, var isSent : Boolean = false, var isSuccess : Boolean = true -) \ No newline at end of file +) diff --git a/app/src/main/java/com/cnx/pingme/chat/ChatVH.kt b/app/src/main/java/com/cnx/pingme/chat/ChatVH.kt index e22c979..e7f53a3 100644 --- a/app/src/main/java/com/cnx/pingme/chat/ChatVH.kt +++ b/app/src/main/java/com/cnx/pingme/chat/ChatVH.kt @@ -9,25 +9,21 @@ import kotlinx.android.synthetic.main.rv_sent_message.view.* /** Could be inside adapter class if it is not gonna be used elsewhere */ -class ChatVH(itemView: View) : RecyclerView.ViewHolder(itemView ) { +class ChatVH(itemView: View) : RecyclerView.ViewHolder(itemView) { - fun bind(messageModel : MessageModel) { + fun bind(messageModel: MessageModel) { with(itemView) { - if(messageModel.isSent) { - + if (messageModel.isSent) { tvMessage.text = messageModel.message tvName.text = messageModel.chatBotName tvFailed.visibility = if (messageModel.isSuccess) View.GONE else View.VISIBLE - } else { + tvSenderMessage.text = messageModel.message tvSenderName.text = messageModel.userSession } - } - } - -} \ No newline at end of file +} diff --git a/app/src/main/java/com/cnx/pingme/chat/ChatViewModel.kt b/app/src/main/java/com/cnx/pingme/chat/ChatViewModel.kt index 844efb7..794d9ab 100644 --- a/app/src/main/java/com/cnx/pingme/chat/ChatViewModel.kt +++ b/app/src/main/java/com/cnx/pingme/chat/ChatViewModel.kt @@ -8,22 +8,20 @@ import com.cnx.pingme.room.ChatRepository import kotlinx.coroutines.CoroutineScope import javax.inject.Inject -class ChatViewModel @Inject constructor(private val chatRepository: ChatRepository, - @CoroutineScopeIO private val ioCoroutineScope: CoroutineScope - -): ViewModel() { +class ChatViewModel @Inject constructor( + private val chatRepository: ChatRepository, + @CoroutineScopeIO private val ioCoroutineScope: CoroutineScope +) : ViewModel() { fun sendAndReceiveChat(messageModel: MessageModel) { - chatRepository.sendAndReceiveChat(messageModel,ioCoroutineScope) + chatRepository.sendAndReceiveChat(messageModel, ioCoroutineScope) } - - var userSessionLd : MutableLiveData = MutableLiveData() + var userSessionLd: MutableLiveData = MutableLiveData() val chatList = chatRepository.getChatList(userSessionLd) - -} \ No newline at end of file +} diff --git a/app/src/main/java/com/cnx/pingme/chat/FeedAdapter.kt b/app/src/main/java/com/cnx/pingme/chat/FeedAdapter.kt index 0006ced..6c6b13f 100644 --- a/app/src/main/java/com/cnx/pingme/chat/FeedAdapter.kt +++ b/app/src/main/java/com/cnx/pingme/chat/FeedAdapter.kt @@ -10,10 +10,8 @@ import com.cnx.pingme.utils.SENT_MESSAGE class ChatAdapter : PagedListAdapter(diffCallback) { - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatVH { - val view = LayoutInflater.from(parent.context) .inflate( viewType,parent,false) @@ -24,21 +22,18 @@ class ChatAdapter : PagedListAdapter(diffCallback) { val chat = getItem(position) chat?.let { holder.bind(messageModel = chat) } - } - override fun getItemViewType(position: Int): Int { return if(currentList!![position]?.isSent == true) SENT_MESSAGE else RECEIVED_MESSAGE } - companion object { /** * This diff callback informs the PagedListAdapter how to compute list differences when new * PagedLists arrive. *

- * When you add a Chat with the 'Add' button, the PagedListAdapter uses diffCallback to + * When you add a Chat, the PagedListAdapter uses diffCallback to * detect there's only a single item difference from before, so it only needs to animate and * rebind a single view. * @@ -48,12 +43,9 @@ class ChatAdapter : PagedListAdapter(diffCallback) { override fun areItemsTheSame(oldItem: MessageModel, newItem: MessageModel): Boolean = oldItem.id == newItem.id - override fun areContentsTheSame(oldItem: MessageModel, newItem: MessageModel): Boolean = oldItem == newItem } } - - } diff --git a/app/src/main/java/com/cnx/pingme/room/AppDatabase.kt b/app/src/main/java/com/cnx/pingme/room/AppDatabase.kt index d6f0b33..ebec828 100644 --- a/app/src/main/java/com/cnx/pingme/room/AppDatabase.kt +++ b/app/src/main/java/com/cnx/pingme/room/AppDatabase.kt @@ -18,9 +18,7 @@ abstract class AppDatabase : RoomDatabase() { abstract fun getChatDao(): ChatDao - companion object { - @Volatile private var instance: AppDatabase? = null diff --git a/app/src/main/java/com/cnx/pingme/room/ChatDao.kt b/app/src/main/java/com/cnx/pingme/room/ChatDao.kt index 35462e2..7f5aef2 100644 --- a/app/src/main/java/com/cnx/pingme/room/ChatDao.kt +++ b/app/src/main/java/com/cnx/pingme/room/ChatDao.kt @@ -13,10 +13,9 @@ interface ChatDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insertChat(chat : MessageModel) - @Query("SELECT * From MessageModel Where userSession = :userSess") fun getMessageForId(userSess : String) : DataSource.Factory @Query("Update MessageModel SET isSuccess = :isSuccess Where id = :msgId") fun updateChat(isSuccess : Boolean, msgId: Int) -} \ No newline at end of file +} diff --git a/app/src/main/java/com/cnx/pingme/room/ChatRepository.kt b/app/src/main/java/com/cnx/pingme/room/ChatRepository.kt index c6628d8..6922ae6 100644 --- a/app/src/main/java/com/cnx/pingme/room/ChatRepository.kt +++ b/app/src/main/java/com/cnx/pingme/room/ChatRepository.kt @@ -16,12 +16,12 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class ChatRepository @Inject constructor(private val chatDao: ChatDao, - private val workManager: WorkManager) : BaseDataSource() { - - - fun sendAndReceiveChat(sentMsgModel: MessageModel, coroutineScopeIO: CoroutineScope){ +class ChatRepository @Inject constructor( + private val chatDao: ChatDao, + private val workManager: WorkManager +) : BaseDataSource() { + fun sendAndReceiveChat(sentMsgModel: MessageModel, coroutineScopeIO: CoroutineScope) { coroutineScopeIO.launch { @@ -29,34 +29,29 @@ class ChatRepository @Inject constructor(private val chatDao: ChatDao, addRequestInQueue(sentMsgModel) } - } - fun addRequestInQueue(messageModel: MessageModel) { - Log.d("Offline","add in request msgId ${messageModel.id}") + Log.d("Offline", "add in request msgId ${messageModel.id}") createWorkRequest(messageModel) } - fun insertChat(messageModel: MessageModel?) { - messageModel?.let { - chatDao.insertChat(messageModel) - } + messageModel?.let { + chatDao.insertChat(messageModel) + } } - val config = PagedList.Config.Builder() .setPageSize(50) .build() - - fun getChatList (userSessionLd : LiveData) = Transformations.switchMap(userSessionLd){ + fun getChatList(userSessionLd: LiveData) = Transformations.switchMap(userSessionLd) { session -> - LivePagedListBuilder(chatDao.getMessageForId(session),config).build() + LivePagedListBuilder(chatDao.getMessageForId(session), config).build() } fun createWorkRequest(messageModel: MessageModel) { @@ -66,25 +61,24 @@ class ChatRepository @Inject constructor(private val chatDao: ChatDao, .setRequiredNetworkType(NetworkType.CONNECTED) .build() - - val stringArray : Array = arrayOf(messageModel.chatBotName!!, - messageModel.userSession,messageModel.message!!, messageModel.id!!.toString()) + val stringArray: Array = arrayOf( + messageModel.chatBotName!!, + messageModel.userSession, messageModel.message!!, messageModel.id!!.toString() + ) val externalId = workDataOf( - MSG_KEY to stringArray) + MSG_KEY to stringArray + ) - Log.d("Worker Sent","externalID ${messageModel.chatBotName} message ${messageModel.message} userSession ${messageModel.userSession}") + Log.d( + "Worker Sent", + "externalID ${messageModel.chatBotName} message ${messageModel.message} userSession ${messageModel.userSession}" + ) val sendMsgRequest = OneTimeWorkRequestBuilder() - .setConstraints(constraints). - - setInputData(externalId).build() - + .setConstraints(constraints).setInputData(externalId).build() workManager.enqueue(sendMsgRequest) - } - - -} \ No newline at end of file +} diff --git a/app/src/main/java/com/cnx/pingme/utils/Constants.kt b/app/src/main/java/com/cnx/pingme/utils/Constants.kt index d115360..8c3e702 100644 --- a/app/src/main/java/com/cnx/pingme/utils/Constants.kt +++ b/app/src/main/java/com/cnx/pingme/utils/Constants.kt @@ -2,14 +2,12 @@ package com.cnx.pingme.utils import com.cnx.pingme.R - const val SENT_MESSAGE = R.layout.rv_sent_message const val RECEIVED_MESSAGE = R.layout.rv_received_message const val CHATBOT_ID = 63906 const val APIKEY = "apiKey" const val USER_NAME = "Kanchan" // This needs to be input by user - const val SESSION_TOM = "Tom" const val SESSION_BOB = "Bob" const val SESSION_MARK = "Mark" diff --git a/app/src/main/java/com/cnx/pingme/worker/SendMsgWorker.kt b/app/src/main/java/com/cnx/pingme/worker/SendMsgWorker.kt index 743cc7d..9f0b28a 100644 --- a/app/src/main/java/com/cnx/pingme/worker/SendMsgWorker.kt +++ b/app/src/main/java/com/cnx/pingme/worker/SendMsgWorker.kt @@ -13,8 +13,8 @@ import com.cnx.pingme.utils.MSG_KEY import java.util.* import javax.inject.Inject -class SendMsgWorker @Inject constructor(appContext : Context, workerParameters: WorkerParameters) - : Worker(appContext , workerParameters) { +class SendMsgWorker @Inject constructor(appContext: Context, workerParameters: WorkerParameters) : + Worker(appContext, workerParameters) { init { AppInjector.appComponent.injectIntoWorker(this) @@ -26,54 +26,34 @@ class SendMsgWorker @Inject constructor(appContext : Context, workerParameters @Inject lateinit var chatDao: ChatDao - override fun doWork(): Result { - val msg = inputData.getStringArray(MSG_KEY) - val externalId = msg?.get(0) ?: "" - val userSession = msg?.get(1) ?: "" - val message = msg?.get(2) ?: "" - val msgId = msg?.get(3)!! - - try { - - val response = offlineChatService.getChats(externalId, message).execute() - - Log.d("Response ", "${response}") + val msg = inputData.getStringArray(MSG_KEY) + val externalId = msg?.get(0) ?: "" + val userSession = msg?.get(1) ?: "" + val message = msg?.get(2) ?: "" + val msgId = msg?.get(3)!! + try { + val response = offlineChatService.getChats(externalId, message).execute() - if (response.isSuccessful) { + Log.d("Response ", "${response}") + if (response.isSuccessful) { + if (response.body()?.success == 1) { - if (response.body()?.success == 1) { + val messagemodel = response.body()?.messageModel - val messagemodel = response.body()?.messageModel + messagemodel?.let { - messagemodel?.let { - - it.userSession = userSession - it.id = UUID.randomUUID().toString() - chatDao.insertChat(it) - messagemodel.isSuccess = true - } - } else { - - Log.d("Update", "update msgID ${msgId}") - val messageModel = MessageModel( - msgId, - userSession, - CHATBOT_ID, - externalId, - null, - message, - true, - false - ) - chatDao.insertChat(messageModel) + it.userSession = userSession + it.id = UUID.randomUUID().toString() + chatDao.insertChat(it) + messagemodel.isSuccess = true } - } else { + Log.d("Update", "update msgID ${msgId}") val messageModel = MessageModel( msgId, userSession, @@ -87,9 +67,7 @@ class SendMsgWorker @Inject constructor(appContext : Context, workerParameters chatDao.insertChat(messageModel) } - return Result.success() - - } catch (e: Exception) { + } else { val messageModel = MessageModel( msgId, @@ -102,16 +80,26 @@ class SendMsgWorker @Inject constructor(appContext : Context, workerParameters false ) chatDao.insertChat(messageModel) + } + return Result.success() - e.printStackTrace() - - } + } catch (e: Exception) { + val messageModel = MessageModel( + msgId, + userSession, + CHATBOT_ID, + externalId, + null, + message, + true, + false + ) + chatDao.insertChat(messageModel) + e.printStackTrace() + } return Result.failure() } - - - -} \ No newline at end of file +}