Melhoramentos nos designs todos e correção de erros
This commit is contained in:
13
.idea/deviceManager.xml
generated
Normal file
13
.idea/deviceManager.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DeviceTable">
|
||||
<option name="columnSorters">
|
||||
<list>
|
||||
<ColumnSorterState>
|
||||
<option name="column" value="Name" />
|
||||
<option name="order" value="ASCENDING" />
|
||||
</ColumnSorterState>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
@@ -4,9 +4,7 @@ plugins {
|
||||
|
||||
android {
|
||||
namespace = "com.example.finzora"
|
||||
compileSdk {
|
||||
version = release(36)
|
||||
}
|
||||
compileSdk = 36
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.example.finzora"
|
||||
@@ -34,8 +32,12 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.appcompat)
|
||||
implementation(libs.material)
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("com.google.android.material:material:1.13.0")
|
||||
implementation("com.github.PhilJay:MPAndroidChart:v3.1.0")
|
||||
implementation("androidx.viewpager2:viewpager2:1.1.0")
|
||||
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
||||
implementation("com.google.code.gson:gson:2.10.1")
|
||||
implementation(libs.activity)
|
||||
implementation(libs.constraintlayout)
|
||||
testImplementation(libs.junit)
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.example.finzora">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
@@ -10,23 +13,33 @@
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Finzora">
|
||||
android:theme="@style/Theme.Finzora"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".LoginActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
android:exported="true"
|
||||
android:windowSoftInputMode="adjustResize"> <intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".MainActivity" />
|
||||
<activity android:name=".RegisterActivity" />
|
||||
<activity
|
||||
android:name=".RegisterActivity"
|
||||
android:name=".DefinicoesActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".EditarPerfilActivity"
|
||||
android:exported="false" />
|
||||
<activity android:name=".RecuperarPasswordActivity" android:exported="false" />
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="false" />
|
||||
<activity android:name=".OnboardingActivity" android:theme="@style/Theme.AppCompat.NoActionBar"/>
|
||||
|
||||
<activity android:name=".AdicionarTransacaoActivity" />
|
||||
|
||||
<activity android:name=".ProfileActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,178 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
public class AdicionarTransacaoActivity extends AppCompatActivity {
|
||||
|
||||
// Declaração dos componentes do ecrã (Sem os RadioButtons!)
|
||||
private EditText editValor;
|
||||
private Spinner spinnerCategoria;
|
||||
private Button btnGuardar;
|
||||
private ImageView btnVoltar;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_adicionar_transacao);
|
||||
|
||||
inicializarComponentes();
|
||||
|
||||
// --- ENCHER O SPINNER COM AS CATEGORIAS ---
|
||||
String[] categorias = {"Alimentação", "Transportes", "Lazer", "Educação", "Saúde", "Salário", "Mesada", "Prémios", "Outros"};
|
||||
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(
|
||||
this,
|
||||
R.layout.item_dropdown,
|
||||
categorias
|
||||
);
|
||||
adapter.setDropDownViewResource(R.layout.item_dropdown);
|
||||
spinnerCategoria.setAdapter(adapter);
|
||||
|
||||
// Botão para voltar para trás
|
||||
if (btnVoltar != null) {
|
||||
btnVoltar.setOnClickListener(v -> finish());
|
||||
}
|
||||
|
||||
// AGORA O BOTÃO GUARDAR CHAMA O POP-UP!
|
||||
btnGuardar.setOnClickListener(v -> perguntarTipoTransacao());
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// A MAGIA DO POP-UP
|
||||
// ====================================================================
|
||||
private void perguntarTipoTransacao() {
|
||||
String valorStr = editValor.getText().toString().trim();
|
||||
|
||||
// Primeiro, verifica se ele preencheu o valor antes de perguntar o tipo
|
||||
if (TextUtils.isEmpty(valorStr)) {
|
||||
editValor.setError("Preenche o valor primeiro!");
|
||||
editValor.requestFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
// Criar o Pop-up de escolha
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle("Tipo de Transação");
|
||||
builder.setMessage("Esta transação é uma Receita (entrada) ou uma Despesa (saída)?");
|
||||
|
||||
// Botão de Receita (Passa o tipo 1 para a base de dados)
|
||||
builder.setPositiveButton("Receita 📈", (dialog, which) -> {
|
||||
salvarTransacaoNaBaseDeDados(1);
|
||||
});
|
||||
|
||||
// Botão de Despesa (Passa o tipo 2 para a base de dados)
|
||||
builder.setNegativeButton("Despesa 📉", (dialog, which) -> {
|
||||
salvarTransacaoNaBaseDeDados(2);
|
||||
});
|
||||
|
||||
// Botão Cancelar (Caso o utilizador queira fechar e alterar algo)
|
||||
builder.setNeutralButton("Cancelar", (dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
// Mostrar o Pop-up no ecrã
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// GUARDAR NA BASE DE DADOS APÓS A ESCOLHA
|
||||
// ====================================================================
|
||||
private void salvarTransacaoNaBaseDeDados(int tipoEscolhido) {
|
||||
// Primeiro, vamos buscar o "Carimbo" (ID) de quem está a usar a app
|
||||
android.content.SharedPreferences prefs = getSharedPreferences("DadosUtilizador", MODE_PRIVATE);
|
||||
String userId = prefs.getString("user_id", null);
|
||||
|
||||
if (userId == null) {
|
||||
android.widget.Toast.makeText(this, "Erro: Utilizador não identificado. Faz login novamente.", android.widget.Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String valorStr = editValor.getText().toString().trim();
|
||||
valorStr = valorStr.replace(",", "."); // Evitar crashes com vírgulas
|
||||
double valor = Double.parseDouble(valorStr);
|
||||
String categoria = spinnerCategoria.getSelectedItem().toString();
|
||||
String dataStr = new java.text.SimpleDateFormat("dd/MM/yyyy", java.util.Locale.getDefault()).format(new java.util.Date());
|
||||
|
||||
// Mudar o texto do botão para o utilizador perceber que está a gravar
|
||||
btnGuardar.setEnabled(false);
|
||||
btnGuardar.setText("A GRAVAR NAS NUVENS...");
|
||||
|
||||
// Preparar o cliente de Internet
|
||||
okhttp3.OkHttpClient client = new okhttp3.OkHttpClient();
|
||||
|
||||
// Construir o JSON que vai viajar até ao Supabase
|
||||
// AQUI ESTÁ A CORREÇÃO: a coluna chama-se "data" para bater certo com o teu SQL!
|
||||
String json = "{"
|
||||
+ "\"user_id\":\"" + userId + "\", "
|
||||
+ "\"valor\":" + valor + ", "
|
||||
+ "\"categoria\":\"" + categoria + "\", "
|
||||
+ "\"tipo\":" + tipoEscolhido + ", "
|
||||
+ "\"data\":\"" + dataStr + "\""
|
||||
+ "}";
|
||||
|
||||
okhttp3.RequestBody body = okhttp3.RequestBody.create(json, okhttp3.MediaType.parse("application/json; charset=utf-8"));
|
||||
|
||||
// Fazer o pedido POST para a tabela "transacoes" do Supabase
|
||||
okhttp3.Request request = new okhttp3.Request.Builder()
|
||||
.url(SupabaseConfig.SUPABASE_URL + "/rest/v1/transacoes")
|
||||
.addHeader("apikey", SupabaseConfig.SUPABASE_KEY)
|
||||
.addHeader("Authorization", "Bearer " + SupabaseConfig.SUPABASE_KEY)
|
||||
.addHeader("Content-Type", "application/json")
|
||||
.addHeader("Prefer", "return=minimal") // Diz ao Supabase para não devolver os dados de volta
|
||||
.post(body)
|
||||
.build();
|
||||
|
||||
// Executar o envio em segundo plano para não bloquear o ecrã
|
||||
client.newCall(request).enqueue(new okhttp3.Callback() {
|
||||
@Override
|
||||
public void onFailure(@androidx.annotation.NonNull okhttp3.Call call, @androidx.annotation.NonNull java.io.IOException e) {
|
||||
runOnUiThread(() -> {
|
||||
btnGuardar.setEnabled(true);
|
||||
btnGuardar.setText("Guardar Transação");
|
||||
android.widget.Toast.makeText(AdicionarTransacaoActivity.this, "Erro de net! A transação não foi guardada.", android.widget.Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(@androidx.annotation.NonNull okhttp3.Call call, @androidx.annotation.NonNull okhttp3.Response response) throws java.io.IOException {
|
||||
runOnUiThread(() -> {
|
||||
if (response.isSuccessful()) {
|
||||
android.widget.Toast.makeText(AdicionarTransacaoActivity.this, "Transação guardada com sucesso! 🎉", android.widget.Toast.LENGTH_SHORT).show();
|
||||
finish(); // Volta ao ecrã principal
|
||||
} else {
|
||||
btnGuardar.setEnabled(true);
|
||||
btnGuardar.setText("Guardar Transação");
|
||||
android.widget.Toast.makeText(AdicionarTransacaoActivity.this, "Erro no Supabase. Tenta novamente.", android.widget.Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
} catch (Exception e) {
|
||||
android.widget.Toast.makeText(this, "ERRO LOCAL: " + e.getMessage(), android.widget.Toast.LENGTH_LONG).show();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private void inicializarComponentes() {
|
||||
editValor = findViewById(R.id.editValor);
|
||||
spinnerCategoria = findViewById(R.id.spinnerCategoria);
|
||||
btnGuardar = findViewById(R.id.btnGuardar);
|
||||
btnVoltar = findViewById(R.id.btnVoltar);
|
||||
}
|
||||
}
|
||||
154
app/src/main/java/com/example/finzora/DBHelper.java
Normal file
154
app/src/main/java/com/example/finzora/DBHelper.java
Normal file
@@ -0,0 +1,154 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DBHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final String DATABASE_NAME = "finzora.db";
|
||||
private static final int DATABASE_VERSION = 2; // Versão 2 para incluir Orçamentos
|
||||
|
||||
public DBHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
// Criação da Tabela de Transações
|
||||
db.execSQL("CREATE TABLE transacoes (id INTEGER PRIMARY KEY AUTOINCREMENT, valor REAL, categoria TEXT, tipo INTEGER, data TEXT)");
|
||||
|
||||
// Criação da Tabela de Orçamentos
|
||||
db.execSQL("CREATE TABLE orcamentos (categoria TEXT PRIMARY KEY, valor_limite REAL)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
db.execSQL("DROP TABLE IF EXISTS transacoes");
|
||||
db.execSQL("DROP TABLE IF EXISTS orcamentos");
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// MÉTODOS PARA AS TRANSAÇÕES
|
||||
// ==========================================
|
||||
|
||||
public void adicionarTransacao(Transacao transacao) {
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("valor", transacao.getValor());
|
||||
values.put("categoria", transacao.getCategoria());
|
||||
values.put("tipo", transacao.getTipo());
|
||||
values.put("data", transacao.getData());
|
||||
db.insert("transacoes", null, values);
|
||||
}
|
||||
|
||||
public List<Transacao> listarTransacoes() {
|
||||
List<Transacao> lista = new ArrayList<>();
|
||||
SQLiteDatabase db = this.getReadableDatabase();
|
||||
Cursor cursor = db.rawQuery("SELECT * FROM transacoes ORDER BY id DESC", null);
|
||||
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
lista.add(new Transacao(
|
||||
cursor.getInt(0), // id
|
||||
cursor.getFloat(1), // valor
|
||||
cursor.getString(2),// categoria
|
||||
cursor.getInt(3), // tipo
|
||||
cursor.getString(4) // data
|
||||
));
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
cursor.close();
|
||||
return lista;
|
||||
}
|
||||
|
||||
public void eliminarTransacao(int id) {
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
db.delete("transacoes", "id=?", new String[]{String.valueOf(id)});
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// MÉTODOS PARA OS ORÇAMENTOS
|
||||
// ==========================================
|
||||
|
||||
public void salvarOrcamento(String categoria, float limite) {
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("categoria", categoria);
|
||||
values.put("valor_limite", limite);
|
||||
// CONFLICT_REPLACE garante que se a categoria já existir, ele só atualiza o limite
|
||||
db.insertWithOnConflict("orcamentos", null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
||||
}
|
||||
|
||||
public Map<String, Float> getOrcamentosDefinidos() {
|
||||
Map<String, Float> orcamentos = new HashMap<>();
|
||||
SQLiteDatabase db = this.getReadableDatabase();
|
||||
Cursor cursor = db.rawQuery("SELECT * FROM orcamentos", null);
|
||||
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
orcamentos.put(cursor.getString(0), cursor.getFloat(1));
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
cursor.close();
|
||||
return orcamentos;
|
||||
}
|
||||
|
||||
public float getGastoPorCategoria(String categoria) {
|
||||
SQLiteDatabase db = this.getReadableDatabase();
|
||||
// Soma todas as transações que sejam Despesa (tipo=2) na categoria escolhida
|
||||
Cursor cursor = db.rawQuery("SELECT SUM(valor) FROM transacoes WHERE tipo=2 AND categoria=?", new String[]{categoria});
|
||||
float total = 0;
|
||||
if (cursor.moveToFirst()) {
|
||||
total = cursor.getFloat(0);
|
||||
}
|
||||
cursor.close();
|
||||
return total;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// MATEMÁTICA PARA OS CARTÕES E GRÁFICOS
|
||||
// ==========================================
|
||||
|
||||
// Calcula todo o dinheiro que entrou (Receitas, tipo = 1)
|
||||
public float getTotalReceitas() {
|
||||
SQLiteDatabase db = this.getReadableDatabase();
|
||||
Cursor cursor = db.rawQuery("SELECT SUM(valor) FROM transacoes WHERE tipo=1", null);
|
||||
float total = 0;
|
||||
if (cursor.moveToFirst()) total = cursor.getFloat(0);
|
||||
cursor.close();
|
||||
return total;
|
||||
}
|
||||
|
||||
// Calcula todo o dinheiro que saiu (Despesas, tipo = 2)
|
||||
public float getTotalDespesas() {
|
||||
SQLiteDatabase db = this.getReadableDatabase();
|
||||
Cursor cursor = db.rawQuery("SELECT SUM(valor) FROM transacoes WHERE tipo=2", null);
|
||||
float total = 0;
|
||||
if (cursor.moveToFirst()) total = cursor.getFloat(0);
|
||||
cursor.close();
|
||||
return total;
|
||||
}
|
||||
|
||||
// Prepara os dados para a aba dos Gráficos (Soma os gastos de cada categoria)
|
||||
public HashMap<String, Float> getDespesasPorCategoria() {
|
||||
HashMap<String, Float> mapa = new HashMap<>();
|
||||
SQLiteDatabase db = this.getReadableDatabase();
|
||||
Cursor cursor = db.rawQuery("SELECT categoria, SUM(valor) FROM transacoes WHERE tipo=2 GROUP BY categoria", null);
|
||||
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
mapa.put(cursor.getString(0), cursor.getFloat(1));
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
cursor.close();
|
||||
return mapa;
|
||||
}
|
||||
}
|
||||
175
app/src/main/java/com/example/finzora/DefinicoesActivity.java
Normal file
175
app/src/main/java/com/example/finzora/DefinicoesActivity.java
Normal file
@@ -0,0 +1,175 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
|
||||
public class DefinicoesActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_definicoes);
|
||||
|
||||
// Ligar todos os botões do ecrã ao nosso código Java
|
||||
TextView btnVoltarDefinicoes = findViewById(R.id.btnVoltarDefinicoes);
|
||||
TextView btnEditarPerfil = findViewById(R.id.btnEditarPerfil);
|
||||
Switch switchModoEscuro = findViewById(R.id.switchModoEscuro);
|
||||
Switch switchNotificacoes = findViewById(R.id.switchNotificacoes);
|
||||
TextView btnSuporte = findViewById(R.id.btnSuporte);
|
||||
Button btnTerminarSessao = findViewById(R.id.btnTerminarSessao);
|
||||
|
||||
// --- 0. BOTÃO DE VOLTAR ---
|
||||
btnVoltarDefinicoes.setOnClickListener(v -> finish());
|
||||
|
||||
// --- 1. EDITAR PERFIL ---
|
||||
// Agora já abre o novo ecrã de Edição de Perfil!
|
||||
btnEditarPerfil.setOnClickListener(v -> {
|
||||
startActivity(new Intent(DefinicoesActivity.this, EditarPerfilActivity.class));
|
||||
});
|
||||
|
||||
// --- 2. MAGIA DO MODO ESCURO / CLARO ---
|
||||
SharedPreferences prefsTema = getSharedPreferences("TemaApp", MODE_PRIVATE);
|
||||
boolean isModoEscuro = prefsTema.getBoolean("modo_escuro", true);
|
||||
switchModoEscuro.setChecked(isModoEscuro);
|
||||
|
||||
switchModoEscuro.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
prefsTema.edit().putBoolean("modo_escuro", isChecked).apply();
|
||||
|
||||
if (isChecked) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
Toast.makeText(this, "Modo Escuro Ativado 🌙", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||
Toast.makeText(this, "Modo Claro Ativado ☀️", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
// --- 3. NOTIFICAÇÕES ---
|
||||
switchNotificacoes.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
if (isChecked) {
|
||||
Toast.makeText(this, "Notificações Ligadas 🔔", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Toast.makeText(this, "Notificações Desligadas 🔕", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
// --- 4. CENTRO DE SUPORTE (POP-UP) ---
|
||||
btnSuporte.setOnClickListener(v -> mostrarDialogSuporte());
|
||||
|
||||
// --- 5. TERMINAR SESSÃO ---
|
||||
btnTerminarSessao.setOnClickListener(v -> terminarSessao());
|
||||
}
|
||||
|
||||
private void mostrarDialogSuporte() {
|
||||
Dialog dialog = new Dialog(this);
|
||||
dialog.setContentView(R.layout.dialog_suporte);
|
||||
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
// O Botão de Fechar o Pop-up principal
|
||||
dialog.findViewById(R.id.btnFecharSuporte).setOnClickListener(v -> dialog.dismiss());
|
||||
|
||||
// Ligar os cliques nos Cartões
|
||||
dialog.findViewById(R.id.cardFAQ).setOnClickListener(v -> {
|
||||
dialog.dismiss(); // Fecha este menu
|
||||
mostrarDialogFAQ(); // Abre o FAQ
|
||||
});
|
||||
|
||||
dialog.findViewById(R.id.cardTutorial).setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
mostrarDialogTutorial();
|
||||
});
|
||||
|
||||
dialog.findViewById(R.id.cardMensagem).setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
mostrarDialogContactar();
|
||||
});
|
||||
|
||||
dialog.findViewById(R.id.cardContactos).setOnClickListener(v -> {
|
||||
Toast.makeText(this, "Email: suporte@finzora.pt\nTel: +351 800 123 456", Toast.LENGTH_LONG).show();
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void mostrarDialogFAQ() {
|
||||
Dialog dialog = new Dialog(this);
|
||||
dialog.setContentView(R.layout.dialog_faq);
|
||||
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
// Setinha de voltar (Fecha o FAQ e volta a abrir o menu principal)
|
||||
dialog.findViewById(R.id.btnVoltarFAQ).setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
mostrarDialogSuporte();
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void mostrarDialogTutorial() {
|
||||
Dialog dialog = new Dialog(this);
|
||||
dialog.setContentView(R.layout.dialog_tutorial);
|
||||
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
// Setinha de voltar
|
||||
dialog.findViewById(R.id.btnVoltarTutorial).setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
mostrarDialogSuporte();
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void mostrarDialogContactar() {
|
||||
Dialog dialog = new Dialog(this);
|
||||
dialog.setContentView(R.layout.dialog_contactar);
|
||||
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
// Setinha de voltar
|
||||
dialog.findViewById(R.id.btnVoltarContactar).setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
mostrarDialogSuporte();
|
||||
});
|
||||
|
||||
// Botões do formulário
|
||||
dialog.findViewById(R.id.btnCancelarContacto).setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
mostrarDialogSuporte();
|
||||
});
|
||||
|
||||
dialog.findViewById(R.id.btnEnviarMensagem).setOnClickListener(v -> {
|
||||
Toast.makeText(this, "Mensagem enviada com sucesso!", Toast.LENGTH_SHORT).show();
|
||||
dialog.dismiss();
|
||||
mostrarDialogSuporte();
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void terminarSessao() {
|
||||
SharedPreferences prefs = getSharedPreferences("DadosUtilizador", MODE_PRIVATE);
|
||||
prefs.edit().clear().apply();
|
||||
|
||||
Toast.makeText(this, "Sessão terminada com sucesso!", Toast.LENGTH_SHORT).show();
|
||||
|
||||
Intent intent = new Intent(this, LoginActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,163 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class DicasFragment extends Fragment {
|
||||
|
||||
// Componentes de Saúde Financeira
|
||||
private TextView tvTaxaPoupanca, tvDicasReceitas, tvDicasDespesas;
|
||||
private ProgressBar progressPoupanca;
|
||||
|
||||
// Componentes das Dicas
|
||||
private TextView tvTituloDica1, tvDescDica1;
|
||||
private TextView tvTituloDica2, tvDescDica2;
|
||||
|
||||
// Distribuição de Gastos
|
||||
private LinearLayout layoutDistribuicao;
|
||||
|
||||
private DBHelper dbHelper;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_dicas, container, false);
|
||||
|
||||
// Ligar os componentes
|
||||
tvTaxaPoupanca = view.findViewById(R.id.tvTaxaPoupanca);
|
||||
tvDicasReceitas = view.findViewById(R.id.tvDicasReceitas);
|
||||
tvDicasDespesas = view.findViewById(R.id.tvDicasDespesas);
|
||||
progressPoupanca = view.findViewById(R.id.progressPoupanca);
|
||||
|
||||
tvTituloDica1 = view.findViewById(R.id.tvTituloDica1);
|
||||
tvDescDica1 = view.findViewById(R.id.tvDescDica1);
|
||||
tvTituloDica2 = view.findViewById(R.id.tvTituloDica2);
|
||||
tvDescDica2 = view.findViewById(R.id.tvDescDica2);
|
||||
|
||||
layoutDistribuicao = view.findViewById(R.id.layoutDistribuicao);
|
||||
|
||||
dbHelper = new DBHelper(getActivity());
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
analisarFinancas();
|
||||
}
|
||||
|
||||
private void analisarFinancas() {
|
||||
float receitas = dbHelper.getTotalReceitas();
|
||||
float despesas = dbHelper.getTotalDespesas();
|
||||
|
||||
// 1. Atualizar Textos Iniciais
|
||||
tvDicasReceitas.setText(String.format("€ %.2f", receitas));
|
||||
tvDicasDespesas.setText(String.format("€ %.2f", despesas));
|
||||
|
||||
// 2. Calcular Taxa de Poupança
|
||||
float taxaPoupanca = 0;
|
||||
if (receitas > 0) {
|
||||
taxaPoupanca = ((receitas - despesas) / receitas) * 100;
|
||||
}
|
||||
|
||||
// Se gastou mais do que ganhou, a taxa é 0
|
||||
if (taxaPoupanca < 0) taxaPoupanca = 0;
|
||||
|
||||
tvTaxaPoupanca.setText(String.format("%.1f%%", taxaPoupanca));
|
||||
progressPoupanca.setProgress((int) taxaPoupanca);
|
||||
|
||||
// Cores consoante a saúde financeira
|
||||
if (taxaPoupanca >= 20) {
|
||||
tvTaxaPoupanca.setTextColor(Color.parseColor("#00E676")); // Verde
|
||||
progressPoupanca.setProgressTintList(ColorStateList.valueOf(Color.parseColor("#00E676")));
|
||||
|
||||
tvTituloDica1.setText("Excelente Taxa de Poupança! \uD83C\uDF1F");
|
||||
tvTituloDica1.setTextColor(Color.parseColor("#00E676"));
|
||||
tvDescDica1.setText("Estás a poupar " + String.format("%.1f", taxaPoupanca) + "% dos teus rendimentos. Continua com este ótimo hábito financeiro!");
|
||||
} else if (taxaPoupanca > 0) {
|
||||
tvTaxaPoupanca.setTextColor(Color.parseColor("#FFD600")); // Amarelo
|
||||
progressPoupanca.setProgressTintList(ColorStateList.valueOf(Color.parseColor("#FFD600")));
|
||||
|
||||
tvTituloDica1.setText("Atenção à Poupança \uD83D\uDD0D");
|
||||
tvTituloDica1.setTextColor(Color.parseColor("#FFD600"));
|
||||
tvDescDica1.setText("Estás a poupar muito pouco. A meta recomendada é guardar pelo menos 20% do que ganhas.");
|
||||
} else {
|
||||
tvTaxaPoupanca.setTextColor(Color.parseColor("#FF1744")); // Vermelho
|
||||
progressPoupanca.setProgressTintList(ColorStateList.valueOf(Color.parseColor("#FF1744")));
|
||||
|
||||
tvTituloDica1.setText("Alerta Vermelho! \uD83D\uDEA8");
|
||||
tvTituloDica1.setTextColor(Color.parseColor("#FF1744"));
|
||||
tvDescDica1.setText("Os teus gastos superam ou igualam os teus ganhos. Verifica urgentemente para onde está a ir o teu dinheiro!");
|
||||
}
|
||||
|
||||
// 3. Descobrir a Categoria mais gasta
|
||||
HashMap<String, Float> gastosPorCategoria = dbHelper.getDespesasPorCategoria();
|
||||
String piorCategoria = "Nenhuma";
|
||||
float maiorGasto = 0;
|
||||
|
||||
for (Map.Entry<String, Float> entry : gastosPorCategoria.entrySet()) {
|
||||
if (entry.getValue() > maiorGasto) {
|
||||
maiorGasto = entry.getValue();
|
||||
piorCategoria = entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
if (maiorGasto > 0) {
|
||||
float percPiorCategoria = (maiorGasto / despesas) * 100;
|
||||
tvTituloDica2.setText("Gastos Elevados em " + piorCategoria);
|
||||
tvTituloDica2.setTextColor(Color.parseColor("#FF1744"));
|
||||
tvDescDica2.setText(String.format("%.1f%%", percPiorCategoria) + " das tuas despesas são em " + piorCategoria + " (€ " + String.format("%.2f", maiorGasto) + "). Tenta reduzir aqui!");
|
||||
} else {
|
||||
tvTituloDica2.setText("Tudo Controlado ✅");
|
||||
tvTituloDica2.setTextColor(Color.parseColor("#00E676"));
|
||||
tvDescDica2.setText("Ainda não tens despesas suficientes para analisarmos. Continua o bom trabalho!");
|
||||
}
|
||||
|
||||
// 4. Construir as barras de Distribuição de Gastos magicamente
|
||||
layoutDistribuicao.removeAllViews(); // Limpa as barras antigas
|
||||
|
||||
if (despesas > 0) {
|
||||
for (Map.Entry<String, Float> entry : gastosPorCategoria.entrySet()) {
|
||||
float valorCat = entry.getValue();
|
||||
if (valorCat > 0) {
|
||||
float percentagem = (valorCat / despesas) * 100;
|
||||
|
||||
// Criar o título da categoria (Ex: Alimentação - €50.00 (20%))
|
||||
TextView tvCat = new TextView(getActivity());
|
||||
tvCat.setText(entry.getKey() + " — € " + String.format("%.2f", valorCat) + " (" + (int) percentagem + "%)");
|
||||
tvCat.setTextColor(Color.WHITE);
|
||||
tvCat.setTextSize(14f);
|
||||
tvCat.setPadding(0, 16, 0, 8); // Margens
|
||||
|
||||
// Criar a barra de progresso horizontal
|
||||
ProgressBar pb = new ProgressBar(getActivity(), null, android.R.attr.progressBarStyleHorizontal);
|
||||
pb.setMax(100);
|
||||
pb.setProgress((int) percentagem);
|
||||
pb.setProgressTintList(ColorStateList.valueOf(Color.parseColor("#00E5FF"))); // Azul Tech
|
||||
|
||||
// Adicionar ao ecrã
|
||||
layoutDistribuicao.addView(tvCat);
|
||||
layoutDistribuicao.addView(pb);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TextView semDespesas = new TextView(getActivity());
|
||||
semDespesas.setText("Ainda não existem despesas registadas.");
|
||||
semDespesas.setTextColor(Color.parseColor("#B0BEC5"));
|
||||
layoutDistribuicao.addView(semDespesas);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
public class EditarPerfilActivity extends AppCompatActivity {
|
||||
|
||||
private EditText editNomePerfil;
|
||||
private EditText editEmailPerfil;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_editar_perfil);
|
||||
|
||||
// Ligar ao XML
|
||||
TextView btnVoltar = findViewById(R.id.btnVoltarEditarPerfil);
|
||||
editNomePerfil = findViewById(R.id.editNomePerfil);
|
||||
editEmailPerfil = findViewById(R.id.editEmailPerfil);
|
||||
Button btnGuardarPerfil = findViewById(R.id.btnGuardarPerfil);
|
||||
|
||||
// Voltar para as definições
|
||||
btnVoltar.setOnClickListener(v -> finish());
|
||||
|
||||
// 1. CARREGAR OS DADOS ATUAIS DA MEMÓRIA
|
||||
SharedPreferences prefs = getSharedPreferences("DadosUtilizador", MODE_PRIVATE);
|
||||
String nomeAtual = prefs.getString("nome_usuario", "Investidor");
|
||||
String emailAtual = prefs.getString("email_usuario", ""); // Pode estar vazio se não guardaste no login
|
||||
|
||||
editNomePerfil.setText(nomeAtual);
|
||||
editEmailPerfil.setText(emailAtual);
|
||||
|
||||
// 2. GUARDAR OS DADOS NOVOS
|
||||
btnGuardarPerfil.setOnClickListener(v -> {
|
||||
String novoNome = editNomePerfil.getText().toString().trim();
|
||||
String novoEmail = editEmailPerfil.getText().toString().trim();
|
||||
|
||||
if (novoNome.isEmpty()) {
|
||||
editNomePerfil.setError("O nome não pode estar vazio!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Grava na memória (SharedPreferences)
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putString("nome_usuario", novoNome);
|
||||
editor.putString("email_usuario", novoEmail);
|
||||
editor.apply();
|
||||
|
||||
Toast.makeText(this, "Perfil atualizado com sucesso! 🎉", Toast.LENGTH_SHORT).show();
|
||||
finish(); // Fecha o ecrã e volta atrás
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,190 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
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 java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class GraficosFragment extends Fragment {
|
||||
|
||||
private PieChart pieChartDespesas;
|
||||
private BarChart barChartOrcamento;
|
||||
private BarChart barChartTendencia;
|
||||
private DBHelper dbHelper;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_graficos, container, false);
|
||||
|
||||
pieChartDespesas = view.findViewById(R.id.pieChartDespesas);
|
||||
barChartOrcamento = view.findViewById(R.id.barChartOrcamento);
|
||||
barChartTendencia = view.findViewById(R.id.barChartTendencia);
|
||||
dbHelper = new DBHelper(getActivity());
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
carregarPieChart();
|
||||
carregarBarChartOrcamento();
|
||||
carregarBarChartTendencia();
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 1. GRÁFICO CIRCULAR (Despesas por Categoria)
|
||||
// ==========================================
|
||||
private void carregarPieChart() {
|
||||
pieChartDespesas.getDescription().setEnabled(false);
|
||||
pieChartDespesas.setHoleColor(Color.parseColor("#2C5364"));
|
||||
pieChartDespesas.getLegend().setTextColor(Color.WHITE);
|
||||
pieChartDespesas.setCenterText("Despesas");
|
||||
pieChartDespesas.setCenterTextColor(Color.WHITE);
|
||||
pieChartDespesas.setEntryLabelColor(Color.WHITE);
|
||||
|
||||
HashMap<String, Float> despesas = dbHelper.getDespesasPorCategoria();
|
||||
ArrayList<PieEntry> entradas = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<String, Float> entry : despesas.entrySet()) {
|
||||
if (entry.getValue() > 0) entradas.add(new PieEntry(entry.getValue(), entry.getKey()));
|
||||
}
|
||||
|
||||
if (entradas.isEmpty()) { pieChartDespesas.clear(); return; }
|
||||
|
||||
PieDataSet dataSet = new PieDataSet(entradas, "");
|
||||
dataSet.setColors(new int[]{Color.parseColor("#7C4DFF"), Color.parseColor("#00E5FF"), Color.parseColor("#FFD600"), Color.parseColor("#FF4081")});
|
||||
|
||||
PieData data = new PieData(dataSet);
|
||||
data.setValueTextSize(14f);
|
||||
data.setValueTextColor(Color.WHITE);
|
||||
pieChartDespesas.setData(data);
|
||||
pieChartDespesas.animateY(1000);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 2. GRÁFICO DE BARRAS (Orçamento vs Gastos)
|
||||
// ==========================================
|
||||
private void carregarBarChartOrcamento() {
|
||||
configurarEstiloBarChart(barChartOrcamento);
|
||||
|
||||
Map<String, Float> orcamentos = dbHelper.getOrcamentosDefinidos();
|
||||
ArrayList<BarEntry> gastosEntries = new ArrayList<>();
|
||||
ArrayList<BarEntry> orcamentoEntries = new ArrayList<>();
|
||||
ArrayList<String> categorias = new ArrayList<>();
|
||||
|
||||
int index = 0;
|
||||
for (Map.Entry<String, Float> entry : orcamentos.entrySet()) {
|
||||
String categoria = entry.getKey();
|
||||
float limite = entry.getValue();
|
||||
float gasto = dbHelper.getGastoPorCategoria(categoria);
|
||||
|
||||
categorias.add(categoria);
|
||||
gastosEntries.add(new BarEntry(index, gasto));
|
||||
orcamentoEntries.add(new BarEntry(index, limite));
|
||||
index++;
|
||||
}
|
||||
|
||||
if (categorias.isEmpty()) { barChartOrcamento.clear(); return; }
|
||||
|
||||
BarDataSet setGastos = new BarDataSet(gastosEntries, "Gastos Reais");
|
||||
setGastos.setColor(Color.parseColor("#FF4081")); // Rosa (Figma)
|
||||
setGastos.setValueTextColor(Color.WHITE);
|
||||
|
||||
BarDataSet setOrcamento = new BarDataSet(orcamentoEntries, "Orçamento");
|
||||
setOrcamento.setColor(Color.parseColor("#00E5FF")); // Azul (Figma)
|
||||
setOrcamento.setValueTextColor(Color.WHITE);
|
||||
|
||||
BarData data = new BarData(setGastos, setOrcamento);
|
||||
// Lógica de agrupamento (Grouped Bar Chart)
|
||||
float groupSpace = 0.2f; float barSpace = 0.05f; float barWidth = 0.35f;
|
||||
data.setBarWidth(barWidth);
|
||||
barChartOrcamento.setData(data);
|
||||
barChartOrcamento.groupBars(-0.5f, groupSpace, barSpace);
|
||||
|
||||
// Labels no Eixo X
|
||||
XAxis xAxis = barChartOrcamento.getXAxis();
|
||||
xAxis.setValueFormatter(new IndexAxisValueFormatter(categorias));
|
||||
xAxis.setAxisMinimum(-0.5f);
|
||||
xAxis.setAxisMaximum(categorias.size() - 0.5f);
|
||||
|
||||
barChartOrcamento.animateY(1000);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 3. GRÁFICO DE BARRAS (Tendência Mensal Geral)
|
||||
// ==========================================
|
||||
private void carregarBarChartTendencia() {
|
||||
configurarEstiloBarChart(barChartTendencia);
|
||||
|
||||
float totalReceitas = dbHelper.getTotalReceitas();
|
||||
float totalDespesas = dbHelper.getTotalDespesas();
|
||||
|
||||
ArrayList<BarEntry> despesaEntry = new ArrayList<>();
|
||||
ArrayList<BarEntry> receitaEntry = new ArrayList<>();
|
||||
|
||||
despesaEntry.add(new BarEntry(0, totalDespesas));
|
||||
receitaEntry.add(new BarEntry(0, totalReceitas));
|
||||
|
||||
BarDataSet setDespesas = new BarDataSet(despesaEntry, "Despesas");
|
||||
setDespesas.setColor(Color.parseColor("#FF1744")); // Vermelho
|
||||
setDespesas.setValueTextColor(Color.WHITE);
|
||||
|
||||
BarDataSet setReceitas = new BarDataSet(receitaEntry, "Receitas");
|
||||
setReceitas.setColor(Color.parseColor("#00E676")); // Verde
|
||||
setReceitas.setValueTextColor(Color.WHITE);
|
||||
|
||||
BarData data = new BarData(setDespesas, setReceitas);
|
||||
|
||||
float groupSpace = 0.3f; float barSpace = 0.05f; float barWidth = 0.3f;
|
||||
data.setBarWidth(barWidth);
|
||||
barChartTendencia.setData(data);
|
||||
barChartTendencia.groupBars(-0.5f, groupSpace, barSpace);
|
||||
|
||||
ArrayList<String> labelMes = new ArrayList<>();
|
||||
labelMes.add("Atual");
|
||||
|
||||
XAxis xAxis = barChartTendencia.getXAxis();
|
||||
xAxis.setValueFormatter(new IndexAxisValueFormatter(labelMes));
|
||||
xAxis.setAxisMinimum(-0.5f);
|
||||
xAxis.setAxisMaximum(0.5f);
|
||||
|
||||
barChartTendencia.animateY(1000);
|
||||
}
|
||||
|
||||
// Função de limpeza de design comum aos dois gráficos de barras
|
||||
private void configurarEstiloBarChart(BarChart chart) {
|
||||
chart.getDescription().setEnabled(false);
|
||||
chart.getLegend().setTextColor(Color.WHITE);
|
||||
chart.getAxisRight().setEnabled(false); // Esconde números à direita
|
||||
|
||||
chart.getAxisLeft().setTextColor(Color.WHITE);
|
||||
chart.getAxisLeft().setDrawGridLines(true);
|
||||
chart.getAxisLeft().setGridColor(Color.parseColor("#455A64")); // Linhas de fundo subtis
|
||||
|
||||
XAxis xAxis = chart.getXAxis();
|
||||
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
|
||||
xAxis.setTextColor(Color.WHITE);
|
||||
xAxis.setDrawGridLines(false);
|
||||
xAxis.setGranularity(1f);
|
||||
xAxis.setCenterAxisLabels(true);
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,66 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import java.io.IOException;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class LoginActivity extends AppCompatActivity {
|
||||
|
||||
private TextInputEditText editEmail, editPassword;
|
||||
private Button btnEntrar;
|
||||
private TextView txtRegistrar;
|
||||
private TextView txtRegistrar, txtEsqueciPassword;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
SharedPreferences prefs = getSharedPreferences("DadosUtilizador", MODE_PRIVATE);
|
||||
boolean jaDeuLogin = prefs.getBoolean("is_logged_in", false);
|
||||
|
||||
if (jaDeuLogin) {
|
||||
// Já tem o carimbo! Vai direto para o ecrã principal.
|
||||
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
return; // Para o código aqui para não desenhar o ecrã de login
|
||||
}
|
||||
|
||||
|
||||
setContentView(R.layout.activity_login);
|
||||
|
||||
// 1. Inicializar os componentes da interface
|
||||
inicializarComponentes();
|
||||
|
||||
// 2. Configurar o clique no botão "Entrar"
|
||||
// Clique no botão "Entrar" -> Agora faz Login de verdade!
|
||||
btnEntrar.setOnClickListener(v -> validarDados());
|
||||
|
||||
// 3. Configurar o clique para ir para a tela de Registo
|
||||
// Clique para ir para Registo
|
||||
txtRegistrar.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
|
||||
startActivity(intent);
|
||||
});
|
||||
|
||||
// Clique no "Esqueci-me da palavra-passe" -> Agora abre o novo ecrã!
|
||||
txtEsqueciPassword.setOnClickListener(v -> {
|
||||
startActivity(new Intent(LoginActivity.this, RecuperarPasswordActivity.class));
|
||||
});
|
||||
}
|
||||
|
||||
private void validarDados() {
|
||||
@@ -44,20 +74,81 @@ public class LoginActivity extends AppCompatActivity {
|
||||
editPassword.setError("Introduza a sua palavra-passe");
|
||||
editPassword.requestFocus();
|
||||
} else {
|
||||
// Se tudo estiver OK, por enquanto vamos apenas simular o login
|
||||
// e saltar para o Dashboard (que será a nossa próxima fase)
|
||||
Toast.makeText(this, "Login efetuado com sucesso!", Toast.LENGTH_SHORT).show();
|
||||
|
||||
// Aqui é onde irás validar com a Base de Dados ou Firebase no futuro
|
||||
irParaDashboard();
|
||||
// Desativa o botão enquanto pensa
|
||||
btnEntrar.setEnabled(false);
|
||||
btnEntrar.setText("A VERIFICAR DADOS...");
|
||||
fazerLoginNoSupabase(email, password);
|
||||
}
|
||||
}
|
||||
|
||||
private void fazerLoginNoSupabase(String email, String password) {
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
|
||||
String json = "{\"email\":\"" + email + "\", \"password\":\"" + password + "\"}";
|
||||
RequestBody body = RequestBody.create(json, MediaType.parse("application/json; charset=utf-8"));
|
||||
|
||||
// URL para fazer login (grant_type=password)
|
||||
Request request = new Request.Builder()
|
||||
.url(SupabaseConfig.SUPABASE_URL + "/auth/v1/token?grant_type=password")
|
||||
.addHeader("apikey", SupabaseConfig.SUPABASE_KEY)
|
||||
.addHeader("Authorization", "Bearer " + SupabaseConfig.SUPABASE_KEY)
|
||||
.post(body)
|
||||
.build();
|
||||
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
||||
runOnUiThread(() -> {
|
||||
Toast.makeText(LoginActivity.this, "Erro de ligação à internet!", Toast.LENGTH_SHORT).show();
|
||||
btnEntrar.setEnabled(true);
|
||||
btnEntrar.setText("INICIAR SESSÃO");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
|
||||
final String responseData = response.body().string();
|
||||
|
||||
runOnUiThread(() -> {
|
||||
btnEntrar.setEnabled(true);
|
||||
btnEntrar.setText("INICIAR SESSÃO");
|
||||
|
||||
if (response.isSuccessful()) {
|
||||
// SUCESSO! A palavra-passe estava certa!
|
||||
try {
|
||||
JSONObject jsonResponse = new JSONObject(responseData);
|
||||
String userId = jsonResponse.getJSONObject("user").getString("id");
|
||||
|
||||
SharedPreferences prefs = getSharedPreferences("DadosUtilizador", MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
|
||||
editor.putBoolean("is_logged_in", true); // O nosso carimbo!
|
||||
editor.putString("user_id", userId); // O ID do Supabase
|
||||
editor.putString("email_usuario", email);// Guardamos o email para o Perfil
|
||||
editor.apply();
|
||||
|
||||
Toast.makeText(LoginActivity.this, "Bem-vindo de volta!", Toast.LENGTH_SHORT).show();
|
||||
irParaDashboard();
|
||||
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(LoginActivity.this, "Erro a processar os dados.", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
} else {
|
||||
// ERRO! Palavra-passe errada ou email não existe!
|
||||
Toast.makeText(LoginActivity.this, "Credenciais incorretas. Tenta novamente!", Toast.LENGTH_LONG).show();
|
||||
editPassword.setError("Palavra-passe errada");
|
||||
editPassword.setText(""); // Limpa a password para ele tentar de novo
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void irParaDashboard() {
|
||||
// Altera 'MainActivity' para o nome da tua classe do Dashboard
|
||||
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
startActivity(intent);
|
||||
finish(); // Fecha o login para o utilizador não voltar atrás ao carregar no botão 'back'
|
||||
finish();
|
||||
}
|
||||
|
||||
private void inicializarComponentes() {
|
||||
@@ -65,5 +156,6 @@ public class LoginActivity extends AppCompatActivity {
|
||||
editPassword = findViewById(R.id.editPassword);
|
||||
btnEntrar = findViewById(R.id.btnEntrar);
|
||||
txtRegistrar = findViewById(R.id.txtRegistrar);
|
||||
txtEsqueciPassword = findViewById(R.id.txtEsqueciPassword);
|
||||
}
|
||||
}
|
||||
@@ -1,59 +1,101 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private Button btnSair;
|
||||
private TabLayout tabLayout;
|
||||
private ViewPager2 viewPager;
|
||||
private FloatingActionButton fabAdicionar;
|
||||
private TextView tvNomeUsuario;
|
||||
private Button btnSair;
|
||||
|
||||
private TextView tvSaldoGeral, tvReceitasGeral, tvDespesasGeral;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
SharedPreferences prefsTema = getSharedPreferences("TemaApp", MODE_PRIVATE);
|
||||
boolean isModoEscuro = prefsTema.getBoolean("modo_escuro", true);
|
||||
|
||||
if (isModoEscuro) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
} else {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||
}
|
||||
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
// 1. PRIMEIRO PASSO OBRIGATÓRIO: Ligar as variáveis ao XML
|
||||
inicializarComponentes();
|
||||
|
||||
// 2. Agora sim, podemos tentar mudar o nome com segurança
|
||||
try {
|
||||
String nomeRecebido = getIntent().getStringExtra("CHAVE_NOME");
|
||||
|
||||
// Só altera o texto se realmente tivermos recebido um nome (ex: vindo do Registo)
|
||||
if (nomeRecebido != null) {
|
||||
tvNomeUsuario.setText("Olá, " + nomeRecebido + "!");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(); // Se der erro, ignora e mantém o texto original
|
||||
}
|
||||
|
||||
// 3. Configurar os botões e abas
|
||||
configurarBotaoSair();
|
||||
configurarAbas();
|
||||
}
|
||||
|
||||
private void inicializarComponentes() {
|
||||
btnSair = findViewById(R.id.btnSair);
|
||||
tabLayout = findViewById(R.id.tabLayoutDashboard);
|
||||
viewPager = findViewById(R.id.viewPager);
|
||||
tvNomeUsuario = findViewById(R.id.tvNomeUsuario); // Certifica-te que este ID existe no XML
|
||||
}
|
||||
fabAdicionar = findViewById(R.id.fabAdicionar);
|
||||
tvNomeUsuario = findViewById(R.id.tvNomeUsuario);
|
||||
btnSair = findViewById(R.id.btnSair);
|
||||
|
||||
tvSaldoGeral = findViewById(R.id.tvSaldoGeral);
|
||||
tvReceitasGeral = findViewById(R.id.tvReceitasGeral);
|
||||
tvDespesasGeral = findViewById(R.id.tvDespesasGeral);
|
||||
|
||||
SharedPreferences prefs = getSharedPreferences("DadosUtilizador", MODE_PRIVATE);
|
||||
String nome = prefs.getString("nome_usuario", "Investidor");
|
||||
tvNomeUsuario.setText("Olá, " + nome);
|
||||
|
||||
private void configurarBotaoSair() {
|
||||
btnSair.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
|
||||
startActivity(intent);
|
||||
prefs.edit().clear().apply();
|
||||
startActivity(new Intent(this, LoginActivity.class));
|
||||
finish();
|
||||
});
|
||||
|
||||
fabAdicionar.setOnClickListener(v -> {
|
||||
startActivity(new Intent(this, AdicionarTransacaoActivity.class));
|
||||
});
|
||||
|
||||
ImageView btnAbrirDefinicoes = findViewById(R.id.btnAbrirDefinicoes);
|
||||
if (btnAbrirDefinicoes != null) {
|
||||
btnAbrirDefinicoes.setOnClickListener(v -> {
|
||||
startActivity(new Intent(MainActivity.this, DefinicoesActivity.class));
|
||||
});
|
||||
}
|
||||
|
||||
configurarAbas();
|
||||
atualizarCartoes(); // Chama a nova função ligada à net!
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
atualizarCartoes();
|
||||
|
||||
SharedPreferences prefs = getSharedPreferences("DadosUtilizador", MODE_PRIVATE);
|
||||
String nome = prefs.getString("nome_usuario", "Investidor");
|
||||
if (tvNomeUsuario != null) {
|
||||
tvNomeUsuario.setText("Olá, " + nome);
|
||||
}
|
||||
}
|
||||
|
||||
private void configurarAbas() {
|
||||
@@ -62,16 +104,80 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
|
||||
switch (position) {
|
||||
case 0:
|
||||
tab.setText("Transações");
|
||||
break;
|
||||
case 1:
|
||||
tab.setText("Gráficos");
|
||||
break;
|
||||
case 2:
|
||||
tab.setText("Dicas");
|
||||
break;
|
||||
case 0: tab.setText("Transações"); break;
|
||||
case 1: tab.setText("Orçamentos"); break;
|
||||
case 2: tab.setText("Gráficos"); break;
|
||||
case 3: tab.setText("Dicas"); break;
|
||||
}
|
||||
}).attach();
|
||||
}
|
||||
|
||||
// ==========================================================
|
||||
// --- CALCULAR O SALDO DIRETAMENTE DO SUPABASE ---
|
||||
// ==========================================================
|
||||
public void atualizarCartoes() {
|
||||
SharedPreferences prefs = getSharedPreferences("DadosUtilizador", MODE_PRIVATE);
|
||||
String userId = prefs.getString("user_id", null);
|
||||
|
||||
if (userId == null) return;
|
||||
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
Request request = new Request.Builder()
|
||||
.url(SupabaseConfig.SUPABASE_URL + "/rest/v1/transacoes?user_id=eq." + userId)
|
||||
.addHeader("apikey", SupabaseConfig.SUPABASE_KEY)
|
||||
.addHeader("Authorization", "Bearer " + SupabaseConfig.SUPABASE_KEY)
|
||||
.build();
|
||||
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(@NonNull Call call, @NonNull IOException e) {}
|
||||
|
||||
@Override
|
||||
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
|
||||
if (response.isSuccessful()) {
|
||||
try {
|
||||
String jsonResposta = response.body().string();
|
||||
JSONArray jsonArray = new JSONArray(jsonResposta);
|
||||
|
||||
float receitas = 0;
|
||||
float despesas = 0;
|
||||
|
||||
// Percorrer todas as transações da nuvem e somar!
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject obj = jsonArray.getJSONObject(i);
|
||||
float valor = (float) obj.getDouble("valor");
|
||||
int tipo = obj.getInt("tipo");
|
||||
|
||||
if (tipo == 1) {
|
||||
receitas += valor;
|
||||
} else if (tipo == 2) {
|
||||
despesas += valor;
|
||||
}
|
||||
}
|
||||
|
||||
final float totalReceitas = receitas;
|
||||
final float totalDespesas = despesas;
|
||||
final float saldo = receitas - despesas;
|
||||
|
||||
// Atualizar o design do ecrã
|
||||
runOnUiThread(() -> {
|
||||
if (tvReceitasGeral != null) tvReceitasGeral.setText(String.format("€ %.2f", totalReceitas));
|
||||
if (tvDespesasGeral != null) tvDespesasGeral.setText(String.format("€ %.2f", totalDespesas));
|
||||
if (tvSaldoGeral != null) {
|
||||
tvSaldoGeral.setText(String.format("€ %.2f", saldo));
|
||||
if (saldo < 0) {
|
||||
tvSaldoGeral.setTextColor(Color.parseColor("#FF1744"));
|
||||
} else {
|
||||
tvSaldoGeral.setTextColor(getResources().getColor(R.color.texto_principal));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
102
app/src/main/java/com/example/finzora/OnboardingActivity.java
Normal file
102
app/src/main/java/com/example/finzora/OnboardingActivity.java
Normal file
@@ -0,0 +1,102 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class OnboardingActivity extends AppCompatActivity {
|
||||
|
||||
private OnboardingAdapter onboardingAdapter;
|
||||
private Button btnProximo;
|
||||
private TextView btnSaltar; // Atenção: no teu XML o Saltar era um TextView
|
||||
private TabLayout tabLayoutIndicator;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_onboarding);
|
||||
|
||||
// --- 1. RECUPERAR O NOME DA MEMÓRIA ---
|
||||
SharedPreferences prefs = getSharedPreferences("DadosUtilizador", MODE_PRIVATE);
|
||||
// Tenta ler "nome_usuario". Se não existir, mete "Visitante"
|
||||
String nomeRecuperado = prefs.getString("nome_usuario", "Visitante");
|
||||
|
||||
// --- 2. CRIAR OS SLIDES ---
|
||||
List<OnboardingItem> lista = new ArrayList<>();
|
||||
|
||||
// SLIDE 1: Usamos a variável 'nomeRecuperado' aqui
|
||||
lista.add(new OnboardingItem(
|
||||
"Olá, " + nomeRecuperado + "! \uD83D\uDC4B",
|
||||
"Bem-vindo ao Finzora. A tua gestão financeira pessoal, agora com tecnologia de ponta.",
|
||||
R.drawable.ic_wallet // Confirma se tens este ícone, ou usa ic_launcher_foreground
|
||||
));
|
||||
|
||||
// SLIDE 2
|
||||
lista.add(new OnboardingItem(
|
||||
"Controlo Total",
|
||||
"Regista receitas e despesas num piscar de olhos e mantém o teu saldo sempre atualizado.",
|
||||
R.drawable.ic_chart
|
||||
));
|
||||
|
||||
// SLIDE 3
|
||||
lista.add(new OnboardingItem(
|
||||
"Inteligência Artificial",
|
||||
"Recebe dicas automáticas baseadas nos teus gastos para poupares mais todos os meses.",
|
||||
R.drawable.ic_idea
|
||||
));
|
||||
|
||||
// --- 3. CONFIGURAR VIEWPAGER E BOTÕES ---
|
||||
ViewPager2 viewPager = findViewById(R.id.viewPagerOnboarding);
|
||||
tabLayoutIndicator = findViewById(R.id.tabLayoutIndicator);
|
||||
btnProximo = findViewById(R.id.btnProximo);
|
||||
btnSaltar = findViewById(R.id.btnSaltar);
|
||||
|
||||
onboardingAdapter = new OnboardingAdapter(lista);
|
||||
viewPager.setAdapter(onboardingAdapter);
|
||||
|
||||
// Ligar as barras de progresso (TabLayout)
|
||||
new TabLayoutMediator(tabLayoutIndicator, viewPager, (tab, position) -> {
|
||||
// Deixar vazio (só queremos as barras, sem texto)
|
||||
}).attach();
|
||||
|
||||
// Lógica do Botão Próximo
|
||||
btnProximo.setOnClickListener(v -> {
|
||||
if (viewPager.getCurrentItem() + 1 < onboardingAdapter.getItemCount()) {
|
||||
viewPager.setCurrentItem(viewPager.getCurrentItem() + 1);
|
||||
} else {
|
||||
finalizarOnboarding();
|
||||
}
|
||||
});
|
||||
|
||||
// Lógica do Botão Saltar
|
||||
btnSaltar.setOnClickListener(v -> finalizarOnboarding());
|
||||
|
||||
// Mudar texto "Próximo" para "Começar" na última página
|
||||
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
super.onPageSelected(position);
|
||||
if (position == onboardingAdapter.getItemCount() - 1) {
|
||||
btnProximo.setText("Começar");
|
||||
} else {
|
||||
btnProximo.setText("Próximo");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void finalizarOnboarding() {
|
||||
// Tem de ir para ProfileActivity.class, e NÃO para MainActivity.class
|
||||
Intent intent = new Intent(OnboardingActivity.this, ProfileActivity.class);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
55
app/src/main/java/com/example/finzora/OnboardingAdapter.java
Normal file
55
app/src/main/java/com/example/finzora/OnboardingAdapter.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package com.example.finzora;
|
||||
|
||||
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 java.util.List;
|
||||
|
||||
public class OnboardingAdapter extends RecyclerView.Adapter<OnboardingAdapter.OnboardingViewHolder> {
|
||||
|
||||
private List<OnboardingItem> onboardingItems;
|
||||
|
||||
public OnboardingAdapter(List<OnboardingItem> onboardingItems) {
|
||||
this.onboardingItems = onboardingItems;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public OnboardingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_onboarding, parent, false);
|
||||
return new OnboardingViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull OnboardingViewHolder holder, int position) {
|
||||
holder.setOnboardingData(onboardingItems.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return onboardingItems.size();
|
||||
}
|
||||
|
||||
class OnboardingViewHolder extends RecyclerView.ViewHolder {
|
||||
private TextView textTitulo;
|
||||
private TextView textDescricao;
|
||||
private ImageView imageOnboarding;
|
||||
|
||||
OnboardingViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
textTitulo = itemView.findViewById(R.id.textTitulo);
|
||||
textDescricao = itemView.findViewById(R.id.textDescricao);
|
||||
imageOnboarding = itemView.findViewById(R.id.imgOnboarding);
|
||||
}
|
||||
|
||||
void setOnboardingData(OnboardingItem item) {
|
||||
textTitulo.setText(item.getTitulo());
|
||||
textDescricao.setText(item.getDescricao());
|
||||
imageOnboarding.setImageResource(item.getImagem());
|
||||
}
|
||||
}
|
||||
}
|
||||
16
app/src/main/java/com/example/finzora/OnboardingItem.java
Normal file
16
app/src/main/java/com/example/finzora/OnboardingItem.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.example.finzora;
|
||||
|
||||
public class OnboardingItem {
|
||||
private String titulo, descricao;
|
||||
private int imagem;
|
||||
|
||||
public OnboardingItem(String titulo, String descricao, int imagem) {
|
||||
this.titulo = titulo;
|
||||
this.descricao = descricao;
|
||||
this.imagem = imagem;
|
||||
}
|
||||
|
||||
public String getTitulo() { return titulo; }
|
||||
public String getDescricao() { return descricao; }
|
||||
public int getImagem() { return imagem; }
|
||||
}
|
||||
78
app/src/main/java/com/example/finzora/OrcamentoAdapter.java
Normal file
78
app/src/main/java/com/example/finzora/OrcamentoAdapter.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class OrcamentoAdapter extends RecyclerView.Adapter<OrcamentoAdapter.OrcamentoViewHolder> {
|
||||
|
||||
// Lista de pares: Chave=Categoria, Valor=Limite
|
||||
private List<Map.Entry<String, Float>> listaOrcamentos;
|
||||
private DBHelper dbHelper;
|
||||
|
||||
public OrcamentoAdapter(List<Map.Entry<String, Float>> lista, DBHelper db) {
|
||||
this.listaOrcamentos = lista;
|
||||
this.dbHelper = db;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public OrcamentoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_orcamento, parent, false);
|
||||
return new OrcamentoViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull OrcamentoViewHolder holder, int position) {
|
||||
Map.Entry<String, Float> entry = listaOrcamentos.get(position);
|
||||
String categoria = entry.getKey();
|
||||
float limite = entry.getValue();
|
||||
|
||||
// Calcular quanto já gastou
|
||||
float gasto = dbHelper.getGastoPorCategoria(categoria);
|
||||
float restante = limite - gasto;
|
||||
int percentagem = (int) ((gasto / limite) * 100);
|
||||
if (percentagem > 100) percentagem = 100;
|
||||
|
||||
// Atualizar Textos
|
||||
holder.tvCategoria.setText(categoria);
|
||||
holder.tvValores.setText(String.format("€ %.2f / € %.2f", gasto, limite));
|
||||
holder.progress.setProgress(percentagem);
|
||||
|
||||
if (restante >= 0) {
|
||||
holder.tvRestante.setText(String.format("Restam € %.2f (%d%%)", restante, 100 - percentagem));
|
||||
holder.tvRestante.setTextColor(Color.parseColor("#90A4AE")); // Cinzento
|
||||
holder.progress.setProgressTintList(ColorStateList.valueOf(Color.parseColor("#00E676"))); // Verde
|
||||
} else {
|
||||
holder.tvRestante.setText(String.format("Ultrapassado por € %.2f!", Math.abs(restante)));
|
||||
holder.tvRestante.setTextColor(Color.parseColor("#FF1744")); // Vermelho
|
||||
holder.progress.setProgressTintList(ColorStateList.valueOf(Color.parseColor("#FF1744"))); // Vermelho
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return listaOrcamentos.size();
|
||||
}
|
||||
|
||||
static class OrcamentoViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView tvCategoria, tvValores, tvRestante;
|
||||
ProgressBar progress;
|
||||
|
||||
public OrcamentoViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
tvCategoria = itemView.findViewById(R.id.tvCatOrcamento);
|
||||
tvValores = itemView.findViewById(R.id.tvValoresOrcamento);
|
||||
tvRestante = itemView.findViewById(R.id.tvRestante);
|
||||
progress = itemView.findViewById(R.id.progressOrcamento);
|
||||
}
|
||||
}
|
||||
}
|
||||
98
app/src/main/java/com/example/finzora/OrcamentoFragment.java
Normal file
98
app/src/main/java/com/example/finzora/OrcamentoFragment.java
Normal file
@@ -0,0 +1,98 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class OrcamentoFragment extends Fragment {
|
||||
|
||||
private Spinner spinnerCategoria;
|
||||
private EditText editLimite;
|
||||
private Button btnSalvar;
|
||||
private RecyclerView recyclerOrcamentos;
|
||||
private DBHelper dbHelper;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
// Carrega o layout XML correto
|
||||
View view = inflater.inflate(R.layout.fragment_orcamento, container, false);
|
||||
|
||||
// Liga os componentes do Java aos IDs do XML
|
||||
// SE AQUI FICAR VERMELHO, É PORQUE O XML NÃO FOI GUARDADO
|
||||
spinnerCategoria = view.findViewById(R.id.spinnerOrcamento);
|
||||
editLimite = view.findViewById(R.id.editLimite);
|
||||
btnSalvar = view.findViewById(R.id.btnDefinirOrcamento);
|
||||
recyclerOrcamentos = view.findViewById(R.id.recyclerOrcamentos);
|
||||
|
||||
// Configura a lista
|
||||
recyclerOrcamentos.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
|
||||
// Inicia a base de dados
|
||||
dbHelper = new DBHelper(getActivity());
|
||||
|
||||
// Configurações iniciais
|
||||
configurarSpinner();
|
||||
|
||||
// Ação do botão
|
||||
btnSalvar.setOnClickListener(v -> salvarOrcamento());
|
||||
|
||||
// Mostrar dados
|
||||
carregarOrcamentos();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
carregarOrcamentos();
|
||||
}
|
||||
|
||||
// Método corrigido (havia um duplicado antes)
|
||||
private void configurarSpinner() {
|
||||
String[] categorias = {"Alimentação", "Transporte", "Salário", "Lazer", "Contas", "Saúde", "Outros"};
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(), R.layout.item_dropdown, categorias);
|
||||
spinnerCategoria.setAdapter(adapter);
|
||||
}
|
||||
|
||||
private void salvarOrcamento() {
|
||||
String limiteStr = editLimite.getText().toString();
|
||||
if (limiteStr.isEmpty()) {
|
||||
editLimite.setError("Define um valor");
|
||||
return;
|
||||
}
|
||||
|
||||
String categoria = spinnerCategoria.getSelectedItem().toString();
|
||||
float limite = Float.parseFloat(limiteStr);
|
||||
|
||||
dbHelper.salvarOrcamento(categoria, limite);
|
||||
|
||||
Toast.makeText(getActivity(), "Orçamento definido!", Toast.LENGTH_SHORT).show();
|
||||
editLimite.setText(""); // Limpar campo
|
||||
|
||||
carregarOrcamentos(); // Atualizar lista
|
||||
}
|
||||
|
||||
private void carregarOrcamentos() {
|
||||
Map<String, Float> orcamentosMap = dbHelper.getOrcamentosDefinidos();
|
||||
List<Map.Entry<String, Float>> lista = new ArrayList<>(orcamentosMap.entrySet());
|
||||
|
||||
OrcamentoAdapter adapter = new OrcamentoAdapter(lista, dbHelper);
|
||||
recyclerOrcamentos.setAdapter(adapter);
|
||||
}
|
||||
}
|
||||
151
app/src/main/java/com/example/finzora/ProfileActivity.java
Normal file
151
app/src/main/java/com/example/finzora/ProfileActivity.java
Normal file
@@ -0,0 +1,151 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import java.util.Random;
|
||||
|
||||
public class ProfileActivity extends AppCompatActivity {
|
||||
|
||||
private ImageView imgPerfil;
|
||||
private TextInputEditText editNomePerfil, editBio;
|
||||
private Button btnEscolherFoto, btnGuardarPerfil;
|
||||
private TextView btnSaltarPerfil;
|
||||
private Uri imagemUriSelecionada = null;
|
||||
|
||||
// Variável de controlo
|
||||
private boolean vindoDoMenu = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_profile);
|
||||
|
||||
// Verifica de onde viemos
|
||||
vindoDoMenu = getIntent().getBooleanExtra("origem_menu", false);
|
||||
|
||||
inicializarComponentes();
|
||||
adaptarInterface(); // Ajusta os textos dos botões
|
||||
carregarDadosAtuais();
|
||||
|
||||
// 1. Escolher Foto
|
||||
ActivityResultLauncher<String> galleryLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.GetContent(),
|
||||
uri -> {
|
||||
if (uri != null) {
|
||||
imagemUriSelecionada = uri;
|
||||
imgPerfil.setImageURI(uri);
|
||||
imgPerfil.setColorFilter(null);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
btnEscolherFoto.setOnClickListener(v -> galleryLauncher.launch("image/*"));
|
||||
|
||||
// 2. Guardar
|
||||
btnGuardarPerfil.setOnClickListener(v -> salvarPerfil());
|
||||
|
||||
// 3. Botão Saltar / Cancelar
|
||||
btnSaltarPerfil.setOnClickListener(v -> {
|
||||
if (vindoDoMenu) {
|
||||
// Se veio do menu, "Saltar" funciona como "Cancelar"
|
||||
finish();
|
||||
} else {
|
||||
// Se veio do Tutorial, salta mas mostra as boas-vindas
|
||||
mostrarMensagemBoasVindas("Investidor");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void inicializarComponentes() {
|
||||
imgPerfil = findViewById(R.id.imgPerfil);
|
||||
editNomePerfil = findViewById(R.id.editNomePerfil);
|
||||
editBio = findViewById(R.id.editBio);
|
||||
btnEscolherFoto = findViewById(R.id.btnEscolherFoto);
|
||||
btnGuardarPerfil = findViewById(R.id.btnGuardarPerfil);
|
||||
btnSaltarPerfil = findViewById(R.id.btnSaltarPerfil);
|
||||
}
|
||||
|
||||
private void adaptarInterface() {
|
||||
if (vindoDoMenu) {
|
||||
// Se já estamos na app
|
||||
btnSaltarPerfil.setText("Cancelar");
|
||||
btnGuardarPerfil.setText("Atualizar Perfil");
|
||||
} else {
|
||||
// Se é o tutorial inicial
|
||||
btnSaltarPerfil.setText("Saltar por agora");
|
||||
btnGuardarPerfil.setText("Guardar e Entrar");
|
||||
}
|
||||
}
|
||||
|
||||
private void carregarDadosAtuais() {
|
||||
SharedPreferences prefs = getSharedPreferences("DadosUtilizador", MODE_PRIVATE);
|
||||
editNomePerfil.setText(prefs.getString("nome_usuario", ""));
|
||||
editBio.setText(prefs.getString("bio_usuario", ""));
|
||||
|
||||
String fotoStr = prefs.getString("foto_usuario", null);
|
||||
if (fotoStr != null) {
|
||||
imgPerfil.setImageURI(Uri.parse(fotoStr));
|
||||
imgPerfil.setColorFilter(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void salvarPerfil() {
|
||||
String novoNome = editNomePerfil.getText().toString().trim();
|
||||
String novaBio = editBio.getText().toString().trim();
|
||||
|
||||
if (novoNome.isEmpty()) {
|
||||
editNomePerfil.setError("O nome não pode estar vazio");
|
||||
return;
|
||||
}
|
||||
|
||||
SharedPreferences.Editor editor = getSharedPreferences("DadosUtilizador", MODE_PRIVATE).edit();
|
||||
editor.putString("nome_usuario", novoNome);
|
||||
editor.putString("bio_usuario", novaBio);
|
||||
if (imagemUriSelecionada != null) {
|
||||
editor.putString("foto_usuario", imagemUriSelecionada.toString());
|
||||
}
|
||||
editor.apply();
|
||||
|
||||
// --- LÓGICA DE SAÍDA ---
|
||||
if (vindoDoMenu) {
|
||||
// Edição simples: avisa e volta para trás
|
||||
Toast.makeText(this, "Perfil atualizado!", Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
} else {
|
||||
// Primeira vez: Mostra a mensagem inspiradora
|
||||
mostrarMensagemBoasVindas(novoNome);
|
||||
}
|
||||
}
|
||||
|
||||
private void mostrarMensagemBoasVindas(String nome) {
|
||||
String[] frases = {
|
||||
"\"Não poupes o que resta depois de gastar, mas gasta o que resta depois de poupar.\" – Warren Buffett",
|
||||
"\"O segredo para ficar à frente é começar.\" – Mark Twain",
|
||||
"\"A tua liberdade financeira começa hoje!\" 🚀"
|
||||
};
|
||||
String fraseDoDia = frases[new Random().nextInt(frases.length)];
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Bem-vindo(a), " + nome + "!")
|
||||
.setMessage(fraseDoDia + "\n\nO teu perfil está pronto. Vamos dominar as tuas finanças?")
|
||||
.setPositiveButton("VAMOS LÁ!", (dialog, which) -> {
|
||||
Intent intent = new Intent(ProfileActivity.this, MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
})
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class RecuperarPasswordActivity extends AppCompatActivity {
|
||||
|
||||
private TextInputEditText editEmailRecuperar;
|
||||
private Button btnEnviarEmail;
|
||||
private ImageView btnVoltar;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_recuperar_password);
|
||||
|
||||
editEmailRecuperar = findViewById(R.id.editEmailRecuperar);
|
||||
btnEnviarEmail = findViewById(R.id.btnEnviarEmail);
|
||||
btnVoltar = findViewById(R.id.btnVoltarRecuperar);
|
||||
|
||||
// Voltar para trás
|
||||
btnVoltar.setOnClickListener(v -> finish());
|
||||
|
||||
btnEnviarEmail.setOnClickListener(v -> {
|
||||
String email = editEmailRecuperar.getText().toString().trim();
|
||||
if (TextUtils.isEmpty(email)) {
|
||||
editEmailRecuperar.setError("Introduz o teu email");
|
||||
editEmailRecuperar.requestFocus();
|
||||
} else {
|
||||
btnEnviarEmail.setEnabled(false);
|
||||
btnEnviarEmail.setText("A ENVIAR...");
|
||||
pedirRecuperacaoPassword(email);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void pedirRecuperacaoPassword(String email) {
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
String json = "{\"email\":\"" + email + "\"}";
|
||||
RequestBody body = RequestBody.create(json, MediaType.parse("application/json; charset=utf-8"));
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(SupabaseConfig.SUPABASE_URL + "/auth/v1/recover")
|
||||
.addHeader("apikey", SupabaseConfig.SUPABASE_KEY)
|
||||
.addHeader("Authorization", "Bearer " + SupabaseConfig.SUPABASE_KEY)
|
||||
.post(body)
|
||||
.build();
|
||||
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
||||
runOnUiThread(() -> {
|
||||
Toast.makeText(RecuperarPasswordActivity.this, "Erro de ligação à internet!", Toast.LENGTH_SHORT).show();
|
||||
btnEnviarEmail.setEnabled(true);
|
||||
btnEnviarEmail.setText("ENVIAR LINK MÁGICO");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
|
||||
runOnUiThread(() -> {
|
||||
btnEnviarEmail.setEnabled(true);
|
||||
btnEnviarEmail.setText("ENVIAR LINK MÁGICO");
|
||||
if (response.isSuccessful()) {
|
||||
Toast.makeText(RecuperarPasswordActivity.this, "Email enviado! Verifica a caixa de entrada.", Toast.LENGTH_LONG).show();
|
||||
finish(); // Fecha esta tela e volta ao Login
|
||||
} else {
|
||||
Toast.makeText(RecuperarPasswordActivity.this, "Erro: Verifica se o email está correto ou se a conta existe.", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,30 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import java.io.IOException;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class RegisterActivity extends AppCompatActivity {
|
||||
|
||||
private TextInputEditText editNome, editEmail, editPassword, editConfirmPassword;
|
||||
private TextInputEditText editNome, editEmailRegister, editPassRegister, editConfirmPass;
|
||||
private Button btnCriarConta;
|
||||
private TextView txtLogin;
|
||||
|
||||
@@ -22,44 +35,122 @@ public class RegisterActivity extends AppCompatActivity {
|
||||
|
||||
inicializarComponentes();
|
||||
|
||||
// Volta para a tela de Login
|
||||
// Voltar para o Login
|
||||
txtLogin.setOnClickListener(v -> finish());
|
||||
|
||||
// Valida e cria a conta
|
||||
// Clicar em Criar Conta
|
||||
btnCriarConta.setOnClickListener(v -> validarDados());
|
||||
}
|
||||
|
||||
private void validarDados() {
|
||||
String nome = editNome.getText().toString().trim();
|
||||
String email = editEmail.getText().toString().trim();
|
||||
String password = editPassword.getText().toString().trim();
|
||||
String confirmPass = editConfirmPassword.getText().toString().trim();
|
||||
String email = editEmailRegister.getText().toString().trim();
|
||||
String password = editPassRegister.getText().toString().trim();
|
||||
String confirmPass = editConfirmPass.getText().toString().trim();
|
||||
|
||||
if (TextUtils.isEmpty(nome)) {
|
||||
editNome.setError("Introduza o seu nome");
|
||||
} else if (TextUtils.isEmpty(email)) {
|
||||
editEmail.setError("Introduza um email válido");
|
||||
} else if (TextUtils.isEmpty(password)) {
|
||||
editPassword.setError("Defina uma palavra-passe");
|
||||
} else if (password.length() < 6) {
|
||||
editPassword.setError("A senha deve ter pelo menos 6 caracteres");
|
||||
} else if (!password.equals(confirmPass)) {
|
||||
editConfirmPassword.setError("As palavras-passe não coincidem");
|
||||
} else {
|
||||
|
||||
Toast.makeText(this, "Conta criada com sucesso!", Toast.LENGTH_SHORT).show();
|
||||
Intent intent = new Intent(RegisterActivity.this, MainActivity.class);
|
||||
intent.putExtra("CHAVE_NOME", nome);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
if (TextUtils.isEmpty(email)) {
|
||||
editEmailRegister.setError("Introduza um email válido");
|
||||
return;
|
||||
}
|
||||
if (TextUtils.isEmpty(password)) {
|
||||
editPassRegister.setError("Defina uma palavra-passe");
|
||||
return;
|
||||
}
|
||||
if (password.length() < 6) {
|
||||
editPassRegister.setError("Mínimo 6 caracteres");
|
||||
return;
|
||||
}
|
||||
if (!password.equals(confirmPass)) {
|
||||
editConfirmPass.setError("As senhas não coincidem");
|
||||
return;
|
||||
}
|
||||
|
||||
btnCriarConta.setEnabled(false);
|
||||
btnCriarConta.setText("A criar conta na nuvem...");
|
||||
|
||||
registarNoSupabase(nome, email, password);
|
||||
}
|
||||
|
||||
private void registarNoSupabase(String nome, String email, String password) {
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
|
||||
// JSON com os dados para o Supabase Auth
|
||||
String json = "{\"email\":\"" + email + "\", \"password\":\"" + password + "\", \"data\": {\"nome\": \"" + nome + "\"}}";
|
||||
RequestBody body = RequestBody.create(json, MediaType.parse("application/json; charset=utf-8"));
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(SupabaseConfig.SUPABASE_URL + "/auth/v1/signup")
|
||||
.addHeader("apikey", SupabaseConfig.SUPABASE_KEY)
|
||||
.addHeader("Authorization", "Bearer " + SupabaseConfig.SUPABASE_KEY)
|
||||
.post(body)
|
||||
.build();
|
||||
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
||||
runOnUiThread(() -> {
|
||||
Toast.makeText(RegisterActivity.this, "Erro de rede! Verifica a internet.", Toast.LENGTH_SHORT).show();
|
||||
resetBotao();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
|
||||
final String responseData = response.body().string();
|
||||
|
||||
runOnUiThread(() -> {
|
||||
if (response.isSuccessful()) {
|
||||
try {
|
||||
// Extrair o ID do utilizador da resposta JSON
|
||||
JSONObject jsonResponse = new JSONObject(responseData);
|
||||
String userId = jsonResponse.getString("id");
|
||||
|
||||
// Guardar Nome e ID localmente para usar nas transações
|
||||
SharedPreferences prefs = getSharedPreferences("DadosUtilizador", MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putString("nome_usuario", nome);
|
||||
editor.putString("user_id", userId);
|
||||
editor.apply();
|
||||
|
||||
Toast.makeText(RegisterActivity.this, "Sucesso! Bem-vindo à nuvem.", Toast.LENGTH_SHORT).show();
|
||||
|
||||
// Avançar para o Onboarding
|
||||
startActivity(new Intent(RegisterActivity.this, OnboardingActivity.class));
|
||||
finish();
|
||||
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(RegisterActivity.this, "Erro ao ler dados da nuvem", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
} else {
|
||||
// LER O ERRO REAL DO SUPABASE
|
||||
try {
|
||||
JSONObject erroObj = new JSONObject(responseData);
|
||||
String mensagemErroReal = erroObj.getString("msg");
|
||||
Toast.makeText(RegisterActivity.this, "ERRO: " + mensagemErroReal, Toast.LENGTH_LONG).show();
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(RegisterActivity.this, "Erro desconhecido: " + responseData, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
resetBotao();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void resetBotao() {
|
||||
btnCriarConta.setEnabled(true);
|
||||
btnCriarConta.setText("CRIAR CONTA");
|
||||
}
|
||||
|
||||
private void inicializarComponentes() {
|
||||
editNome = findViewById(R.id.editNome);
|
||||
editEmail = findViewById(R.id.editEmailRegister);
|
||||
editPassword = findViewById(R.id.editPassRegister);
|
||||
editConfirmPassword = findViewById(R.id.editConfirmPass);
|
||||
editEmailRegister = findViewById(R.id.editEmailRegister);
|
||||
editPassRegister = findViewById(R.id.editPassRegister);
|
||||
editConfirmPass = findViewById(R.id.editConfirmPass);
|
||||
btnCriarConta = findViewById(R.id.btnCriarConta);
|
||||
txtLogin = findViewById(R.id.txtLogin);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.example.finzora;
|
||||
|
||||
public class SupabaseConfig {
|
||||
|
||||
public static final String SUPABASE_URL = "https://cnxbsherdagpdpjhbtae.supabase.co";
|
||||
public static final String SUPABASE_KEY = "sb_secret_bJg45XiAMz-KTyXw2FmMMA_HF97o_aV";
|
||||
|
||||
}
|
||||
38
app/src/main/java/com/example/finzora/Transacao.java
Normal file
38
app/src/main/java/com/example/finzora/Transacao.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package com.example.finzora;
|
||||
|
||||
public class Transacao {
|
||||
private int id;
|
||||
private float valor;
|
||||
private String categoria;
|
||||
private int tipo; // 1 = Receita, 2 = Despesa
|
||||
private String data;
|
||||
|
||||
// --- CONSTRUTOR 1: Para ler da Base de Dados (TEM ID) ---
|
||||
public Transacao(int id, float valor, String categoria, int tipo, String data) {
|
||||
this.id = id;
|
||||
this.valor = valor;
|
||||
this.categoria = categoria;
|
||||
this.tipo = tipo;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
// --- CONSTRUTOR 2: Para criar nova transação (NÃO TEM ID) ---
|
||||
public Transacao(float valor, String categoria, int tipo, String data) {
|
||||
this.valor = valor;
|
||||
this.categoria = categoria;
|
||||
this.tipo = tipo;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
// --- GETTERS (Para os outros lerem) ---
|
||||
public int getId() { return id; }
|
||||
public float getValor() { return valor; }
|
||||
public String getCategoria() { return categoria; }
|
||||
public int getTipo() { return tipo; }
|
||||
public String getData() { return data; }
|
||||
|
||||
// --- SETTERS (Opcional, mas evita erros se algum código antigo os chamar) ---
|
||||
public void setId(int id) { this.id = id; }
|
||||
public void setValor(float valor) { this.valor = valor; }
|
||||
public void setCategoria(String categoria) { this.categoria = categoria; }
|
||||
}
|
||||
79
app/src/main/java/com/example/finzora/TransacoesAdapter.java
Normal file
79
app/src/main/java/com/example/finzora/TransacoesAdapter.java
Normal file
@@ -0,0 +1,79 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.content.Context;
|
||||
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 java.util.List;
|
||||
|
||||
public class TransacoesAdapter extends RecyclerView.Adapter<TransacoesAdapter.MyViewHolder> {
|
||||
|
||||
private List<Transacao> listaTransacoes;
|
||||
private Context context;
|
||||
private TransacoesFragment fragment;
|
||||
|
||||
// O teu construtor mantém-se igual!
|
||||
public TransacoesAdapter(List<Transacao> lista, Context context, TransacoesFragment fragment) {
|
||||
this.listaTransacoes = lista;
|
||||
this.context = context;
|
||||
this.fragment = fragment;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View itemLista = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_transacao, parent, false);
|
||||
return new MyViewHolder(itemLista);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
|
||||
Transacao transacao = listaTransacoes.get(position);
|
||||
|
||||
// --- ATUALIZADO PARA OS NOVOS IDs DO XML ---
|
||||
holder.tvDescricao.setText(transacao.getCategoria());
|
||||
holder.tvData.setText(transacao.getData());
|
||||
|
||||
// Cores e Ícones
|
||||
if (transacao.getTipo() == 1) { // Receita
|
||||
holder.tvValor.setTextColor(Color.parseColor("#388E3C")); // Verde
|
||||
holder.tvValor.setText("+ € " + String.format("%.2f", transacao.getValor()));
|
||||
if(holder.imgIcone != null) holder.imgIcone.setImageResource(android.R.drawable.arrow_up_float);
|
||||
} else { // Despesa
|
||||
holder.tvValor.setTextColor(Color.parseColor("#D32F2F")); // Vermelho
|
||||
holder.tvValor.setText("- € " + String.format("%.2f", transacao.getValor()));
|
||||
if(holder.imgIcone != null) holder.imgIcone.setImageResource(android.R.drawable.arrow_down_float);
|
||||
}
|
||||
|
||||
// O botão de apagar agora chama-se btnEliminar no XML
|
||||
holder.btnEliminar.setOnClickListener(v -> {
|
||||
if (fragment != null) fragment.confirmarExclusao(transacao);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return listaTransacoes.size();
|
||||
}
|
||||
|
||||
public class MyViewHolder extends RecyclerView.ViewHolder {
|
||||
// --- AQUI ESTÃO OS NOVOS NOMES DO XML ---
|
||||
TextView tvDescricao, tvValor, tvData;
|
||||
ImageView imgIcone, btnEliminar;
|
||||
|
||||
public MyViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
// Agora liga perfeitamente ao layout tech!
|
||||
tvDescricao = itemView.findViewById(R.id.tvDescricao);
|
||||
tvData = itemView.findViewById(R.id.tvData);
|
||||
tvValor = itemView.findViewById(R.id.tvValor);
|
||||
imgIcone = itemView.findViewById(R.id.imgIcone);
|
||||
btnEliminar = itemView.findViewById(R.id.btnEliminar);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,158 @@
|
||||
package com.example.finzora;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class TransacoesFragment extends Fragment {
|
||||
|
||||
private RecyclerView recyclerTransacoes;
|
||||
private TransacoesAdapter adapter;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_transacoes, container, false);
|
||||
recyclerTransacoes = view.findViewById(R.id.recyclerTransacoes);
|
||||
recyclerTransacoes.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
carregarDadosDoSupabase();
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// BUSCAR AS TRANSAÇÕES À NUVEM (SUPABASE)
|
||||
// ====================================================================
|
||||
public void carregarDadosDoSupabase() {
|
||||
SharedPreferences prefs = getActivity().getSharedPreferences("DadosUtilizador", Context.MODE_PRIVATE);
|
||||
String userId = prefs.getString("user_id", null);
|
||||
|
||||
if (userId == null) return; // Se não houver utilizador, não faz nada
|
||||
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
|
||||
// O URL pede ao Supabase: "Dá-me as transações onde o user_id seja igual ao meu!"
|
||||
Request request = new Request.Builder()
|
||||
.url(SupabaseConfig.SUPABASE_URL + "/rest/v1/transacoes?user_id=eq." + userId + "&order=id.desc")
|
||||
.addHeader("apikey", SupabaseConfig.SUPABASE_KEY)
|
||||
.addHeader("Authorization", "Bearer " + SupabaseConfig.SUPABASE_KEY)
|
||||
.build();
|
||||
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
||||
if (getActivity() != null) {
|
||||
getActivity().runOnUiThread(() ->
|
||||
Toast.makeText(getActivity(), "Erro de internet ao carregar transações.", Toast.LENGTH_SHORT).show()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
|
||||
if (response.isSuccessful()) {
|
||||
String jsonResposta = response.body().string();
|
||||
List<Transacao> listaNuvem = new ArrayList<>();
|
||||
|
||||
try {
|
||||
JSONArray jsonArray = new JSONArray(jsonResposta);
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject obj = jsonArray.getJSONObject(i);
|
||||
|
||||
// Traduzir do JSON do Supabase para o teu Java
|
||||
int id = obj.getInt("id");
|
||||
float valor = (float) obj.getDouble("valor");
|
||||
String categoria = obj.getString("categoria");
|
||||
int tipo = obj.getInt("tipo");
|
||||
String data = obj.getString("data");
|
||||
|
||||
Transacao t = new Transacao(valor, categoria, tipo, data);
|
||||
t.setId(id); // Guarda o ID verdadeiro da nuvem para podermos apagar depois!
|
||||
listaNuvem.add(t);
|
||||
}
|
||||
|
||||
// Atualizar o ecrã tem de ser sempre na Thread Principal (runOnUiThread)
|
||||
if (getActivity() != null) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
adapter = new TransacoesAdapter(listaNuvem, getActivity(), TransacoesFragment.this);
|
||||
recyclerTransacoes.setAdapter(adapter);
|
||||
});
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// APAGAR TRANSAÇÃO NA NUVEM
|
||||
// ====================================================================
|
||||
public void confirmarExclusao(Transacao transacao) {
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setTitle("Eliminar Transação")
|
||||
.setMessage("Apagar " + transacao.getCategoria() + "?")
|
||||
.setPositiveButton("Sim", (dialog, which) -> {
|
||||
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
Request request = new Request.Builder()
|
||||
.url(SupabaseConfig.SUPABASE_URL + "/rest/v1/transacoes?id=eq." + transacao.getId())
|
||||
.addHeader("apikey", SupabaseConfig.SUPABASE_KEY)
|
||||
.addHeader("Authorization", "Bearer " + SupabaseConfig.SUPABASE_KEY)
|
||||
.delete() // O comando mágico para apagar!
|
||||
.build();
|
||||
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(@NonNull Call call, @NonNull IOException e) {}
|
||||
|
||||
@Override
|
||||
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
|
||||
if (getActivity() != null) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
Toast.makeText(getActivity(), "Eliminado das nuvens!", Toast.LENGTH_SHORT).show();
|
||||
carregarDadosDoSupabase(); // Recarrega a lista
|
||||
|
||||
// Atualiza os cartões na MainActivity
|
||||
if (getActivity() instanceof MainActivity) {
|
||||
((MainActivity) getActivity()).atualizarCartoes();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
.setNegativeButton("Não", null)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
@@ -14,17 +14,17 @@ public class ViewPagerAdapter extends FragmentStateAdapter {
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
// Aqui definimos a ordem das abas
|
||||
switch (position) {
|
||||
case 0: return new TransacoesFragment(); // Aba 1
|
||||
case 1: return new GraficosFragment(); // Aba 2
|
||||
case 2: return new DicasFragment(); // Aba 3
|
||||
case 0: return new TransacoesFragment();
|
||||
case 1: return new OrcamentoFragment();
|
||||
case 2: return new GraficosFragment();
|
||||
case 3: return new DicasFragment();
|
||||
default: return new TransacoesFragment();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return 3; // Temos 3 abas no total
|
||||
return 4; // Total de 4 abas
|
||||
}
|
||||
}
|
||||
6
app/src/main/res/drawable/bg_card_tech.xml
Normal file
6
app/src/main/res/drawable/bg_card_tech.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#1AFFFFFF"/>
|
||||
<corners android:radius="16dp"/>
|
||||
<stroke android:width="1dp" android:color="#30FFFFFF"/>
|
||||
</shape>
|
||||
6
app/src/main/res/drawable/bg_circle_icon.xml
Normal file
6
app/src/main/res/drawable/bg_circle_icon.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="#2C5364"/>
|
||||
<stroke android:width="1dp" android:color="@color/tech_accent_cyan"/>
|
||||
</shape>
|
||||
6
app/src/main/res/drawable/bg_icone_transacao.xml
Normal file
6
app/src/main/res/drawable/bg_icone_transacao.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="#E8F5E9" />
|
||||
<size android:width="48dp" android:height="48dp"/>
|
||||
</shape>
|
||||
10
app/src/main/res/drawable/bg_tech_gradient.xml
Normal file
10
app/src/main/res/drawable/bg_tech_gradient.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:startColor="#0F2027"
|
||||
android:centerColor="#203A43"
|
||||
android:endColor="#2C5364"
|
||||
android:angle="45"
|
||||
android:type="linear"/>
|
||||
</shape>
|
||||
BIN
app/src/main/res/drawable/eliminar.png
Normal file
BIN
app/src/main/res/drawable/eliminar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.7 KiB |
9
app/src/main/res/drawable/ic_arrow_back.xml
Normal file
9
app/src/main/res/drawable/ic_arrow_back.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z" />
|
||||
</vector>
|
||||
4
app/src/main/res/drawable/ic_baseline_delete_24.xml
Normal file
4
app/src/main/res/drawable/ic_baseline_delete_24.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</selector>
|
||||
26
app/src/main/res/drawable/ic_carteira_tech.xml
Normal file
26
app/src/main/res/drawable/ic_carteira_tech.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="120dp"
|
||||
android:height="120dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="#673AB7"
|
||||
android:pathData="M21,7.28V5c0,-1.1 -0.9,-2 -2,-2H5C3.89,3 3,3.9 3,5v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2v-2.28A2,2 0 0,0 22,15V9C22,8.14 21.46,7.5 21,7.28zM5,19V5h14v2h-6c-1.1,0 -2,0.9 -2,2v6c0,1.1 0.9,2 2,2h6v2H5z" />
|
||||
|
||||
<path
|
||||
android:fillColor="#4527A0"
|
||||
android:pathData="M20,9v6h-7V9H20z" />
|
||||
|
||||
<path
|
||||
android:fillColor="#00E676"
|
||||
android:pathData="M16.5,10.5 m-1.5,0 a1.5,1.5 0,1 1,3 0 a1.5,1.5 0,1 1,-3 0" />
|
||||
|
||||
<path
|
||||
android:strokeColor="#00E676"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round"
|
||||
android:pathData="M5,8 h3 v3 M5,16 h4" />
|
||||
</vector>
|
||||
10
app/src/main/res/drawable/ic_chart.xml
Normal file
10
app/src/main/res/drawable/ic_chart.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#FF1744">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19,3H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2zM9,17H7v-7h2v7zm4,0h-2v-3h2v3zm4,0h-2v-5h2v5z"/>
|
||||
</vector>
|
||||
10
app/src/main/res/drawable/ic_idea.xml
Normal file
10
app/src/main/res/drawable/ic_idea.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#FFD600">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M9,21c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-1H9v1zm3,-19C8.14,2 5,5.14 5,9c0,2.38 1.19,4.47 3,5.74V17c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-2.26c1.81,-1.27 3,-3.36 3,-5.74 0,-3.86 -3.14,-7 -7,-7zm2.85,11.1l-0.85,0.6V16h-4v-2.3l-0.85,-0.6C7.8,12.16 7,10.63 7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,1.63 -0.8,3.16 -2.15,4.1z"/>
|
||||
</vector>
|
||||
10
app/src/main/res/drawable/ic_pulse.xml
Normal file
10
app/src/main/res/drawable/ic_pulse.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#00E676">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,13h2.28l1.45,-4.79l2.77,8.83L12,5l3.5,12.04L17.28,13H21v-2h-4.72l-1.45,4.79l-2.77,-8.83L9.5,19L6,6.96L4.22,11H3v2z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_settings_pap.xml
Normal file
9
app/src/main/res/drawable/ic_settings_pap.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#FFFFFF"> <path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.33 -0.02,-0.64 -0.06,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.13,5.91 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.82,11.67 4.82,12c0,0.33 0.02,0.64 0.06,0.94L2.86,14.52c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5s3.5,1.57 3.5,3.5S13.93,15.5 12,15.5z"/>
|
||||
</vector>
|
||||
@@ -1,5 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="/Users/230402/wallet-glyph-style-blue-colour_78370-7159.avif" />
|
||||
</selector>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/tech_accent_green"
|
||||
android:pathData="M21,18v1c0,1.1 -0.9,2 -2,2H5c-1.11,0 -2,-0.9 -2,-2V5c0,-1.1 0.89,-2 2,-2h14c1.1,0 2,0.9 2,2v1h-9c-1.11,0 -2,0.9 -2,2v8c0,1.1 0.89,2 2,2h9zm-9,-2h10V8H12v8zm4,-2.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
|
||||
</vector>
|
||||
18
app/src/main/res/drawable/progress_neon.xml
Normal file
18
app/src/main/res/drawable/progress_neon.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@android:id/background">
|
||||
<shape>
|
||||
<corners android:radius="10dp"/>
|
||||
<solid android:color="#263238"/>
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item android:id="@android:id/progress">
|
||||
<clip>
|
||||
<shape>
|
||||
<corners android:radius="10dp"/>
|
||||
<solid android:color="@color/tech_accent_cyan"/>
|
||||
</shape>
|
||||
</clip>
|
||||
</item>
|
||||
</layer-list>
|
||||
17
app/src/main/res/drawable/progress_savings.xml
Normal file
17
app/src/main/res/drawable/progress_savings.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@android:id/background">
|
||||
<shape>
|
||||
<corners android:radius="5dp"/>
|
||||
<solid android:color="#37474F"/>
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item android:id="@android:id/progress">
|
||||
<scale android:scaleWidth="100%">
|
||||
<shape>
|
||||
<corners android:radius="5dp"/>
|
||||
<solid android:color="#00E676"/> </shape>
|
||||
</scale>
|
||||
</item>
|
||||
</layer-list>
|
||||
BIN
app/src/main/res/drawable/wallet.png
Normal file
BIN
app/src/main/res/drawable/wallet.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
61
app/src/main/res/layout/activity_adicionar_transacao.xml
Normal file
61
app/src/main/res/layout/activity_adicionar_transacao.xml
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/bg_tech_gradient"
|
||||
android:padding="24dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btnVoltar"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="@android:drawable/ic_menu_close_clear_cancel"
|
||||
app:tint="@color/white"
|
||||
android:layout_marginBottom="24dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Nova Transação"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/white"
|
||||
android:layout_marginBottom="32dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editValor"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Valor (€)"
|
||||
android:textColorHint="#B0BEC5"
|
||||
android:textColor="@color/white"
|
||||
android:inputType="numberDecimal"
|
||||
android:backgroundTint="@color/tech_accent_cyan"
|
||||
android:textSize="20sp"
|
||||
android:layout_marginBottom="24dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Categoria"
|
||||
android:textColor="#B0BEC5"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinnerCategoria"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:background="@drawable/bg_card_tech"
|
||||
android:layout_marginBottom="40dp"/> <Button
|
||||
android:id="@+id/btnGuardar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Guardar Transação"
|
||||
android:textColor="@color/black"
|
||||
android:padding="12dp"
|
||||
android:textStyle="bold"
|
||||
app:backgroundTint="@color/tech_accent_cyan"/>
|
||||
|
||||
</LinearLayout>
|
||||
90
app/src/main/res/layout/activity_definicoes.xml
Normal file
90
app/src/main/res/layout/activity_definicoes.xml
Normal file
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp"
|
||||
android:background="@color/fundo_app"> <LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="32dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btnVoltarDefinicoes"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="←"
|
||||
android:textColor="@color/texto_principal"
|
||||
android:textSize="32sp"
|
||||
android:textStyle="bold"
|
||||
android:paddingEnd="16dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Definições"
|
||||
android:textColor="@color/texto_principal"
|
||||
android:textSize="28sp"
|
||||
android:textStyle="bold"/>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btnEditarPerfil"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Editar Perfil"
|
||||
android:textColor="@color/texto_principal"
|
||||
android:textSize="18sp"
|
||||
android:paddingVertical="16dp"
|
||||
android:background="?attr/selectableItemBackground"/>
|
||||
|
||||
<View android:layout_width="match_parent" android:layout_height="1dp" android:background="@color/linha_separadora" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/switchModoEscuro"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Modo Escuro"
|
||||
android:textColor="@color/texto_principal"
|
||||
android:textSize="18sp"
|
||||
android:paddingVertical="16dp" />
|
||||
|
||||
<View android:layout_width="match_parent" android:layout_height="1dp" android:background="@color/linha_separadora" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/switchNotificacoes"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Ativar Notificações"
|
||||
android:textColor="@color/texto_principal"
|
||||
android:textSize="18sp"
|
||||
android:paddingVertical="16dp" />
|
||||
|
||||
<View android:layout_width="match_parent" android:layout_height="1dp" android:background="@color/linha_separadora" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btnSuporte"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Centro de Suporte"
|
||||
android:textColor="@color/texto_principal"
|
||||
android:textSize="18sp"
|
||||
android:paddingVertical="16dp"
|
||||
android:background="?attr/selectableItemBackground"/>
|
||||
|
||||
<View android:layout_width="match_parent" android:layout_height="1dp" android:background="@color/linha_separadora" android:layout_marginBottom="32dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnTerminarSessao"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Terminar Sessão"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textStyle="bold"
|
||||
android:padding="16dp"
|
||||
app:cornerRadius="8dp"
|
||||
android:backgroundTint="#FF1744" /> </LinearLayout>
|
||||
93
app/src/main/res/layout/activity_editar_perfil.xml
Normal file
93
app/src/main/res/layout/activity_editar_perfil.xml
Normal file
@@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp"
|
||||
android:background="#1A202C"> <LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="40dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btnVoltarEditarPerfil"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="←"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="32sp"
|
||||
android:textStyle="bold"
|
||||
android:paddingEnd="16dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Editar Perfil"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="28sp"
|
||||
android:textStyle="bold"/>
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="@drawable/bg_circle_icon"
|
||||
android:src="@android:drawable/ic_menu_camera"
|
||||
app:tint="#FFFFFF"
|
||||
android:padding="24dp"
|
||||
android:layout_marginBottom="32dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Nome"
|
||||
android:textColor="#B0BEC5"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editNomePerfil"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#2D3748"
|
||||
android:textColor="#FFFFFF"
|
||||
android:padding="16dp"
|
||||
android:hint="O teu nome"
|
||||
android:textColorHint="#718096"
|
||||
android:layout_marginBottom="24dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Email"
|
||||
android:textColor="#B0BEC5"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editEmailPerfil"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#2D3748"
|
||||
android:textColor="#FFFFFF"
|
||||
android:padding="16dp"
|
||||
android:hint="O teu email"
|
||||
android:textColorHint="#718096"
|
||||
android:inputType="textEmailAddress"
|
||||
android:layout_marginBottom="40dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnGuardarPerfil"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Guardar Alterações"
|
||||
android:textColor="#1A202C"
|
||||
android:textStyle="bold"
|
||||
android:padding="16dp"
|
||||
app:cornerRadius="8dp"
|
||||
android:backgroundTint="#00E676" /> </LinearLayout>
|
||||
@@ -1,95 +1,145 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#F5F7FA"
|
||||
android:background="@drawable/bg_tech_gradient"
|
||||
android:padding="24dp">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
<LinearLayout
|
||||
android:id="@+id/headerLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="8dp">
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:layout_marginTop="60dp"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
app:cardCornerRadius="20dp"
|
||||
app:cardBackgroundColor="#1AFFFFFF"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imgLogoLogin"
|
||||
android:layout_width="100dp" android:layout_height="100dp"
|
||||
android:src="@drawable/ic_carteira_tech"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:background="@android:color/transparent"/>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="FINZORA"
|
||||
android:textSize="32sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/white"
|
||||
android:letterSpacing="0.1"
|
||||
android:layout_marginTop="24dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Acesso ao Sistema"
|
||||
android:textSize="16sp"
|
||||
android:textColor="#B0BEC5"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/imagem_convertida"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="Finzora"
|
||||
android:textSize="28sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#333333"
|
||||
android:layout_marginTop="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="Entre na sua conta para gerir as suas despesas"
|
||||
android:textColor="#666666"
|
||||
android:layout_marginBottom="24dp"/>
|
||||
android:layout_marginTop="48dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/headerLayout">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Email"
|
||||
app:boxCornerRadiusBottomEnd="8dp"
|
||||
app:boxCornerRadiusTopStart="8dp">
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:textColorHint="#90A4AE"
|
||||
app:boxStrokeColor="@color/tech_accent_cyan"
|
||||
app:boxStrokeWidth="1dp"
|
||||
app:boxBackgroundColor="#10FFFFFF"
|
||||
app:boxCornerRadiusTopStart="12dp"
|
||||
app:boxCornerRadiusTopEnd="12dp"
|
||||
app:boxCornerRadiusBottomStart="12dp"
|
||||
app:boxCornerRadiusBottomEnd="12dp"
|
||||
app:hintTextColor="@color/tech_accent_cyan">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/editEmail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textEmailAddress" />
|
||||
android:hint="Email"
|
||||
android:inputType="textEmailAddress"
|
||||
android:textColor="@color/white"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:hint="Palavra-passe"
|
||||
app:passwordToggleEnabled="true">
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_marginTop="16dp"
|
||||
android:textColorHint="#90A4AE"
|
||||
app:boxStrokeColor="@color/tech_accent_cyan"
|
||||
app:boxBackgroundColor="#10FFFFFF"
|
||||
app:boxCornerRadiusTopStart="12dp"
|
||||
app:boxCornerRadiusTopEnd="12dp"
|
||||
app:boxCornerRadiusBottomStart="12dp"
|
||||
app:boxCornerRadiusBottomEnd="12dp"
|
||||
app:hintTextColor="@color/tech_accent_cyan"
|
||||
app:endIconMode="password_toggle"
|
||||
app:endIconTint="#B0BEC5">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/editPassword"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textPassword" />
|
||||
android:hint="Password"
|
||||
android:inputType="textPassword"
|
||||
android:textColor="@color/white"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtEsqueciPassword"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="Esqueci-me da palavra-passe"
|
||||
android:textColor="@color/tech_accent_cyan"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:padding="4dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnEntrar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="Entrar"
|
||||
android:backgroundTint="#4A47E0"
|
||||
app:cornerRadius="8dp" />
|
||||
android:text="INICIAR SESSÃO"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
app:backgroundTint="@color/tech_accent_cyan"
|
||||
app:cornerRadius="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtRegistrar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Não tem conta? Registar agora"
|
||||
android:textColor="#4A47E0" />
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="Não tens conta? Criar agora"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14sp"/>
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</RelativeLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,9 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#F5F7FA"
|
||||
android:background="@color/fundo_app">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
@@ -11,36 +16,30 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="20dp">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/avatarCard"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
app:cardBackgroundColor="#4A47E0"
|
||||
app:cardCornerRadius="24dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:text="J"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
<ImageView
|
||||
android:id="@+id/imgLogo"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:background="@drawable/bg_circle_icon"
|
||||
android:padding="8dp"
|
||||
android:src="@android:drawable/ic_menu_gallery"
|
||||
app:tint="@color/white" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_toEndOf="@id/avatarCard"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:layout_toEndOf="@id/imgLogo"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="12dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Finzora"
|
||||
android:textColor="#333333"
|
||||
android:text="FINZORA"
|
||||
android:textColor="@color/tech_accent_cyan"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
@@ -48,39 +47,37 @@
|
||||
android:id="@+id/tvNomeUsuario"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Olá, Jorge!"
|
||||
android:textColor="#666666"/>
|
||||
android:text="Olá, Investidor"
|
||||
android:textColor="@color/texto_principal"
|
||||
android:textSize="14sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
<Button
|
||||
android:id="@+id/btnSair"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:text="Sair"
|
||||
android:textAllCaps="false"
|
||||
app:cornerRadius="8dp"
|
||||
app:strokeColor="#DDDDDD" />
|
||||
android:textColor="#FFFFFF"
|
||||
android:backgroundTint="#FF1744"
|
||||
style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
|
||||
app:cornerRadius="8dp"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars="none"
|
||||
android:clipToPadding="false"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp">
|
||||
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:clipToPadding="false">
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include layout="@layout/card_saldo_total" />
|
||||
<include layout="@layout/card_receitas" />
|
||||
<include layout="@layout/card_despesas" />
|
||||
|
||||
</LinearLayout>
|
||||
</HorizontalScrollView>
|
||||
|
||||
@@ -88,17 +85,41 @@
|
||||
android:id="@+id/tabLayoutDashboard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:tabMode="fixed"
|
||||
app:tabGravity="fill"
|
||||
app:tabIndicatorColor="#4A47E0"
|
||||
app:tabSelectedTextColor="#4A47E0"
|
||||
android:contentDescription="Menu de navegação principal" />
|
||||
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:tabTextColor="@color/texto_principal"
|
||||
app:tabSelectedTextColor="@color/tech_accent_cyan"
|
||||
app:tabIndicatorColor="@color/tech_accent_cyan"
|
||||
app:tabMode="scrollable"/>
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabAdicionar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="24dp"
|
||||
android:src="@android:drawable/ic_input_add"
|
||||
app:backgroundTint="@color/tech_accent_cyan"
|
||||
app:tint="@color/black"
|
||||
app:elevation="6dp"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btnAbrirDefinicoes"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_gravity="bottom|start"
|
||||
android:layout_margin="24dp"
|
||||
android:padding="12dp"
|
||||
android:src="@drawable/ic_settings_pap"
|
||||
app:tint="@color/texto_principal"
|
||||
android:elevation="6dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"/>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
68
app/src/main/res/layout/activity_onboarding.xml
Normal file
68
app/src/main/res/layout/activity_onboarding.xml
Normal file
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:ignore="HardcodedText"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/bg_tech_gradient">
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:contentDescription="Indicadores de página"
|
||||
android:id="@+id/tabLayoutIndicator"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="10dp"
|
||||
android:layout_marginTop="48dp"
|
||||
android:background="@drawable/bg_card_tech"
|
||||
app:tabIndicatorColor="@color/tech_accent_cyan"
|
||||
app:tabIndicatorHeight="4dp"
|
||||
app:tabIndicatorFullWidth="false"
|
||||
app:tabGravity="center"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/viewPagerOnboarding"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tabLayoutIndicator"
|
||||
app:layout_constraintBottom_toTopOf="@+id/layoutBotoes" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutBotoes"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="32dp"
|
||||
android:gravity="center_vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btnSaltar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Saltar"
|
||||
android:textSize="16sp"
|
||||
android:textColor="#90A4AE"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:padding="8dp"/>
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnProximo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="50dp"
|
||||
android:text="Próximo"
|
||||
android:textColor="@color/black"
|
||||
android:textStyle="bold"
|
||||
app:backgroundTint="@color/tech_accent_cyan"
|
||||
app:cornerRadius="25dp"
|
||||
android:paddingHorizontal="32dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
132
app/src/main/res/layout/activity_profile.xml
Normal file
132
app/src/main/res/layout/activity_profile.xml
Normal file
@@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/bg_tech_gradient"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="O Teu Perfil"
|
||||
android:textSize="28sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/white"
|
||||
android:layout_marginTop="40dp"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Personaliza a tua identidade no Finzora"
|
||||
android:textColor="#B0BEC5"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginBottom="40dp"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="120dp"
|
||||
app:cardCornerRadius="60dp"
|
||||
app:cardBackgroundColor="#20FFFFFF"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imgPerfil"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:src="@drawable/ic_launcher_foreground"
|
||||
android:scaleType="centerCrop"
|
||||
app:tint="@color/tech_accent_cyan"/>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnEscolherFoto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Escolher Foto"
|
||||
android:layout_marginTop="16dp"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:textColor="@color/tech_accent_cyan"/>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:textColorHint="#90A4AE"
|
||||
app:boxStrokeColor="@color/tech_accent_cyan"
|
||||
app:boxBackgroundColor="#10FFFFFF"
|
||||
app:boxCornerRadiusTopStart="12dp"
|
||||
app:boxCornerRadiusTopEnd="12dp"
|
||||
app:boxCornerRadiusBottomStart="12dp"
|
||||
app:boxCornerRadiusBottomEnd="12dp"
|
||||
app:hintTextColor="@color/tech_accent_cyan">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/editNomePerfil"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Nome Completo"
|
||||
android:inputType="textPersonName"
|
||||
android:textColor="@color/white"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:textColorHint="#90A4AE"
|
||||
app:boxStrokeColor="@color/tech_accent_cyan"
|
||||
app:boxBackgroundColor="#10FFFFFF"
|
||||
app:boxCornerRadiusTopStart="12dp"
|
||||
app:boxCornerRadiusTopEnd="12dp"
|
||||
app:boxCornerRadiusBottomStart="12dp"
|
||||
app:boxCornerRadiusBottomEnd="12dp"
|
||||
app:hintTextColor="@color/tech_accent_cyan">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/editBio"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Sobre Mim (Opcional)"
|
||||
android:inputType="textMultiLine"
|
||||
android:lines="3"
|
||||
android:textColor="@color/white"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnGuardarPerfil"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:text="Guardar Perfil"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
app:backgroundTint="@color/tech_accent_cyan"
|
||||
app:cornerRadius="12dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btnSaltarPerfil"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Saltar por agora"
|
||||
android:textColor="#B0BEC5"
|
||||
android:textSize="14sp"
|
||||
android:padding="8dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
83
app/src/main/res/layout/activity_recuperar_password.xml
Normal file
83
app/src/main/res/layout/activity_recuperar_password.xml
Normal file
@@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/bg_tech_gradient"
|
||||
android:padding="24dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btnVoltarRecuperar"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="@android:drawable/ic_menu_close_clear_cancel"
|
||||
app:tint="@color/white"
|
||||
android:layout_marginTop="24dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvTituloRecuperar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Recuperar Palavra-passe"
|
||||
android:textSize="28sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/white"
|
||||
android:layout_marginTop="40dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btnVoltarRecuperar"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSubtituloRecuperar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Insere o teu email registado. Vamos enviar-te um link mágico para redefinires a tua palavra-passe."
|
||||
android:textSize="16sp"
|
||||
android:textColor="#B0BEC5"
|
||||
android:layout_marginTop="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvTituloRecuperar"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="40dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvSubtituloRecuperar">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:textColorHint="#90A4AE"
|
||||
app:boxStrokeColor="@color/tech_accent_cyan"
|
||||
app:boxBackgroundColor="#10FFFFFF"
|
||||
app:boxCornerRadiusTopStart="12dp"
|
||||
app:boxCornerRadiusTopEnd="12dp"
|
||||
app:boxCornerRadiusBottomStart="12dp"
|
||||
app:boxCornerRadiusBottomEnd="12dp"
|
||||
app:hintTextColor="@color/tech_accent_cyan">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/editEmailRecuperar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="O teu Email"
|
||||
android:inputType="textEmailAddress"
|
||||
android:textColor="@color/white"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnEnviarEmail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:text="ENVIAR LINK MÁGICO"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
app:backgroundTint="@color/tech_accent_cyan"
|
||||
app:cornerRadius="12dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,131 +1,162 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#F5F7FA"
|
||||
android:background="@drawable/bg_tech_gradient"
|
||||
android:fillViewport="true">
|
||||
|
||||
<RelativeLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="24dp">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="339dp"
|
||||
android:layout_height="603dp"
|
||||
android:layout_centerInParent="true"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="8dp">
|
||||
<TextView
|
||||
android:id="@+id/tvTituloRegisto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Nova Conta"
|
||||
android:textSize="32sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/white"
|
||||
android:layout_marginTop="40dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSubtitulo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Junta-te ao futuro das finanças."
|
||||
android:textSize="16sp"
|
||||
android:textColor="#B0BEC5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvTituloRegisto"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="634dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/imagem_convertida" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Criar Conta"
|
||||
android:textColor="#333333"
|
||||
android:textSize="28sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:text="Junte-se ao Finzora e comece a gerir as suas finanças"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#666666" />
|
||||
android:layout_marginTop="40dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvSubtitulo">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Nome"
|
||||
app:boxCornerRadiusBottomEnd="8dp"
|
||||
app:boxCornerRadiusTopStart="8dp">
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:textColorHint="#90A4AE"
|
||||
app:boxStrokeColor="@color/tech_accent_green"
|
||||
app:boxBackgroundColor="#10FFFFFF"
|
||||
app:boxCornerRadiusTopStart="12dp"
|
||||
app:boxCornerRadiusTopEnd="12dp"
|
||||
app:boxCornerRadiusBottomStart="12dp"
|
||||
app:boxCornerRadiusBottomEnd="12dp"
|
||||
app:hintTextColor="@color/tech_accent_green">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/editNome"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textPersonName" />
|
||||
android:hint="Nome Completo"
|
||||
android:inputType="textPersonName"
|
||||
android:textColor="@color/white"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:hint="Email">
|
||||
android:layout_marginTop="16dp"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:textColorHint="#90A4AE"
|
||||
app:boxStrokeColor="@color/tech_accent_green"
|
||||
app:boxBackgroundColor="#10FFFFFF"
|
||||
app:boxCornerRadiusTopStart="12dp"
|
||||
app:boxCornerRadiusTopEnd="12dp"
|
||||
app:boxCornerRadiusBottomStart="12dp"
|
||||
app:boxCornerRadiusBottomEnd="12dp"
|
||||
app:hintTextColor="@color/tech_accent_green">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/editEmailRegister"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textEmailAddress" />
|
||||
android:hint="Email"
|
||||
android:inputType="textEmailAddress"
|
||||
android:textColor="@color/white"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:hint="Palavra-passe"
|
||||
app:passwordToggleEnabled="true">
|
||||
android:layout_marginTop="16dp"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:textColorHint="#90A4AE"
|
||||
app:boxStrokeColor="@color/tech_accent_green"
|
||||
app:boxBackgroundColor="#10FFFFFF"
|
||||
app:boxCornerRadiusTopStart="12dp"
|
||||
app:boxCornerRadiusTopEnd="12dp"
|
||||
app:boxCornerRadiusBottomStart="12dp"
|
||||
app:boxCornerRadiusBottomEnd="12dp"
|
||||
app:hintTextColor="@color/tech_accent_green"
|
||||
app:endIconMode="password_toggle"
|
||||
app:endIconTint="#B0BEC5">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/editPassRegister"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textPassword" />
|
||||
android:hint="Password"
|
||||
android:inputType="textPassword"
|
||||
android:textColor="@color/white"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:hint="Confirmar Palavra-passe"
|
||||
app:passwordToggleEnabled="true">
|
||||
android:layout_marginTop="16dp"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:textColorHint="#90A4AE"
|
||||
app:boxStrokeColor="@color/tech_accent_green"
|
||||
app:boxBackgroundColor="#10FFFFFF"
|
||||
app:boxCornerRadiusTopStart="12dp"
|
||||
app:boxCornerRadiusTopEnd="12dp"
|
||||
app:boxCornerRadiusBottomStart="12dp"
|
||||
app:boxCornerRadiusBottomEnd="12dp"
|
||||
app:hintTextColor="@color/tech_accent_green"
|
||||
app:endIconMode="password_toggle"
|
||||
app:endIconTint="#B0BEC5">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/editConfirmPass"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textPassword" />
|
||||
android:hint="Confirmar Password"
|
||||
android:inputType="textPassword"
|
||||
android:textColor="@color/white"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnCriarConta"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:backgroundTint="#4A47E0"
|
||||
android:text="Criar Conta"
|
||||
app:cornerRadius="8dp" />
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:text="CRIAR CONTA"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
app:backgroundTint="@color/tech_accent_green"
|
||||
app:cornerRadius="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtLogin"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Já tem conta? Entrar"
|
||||
android:textColor="#4A47E0" />
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="Já tens conta? Entrar"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14sp"/>
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</RelativeLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
||||
@@ -1,41 +1,49 @@
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="160dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="4dp">
|
||||
app:cardElevation="4dp"
|
||||
app:cardBackgroundColor="@color/fundo_cartao">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
android:padding="20dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Despesas"
|
||||
android:textColor="#666666" />
|
||||
android:textColor="@color/texto_principal"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:src="@drawable/redarrow" />
|
||||
android:src="@android:drawable/arrow_down_float"
|
||||
app:tint="@color/tech_accent_red" />
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDespesasValor"
|
||||
android:id="@+id/tvDespesasGeral"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="€150.50"
|
||||
android:textColor="#D32F2F"
|
||||
android:textSize="22sp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="€ 0.00"
|
||||
android:textColor="@color/tech_accent_red"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</androidx.cardview.widget.CardView>
|
||||
@@ -1,41 +1,49 @@
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="160dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="4dp">
|
||||
app:cardElevation="4dp"
|
||||
app:cardBackgroundColor="@color/fundo_cartao">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
android:padding="20dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Receitas"
|
||||
android:textColor="#666666" />
|
||||
android:textColor="@color/texto_principal"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:src="@drawable/greenarrow" />
|
||||
android:src="@android:drawable/arrow_up_float"
|
||||
app:tint="@color/tech_accent_green" />
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvReceitasValor"
|
||||
android:id="@+id/tvReceitasGeral"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="€1500.00"
|
||||
android:textColor="#2E7D32"
|
||||
android:textSize="22sp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="€ 0.00"
|
||||
android:textColor="@color/tech_accent_green"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</androidx.cardview.widget.CardView>
|
||||
@@ -1,32 +1,45 @@
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="160dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
app:cardElevation="4dp"
|
||||
app:cardBackgroundColor="@color/fundo_cartao"> <LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
android:padding="20dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Saldo Total"
|
||||
android:textColor="#666666" />
|
||||
android:textColor="@color/texto_principal"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" /> <ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:src="@android:drawable/ic_menu_save"
|
||||
app:tint="@color/tech_accent_cyan" />
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSaldoValor"
|
||||
android:id="@+id/tvSaldoGeral"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="€1349.50"
|
||||
android:textColor="#2E7D32"
|
||||
android:textSize="22sp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="€ 0.00"
|
||||
android:textColor="@color/tech_accent_green"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</androidx.cardview.widget.CardView>
|
||||
38
app/src/main/res/layout/dialog_contactar.xml
Normal file
38
app/src/main/res/layout/dialog_contactar.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:padding="16dp">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="20dp"
|
||||
app:cardBackgroundColor="#FFFFFF"
|
||||
app:cardElevation="8dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical" android:layout_marginBottom="24dp">
|
||||
<TextView android:id="@+id/btnVoltarContactar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="← Voltar" android:textColor="#2D3748" android:textStyle="bold" android:background="?attr/selectableItemBackground" android:paddingEnd="16dp"/>
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Contactar Suporte" android:textSize="18sp" android:textStyle="bold" android:textColor="#1A202C"/>
|
||||
</LinearLayout>
|
||||
|
||||
<EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="O seu email" android:background="#F7FAFC" android:padding="16dp" android:layout_marginBottom="12dp"/>
|
||||
<EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Assunto" android:background="#F7FAFC" android:padding="16dp" android:layout_marginBottom="12dp"/>
|
||||
<EditText android:layout_width="match_parent" android:layout_height="120dp" android:hint="Descreva o seu problema..." android:background="#F7FAFC" android:padding="16dp" android:gravity="top|start" android:layout_marginBottom="24dp"/>
|
||||
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="end">
|
||||
<Button android:id="@+id/btnCancelarContacto" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Cancelar" android:backgroundTint="#FFFFFF" android:textColor="#2D3748" android:layout_marginEnd="8dp"/>
|
||||
<Button android:id="@+id/btnEnviarMensagem" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Enviar Mensagem" android:backgroundTint="#1A202C" android:textColor="#FFFFFF"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
64
app/src/main/res/layout/dialog_faq.xml
Normal file
64
app/src/main/res/layout/dialog_faq.xml
Normal file
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:padding="16dp">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="500dp"
|
||||
app:cardCornerRadius="20dp"
|
||||
app:cardBackgroundColor="#FFFFFF"
|
||||
app:cardElevation="8dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical" android:layout_marginBottom="8dp">
|
||||
<TextView android:id="@+id/btnVoltarFAQ" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="← Voltar" android:textColor="#2D3748" android:textStyle="bold" android:background="?attr/selectableItemBackground" android:paddingEnd="16dp"/>
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Perguntas Frequentes" android:textSize="18sp" android:textStyle="bold" android:textColor="#1A202C"/>
|
||||
</LinearLayout>
|
||||
|
||||
<ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="8dp">
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingBottom="16dp">
|
||||
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@drawable/bg_tech_gradient" android:backgroundTint="#F7FAFC" android:padding="16dp" android:layout_marginBottom="12dp">
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Como adiciono uma transação?" android:textStyle="bold" android:textColor="#2D3748" android:layout_marginBottom="8dp"/>
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Vá ao separador 'Adicionar', selecione o tipo (Receita ou Despesa), preencha os campos e clique em 'Adicionar Transação'." android:textColor="#718096" android:textSize="13sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@drawable/bg_tech_gradient" android:backgroundTint="#F7FAFC" android:padding="16dp" android:layout_marginBottom="12dp">
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Como posso definir um orçamento?" android:textStyle="bold" android:textColor="#2D3748" android:layout_marginBottom="8dp"/>
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="No separador 'Orçamentos', escolha a categoria, defina o limite de gastos e clique em 'Definir Orçamento'." android:textColor="#718096" android:textSize="13sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@drawable/bg_tech_gradient" android:backgroundTint="#F7FAFC" android:padding="16dp" android:layout_marginBottom="12dp">
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Como visualizo os meus gastos por categoria?" android:textStyle="bold" android:textColor="#2D3748" android:layout_marginBottom="8dp"/>
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Aceda ao separador 'Gráficos' para ver representações visuais dos seus gastos organizados por categoria e período." android:textColor="#718096" android:textSize="13sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@drawable/bg_tech_gradient" android:backgroundTint="#F7FAFC" android:padding="16dp" android:layout_marginBottom="12dp">
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="O que são as dicas financeiras?" android:textStyle="bold" android:textColor="#2D3748" android:layout_marginBottom="8dp"/>
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="No separador 'Dicas', encontrará recomendações personalizadas baseadas nos seus padrões de gastos para melhorar a sua saúde financeira." android:textColor="#718096" android:textSize="13sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@drawable/bg_tech_gradient" android:backgroundTint="#F7FAFC" android:padding="16dp" android:layout_marginBottom="12dp">
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Como edito o meu perfil?" android:textStyle="bold" android:textColor="#2D3748" android:layout_marginBottom="8dp"/>
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Clique no ícone de definições ao lado do nome 'Finzora' ou na sua foto de perfil para aceder às configurações." android:textColor="#718096" android:textSize="13sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@drawable/bg_tech_gradient" android:backgroundTint="#F7FAFC" android:padding="16dp" android:layout_marginBottom="12dp">
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Os meus dados estão seguros?" android:textStyle="bold" android:textColor="#2D3748" android:layout_marginBottom="8dp"/>
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Sim! Todos os seus dados são armazenados localmente no seu dispositivo e não são partilhados com terceiros." android:textColor="#718096" android:textSize="13sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
130
app/src/main/res/layout/dialog_suporte.xml
Normal file
130
app/src/main/res/layout/dialog_suporte.xml
Normal file
@@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:background="@android:color/transparent"
|
||||
android:padding="16dp">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="20dp"
|
||||
app:cardBackgroundColor="#FFFFFF"
|
||||
app:cardElevation="8dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Centro de Suporte"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#1A202C"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Como podemos ajudá-lo hoje?"
|
||||
android:textSize="14sp"
|
||||
android:textColor="#718096"
|
||||
android:layout_marginBottom="24dp"/>
|
||||
|
||||
<GridLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:columnCount="2"
|
||||
android:rowCount="2">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/cardFAQ"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_columnWeight="1"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
android:layout_margin="8dp"
|
||||
android:background="@drawable/bg_tech_gradient"
|
||||
android:backgroundTint="#F7FAFC">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Perguntas Frequentes"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#2D3748"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/cardTutorial"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_columnWeight="1"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
android:layout_margin="8dp"
|
||||
android:background="@drawable/bg_tech_gradient"
|
||||
android:backgroundTint="#F7FAFC">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Tutorial Passo a Passo"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#2D3748"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/cardMensagem"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_columnWeight="1"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
android:layout_margin="8dp"
|
||||
android:background="@drawable/bg_tech_gradient"
|
||||
android:backgroundTint="#F7FAFC">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Contactar Suporte"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#2D3748"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/cardContactos"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_columnWeight="1"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
android:layout_margin="8dp"
|
||||
android:background="@drawable/bg_tech_gradient"
|
||||
android:backgroundTint="#F7FAFC">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Contactos Diretos"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#2D3748"/>
|
||||
</LinearLayout>
|
||||
|
||||
</GridLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnFecharSuporte"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Fechar"
|
||||
android:backgroundTint="#E2E8F0"
|
||||
android:textColor="#2D3748"
|
||||
android:layout_marginTop="16dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
59
app/src/main/res/layout/dialog_tutorial.xml
Normal file
59
app/src/main/res/layout/dialog_tutorial.xml
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:padding="16dp">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="500dp"
|
||||
app:cardCornerRadius="20dp"
|
||||
app:cardBackgroundColor="#FFFFFF"
|
||||
app:cardElevation="8dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical" android:layout_marginBottom="8dp">
|
||||
<TextView android:id="@+id/btnVoltarTutorial" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="← Voltar" android:textColor="#2D3748" android:textStyle="bold" android:background="?attr/selectableItemBackground" android:paddingEnd="16dp"/>
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Tutorial da Finzora" android:textSize="18sp" android:textStyle="bold" android:textColor="#1A202C"/>
|
||||
</LinearLayout>
|
||||
|
||||
<ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="8dp">
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingBottom="16dp">
|
||||
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@drawable/bg_tech_gradient" android:backgroundTint="#F7FAFC" android:padding="16dp" android:layout_marginBottom="12dp">
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="1. Registe as suas transações" android:textStyle="bold" android:textColor="#2D3748" android:layout_marginBottom="8dp"/>
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Comece por adicionar todas as suas receitas e despesas no separador 'Adicionar'." android:textColor="#718096" android:textSize="13sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@drawable/bg_tech_gradient" android:backgroundTint="#F7FAFC" android:padding="16dp" android:layout_marginBottom="12dp">
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="2. Defina os seus orçamentos" android:textStyle="bold" android:textColor="#2D3748" android:layout_marginBottom="8dp"/>
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Estabeleça limites de gastos por categoria para manter o controlo financeiro." android:textColor="#718096" android:textSize="13sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@drawable/bg_tech_gradient" android:backgroundTint="#F7FAFC" android:padding="16dp" android:layout_marginBottom="12dp">
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="3. Acompanhe os seus gastos" android:textStyle="bold" android:textColor="#2D3748" android:layout_marginBottom="8dp"/>
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Use os gráficos para visualizar para onde vai o seu dinheiro." android:textColor="#718096" android:textSize="13sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@drawable/bg_tech_gradient" android:backgroundTint="#F7FAFC" android:padding="16dp" android:layout_marginBottom="12dp">
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="4. Siga as dicas personalizadas" android:textStyle="bold" android:textColor="#2D3748" android:layout_marginBottom="8dp"/>
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="A Finzora analisa os seus padrões e fornece recomendações úteis." android:textColor="#718096" android:textSize="13sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@drawable/bg_tech_gradient" android:backgroundTint="#F0FFF4" android:padding="16dp" android:layout_marginBottom="12dp">
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="✓ Dica Extra" android:textStyle="bold" android:textColor="#2F855A" android:layout_marginBottom="8dp"/>
|
||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Mantenha a sua aplicação atualizada com transações regulares para obter dicas financeiras mais precisas e personalizadas!" android:textColor="#276749" android:textSize="13sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
395
app/src/main/res/layout/fragment_dicas.xml
Normal file
395
app/src/main/res/layout/fragment_dicas.xml
Normal file
@@ -0,0 +1,395 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/bg_tech_gradient"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Resumo da Sua Saúde Financeira"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="12dp"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardBackgroundColor="#2C5364"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="8dp">
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Taxa de Poupança"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"/>
|
||||
<TextView
|
||||
android:id="@+id/tvTaxaPoupanca"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="0.0%"
|
||||
android:textColor="#00E676"
|
||||
android:textStyle="bold"/>
|
||||
</LinearLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressPoupanca"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="8dp"
|
||||
android:max="100"
|
||||
android:progress="0"
|
||||
android:progressTint="#00E676"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:background="#1AFFFFFF"
|
||||
android:padding="12dp"
|
||||
android:layout_marginEnd="8dp">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Receitas"
|
||||
android:textColor="#B0BEC5"
|
||||
android:textSize="12sp"/>
|
||||
<TextView
|
||||
android:id="@+id/tvDicasReceitas"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="€ 0.00"
|
||||
android:textColor="#00E676"
|
||||
android:textStyle="bold"
|
||||
android:textSize="16sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:background="#1AFFFFFF"
|
||||
android:padding="12dp"
|
||||
android:layout_marginStart="8dp">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Despesas"
|
||||
android:textColor="#B0BEC5"
|
||||
android:textSize="12sp"/>
|
||||
<TextView
|
||||
android:id="@+id/tvDicasDespesas"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="€ 0.00"
|
||||
android:textColor="#FF1744"
|
||||
android:textStyle="bold"
|
||||
android:textSize="16sp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Dicas Personalizadas"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="12dp"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/cardDica1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardBackgroundColor="#2C5364"
|
||||
app:cardElevation="2dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
<TextView
|
||||
android:id="@+id/tvTituloDica1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="A calcular..."
|
||||
android:textColor="#00E676"
|
||||
android:textStyle="bold"
|
||||
android:textSize="16sp"/>
|
||||
<TextView
|
||||
android:id="@+id/tvDescDica1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="..."
|
||||
android:textColor="#B0BEC5"
|
||||
android:layout_marginTop="4dp"/>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/cardDica2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardBackgroundColor="#2C5364"
|
||||
app:cardElevation="2dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
<TextView
|
||||
android:id="@+id/tvTituloDica2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="A analisar gastos..."
|
||||
android:textColor="#FF1744"
|
||||
android:textStyle="bold"
|
||||
android:textSize="16sp"/>
|
||||
<TextView
|
||||
android:id="@+id/tvDescDica2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="..."
|
||||
android:textColor="#B0BEC5"
|
||||
android:layout_marginTop="4dp"/>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Distribuição de Gastos"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="12dp"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardBackgroundColor="#2C5364"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutDistribuicao"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_idea"
|
||||
app:tint="@color/white"
|
||||
android:layout_marginEnd="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Dicas Rápidas de Economia"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"/>
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="32dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardBackgroundColor="#2C5364"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="16dp">
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:src="@android:drawable/checkbox_on_background"
|
||||
app:tint="#00E676"
|
||||
android:layout_marginTop="2dp"/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginStart="12dp">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Prepare refeições em casa"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"
|
||||
android:textSize="14sp"/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Pode poupar até €200/mês reduzindo refeições fora"
|
||||
android:textColor="#B0BEC5"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginTop="2dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="16dp">
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:src="@android:drawable/checkbox_on_background"
|
||||
app:tint="#00E676"
|
||||
android:layout_marginTop="2dp"/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginStart="12dp">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Compare preços antes de comprar"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"
|
||||
android:textSize="14sp"/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Use apps de comparação para encontrar melhores ofertas"
|
||||
android:textColor="#B0BEC5"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginTop="2dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="16dp">
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:src="@android:drawable/checkbox_on_background"
|
||||
app:tint="#00E676"
|
||||
android:layout_marginTop="2dp"/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginStart="12dp">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Cancele subscrições não utilizadas"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"
|
||||
android:textSize="14sp"/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Reveja streamings, ginásios e apps que paga mas não usa"
|
||||
android:textColor="#B0BEC5"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginTop="2dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:src="@android:drawable/checkbox_on_background"
|
||||
app:tint="#00E676"
|
||||
android:layout_marginTop="2dp"/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginStart="12dp">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Use transportes públicos"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"
|
||||
android:textSize="14sp"/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Economize em combustível, estacionamento e manutenção"
|
||||
android:textColor="#B0BEC5"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginTop="2dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
88
app/src/main/res/layout/fragment_graficos.xml
Normal file
88
app/src/main/res/layout/fragment_graficos.xml
Normal file
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/bg_tech_gradient"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Despesas por Categoria"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="300dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardBackgroundColor="#2C5364"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<com.github.mikephil.charting.charts.PieChart
|
||||
android:id="@+id/pieChartDespesas"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="12dp"/>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Orçamento vs Gastos Reais"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="300dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardBackgroundColor="#2C5364"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<com.github.mikephil.charting.charts.BarChart
|
||||
android:id="@+id/barChartOrcamento"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="12dp"/>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Tendência Mensal (Geral)"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="300dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardBackgroundColor="#2C5364"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<com.github.mikephil.charting.charts.BarChart
|
||||
android:id="@+id/barChartTendencia"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="12dp"/>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
93
app/src/main/res/layout/fragment_orcamento.xml
Normal file
93
app/src/main/res/layout/fragment_orcamento.xml
Normal file
@@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout 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:orientation="vertical"
|
||||
android:background="@drawable/bg_tech_gradient"
|
||||
android:padding="16dp"
|
||||
tools:ignore="HardcodedText">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Planeamento de Orçamento"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"
|
||||
android:textSize="18sp"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardBackgroundColor="@color/white">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Categoria"
|
||||
android:textColor="#333333"
|
||||
android:textStyle="bold"
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinnerOrcamento"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="48dp"
|
||||
android:background="#F5F5F5"
|
||||
android:layout_marginBottom="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Limite Mensal (€)"
|
||||
android:textColor="#333333"
|
||||
android:textStyle="bold"
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editLimite"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:background="#F5F5F5"
|
||||
android:padding="8dp"
|
||||
android:inputType="numberDecimal"
|
||||
android:hint="0.00"
|
||||
android:textColor="#000000"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnDefinirOrcamento"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Definir Orçamento"
|
||||
android:backgroundTint="#0F2027"
|
||||
android:textColor="@color/white"/>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Orçamentos Ativos"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"
|
||||
android:textSize="18sp"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerOrcamentos"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</LinearLayout>
|
||||
14
app/src/main/res/layout/fragment_transacoes.xml
Normal file
14
app/src/main/res/layout/fragment_transacoes.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/bg_tech_gradient"
|
||||
android:padding="8dp">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerTransacoes"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="80dp"/> </LinearLayout>
|
||||
12
app/src/main/res/layout/item_dropdown.xml
Normal file
12
app/src/main/res/layout/item_dropdown.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="12dp"
|
||||
android:textSize="16sp"
|
||||
android:textColor="#FFFFFF"
|
||||
android:background="#1A202C"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"/>
|
||||
54
app/src/main/res/layout/item_onboarding.xml
Normal file
54
app/src/main/res/layout/item_onboarding.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="24dp"
|
||||
android:background="@drawable/bg_tech_gradient"> <LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="120dp"
|
||||
app:cardCornerRadius="24dp"
|
||||
app:cardElevation="0dp"
|
||||
app:cardBackgroundColor="#20FFFFFF"
|
||||
android:layout_marginBottom="40dp">
|
||||
<ImageView
|
||||
android:id="@+id/imgOnboarding"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/wallet"/>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textTitulo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Título do Tutorial"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="28sp"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textDescricao"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Descrição detalhada sobre a funcionalidade."
|
||||
android:textColor="#B0BEC5"
|
||||
android:textSize="16sp"
|
||||
android:gravity="center"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:layout_marginHorizontal="16dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
61
app/src/main/res/layout/item_orcamento.xml
Normal file
61
app/src/main/res/layout/item_orcamento.xml
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardBackgroundColor="#2C5364"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCatOrcamento"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Alimentação"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvValoresOrcamento"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="€85.50 / €300.00"
|
||||
android:textColor="#B0BEC5"
|
||||
android:textSize="14sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressOrcamento"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="8dp"
|
||||
android:progressDrawable="@drawable/progress_savings"
|
||||
android:max="100"
|
||||
android:progress="50"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvRestante"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Restam €214.50 (72%)"
|
||||
android:textColor="#90A4AE"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginTop="6dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
79
app/src/main/res/layout/item_transacao.xml
Normal file
79
app/src/main/res/layout/item_transacao.xml
Normal file
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginVertical="8dp"
|
||||
app:cardBackgroundColor="#FFFFFF"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imgIcone"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="@drawable/bg_icone_transacao"
|
||||
android:src="@android:drawable/ic_menu_sort_by_size"
|
||||
app:tint="#4CAF50" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="16dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDescricao"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Descrição"
|
||||
android:textColor="#1A202C"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvData"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Data"
|
||||
android:textColor="#718096"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginTop="4dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="end">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvValor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="€ 0.00"
|
||||
android:textColor="#4CAF50"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btnEliminar"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:src="@android:drawable/ic_menu_delete"
|
||||
app:tint="#F44336" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
7
app/src/main/res/values-night/colors.xml
Normal file
7
app/src/main/res/values-night/colors.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="fundo_app">#1A202C</color>
|
||||
<color name="texto_principal">#FFFFFF</color>
|
||||
<color name="fundo_cartao">#2D3748</color>
|
||||
<color name="linha_separadora">#2D3748</color>
|
||||
</resources>
|
||||
@@ -2,4 +2,15 @@
|
||||
<resources>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
<color name="tech_accent_cyan">#00E676</color>
|
||||
<color name="tech_card_bg">#2D3748</color>
|
||||
<color name="text_secondary">#A0AEC0</color>
|
||||
<color name="tech_accent_green">#48BB78</color>
|
||||
<color name="tech_accent_yellow">#ECC94B</color> <color name="tech_accent_red">#F56565</color>
|
||||
<color name="tech_bg_dark">#1A202C</color>
|
||||
|
||||
<color name="fundo_app">#FFFFFF</color>
|
||||
<color name="texto_principal">#1A202C</color>
|
||||
<color name="fundo_cartao">#F7FAFC</color>
|
||||
<color name="linha_separadora">#E2E8F0</color>
|
||||
</resources>
|
||||
@@ -1,4 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<item name="main" type="id" />
|
||||
<item name="editValor" type="id" />
|
||||
<item name="editData" type="id" />
|
||||
<item name="editCategoria" type="id" />
|
||||
<item name="editDescricao" type="id" />
|
||||
<item name="rbReceita" type="id" />
|
||||
<item name="rbDespesa" type="id" />
|
||||
<item name="btnSalvarTransacao" type="id" />
|
||||
<item name="tabLayoutIndicator" type="id" />
|
||||
<item name="iconSeta" type="id" />
|
||||
<item name="btnApagar" type="id" />
|
||||
<item name="spinnerCategoria" type="id" />
|
||||
<item name="btnSalvar" type="id" />
|
||||
<item name="tvTotalReceitas" type="id" />
|
||||
<item name="tvTotalDespesas" type="id" />
|
||||
<item name="tvPercentagemPoupanca" type="id" />
|
||||
<item name="progressPoupanca" type="id" />
|
||||
<item name="cardElogio" type="id" />
|
||||
<item name="tvTextoElogio" type="id" />
|
||||
<item name="cardAlerta" type="id" />
|
||||
<item name="tvTituloAlerta" type="id" />
|
||||
<item name="tvTextoAlerta" type="id" />
|
||||
<item name="btnGuardar" type="id" />
|
||||
</resources>
|
||||
@@ -1,8 +1,29 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Base.Theme.Finzora" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<!-- Customize your light theme here. -->
|
||||
<!-- <item name="colorPrimary">@color/my_light_primary</item> -->
|
||||
<item name="colorPrimary">@color/tech_accent_cyan</item>
|
||||
<item name="colorOnPrimary">@color/black</item>
|
||||
<item name="colorPrimaryContainer">@color/tech_card_bg</item>
|
||||
<item name="colorOnPrimaryContainer">@color/white</item>
|
||||
<item name="colorSecondary">@color/tech_accent_green</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<item name="colorSecondaryContainer">@color/tech_card_bg</item>
|
||||
<item name="colorOnSecondaryContainer">@color/white</item>
|
||||
<item name="colorTertiary">@color/tech_accent_yellow</item>
|
||||
<item name="colorOnTertiary">@color/black</item>
|
||||
<item name="colorTertiaryContainer">@color/tech_card_bg</item>
|
||||
<item name="colorOnTertiaryContainer">@color/white</item>
|
||||
<item name="colorError">@color/tech_accent_red</item>
|
||||
<item name="colorOnError">@color/black</item>
|
||||
<item name="colorErrorContainer">@color/tech_card_bg</item>
|
||||
<item name="colorOnErrorContainer">@color/white</item>
|
||||
<item name="android:colorBackground">@color/tech_bg_dark</item>
|
||||
<item name="colorOnBackground">@color/white</item>
|
||||
<item name="colorSurface">@color/tech_card_bg</item>
|
||||
<item name="colorOnSurface">@color/white</item>
|
||||
<item name="colorSurfaceVariant">@color/tech_card_bg</item>
|
||||
<item name="colorOnSurfaceVariant">@color/text_secondary</item>
|
||||
<item name="colorOutline">@color/tech_accent_cyan</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Finzora" parent="Base.Theme.Finzora" />
|
||||
|
||||
@@ -19,3 +19,13 @@ android.useAndroidX=true
|
||||
# resources declared in the library itself and none from the library's dependencies,
|
||||
# thereby reducing the size of the R class for that library
|
||||
android.nonTransitiveRClass=true
|
||||
android.defaults.buildfeatures.resvalues=true
|
||||
android.sdk.defaultTargetSdkToCompileSdkIfUnset=false
|
||||
android.enableAppCompileTimeRClass=false
|
||||
android.usesSdkInManifest.disallowed=false
|
||||
android.uniquePackageNames=false
|
||||
android.dependency.useConstraints=true
|
||||
android.r8.strictFullModeForKeepRules=false
|
||||
android.r8.optimizedResourceShrinking=false
|
||||
android.builtInKotlin=false
|
||||
android.newDsl=false
|
||||
@@ -1,5 +1,5 @@
|
||||
[versions]
|
||||
agp = "8.13.2"
|
||||
agp = "9.0.0"
|
||||
junit = "4.13.2"
|
||||
junitVersion = "1.3.0"
|
||||
espressoCore = "3.7.0"
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,7 +1,7 @@
|
||||
#Tue Jan 20 14:33:41 WET 2026
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -16,9 +16,9 @@ dependencyResolutionManagement {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven { url = uri("https://jitpack.io") }
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "Finzora"
|
||||
include(":app")
|
||||
|
||||
Reference in New Issue
Block a user