Firebase Firestore not connecting - android

I have a problem that drives me crazy. I try to populate Firestore db with some tests fields. First time when i tried it worked perfectly, i did some modifications and nothing seems to work right now. The problem is that set/add are never called whatever i do. I can create and log in without problems. I don't post layout because is self explanatory. A button that set data: add_ddb. Thanks.
class StartingActivity : AppCompatActivity() {
private lateinit var firebaseFirestore: FirebaseFirestore
private val firebaseAuth by lazy { FirebaseAuth.getInstance() }
private var uid = firebaseAuth.currentUser?.uid
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_starting)
firebaseFirestore = FirebaseFirestore.getInstance()
setSupportActionBar(toolbar)
supportActionBar?.apply {
setDisplayHomeAsUpEnabled(true)
setHomeAsUpIndicator(R.drawable.ic_menu_black_24dp)
}
add_ddb.setOnClickListener {vieew->
val detail = mutableMapOf<String, Any>()
detail.put("nameOfDocument","sdsad")
detail.put("documentNumber","sdasdvc")
firebaseFirestore.collection("users").document("asda").
set(detail).addOnSuccessListener {
Toast.makeText(this,"sdasdasdasda",Toast.LENGTH_SHORT).show()
}.addOnFailureListener {
Toast.makeText(this,it.toString(),Toast.LENGTH_SHORT).show()
}
}
nav_view.apply {
setNavigationItemSelectedListener {
it.isChecked = true
drawer_layout.closeDrawers()
when (it.itemId) {
R.id.nav_signOut -> {
signOut()
true
}
else -> false
}
}
}
recycler.apply {
layoutManager = LinearLayoutManager(applicationContext)
}
DisplayInRecycler(this).displayDetails(recycler)
fab.setOnClickListener {
startActivity(intentFor<ActivityAdd>())
}
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
return when (item?.itemId) {
android.R.id.home -> {
drawer_layout.openDrawer(Gravity.START)
true
}
else -> super.onOptionsItemSelected(item)
}
}
fun signOut(){
FirebaseAuth.getInstance().signOut()
startActivity(intentFor<SignInActivity>().clearTop().clearTask())
finish()
}
}

Related

Get a filtred list from database

Well, I'm using Room Database and I need pick a filtred list by one property, that is isSelected: Boolean. I need it to put in a variable selectedTasksList to show programmatically a menuItem based on selection mode that is enabled if the selectedTasksList isn't empty and after this, to delete the tasks selecteds. But first I need setup the selectedTasksList putting into the tasks that is isSelected = true.
Some Idea???
My Object:
data class Task(
#PrimaryKey(autoGenerate = true)
val uid: Int,
[...]
#ColumnInfo
var isSelected: Boolean
)
Activity:
class ListTaskActivity : AppCompatActivity() {
private lateinit var binding: ActivityListTaskBinding
lateinit var viewModel: ListTaskViewModel
private lateinit var adapter: ListTaskAdapter
private var deleteMenu: Menu? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityListTaskBinding.inflate(layoutInflater)
viewModel = ListTaskViewModel(application)
setContentView(binding.root)
viewModel.taskList.observe(
this
) { tasks ->
adapter.addTask(tasks)
}
viewModel.selectionMode.observe(
this
) { selectionMode ->
changeTrashVisibilityBasedOnSelectionMode()
}
changeTrashVisibilityBasedOnSelectionMode()
setupList()
}
private fun changeTrashVisibilityBasedOnSelectionMode() {
this.deleteMenu?.findItem(R.id.menu_delete_action)?.isVisible =
viewModel.selectionMode.value == true
}
private fun setupList() {
adapter = ListTaskAdapter(
selectionTaskCallback = { task ->
viewModel.syncSelection(task) }
)
binding.recyclerViewTasks.layoutManager = LinearLayoutManager(this)
binding.recyclerViewTasks.adapter = adapter
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.delete_menu, menu)
this.deleteMenu = menu
this.deleteMenu?.findItem(R.id.menu_delete_action)?.isVisible = false
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if(item.itemId == R.id.menu_delete_action){
setupConfirmationDialog()
}
return super.onOptionsItemSelected(item)
}
}
ViewModel:
class ListTaskViewModel(private val context: Application) : AndroidViewModel(context) {
val taskList = MutableLiveData<List<Task>>()
val selectionMode = MutableLiveData<Boolean>(false)
private var selectedTasks = ArrayList<Task>()
fun syncSelection(task: Task) {
if (task.isTaskSelected()) {
val exists = selectedTasks.any { it.uid == task.uid }
if (!exists) {
selectedTasks.add(task)
}
} else {
selectedTasks.remove(task)
}
if (isSelectionModeEnabled() != selectionMode.value) {
selectionMode.value = isSelectionModeEnabled()
}
}
fun deleteSelectedTasks(context: Context){
viewModelScope.launch {
selectedTasks.forEach {
DataBaseConnect.getTaskDao(context).deleteTask(it)
}
selectionMode.postValue(false)
selectedTasks.clear()
refreshScreen()
}
}
fun isTaskListEmpty(): Boolean? {
return taskList.value?.isEmpty()
}
fun isSelectionModeEnabled(): Boolean {
return selectedTasks.isNotEmpty()
}
fun update(task: Task) {
viewModelScope.launch {
DataBaseConnect.getTaskDao(context).updateTask(task)
}
}
}
In order to query a table and filter rows by a column, we need to use the SELECT keyword.
Using Room DB we need to use the #Query annotation that allows us to perform custom SQLite queries. More about it here.
Adding this function to your dao should do the trick (assuming your table name is task):
#Query("SELECT * FROM task WHERE isSelected = 0")
fun getSelectedTasks(): List<Task>
Notice that we compare isSelected to 0. This is because SQLite using 0/1 for booleans.

how can I add when/if to buttons (viewBinding)

I am trying to add when or if statement to my code. for example, once I press the first/second button it will change the colors of button,button2 to red. and if I just press the button3 it will become green. If there is also a way more easy method I am looking for it.
`binding.button.isSelected
binding.button.setOnClickListener {
binding.button.setBackgroundColor(R.drawable.red)
}
binding.button2.isSelected
binding.button2.setOnClickListener {
binding.button2.setBackgroundColor(R.drawable.red)
}
binding.button3.isSelected
binding.button3.setOnClickListener {
binding.button3.setBackgroundColor(R.drawable.green)
}`
EDIT
I did figure out thanks to #Tonnie, I had to change a few lines to work it as I intended. this is the code;
var isRedButtonsClicked = true
var isGreenButtonClicked = true
fun colorButtonsRed() {
binding.button.setBackgroundColor(R.color.red)
binding.button2.setBackgroundColor(R.color.red)
}
fun colorButtonGreen() {
binding.button3.setBackgroundColor(R.color.green)
}
binding.button.setOnClickListener {
when (isRedButtonsClicked) {
true -> colorButtonsRed()
}
}
binding.button2.setOnClickListener {
when (isRedButtonsClicked) {
true -> colorButtonsRed()
}
}
binding.button3.setOnClickListener {
when (isGreenButtonClicked) {
true -> colorButtonGreen()
}
}
setContentView(binding.root)
I get you, you need the Buttons to work simultaneously.
In this case try to build onto this code to suit your needs.
First create a var which I name isRedButtonsSelected to monitor
Button States.
Add 2 functions to switch colors btw Green/Red and Gray (or any
color you choose)
Add 3 onClickListeners to change button Colors
The code
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var isRedButtonsClicked = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
binding.button.setOnClickListener {
when (isRedButtonsClicked) {
true -> colorButtons()
false -> unColorButtons()
}
}
binding.button2.setOnClickListener {
when (isRedButtonsClicked) {
true -> colorButtons()
false -> unColorButtons()
}
}
binding.button3.setOnClickListener {
when (isRedButtonsClicked) {
true -> colorButtons()
false -> unColorButtons()
}
}
setContentView(binding.root)
}
private fun colorButtons() {
binding.button.setBackgroundColor(Color.GRAY)
binding.button2.setBackgroundColor(Color.GRAY)
binding.button3.setBackgroundColor(Color.GREEN)
isRedButtonsClicked = false
}
private fun unColorButtons() {
binding.button.setBackgroundColor(Color.RED)
binding.button2.setBackgroundColor(Color.RED)
binding.button3.setBackgroundColor(Color.GRAY)
isRedButtonsClicked = true
}
}
#Gabe Sechan is right. You should use setBackgroundColor() with a Color Constant.
I am not sure what isSelected is intended to do but this code should work.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
binding.button.setOnClickListener {
binding.button.setBackgroundColor(Color.RED)
}
binding.button2.setOnClickListener {
binding.button2.setBackgroundColor(Color.RED)
}
binding.button3.setOnClickListener {
binding.button3.setBackgroundColor(Color.GREEN)
}
setContentView(binding.root)
}

onResume does not worked in viewmodel

my data is fetched only when it is created...im using viewmodel...when press back button it doesnt update the previous data..onresume is not working in this...
i refered this but none of those helped--> Reacting to activity lifecycle in ViewModel
i need help
thanks in advance
activity:--
class MyAccount : BaseClassActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.myaccount)
var mActionBarToolbar = findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbartable);
setSupportActionBar(mActionBarToolbar);
setEnabledTitle()
val resetbutton=findViewById<Button>(R.id.resetpwd)
resetbutton.setOnClickListener {
val i=Intent(applicationContext,
ResetPasswordActivity::class.java)
startActivity(i)
}
val editbutton=findViewById<Button>(R.id.editdetail)
editbutton.setOnClickListener {
val i=Intent(applicationContext, EditProfile::class.java)
startActivity(i)
}
hello()
}
override fun onResume() {
super.onResume()
hello()
}
fun hello(){
val first_name = findViewById<TextView>(R.id.firstname)
val last_name = findViewById<TextView>(R.id.lastname)
val emailuser = findViewById<TextView>(R.id.emailuser)
val phone_no = findViewById<TextView>(R.id.phone_no)
val birthday = findViewById<TextView>(R.id.birthday)
val image=findViewById<ImageView>(R.id.imageprofile)
val model = ViewModelProvider(this)[MyAccountViewModel::class.java]
model.viewmodel?.observe(this, object : Observer<My_account_base_response> {
override fun onChanged(t: My_account_base_response?) {
first_name.setText(t?.data?.user_data?.first_name)
last_name.setText(t?.data?.user_data?.last_name)
emailuser.setText(t?.data?.user_data?.email)
phone_no.setText(t?.data?.user_data?.phone_no).toString()
birthday.setText(t?.data?.user_data?.dob).toString()
Glide.with(applicationContext).load(t?.data?.user_data?.profile_pic)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.placeholder(R.drawable.ic_launcher_foreground)
.into(image)
}
})
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
NavUtils.navigateUpFromSameTask(this)
true
}
else -> super.onOptionsItemSelected(item)
}
}}
viewmodel:--
class MyAccountViewModel(context: Application) :AndroidViewModel(context),LifecycleObserver{
private var MyAccountViewModels: MutableLiveData<My_account_base_response>? = null
val viewmodel: MutableLiveData<My_account_base_response>?
get() {
if (MyAccountViewModels == null) {
MyAccountViewModels = MutableLiveData<My_account_base_response>()
loadviewmodel()
}
return MyAccountViewModels
}
private fun loadviewmodel(){
val token :String = SharedPrefManager.getInstance(getApplication()).user.access_token.toString()
RetrofitClient.instance.fetchUser(token)
.enqueue(object : Callback<My_account_base_response> {
override fun onFailure(call: Call<My_account_base_response>, t: Throwable) {
Log.d("res", "" + t)
}
override fun onResponse(
call: Call<My_account_base_response>,
response: Response<My_account_base_response>
) {
var res = response
if (res.body()?.status == 200) {
MyAccountViewModels!!.value = response.body()
} else {
try {
val jObjError =
JSONObject(response.errorBody()!!.string())
Toast.makeText(getApplication(),
jObjError.getString("user_msg"),
Toast.LENGTH_LONG).show()
} catch (e: Exception) {
Log.e("errorrr", e.message)
}
}
}
})
}}
There are bunch of things wrong here, so let me provide you refactored code and explanation as much as I would be able to..
Activity:
class MyAccount : BaseClassActivity() {
private val mActionBarToolbar by lazy { findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbartable) }
private val resetbutton by lazy { findViewById<Button>(R.id.resetpwd) }
private val editbutton by lazy { findViewById<Button>(R.id.editdetail) }
private val first_name by lazy { findViewById<TextView>(R.id.firstname) }
private val last_name by lazy { findViewById<TextView>(R.id.lastname) }
private val emailuser by lazy { findViewById<TextView>(R.id.emailuser) }
private val phone_no by lazy { findViewById<TextView>(R.id.phone_no) }
private val birthday by lazy { findViewById<TextView>(R.id.birthday) }
private val image by lazy { findViewById<ImageView>(R.id.imageprofile) }
lateinit var model: MyAccountViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.myaccount)
setSupportActionBar(mActionBarToolbar)
setEnabledTitle()
model = ViewModelProvider(this)[MyAccountViewModel::class.java]
resetbutton.setOnClickListener {
val i = Intent(applicationContext, ResetPasswordActivity::class.java)
startActivity(i)
}
editbutton.setOnClickListener {
val i = Intent(applicationContext, EditProfile::class.java)
startActivity(i)
}
model.accountResponseData.observe(this, object : Observer<My_account_base_response> {
override fun onChanged(t: My_account_base_response?) {
first_name.setText(t?.data?.user_data?.first_name)
last_name.setText(t?.data?.user_data?.last_name)
emailuser.setText(t?.data?.user_data?.email)
phone_no.setText(t?.data?.user_data?.phone_no).toString()
birthday.setText(t?.data?.user_data?.dob).toString()
Glide.with(applicationContext)
.load(t?.data?.user_data?.profile_pic)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.placeholder(R.drawable.ic_launcher_foreground)
.into(image)
}
})
}
override fun onResume() {
super.onResume()
model.loadAccountData()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
NavUtils.navigateUpFromSameTask(this)
true
}
else -> super.onOptionsItemSelected(item)
}
}
}
Few notes on your activity class:
You don't need to findViewById everytime, just do it once during onCreate or do it lazily. (FYI consider using kotlin synthetics or view binding or data binding)
Initialize your viewModel during onCreate method only. (That's the best way to do it)
Also observer your LiveData from ViewModel once, it should be also from the onCreate as it's the entry point to the activity and apart from config changes this method called only once. So, it's safe to observe it over there rather than during onResume which will be called multiple times during activity lifecycle. (The main issue your code wasn't working, so as a fix you only call your API method from ViewModel during resume)
ViewModel:
class MyAccountViewModel(context: Application) : AndroidViewModel(context) {
private val _accountResponseData = MutableLiveData<My_account_base_response?>()
val accountResponseData: MutableLiveData<My_account_base_response?>
get() = _accountResponseData
init {
loadAccountData()
}
fun loadAccountData() {
val token: String = SharedPrefManager.getInstance(getApplication()).user.access_token.toString()
RetrofitClient.instance.fetchUser(token)
.enqueue(object : Callback<My_account_base_response> {
override fun onFailure(call: Call<My_account_base_response>, t: Throwable) {
Log.d("res", "" + t)
_accountResponseData.value = null
}
override fun onResponse(
call: Call<My_account_base_response>,
response: Response<My_account_base_response>
) {
var res = response
if (res.body()?.status == 200) {
_accountResponseData.value = response.body()
} else {
try {
val jObjError =
JSONObject(response.errorBody()!!.string())
Toast.makeText(
getApplication(),
jObjError.getString("user_msg"),
Toast.LENGTH_LONG
).show()
} catch (e: Exception) {
Log.e("errorrr", e.message)
}
}
}
})
}
}
Don't make initial API call along with LiveData creation, it's okay to do in most of cases but if you're updating LiveData on response of that call then it's good to make it separately like during init block.
It's good practice not to allow Ui (Activity/Fragments) to modify LiveDatas of ViewModel directly. So, that's good sign you're following such pattern by having private MutableLiveData exposed as public LiveData, but do it correctly as suggested.
Side note: Your view model doesn't need to be LifecycleObserver. LifecycleObserver is used for some custom class/component which needs to be managed by their self by silently observing/depending on activity lifecycle independently. That's not the use case of ViewModel.
The only thing that I found why your code wasn't working correctly is because you were creating & observing ViewModel & LiveData over & over again as new objects from onResume method where you called hello() method.
Let me know if something don't make sense or missing.

How to handle Flow Coroutines Asynchronous Behaviour while using API

I am trying to get The liveStatus of authStateListener using Flow Coroutines .But everytime it returns False. Below is the code with which I tried to implement the following.It follows the MVVM pattern.
Code ->
FirebaseUserFlow
open class FirebaseUserFlow() {
private val firebaseAuth = FirebaseAuth.getInstance()
private var auth: FirebaseUser? = null
#ExperimentalCoroutinesApi
fun getUserInfo(): Flow<FirebaseUser?> =
callbackFlow {
val authStateListener = FirebaseAuth.AuthStateListener {
auth = it.currentUser
}
offer(auth)
firebaseAuth.addAuthStateListener(authStateListener)
awaitClose {
firebaseAuth.removeAuthStateListener(authStateListener)
}
}
}
ViewModel
class AuthViewModel : ViewModel() {
enum class AuthenticationClass {
AUTHENTICATED,
UNAUTHENTICATED
}
#ExperimentalCoroutinesApi
val authenticationState = FirebaseUserFlow().getUserInfo().map {
Log.d("Tag","The value of the user is $it")
if (it != null) {
AuthenticationClass.AUTHENTICATED
} else {
AuthenticationClass.UNAUTHENTICATED
}
}.asLiveData()
}
The log above always returns false
Fragment
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel.authenticationState.observe(viewLifecycleOwner, Observer {authenticationstate ->
when (authenticationstate) {
AuthViewModel.AuthenticationClass.AUTHENTICATED -> {
findNavController().navigate(R.id.action_loginFragmentUser_to_homeFragment)
Log.d("TAG","Authenticated")
}
else -> Log.d("TAG","Else")
}
})
}
In the above fragment , In the onActivityCreated the liveData is observed and based on the state it navigates to the Home Fragment .
Your error is here
FirebaseAuth.AuthStateListener {
auth = it.currentUser
}
trySendBlocking(auth)
You should call offer() inside the callback.
open class FirebaseUserFlow() {
private val firebaseAuth = FirebaseAuth.getInstance()
#ExperimentalCoroutinesApi
fun getUserInfo(): Flow<FirebaseUser?> =
callbackFlow {
val authStateListener = FirebaseAuth.AuthStateListener {
trySendBlocking(it.currentUser)
}
firebaseAuth.addAuthStateListener(authStateListener)
awaitClose {
firebaseAuth.removeAuthStateListener(authStateListener)
}
}
}

RxBinding 'clicks()' method not triggering again when coming back from another activity

I am using 'RxJava binding APIs for Android UI widgets' to trigger click events on buttons or textview.
PFB code(Edited) that using to trigger the event
class BookAgentActivity : BaseActivity(), BookAgentView {
#Inject
#field:Named("activity")
lateinit var compositeDisposable: CompositeDisposable
#Inject
lateinit var bookAgentViewModelFactory: BookAgentViewModelFactory
private lateinit var bookAgentViewModel: BookAgentViewModel
private lateinit var cityLocalityJson: CityLocalitiesMO
override fun getLayoutId(): Int {
return R.layout.activity_book_agent
}
override fun initializeDagger() {
IleApplication.getRoomComponent().inject(this)
}
override fun initializeViewModel() {
bookAgentViewModel = ViewModelProviders.of(this, bookAgentViewModelFactory).get(BookAgentViewModel::class.java)
bookAgentViewModel.setView(this)
}
override fun setUpUi() {
gradientStatusBar()
cityLocalityJson = appPreferences.cityLocalitiesJson
compositeDisposable.add(bookAgentCityLocationTV.clicks().observeOn(AndroidSchedulers.mainThread()).subscribe {
startActivity(Intent(this, AreaLocalitiesActivity::class.java)
.putExtra(AppConstants.COMING_FROM_AGENT_KEY, true))
})
compositeDisposable.add(filtersButton.clicks().observeOn(AndroidSchedulers.mainThread()).subscribe {
startActivity(Intent(this, FiltersMainActivity::class.java)
.putExtra(AppConstants.FILTER_TYPE_KEY, AppConstants.AGENT_FILTER))
})
compositeDisposable.add(searchAgentsButton.clicks()
.subscribe { startActivity(Intent(this#BookAgentActivity, SearchAgentActivity::class.java)) })
}
override fun onSuccess(response: Any) {
if (response is AgentsDetailAPIResponse) {
response.let {
val agentDetailsList = it.data
if (agentDetailsList != null && agentDetailsList.size > 0) {
updateAgentPinsOnMap(agentDetailsList)
}
}
}
}
override fun onDestroy() {
super.onDestroy()
compositeDisposable.clear()
}
}
:) Above code works fine for the first time
:( But after coming back from BookAgentActivity (onBackPressed())
Click events are not working for searchAgentsButton as well as for other views too.
Have tried including combinations of other lines of code like below:
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.share()
But none of the above things are working.

Categories

Resources