I create retrofitconfig for get data from API in first time I use it works and good but in 2 days data not showing from Api
this is my interface
interface CnnApi {
#GET("cnbc-news/")
fun getNewsCNN(): Call<NewsResponse>
#GET("cnbc-news/{type}")
fun getNewsCCNType(#Path("type") type: String ) : Call<NewsResponse>
}
and then this is object I use to make retrofit
object RetrofitConfig {
fun getData(): CnnApi {
val loggingInterceptor =
HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
val client = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://berita-indo-api.vercel.app/v1/")
.client(client)
.build()
return retrofit.create(CnnApi::class.java)
}
}
and then this is my HomeViewModel
class HomeViewModel : ViewModel() {
private val _isLoading = MutableLiveData<Boolean>()
val isLoading: LiveData<Boolean> = _isLoading
private val _dataItem = MutableLiveData<List<DataItem>>()
val dataItem: LiveData<List<DataItem>> = _dataItem
private val _image = MutableLiveData<Image>()
val image:LiveData<Image> = _image
companion object{
private const val TAG = "News"
private const val type ="lifestyle"
}
init{
getDataFromAPI()
}
private fun getDataFromAPI(){
EspressoIdlingResource.increment()
_isLoading.value = true
val client = RetrofitConfig.getData().getNewsCCNType(type)
client.enqueue(object: Callback<NewsResponse>{
override fun onResponse(call: Call<NewsResponse>, response: Response<NewsResponse>) {
_isLoading.value = false
if(response.isSuccessful || response.body()?.total== 200){
_dataItem.value = response.body()?.data
}else{
Log.e(TAG,"onFailure: ${response.message()}")
}
}
override fun onFailure(call: Call<NewsResponse>, t: Throwable) {
_isLoading.value = false
Log.e(TAG, "onFailure: ${t.message.toString()}")
EspressoIdlingResource.decrement()
}
})
}
}
This is the view or how I show the data
homeViewModel =
ViewModelProvider(this).get(HomeViewModel::class.java)
_binding = FragmentHomeBinding.inflate(inflater, container, false)
val root: View = binding.root
homeViewModel.dataItem.observe(viewLifecycleOwner, { news ->
binding.articleTitle.text = news[0].title
Glide.with(this)
.load(news[0].image.small)
.into(binding.articleImage)
binding.articleFrom.text = "CNN Indonesia"
link = news[0].link
})
binding.imageCard.setOnClickListener {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse(link)
startActivity(intent)
}
Logcat or error
logcat is what I think makes the application so it doesn't display the desired data, how to solve must-revalidate data ? because I think because of it I cant show the data from API
Related
1) This is the create campaign activity which creates the campaign and candidate
class CreateCampaignActivity : AppCompatActivity() {
private lateinit var startDateTimeTextView: TextView
private lateinit var endDateTimeTextView: TextView
private lateinit var titleEditText: TextInputEditText
private lateinit var db: FirebaseFirestore
private lateinit var candidate1Text: TextInputEditText
private lateinit var candidate2Text: TextInputEditText
private lateinit var candidate3Text: TextInputEditText
private lateinit var addCampaignButton : Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_create_campaign)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
supportActionBar!!.title = "Create New Campaign"
titleEditText = findViewById(R.id.textTitle)
startDateTimeTextView = findViewById(R.id.start_date_time)
endDateTimeTextView = findViewById(R.id.end_date_time)
addCampaignButton = findViewById(R.id.btnAddCampaign)
candidate1Text = findViewById(R.id.textCandidate1)
candidate2Text = findViewById(R.id.textCandidate2)
candidate3Text = findViewById(R.id.textCandidate3)
db = FirebaseFirestore.getInstance()
addCampaignButton.setOnClickListener {
val title = titleEditText.text.toString().trim()
val startDateTime = startDateTimeTextView.text.toString().trim()
val endDateTime = endDateTimeTextView.text.toString().trim()
val candidate1Name = candidate1Text.text.toString().trim()
val candidate2Name = candidate2Text.text.toString().trim()
val candidate3Name = candidate3Text.text.toString().trim()
if (title.isEmpty() || startDateTime.isEmpty() || endDateTime.isEmpty() || candidate1Name.isEmpty() || candidate2Name.isEmpty() || candidate3Name.isEmpty()) {
Toast.makeText(this#CreateCampaignActivity, "Please fill up empty fields", Toast.LENGTH_SHORT).show()
} else if (!isEndTimeValid(startDateTime, endDateTime)) {
// Show error message or toast indicating that end time must be after start time
Toast.makeText(this#CreateCampaignActivity, "The end time must be after start time", Toast.LENGTH_SHORT).show()
} else {
val format = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US)
val startTimestamp = Timestamp(format.parse(startDateTime)!!)
val endTimestamp = Timestamp(format.parse(endDateTime)!!)
val campaign = Campaign(
id = UUID.randomUUID().toString(),
title = title,
startDateTime = startTimestamp,
endDateTime = endTimestamp,
candidate1 = Candidate(
id = UUID.randomUUID().toString(),
name = candidate1Name
),
candidate2 = Candidate(
id = UUID.randomUUID().toString(),
name = candidate2Name
),
candidate3 = Candidate(id = UUID.randomUUID().toString(), name = candidate3Name)
)
// Add the campaign to the Firestore database
db.collection("campaigns")
.add(campaign)
.addOnSuccessListener { documentReference ->
campaign.id = documentReference.id
Log.d(
TAG,
"Campaign successfully added to Firestore with ID: ${documentReference.id}"
)
// Show success message or toast indicating that the campaign was successfully added
Toast.makeText(this#CreateCampaignActivity, "Campaign successfully added", Toast.LENGTH_SHORT).show()
// Clear the input fields
titleEditText.setText("")
startDateTimeTextView.text = ""
endDateTimeTextView.text = ""
candidate1Text.setText("")
candidate2Text.setText("")
candidate3Text.setText("")
// Navigate back to the previous activity
finish()
}
.addOnFailureListener { e ->
Log.w(TAG, "Error adding campaign to Firestore", e)
// Show error message or toast indicating that there was an error adding the campaign
Toast.makeText(this#CreateCampaignActivity, "Error adding campaign", Toast.LENGTH_SHORT).show()
}
}
startDateTimeTextView.setOnClickListener {
showStartDateTimeDialog()
}
endDateTimeTextView.setOnClickListener {
showEndDateTimeDialog()
}
}
}
private fun showStartDateTimeDialog() {
// Code to show the DatePicker and TimePicker dialogs
val calendar = Calendar.getInstance()
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, day ->
calendar.set(Calendar.YEAR, year)
calendar.set(Calendar.MONTH, month)
calendar.set(Calendar.DAY_OF_MONTH, day)
val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
calendar.set(Calendar.HOUR_OF_DAY, hour)
calendar.set(Calendar.MINUTE, minute)
startDateTimeTextView.text =
SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()).format(calendar.time)
}
TimePickerDialog(
this#CreateCampaignActivity,
timeSetListener,
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
true
).show()
}
DatePickerDialog(
this#CreateCampaignActivity,
dateSetListener,
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)
).show()
}
private fun showEndDateTimeDialog() {
// Code to show the DatePicker and TimePicker dialogs
val calendar = Calendar.getInstance()
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, day ->
calendar.set(Calendar.YEAR, year)
calendar.set(Calendar.MONTH, month)
calendar.set(Calendar.DAY_OF_MONTH, day)
val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
calendar.set(Calendar.HOUR_OF_DAY, hour)
calendar.set(Calendar.MINUTE, minute)
endDateTimeTextView.text =
SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()).format(calendar.time)
}
TimePickerDialog(
this#CreateCampaignActivity,
timeSetListener,
calendar.get(Calendar.HOUR_OF_DAY),calendar.get(Calendar.MINUTE),
true
).show()
}
DatePickerDialog(
this#CreateCampaignActivity,
dateSetListener,
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)
).show()
}
private fun isEndTimeValid(startDateTime: String, endDateTime: String): Boolean {
// Code to check if the end time is valid (i.e. after the start time)
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault())
val startDate = sdf.parse(startDateTime)
val endDate = sdf.parse(endDateTime)
return endDate?.after(startDate) ?: false
}
companion object {
private const val TAG = "CreateCampaignActivity"
}
}
2) This is the edit campaign Activity to edit and delete campaign
class EditCampaignActivity : AppCompatActivity() {
private lateinit var datetimeTextView: TextView
private lateinit var titleEditText: TextInputEditText
private lateinit var db: FirebaseFirestore
private lateinit var candidate1Text: TextInputEditText
private lateinit var candidate2Text: TextInputEditText
private lateinit var candidate3Text: TextInputEditText
private lateinit var editCampaign : Button
private lateinit var delCampaign: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_edit_campaign)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
supportActionBar!!.title = "Edit Campaign"
titleEditText = findViewById(R.id.textTitle)
datetimeTextView = findViewById(R.id.DateTime)
delCampaign = findViewById(R.id.btndelCampaign)
editCampaign = findViewById(R.id.btnSaveCampaign)
db = FirebaseFirestore.getInstance()
candidate1Text = findViewById(R.id.textCandidate1)
candidate2Text = findViewById(R.id.textCandidate2)
candidate3Text = findViewById(R.id.textCandidate3)
intent.getStringExtra("CAMPAIGN_ID")
val campaign = intent.getParcelableExtra<Campaign>("CAMPAIGN_DATA")
if (campaign != null) {
intent.putExtra("CAMPAIGN_ID", campaign.id)
}
if (campaign != null) {
titleEditText.setText(campaign.title)
}
if (campaign != null) {
datetimeTextView.text = campaign.endDateTime.toDate().toString()
}
if (campaign != null) {
candidate1Text.setText(campaign.candidate1.name)
}
if (campaign != null) {
candidate2Text.setText(campaign.candidate2.name)
}
if (campaign != null) {
candidate3Text.setText(campaign.candidate3.name)
}
//Update function
editCampaign.setOnClickListener {
// Update the fields of the Campaign object
val updatedTitle = titleEditText.text.toString()
val updatedCandidate1 = candidate1Text.text.toString()
val updatedCandidate2 = candidate2Text.text.toString()
val updatedCandidate3 = candidate3Text.text.toString()
campaign?.apply {
title = updatedTitle
endDateTime = Timestamp.now()
candidate1.name = updatedCandidate1
candidate2.name = updatedCandidate2
candidate3.name = updatedCandidate3
}
if (campaign != null) {
db.collection("campaigns").document(campaign.id)
.update(mapOf(
"title" to updatedTitle,
"endDateTime" to Timestamp.now(),
"candidate1" to mapOf(
"name" to updatedCandidate1
),
"candidate2" to mapOf(
"name" to updatedCandidate2
),
"candidate3" to mapOf(
"name" to updatedCandidate3
)
))
.addOnSuccessListener {
// Update successful, show a message to the user
Toast.makeText(this, "Campaign updated", Toast.LENGTH_SHORT).show()
}
.addOnFailureListener {
// Update failed, show an error message
Toast.makeText(this, "Error updating campaign: $it", Toast.LENGTH_SHORT).show()
}
}
// Confirm the edit action with the user
AlertDialog.Builder(this)
.setTitle("Edit Campaign")
.setMessage("Are you sure you want to save the changes to this campaign?")
.setPositiveButton("Yes") { _, _ ->
// Navigate back to the OrganiserActivity
finish()
}
.setNegativeButton("No", null)
.show()
}
// perform delete function
delCampaign.setOnClickListener {
// Show a message dialog to confirm the delete action
AlertDialog.Builder(this)
.setTitle("Delete Campaign")
.setMessage("Are you sure you want to delete this campaign?")
.setPositiveButton("Yes") { _, _ ->
if (campaign != null) {
deleteCampaign(campaign)
}
}
.setNegativeButton("No", null)
.show()
}
}
private fun deleteCampaign(campaign: Campaign) {
db.collection("campaigns").document(campaign.id).delete()
.addOnSuccessListener {
// Navigate back to the OrganiserActivity
finish()
}
.addOnFailureListener { e ->
// Show an error message
Toast.makeText(this, "Error deleting campaign: ${e.message}", Toast.LENGTH_SHORT).show()
}
}
}
The problem is I can't perform the delete and update function in the edit campaign activity. Whenever I created a new campaign from createCampaignActivity, I tried to edit the campaign and it states in the message dialog that firestore database has no document to update even though the document exists in the firestorm. How to solve this issue?
This is my code to sent notification of new message in a chat ro all the chats participants:
private inner class SentNotificationToUserAsyncTask(
val boardName:String,
val textMessage: String, val token: ArrayList<String>
)
: AsyncTask<Any, Void, String>() {
override fun onPreExecute() {
super.onPreExecute()
showProgressDialog()
}
override fun doInBackground(vararg params: Any?): String {
var result: String
var connection: HttpURLConnection? = null
try {
val url = URL(Constans.FCM_BASE_URL)
connection = url.openConnection() as HttpURLConnection
connection.doOutput = true
connection.doInput = true
connection.requestMethod = "POST"
/**
* Sets the general request property. If a property with the key already
* exists, overwrite its value with the new value.
*/
connection.setRequestProperty("Content-Type", "application/json")
connection.setRequestProperty("charset", "utf-8")
connection.setRequestProperty("Accept", "application/json")
connection.setRequestProperty(
Constans.FCM_AUTHORIZATION, "${Constans.FCM_KEY}=${Constans.FCM_SERVER_KEY}",
)
connection.useCaches = false
val wr = DataOutputStream(connection.outputStream)
val jsonRequest = JSONObject()
val dataObject = JSONObject()
dataObject.put(Constans.FCM_KEY_TITLE,"${boardName}: ")
dataObject.put(Constans.FCM_KEY_MESSAGE,textMessage )
jsonRequest.put(Constans.FCM_KEY_DATA, dataObject)
jsonRequest.put(Constans.FCM_KEY_TO, token)
wr.writeBytes(jsonRequest.toString())
wr.flush()
wr.close()
val httpResult:Int = connection.responseCode
if (httpResult == HttpURLConnection.HTTP_OK){
val inputStream = connection.inputStream
val reader = BufferedReader(
InputStreamReader(
inputStream)
)
val sb = StringBuilder()
var line: String?
try {
while (reader.readLine().also{ line=it} !=null ){
sb.append(line+"\n")
}
}catch (e: IOException){
e.printStackTrace()
}finally {
try {
inputStream.close()
}catch (e: IOException){
e.printStackTrace()
}
}
result = sb.toString()
}else{
result = connection.responseMessage
}
}catch (e: SocketTimeoutException){
e.printStackTrace()
result = "ERROR : "+ e.printStackTrace()
}finally {
connection?.disconnect()
}
return result
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
hideProgressDialog()
}
}
The class that handling the notification:
class MyFirebaseMessagingService: FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
Log.d("onMessageReceived","FROM: ${remoteMessage.from}")
remoteMessage.data.isNotEmpty().let {
Log.d("onMessageReceived","Message data: ${remoteMessage.data}")
val title = remoteMessage.data[Constans.FCM_KEY_TITLE]!!
val message = remoteMessage.data[Constans.FCM_KEY_MESSAGE]!!
sentNotification(title,message)
}
remoteMessage.notification.let {
Log.d("onMessageReceived","Message notification body: ${it?.body}")
}
}
override fun onNewToken(token: String) {
super.onNewToken(token)
Log.e("onNewToken", "Refresh token $token")
sentResitrationToServer(token)
}
private fun sentResitrationToServer(token: String?){
}
private fun sentNotification(title: String,messageBody: String){
val intent = if (FireStore().getCurrentUid().isNotEmpty()) {
Intent(this, MainActivity::class.java)
} else {
Intent(this, signInActivity::class.java)
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_CLEAR_TASK)
val pendingIntent = PendingIntent.getActivity(this,
0,intent,PendingIntent.FLAG_ONE_SHOT)
val channelId = this.resources.getString(R.string.deafult_notification_channel_id)
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
val notificationBuilder = NotificationCompat.Builder(
this,channelId
).setSmallIcon(R.drawable.ic_baseline_android_24)
.setContentTitle(title)
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_MAX)
val notificationManager = getSystemService(
Context.NOTIFICATION_SERVICE
) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
val channel = NotificationChannel(channelId,
"channel MessagePiegon title",
NotificationManager.IMPORTANCE_DEFAULT)
notificationManager.createNotificationChannel(channel)
}
notificationManager.notify(0,notificationBuilder.build())
}
}
The notification will work if I would sent one token instead of Array list of tokens,
what do I need to change in order to sent notification to few users?
If sombody have an idea it would be very helpful
I am trying to get the user uid after creating an account, so I can create a document on Firestore with the uid as document id. The problem is that I get only null, everything is working fine and I'm able to sign the user and receive the code but the uid is always null.
I know I'm accessing the uid before it's initialized because it takes time to restore the authentication state when the app starts so any idea how to wait for it until it's initialized?
First of all, if the data entered is correct then we call login() function, then we send the verification code, when the code is sent inside the onCodeSent(), the method we call uploadSelectedImageToFirebaseStorage() to upload the user image then we call saveUserToDatabase() function, and here is the problem. Inside the saveUserToDatabase() function, the UID is always null no matter what I tried, am I missing something?
#file:Suppress("DEPRECATION")
class SignUpActivity : AppCompatActivity() {
private lateinit var binding: ActivitySignUpBinding
private lateinit var auth: FirebaseAuth
private lateinit var callbacks: PhoneAuthProvider.OnVerificationStateChangedCallbacks
lateinit var storedVerificationId: String
lateinit var resendToken: PhoneAuthProvider.ForceResendingToken
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySignUpBinding.inflate(LayoutInflater.from(this))
auth = FirebaseAuth.getInstance()
setContentView(binding.root)
val flProfilePicture = binding.frameProfilePicture
val tilUserName = binding.tilUserName
val tilPhoneNumber = binding.tilPhoneNumber
val startButton = binding.startButton
val currentUser = auth.currentUser
if (currentUser != null) {
val intent = Intent(this#SignUpActivity, MainChatsActivity::class.java)
startActivity(intent)
finish()
}
callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) { }
override fun onVerificationFailed(e: FirebaseException) { }
override fun onCodeSent(
verificationId: String,
token: PhoneAuthProvider.ForceResendingToken,
) {
Toast.makeText(baseContext, "Code Sent", Toast.LENGTH_SHORT).show()
storedVerificationId = verificationId
resendToken = token
val intent = Intent(applicationContext, AuthenticatePhoneActivity::class.java)
intent.putExtra("storedVerificationId", storedVerificationId)
uploadSelectedImageToFirebaseStorage()
startActivity(intent)
finish()
}
}
flProfilePicture.setOnClickListener {
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
startActivityForResult(intent, 0)
}
startButton.setOnClickListener {
if (TextUtils.isEmpty(tilUserName.text.toString())) {
tilUserName.error = "Enter valid Name"
}
if (TextUtils.isEmpty(tilPhoneNumber.text.toString())) {
tilPhoneNumber.error = "Enter valid phone number"
} else {
val userName: String = tilUserName.text.toString()
val userPhoneNumber: String = tilPhoneNumber.text.toString()
login()
}
}
}
private var selectedProfilePicture: Uri? = null
#Deprecated("Deprecated in Java")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 0 && data != null) {
selectedProfilePicture = data.data
val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, selectedProfilePicture)
val flProfilePicture = binding.frameProfilePicture
val selectedCircleFrame = binding.selectedPictureCircleFrame
selectedCircleFrame.setImageBitmap(bitmap)
flProfilePicture.alpha = 0f
}
}
private fun login() {
val mobileNumber = binding.tilPhoneNumber
val number = mobileNumber.text.toString().trim()
if (number.isNotEmpty()) {
sendVerificationCode(number)
} else {
mobileNumber.error = "Enter a valid phone number"
}
}
private fun sendVerificationCode(number: String) {
val options = PhoneAuthOptions.newBuilder(auth)
.setPhoneNumber(number)
.setTimeout(60L, TimeUnit.SECONDS)
.setActivity(this)
.setCallbacks(callbacks)
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
private fun uploadSelectedImageToFirebaseStorage() {
if (selectedProfilePicture == null) {
return
}
val fileName = UUID.randomUUID().toString()
val ref = FirebaseStorage.getInstance().getReference("/images/$fileName")
ref.putFile(selectedProfilePicture!!)
.addOnSuccessListener {
ref.downloadUrl.addOnSuccessListener {
it.toString()
Log.d("SignUpActivity", "image uploaded successfully")
saveUserToDatabase(it.toString())
}
}
.addOnFailureListener {
saveUserToDatabase(it.toString())
}
}
private fun saveUserToDatabase(profileImageUrl: String) {
val tilUserName = binding.tilUserName.text.toString()
val tilPhoneNumber = binding.tilPhoneNumber.text.toString()
val uid = FirebaseAuth.getInstance().uid.toString()
val database = Firebase.database("https://blend-4a9e4-default-rtdb.asia-southeast1.firebasedatabase.app")
val myRef = database.getReference("/users/$uid")
val user = User(uid, tilPhoneNumber, tilUserName, profileImageUrl)
Log.d("currentUser", uid)
myRef.setValue(user)
.addOnFailureListener {
Toast.makeText(baseContext, "Something went wrong, try again.", Toast.LENGTH_SHORT).show()
}
}
}
It successfully shows notifications when the app is open. It shows even when the app is in the background. When I close the app it doesn't show up anymore. I don't want to use FCM. because I want to remember this when doing other applications. In a video, she said that the service above Android 8 does not work permanently, and that startForeground () should be used as a solution for this.But I don't want to use it because it creates a permanent notification on top
class MyFirebaseMessagingService : Service() {
private val channelId = "notification_channel"
private val channelName = "com.dombikpanda.doktarasor.service"
private val notificationTitle = "Sorunuz Cevaplanmıştır"
private val notificationMessage =
"Doktor tarafından sorunuz cevaplanmıştır.Görmek için tıklayınız"
private var importance = 0
private var notifManagerId = 0
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
questionNotification()
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
}
override fun onCreate() {
createNotifChannel()
super.onCreate()
}
private val crudRepository = CrudRepository()
private fun questionNotification() {
val shared = getSharedPreferences("kontrol", MODE_PRIVATE)
val control = shared.getLong("date", 0)
val collection = Firebase.firestore.collection("questions")
collection
.addSnapshotListener { value, error ->
error.let {
}
value?.let { result ->
for (document in result) {
if (document["userid"] == crudRepository.getFirebaseAuth().uid) {
if (document["cevapdurum"] == true && document["messageDurum"] == true && document["date"] == control) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotification()
}
break
}
}
}
}
}
}
private fun createNotifChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
importance = NotificationManager.IMPORTANCE_HIGH //normal high
val notificationChannel =
NotificationChannel(channelId, channelName, importance).apply {
description = notificationMessage
}
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.createNotificationChannel(notificationChannel)
}
}
#RequiresApi(Build.VERSION_CODES.O)
private fun createNotification() {
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent: PendingIntent =
PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
val notification = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_stat_name)
.setContentTitle(notificationTitle)
.setContentText(notificationMessage)
.setAutoCancel(true)
.setOnlyAlertOnce(true)
.setStyle(NotificationCompat.DecoratedCustomViewStyle())
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setVibrate(longArrayOf(1000, 1000, 1000, 1000))
.setSound(Settings.System.DEFAULT_NOTIFICATION_URI)
.setContentIntent(pendingIntent)
with(NotificationManagerCompat.from(this)) {
notify(notifManagerId, notification.build())
notifManagerId++
}
}
}
This is a simple chat messaging app, using Firebase Realtime Database and the Authentication. I have successfully created the database, but I cannot fetch the message from one user to another. Because, when I send the message/click the send button, it creates different nodes, I think its a string node with quotation mark in the name. The node structure I created is user-messages --> fromId(current user uid) --> toUid(to whom the messages are sent).
To make more clear explanation, this is the screenshot of what happened.
I think the problem is, it creates a different nodes with the "uid", which means string. So the database has two nodes, one with the "...", and the other the normal one. For some info, I use some library such as Picasso image load, groupie, and parcelize.
This is the source code for the ChatLogActivity
import...
class ChatLogActivity : AppCompatActivity() {
companion object {
val TAG = "ChatLog"
}
val adapter = GroupAdapter<ViewHolder>()
var toUser: User? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat_log)
recyclerview_chat_log.adapter = adapter
toUser = intent.getParcelableExtra(NewMessageActivity.USER_KEY)
titleChatLog.text = toUser?.nama
listenForMessages()
arrowBack.setOnClickListener {
finish()
}
send_button_chat_log.setOnClickListener {
Log.d(TAG, "Attempt to send message.....")
performSendMessage()
}
}
private fun listenForMessages() {
val fromId = FirebaseAuth.getInstance().uid
val toId = toUser?.uid
val ref = FirebaseDatabase.getInstance().getReference("/user-messages/$fromId/$toId")
ref.addChildEventListener(object : ChildEventListener {
override fun onChildAdded(p0: DataSnapshot, p1: String?) {
val chatMessage = p0.getValue(ChatMessage::class.java)
if (chatMessage != null) {
Log.d(TAG, chatMessage.text)
if (chatMessage.fromId == FirebaseAuth.getInstance().uid) {
val currentUser = LatestMessageActivity.currentUser?: return
adapter.add(ChatFromItem(chatMessage.text, currentUser))
} else {
adapter.add(ChatToItem(chatMessage.text, toUser!!))
}
}
}
override fun onCancelled(p0: DatabaseError) {
}
override fun onChildChanged(p0: DataSnapshot, p1: String?) {
}
override fun onChildMoved(p0: DataSnapshot, p1: String?) {
}
override fun onChildRemoved(p0: DataSnapshot) {
}
})
}
private fun performSendMessage() {
val text = edittext_chat_log.text.toString()
val fromId = FirebaseAuth.getInstance().uid
val user = intent.getParcelableExtra<User>(NewMessageActivity.USER_KEY)
val toId = user.uid
val ref = FirebaseDatabase.getInstance().getReference("/user-messages/$fromId/$toId").push()
val toRef = FirebaseDatabase.getInstance().getReference("/user-messages/$toId/$fromId ").push()
if (fromId == null) return
val chatMessage = ChatMessage(ref.key!!, text, fromId, toId, System.currentTimeMillis() / 1000)
ref.setValue(chatMessage)
.addOnSuccessListener {
Log.d(TAG, "Save our chat message: ${ref.key}")
edittext_chat_log.text.clear()
recyclerview_chat_log.scrollToPosition(adapter.itemCount - 1)
}
toRef.setValue(chatMessage)
}
}
class ChatFromItem(val text: String, val user: User) : Item<ViewHolder>() {
override fun getLayout(): Int {
return R.layout.chat_from_row
}
override fun bind(viewHolder: ViewHolder, position: Int) {
val uri = user.profileImageUrl
val targetImageView = viewHolder.itemView.imageViewFrom
Picasso.get().load(uri).into(targetImageView)
viewHolder.itemView.textViewFrom.text = text
}
}
class ChatToItem(val text: String, val user: User) : Item<ViewHolder>() {
override fun getLayout(): Int {
return R.layout.chat_to_row
}
override fun bind(viewHolder: ViewHolder, position: Int) {
val uri = user.profileImageUrl
val targetImageView = viewHolder.itemView.imageViewTo
Picasso.get().load(uri).into(targetImageView)
viewHolder.itemView.textViewTo.text = text
}
}
And this is the ChatMessage, class that store the messages.
class ChatMessage(val id:String, val text: String, val fromId: String, val toId: String, val timeStamp: Long) {
constructor(): this("", "", "", "", -1)
}
I'm very glad if anyone can help this problem. Thank you