diff --git a/app/src/main/java/com/example/lifegrid/CriarContaActivity.java b/app/src/main/java/com/example/lifegrid/CriarContaActivity.java index 19f3372..f9527ba 100644 --- a/app/src/main/java/com/example/lifegrid/CriarContaActivity.java +++ b/app/src/main/java/com/example/lifegrid/CriarContaActivity.java @@ -33,6 +33,13 @@ import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.FirebaseUser; import com.google.firebase.auth.GoogleAuthProvider; +import com.google.firebase.auth.GoogleAuthProvider; + +/** + * CriarContaActivity é a atividade responsável por gerir o registo de novos utilizadores na aplicação LifeGrid. + * Permite a criação de conta utilizando Email/Password e validações de formulário. + * Também suporta registo integrado via conta Google. + */ public class CriarContaActivity extends AppCompatActivity { private EditText nomeEditText; @@ -68,9 +75,14 @@ public class CriarContaActivity extends AppCompatActivity { firebaseAuth = FirebaseAuth.getInstance(); credentialManager = CredentialManager.create(this); + // Configura o botão de registo para acionar a validação e criação de conta loginButton2.setOnClickListener(v -> criarConta()); } + /** + * Extrai os dados dos campos de texto, chama o método de validação, + * e caso os dados estejam corretos, regista o utilizador no Firebase Auth. + */ private void criarConta() { String nome = nomeEditText.getText().toString().trim(); String email = emailEditText2.getText().toString().trim(); @@ -119,6 +131,10 @@ public class CriarContaActivity extends AppCompatActivity { }); } + /** + * Valida os diferentes campos do formulário para garantir que estão preenchidos + * corretamente (tamanho e formato do email) antes de tentar comunicar com o Firebase. + */ private boolean validarDados(String nome, String email, String password, String confirmarPassword) { // Validar nome if (TextUtils.isEmpty(nome)) { diff --git a/app/src/main/java/com/example/lifegrid/LoginActivity.java b/app/src/main/java/com/example/lifegrid/LoginActivity.java index fbf50d7..b1a95e4 100644 --- a/app/src/main/java/com/example/lifegrid/LoginActivity.java +++ b/app/src/main/java/com/example/lifegrid/LoginActivity.java @@ -45,6 +45,11 @@ import com.google.firebase.auth.GoogleAuthProvider; import java.util.concurrent.Executors; +/** + * LoginActivity é o ecrã inicial da aplicação onde o utilizador fornece as suas credenciais. + * Suporta o login regular com Email e Palavra-Passe ligando ao Firebase Auth. + * Também suporta autenticação moderna pela API do CredentialManager (Google Sign In). + */ public class LoginActivity extends AppCompatActivity { private TextView textView5; @@ -106,7 +111,7 @@ public class LoginActivity extends AppCompatActivity { } }); - // Inicialmente desabilitar o TextView de recuperar senha + // Inicialmente desabilitar o TextView de recuperar palavra-passe passesquecerTextView.setEnabled(false); passesquecerTextView.setAlpha(0.5f); // Visualmente mais claro quando desabilitado @@ -115,11 +120,11 @@ public class LoginActivity extends AppCompatActivity { public void onClick(View view) { String email = emailEditText.getText().toString().trim(); - // Validar se há email antes de abrir a atividade de recuperação + // Validar se tem e-mail antes de abrir a atividade de recuperação if (TextUtils.isEmpty(email)) { - emailEditText.setError("Por favor, digite seu email primeiro."); + emailEditText.setError("Por favor, digite o seu e-mail primeiro."); emailEditText.requestFocus(); - Toast.makeText(LoginActivity.this, "Digite seu email para recuperar a senha.", Toast.LENGTH_SHORT).show(); + Toast.makeText(LoginActivity.this, "Digite o seu e-mail para recuperar a palavra-passe.", Toast.LENGTH_SHORT).show(); return; } @@ -147,7 +152,10 @@ public class LoginActivity extends AppCompatActivity { }); } - + /** + * Extrai os dados dos campos de Email e Password, executa as funções de validação + * e caso os dados estejam em boa forma efetua a requisição de entrada pela plataforma Firebase. + */ private void validarLogin() { String email = emailEditText.getText().toString().trim(); String password = passwordEditText.getText().toString(); @@ -269,19 +277,19 @@ public class LoginActivity extends AppCompatActivity { private void launchCredentialManager() { // [START create_credential_manager_request] - // Instantiate a Google sign-in request + // Instancia um pedido de início de sessão do Google GetGoogleIdOption googleIdOption = new GetGoogleIdOption.Builder() .setFilterByAuthorizedAccounts(true) .setServerClientId(getString(R.string.default_web_client_id)) .build(); - // Create the Credential Manager request + // Cria o pedido do Gestor de Credenciais GetCredentialRequest request = new GetCredentialRequest.Builder() .addCredentialOption(googleIdOption) .build(); // [END create_credential_manager_request] - // Launch Credential Manager UI + // Lança a interface do Gestor de Credenciais credentialManager.getCredentialAsync( getBaseContext(), request, @@ -290,7 +298,7 @@ public class LoginActivity extends AppCompatActivity { new CredentialManagerCallback<>() { @Override public void onResult(GetCredentialResponse result) { - // Extract credential from the result returned by Credential Manager + // Extrai a credencial do resultado devolvido pelo Gestor de Credenciais handleSignIn(result.getCredential()); } @@ -303,14 +311,14 @@ public class LoginActivity extends AppCompatActivity { } private void handleSignIn(Credential credential) { - // Check if credential is of type Google ID + // Verifica se a credencial é do tipo Google ID if (credential instanceof CustomCredential customCredential && credential.getType().equals(GOOGLE_ID_TOKEN_CREDENTIAL)) { - // Create Google ID Token + // Cria o token do Google ID Bundle credentialData = customCredential.getData(); GoogleIdTokenCredential googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credentialData); - // Sign in to Firebase with using the token + // Inicia a sessão no Firebase usando o token firebaseAuthWithGoogle(googleIdTokenCredential.getIdToken()); } else { Log.w(TAG, "Credential is not of type Google ID!"); @@ -318,10 +326,10 @@ public class LoginActivity extends AppCompatActivity { } private void signOut() { - // Firebase sign out + // Termina a sessão no Firebase mAuth.signOut(); - // When a user signs out, clear the current user credential state from all credential providers. + // Quando o utilizador termina a sessão, limpa o estado atual da credencial do utilizador de todos os provedores de credenciais. ClearCredentialStateRequest clearRequest = new ClearCredentialStateRequest(); credentialManager.clearCredentialStateAsync( clearRequest, @@ -343,7 +351,7 @@ public class LoginActivity extends AppCompatActivity { @Override public void onStart() { super.onStart(); - // Check if user is signed in (non-null) and update UI accordingly. + // Verifica se o utilizador tem sessão iniciada (não nulo) e atualiza a interface conformemente. FirebaseUser currentUser = mAuth.getCurrentUser(); if (currentUser != null) { Intent intent = new Intent(LoginActivity.this, TelaInicialActivity.class); diff --git a/app/src/main/java/com/example/lifegrid/RecupearPasswordActivity.java b/app/src/main/java/com/example/lifegrid/RecupearPasswordActivity.java index 7a4e20f..d6ade04 100644 --- a/app/src/main/java/com/example/lifegrid/RecupearPasswordActivity.java +++ b/app/src/main/java/com/example/lifegrid/RecupearPasswordActivity.java @@ -18,6 +18,10 @@ import androidx.core.view.WindowInsetsCompat; import com.google.firebase.FirebaseApp; import com.google.firebase.auth.FirebaseAuth; +/** + * RecupearPasswordActivity é a atividade que coordena o envio do formulário de recuperação de senha. + * Liga-se ao Firebase e envia automaticamente um link de redifinição de palavra-passe para a caixa de correio do utilizador. + */ public class RecupearPasswordActivity extends AppCompatActivity { private EditText emailEditText4; @@ -56,6 +60,10 @@ public class RecupearPasswordActivity extends AppCompatActivity { loginButton3.setOnClickListener(v -> recuperarPassword()); } + /** + * Valida o campo do e-mail fornecido pelo utilizador para enviar o pedido + * de mudança de palavra-passe aos servidores do serviço Firebase. Trata as respetivas mensagens de sucesso e erro. + */ private void recuperarPassword() { String email = emailEditText4.getText().toString().trim(); String emailPassado = getIntent().getStringExtra("email"); diff --git a/app/src/main/java/com/example/lifegrid/TelaInicialActivity.java b/app/src/main/java/com/example/lifegrid/TelaInicialActivity.java index f5ea8ec..c5ed680 100644 --- a/app/src/main/java/com/example/lifegrid/TelaInicialActivity.java +++ b/app/src/main/java/com/example/lifegrid/TelaInicialActivity.java @@ -18,6 +18,11 @@ import com.example.lifegrid.menu.GraficosFragment; import com.example.lifegrid.menu.MetasFragment; import com.example.lifegrid.menu.TransacoesFragment; +/** + * TelaInicialActivity funciona como a janela mestre (Container) de navegação da aplicação. + * É a responsável por carregar e trocar as visualizações menores (Fragmentos) na área principal do ecrã + * mediante o clique numa série de botões situados na barra de fundo. + */ public class TelaInicialActivity extends AppCompatActivity { private TextView tvValor; diff --git a/app/src/main/java/com/example/lifegrid/menu/AtivosFragment.java b/app/src/main/java/com/example/lifegrid/menu/AtivosFragment.java index 06804b7..3488b25 100644 --- a/app/src/main/java/com/example/lifegrid/menu/AtivosFragment.java +++ b/app/src/main/java/com/example/lifegrid/menu/AtivosFragment.java @@ -10,11 +10,14 @@ import android.view.ViewGroup; import com.example.lifegrid.R; - +/** + * AtivosFragment diz respeito à janela do ecossistema dedicada à gestão + * do património estático ou em avaliação progressiva na bolsa/bancos. + */ public class AtivosFragment extends Fragment { public AtivosFragment() { - // Required empty public constructor + // Construtor público vazio obrigatório } @Override @@ -25,7 +28,7 @@ public class AtivosFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - // Inflate the layout for this fragment + // Inflaciona o layout para este fragmento View root = inflater.inflate(R.layout.fragment_ativos, container, false); diff --git a/app/src/main/java/com/example/lifegrid/menu/DefinicoesFragment.java b/app/src/main/java/com/example/lifegrid/menu/DefinicoesFragment.java index e263dfb..8191dc1 100644 --- a/app/src/main/java/com/example/lifegrid/menu/DefinicoesFragment.java +++ b/app/src/main/java/com/example/lifegrid/menu/DefinicoesFragment.java @@ -10,11 +10,14 @@ import android.view.ViewGroup; import com.example.lifegrid.R; - +/** + * DefinicoesFragment carrega os menus base de configurações do utilizador, + * sendo o local ideal para definir opções de acessibilidade, mudança de password e logout. + */ public class DefinicoesFragment extends Fragment { public DefinicoesFragment() { - // Required empty public constructor + // Construtor público vazio obrigatório } @Override @@ -25,7 +28,7 @@ public class DefinicoesFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - // Inflate the layout for this fragment + // Inflaciona o layout para este fragmento View root = inflater.inflate(R.layout.fragment_definicoes, container, false); diff --git a/app/src/main/java/com/example/lifegrid/menu/DocumentosFragment.java b/app/src/main/java/com/example/lifegrid/menu/DocumentosFragment.java index 33d5b5c..d8897ea 100644 --- a/app/src/main/java/com/example/lifegrid/menu/DocumentosFragment.java +++ b/app/src/main/java/com/example/lifegrid/menu/DocumentosFragment.java @@ -10,11 +10,14 @@ import android.view.ViewGroup; import com.example.lifegrid.R; - +/** + * DocumentosFragment é a área orientada ao scan, compilação de faturas e arquivo seguro. + * Foca-se unicamente nas componentes não contabéis mas sim em anotações em anexo faturado. + */ public class DocumentosFragment extends Fragment { public DocumentosFragment() { - // Required empty public constructor + // Construtor público vazio obrigatório } @Override @@ -25,7 +28,7 @@ public class DocumentosFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - // Inflate the layout for this fragment + // Inflaciona o layout para este fragmento View root = inflater.inflate(R.layout.fragment_documentos, container, false); diff --git a/app/src/main/java/com/example/lifegrid/menu/GraficosFragment.java b/app/src/main/java/com/example/lifegrid/menu/GraficosFragment.java index 5cb9ce0..42b0f47 100644 --- a/app/src/main/java/com/example/lifegrid/menu/GraficosFragment.java +++ b/app/src/main/java/com/example/lifegrid/menu/GraficosFragment.java @@ -10,10 +10,14 @@ import android.view.ViewGroup; import com.example.lifegrid.R; +/** + * GraficosFragment tem como único propósito compilar a informação da aplicação sob uma + * componente puramente matemática exibida de forma ilustrativa. Tarta da visão de Dashboard de estatística. + */ public class GraficosFragment extends Fragment { public GraficosFragment() { - // Required empty public constructor + // Construtor público vazio obrigatório } @Override @@ -24,7 +28,7 @@ public class GraficosFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - // Inflate the layout for this fragment + // Inflaciona o layout para este fragmento View root = inflater.inflate(R.layout.fragment_graficos, container, false); diff --git a/app/src/main/java/com/example/lifegrid/menu/MetasFragment.java b/app/src/main/java/com/example/lifegrid/menu/MetasFragment.java index bc2c865..3bd8ea2 100644 --- a/app/src/main/java/com/example/lifegrid/menu/MetasFragment.java +++ b/app/src/main/java/com/example/lifegrid/menu/MetasFragment.java @@ -10,10 +10,14 @@ import android.view.ViewGroup; import com.example.lifegrid.R; +/** + * MetasFragment projeta objetivos futuros onde o utilizador fixa montantes e datas a alcançar + * sendo apresentada percentagem de sucesso à medida que deposita fundos dedicados. + */ public class MetasFragment extends Fragment { public MetasFragment() { - // Required empty public constructor + // Construtor público vazio obrigatório } @Override @@ -24,7 +28,7 @@ public class MetasFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - // Inflate the layout for this fragment + // Inflaciona o layout para este fragmento View root = inflater.inflate(R.layout.fragment_metas, container, false); diff --git a/app/src/main/java/com/example/lifegrid/menu/TransacoesFragment.java b/app/src/main/java/com/example/lifegrid/menu/TransacoesFragment.java index f2f96a4..2dbb2ab 100644 --- a/app/src/main/java/com/example/lifegrid/menu/TransacoesFragment.java +++ b/app/src/main/java/com/example/lifegrid/menu/TransacoesFragment.java @@ -8,15 +8,40 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.app.AlertDialog; +import android.app.DatePickerDialog; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.Calendar; +import java.util.Locale; + import com.example.lifegrid.R; +import com.example.lifegrid.models.Transacao; +import com.google.firebase.Firebase; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; - +/** + * TransacoesFragment controla a aba pertencente às listagens e histórico de carteira e gestão de dados base. + * É responsável por permitir o lançamento do pop-up para a construção de novas entradas financeiras (receitas/despesas). + */ public class TransacoesFragment extends Fragment { public TransacoesFragment() { - // Required empty public constructor + // Construtor público vazio obrigatório } @@ -29,10 +54,93 @@ public class TransacoesFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - // Inflate the layout for this fragment + // Inflaciona o layout para este fragmento View root = inflater.inflate(R.layout.fragment_transacoes, container, false); + Button novaTransacaoButton = root.findViewById(R.id.novaTransacaoButton); + novaTransacaoButton.setOnClickListener(v -> showNovaTransacaoDialog()); return root; } + + /** + * Cria e monta manualmente uma janela Modal (Pop-up) a fim do utilizador preencher + * os detalhes referentes a uma recém aquisição de receita ou encargo para alimentar a base de dados. + */ + private void showNovaTransacaoDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); + View dialogView = getLayoutInflater().inflate(R.layout.dialog_nova_transacao, null); + builder.setView(dialogView); + + AlertDialog dialog = builder.create(); + if (dialog.getWindow() != null) { + dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + } + + ImageView btnFechar = dialogView.findViewById(R.id.btnFechar); + btnFechar.setOnClickListener(v -> dialog.dismiss()); + + EditText etData = dialogView.findViewById(R.id.etData); + etData.setOnClickListener(v -> { + Calendar calendar = Calendar.getInstance(); + int year = calendar.get(Calendar.YEAR); + int month = calendar.get(Calendar.MONTH); + int day = calendar.get(Calendar.DAY_OF_MONTH); + + DatePickerDialog datePickerDialog = new DatePickerDialog(requireContext(), + (view, selectedYear, selectedMonth, selectedDay) -> { + String formattedDate = String.format(Locale.getDefault(), "%02d/%02d/%04d", selectedDay, selectedMonth + 1, selectedYear); + etData.setText(formattedDate); + }, year, month, day); + datePickerDialog.show(); + }); + + Button btnAdicionarTransacao = dialogView.findViewById(R.id.btnAdicionarTransacao); + EditText etValor = dialogView.findViewById(R.id.etValor); + EditText etDescricao = dialogView.findViewById(R.id.etDescricao); + Spinner spinnerCategoria = dialogView.findViewById(R.id.spinnerCategoria); + Spinner spinnerTipo = dialogView.findViewById(R.id.spinnerTipo); + + spinnerTipo.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + int arrayResId = position == 0 ? R.array.categoria_receita : R.array.categoria_despesa; + ArrayAdapter adapter = ArrayAdapter.createFromResource(requireContext(), + arrayResId, android.R.layout.simple_spinner_item); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinnerCategoria.setAdapter(adapter); + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }); + + btnAdicionarTransacao.setOnClickListener(v -> { + String valor = etValor.getText().toString().trim(); + String descricao = etDescricao.getText().toString().trim(); + String data = etData.getText().toString().trim(); + String tipo = spinnerTipo.getSelectedItem().toString(); + String categoria = spinnerCategoria.getSelectedItem().toString(); + + Transacao transacao = new Transacao(tipo, valor, categoria, descricao, data); + + + if (valor.isEmpty() || descricao.isEmpty() || data.isEmpty() || spinnerCategoria.getSelectedItemPosition() == 0) { + Toast.makeText(requireContext(), "Por favor, preencha todos os campos.", Toast.LENGTH_SHORT).show(); + } else { + DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference(); + String userId = FirebaseAuth.getInstance().getCurrentUser().getUid(); + String key = databaseReference.child("users").child(userId).child("transacoes").push().getKey(); + + databaseReference.child("users").child(userId).child("transacoes").child(key).setValue(transacao); + + + dialog.dismiss(); + Toast.makeText(requireContext(), "Transação adicionada com sucesso!", Toast.LENGTH_SHORT).show(); + } + }); + + dialog.show(); + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/lifegrid/models/Transacao.java b/app/src/main/java/com/example/lifegrid/models/Transacao.java new file mode 100644 index 0000000..e331e55 --- /dev/null +++ b/app/src/main/java/com/example/lifegrid/models/Transacao.java @@ -0,0 +1,61 @@ +package com.example.lifegrid.models; + +public class Transacao { + private String tipo; + private String valor; + private String categoria; + private String descricao; + private String data; + + public Transacao() { + } + + + public Transacao(String tipo, String valor, String categoria, String descricao, String data) { + this.tipo = tipo; + this.valor = valor; + this.categoria = categoria; + this.descricao = descricao; + this.data = data; + } + + public String getTipo() { + return tipo; + } + + public void setTipo(String tipo) { + this.tipo = tipo; + } + + public String getValor() { + return valor; + } + + public void setValor(String valor) { + this.valor = valor; + } + + public String getCategoria() { + return categoria; + } + + public void setCategoria(String categoria) { + this.categoria = categoria; + } + + public String getDescricao() { + return descricao; + } + + public void setDescricao(String descricao) { + this.descricao = descricao; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } +} diff --git a/app/src/main/res/drawable/dialog_bg.xml b/app/src/main/res/drawable/dialog_bg.xml new file mode 100644 index 0000000..bfbd6cd --- /dev/null +++ b/app/src/main/res/drawable/dialog_bg.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/rounded_input_bg.xml b/app/src/main/res/drawable/rounded_input_bg.xml new file mode 100644 index 0000000..9e6a89b --- /dev/null +++ b/app/src/main/res/drawable/rounded_input_bg.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/app/src/main/res/layout/dialog_nova_transacao.xml b/app/src/main/res/layout/dialog_nova_transacao.xml new file mode 100644 index 0000000..f0663a4 --- /dev/null +++ b/app/src/main/res/layout/dialog_nova_transacao.xml @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +