Skip to content

Commit 281579e

Browse files
authored
Feature/implement firebase logout (#493)
* save cooldown time on save click to prevent accidental time cahnge on picker scroll * Update code Apps filter page, status is not required * implement displaying logged in user details and also provide logout option for googleplay variant, else hide account section in settings * implement email verification * resolve merge conflicts * show notification access revoked permission only if user enabled auto reply. Not just app installed
1 parent 846f059 commit 281579e

File tree

8 files changed

+298
-69
lines changed

8 files changed

+298
-69
lines changed

app/src/Default/java/com/parishod/watomatic/flavor/FlavorNavigator.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,15 @@ object FlavorNavigator {
1111
// Ensure login is never triggered in Default flavor
1212
return false
1313
}
14+
15+
fun startLogin(activity: Activity) {
16+
// No-op in Default flavor
17+
}
18+
19+
fun logout(activity: Activity, preferencesManager: PreferencesManager) {
20+
// Clear any login flags if set inadvertently
21+
preferencesManager.setLoggedIn(false)
22+
preferencesManager.setGuestMode(false)
23+
preferencesManager.setUserEmail("")
24+
}
1425
}

app/src/GooglePlay/java/com/parishod/watomatic/activity/login/LoginActivity.kt

Lines changed: 137 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.parishod.watomatic.activity.login
22

3+
import android.app.AlertDialog
34
import android.content.Intent
45
import android.os.Bundle
56
import android.text.Editable
@@ -11,11 +12,14 @@ import androidx.activity.result.contract.ActivityResultContracts
1112
import androidx.core.view.ViewCompat
1213
import androidx.core.view.WindowInsetsCompat
1314
import com.google.android.gms.auth.api.signin.GoogleSignIn
15+
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
1416
import com.google.android.gms.auth.api.signin.GoogleSignInClient
1517
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
1618
import com.google.android.gms.common.SignInButton
1719
import com.google.android.gms.common.api.ApiException
20+
import com.google.android.gms.tasks.Task
1821
import com.google.firebase.auth.FirebaseAuth
22+
import com.google.firebase.auth.FirebaseUser
1923
import com.google.firebase.auth.GoogleAuthProvider
2024
import com.parishod.watomatic.R
2125
import com.parishod.watomatic.activity.BaseActivity
@@ -30,6 +34,12 @@ class LoginActivity : BaseActivity() {
3034
private lateinit var auth: FirebaseAuth
3135
private lateinit var googleSignInLauncher: ActivityResultLauncher<Intent>
3236

37+
companion object {
38+
private const val PREF_USER_EMAIL = "pref_user_email"
39+
private const val EMAIL_ALREADY_EXISTS = "email address is already"
40+
private const val INVALID_CREDENTIALS = "credential is incorrect"
41+
}
42+
3343
override fun onCreate(savedInstanceState: Bundle?) {
3444
super.onCreate(savedInstanceState)
3545
binding = ActivityLoginBinding.inflate(layoutInflater)
@@ -56,37 +66,34 @@ class LoginActivity : BaseActivity() {
5666

5767
googleSignInClient = GoogleSignIn.getClient(this, gso)
5868

59-
googleSignInLauncher = registerForActivityResult(
60-
ActivityResultContracts.StartActivityForResult()
61-
) { result ->
69+
googleSignInLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
6270
if (result.resultCode == RESULT_OK) {
6371
val task = GoogleSignIn.getSignedInAccountFromIntent(result.data)
64-
try {
65-
val account = task.getResult(ApiException::class.java)
66-
account.idToken?.let { firebaseAuthWithGoogle(it) }
67-
} catch (e: ApiException) {
68-
Toast.makeText(this, "Google sign in failed: ${e.message}", Toast.LENGTH_SHORT).show()
69-
}
72+
handleGoogleSignInResult(task)
7073
}
7174
}
7275
}
7376

77+
private fun handleGoogleSignInResult(completedTask: Task<GoogleSignInAccount>) {
78+
try {
79+
val account = completedTask.getResult(ApiException::class.java)
80+
account?.idToken?.let { firebaseAuthWithGoogle(it) }
81+
} catch (e: ApiException) {
82+
Toast.makeText(this, getString(R.string.google_sign_in_failed, e.message), Toast.LENGTH_SHORT).show()
83+
}
84+
}
85+
7486
private fun firebaseAuthWithGoogle(idToken: String) {
7587
val credential = GoogleAuthProvider.getCredential(idToken, null)
7688
auth.signInWithCredential(credential)
77-
.addOnCompleteListener(this) { task ->
78-
if (task.isSuccessful) {
79-
val user = auth.currentUser
80-
user?.email?.let { email ->
81-
preferencesManager.isLoggedIn = true
82-
preferencesManager.isGuestMode = false
83-
preferencesManager.saveString("pref_user_email", email)
84-
handleSuccessfulLogin()
85-
}
86-
} else {
87-
Toast.makeText(this, "Authentication failed", Toast.LENGTH_SHORT).show()
89+
.addOnSuccessListener { authResult ->
90+
authResult.user?.email?.let { email ->
91+
handleSuccessfulAuth(email)
8892
}
8993
}
94+
.addOnFailureListener {
95+
Toast.makeText(this, getString(R.string.authentication_failed), Toast.LENGTH_SHORT).show()
96+
}
9097
}
9198

9299
private fun setupViews() {
@@ -99,43 +106,53 @@ class LoginActivity : BaseActivity() {
99106

100107
private fun setupClickListeners() {
101108
binding.btnLogin.setOnClickListener {
102-
val email = binding.etEmail.text.toString()
103-
val password = binding.etPassword.text.toString()
104-
105-
if (validateInputs(email, password)) {
106-
checkIfEmailExists(email) { exists ->
107-
if (exists) {
108-
doSignin(email, password)
109-
} else {
110-
showSignUpConfirmation(email, password)
111-
}
112-
}
113-
}
109+
handleLoginButtonClick()
114110
}
115111

116112
binding.btnGoogleSignIn.setSize(SignInButton.SIZE_WIDE)
117113
binding.btnGoogleSignIn.setOnClickListener {
118-
val signInIntent = googleSignInClient.signInIntent
119-
googleSignInLauncher.launch(signInIntent)
114+
signInWithGoogle()
120115
}
121116

122117
binding.btnContinueAsGuest.setOnClickListener {
123-
preferencesManager.isGuestMode = true
124-
navigateToMain()
118+
continueAsGuest()
125119
}
126120
}
127121

128-
fun doSignin(email: String, password: String){
129-
auth.signInWithEmailAndPassword(email, password)
130-
.addOnCompleteListener(this) { task ->
131-
if (task.isSuccessful) {
132-
handleSuccessfulAuth(email)
122+
private fun handleLoginButtonClick() {
123+
val email = binding.etEmail.text.toString()
124+
val password = binding.etPassword.text.toString()
125+
126+
if (validateInputs(email, password)) {
127+
checkIfEmailExists(email) { exists ->
128+
if (exists) {
129+
doSignin(email, password)
133130
} else {
134-
val exception = task.exception
135-
Toast.makeText(this, "Authentication failed: ${exception?.message}",
136-
Toast.LENGTH_LONG).show()
131+
createNewAccount(email, password)
137132
}
138133
}
134+
}
135+
}
136+
137+
private fun signInWithGoogle() {
138+
val signInIntent = googleSignInClient.signInIntent
139+
googleSignInLauncher.launch(signInIntent)
140+
}
141+
142+
private fun continueAsGuest() {
143+
preferencesManager.isGuestMode = true
144+
navigateToMain()
145+
}
146+
147+
private fun doSignin(email: String, password: String) {
148+
auth.signInWithEmailAndPassword(email, password)
149+
.addOnSuccessListener {
150+
checkAndSendEmailVerification(it.user)
151+
}
152+
.addOnFailureListener { exception ->
153+
Toast.makeText(this, getString(R.string.authentication_failed_with_message, exception.message),
154+
Toast.LENGTH_LONG).show()
155+
}
139156
}
140157

141158
fun checkIfEmailExists(email: String, onResult: (Boolean) -> Unit) {
@@ -151,43 +168,96 @@ class LoginActivity : BaseActivity() {
151168
}
152169

153170
private fun showSignUpConfirmation(email: String, password: String) {
154-
android.app.AlertDialog.Builder(this)
155-
.setTitle("Create New Account")
156-
.setMessage("Would you like to create a new account with this email?\n\n$email")
157-
.setPositiveButton("Create Account") { _, _ ->
171+
AlertDialog.Builder(this)
172+
.setTitle(R.string.create_new_account)
173+
.setMessage(getString(R.string.create_new_account_prompt, email))
174+
.setPositiveButton(R.string.create_account) { _, _ ->
158175
createNewAccount(email, password)
159176
}
160-
.setNegativeButton("Cancel", null)
177+
.setNegativeButton(android.R.string.cancel, null)
161178
.show()
162179
}
163180

164181
private fun createNewAccount(email: String, password: String) {
165182
auth.createUserWithEmailAndPassword(email, password)
166-
.addOnCompleteListener(this) { task ->
167-
if (task.isSuccessful) {
168-
Toast.makeText(this, "Account created successfully!", Toast.LENGTH_SHORT).show()
169-
handleSuccessfulAuth(email)
170-
} else {
171-
when {
172-
task.exception?.message?.contains("email address is already", ignoreCase = true) == true -> {
173-
Toast.makeText(this, "This email is already registered. Please try signing in.", Toast.LENGTH_LONG).show()
174-
}
175-
task.exception?.message?.contains("credential is incorrect", ignoreCase = true) == true -> {
176-
Toast.makeText(this, "Please use a valid email and a password with at least 6 characters", Toast.LENGTH_LONG).show()
177-
}
178-
else -> {
179-
Toast.makeText(this, "Failed to create account: ${task.exception?.message}",
180-
Toast.LENGTH_LONG).show()
181-
}
183+
.addOnSuccessListener {
184+
checkAndSendEmailVerification(it.user)
185+
}
186+
.addOnFailureListener { exception ->
187+
val message = when {
188+
exception.message?.contains(EMAIL_ALREADY_EXISTS, ignoreCase = true) == true -> {
189+
doSignin(email, password)
190+
// getString(R.string.email_already_registered)
191+
""
192+
}
193+
exception.message?.contains(INVALID_CREDENTIALS, ignoreCase = true) == true -> {
194+
getString(R.string.invalid_email_or_password_length)
195+
}
196+
else -> {
197+
getString(R.string.create_account_failed, exception.message)
182198
}
183199
}
200+
if(message.isNotEmpty())
201+
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
184202
}
185203
}
186204

205+
private fun checkAndSendEmailVerification(user: FirebaseUser?) {
206+
if (user != null && !user.isEmailVerified) {
207+
user.sendEmailVerification()
208+
.addOnSuccessListener {
209+
Toast.makeText(this, getString(R.string.verification_email_sent, user.email), Toast.LENGTH_SHORT).show()
210+
showVerificationDialog(user)
211+
}
212+
.addOnFailureListener { exception ->
213+
Toast.makeText(this, getString(R.string.verification_email_failed, exception.message), Toast.LENGTH_SHORT).show()
214+
}
215+
} else {
216+
user?.email?.let { handleSuccessfulAuth(it) }
217+
}
218+
}
219+
220+
private fun showVerificationDialog(user: FirebaseUser) {
221+
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
222+
builder.setTitle(getString(R.string.verify_your_email))
223+
builder.setMessage(getString(R.string.verification_dialog_message, user.email))
224+
225+
builder.setPositiveButton(getString(R.string.i_ve_verified)) { _, _ ->
226+
user.reload()
227+
.addOnSuccessListener {
228+
if (user.isEmailVerified) {
229+
Toast.makeText(this, getString(R.string.email_verified), Toast.LENGTH_SHORT).show()
230+
user.email?.let { handleSuccessfulAuth(it) }
231+
} else {
232+
Toast.makeText(this, getString(R.string.email_not_verified_yet), Toast.LENGTH_SHORT).show()
233+
showVerificationDialog(user)
234+
}
235+
}
236+
.addOnFailureListener { exception ->
237+
Toast.makeText(this, getString(R.string.verification_check_failed, exception.message), Toast.LENGTH_SHORT).show()
238+
}
239+
}
240+
241+
builder.setNeutralButton(getString(R.string.resend_email)) { _, _ ->
242+
user.sendEmailVerification()
243+
.addOnSuccessListener {
244+
Toast.makeText(this, getString(R.string.verification_email_resent, user.email), Toast.LENGTH_SHORT).show()
245+
}
246+
.addOnFailureListener { exception ->
247+
Toast.makeText(this, getString(R.string.failed_to_resend_email, exception.message), Toast.LENGTH_SHORT).show()
248+
}
249+
}
250+
251+
builder.setNegativeButton(getString(R.string.contact_permission_dialog_cancel)) { dialog, _ -> dialog.dismiss() }
252+
253+
builder.setCancelable(false)
254+
builder.show()
255+
}
256+
187257
private fun handleSuccessfulAuth(email: String) {
188258
preferencesManager.isLoggedIn = true
189259
preferencesManager.isGuestMode = false
190-
preferencesManager.saveString("pref_user_email", email)
260+
preferencesManager.saveString(PREF_USER_EMAIL, email)
191261
handleSuccessfulLogin()
192262
}
193263

@@ -235,4 +305,4 @@ class LoginActivity : BaseActivity() {
235305
startActivity(Intent(this, MainActivity::class.java))
236306
finish()
237307
}
238-
}
308+
}

app/src/GooglePlay/java/com/parishod/watomatic/flavor/FlavorNavigator.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,21 @@ object FlavorNavigator {
1818
false
1919
}
2020
}
21+
22+
fun startLogin(activity: Activity) {
23+
activity.startActivity(Intent(activity, LoginActivity::class.java))
24+
activity.finish()
25+
}
26+
27+
fun logout(activity: Activity, preferencesManager: PreferencesManager) {
28+
try {
29+
// Sign out of Firebase if available in this flavor
30+
com.google.firebase.auth.FirebaseAuth.getInstance().signOut()
31+
} catch (e: Throwable) {
32+
// ignore
33+
}
34+
preferencesManager.setLoggedIn(false)
35+
preferencesManager.setGuestMode(false)
36+
preferencesManager.setUserEmail("")
37+
}
2138
}

0 commit comments

Comments
 (0)