Alterei o design para ficar m ais fluido mas falta alterar a cor dos botões e adicionar um botão de voltar no activity_expenses_list.xml e tambem adicionei mais explicações
parent
249eb6f6f2
commit
f021060585
|
|
@ -8,12 +8,16 @@ import androidx.appcompat.app.AppCompatActivity; // Importa classe base para Act
|
||||||
|
|
||||||
import com.google.android.material.button.MaterialButton; // Importa botão Material Design
|
import com.google.android.material.button.MaterialButton; // Importa botão Material Design
|
||||||
import com.google.android.material.textfield.TextInputEditText; // Importa campo de texto Material Design
|
import com.google.android.material.textfield.TextInputEditText; // Importa campo de texto Material Design
|
||||||
|
import com.google.android.material.textfield.MaterialAutoCompleteTextView; // Campo com menu suspenso
|
||||||
|
|
||||||
import java.text.SimpleDateFormat; // Importa classe para formatação de datas
|
import java.text.SimpleDateFormat; // Importa classe para formatação de datas
|
||||||
import java.util.Date; // Importa classe para trabalhar com datas
|
import java.util.Date; // Importa classe para trabalhar com datas
|
||||||
import java.util.Locale; // Importa classe para configurações de localização
|
import java.util.Locale; // Importa classe para configurações de localização
|
||||||
|
import java.util.Arrays; // Utilitário para trabalhar com arrays
|
||||||
|
import java.util.ArrayList; // Lista mutável
|
||||||
|
|
||||||
import pt.epvc.gestodedespesas.data.DatabaseHelper; // DatabaseHelper movido para pacote data
|
import pt.epvc.gestodedespesas.data.DatabaseHelper; // DatabaseHelper movido para pacote data
|
||||||
|
import android.widget.ArrayAdapter; // Adapter para preencher o dropdown
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AddExpenseActivity - Tela de Adicionar/Editar Despesas
|
* AddExpenseActivity - Tela de Adicionar/Editar Despesas
|
||||||
|
|
@ -30,7 +34,8 @@ import pt.epvc.gestodedespesas.data.DatabaseHelper; // DatabaseHelper movido par
|
||||||
public class AddExpenseActivity extends AppCompatActivity { // Declara classe que estende AppCompatActivity
|
public class AddExpenseActivity extends AppCompatActivity { // Declara classe que estende AppCompatActivity
|
||||||
|
|
||||||
// Views da interface - campos de entrada do formulário
|
// Views da interface - campos de entrada do formulário
|
||||||
private TextInputEditText etDescription, etAmount, etCategory, etDate, etNotes; // Declara campos de texto para entrada de dados
|
private TextInputEditText etDescription, etAmount, etDate, etNotes; // Declara campos de texto para entrada de dados
|
||||||
|
private MaterialAutoCompleteTextView etCategory; // Campo de categoria com dropdown
|
||||||
private MaterialButton btnSave, btnCancel; // Declara botões de ação
|
private MaterialButton btnSave, btnCancel; // Declara botões de ação
|
||||||
|
|
||||||
// Objetos para funcionalidade
|
// Objetos para funcionalidade
|
||||||
|
|
@ -59,6 +64,8 @@ public class AddExpenseActivity extends AppCompatActivity { // Declara classe qu
|
||||||
// Para nova despesa, define a data atual como padrão
|
// Para nova despesa, define a data atual como padrão
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()); // Cria formato de data brasileiro
|
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()); // Cria formato de data brasileiro
|
||||||
etDate.setText(sdf.format(new Date())); // Define data atual no campo de data
|
etDate.setText(sdf.format(new Date())); // Define data atual no campo de data
|
||||||
|
// Categoria padrão opcional (ex.: "Outros") para facilitar
|
||||||
|
etCategory.setText("Outros", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,13 +77,26 @@ public class AddExpenseActivity extends AppCompatActivity { // Declara classe qu
|
||||||
// Conecta os campos de entrada de texto
|
// Conecta os campos de entrada de texto
|
||||||
etDescription = findViewById(R.id.etDescription); // Busca campo de descrição por ID e atribui à variável
|
etDescription = findViewById(R.id.etDescription); // Busca campo de descrição por ID e atribui à variável
|
||||||
etAmount = findViewById(R.id.etAmount); // Busca campo de valor por ID e atribui à variável
|
etAmount = findViewById(R.id.etAmount); // Busca campo de valor por ID e atribui à variável
|
||||||
etCategory = findViewById(R.id.etCategory); // Busca campo de categoria por ID e atribui à variável
|
etCategory = findViewById(R.id.etCategory); // Busca campo de categoria (dropdown) por ID
|
||||||
etDate = findViewById(R.id.etDate); // Busca campo de data por ID e atribui à variável
|
etDate = findViewById(R.id.etDate); // Busca campo de data por ID e atribui à variável
|
||||||
etNotes = findViewById(R.id.etNotes); // Busca campo de notas por ID e atribui à variável
|
etNotes = findViewById(R.id.etNotes); // Busca campo de notas por ID e atribui à variável
|
||||||
|
|
||||||
// Conecta os botões de ação
|
// Conecta os botões de ação
|
||||||
btnSave = findViewById(R.id.btnSave); // Busca botão salvar por ID e atribui à variável
|
btnSave = findViewById(R.id.btnSave); // Busca botão salvar por ID e atribui à variável
|
||||||
btnCancel = findViewById(R.id.btnCancel); // Busca botão cancelar por ID e atribui à variável
|
btnCancel = findViewById(R.id.btnCancel); // Busca botão cancelar por ID e atribui à variável
|
||||||
|
|
||||||
|
// Configura o dropdown de categorias com as mesmas opções do filtro
|
||||||
|
String[] allCategories = getResources().getStringArray(R.array.expense_categories); // Inclui "Todas"
|
||||||
|
ArrayList<String> formCategories = new ArrayList<>(Arrays.asList(allCategories));
|
||||||
|
formCategories.remove("Todas"); // Remove "Todas" do formulário (apenas para filtro)
|
||||||
|
ArrayAdapter<String> categoryAdapter = new ArrayAdapter<>(
|
||||||
|
this,
|
||||||
|
android.R.layout.simple_list_item_1,
|
||||||
|
formCategories
|
||||||
|
);
|
||||||
|
etCategory.setAdapter(categoryAdapter);
|
||||||
|
etCategory.setOnClickListener(v -> etCategory.showDropDown()); // Abre ao tocar
|
||||||
|
etCategory.setOnFocusChangeListener((v, hasFocus) -> { if (hasFocus) etCategory.showDropDown(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ import androidx.core.view.WindowInsetsCompat; // Insets de janela
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager; // Layout vertical
|
import androidx.recyclerview.widget.LinearLayoutManager; // Layout vertical
|
||||||
import androidx.recyclerview.widget.RecyclerView; // Lista eficiente
|
import androidx.recyclerview.widget.RecyclerView; // Lista eficiente
|
||||||
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton; // Botão flutuante
|
|
||||||
import com.google.android.material.button.MaterialButton; // Botão Material
|
import com.google.android.material.button.MaterialButton; // Botão Material
|
||||||
|
|
||||||
import java.text.DecimalFormat; // Formatar valores monetários
|
import java.text.DecimalFormat; // Formatar valores monetários
|
||||||
|
|
@ -34,13 +33,12 @@ public class ExpensesListActivity extends AppCompatActivity implements ExpenseAd
|
||||||
|
|
||||||
private RecyclerView recyclerViewExpenses; // Lista de despesas
|
private RecyclerView recyclerViewExpenses; // Lista de despesas
|
||||||
private TextView tvTotal, tvExpenseCount, tvAverage; // Indicadores de total, contagem e média
|
private TextView tvTotal, tvExpenseCount, tvAverage; // Indicadores de total, contagem e média
|
||||||
private FloatingActionButton fabAddExpense; // Botão flutuante para adicionar
|
|
||||||
private MaterialButton btnFilter; // Botão para filtrar por categoria
|
private MaterialButton btnFilter; // Botão para filtrar por categoria
|
||||||
private DatabaseHelper databaseHelper; // Acesso ao SQLite
|
private DatabaseHelper databaseHelper; // Acesso ao SQLite
|
||||||
private ExpenseAdapter expenseAdapter; // Adapter do RecyclerView
|
private ExpenseAdapter expenseAdapter; // Adapter do RecyclerView
|
||||||
private List<Expense> expenseList; // Dados das despesas
|
private List<Expense> expenseList; // Dados das despesas
|
||||||
private DecimalFormat currencyFormat = new DecimalFormat("€#,##0.00"); // Formatação em euro
|
private DecimalFormat currencyFormat = new DecimalFormat("€#,##0.00"); // Formatação em euro
|
||||||
private boolean isShowingEmptyState = false; // Controle de qual layout está visível (lista ou estado vazio)
|
private View emptyStateView; // Container do empty state incluído no layout
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onCreate: configura layout, Edge-to-Edge e listeners de insets, inicializa
|
* onCreate: configura layout, Edge-to-Edge e listeners de insets, inicializa
|
||||||
|
|
@ -50,8 +48,19 @@ public class ExpensesListActivity extends AppCompatActivity implements ExpenseAd
|
||||||
protected void onCreate(Bundle savedInstanceState) { // Ciclo de vida: criação da Activity
|
protected void onCreate(Bundle savedInstanceState) { // Ciclo de vida: criação da Activity
|
||||||
super.onCreate(savedInstanceState); // Chama implementação base
|
super.onCreate(savedInstanceState); // Chama implementação base
|
||||||
EdgeToEdge.enable(this); // Ativa layout de ponta a ponta
|
EdgeToEdge.enable(this); // Ativa layout de ponta a ponta
|
||||||
databaseHelper = new DatabaseHelper(this); // Instancia acesso ao DB (SQLiteHelper)
|
setContentView(R.layout.activity_expenses_list); // Usa layout principal sempre
|
||||||
renderLayoutByData(); // Decide e aplica o layout conforme existência de despesas
|
try {
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
|
||||||
|
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||||
|
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
|
||||||
|
return insets;
|
||||||
|
});
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
databaseHelper = new DatabaseHelper(this); // Instancia acesso ao DB
|
||||||
|
initializeViews(); // Faz bind das views (inclui empty state)
|
||||||
|
setupRecyclerView(); // Configura lista
|
||||||
|
setupClickListeners(); // Configura cliques (filtro e empty state)
|
||||||
|
loadExpenses(); // Carrega dados iniciais
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -63,8 +72,8 @@ public class ExpensesListActivity extends AppCompatActivity implements ExpenseAd
|
||||||
tvTotal = findViewById(R.id.tvTotal); // Texto do total gasto
|
tvTotal = findViewById(R.id.tvTotal); // Texto do total gasto
|
||||||
tvExpenseCount = findViewById(R.id.tvExpenseCount); // Texto da contagem
|
tvExpenseCount = findViewById(R.id.tvExpenseCount); // Texto da contagem
|
||||||
tvAverage = findViewById(R.id.tvAverage); // Texto da média
|
tvAverage = findViewById(R.id.tvAverage); // Texto da média
|
||||||
fabAddExpense = findViewById(R.id.fabAddExpense); // FAB adicionar
|
|
||||||
btnFilter = findViewById(R.id.btnFilter); // Botão filtrar
|
btnFilter = findViewById(R.id.btnFilter); // Botão filtrar
|
||||||
|
emptyStateView = findViewById(R.id.emptyStateContainer); // Empty state incluído
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Toast.makeText(this, "Erro ao inicializar views: " + e.getMessage(), Toast.LENGTH_LONG).show(); // Feedback de erro
|
Toast.makeText(this, "Erro ao inicializar views: " + e.getMessage(), Toast.LENGTH_LONG).show(); // Feedback de erro
|
||||||
}
|
}
|
||||||
|
|
@ -92,16 +101,6 @@ public class ExpensesListActivity extends AppCompatActivity implements ExpenseAd
|
||||||
*/
|
*/
|
||||||
private void setupClickListeners() {
|
private void setupClickListeners() {
|
||||||
try {
|
try {
|
||||||
if (fabAddExpense != null) { // Verifica se a view foi encontrada
|
|
||||||
fabAddExpense.setOnClickListener(new View.OnClickListener() { // Clique do FAB
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) { // Ação ao clicar
|
|
||||||
Intent intent = new Intent(ExpensesListActivity.this, AddExpenseActivity.class); // Ir para adicionar
|
|
||||||
startActivityForResult(intent, 1); // Abrir aguardando resultado
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (btnFilter != null) { // Verifica existência do botão
|
if (btnFilter != null) { // Verifica existência do botão
|
||||||
btnFilter.setOnClickListener(new View.OnClickListener() { // Clique do filtro
|
btnFilter.setOnClickListener(new View.OnClickListener() { // Clique do filtro
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -110,6 +109,18 @@ public class ExpensesListActivity extends AppCompatActivity implements ExpenseAd
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Botões do empty state (se presentes no include)
|
||||||
|
View add = findViewById(R.id.btnAddFirstExpense);
|
||||||
|
if (add != null) {
|
||||||
|
add.setOnClickListener(v -> {
|
||||||
|
Intent intent = new Intent(ExpensesListActivity.this, AddExpenseActivity.class);
|
||||||
|
startActivityForResult(intent, 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
View back = findViewById(R.id.btnBackFromEmpty);
|
||||||
|
if (back != null) {
|
||||||
|
back.setOnClickListener(v -> finish());
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Toast.makeText(this, "Erro ao configurar click listeners: " + e.getMessage(), Toast.LENGTH_LONG).show(); // Feedback de erro
|
Toast.makeText(this, "Erro ao configurar click listeners: " + e.getMessage(), Toast.LENGTH_LONG).show(); // Feedback de erro
|
||||||
}
|
}
|
||||||
|
|
@ -122,20 +133,15 @@ public class ExpensesListActivity extends AppCompatActivity implements ExpenseAd
|
||||||
private void loadExpenses() {
|
private void loadExpenses() {
|
||||||
try {
|
try {
|
||||||
expenseList = databaseHelper.getAllExpenses(); // Puxa despesas do DB
|
expenseList = databaseHelper.getAllExpenses(); // Puxa despesas do DB
|
||||||
boolean hasData = expenseList != null && !expenseList.isEmpty();
|
if (expenseAdapter != null) { // Atualiza a lista
|
||||||
if (!hasData) {
|
expenseAdapter.updateExpenses(expenseList);
|
||||||
if (!isShowingEmptyState) {
|
|
||||||
renderEmptyLayout();
|
|
||||||
}
|
|
||||||
return; // Nada para atualizar no layout vazio
|
|
||||||
}
|
|
||||||
if (isShowingEmptyState) {
|
|
||||||
renderMainLayout();
|
|
||||||
}
|
|
||||||
if (expenseAdapter != null) { // Garante adapter existente
|
|
||||||
expenseAdapter.updateExpenses(expenseList); // Atualiza lista na UI
|
|
||||||
}
|
}
|
||||||
updateTotal(); // Recalcula indicadores
|
updateTotal(); // Recalcula indicadores
|
||||||
|
// Mostra/oculta o empty state no fim da tela
|
||||||
|
boolean isEmpty = expenseList == null || expenseList.isEmpty();
|
||||||
|
if (emptyStateView != null) {
|
||||||
|
emptyStateView.setVisibility(isEmpty ? View.VISIBLE : View.GONE);
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Toast.makeText(this, "Erro ao carregar despesas: " + e.getMessage(), Toast.LENGTH_LONG).show(); // Feedback de erro
|
Toast.makeText(this, "Erro ao carregar despesas: " + e.getMessage(), Toast.LENGTH_LONG).show(); // Feedback de erro
|
||||||
}
|
}
|
||||||
|
|
@ -178,14 +184,11 @@ public class ExpensesListActivity extends AppCompatActivity implements ExpenseAd
|
||||||
} else { // Categoria específica
|
} else { // Categoria específica
|
||||||
String category = categories[which]; // Nome da categoria
|
String category = categories[which]; // Nome da categoria
|
||||||
expenseList = databaseHelper.getExpensesByCategory(category); // Busca filtrada
|
expenseList = databaseHelper.getExpensesByCategory(category); // Busca filtrada
|
||||||
if (expenseList == null || expenseList.isEmpty()) {
|
expenseAdapter.updateExpenses(expenseList); // Atualiza adapter (lista pode ficar vazia)
|
||||||
renderEmptyLayout();
|
|
||||||
} else {
|
|
||||||
if (isShowingEmptyState) {
|
|
||||||
renderMainLayout();
|
|
||||||
}
|
|
||||||
expenseAdapter.updateExpenses(expenseList); // Atualiza adapter
|
|
||||||
updateTotal(); // Recalcula totais com filtro
|
updateTotal(); // Recalcula totais com filtro
|
||||||
|
boolean isEmpty = expenseList == null || expenseList.isEmpty();
|
||||||
|
if (emptyStateView != null) {
|
||||||
|
emptyStateView.setVisibility(isEmpty ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -230,54 +233,5 @@ public class ExpensesListActivity extends AppCompatActivity implements ExpenseAd
|
||||||
.show(); // Exibe diálogo
|
.show(); // Exibe diálogo
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Métodos de alternância de layout foram substituídos por um include do empty state no XML
|
||||||
* Decide qual layout usar com base nos dados atuais do DB.
|
|
||||||
*/
|
|
||||||
private void renderLayoutByData() { // Decide qual layout mostrar com base nos dados
|
|
||||||
try {
|
|
||||||
List<Expense> initial = databaseHelper.getAllExpenses(); // Consulta inicial ao DB
|
|
||||||
if (initial == null || initial.isEmpty()) { // Sem dados?
|
|
||||||
renderEmptyLayout(); // Mostra estado vazio
|
|
||||||
} else { // Há dados
|
|
||||||
expenseList = initial; // Mantém em memória
|
|
||||||
renderMainLayout(); // Mostra lista principal
|
|
||||||
}
|
|
||||||
} catch (Exception e) { // Qualquer erro
|
|
||||||
renderEmptyLayout(); // Fallback: evita crash mostrando estado vazio
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mostra o layout principal de lista, inicializa views/adapter e listeners.
|
|
||||||
*/
|
|
||||||
private void renderMainLayout() { // Exibe layout principal de lista
|
|
||||||
setContentView(R.layout.activity_expenses_list); // Aplica XML de lista
|
|
||||||
isShowingEmptyState = false; // Marca que a lista está ativa
|
|
||||||
try {
|
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { // Listener de insets
|
|
||||||
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); // Áreas das barras
|
|
||||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); // Padding seguro
|
|
||||||
return insets; // Continua propagação
|
|
||||||
});
|
|
||||||
} catch (Exception ignored) { } // Se não existir view com id main, ignora
|
|
||||||
initializeViews(); // Associa views do layout
|
|
||||||
setupRecyclerView(); // Configura RecyclerView e adapter
|
|
||||||
setupClickListeners(); // Registra cliques (FAB e filtro)
|
|
||||||
updateTotal(); // Atualiza totais na UI
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mostra o layout de estado vazio e configura o botão de adicionar.
|
|
||||||
*/
|
|
||||||
private void renderEmptyLayout() { // Exibe layout de estado vazio
|
|
||||||
setContentView(R.layout.empty_state); // Aplica XML vazio
|
|
||||||
isShowingEmptyState = true; // Marca que estado vazio está ativo
|
|
||||||
View add = findViewById(R.id.btnAddFirstExpense); // Botão "Adicionar Despesa"
|
|
||||||
if (add != null) { // Se existir no layout
|
|
||||||
add.setOnClickListener(v -> { // Ao clicar
|
|
||||||
Intent intent = new Intent(ExpensesListActivity.this, AddExpenseActivity.class); // Abre tela de adição
|
|
||||||
startActivityForResult(intent, 1); // Aguarda resultado para recarregar
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,8 +112,8 @@ public class MainActivity extends AppCompatActivity { // Declara classe que este
|
||||||
btnViewExpenses.setOnClickListener(new View.OnClickListener() { // Define listener de clique para o botão "Ver Despesas"
|
btnViewExpenses.setOnClickListener(new View.OnClickListener() { // Define listener de clique para o botão "Ver Despesas"
|
||||||
@Override // Sobrescreve método da interface
|
@Override // Sobrescreve método da interface
|
||||||
public void onClick(View v) { // Método chamado quando botão é clicado
|
public void onClick(View v) { // Método chamado quando botão é clicado
|
||||||
// Navega para a tela simplificada de lista de despesas
|
// Navega para a tela avançada de lista de despesas (usa empty_state e activity_expenses_list)
|
||||||
Intent intent = new Intent(MainActivity.this, SimpleExpensesActivity.class); // Cria Intent para navegar para SimpleExpensesActivity
|
Intent intent = new Intent(MainActivity.this, ExpensesListActivity.class); // Cria Intent para ExpensesListActivity
|
||||||
startActivity(intent); // Inicia Activity sem esperar resultado
|
startActivity(intent); // Inicia Activity sem esperar resultado
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import android.database.Cursor; // Onde ficam os resultados de uma consulta
|
||||||
import android.database.sqlite.SQLiteDatabase; // Objeto que permite ler/escrever no banco
|
import android.database.sqlite.SQLiteDatabase; // Objeto que permite ler/escrever no banco
|
||||||
import android.database.sqlite.SQLiteOpenHelper; // Classe que ajuda a criar e atualizar o banco
|
import android.database.sqlite.SQLiteOpenHelper; // Classe que ajuda a criar e atualizar o banco
|
||||||
|
|
||||||
import java.util.ArrayList; // Lista de tamanho variável
|
import java.util.ArrayList; // Lista de tamanho variável (pode crescer conforme necessário)
|
||||||
import java.util.List; // Tipo "lista" em Java
|
import java.util.List; // Tipo "lista" em Java (coleção de itens)
|
||||||
|
|
||||||
import pt.epvc.gestodedespesas.Expense; // Nossa classe que representa uma despesa
|
import pt.epvc.gestodedespesas.Expense; // Nossa classe que representa uma despesa
|
||||||
|
|
||||||
|
|
@ -23,24 +23,24 @@ public class DatabaseHelper extends SQLiteOpenHelper { // Helper do SQLite
|
||||||
private static final int DATABASE_VERSION = 1; // Versão do banco (muda quando a estrutura mudar)
|
private static final int DATABASE_VERSION = 1; // Versão do banco (muda quando a estrutura mudar)
|
||||||
|
|
||||||
// Nome da tabela e das colunas (os "campos" da tabela)
|
// Nome da tabela e das colunas (os "campos" da tabela)
|
||||||
private static final String TABLE_EXPENSES = "expenses";
|
private static final String TABLE_EXPENSES = "expenses"; // Nome da tabela no banco
|
||||||
private static final String COLUMN_ID = "id";
|
private static final String COLUMN_ID = "id"; // Coluna: identificador único da despesa
|
||||||
private static final String COLUMN_DESCRIPTION = "description";
|
private static final String COLUMN_DESCRIPTION = "description"; // Coluna: descrição do gasto
|
||||||
private static final String COLUMN_AMOUNT = "amount";
|
private static final String COLUMN_AMOUNT = "amount"; // Coluna: valor do gasto
|
||||||
private static final String COLUMN_CATEGORY = "category";
|
private static final String COLUMN_CATEGORY = "category"; // Coluna: categoria do gasto
|
||||||
private static final String COLUMN_DATE = "date";
|
private static final String COLUMN_DATE = "date"; // Coluna: data do gasto (texto formatado)
|
||||||
private static final String COLUMN_NOTES = "notes";
|
private static final String COLUMN_NOTES = "notes"; // Coluna: notas/opcional
|
||||||
|
|
||||||
// Comando que cria a tabela de despesas (rodado somente na primeira vez)
|
// Comando que cria a tabela de despesas (rodado somente na primeira vez)
|
||||||
private static final String CREATE_TABLE_EXPENSES =
|
private static final String CREATE_TABLE_EXPENSES = // Texto do comando para criar a tabela
|
||||||
"CREATE TABLE " + TABLE_EXPENSES + "(" +
|
"CREATE TABLE " + TABLE_EXPENSES + "(" + // Começa criando a tabela "expenses"
|
||||||
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
|
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + // id numérico que cresce sozinho
|
||||||
COLUMN_DESCRIPTION + " TEXT NOT NULL," +
|
COLUMN_DESCRIPTION + " TEXT NOT NULL," + // descrição obrigatória
|
||||||
COLUMN_AMOUNT + " REAL NOT NULL," +
|
COLUMN_AMOUNT + " REAL NOT NULL," + // valor obrigatório (número)
|
||||||
COLUMN_CATEGORY + " TEXT NOT NULL," +
|
COLUMN_CATEGORY + " TEXT NOT NULL," + // categoria obrigatória
|
||||||
COLUMN_DATE + " TEXT NOT NULL," +
|
COLUMN_DATE + " TEXT NOT NULL," + // data obrigatória (guardada como texto)
|
||||||
COLUMN_NOTES + " TEXT" +
|
COLUMN_NOTES + " TEXT" + // notas opcionais
|
||||||
")";
|
")"; // fecha o comando
|
||||||
|
|
||||||
public DatabaseHelper(Context context) { // Chamado quando precisamos usar o banco
|
public DatabaseHelper(Context context) { // Chamado quando precisamos usar o banco
|
||||||
super(context, DATABASE_NAME, null, DATABASE_VERSION); // Diz o nome e a versão do banco
|
super(context, DATABASE_NAME, null, DATABASE_VERSION); // Diz o nome e a versão do banco
|
||||||
|
|
@ -73,11 +73,11 @@ public class DatabaseHelper extends SQLiteOpenHelper { // Helper do SQLite
|
||||||
|
|
||||||
public Expense getExpense(int id) { // Busca uma despesa específica pelo id
|
public Expense getExpense(int id) { // Busca uma despesa específica pelo id
|
||||||
SQLiteDatabase db = this.getReadableDatabase(); // Abre o banco para leitura
|
SQLiteDatabase db = this.getReadableDatabase(); // Abre o banco para leitura
|
||||||
Cursor cursor = db.query(
|
Cursor cursor = db.query( // Faz uma consulta procurando pelo id
|
||||||
TABLE_EXPENSES,
|
TABLE_EXPENSES, // na tabela de despesas
|
||||||
new String[]{COLUMN_ID, COLUMN_DESCRIPTION, COLUMN_AMOUNT, COLUMN_CATEGORY, COLUMN_DATE, COLUMN_NOTES},
|
new String[]{COLUMN_ID, COLUMN_DESCRIPTION, COLUMN_AMOUNT, COLUMN_CATEGORY, COLUMN_DATE, COLUMN_NOTES}, // colunas desejadas
|
||||||
COLUMN_ID + "=?",
|
COLUMN_ID + "=?", // condição: id igual ao informado
|
||||||
new String[]{String.valueOf(id)}, null, null, null, null
|
new String[]{String.valueOf(id)}, null, null, null, null // valor do id
|
||||||
);
|
);
|
||||||
|
|
||||||
if (cursor != null && cursor.moveToFirst()) { // Se achou o registro
|
if (cursor != null && cursor.moveToFirst()) { // Se achou o registro
|
||||||
|
|
@ -100,9 +100,9 @@ public class DatabaseHelper extends SQLiteOpenHelper { // Helper do SQLite
|
||||||
|
|
||||||
public List<Expense> getAllExpenses() { // Busca todas as despesas, mais recentes primeiro
|
public List<Expense> getAllExpenses() { // Busca todas as despesas, mais recentes primeiro
|
||||||
List<Expense> expenseList = new ArrayList<>(); // Cria uma lista vazia
|
List<Expense> expenseList = new ArrayList<>(); // Cria uma lista vazia
|
||||||
String selectQuery = "SELECT * FROM " + TABLE_EXPENSES + " ORDER BY " + COLUMN_DATE + " DESC"; // Consulta
|
String selectQuery = "SELECT * FROM " + TABLE_EXPENSES + " ORDER BY " + COLUMN_DATE + " DESC"; // Consulta: tudo, ordenado pela data (mais recente primeiro)
|
||||||
SQLiteDatabase db = this.getWritableDatabase(); // Abre o banco
|
SQLiteDatabase db = this.getWritableDatabase(); // Abre o banco
|
||||||
Cursor cursor = db.rawQuery(selectQuery, null); // Executa a consulta
|
Cursor cursor = db.rawQuery(selectQuery, null); // Executa a consulta e devolve um "cursor" para navegar
|
||||||
|
|
||||||
if (cursor.moveToFirst()) { // Se tem pelo menos uma linha
|
if (cursor.moveToFirst()) { // Se tem pelo menos uma linha
|
||||||
do { // Repete para cada linha
|
do { // Repete para cada linha
|
||||||
|
|
@ -157,10 +157,10 @@ public class DatabaseHelper extends SQLiteOpenHelper { // Helper do SQLite
|
||||||
List<Expense> expenseList = new ArrayList<>(); // Lista vazia
|
List<Expense> expenseList = new ArrayList<>(); // Lista vazia
|
||||||
SQLiteDatabase db = this.getReadableDatabase(); // Abre para leitura
|
SQLiteDatabase db = this.getReadableDatabase(); // Abre para leitura
|
||||||
Cursor cursor = db.query( // Faz a consulta com filtro de categoria
|
Cursor cursor = db.query( // Faz a consulta com filtro de categoria
|
||||||
TABLE_EXPENSES,
|
TABLE_EXPENSES, // tabela "expenses"
|
||||||
new String[]{COLUMN_ID, COLUMN_DESCRIPTION, COLUMN_AMOUNT, COLUMN_CATEGORY, COLUMN_DATE, COLUMN_NOTES},
|
new String[]{COLUMN_ID, COLUMN_DESCRIPTION, COLUMN_AMOUNT, COLUMN_CATEGORY, COLUMN_DATE, COLUMN_NOTES}, // colunas
|
||||||
COLUMN_CATEGORY + "=?",
|
COLUMN_CATEGORY + "=?", // condição de filtro
|
||||||
new String[]{category}, null, null, COLUMN_DATE + " DESC", null
|
new String[]{category}, null, null, COLUMN_DATE + " DESC", null // valor do filtro e ordenação
|
||||||
);
|
);
|
||||||
|
|
||||||
if (cursor.moveToFirst()) { // Se achou resultados
|
if (cursor.moveToFirst()) { // Se achou resultados
|
||||||
|
|
|
||||||
|
|
@ -89,14 +89,17 @@
|
||||||
android:hint="Categoria"
|
android:hint="Categoria"
|
||||||
app:startIconDrawable="@drawable/ic_category"
|
app:startIconDrawable="@drawable/ic_category"
|
||||||
app:boxStrokeColor="@color/primary_color"
|
app:boxStrokeColor="@color/primary_color"
|
||||||
app:hintTextColor="@color/primary_color">
|
app:hintTextColor="@color/primary_color"
|
||||||
|
app:endIconMode="dropdown_menu">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
||||||
android:id="@+id/etCategory"
|
android:id="@+id/etCategory"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:inputType="text"
|
android:inputType="none"
|
||||||
android:textColor="@color/text_primary" />
|
android:textColor="@color/text_primary"
|
||||||
|
android:hint="Selecione uma categoria"
|
||||||
|
android:entries="@array/expense_categories" />
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -225,23 +225,16 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="80dp" />
|
android:layout_marginBottom="80dp" />
|
||||||
|
|
||||||
|
<!-- Empty state embutido (mostrado quando não há despesas) -->
|
||||||
|
<include
|
||||||
|
android:id="@+id/emptyStateContainer"
|
||||||
|
layout="@layout/empty_state"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
<!-- Floating Action Button -->
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
||||||
android:id="@+id/fabAddExpense"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end|bottom"
|
|
||||||
android:layout_margin="16dp"
|
|
||||||
android:src="@drawable/ic_add_white"
|
|
||||||
app:backgroundTint="@color/primary_color"
|
|
||||||
app:borderWidth="0dp"
|
|
||||||
app:elevation="12dp"
|
|
||||||
app:fabSize="normal"
|
|
||||||
app:tint="@color/white"
|
|
||||||
app:rippleColor="@color/primary_dark" />
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
|
||||||
|
|
@ -33,40 +33,40 @@
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="32dp"
|
android:padding="32dp">
|
||||||
android:gravity="center">
|
|
||||||
|
|
||||||
<!-- Ícone principal -->
|
<!-- Ícone principal -->
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="120dp"
|
android:layout_width="120dp"
|
||||||
android:layout_height="120dp"
|
android:layout_height="120dp"
|
||||||
android:src="@drawable/ic_wallet"
|
android:layout_marginBottom="24dp"
|
||||||
android:background="@drawable/welcome_icon_background"
|
android:background="@drawable/welcome_icon_background"
|
||||||
android:padding="24dp"
|
android:padding="24dp"
|
||||||
android:layout_marginBottom="24dp" />
|
android:src="@drawable/ic_wallet" />
|
||||||
|
|
||||||
<!-- Título principal -->
|
<!-- Título principal -->
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="💰 Gestão de Despesas"
|
android:layout_marginBottom="12dp"
|
||||||
android:textSize="32sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:textColor="@color/text_primary"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:layout_marginBottom="12dp" />
|
android:text="💰 Gestão de Despesas"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textSize="32sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<!-- Subtítulo -->
|
<!-- Subtítulo -->
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Controle seus gastos de forma inteligente e organizada"
|
android:layout_marginBottom="24dp"
|
||||||
android:textSize="16sp"
|
|
||||||
android:textColor="@color/text_secondary"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:lineSpacingExtra="4dp"
|
android:lineSpacingExtra="4dp"
|
||||||
android:layout_marginBottom="24dp" />
|
android:text="Controle seus gastos de forma inteligente e organizada"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
<!-- Botão principal -->
|
<!-- Botão principal -->
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
|
|
@ -74,14 +74,14 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="56dp"
|
android:layout_height="56dp"
|
||||||
android:text="🚀 Começar Agora"
|
android:text="🚀 Começar Agora"
|
||||||
android:textSize="18sp"
|
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
|
android:textSize="18sp"
|
||||||
app:backgroundTint="@color/primary_color"
|
app:backgroundTint="@color/primary_color"
|
||||||
app:cornerRadius="28dp"
|
app:cornerRadius="28dp"
|
||||||
|
app:elevation="6dp"
|
||||||
app:icon="@drawable/ic_rocket"
|
app:icon="@drawable/ic_rocket"
|
||||||
app:iconTint="@color/white"
|
|
||||||
app:iconSize="24dp"
|
app:iconSize="24dp"
|
||||||
app:elevation="6dp" />
|
app:iconTint="@color/white" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,4 +45,16 @@
|
||||||
app:icon="@drawable/ic_add_white"
|
app:icon="@drawable/ic_add_white"
|
||||||
app:iconTint="@color/white" />
|
app:iconTint="@color/white" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btnBackFromEmpty"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:text="🔙 Voltar"
|
||||||
|
android:textColor="@color/primary_color"
|
||||||
|
app:backgroundTint="@android:color/transparent"
|
||||||
|
app:strokeColor="@color/primary_color"
|
||||||
|
app:strokeWidth="2dp"
|
||||||
|
app:cornerRadius="20dp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,13 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Gestão de Despesas</string>
|
<string name="app_name">Gestão de Despesas</string>
|
||||||
|
|
||||||
|
<string-array name="expense_categories">
|
||||||
|
<item>Todas</item>
|
||||||
|
<item>Alimentação</item>
|
||||||
|
<item>Transporte</item>
|
||||||
|
<item>Entretenimento</item>
|
||||||
|
<item>Saúde</item>
|
||||||
|
<item>Compras</item>
|
||||||
|
<item>Outros</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
||||||
Loading…
Reference in New Issue