primeiro commit
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
@@ -23,6 +24,7 @@
|
||||
<activity android:name=".RegisterActivity" />
|
||||
<activity android:name=".ForgotPasswordActivity" />
|
||||
<activity android:name=".MainActivity" />
|
||||
<activity android:name=".SettingsActivity" />
|
||||
|
||||
</application>
|
||||
|
||||
|
||||
@@ -9,14 +9,43 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.google.firebase.FirebaseApp;
|
||||
import com.google.firebase.appcheck.FirebaseAppCheck;
|
||||
import com.google.firebase.appcheck.debug.DebugAppCheckProviderFactory;
|
||||
import com.google.firebase.appcheck.playintegrity.PlayIntegrityAppCheckProviderFactory;
|
||||
|
||||
public class LoginActivity extends AppCompatActivity {
|
||||
|
||||
private EditText etEmail, etPassword, etUsuario;
|
||||
private EditText etEmail, etPassword;
|
||||
private Button btnLogin;
|
||||
private TextView tvGoToRegister, tvForgotPassword;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
// Inicializar Firebase e App Check antes de qualquer outra chamada
|
||||
FirebaseApp.initializeApp(this);
|
||||
FirebaseAppCheck firebaseAppCheck = FirebaseAppCheck.getInstance();
|
||||
|
||||
if (com.fluxup.app.BuildConfig.DEBUG) {
|
||||
// Modo Desenvolvimento: Usa Debug Provider para gerar token no Logcat
|
||||
firebaseAppCheck.installAppCheckProviderFactory(
|
||||
DebugAppCheckProviderFactory.getInstance());
|
||||
android.util.Log.d("FLUXUP_DEBUG", "App Check: Debug Provider instalado. Procure pelo token no Logcat.");
|
||||
} else {
|
||||
// Modo Produção: Usa Play Integrity
|
||||
firebaseAppCheck.installAppCheckProviderFactory(
|
||||
PlayIntegrityAppCheckProviderFactory.getInstance());
|
||||
}
|
||||
|
||||
// Aplicar preferências de tema antes do super.onCreate
|
||||
android.content.SharedPreferences prefs = getSharedPreferences("FluxupSettings", android.content.Context.MODE_PRIVATE);
|
||||
boolean isDarkMode = prefs.getBoolean("darkMode", false);
|
||||
if (isDarkMode) {
|
||||
androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode(androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES);
|
||||
} else {
|
||||
androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode(androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO);
|
||||
}
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Verificar se o utilizador já está logado
|
||||
@@ -31,7 +60,7 @@ public class LoginActivity extends AppCompatActivity {
|
||||
|
||||
etEmail = findViewById(R.id.etEmail);
|
||||
etPassword = findViewById(R.id.etPassword);
|
||||
etUsuario = findViewById(R.id.etUsuario);
|
||||
|
||||
btnLogin = findViewById(R.id.btnLogin);
|
||||
tvGoToRegister = findViewById(R.id.tvGoToRegister);
|
||||
tvForgotPassword = findViewById(R.id.tvForgotPassword);
|
||||
@@ -54,11 +83,9 @@ public class LoginActivity extends AppCompatActivity {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Validar utilizador se estiver visível/preenchido
|
||||
String user = etUsuario.getText().toString();
|
||||
if (!user.isEmpty() && !user.matches("[a-zA-ZáàâãéèêíïóôõöúçÁÀÂÃÉÈÊÍÏÓÔÕÖÚÇ ]+")) {
|
||||
Toast.makeText(LoginActivity.this, "O nome de utilizador deve conter apenas letras", Toast.LENGTH_SHORT).show();
|
||||
// Verificar Ligação à Internet
|
||||
if (!ConnectivityUtils.isNetworkAvailable(LoginActivity.this)) {
|
||||
Toast.makeText(LoginActivity.this, "Sem ligação à internet", Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -73,7 +100,8 @@ public class LoginActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
public void onError(String error) {
|
||||
Toast.makeText(LoginActivity.this, "Erro: " + error, Toast.LENGTH_LONG).show();
|
||||
// Mostrar erro amigável ao utilizador
|
||||
Toast.makeText(LoginActivity.this, error, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,6 +9,24 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
// Aplicar preferências de tema e idioma
|
||||
android.content.SharedPreferences prefs = getSharedPreferences("FluxupSettings", android.content.Context.MODE_PRIVATE);
|
||||
|
||||
// Tema
|
||||
if (prefs.getBoolean("darkMode", false)) {
|
||||
androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode(androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES);
|
||||
} else {
|
||||
androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode(androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO);
|
||||
}
|
||||
|
||||
// Idioma
|
||||
String lang = prefs.getString("language", "pt");
|
||||
java.util.Locale locale = new java.util.Locale(lang);
|
||||
java.util.Locale.setDefault(locale);
|
||||
android.content.res.Configuration config = new android.content.res.Configuration();
|
||||
config.setLocale(locale);
|
||||
getResources().updateConfiguration(config, getResources().getDisplayMetrics());
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package com.fluxup.app;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageButton;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
@@ -13,7 +16,14 @@ public class ProfileFragment extends Fragment {
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
return inflater.inflate(R.layout.fragment_profile, container, false);
|
||||
View view = inflater.inflate(R.layout.fragment_profile, container, false);
|
||||
|
||||
ImageButton btnSettings = view.findViewById(R.id.btnSettings);
|
||||
btnSettings.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(getActivity(), SettingsActivity.class);
|
||||
startActivity(intent);
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.fluxup.app;
|
||||
|
||||
import android.content.Context;
|
||||
import com.google.firebase.auth.FirebaseAuth;
|
||||
import com.google.firebase.auth.FirebaseAuthException;
|
||||
import com.google.firebase.auth.FirebaseUser;
|
||||
import com.google.firebase.firestore.FirebaseFirestore;
|
||||
import java.util.HashMap;
|
||||
@@ -13,45 +14,107 @@ public class UsuariosService {
|
||||
private static final FirebaseFirestore mFirestore = FirebaseFirestore.getInstance();
|
||||
|
||||
public static void login(Context context, String email, String password, ServiceCallback<Usuario> callback) {
|
||||
android.util.Log.d("FLUXUP_SERVICE", "A tentar iniciar sessão para: " + email);
|
||||
mAuth.signInWithEmailAndPassword(email, password)
|
||||
.addOnCompleteListener(task -> {
|
||||
if (task.isSuccessful()) {
|
||||
android.util.Log.d("FLUXUP_SERVICE", "Auth bem-sucedido para: " + email);
|
||||
FirebaseUser user = mAuth.getCurrentUser();
|
||||
if (user != null) {
|
||||
// Buscar detalhes no Firestore
|
||||
Usuario defaultUsuario = new Usuario(user.getUid(), "", user.getEmail(), "", "");
|
||||
defaultUsuario.id = user.getUid();
|
||||
|
||||
mFirestore.collection("users").document(user.getUid()).get()
|
||||
.addOnSuccessListener(documentSnapshot -> {
|
||||
android.util.Log.d("FLUXUP_SERVICE", "Dados recuperados do Firestore com sucesso.");
|
||||
Usuario usuario = documentSnapshot.toObject(Usuario.class);
|
||||
if (usuario == null) {
|
||||
// Fallback if document not found
|
||||
usuario = new Usuario(user.getUid(), "", user.getEmail(), "", "");
|
||||
if (usuario != null) {
|
||||
callback.onSuccess(usuario);
|
||||
} else {
|
||||
android.util.Log.w("FLUXUP_SERVICE", "Documento do utilizador não encontrado no Firestore.");
|
||||
callback.onSuccess(defaultUsuario);
|
||||
}
|
||||
callback.onSuccess(usuario);
|
||||
})
|
||||
.addOnFailureListener(e -> callback.onError(e.getMessage()));
|
||||
.addOnFailureListener(e -> {
|
||||
android.util.Log.e("FLUXUP_SERVICE", "Erro ao carregar do Firestore: " + e.getMessage());
|
||||
callback.onSuccess(defaultUsuario);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
callback.onError(task.getException() != null ? task.getException().getMessage() : "Erro ao entrar");
|
||||
android.util.Log.e("FLUXUP_SERVICE", "Falha no Auth: " + (task.getException() != null ? task.getException().getMessage() : "Desconhecido"));
|
||||
String errorMsg = "Erro ao entrar";
|
||||
if (task.getException() instanceof FirebaseAuthException) {
|
||||
String errorCode = ((FirebaseAuthException) task.getException()).getErrorCode();
|
||||
switch (errorCode) {
|
||||
case "ERROR_INVALID_EMAIL":
|
||||
case "ERROR_USER_NOT_FOUND":
|
||||
errorMsg = "Utilizador não encontrado";
|
||||
break;
|
||||
case "ERROR_WRONG_PASSWORD":
|
||||
errorMsg = "Palavra-passe incorreta";
|
||||
break;
|
||||
case "ERROR_USER_DISABLED":
|
||||
errorMsg = "Este utilizador foi desativado";
|
||||
break;
|
||||
case "ERROR_TOO_MANY_REQUESTS":
|
||||
errorMsg = "Demasiadas tentativas. Tente mais tarde";
|
||||
break;
|
||||
case "ERROR_INVALID_CREDENTIAL":
|
||||
errorMsg = "Credenciais inválidas ou expiradas";
|
||||
break;
|
||||
default:
|
||||
errorMsg = "Erro na autenticação: " + task.getException().getLocalizedMessage();
|
||||
break;
|
||||
}
|
||||
} else if (task.getException() != null) {
|
||||
errorMsg = task.getException().getLocalizedMessage();
|
||||
}
|
||||
callback.onError(errorMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void registar(Context context, Usuario usuario, ServiceCallback<Usuario> callback) {
|
||||
android.util.Log.d("FLUXUP_SERVICE", "A tentar registar utilizador: " + usuario.email);
|
||||
mAuth.createUserWithEmailAndPassword(usuario.email, usuario.palavra_passe)
|
||||
.addOnCompleteListener(task -> {
|
||||
if (task.isSuccessful()) {
|
||||
android.util.Log.d("FLUXUP_SERVICE", "Utilizador criado no Auth com sucesso: " + usuario.email);
|
||||
FirebaseUser firebaseUser = mAuth.getCurrentUser();
|
||||
if (firebaseUser != null) {
|
||||
usuario.id_usuario = firebaseUser.getUid();
|
||||
// Não salvar a senha no Firestore por segurança
|
||||
String uid = firebaseUser.getUid();
|
||||
usuario.id_usuario = uid;
|
||||
usuario.id = uid;
|
||||
|
||||
String tempPass = usuario.palavra_passe;
|
||||
usuario.palavra_passe = null;
|
||||
|
||||
mFirestore.collection("users").document(firebaseUser.getUid()).set(usuario)
|
||||
.addOnSuccessListener(aVoid -> callback.onSuccess(usuario))
|
||||
.addOnFailureListener(e -> callback.onError(e.getMessage()));
|
||||
android.util.Log.d("FLUXUP_SERVICE", "A guardar utilizador no Firestore (Coleção: users, ID: " + uid + ")...");
|
||||
mFirestore.collection("users").document(uid).set(usuario)
|
||||
.addOnSuccessListener(aVoid -> {
|
||||
android.util.Log.d("FLUXUP_SERVICE", "Utilizador guardado no Firestore com sucesso.");
|
||||
usuario.palavra_passe = tempPass;
|
||||
callback.onSuccess(usuario);
|
||||
})
|
||||
.addOnFailureListener(e -> {
|
||||
android.util.Log.e("FLUXUP_SERVICE", "ERRO NO FIRESTORE: " + e.getMessage());
|
||||
callback.onError("Erro ao guardar na base de dados: " + e.getMessage());
|
||||
});
|
||||
}
|
||||
} else {
|
||||
callback.onError(task.getException() != null ? task.getException().getMessage() : "Erro ao criar conta");
|
||||
android.util.Log.e("FLUXUP_SERVICE", "Falha ao criar conta no Auth: " + (task.getException() != null ? task.getException().getMessage() : "Desconhecido"));
|
||||
String errorMsg = "Erro ao criar conta";
|
||||
if (task.getException() instanceof FirebaseAuthException) {
|
||||
String errorCode = ((FirebaseAuthException) task.getException()).getErrorCode();
|
||||
if (errorCode.equals("ERROR_EMAIL_ALREADY_IN_USE")) {
|
||||
errorMsg = "Este email já está a ser utilizado";
|
||||
} else {
|
||||
errorMsg = task.getException().getLocalizedMessage();
|
||||
}
|
||||
} else if (task.getException() != null) {
|
||||
errorMsg = task.getException().getLocalizedMessage();
|
||||
}
|
||||
callback.onError(errorMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -45,14 +45,6 @@
|
||||
android:layout_marginBottom="15dp"
|
||||
android:inputType="textPassword"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etUsuario"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:hint="Usuário"
|
||||
android:background="@drawable/edit_text_bg"
|
||||
android:paddingHorizontal="15dp"
|
||||
android:layout_marginBottom="20dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnLogin"
|
||||
|
||||
@@ -18,13 +18,15 @@
|
||||
android:paddingTop="20dp"
|
||||
android:paddingBottom="20dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
<ImageButton
|
||||
android:id="@+id/btnSettings"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="top|end"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:src="@android:drawable/ic_menu_manage"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_settings"
|
||||
app:tint="@color/white" />
|
||||
|
||||
<LinearLayout
|
||||
|
||||
@@ -2,4 +2,21 @@
|
||||
<string name="app_name">Fluxup</string>
|
||||
<string name="greeting">Hoje é um bom dia</string>
|
||||
<string name="subtitle">Olá, Matheus! Preparado para o seu dia de produtividade?</string>
|
||||
|
||||
<!-- Settings Strings -->
|
||||
<string name="settings">Configurações</string>
|
||||
<string name="preferences">Preferências</string>
|
||||
<string name="dark_mode">Modo Escuro</string>
|
||||
<string name="account">Conta</string>
|
||||
<string name="username">Utilizador</string>
|
||||
<string name="email">Email</string>
|
||||
<string name="change_password">Alterar palavra-passe</string>
|
||||
<string name="privacy">Privacidade</string>
|
||||
<string name="private_account">Conta Privada</string>
|
||||
<string name="notifications">Notificações</string>
|
||||
<string name="app_section">App</string>
|
||||
<string name="language">Idioma</string>
|
||||
<string name="logout">Terminar sessão</string>
|
||||
<string name="back">Voltar</string>
|
||||
</resources>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user