From f43ce1d70d5e4c63871d2c4405fdafa959a2fcc4 Mon Sep 17 00:00:00 2001 From: 230412 <230412@epvc.pt> Date: Mon, 15 Jun 2026 17:18:22 +0100 Subject: [PATCH] =?UTF-8?q?corrigir=20os=20novos=20erros=20amnh=C3=A3=20e?= =?UTF-8?q?=20adicionar=20qual=20tipo=20de=20sexo=20a=20pessoa=20=C3=A9=20?= =?UTF-8?q?no=20register?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 7 + .../com/example/pap/DefinicoesActivity.java | 237 +++--------------- .../com/example/pap/DesafiosActivity.java | 30 ++- .../com/example/pap/EstatisticasActivity.java | 28 ++- .../java/com/example/pap/FotoActivity.java | 19 +- .../main/res/layout/activity_definicoes.xml | 152 +++++------ .../main/res/layout/activity_estatisticas.xml | 10 +- app/src/main/res/layout/activity_home.xml | 2 +- 8 files changed, 174 insertions(+), 311 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a0f7d5e..293fccd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,7 +3,14 @@ xmlns:tools="http://schemas.android.com/tools"> + + + + + + + finish()); - // 1. Lógica do Modo Escuro - boolean isDarkMode = sharedPreferences.getBoolean("dark_mode", false); - switchDarkMode.setChecked(isDarkMode); + // 1. CARREGAR E CONFIGURAR O MODO ESCURO + SharedPreferences themePrefs = getSharedPreferences("Definicoes", MODE_PRIVATE); + boolean isDark = themePrefs.getBoolean("dark_mode", false); + switchModoEscuro.setChecked(isDark); + + switchModoEscuro.setOnCheckedChangeListener((buttonView, isChecked) -> { + SharedPreferences.Editor editor = themePrefs.edit(); + editor.putBoolean("dark_mode", isChecked); + editor.apply(); - switchDarkMode.setOnCheckedChangeListener((buttonView, isChecked) -> { if (isChecked) { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); } else { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); } - sharedPreferences.edit().putBoolean("dark_mode", isChecked).apply(); }); - // Configurar os cliques nos botões - btnEditarNome.setOnClickListener(v -> mostrarPopupNome()); - btnMudarEmail.setOnClickListener(v -> mostrarPopupEmail()); - btnMudarPass.setOnClickListener(v -> mostrarPopupPassword()); - btnVoltarDef.setOnClickListener(v -> finish()); - } + // 2. CARREGAR O NOME E EMAIL ATUAIS PARA O CAMPO DE TEXTO + SharedPreferences dadosPrefs = getSharedPreferences("MeusDadosApp", MODE_PRIVATE); + etNovoNome.setText(dadosPrefs.getString("nome", "")); + etNovoEmail.setText(dadosPrefs.getString("email", "")); - // --- FUNÇÕES DOS POP-UPS --- - - private void mostrarPopupNome() { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle("Mudar Nome"); - - final EditText input = new EditText(this); - input.setHint("Novo nome"); - builder.setView(input); - - builder.setPositiveButton("Guardar", (dialog, which) -> { - String novoNome = input.getText().toString().trim(); - if (!novoNome.isEmpty()) { - sharedPreferences.edit().putString("nome", novoNome).apply(); - Toast.makeText(this, "Nome atualizado com sucesso!", Toast.LENGTH_SHORT).show(); - } - }); - builder.show(); - } - - private void mostrarPopupEmail() { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle("Alterar Email"); - - LinearLayout layout = new LinearLayout(this); - layout.setOrientation(LinearLayout.VERTICAL); - layout.setPadding(50, 20, 50, 0); - - final EditText etPassAtual = new EditText(this); - etPassAtual.setHint("A tua Password atual"); - etPassAtual.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); - layout.addView(etPassAtual); - - final EditText etNovoEmail = new EditText(this); - etNovoEmail.setHint("Novo Email"); - layout.addView(etNovoEmail); - - builder.setView(layout); - builder.setPositiveButton("Alterar", (dialog, which) -> { - String passAtual = etPassAtual.getText().toString().trim(); + // 3. GUARDAR AS ALTERAÇÕES + btnGuardarAlteracoes.setOnClickListener(v -> { + String novoNome = etNovoNome.getText().toString().trim(); String novoEmail = etNovoEmail.getText().toString().trim(); - String emailAtual = sharedPreferences.getString("email", ""); + String novaPassword = etNovaPassword.getText().toString().trim(); - if (passAtual.isEmpty() || novoEmail.isEmpty()) { - Toast.makeText(this, "Preenche todos os campos!", Toast.LENGTH_SHORT).show(); - return; + SharedPreferences.Editor editor = dadosPrefs.edit(); + + if (!novoNome.isEmpty()) { + editor.putString("nome", novoNome); + } + if (!novoEmail.isEmpty()) { + editor.putString("email", novoEmail); } - SupabaseApi api = SupabaseConfig.getRetrofit().create(SupabaseApi.class); - UserCredentials creds = new UserCredentials(emailAtual, passAtual); + editor.apply(); - // Confirma a identidade do utilizador (Mini-login) - api.login(SupabaseConfig.SUPABASE_KEY, creds).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - String freshToken = response.body().access_token; - - // Envia o pedido de alteração de email para o Supabase - Map updates = new HashMap<>(); - updates.put("email", novoEmail); - - api.updateUserData(SupabaseConfig.SUPABASE_KEY, "Bearer " + freshToken, updates).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - // Apenas avisa o utilizador. O email só muda após clicar no link! - Toast.makeText(DefinicoesActivity.this, "Link enviado! Verifica a tua nova caixa de correio para confirmar.", Toast.LENGTH_LONG).show(); - } else { - Toast.makeText(DefinicoesActivity.this, "Erro ao tentar enviar o email de confirmação.", Toast.LENGTH_SHORT).show(); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - Toast.makeText(DefinicoesActivity.this, "Verifica a tua ligação à internet!", Toast.LENGTH_SHORT).show(); - } - }); - } else { - Toast.makeText(DefinicoesActivity.this, "A password atual está incorreta!", Toast.LENGTH_LONG).show(); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - Toast.makeText(DefinicoesActivity.this, "Verifica a tua ligação à internet!", Toast.LENGTH_SHORT).show(); - } - }); + Toast.makeText(this, "Alterações guardadas com sucesso!", Toast.LENGTH_SHORT).show(); + finish(); // Volta ao ecrã anterior }); - builder.show(); - } - - private void mostrarPopupPassword() { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle("Alterar Password"); - - LinearLayout layout = new LinearLayout(this); - layout.setOrientation(LinearLayout.VERTICAL); - layout.setPadding(50, 20, 50, 0); - - final EditText etAntiga = new EditText(this); - etAntiga.setHint("Password Antiga"); - etAntiga.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); - layout.addView(etAntiga); - - final EditText etNova = new EditText(this); - etNova.setHint("Nova Password (min. 6 caracteres)"); - etNova.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); - layout.addView(etNova); - - final EditText etConfirma = new EditText(this); - etConfirma.setHint("Confirma a Nova Password"); - etConfirma.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); - layout.addView(etConfirma); - - builder.setView(layout); - builder.setPositiveButton("Atualizar", (dialog, which) -> { - String pAntiga = etAntiga.getText().toString().trim(); - String pNova = etNova.getText().toString().trim(); - String pConfirma = etConfirma.getText().toString().trim(); - String emailAtual = sharedPreferences.getString("email", ""); - - if (pAntiga.isEmpty() || pNova.isEmpty() || pConfirma.isEmpty()) { - Toast.makeText(this, "Preenche todos os campos!", Toast.LENGTH_SHORT).show(); - return; - } - - if (!pNova.equals(pConfirma) || pNova.length() < 6) { - Toast.makeText(this, "As novas passwords não coincidem ou são muito curtas!", Toast.LENGTH_LONG).show(); - return; - } - - SupabaseApi api = SupabaseConfig.getRetrofit().create(SupabaseApi.class); - UserCredentials creds = new UserCredentials(emailAtual, pAntiga); - - // Confirma a identidade do utilizador (Mini-login) - api.login(SupabaseConfig.SUPABASE_KEY, creds).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - String freshToken = response.body().access_token; - - // Atualiza a palavra-passe no Supabase - Map updates = new HashMap<>(); - updates.put("password", pNova); - - api.updateUserData(SupabaseConfig.SUPABASE_KEY, "Bearer " + freshToken, updates).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - Toast.makeText(DefinicoesActivity.this, "Password alterada com sucesso!", Toast.LENGTH_LONG).show(); - } else { - Toast.makeText(DefinicoesActivity.this, "Erro no servidor ao mudar password.", Toast.LENGTH_SHORT).show(); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - Toast.makeText(DefinicoesActivity.this, "Verifica a tua ligação à internet!", Toast.LENGTH_SHORT).show(); - } - }); - } else { - Toast.makeText(DefinicoesActivity.this, "A password antiga está incorreta!", Toast.LENGTH_LONG).show(); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - Toast.makeText(DefinicoesActivity.this, "Verifica a tua ligação à internet!", Toast.LENGTH_SHORT).show(); - } - }); - }); - builder.show(); } } \ No newline at end of file diff --git a/app/src/main/java/com/example/pap/DesafiosActivity.java b/app/src/main/java/com/example/pap/DesafiosActivity.java index 996d4ff..cf8a7b7 100644 --- a/app/src/main/java/com/example/pap/DesafiosActivity.java +++ b/app/src/main/java/com/example/pap/DesafiosActivity.java @@ -58,7 +58,6 @@ public class DesafiosActivity extends AppCompatActivity { verificarResetMeiaNoite(); - // Launcher da Câmara ActivityResultLauncher videoLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { @@ -70,7 +69,6 @@ public class DesafiosActivity extends AppCompatActivity { } }); - // Configurar Botões btnVideoAgua.setOnClickListener(v -> { desafioAtualSendoGravado = 0; abrirCamera(videoLauncher); }); btnVideoD1.setOnClickListener(v -> { desafioAtualSendoGravado = 1; abrirCamera(videoLauncher); }); btnVideoD2.setOnClickListener(v -> { desafioAtualSendoGravado = 2; abrirCamera(videoLauncher); }); @@ -91,7 +89,6 @@ public class DesafiosActivity extends AppCompatActivity { String dataGuardada = prefs.getString("data_5_desafios", ""); if (!dataHoje.equals(dataGuardada)) { - // Limpar tudo SharedPreferences.Editor editor = prefs.edit(); editor.putString("data_5_desafios", dataHoje); editor.putFloat("agua_litros", 0.0f); @@ -99,8 +96,10 @@ public class DesafiosActivity extends AppCompatActivity { editor.putBoolean("d2_concluido", false); editor.putBoolean("d3_concluido", false); editor.putBoolean("d4_concluido", false); - // Zera a água para as estatísticas + + // Zera a água e as calorias dos desafios diários editor.putInt("agua_hoje", 0); + editor.putInt("calorias_desafios", 0); editor.apply(); } @@ -122,10 +121,10 @@ public class DesafiosActivity extends AppCompatActivity { private void atualizarTextoDesafio(TextView tv, boolean concluido) { if (concluido) { tv.setText("Estado: Concluído ✅"); - tv.setTextColor(Color.parseColor("#10B981")); // Verde + tv.setTextColor(Color.parseColor("#10B981")); } else { tv.setText("Estado: Pendente"); - tv.setTextColor(Color.parseColor("#EF4444")); // Vermelho + tv.setTextColor(Color.parseColor("#EF4444")); } } @@ -178,7 +177,6 @@ public class DesafiosActivity extends AppCompatActivity { SharedPreferences prefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit(); - // Dar pontos no perfil SharedPreferences perfilPrefs = getSharedPreferences("MeusDadosApp", MODE_PRIVATE); SharedPreferences.Editor perfilEditor = perfilPrefs.edit(); @@ -191,7 +189,7 @@ public class DesafiosActivity extends AppCompatActivity { litrosAgua += lido; editor.putFloat("agua_litros", litrosAgua); - editor.putInt("agua_hoje", (int) (litrosAgua / 0.25f)); // Atualiza Estatísticas + editor.putInt("agua_hoje", (int) (litrosAgua / 0.25f)); tvStatusGeralIA.setText("IA leu: +" + lido + " Litros!"); } catch (Exception e) { @@ -200,12 +198,18 @@ public class DesafiosActivity extends AppCompatActivity { } } else { if (texto.contains("Status: Concluido")) { - tvStatusGeralIA.setText("IA: Desafio Validado! ✅ +50 Pontos"); - if (desafioAtualSendoGravado == 1) editor.putBoolean("d1_concluido", true); - if (desafioAtualSendoGravado == 2) editor.putBoolean("d2_concluido", true); - if (desafioAtualSendoGravado == 3) editor.putBoolean("d3_concluido", true); - if (desafioAtualSendoGravado == 4) editor.putBoolean("d4_concluido", true); + int caloriasAQueimar = 0; + if (desafioAtualSendoGravado == 1) { editor.putBoolean("d1_concluido", true); caloriasAQueimar = 2; } + if (desafioAtualSendoGravado == 2) { editor.putBoolean("d2_concluido", true); caloriasAQueimar = 2; } + if (desafioAtualSendoGravado == 3) { editor.putBoolean("d3_concluido", true); caloriasAQueimar = 2; } + if (desafioAtualSendoGravado == 4) { editor.putBoolean("d4_concluido", true); caloriasAQueimar = 3; } + + // Soma as calorias queimadas e atualiza a pontuação + int caloriasTotaisQueimadas = prefs.getInt("calorias_desafios", 0) + caloriasAQueimar; + editor.putInt("calorias_desafios", caloriasTotaisQueimadas); + + tvStatusGeralIA.setText("IA: Desafio Validado! ✅ +50 Pontos | 🔥 +" + caloriasAQueimar + " kcal"); perfilEditor.putInt("pontos", perfilPrefs.getInt("pontos", 0) + 50); perfilEditor.putInt("desafios_concluidos", perfilPrefs.getInt("desafios_concluidos", 0) + 1); diff --git a/app/src/main/java/com/example/pap/EstatisticasActivity.java b/app/src/main/java/com/example/pap/EstatisticasActivity.java index bf9e651..d269cdf 100644 --- a/app/src/main/java/com/example/pap/EstatisticasActivity.java +++ b/app/src/main/java/com/example/pap/EstatisticasActivity.java @@ -11,7 +11,7 @@ import java.util.Locale; public class EstatisticasActivity extends AppCompatActivity { - private TextView tvValorIMC, tvStatusIMC, tvCaloriasMeta; + private TextView tvValorIMC, tvStatusIMC, tvCaloriasMeta, tvDicaIA, tvCaloriasQueimadas; private TextView tvProtGramas, tvHidrGramas, tvGordGramas, tvComida1; private TextView tvAguaStats; private ProgressBar progressProt, progressHidr, progressGord; @@ -21,11 +21,13 @@ public class EstatisticasActivity extends AppCompatActivity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_estatisticas); - // Ligar o layout (XML) às variáveis do Java tvValorIMC = findViewById(R.id.tvValorIMC); tvStatusIMC = findViewById(R.id.tvStatusIMC); tvCaloriasMeta = findViewById(R.id.tvCaloriasMeta); + tvDicaIA = findViewById(R.id.tvDicaIA); + tvCaloriasQueimadas = findViewById(R.id.tvCaloriasQueimadas); + tvProtGramas = findViewById(R.id.tvProtGramas); tvHidrGramas = findViewById(R.id.tvHidrGramas); tvGordGramas = findViewById(R.id.tvGordGramas); @@ -37,14 +39,13 @@ public class EstatisticasActivity extends AppCompatActivity { progressHidr = findViewById(R.id.progressHidr); progressGord = findViewById(R.id.progressGord); - // Botão voltar findViewById(R.id.btnVoltarStats).setOnClickListener(v -> finish()); - // Chamar as funções que preenchem os dados calcularIMC(); calcularTMB(); carregarMacrosDaIA(); carregarAgua(); + carregarCaloriasQueimadas(); } private void calcularIMC() { @@ -80,24 +81,19 @@ public class EstatisticasActivity extends AppCompatActivity { float peso = prefs.getFloat("peso", 0); float alturaMetros = prefs.getFloat("altura", 0); String sexo = prefs.getString("sexo", ""); - - // Puxa a idade real. Se der erro ou não existir, assume 20. int idade = prefs.getInt("idade", 20); if (peso > 0 && alturaMetros > 0 && !sexo.isEmpty()) { - float alturaCm = alturaMetros * 100; // Passar para centímetros + float alturaCm = alturaMetros * 100; double tmb; - // Fórmula de Harris-Benedict if (sexo.equals("Masculino")) { tmb = (10 * peso) + (6.25 * alturaCm) - (5 * idade) + 5; } else { tmb = (10 * peso) + (6.25 * alturaCm) - (5 * idade) - 161; } - // Fator de atividade leve para dar uma meta real (1.2) double caloriasTotais = tmb * 1.2; - tvCaloriasMeta.setText(String.valueOf((int) caloriasTotais)); } else { tvCaloriasMeta.setText("--"); @@ -112,6 +108,10 @@ public class EstatisticasActivity extends AppCompatActivity { int gord = prefs.getInt("gord_hoje", 0); String ultimaComida = prefs.getString("ultimo_prato", "Ainda não leste nada hoje."); + // Puxa a dica extraída da foto! + String dicaIa = prefs.getString("ultima_dica_ia", "Continua a registar as tuas refeições para ver dicas."); + tvDicaIA.setText(dicaIa); + tvProtGramas.setText("Proteína: " + prot + "g"); tvHidrGramas.setText("Hidratos: " + hidr + "g"); tvGordGramas.setText("Gordura: " + gord + "g"); @@ -126,9 +126,13 @@ public class EstatisticasActivity extends AppCompatActivity { private void carregarAgua() { SharedPreferences prefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE); int coposBebidos = prefs.getInt("agua_hoje", 0); - float litrosTotais = coposBebidos * 0.25f; - tvAguaStats.setText(String.format(Locale.getDefault(), "💧 %.2f L", litrosTotais)); } + + private void carregarCaloriasQueimadas() { + SharedPreferences prefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE); + int kcalQueimadas = prefs.getInt("calorias_desafios", 0); + tvCaloriasQueimadas.setText(kcalQueimadas + " kcal"); + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/pap/FotoActivity.java b/app/src/main/java/com/example/pap/FotoActivity.java index a35cea4..a09a32c 100644 --- a/app/src/main/java/com/example/pap/FotoActivity.java +++ b/app/src/main/java/com/example/pap/FotoActivity.java @@ -158,28 +158,31 @@ public class FotoActivity extends AppCompatActivity { }); } - // Função que "lê" a resposta da IA e guarda os números + // Função que "lê" a resposta da IA e guarda os números E A DICA private void extrairEGuardarDados(String texto) { try { - // Apanhar o Nome do prato (tudo o que está a seguir a "Prato: " até à próxima linha) int indexNomeStart = texto.indexOf("Prato: ") + 7; int indexNomeEnd = texto.indexOf("\n", indexNomeStart); String nomePrato = texto.substring(indexNomeStart, indexNomeEnd).trim(); - // Apanhar os números int calorias = extrairNumero(texto, "Calorias: ", " kcal"); int proteina = extrairNumero(texto, "Macros: ", "g Proteína"); int hidratos = extrairNumero(texto, "Proteína, ", "g Hidratos"); int gordura = extrairNumero(texto, "Hidratos, ", "g Gordura"); - // Abrir a memória + // EXTRAIR A DICA DA IA + String dicaIA = "Continua a registar refeições para ver dicas."; + if (texto.contains("Dica: ")) { + int indexDica = texto.indexOf("Dica: ") + 6; + dicaIA = texto.substring(indexDica).trim(); + } + SharedPreferences prefs = getSharedPreferences("DadosSaude", MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit(); - // Guardar nome do último prato editor.putString("ultimo_prato", nomePrato); + editor.putString("ultima_dica_ia", dicaIA); // Guarda a dica - // Somar aos valores do dia editor.putInt("cal_hoje", prefs.getInt("cal_hoje", 0) + calorias); editor.putInt("prot_hoje", prefs.getInt("prot_hoje", 0) + proteina); editor.putInt("hidr_hoje", prefs.getInt("hidr_hoje", 0) + hidratos); @@ -191,17 +194,15 @@ public class FotoActivity extends AppCompatActivity { } } - // Ferramenta que corta a fatia certa de texto para tirar os números private int extrairNumero(String texto, String inicio, String fim) { try { int start = texto.indexOf(inicio) + inicio.length(); int end = texto.indexOf(fim, start); String valorString = texto.substring(start, end).trim(); - // Limpa tudo o que não for número (caso a IA escreva mal) valorString = valorString.replaceAll("[^0-9]", ""); return Integer.parseInt(valorString); } catch (Exception e) { - return 0; // Se não encontrar, assume 0 + return 0; } } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_definicoes.xml b/app/src/main/res/layout/activity_definicoes.xml index 5c9e5fa..71f4f3f 100644 --- a/app/src/main/res/layout/activity_definicoes.xml +++ b/app/src/main/res/layout/activity_definicoes.xml @@ -4,62 +4,65 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:background="#F8FAFC"> + android:background="?android:attr/colorBackground" + android:padding="24dp"> - + android:layout_marginBottom="24dp"> + - + android:textColor="?android:attr/textColorPrimary" + android:layout_centerInParent="true" /> + + android:scrollbars="none"> - - + android:layout_marginBottom="24dp" + app:cardCornerRadius="16dp" + app:cardElevation="0dp" + app:cardBackgroundColor="#F2F2F7"> - + @@ -68,58 +71,65 @@ + android:layout_marginBottom="12dp"/> -