corrigir os novos erros amnhã e adicionar qual tipo de sexo a pessoa é no register

This commit is contained in:
2026-07-01 10:57:36 +01:00
parent 89dc24cc13
commit 3af183fcf7
3 changed files with 64 additions and 49 deletions

View File

@@ -43,8 +43,9 @@ public class DesafiosActivity extends AppCompatActivity {
private float litrosAgua = 0.0f; private float litrosAgua = 0.0f;
private ActivityResultLauncher<Intent> videoLauncher; private ActivityResultLauncher<Intent> videoLauncher;
private AlertDialog popupCarregamento; // A janela de loading private AlertDialog popupCarregamento;
// COLOCA AQUI A TUA CHAVE DO OPENROUTER:
private final String MINHA_API_KEY = "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"; private final String MINHA_API_KEY = "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";
@Override @Override
@@ -53,7 +54,6 @@ public class DesafiosActivity extends AppCompatActivity {
setContentView(R.layout.activity_desafios); setContentView(R.layout.activity_desafios);
tvStatusGeralIA = findViewById(R.id.tvStatusGeralIA); tvStatusGeralIA = findViewById(R.id.tvStatusGeralIA);
// Esconde o texto antigo do topo, já não precisamos dele!
tvStatusGeralIA.setVisibility(View.GONE); tvStatusGeralIA.setVisibility(View.GONE);
tvStatusAgua = findViewById(R.id.tvStatusAgua); tvStatusAgua = findViewById(R.id.tvStatusAgua);
@@ -146,7 +146,7 @@ public class DesafiosActivity extends AppCompatActivity {
SharedPreferences prefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE); SharedPreferences prefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE);
litrosAgua = prefs.getFloat("agua_litros", 0.0f); litrosAgua = prefs.getFloat("agua_litros", 0.0f);
tvStatusAgua.setText(String.format(Locale.getDefault(), "Progresso: %.1f / 2.0 L", litrosAgua)); tvStatusAgua.setText(String.format(Locale.getDefault(), "Progresso: %.2f / 2.0 L", litrosAgua));
atualizarTextoDesafio(tvStatusD1, prefs.getBoolean("d1_concluido", false)); atualizarTextoDesafio(tvStatusD1, prefs.getBoolean("d1_concluido", false));
atualizarTextoDesafio(tvStatusD2, prefs.getBoolean("d2_concluido", false)); atualizarTextoDesafio(tvStatusD2, prefs.getBoolean("d2_concluido", false));
@@ -164,15 +164,12 @@ public class DesafiosActivity extends AppCompatActivity {
} }
} }
// ==========================================
// NOVOS POP-UPS DE LOADING E RESULTADOS
// ==========================================
private void mostrarLoading() { private void mostrarLoading() {
runOnUiThread(() -> { runOnUiThread(() -> {
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("A analisar o vídeo... ⏳"); builder.setTitle("A analisar o vídeo... ⏳");
builder.setMessage("A Inteligência Artificial está a avaliar o teu desempenho. Por favor, aguarda um momento."); builder.setMessage("A Inteligência Artificial está a avaliar o teu desempenho. Por favor, aguarda um momento.");
builder.setCancelable(false); // Impede que o utilizador feche sem querer builder.setCancelable(false);
popupCarregamento = builder.create(); popupCarregamento = builder.create();
popupCarregamento.show(); popupCarregamento.show();
@@ -181,12 +178,10 @@ public class DesafiosActivity extends AppCompatActivity {
private void mostrarResultadoFinal(String titulo, String mensagem) { private void mostrarResultadoFinal(String titulo, String mensagem) {
runOnUiThread(() -> { runOnUiThread(() -> {
// Fecha a janela de "A aguardar..."
if (popupCarregamento != null && popupCarregamento.isShowing()) { if (popupCarregamento != null && popupCarregamento.isShowing()) {
popupCarregamento.dismiss(); popupCarregamento.dismiss();
} }
// Abre a janela com o resultado final
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(titulo); builder.setTitle(titulo);
builder.setMessage(mensagem); builder.setMessage(mensagem);
@@ -197,9 +192,23 @@ public class DesafiosActivity extends AppCompatActivity {
private void enviarVideoParaIA(Uri uri) { private void enviarVideoParaIA(Uri uri) {
bloquearBotoes(false); bloquearBotoes(false);
mostrarLoading(); // Mostra a janela de loading logo aqui! mostrarLoading();
new Thread(() -> { new Thread(() -> {
// 🔥 TRUQUE DE MESTRE: Se for o desafio da água (0), não enviamos para a IA!
// Fingimos que processa e damos sempre 250ml diretos.
if (desafioAtualSendoGravado == 0) {
try {
Thread.sleep(1500); // Finge que está a processar durante 1.5s
} catch (InterruptedException e) {}
// Vai direto para o processamento com código de sucesso!
processarResposta("SUCESSO_AGUA");
return;
}
// Daqui para baixo é SÓ para os vídeos de exercício físico (D1, D2, D3, D4)
String base64Video = converterVideo(uri); String base64Video = converterVideo(uri);
if (base64Video == null) { if (base64Video == null) {
mostrarResultadoFinal("Erro no Vídeo ⚠️", "Não foi possível ler o vídeo gravado."); mostrarResultadoFinal("Erro no Vídeo ⚠️", "Não foi possível ler o vídeo gravado.");
@@ -207,13 +216,9 @@ public class DesafiosActivity extends AppCompatActivity {
return; return;
} }
String instrucao = ""; String instrucao = "Analisa o exercício físico do vídeo. Verifica se a pessoa fez o movimento corretamente. Devolve apenas o formato: Status: Concluido ou Status: Falhou";
if (desafioAtualSendoGravado == 0) {
instrucao = "Analisa a pessoa a beber água. Devolve apenas os litros consumidos. Formato exato: Litros: [valor_decimal]";
} else {
instrucao = "Analisa o exercício físico do vídeo. Verifica se a pessoa fez o movimento corretamente. Devolve apenas o formato: Status: Concluido ou Status: Falhou";
}
// OpenRouter utiliza a tag "video_url"
AiRequest request = new AiRequest(Collections.singletonList( AiRequest request = new AiRequest(Collections.singletonList(
new Message("user", java.util.Arrays.asList( new Message("user", java.util.Arrays.asList(
new ContentPart("text", instrucao), new ContentPart("text", instrucao),
@@ -251,25 +256,23 @@ public class DesafiosActivity extends AppCompatActivity {
SharedPreferences.Editor perfilEditor = perfilPrefs.edit(); SharedPreferences.Editor perfilEditor = perfilPrefs.edit();
runOnUiThread(() -> { runOnUiThread(() -> {
// LÓGICA DA ÁGUA FIXA (250ml / 0.25L)
if (desafioAtualSendoGravado == 0) { if (desafioAtualSendoGravado == 0) {
if (texto.contains("Litros:")) {
try {
String valorStr = texto.substring(texto.indexOf("Litros:") + 7).trim().replaceAll("[^0-9.]", "");
float lido = Float.parseFloat(valorStr);
litrosAgua += lido;
editor.putFloat("agua_litros", litrosAgua); float copo = 0.25f; // 250 ml = 0.25 Litros
editor.putInt("agua_hoje", (int) (litrosAgua / 0.25f)); litrosAgua += copo; // Soma à água total
editor.putFloat("agua_litros", litrosAgua);
// "agua_hoje" conta o número de copos (que reflete nas Estatísticas)
int coposAtuais = prefs.getInt("agua_hoje", 0);
editor.putInt("agua_hoje", coposAtuais + 1);
mostrarResultadoFinal("Bom trabalho! 💧", "Registaste +250ml de água! Mantém-te hidratado!");
// Mostra o resultado da Água!
mostrarResultadoFinal("Bom trabalho! 💧", "A IA detetou que bebeste +" + lido + " Litros!");
} catch (Exception e) {
mostrarResultadoFinal("Oops! 🤔", "A IA teve dificuldade em ler a quantidade exata. Tenta gravar de novo.");
}
} else {
mostrarResultadoFinal("Oops! 🤔", "A IA não percebeu o vídeo. Garante que o copo ou garrafa se vê bem!");
}
} else { } else {
// LÓGICA DOS EXERCÍCIOS
if (texto.contains("Status: Concluido")) { if (texto.contains("Status: Concluido")) {
int caloriasAQueimar = 0; int caloriasAQueimar = 0;
@@ -285,14 +288,13 @@ public class DesafiosActivity extends AppCompatActivity {
perfilEditor.putInt("desafios_concluidos", perfilPrefs.getInt("desafios_concluidos", 0) + 1); perfilEditor.putInt("desafios_concluidos", perfilPrefs.getInt("desafios_concluidos", 0) + 1);
perfilEditor.apply(); perfilEditor.apply();
// Mostra o resultado do Exercício!
mostrarResultadoFinal("Desafio Validado! ✅", "Ganhaste +50 Pontos e queimaste " + caloriasAQueimar + " kcal. Continua assim!"); mostrarResultadoFinal("Desafio Validado! ✅", "Ganhaste +50 Pontos e queimaste " + caloriasAQueimar + " kcal. Continua assim!");
} else { } else {
mostrarResultadoFinal("Desafio Falhou ❌", "A IA acha que o movimento não foi claro ou bem feito. Tenta outra vez!"); mostrarResultadoFinal("Desafio Falhou ❌", "A IA acha que o movimento não foi claro ou bem feito. Tenta outra vez!");
} }
} }
editor.apply(); editor.apply();
carregarEstadosNaTela(); carregarEstadosNaTela(); // Atualiza logo os números da água na tela dos Desafios
bloquearBotoes(true); bloquearBotoes(true);
}); });
} }

View File

@@ -26,22 +26,18 @@ public class LoginActivity extends AppCompatActivity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login); setContentView(R.layout.activity_login);
// Ligar o código aos IDs do ecrã
etLoginEmail = findViewById(R.id.etLoginEmail); etLoginEmail = findViewById(R.id.etLoginEmail);
etLoginPassword = findViewById(R.id.etLoginPassword); etLoginPassword = findViewById(R.id.etLoginPassword);
btnLogin = findViewById(R.id.btnLogin); btnLogin = findViewById(R.id.btnLogin);
tvGoToRegister = findViewById(R.id.tvGoToRegister); tvGoToRegister = findViewById(R.id.tvGoToRegister);
// Iniciar a memória do telemóvel
sharedPreferences = getSharedPreferences("MeusDadosApp", MODE_PRIVATE); sharedPreferences = getSharedPreferences("MeusDadosApp", MODE_PRIVATE);
// Enviar para o Registo
tvGoToRegister.setOnClickListener(v -> { tvGoToRegister.setOnClickListener(v -> {
Intent intent = new Intent(LoginActivity.this, RegisterActivity.class); Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
startActivity(intent); startActivity(intent);
}); });
// Botão de Entrar
btnLogin.setOnClickListener(v -> { btnLogin.setOnClickListener(v -> {
String email = etLoginEmail.getText().toString().trim(); String email = etLoginEmail.getText().toString().trim();
String password = etLoginPassword.getText().toString().trim(); String password = etLoginPassword.getText().toString().trim();
@@ -59,12 +55,22 @@ public class LoginActivity extends AppCompatActivity {
public void onResponse(Call<SupabaseResponse> call, Response<SupabaseResponse> response) { public void onResponse(Call<SupabaseResponse> call, Response<SupabaseResponse> response) {
if (response.isSuccessful() && response.body() != null) { if (response.isSuccessful() && response.body() != null) {
// Guardar o token e o email para usar nas Definições
String token = response.body().access_token;
SharedPreferences.Editor editor = sharedPreferences.edit(); SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("access_token", token); editor.putString("access_token", response.body().access_token);
editor.putString("email", email); editor.putString("email", email);
editor.apply();
// NOVO: Puxar os teus dados de saúde do Supabase e guardar na memória!
if (response.body().user != null && response.body().user.user_metadata != null) {
UserMetadata meta = response.body().user.user_metadata;
if (meta.nome != null) editor.putString("nome", meta.nome);
editor.putInt("idade", meta.idade);
editor.putFloat("altura", meta.altura);
editor.putFloat("peso", meta.peso);
if (meta.sexo != null) editor.putString("sexo", meta.sexo);
}
editor.apply(); // Tranca a gaveta com todos os dados lá dentro
Toast.makeText(LoginActivity.this, "Entraste com sucesso! 🚀", Toast.LENGTH_SHORT).show(); Toast.makeText(LoginActivity.this, "Entraste com sucesso! 🚀", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(LoginActivity.this, HomeActivity.class); Intent intent = new Intent(LoginActivity.this, HomeActivity.class);

View File

@@ -10,15 +10,12 @@ import java.util.Map;
public interface SupabaseApi { public interface SupabaseApi {
// 1. Rota para criar a conta
@POST("auth/v1/signup") @POST("auth/v1/signup")
Call<SupabaseResponse> signUp(@Header("apikey") String apiKey, @Body UserCredentials credentials); Call<SupabaseResponse> signUp(@Header("apikey") String apiKey, @Body UserCredentials credentials);
// 2. Rota para fazer login
@POST("auth/v1/token?grant_type=password") @POST("auth/v1/token?grant_type=password")
Call<SupabaseResponse> login(@Header("apikey") String apiKey, @Body UserCredentials credentials); Call<SupabaseResponse> login(@Header("apikey") String apiKey, @Body UserCredentials credentials);
// 3. Rota para atualizar a palavra-passe ou dados do utilizador
@PUT("auth/v1/user") @PUT("auth/v1/user")
Call<Void> updateUserData( Call<Void> updateUserData(
@Header("apikey") String apikey, @Header("apikey") String apikey,
@@ -32,20 +29,16 @@ public interface SupabaseApi {
class UserCredentials { class UserCredentials {
String email; String email;
String password; String password;
Map<String, Object> data; // O Supabase exige que os dados extras fiquem aqui dentro! Map<String, Object> data;
// Construtor 1: Usado para o LOGIN (só precisa de email e password)
public UserCredentials(String email, String password) { public UserCredentials(String email, String password) {
this.email = email; this.email = email;
this.password = password; this.password = password;
} }
// Construtor 2: Usado para o REGISTO (arruma os dados de saúde na pasta "data")
public UserCredentials(String email, String password, String nome, int idade, float altura, float peso, String sexo) { public UserCredentials(String email, String password, String nome, int idade, float altura, float peso, String sexo) {
this.email = email; this.email = email;
this.password = password; this.password = password;
// Empacotar os dados exatamente como o Supabase pede
this.data = new HashMap<>(); this.data = new HashMap<>();
this.data.put("nome", nome); this.data.put("nome", nome);
this.data.put("idade", idade); this.data.put("idade", idade);
@@ -55,6 +48,20 @@ class UserCredentials {
} }
} }
// O SEGREDO ESTÁ AQUI: Ensinar a app a ler os dados de saúde do Supabase!
class SupabaseResponse { class SupabaseResponse {
public String access_token; public String access_token;
public SupabaseUser user; // Puxa o objeto do utilizador
}
class SupabaseUser {
public UserMetadata user_metadata; // Puxa os dados que guardaste no registo
}
class UserMetadata {
public String nome;
public int idade;
public float altura;
public float peso;
public String sexo;
} }