Files
PAP/app/src/main/java/com/example/pap/DesafiosActivity.java

320 lines
14 KiB
Java

package com.example.pap;
import android.Manifest;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Base64;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.Locale;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class DesafiosActivity extends AppCompatActivity {
private TextView tvStatusGeralIA;
private TextView tvStatusAgua, tvStatusD1, tvStatusD2, tvStatusD3, tvStatusD4;
private Button btnVideoAgua, btnVideoD1, btnVideoD2, btnVideoD3, btnVideoD4;
private int desafioAtualSendoGravado = -1; // 0=Agua, 1=D1, 2=D2, 3=D3, 4=D4
private float litrosAgua = 0.0f;
private ActivityResultLauncher<Intent> videoLauncher;
private AlertDialog popupCarregamento;
// COLOCA AQUI A TUA CHAVE DO OPENROUTER:
private final String MINHA_API_KEY = "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";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_desafios);
tvStatusGeralIA = findViewById(R.id.tvStatusGeralIA);
tvStatusGeralIA.setVisibility(View.GONE);
tvStatusAgua = findViewById(R.id.tvStatusAgua);
tvStatusD1 = findViewById(R.id.tvStatusD1);
tvStatusD2 = findViewById(R.id.tvStatusD2);
tvStatusD3 = findViewById(R.id.tvStatusD3);
tvStatusD4 = findViewById(R.id.tvStatusD4);
btnVideoAgua = findViewById(R.id.btnVideoAgua);
btnVideoD1 = findViewById(R.id.btnVideoD1);
btnVideoD2 = findViewById(R.id.btnVideoD2);
btnVideoD3 = findViewById(R.id.btnVideoD3);
btnVideoD4 = findViewById(R.id.btnVideoD4);
findViewById(R.id.btnVoltarDesafios).setOnClickListener(v -> finish());
verificarResetMeiaNoite();
videoLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK && result.getData() != null) {
Uri uriVideo = result.getData().getData();
if (uriVideo != null) {
enviarVideoParaIA(uriVideo);
}
}
});
btnVideoAgua.setOnClickListener(v -> { desafioAtualSendoGravado = 0; verificarPermissaoEAbrir(); });
btnVideoD1.setOnClickListener(v -> { desafioAtualSendoGravado = 1; verificarPermissaoEAbrir(); });
btnVideoD2.setOnClickListener(v -> { desafioAtualSendoGravado = 2; verificarPermissaoEAbrir(); });
btnVideoD3.setOnClickListener(v -> { desafioAtualSendoGravado = 3; verificarPermissaoEAbrir(); });
btnVideoD4.setOnClickListener(v -> { desafioAtualSendoGravado = 4; verificarPermissaoEAbrir(); });
}
private void verificarPermissaoEAbrir() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 100);
} else {
abrirCameraReal();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 100) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
abrirCameraReal();
} else {
Toast.makeText(this, "Precisas de dar permissão da câmara para fazer o desafio!", Toast.LENGTH_SHORT).show();
}
}
}
private void abrirCameraReal() {
try {
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10);
videoLauncher.launch(intent);
} catch (Exception e) {
Toast.makeText(this, "Erro: Não foi possível iniciar a câmara.", Toast.LENGTH_LONG).show();
}
}
private void verificarResetMeiaNoite() {
SharedPreferences prefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE);
String dataHoje = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date());
String dataGuardada = prefs.getString("data_5_desafios", "");
if (!dataHoje.equals(dataGuardada)) {
SharedPreferences.Editor editor = prefs.edit();
editor.putString("data_5_desafios", dataHoje);
editor.putFloat("agua_litros", 0.0f);
editor.putBoolean("d1_concluido", false);
editor.putBoolean("d2_concluido", false);
editor.putBoolean("d3_concluido", false);
editor.putBoolean("d4_concluido", false);
editor.putInt("agua_hoje", 0);
editor.putInt("calorias_desafios", 0);
editor.apply();
}
carregarEstadosNaTela();
}
private void carregarEstadosNaTela() {
SharedPreferences prefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE);
litrosAgua = prefs.getFloat("agua_litros", 0.0f);
tvStatusAgua.setText(String.format(Locale.getDefault(), "Progresso: %.2f / 2.0 L", litrosAgua));
atualizarTextoDesafio(tvStatusD1, prefs.getBoolean("d1_concluido", false));
atualizarTextoDesafio(tvStatusD2, prefs.getBoolean("d2_concluido", false));
atualizarTextoDesafio(tvStatusD3, prefs.getBoolean("d3_concluido", false));
atualizarTextoDesafio(tvStatusD4, prefs.getBoolean("d4_concluido", false));
}
private void atualizarTextoDesafio(TextView tv, boolean concluido) {
if (concluido) {
tv.setText("Estado: Concluído ✅");
tv.setTextColor(Color.parseColor("#10B981"));
} else {
tv.setText("Estado: Pendente");
tv.setTextColor(Color.parseColor("#EF4444"));
}
}
private void mostrarLoading() {
runOnUiThread(() -> {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
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.setCancelable(false);
popupCarregamento = builder.create();
popupCarregamento.show();
});
}
private void mostrarResultadoFinal(String titulo, String mensagem) {
runOnUiThread(() -> {
if (popupCarregamento != null && popupCarregamento.isShowing()) {
popupCarregamento.dismiss();
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(titulo);
builder.setMessage(mensagem);
builder.setPositiveButton("OK", null);
builder.show();
});
}
private void enviarVideoParaIA(Uri uri) {
bloquearBotoes(false);
mostrarLoading();
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);
if (base64Video == null) {
mostrarResultadoFinal("Erro no Vídeo ⚠️", "Não foi possível ler o vídeo gravado.");
runOnUiThread(() -> bloquearBotoes(true));
return;
}
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";
// OpenRouter utiliza a tag "video_url"
AiRequest request = new AiRequest(Collections.singletonList(
new Message("user", java.util.Arrays.asList(
new ContentPart("text", instrucao),
new ContentPart("video_url", new ImageUrl("data:video/mp4;base64," + base64Video))
))
));
AiConfig.getRetrofit().create(AiApi.class)
.analisarImagem("Bearer " + MINHA_API_KEY, request)
.enqueue(new Callback<AiResponse>() {
@Override
public void onResponse(Call<AiResponse> call, Response<AiResponse> response) {
if (response.isSuccessful() && response.body() != null) {
String respostaIA = response.body().choices.get(0).message.content;
processarResposta(respostaIA);
} else {
mostrarResultadoFinal("Erro de Servidor ⚠️", "Erro ao contactar a IA. Código: " + response.code());
runOnUiThread(() -> bloquearBotoes(true));
}
}
@Override
public void onFailure(Call<AiResponse> call, Throwable t) {
mostrarResultadoFinal("Sem Internet 🌐", "Não conseguimos ligar à IA. Verifica a tua rede.");
runOnUiThread(() -> bloquearBotoes(true));
}
});
}).start();
}
private void processarResposta(String texto) {
SharedPreferences prefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
SharedPreferences perfilPrefs = getSharedPreferences("MeusDadosApp", MODE_PRIVATE);
SharedPreferences.Editor perfilEditor = perfilPrefs.edit();
runOnUiThread(() -> {
// LÓGICA DA ÁGUA FIXA (250ml / 0.25L)
if (desafioAtualSendoGravado == 0) {
float copo = 0.25f; // 250 ml = 0.25 Litros
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!");
} else {
// LÓGICA DOS EXERCÍCIOS
if (texto.contains("Status: Concluido")) {
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; }
int caloriasTotaisQueimadas = prefs.getInt("calorias_desafios", 0) + caloriasAQueimar;
editor.putInt("calorias_desafios", caloriasTotaisQueimadas);
perfilEditor.putInt("pontos", perfilPrefs.getInt("pontos", 0) + 50);
perfilEditor.putInt("desafios_concluidos", perfilPrefs.getInt("desafios_concluidos", 0) + 1);
perfilEditor.apply();
mostrarResultadoFinal("Desafio Validado! ✅", "Ganhaste +50 Pontos e queimaste " + caloriasAQueimar + " kcal. Continua assim!");
} else {
mostrarResultadoFinal("Desafio Falhou ❌", "A IA acha que o movimento não foi claro ou bem feito. Tenta outra vez!");
}
}
editor.apply();
carregarEstadosNaTela(); // Atualiza logo os números da água na tela dos Desafios
bloquearBotoes(true);
});
}
private void bloquearBotoes(boolean estado) {
btnVideoAgua.setEnabled(estado);
btnVideoD1.setEnabled(estado);
btnVideoD2.setEnabled(estado);
btnVideoD3.setEnabled(estado);
btnVideoD4.setEnabled(estado);
}
private String converterVideo(Uri uri) {
try {
InputStream is = getContentResolver().openInputStream(uri);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int l;
byte[] b = new byte[4096];
while ((l = is.read(b)) != -1) { buffer.write(b, 0, l); }
return Base64.encodeToString(buffer.toByteArray(), Base64.NO_WRAP);
} catch (Exception e) { return null; }
}
}