This commit is contained in:
2026-05-11 15:00:55 +01:00
parent e7ead2a066
commit 413019cfac
5 changed files with 304 additions and 8 deletions

View File

@@ -68,4 +68,5 @@ dependencies {
androidTestImplementation(libs.ui.test.junit4)
debugImplementation(libs.ui.tooling)
debugImplementation(libs.ui.test.manifest)
implementation("com.github.PhilJay:MPAndroidChart:v3.1.0")
}

View File

@@ -298,6 +298,9 @@ public class TelaInicialActivity extends AppCompatActivity {
((HomeFragment) currentFragment).carregarDados(mesSelecionado, anoSelecionado, mesNome);
} else if (currentFragment instanceof TransacoesFragment) {
((TransacoesFragment) currentFragment).setFiltro(mesSelecionado, anoSelecionado);
} else if (currentFragment instanceof GraficosFragment) {
String mesNome = meses[spinnerMes.getSelectedItemPosition()];
((GraficosFragment) currentFragment).setFiltro(mesSelecionado, anoSelecionado, mesNome);
}
}

View File

@@ -2,20 +2,57 @@ package com.example.lifegrid.menu;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import com.example.lifegrid.R;
import com.example.lifegrid.models.Transacao;
import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.charts.PieChart;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.PieData;
import com.github.mikephil.charting.data.PieDataSet;
import com.github.mikephil.charting.data.PieEntry;
import com.github.mikephil.charting.formatter.IndexAxisValueFormatter;
import com.github.mikephil.charting.utils.ColorTemplate;
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 java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 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.
* componente puramente matemática exibida de forma ilustrativa. Trata da visão de Dashboard de estatística.
*/
public class GraficosFragment extends Fragment {
private PieChart pieChartMensal;
private BarChart barChartAnual;
private TextView tvTituloMensal;
private TextView tvTituloAnual;
private List<Transacao> allTransacoesList = new ArrayList<>();
private int currentMes = -1;
private String currentAno = "";
private String currentMesNome = "";
public GraficosFragment() {
// Construtor público vazio obrigatório
}
@@ -25,13 +62,200 @@ public class GraficosFragment extends Fragment {
super.onCreate(savedInstanceState);
}
@Override
public void onResume() {
super.onResume();
if (getActivity() instanceof com.example.lifegrid.TelaInicialActivity) {
((com.example.lifegrid.TelaInicialActivity) getActivity()).atualizarDadosHome();
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflaciona o layout para este fragmento
View root = inflater.inflate(R.layout.fragment_graficos, container, false);
pieChartMensal = root.findViewById(R.id.pieChartMensal);
barChartAnual = root.findViewById(R.id.barChartAnual);
tvTituloMensal = root.findViewById(R.id.tvTituloMensal);
tvTituloAnual = root.findViewById(R.id.tvTituloAnual);
configurarGraficos();
carregarTransacoes();
return root;
}
private void configurarGraficos() {
// Config PieChart
pieChartMensal.getDescription().setEnabled(false);
pieChartMensal.setUsePercentValues(true);
pieChartMensal.setEntryLabelColor(android.graphics.Color.BLACK);
pieChartMensal.setEntryLabelTextSize(12f);
pieChartMensal.setCenterText("Despesas");
pieChartMensal.setCenterTextSize(18f);
// Config BarChart
barChartAnual.getDescription().setEnabled(false);
barChartAnual.setDrawGridBackground(false);
barChartAnual.getAxisRight().setEnabled(false);
XAxis xAxis = barChartAnual.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
xAxis.setGranularity(1f);
xAxis.setCenterAxisLabels(true);
String[] mesesLabel = new String[]{"Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"};
xAxis.setValueFormatter(new IndexAxisValueFormatter(mesesLabel));
}
private void carregarTransacoes() {
FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
if (currentUser == null) return;
String userId = currentUser.getUid();
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference();
databaseReference.child("users").child(userId).child("transacoes").addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
allTransacoesList.clear();
for (DataSnapshot ds : snapshot.getChildren()) {
Transacao t = ds.getValue(Transacao.class);
if (t != null) {
t.setId(ds.getKey());
allTransacoesList.add(t);
}
}
atualizarGraficos();
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
if (getContext() != null) {
Toast.makeText(getContext(), "Erro ao carregar transações.", Toast.LENGTH_SHORT).show();
}
}
});
}
public void setFiltro(int mesSelecionado, String anoSelecionado, String mesNome) {
this.currentMes = mesSelecionado;
this.currentAno = anoSelecionado;
this.currentMesNome = mesNome;
if (tvTituloMensal != null) {
tvTituloMensal.setText("Resumo de " + mesNome + " " + anoSelecionado);
}
}
if (tvTituloAnual != null) {
tvTituloAnual.setText("Balanço Anual - " + anoSelecionado);
}
atualizarGraficos();
}
private void atualizarGraficos() {
if (currentMes == -1 || currentAno.isEmpty()) return;
atualizarPieChart();
atualizarBarChart();
}
private void atualizarPieChart() {
Map<String, Float> categoriasMap = new HashMap<>();
for (Transacao t : allTransacoesList) {
if (t.getData() != null && t.getTipo() != null && t.getTipo().equalsIgnoreCase("Despesa")) {
String[] parts = t.getData().split("/");
if (parts.length == 3) {
try {
int mesTransacao = Integer.parseInt(parts[1]);
String anoTransacao = parts[2];
if (mesTransacao == currentMes && anoTransacao.equals(currentAno)) {
float valor = Float.parseFloat(t.getValor());
String cat = t.getCategoria();
categoriasMap.put(cat, categoriasMap.getOrDefault(cat, 0f) + valor);
}
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
}
}
List<PieEntry> entries = new ArrayList<>();
for (Map.Entry<String, Float> entry : categoriasMap.entrySet()) {
if (entry.getValue() > 0) {
entries.add(new PieEntry(entry.getValue(), entry.getKey()));
}
}
PieDataSet dataSet = new PieDataSet(entries, "");
dataSet.setColors(ColorTemplate.MATERIAL_COLORS);
dataSet.setSliceSpace(3f);
dataSet.setValueTextSize(14f);
dataSet.setValueTextColor(android.graphics.Color.WHITE);
PieData data = new PieData(dataSet);
pieChartMensal.setData(data);
pieChartMensal.invalidate(); // refresh
}
private void atualizarBarChart() {
float[] receitasPorMes = new float[12];
float[] despesasPorMes = new float[12];
for (Transacao t : allTransacoesList) {
if (t.getData() != null) {
String[] parts = t.getData().split("/");
if (parts.length == 3) {
try {
int mesTransacao = Integer.parseInt(parts[1]) - 1; // 0 a 11
String anoTransacao = parts[2];
if (anoTransacao.equals(currentAno) && mesTransacao >= 0 && mesTransacao < 12) {
float valor = Float.parseFloat(t.getValor());
if (t.getTipo() != null && t.getTipo().equalsIgnoreCase("Receita")) {
receitasPorMes[mesTransacao] += valor;
} else {
despesasPorMes[mesTransacao] += valor;
}
}
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
}
}
List<BarEntry> entriesReceitas = new ArrayList<>();
List<BarEntry> entriesDespesas = new ArrayList<>();
for (int i = 0; i < 12; i++) {
entriesReceitas.add(new BarEntry(i, receitasPorMes[i]));
entriesDespesas.add(new BarEntry(i, despesasPorMes[i]));
}
BarDataSet setReceitas = new BarDataSet(entriesReceitas, "Receitas");
setReceitas.setColor(android.graphics.Color.parseColor("#2ECC71"));
setReceitas.setValueTextSize(10f);
BarDataSet setDespesas = new BarDataSet(entriesDespesas, "Despesas");
setDespesas.setColor(android.graphics.Color.parseColor("#E74C3C"));
setDespesas.setValueTextSize(10f);
BarData data = new BarData(setReceitas, setDespesas);
// agrupar barras
float groupSpace = 0.4f;
float barSpace = 0.05f;
float barWidth = 0.25f;
data.setBarWidth(barWidth);
barChartAnual.setData(data);
barChartAnual.groupBars(0f, groupSpace, barSpace);
barChartAnual.getXAxis().setAxisMinimum(0f);
barChartAnual.getXAxis().setAxisMaximum(0f + barChartAnual.getBarData().getGroupWidth(groupSpace, barSpace) * 12);
barChartAnual.invalidate(); // refresh
}
}

View File

@@ -1,14 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
tools:context=".menu.GraficosFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello_blank_fragment" />
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="100dp"
android:paddingTop="16dp">
</FrameLayout>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginBottom="16dp"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
android:backgroundTint="#FFFFFF">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/tvTituloMensal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Resumo Mensal"
android:textColor="#1A202C"
android:textSize="18sp"
android:textStyle="bold" />
<com.github.mikephil.charting.charts.PieChart
android:id="@+id/pieChartMensal"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_marginTop="16dp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginBottom="16dp"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
android:backgroundTint="#FFFFFF">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/tvTituloAnual"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Balanço Anual"
android:textColor="#1A202C"
android:textSize="18sp"
android:textStyle="bold" />
<com.github.mikephil.charting.charts.BarChart
android:id="@+id/barChartAnual"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_marginTop="16dp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
</ScrollView>