corrige o erro da camera e da ia não funcionar e mudar o layout futuramente

This commit is contained in:
2026-05-06 12:48:08 +01:00
parent a5ee481b39
commit e480abd98e
30 changed files with 1807 additions and 1039 deletions

View File

@@ -1,138 +1,168 @@
package com.example.pap;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import org.json.JSONArray;
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 ChatActivity extends AppCompatActivity {
private EditText etMensagem;
private ImageButton btnEnviar;
private LinearLayout chatLayout;
private ScrollView chatScrollView;
private EditText etNovaMensagem;
private Button btnEnviarMensagem;
private Button btnVoltarChat;
// A TUA CHAVE DA GOOGLE VEM PARA AQUI!
private static final String GEMINI_API_KEY = "AQ.Ab8RN6IfhsFBO3UOpK3vYd7BrR2nfFb-mVE--nvqRnR46hB36A";
// O motor do Gemini 1.5 Flash
private static final String GEMINI_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=" + GEMINI_API_KEY;
private OkHttpClient client;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
// 1. Associar os componentes do layout
etMensagem = findViewById(R.id.etMensagem);
btnEnviar = findViewById(R.id.btnEnviar);
chatLayout = findViewById(R.id.chatLayout);
chatScrollView = findViewById(R.id.chatScrollView);
etNovaMensagem = findViewById(R.id.etNovaMensagem);
btnEnviarMensagem = findViewById(R.id.btnEnviarMensagem);
btnVoltarChat = findViewById(R.id.btnVoltarChat);
// Mensagem inicial da IA ao abrir o ecrã
adicionarMensagemBalao("Olá! Sou o teu IA Coach de Saúde. Como te posso ajudar hoje na tua jornada de emagrecimento?", false);
client = new OkHttpClient();
// 2. Clique no botão de Enviar
btnEnviarMensagem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String mensagemUser = etNovaMensagem.getText().toString().trim();
// Dá as boas vindas
adicionarBalaoNoEcra("Olá! Sou o NutriChat AI 🤖. O que comeste hoje ou que dúvidas tens sobre a tua dieta?", false);
if (!mensagemUser.isEmpty()) {
// Adiciona a mensagem do utilizador no ecrã
adicionarMensagemBalao(mensagemUser, true);
btnEnviar.setOnClickListener(v -> {
String pergunta = etMensagem.getText().toString().trim();
if (pergunta.isEmpty()) {
Toast.makeText(this, "Escreve alguma merda primeiro!", Toast.LENGTH_SHORT).show();
return;
}
// Limpa a caixa de texto
etNovaMensagem.setText("");
// 1. Mostrar a mensagem do utilizador no ecrã
adicionarBalaoNoEcra(pergunta, true);
etMensagem.setText(""); // Limpa a caixa de texto
// Simula a IA a processar e a responder
simularRespostaDaIA(mensagemUser);
// 2. Chamar a Inteligência Artificial
chamarGemini(pergunta);
});
}
// Função que desenha os balões de conversa no ecrã
private void adicionarBalaoNoEcra(String texto, boolean isUser) {
runOnUiThread(() -> {
TextView tv = new TextView(this);
tv.setText(texto);
tv.setTextSize(16f);
tv.setPadding(30, 20, 30, 20);
tv.setTextColor(isUser ? Color.WHITE : Color.parseColor("#1E293B"));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
params.setMargins(0, 10, 0, 10);
// Se for o utilizador, o balão vai para a direita e fica azul
if (isUser) {
params.gravity = Gravity.END;
tv.setBackgroundResource(R.drawable.balao_user); // Já vamos criar isto!
} else {
// Se for a IA, o balão vai para a esquerda e fica branco/cinza
params.gravity = Gravity.START;
tv.setBackgroundResource(R.drawable.balao_ai); // Já vamos criar isto!
}
tv.setLayoutParams(params);
chatLayout.addView(tv);
// Faz scroll automático para o fundo para ver a mensagem nova
chatScrollView.post(() -> chatScrollView.fullScroll(ScrollView.FOCUS_DOWN));
});
}
// Função que vai à internet falar com o cérebro da Google
private void chamarGemini(String pergunta) {
try {
// Instrução secreta para ele agir como Nutricionista
String promptCompleto = "Aja como um nutricionista simpático e profissional. Responda de forma curta e direta à seguinte mensagem do utilizador: " + pergunta;
// Construir o JSON que o Gemini exige
JSONObject part = new JSONObject();
part.put("text", promptCompleto);
JSONArray parts = new JSONArray();
parts.put(part);
JSONObject content = new JSONObject();
content.put("parts", parts);
JSONArray contents = new JSONArray();
contents.put(content);
JSONObject jsonBody = new JSONObject();
jsonBody.put("contents", contents);
RequestBody body = RequestBody.create(jsonBody.toString(), MediaType.get("application/json; charset=utf-8"));
Request request = new Request.Builder()
.url(GEMINI_URL)
.post(body)
.build();
// Fazer a chamada fora da Thread principal para a app não encravar
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
adicionarBalaoNoEcra("Oops! Fiquei sem internet ou deu merda na ligação. 🔌", false);
}
}
});
// 3. Clique no botão de Voltar
btnVoltarChat.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
try {
String respostaJSON = response.body().string();
JSONObject jsonObject = new JSONObject(respostaJSON);
// Escarafunchar o JSON para tirar só o texto da resposta
String respostaIA = jsonObject.getJSONArray("candidates")
.getJSONObject(0)
.getJSONObject("content")
.getJSONArray("parts")
.getJSONObject(0)
.getString("text");
// Passo 3: Função para desenhar os balões de conversa no ecrã
private void adicionarMensagemBalao(String texto, boolean isUser) {
TextView textView = new TextView(this);
textView.setText(texto);
textView.setTextSize(16f);
textView.setPadding(32, 24, 32, 24);
// Mostrar a resposta no ecrã
adicionarBalaoNoEcra(respostaIA, false);
// Configurar as margens e o alinhamento (Direita = Utilizador, Esquerda = IA)
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
params.setMargins(0, 16, 0, 16);
} catch (Exception e) {
adicionarBalaoNoEcra("Deu um nó no meu cérebro ao ler os dados. 🤯", false);
}
} else {
adicionarBalaoNoEcra("Erro da Google: " + response.code(), false);
}
}
});
// Configurar o design arredondado do balão
GradientDrawable background = new GradientDrawable();
background.setCornerRadius(32f);
if (isUser) {
// Estilo do Utilizador (Fundo Verde, Texto Branco, Alinhado à direita)
params.gravity = Gravity.END;
background.setColor(Color.parseColor("#4CAF50"));
textView.setTextColor(Color.WHITE);
} else {
// Estilo da IA (Fundo Cinza/Branco, Texto Escuro, Alinhado à esquerda)
params.gravity = Gravity.START;
background.setColor(Color.parseColor("#FFFFFF"));
textView.setTextColor(Color.parseColor("#2E3D32"));
textView.setElevation(4f); // Dá uma pequena sombra ao balão da IA
} catch (Exception e) {
e.printStackTrace();
}
textView.setLayoutParams(params);
textView.setBackground(background);
// Adicionar o balão ao ecrã
chatLayout.addView(textView);
// Fazer scroll automático para baixo para ver a nova mensagem
chatScrollView.post(new Runnable() {
@Override
public void run() {
chatScrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
});
}
// Passo 4: Função para simular a inteligência da IA
private void simularRespostaDaIA(String perguntaUtilizador) {
perguntaUtilizador = perguntaUtilizador.toLowerCase();
final String resposta;
// Regras simples para fingir que a IA está a entender a pergunta
if (perguntaUtilizador.contains("água") || perguntaUtilizador.contains("agua")) {
resposta = "A hidratação é fundamental! O ideal é beberes pelo menos 2 a 3 litros de água por dia. Já bebeste algum copo hoje?";
} else if (perguntaUtilizador.contains("comer") || perguntaUtilizador.contains("fome") || perguntaUtilizador.contains("dieta")) {
resposta = "Se sentires fome entre as refeições, opta por snacks saudáveis como uma peça de fruta ou um punhado de frutos secos. Evita os doces!";
} else if (perguntaUtilizador.contains("treino") || perguntaUtilizador.contains("exercício") || perguntaUtilizador.contains("correr")) {
resposta = "Excelente! O exercício acelera o metabolismo. Lembra-te que a consistência é mais importante do que a intensidade. 30 minutos de caminhada já fazem a diferença.";
} else {
resposta = "Essa é uma ótima questão! O segredo do emagrecimento é o défice calórico aliado a bons hábitos. Continua focado, estou aqui para te apoiar em cada passo!";
}
// Simular um tempo de "pensamento" da IA (espera 1.5 segundos antes de mostrar a resposta)
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
adicionarMensagemBalao(resposta, false);
}
}, 1500);
}
}