first commit
This commit is contained in:
340
app/src/main/java/com/example/bem/LoginActivity.java
Normal file
340
app/src/main/java/com/example/bem/LoginActivity.java
Normal file
@@ -0,0 +1,340 @@
|
||||
package com.example.bem;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.google.firebase.auth.FirebaseAuth;
|
||||
import com.google.firebase.auth.FirebaseUser;
|
||||
import com.google.firebase.firestore.FirebaseFirestore;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class LoginActivity extends AppCompatActivity {
|
||||
|
||||
private FirebaseAuth mAuth;
|
||||
private FirebaseFirestore db;
|
||||
private SharedPreferences prefs;
|
||||
private static final String PREF_DARK_MODE = "dark_mode";
|
||||
|
||||
private EditText inputEmail;
|
||||
private EditText inputPassword;
|
||||
private EditText inputName;
|
||||
private EditText inputPhone;
|
||||
private Button btnLogin;
|
||||
private TextView textLoginType;
|
||||
private TextView textSwitchMode;
|
||||
private TextView textForgotPassword;
|
||||
private TextView textSwitchToGuardian;
|
||||
private ProgressBar progressBar;
|
||||
|
||||
private boolean isRegisterMode = false;
|
||||
private boolean isGuardianMode = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
prefs = getSharedPreferences("app_prefs", MODE_PRIVATE);
|
||||
applyThemeFromPrefs();
|
||||
|
||||
mAuth = FirebaseAuth.getInstance();
|
||||
db = FirebaseFirestore.getInstance();
|
||||
|
||||
// Forçar login sempre que abrir a app: faz signOut se já existir sessão
|
||||
if (mAuth.getCurrentUser() != null) {
|
||||
mAuth.signOut();
|
||||
}
|
||||
|
||||
setContentView(R.layout.activity_login);
|
||||
|
||||
inputEmail = findViewById(R.id.inputEmail);
|
||||
inputPassword = findViewById(R.id.inputPassword);
|
||||
inputName = findViewById(R.id.inputName);
|
||||
inputPhone = findViewById(R.id.inputPhone);
|
||||
btnLogin = findViewById(R.id.btnLogin);
|
||||
textLoginType = findViewById(R.id.textLoginType);
|
||||
textSwitchMode = findViewById(R.id.textSwitchMode);
|
||||
textForgotPassword = findViewById(R.id.textForgotPassword);
|
||||
textSwitchToGuardian = findViewById(R.id.textSwitchToGuardian);
|
||||
|
||||
btnLogin.setOnClickListener(v -> handleLogin());
|
||||
textSwitchMode.setOnClickListener(v -> toggleMode());
|
||||
textForgotPassword.setOnClickListener(v -> showForgotPasswordDialog());
|
||||
textSwitchToGuardian.setOnClickListener(v -> switchToGuardianMode());
|
||||
}
|
||||
|
||||
private void switchToGuardianMode() {
|
||||
isGuardianMode = !isGuardianMode;
|
||||
|
||||
if (isGuardianMode) {
|
||||
textLoginType.setText("Login de Responsável");
|
||||
textSwitchToGuardian.setText("👤 Sou Utilizador");
|
||||
inputPhone.setVisibility(View.VISIBLE);
|
||||
inputPhone.setHint("Número de telemóvel");
|
||||
} else {
|
||||
textLoginType.setText("Login de Utilizador");
|
||||
textSwitchToGuardian.setText("🔒 Sou Responsável");
|
||||
inputPhone.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
isRegisterMode = false;
|
||||
updateUI();
|
||||
}
|
||||
|
||||
private void toggleMode() {
|
||||
isRegisterMode = !isRegisterMode;
|
||||
updateUI();
|
||||
}
|
||||
|
||||
private void updateUI() {
|
||||
if (isRegisterMode) {
|
||||
btnLogin.setText("Criar Conta");
|
||||
textSwitchMode.setText("Já tem conta? Entrar");
|
||||
inputName.setVisibility(View.VISIBLE);
|
||||
|
||||
if (isGuardianMode) {
|
||||
inputPhone.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} else {
|
||||
btnLogin.setText("Entrar");
|
||||
textSwitchMode.setText("Não tem conta? Registar");
|
||||
inputName.setVisibility(View.GONE);
|
||||
|
||||
if (!isGuardianMode) {
|
||||
inputPhone.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLogin() {
|
||||
String email = inputEmail.getText().toString().trim();
|
||||
String password = inputPassword.getText().toString().trim();
|
||||
String name = inputName.getText().toString().trim();
|
||||
String phone = inputPhone.getText().toString().trim();
|
||||
|
||||
if (TextUtils.isEmpty(email)) {
|
||||
inputEmail.setError("Insira o email");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
|
||||
inputEmail.setError("Email inválido");
|
||||
return;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(password)) {
|
||||
inputPassword.setError("Insira a palavra-passe");
|
||||
return;
|
||||
}
|
||||
|
||||
if (password.length() < 6) {
|
||||
inputPassword.setError("Mínimo 6 caracteres");
|
||||
return;
|
||||
}
|
||||
|
||||
if (isRegisterMode && TextUtils.isEmpty(name)) {
|
||||
inputName.setError("Insira o nome");
|
||||
return;
|
||||
}
|
||||
|
||||
btnLogin.setEnabled(false);
|
||||
|
||||
if (isRegisterMode) {
|
||||
registerUser(email, password, name, phone);
|
||||
} else {
|
||||
loginUser(email, password);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerUser(String email, String password, String name, String phone) {
|
||||
mAuth.createUserWithEmailAndPassword(email, password)
|
||||
.addOnCompleteListener(task -> {
|
||||
if (task.isSuccessful()) {
|
||||
FirebaseUser user = mAuth.getCurrentUser();
|
||||
if (user != null) {
|
||||
saveUserData(user.getUid(), email, name, phone, true);
|
||||
} else {
|
||||
btnLogin.setEnabled(true);
|
||||
Toast.makeText(this, "Erro ao obter utilizador. Tente entrar com o email/senha.",
|
||||
Toast.LENGTH_LONG).show();
|
||||
mAuth.signOut();
|
||||
}
|
||||
} else {
|
||||
btnLogin.setEnabled(true);
|
||||
String error = task.getException() != null ? task.getException().getMessage()
|
||||
: "Erro desconhecido";
|
||||
Toast.makeText(this, "Erro: " + error, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void saveUserData(String uid, String email, String name, String phone, boolean fromRegister) {
|
||||
Map<String, Object> userData = new HashMap<>();
|
||||
userData.put("email", email);
|
||||
userData.put("name", name);
|
||||
userData.put("phone", phone != null ? phone : "");
|
||||
userData.put("type", isGuardianMode ? "guardian" : "user");
|
||||
userData.put("createdAt", System.currentTimeMillis());
|
||||
|
||||
db.collection("users").document(uid)
|
||||
.set(userData)
|
||||
.addOnSuccessListener(aVoid -> {
|
||||
if (fromRegister) {
|
||||
Toast.makeText(this, "✓ Conta criada! Faça login para continuar.", Toast.LENGTH_LONG).show();
|
||||
mAuth.signOut();
|
||||
btnLogin.setEnabled(true);
|
||||
// Recarrega a tela limpa
|
||||
Intent intent = getIntent();
|
||||
finish();
|
||||
startActivity(intent);
|
||||
} else {
|
||||
redirectToApp();
|
||||
}
|
||||
})
|
||||
.addOnFailureListener(e -> {
|
||||
btnLogin.setEnabled(true);
|
||||
Toast.makeText(this, "Erro ao salvar dados: " + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
});
|
||||
}
|
||||
|
||||
private void loginUser(String email, String password) {
|
||||
mAuth.signInWithEmailAndPassword(email, password)
|
||||
.addOnCompleteListener(task -> {
|
||||
if (task.isSuccessful()) {
|
||||
FirebaseUser user = mAuth.getCurrentUser();
|
||||
if (user != null) {
|
||||
checkUserTypeAndRedirect(user.getUid());
|
||||
} else {
|
||||
btnLogin.setEnabled(true);
|
||||
Toast.makeText(this, "Erro ao iniciar sessão. Tente novamente.", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
} else {
|
||||
btnLogin.setEnabled(true);
|
||||
String error = task.getException() != null ? task.getException().getMessage()
|
||||
: "Credenciais inválidas";
|
||||
Toast.makeText(this, "Erro: " + error, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void checkUserTypeAndRedirect(String uid) {
|
||||
db.collection("users").document(uid)
|
||||
.get()
|
||||
.addOnSuccessListener(document -> {
|
||||
if (document.exists()) {
|
||||
String type = document.getString("type");
|
||||
prefs.edit()
|
||||
.putString("user_type", type != null ? type : "user")
|
||||
.putString("user_name", document.getString("name"))
|
||||
.apply();
|
||||
|
||||
if ("guardian".equals(type)) {
|
||||
// Verifies if guardian is already linked to a user
|
||||
java.util.List<String> managedUsers = (java.util.List<String>) document.get("managedUsers");
|
||||
|
||||
if (managedUsers != null && !managedUsers.isEmpty()) {
|
||||
redirectToApp();
|
||||
} else {
|
||||
// If not linked, redirect to enter access code
|
||||
Intent intent = new Intent(LoginActivity.this, InviteCodeActivity.class);
|
||||
intent.putExtra("is_guardian", true);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
} else {
|
||||
redirectToApp();
|
||||
}
|
||||
} else {
|
||||
// Se o documento não existir (ex.: registo antigo sem salvar), cria um básico
|
||||
FirebaseUser user = mAuth.getCurrentUser();
|
||||
String email = user != null ? user.getEmail() : "";
|
||||
String name = (email != null && email.contains("@")) ? email.substring(0, email.indexOf("@"))
|
||||
: "Utilizador";
|
||||
|
||||
Map<String, Object> userData = new HashMap<>();
|
||||
userData.put("email", email);
|
||||
userData.put("name", name);
|
||||
userData.put("phone", "");
|
||||
userData.put("type", "user");
|
||||
userData.put("createdAt", System.currentTimeMillis());
|
||||
|
||||
db.collection("users").document(uid)
|
||||
.set(userData)
|
||||
.addOnSuccessListener(aVoid -> {
|
||||
prefs.edit()
|
||||
.putString("user_type", "user")
|
||||
.putString("user_name", name)
|
||||
.apply();
|
||||
redirectToApp();
|
||||
})
|
||||
.addOnFailureListener(e -> {
|
||||
Toast.makeText(this, "Erro ao criar perfil: " + e.getMessage(), Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
btnLogin.setEnabled(true);
|
||||
});
|
||||
}
|
||||
})
|
||||
.addOnFailureListener(e -> {
|
||||
Toast.makeText(this, "Erro ao carregar dados", Toast.LENGTH_SHORT).show();
|
||||
btnLogin.setEnabled(true);
|
||||
});
|
||||
}
|
||||
|
||||
private void redirectToApp() {
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void showForgotPasswordDialog() {
|
||||
View dialogView = getLayoutInflater().inflate(android.R.layout.simple_list_item_1, null);
|
||||
EditText emailInput = new EditText(this);
|
||||
emailInput.setHint("Email de recuperação");
|
||||
emailInput.setInputType(android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
|
||||
emailInput.setPadding(50, 40, 50, 40);
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Recuperar Palavra-passe")
|
||||
.setMessage("Insira o email para receber o link de recuperação:")
|
||||
.setView(emailInput)
|
||||
.setPositiveButton("Enviar", (dialog, which) -> {
|
||||
String email = emailInput.getText().toString().trim();
|
||||
if (TextUtils.isEmpty(email)) {
|
||||
Toast.makeText(this, "Insira um email", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
mAuth.sendPasswordResetEmail(email)
|
||||
.addOnSuccessListener(aVoid -> {
|
||||
Toast.makeText(this, "✓ Email enviado! Verifique a caixa de entrada.",
|
||||
Toast.LENGTH_LONG).show();
|
||||
})
|
||||
.addOnFailureListener(e -> {
|
||||
Toast.makeText(this, "Erro: " + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
});
|
||||
})
|
||||
.setNegativeButton("Cancelar", null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void applyThemeFromPrefs() {
|
||||
boolean dark = getSharedPreferences("app_prefs", MODE_PRIVATE).getBoolean(PREF_DARK_MODE, false);
|
||||
AppCompatDelegate
|
||||
.setDefaultNightMode(dark ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user