From 9a56ecd1dd1688cadb0c3057e6a316ecce6f61c5 Mon Sep 17 00:00:00 2001 From: 230415 <230415@epvc.pt> Date: Thu, 23 Apr 2026 16:05:48 +0100 Subject: [PATCH] tudo a andar rapido vamossss --- .../example/lifegrid/TelaInicialActivity.java | 146 ++++++++++++++++ .../lifegrid/adapters/MetaAdapter.java | 144 ++++++++++++++++ .../lifegrid/adapters/TransacaoAdapter.java | 87 ++++++++++ .../example/lifegrid/menu/MetasFragment.java | 114 +++++++++++++ .../lifegrid/menu/TransacoesFragment.java | 77 ++++++++- .../com/example/lifegrid/models/Meta.java | 20 +++ .../example/lifegrid/models/Transacao.java | 11 ++ .../main/res/drawable/bg_badge_category.xml | 6 + app/src/main/res/drawable/bg_circle_green.xml | 5 + app/src/main/res/drawable/bg_circle_red.xml | 5 + .../main/res/drawable/custom_progressbar.xml | 17 ++ app/src/main/res/drawable/ic_arrow_down.xml | 9 + app/src/main/res/drawable/ic_calendar.xml | 10 ++ app/src/main/res/drawable/ic_delete.xml | 10 ++ app/src/main/res/drawable/ic_goal.xml | 10 ++ app/src/main/res/drawable/ic_trend_up.xml | 10 ++ .../main/res/drawable/spinner_border_bg.xml | 11 ++ .../main/res/layout/activity_tela_inicial.xml | 36 +++- app/src/main/res/layout/fragment_metas.xml | 1 + app/src/main/res/layout/item_meta.xml | 157 ++++++++++++++++++ app/src/main/res/layout/item_transacao.xml | 107 ++++++++++++ 21 files changed, 990 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/com/example/lifegrid/adapters/MetaAdapter.java create mode 100644 app/src/main/java/com/example/lifegrid/adapters/TransacaoAdapter.java create mode 100644 app/src/main/res/drawable/bg_badge_category.xml create mode 100644 app/src/main/res/drawable/bg_circle_green.xml create mode 100644 app/src/main/res/drawable/bg_circle_red.xml create mode 100644 app/src/main/res/drawable/custom_progressbar.xml create mode 100644 app/src/main/res/drawable/ic_arrow_down.xml create mode 100644 app/src/main/res/drawable/ic_calendar.xml create mode 100644 app/src/main/res/drawable/ic_delete.xml create mode 100644 app/src/main/res/drawable/ic_goal.xml create mode 100644 app/src/main/res/drawable/ic_trend_up.xml create mode 100644 app/src/main/res/drawable/spinner_border_bg.xml create mode 100644 app/src/main/res/layout/item_meta.xml create mode 100644 app/src/main/res/layout/item_transacao.xml diff --git a/app/src/main/java/com/example/lifegrid/TelaInicialActivity.java b/app/src/main/java/com/example/lifegrid/TelaInicialActivity.java index c5ed680..175fe91 100644 --- a/app/src/main/java/com/example/lifegrid/TelaInicialActivity.java +++ b/app/src/main/java/com/example/lifegrid/TelaInicialActivity.java @@ -17,6 +17,25 @@ import com.example.lifegrid.menu.DocumentosFragment; import com.example.lifegrid.menu.GraficosFragment; import com.example.lifegrid.menu.MetasFragment; import com.example.lifegrid.menu.TransacoesFragment; +import com.example.lifegrid.models.Transacao; + +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Spinner; +import android.widget.Toast; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.database.DataSnapshot; +import com.google.firebase.database.DatabaseError; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.ValueEventListener; +import androidx.annotation.NonNull; + +import java.util.Calendar; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; /** * TelaInicialActivity funciona como a janela mestre (Container) de navegação da aplicação. @@ -33,6 +52,13 @@ public class TelaInicialActivity extends AppCompatActivity { private TextView tvTransacoes3; private TextView tvValor4; private TextView tvTransacoes4; + private TextView tvTitulo; + private TextView tvTitulo2; + + private Spinner spinnerMes; + private Spinner spinnerAno; + + private String[] meses = {"Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"}; @Override protected void onCreate(Bundle savedInstanceState) { @@ -45,6 +71,22 @@ public class TelaInicialActivity extends AppCompatActivity { return insets; }); + tvValor = findViewById(R.id.tvValor); + tvTransacoes = findViewById(R.id.tvTransacoes); + tvValor2 = findViewById(R.id.tvValor2); + tvTransacoes2 = findViewById(R.id.tvTransacoes2); + tvValor3 = findViewById(R.id.tvValor3); + tvTransacoes3 = findViewById(R.id.tvTransacoes3); + tvValor4 = findViewById(R.id.tvValor4); + tvTransacoes4 = findViewById(R.id.tvTransacoes4); + tvTitulo = findViewById(R.id.tvTitulo); + tvTitulo2 = findViewById(R.id.tvTitulo2); + + spinnerMes = findViewById(R.id.spinnerMes); + spinnerAno = findViewById(R.id.spinnerAno); + + setupSpinners(); + Fragment transacoesFragment2 = new TransacoesFragment(); getSupportFragmentManager().beginTransaction() .replace(R.id.fragmentContainerView, transacoesFragment2) @@ -93,4 +135,108 @@ public class TelaInicialActivity extends AppCompatActivity { .commit(); }); } + + private void setupSpinners() { + ArrayAdapter mesAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, meses); + mesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinnerMes.setAdapter(mesAdapter); + + int currentYear = Calendar.getInstance().get(Calendar.YEAR); + List anos = new ArrayList<>(); + for (int i = currentYear - 5; i <= currentYear + 5; i++) { + anos.add(String.valueOf(i)); + } + ArrayAdapter anoAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, anos); + anoAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinnerAno.setAdapter(anoAdapter); + + // Set current month and year + spinnerMes.setSelection(Calendar.getInstance().get(Calendar.MONTH)); + spinnerAno.setSelection(anos.indexOf(String.valueOf(currentYear))); + + AdapterView.OnItemSelectedListener listener = new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, android.view.View view, int position, long id) { + carregarDados(); + } + + @Override + public void onNothingSelected(AdapterView parent) {} + }; + + spinnerMes.setOnItemSelectedListener(listener); + spinnerAno.setOnItemSelectedListener(listener); + } + + private void carregarDados() { + FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + if (user == null) return; + + int mesSelecionado = spinnerMes.getSelectedItemPosition() + 1; // 1 to 12 + String anoSelecionado = spinnerAno.getSelectedItem().toString(); + + String mesNome = meses[spinnerMes.getSelectedItemPosition()]; + tvTitulo.setText("Receitas (" + mesNome + " " + anoSelecionado + ")"); + tvTitulo2.setText("Despesas (" + mesNome + " " + anoSelecionado + ")"); + + DatabaseReference transacoesRef = FirebaseDatabase.getInstance().getReference() + .child("users").child(user.getUid()).child("transacoes"); + + transacoesRef.addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot snapshot) { + double totalReceitas = 0; + double totalDespesas = 0; + int countReceitas = 0; + int countDespesas = 0; + + for (DataSnapshot ds : snapshot.getChildren()) { + Transacao transacao = ds.getValue(Transacao.class); + if (transacao != null && transacao.getData() != null) { + String[] parts = transacao.getData().split("/"); + if (parts.length == 3) { + try { + int mesTransacao = Integer.parseInt(parts[1]); + String anoTransacao = parts[2]; + + if (mesTransacao == mesSelecionado && anoTransacao.equals(anoSelecionado)) { + double valor = Double.parseDouble(transacao.getValor().replace(",", ".")); + if ("Receita".equals(transacao.getTipo())) { + totalReceitas += valor; + countReceitas++; + } else if ("Despesa".equals(transacao.getTipo())) { + totalDespesas += valor; + countDespesas++; + } + } + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + } + } + + tvValor.setText(String.format(Locale.getDefault(), "%.2f€", totalReceitas)); + tvTransacoes.setText(countReceitas + " transações"); + + tvValor2.setText(String.format(Locale.getDefault(), "%.2f€", totalDespesas)); + tvTransacoes2.setText(countDespesas + " transações"); + + double saldo = totalReceitas - totalDespesas; + tvValor3.setText(String.format(Locale.getDefault(), "%.2f€", saldo)); + if (saldo >= 0) { + tvTransacoes3.setText("Poupança positiva"); + tvTransacoes3.setTextColor(android.graphics.Color.parseColor("#8E8E8E")); + } else { + tvTransacoes3.setText("Poupança negativa"); + tvTransacoes3.setTextColor(android.graphics.Color.parseColor("#FF0000")); + } + } + + @Override + public void onCancelled(@NonNull DatabaseError error) { + Toast.makeText(TelaInicialActivity.this, "Erro ao carregar dados", Toast.LENGTH_SHORT).show(); + } + }); + } } diff --git a/app/src/main/java/com/example/lifegrid/adapters/MetaAdapter.java b/app/src/main/java/com/example/lifegrid/adapters/MetaAdapter.java new file mode 100644 index 0000000..32b8175 --- /dev/null +++ b/app/src/main/java/com/example/lifegrid/adapters/MetaAdapter.java @@ -0,0 +1,144 @@ +package com.example.lifegrid.adapters; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.example.lifegrid.R; +import com.example.lifegrid.models.Meta; +import com.google.android.material.button.MaterialButton; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +public class MetaAdapter extends RecyclerView.Adapter { + + private List metasList; + private OnItemClickListener listener; + + public interface OnItemClickListener { + void onDeleteClick(Meta meta); + void onAddValueClick(Meta meta, double valorAdicional, EditText editText); + } + + public MetaAdapter(List metasList, OnItemClickListener listener) { + this.metasList = metasList; + this.listener = listener; + } + + @NonNull + @Override + public MetaViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_meta, parent, false); + return new MetaViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull MetaViewHolder holder, int position) { + Meta meta = metasList.get(position); + + holder.tvNome.setText(meta.getNome()); + holder.tvCategoria.setText(meta.getCategoria()); + + double valorObjetivo = 0; + double valorGuardado = 0; + + try { + valorObjetivo = Double.parseDouble(meta.getValor().replace(",", ".")); + if (meta.getValorGuardado() != null && !meta.getValorGuardado().isEmpty()) { + valorGuardado = Double.parseDouble(meta.getValorGuardado().replace(",", ".")); + } + } catch (NumberFormatException e) { + e.printStackTrace(); + } + + holder.tvValorStatus.setText(String.format(Locale.getDefault(), "%.2f€ / %.2f€", valorGuardado, valorObjetivo)); + + int progress = 0; + if (valorObjetivo > 0) { + progress = (int) ((valorGuardado / valorObjetivo) * 100); + if (progress > 100) progress = 100; + } + holder.pbProgresso.setProgress(progress); + holder.tvPercentagem.setText(progress + ".0%"); + + // Calculate days remaining + long daysRemaining = 0; + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()); + try { + Date goalDate = sdf.parse(meta.getData()); + if (goalDate != null) { + long diff = goalDate.getTime() - new Date().getTime(); + daysRemaining = diff / (1000 * 60 * 60 * 24); + } + } catch (ParseException e) { + e.printStackTrace(); + } + + if (daysRemaining >= 0) { + holder.tvDiasRestantes.setText("Faltam " + daysRemaining + " dias"); + } else { + holder.tvDiasRestantes.setText("Atrasado " + Math.abs(daysRemaining) + " dias"); + } + + holder.ivDelete.setOnClickListener(v -> { + if (listener != null) { + listener.onDeleteClick(meta); + } + }); + + holder.btnAddValor.setOnClickListener(v -> { + if (listener != null) { + String input = holder.etAdicionarValor.getText().toString().trim(); + if (!input.isEmpty()) { + try { + double valorAdicional = Double.parseDouble(input); + listener.onAddValueClick(meta, valorAdicional, holder.etAdicionarValor); + } catch (NumberFormatException e) { + Toast.makeText(v.getContext(), "Valor inválido", Toast.LENGTH_SHORT).show(); + } + } + } + }); + } + + @Override + public int getItemCount() { + return metasList.size(); + } + + public static class MetaViewHolder extends RecyclerView.ViewHolder { + ImageView ivIcon, ivDelete, ivCalendar; + TextView tvNome, tvCategoria, tvLabelProgresso, tvValorStatus, tvDiasRestantes, tvPercentagem; + ProgressBar pbProgresso; + EditText etAdicionarValor; + MaterialButton btnAddValor; + + public MetaViewHolder(@NonNull View itemView) { + super(itemView); + ivIcon = itemView.findViewById(R.id.ivIcon); + ivDelete = itemView.findViewById(R.id.ivDelete); + ivCalendar = itemView.findViewById(R.id.ivCalendar); + tvNome = itemView.findViewById(R.id.tvNome); + tvCategoria = itemView.findViewById(R.id.tvCategoria); + tvLabelProgresso = itemView.findViewById(R.id.tvLabelProgresso); + tvValorStatus = itemView.findViewById(R.id.tvValorStatus); + tvDiasRestantes = itemView.findViewById(R.id.tvDiasRestantes); + tvPercentagem = itemView.findViewById(R.id.tvPercentagem); + pbProgresso = itemView.findViewById(R.id.pbProgresso); + etAdicionarValor = itemView.findViewById(R.id.etAdicionarValor); + btnAddValor = itemView.findViewById(R.id.btnAddValor); + } + } +} diff --git a/app/src/main/java/com/example/lifegrid/adapters/TransacaoAdapter.java b/app/src/main/java/com/example/lifegrid/adapters/TransacaoAdapter.java new file mode 100644 index 0000000..1f666dd --- /dev/null +++ b/app/src/main/java/com/example/lifegrid/adapters/TransacaoAdapter.java @@ -0,0 +1,87 @@ +package com.example.lifegrid.adapters; + +import android.graphics.Color; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.example.lifegrid.R; +import com.example.lifegrid.models.Transacao; + +import java.util.List; + +public class TransacaoAdapter extends RecyclerView.Adapter { + + private List transacoesList; + private OnItemClickListener listener; + + public interface OnItemClickListener { + void onDeleteClick(Transacao transacao); + } + + public TransacaoAdapter(List transacoesList, OnItemClickListener listener) { + this.transacoesList = transacoesList; + this.listener = listener; + } + + @NonNull + @Override + public TransacaoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_transacao, parent, false); + return new TransacaoViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull TransacaoViewHolder holder, int position) { + Transacao transacao = transacoesList.get(position); + holder.tvDescricao.setText(transacao.getDescricao()); + holder.tvCategoria.setText(transacao.getCategoria()); + holder.tvData.setText(transacao.getData()); + + if ("Receita".equals(transacao.getTipo())) { + holder.ivIconBackground.setBackgroundResource(R.drawable.bg_circle_green); + holder.ivIcon.setImageResource(R.drawable.diagonalarrowrightup_110941); + holder.ivIcon.setColorFilter(Color.parseColor("#2ECC71")); + holder.tvValor.setText("+" + transacao.getValor() + "€"); + holder.tvValor.setTextColor(Color.parseColor("#2ECC71")); + } else { + holder.ivIconBackground.setBackgroundResource(R.drawable.bg_circle_red); + holder.ivIcon.setImageResource(R.drawable.diagonalarrowleftdownoutline_110924); + holder.ivIcon.setColorFilter(Color.parseColor("#E74C3C")); + holder.tvValor.setText("-" + transacao.getValor() + "€"); + holder.tvValor.setTextColor(Color.parseColor("#E74C3C")); + } + + holder.ivDelete.setOnClickListener(v -> { + if (listener != null) { + listener.onDeleteClick(transacao); + } + }); + } + + @Override + public int getItemCount() { + return transacoesList.size(); + } + + public static class TransacaoViewHolder extends RecyclerView.ViewHolder { + ImageView ivIconBackground, ivIcon, ivDelete; + TextView tvDescricao, tvCategoria, tvData, tvValor; + + public TransacaoViewHolder(@NonNull View itemView) { + super(itemView); + ivIconBackground = itemView.findViewById(R.id.ivIconBackground); + ivIcon = itemView.findViewById(R.id.ivIcon); + ivDelete = itemView.findViewById(R.id.ivDelete); + tvDescricao = itemView.findViewById(R.id.tvDescricao); + tvCategoria = itemView.findViewById(R.id.tvCategoria); + tvData = itemView.findViewById(R.id.tvData); + tvValor = itemView.findViewById(R.id.tvValor); + } + } +} 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 7a5ec6f..9b23106 100644 --- a/app/src/main/java/com/example/lifegrid/menu/MetasFragment.java +++ b/app/src/main/java/com/example/lifegrid/menu/MetasFragment.java @@ -14,16 +14,32 @@ import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; +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.adapters.MetaAdapter; import com.example.lifegrid.models.Meta; +import com.example.lifegrid.models.Transacao; import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.database.DataSnapshot; +import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.ValueEventListener; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; /** * MetasFragment projeta objetivos futuros onde o utilizador fixa montantes e datas a alcançar @@ -31,6 +47,13 @@ import com.google.firebase.database.FirebaseDatabase; */ public class MetasFragment extends Fragment { + private RecyclerView rvMetas; + private MetaAdapter metaAdapter; + private List metasList; + private TextView tvEmptyState; + private DatabaseReference databaseReference; + private String userId; + public MetasFragment() { // Construtor público vazio obrigatório } @@ -49,8 +72,99 @@ public class MetasFragment extends Fragment { Button novaTransacaoButton = root.findViewById(R.id.novaTransacaoButton); novaTransacaoButton.setOnClickListener(v -> showNovaMetaDialog()); + rvMetas = root.findViewById(R.id.rvMetas); + tvEmptyState = root.findViewById(R.id.textView13); + + rvMetas.setLayoutManager(new LinearLayoutManager(requireContext())); + metasList = new ArrayList<>(); + + metaAdapter = new MetaAdapter(metasList, new MetaAdapter.OnItemClickListener() { + @Override + public void onDeleteClick(Meta meta) { + new AlertDialog.Builder(requireContext()) + .setTitle("Excluir Meta") + .setMessage("Tem a certeza que deseja excluir esta meta?") + .setPositiveButton("Sim", (dialog, which) -> { + if (databaseReference != null && userId != null && meta.getId() != null) { + databaseReference.child("users").child(userId).child("metas").child(meta.getId()).removeValue(); + Toast.makeText(requireContext(), "Meta excluída.", Toast.LENGTH_SHORT).show(); + } + }) + .setNegativeButton("Não", null) + .show(); + } + + @Override + public void onAddValueClick(Meta meta, double valorAdicional, EditText editText) { + if (databaseReference != null && userId != null && meta.getId() != null) { + double valorAtual = 0; + if (meta.getValorGuardado() != null && !meta.getValorGuardado().isEmpty()) { + valorAtual = Double.parseDouble(meta.getValorGuardado().replace(",", ".")); + } + + double novoValor = valorAtual + valorAdicional; + + // Update Meta + databaseReference.child("users").child(userId).child("metas").child(meta.getId()) + .child("valorGuardado").setValue(String.format(Locale.US, "%.2f", novoValor)); + + // Create a Despesa Transaction to adjust the global balance (Receitas - Despesas) + String todayDate = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()).format(new Date()); + Transacao transacao = new Transacao("Despesa", String.format(Locale.US, "%.2f", valorAdicional), "Investimento/Meta", "Adicionado à meta: " + meta.getNome(), todayDate); + + String key = databaseReference.child("users").child(userId).child("transacoes").push().getKey(); + if (key != null) { + databaseReference.child("users").child(userId).child("transacoes").child(key).setValue(transacao); + } + + editText.setText(""); + Toast.makeText(requireContext(), "Valor adicionado e despesa registada!", Toast.LENGTH_SHORT).show(); + } + } + }); + + rvMetas.setAdapter(metaAdapter); + + carregarMetas(); + return root; } + + private void carregarMetas() { + FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser(); + if (currentUser == null) return; + + userId = currentUser.getUid(); + databaseReference = FirebaseDatabase.getInstance().getReference(); + + databaseReference.child("users").child(userId).child("metas").addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot snapshot) { + metasList.clear(); + for (DataSnapshot ds : snapshot.getChildren()) { + Meta m = ds.getValue(Meta.class); + if (m != null) { + m.setId(ds.getKey()); + metasList.add(m); + } + } + metaAdapter.notifyDataSetChanged(); + + if (metasList.isEmpty()) { + tvEmptyState.setVisibility(View.VISIBLE); + rvMetas.setVisibility(View.GONE); + } else { + tvEmptyState.setVisibility(View.GONE); + rvMetas.setVisibility(View.VISIBLE); + } + } + + @Override + public void onCancelled(@NonNull DatabaseError error) { + Toast.makeText(requireContext(), "Erro ao carregar metas.", Toast.LENGTH_SHORT).show(); + } + }); + } private void showNovaMetaDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()); 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 2dbb2ab..93a288d 100644 --- a/app/src/main/java/com/example/lifegrid/menu/TransacoesFragment.java +++ b/app/src/main/java/com/example/lifegrid/menu/TransacoesFragment.java @@ -25,12 +25,21 @@ import java.util.Calendar; import java.util.Locale; import com.example.lifegrid.R; +import com.example.lifegrid.adapters.TransacaoAdapter; 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.DataSnapshot; +import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.ValueEventListener; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import java.util.ArrayList; +import java.util.List; /** * TransacoesFragment controla a aba pertencente às listagens e histórico de carteira e gestão de dados base. @@ -38,7 +47,12 @@ import com.google.firebase.database.FirebaseDatabase; */ public class TransacoesFragment extends Fragment { - + private RecyclerView rvTransacoes; + private TransacaoAdapter transacaoAdapter; + private List transacoesList; + private TextView tvEmptyState; + private DatabaseReference databaseReference; + private String userId; public TransacoesFragment() { // Construtor público vazio obrigatório @@ -60,8 +74,67 @@ public class TransacoesFragment extends Fragment { Button novaTransacaoButton = root.findViewById(R.id.novaTransacaoButton); novaTransacaoButton.setOnClickListener(v -> showNovaTransacaoDialog()); + rvTransacoes = root.findViewById(R.id.rvTransacoes); + tvEmptyState = root.findViewById(R.id.textView13); + + rvTransacoes.setLayoutManager(new LinearLayoutManager(requireContext())); + transacoesList = new ArrayList<>(); + + transacaoAdapter = new TransacaoAdapter(transacoesList, transacao -> { + new AlertDialog.Builder(requireContext()) + .setTitle("Excluir Transação") + .setMessage("Tem a certeza que deseja excluir esta transação?") + .setPositiveButton("Sim", (dialog, which) -> { + if (databaseReference != null && userId != null && transacao.getId() != null) { + databaseReference.child("users").child(userId).child("transacoes").child(transacao.getId()).removeValue(); + Toast.makeText(requireContext(), "Transação excluída.", Toast.LENGTH_SHORT).show(); + } + }) + .setNegativeButton("Não", null) + .show(); + }); + rvTransacoes.setAdapter(transacaoAdapter); + + carregarTransacoes(); + return root; } + + private void carregarTransacoes() { + FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser(); + if (currentUser == null) return; + + userId = currentUser.getUid(); + databaseReference = FirebaseDatabase.getInstance().getReference(); + + databaseReference.child("users").child(userId).child("transacoes").addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot snapshot) { + transacoesList.clear(); + for (DataSnapshot ds : snapshot.getChildren()) { + Transacao t = ds.getValue(Transacao.class); + if (t != null) { + t.setId(ds.getKey()); + transacoesList.add(t); + } + } + transacaoAdapter.notifyDataSetChanged(); + + if (transacoesList.isEmpty()) { + tvEmptyState.setVisibility(View.VISIBLE); + rvTransacoes.setVisibility(View.GONE); + } else { + tvEmptyState.setVisibility(View.GONE); + rvTransacoes.setVisibility(View.VISIBLE); + } + } + + @Override + public void onCancelled(@NonNull DatabaseError error) { + Toast.makeText(requireContext(), "Erro ao carregar transações.", Toast.LENGTH_SHORT).show(); + } + }); + } /** * Cria e monta manualmente uma janela Modal (Pop-up) a fim do utilizador preencher diff --git a/app/src/main/java/com/example/lifegrid/models/Meta.java b/app/src/main/java/com/example/lifegrid/models/Meta.java index 60a8acb..5f12333 100644 --- a/app/src/main/java/com/example/lifegrid/models/Meta.java +++ b/app/src/main/java/com/example/lifegrid/models/Meta.java @@ -5,6 +5,8 @@ public class Meta { private String categoria; private String valor; private String data; + private String valorGuardado = "0.00"; + private String id; public Meta(){ } @@ -47,4 +49,22 @@ public class Meta { public void setData(String data) { this.data = data; } + + public String getValorGuardado() { + return valorGuardado; + } + + public void setValorGuardado(String valorGuardado) { + this.valorGuardado = valorGuardado; + } + + @com.google.firebase.database.Exclude + public String getId() { + return id; + } + + @com.google.firebase.database.Exclude + public void setId(String id) { + this.id = id; + } } diff --git a/app/src/main/java/com/example/lifegrid/models/Transacao.java b/app/src/main/java/com/example/lifegrid/models/Transacao.java index e331e55..72b72fb 100644 --- a/app/src/main/java/com/example/lifegrid/models/Transacao.java +++ b/app/src/main/java/com/example/lifegrid/models/Transacao.java @@ -6,6 +6,7 @@ public class Transacao { private String categoria; private String descricao; private String data; + private String id; public Transacao() { } @@ -58,4 +59,14 @@ public class Transacao { public void setData(String data) { this.data = data; } + + @com.google.firebase.database.Exclude + public String getId() { + return id; + } + + @com.google.firebase.database.Exclude + public void setId(String id) { + this.id = id; + } } diff --git a/app/src/main/res/drawable/bg_badge_category.xml b/app/src/main/res/drawable/bg_badge_category.xml new file mode 100644 index 0000000..e8874bf --- /dev/null +++ b/app/src/main/res/drawable/bg_badge_category.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/app/src/main/res/drawable/bg_circle_green.xml b/app/src/main/res/drawable/bg_circle_green.xml new file mode 100644 index 0000000..e5b289e --- /dev/null +++ b/app/src/main/res/drawable/bg_circle_green.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/src/main/res/drawable/bg_circle_red.xml b/app/src/main/res/drawable/bg_circle_red.xml new file mode 100644 index 0000000..8411912 --- /dev/null +++ b/app/src/main/res/drawable/bg_circle_red.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/src/main/res/drawable/custom_progressbar.xml b/app/src/main/res/drawable/custom_progressbar.xml new file mode 100644 index 0000000..44b0098 --- /dev/null +++ b/app/src/main/res/drawable/custom_progressbar.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_arrow_down.xml b/app/src/main/res/drawable/ic_arrow_down.xml new file mode 100644 index 0000000..77cc245 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_down.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_calendar.xml b/app/src/main/res/drawable/ic_calendar.xml new file mode 100644 index 0000000..c1727ff --- /dev/null +++ b/app/src/main/res/drawable/ic_calendar.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml new file mode 100644 index 0000000..84820cb --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_goal.xml b/app/src/main/res/drawable/ic_goal.xml new file mode 100644 index 0000000..e1ee4fc --- /dev/null +++ b/app/src/main/res/drawable/ic_goal.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_trend_up.xml b/app/src/main/res/drawable/ic_trend_up.xml new file mode 100644 index 0000000..c4b004d --- /dev/null +++ b/app/src/main/res/drawable/ic_trend_up.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/spinner_border_bg.xml b/app/src/main/res/drawable/spinner_border_bg.xml new file mode 100644 index 0000000..053fcdd --- /dev/null +++ b/app/src/main/res/drawable/spinner_border_bg.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_tela_inicial.xml b/app/src/main/res/layout/activity_tela_inicial.xml index e293967..7942f4f 100644 --- a/app/src/main/res/layout/activity_tela_inicial.xml +++ b/app/src/main/res/layout/activity_tela_inicial.xml @@ -32,7 +32,7 @@ android:padding="16dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/textView11"> + app:layout_constraintTop_toBottomOf="@+id/llFiltros"> @@ -119,6 +119,40 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView10" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_transacao.xml b/app/src/main/res/layout/item_transacao.xml new file mode 100644 index 0000000..6031a93 --- /dev/null +++ b/app/src/main/res/layout/item_transacao.xml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + +