diff --git a/app/src/main/java/com/example/pap/DesafiosActivity.java b/app/src/main/java/com/example/pap/DesafiosActivity.java index 21df418..996d4ff 100644 --- a/app/src/main/java/com/example/pap/DesafiosActivity.java +++ b/app/src/main/java/com/example/pap/DesafiosActivity.java @@ -2,23 +2,24 @@ package com.example.pap; import android.content.Intent; import android.content.SharedPreferences; -import android.graphics.Bitmap; -import android.media.MediaMetadataRetriever; +import android.graphics.Color; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.util.Base64; import android.widget.Button; -import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; - import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.appcompat.app.AppCompatActivity; 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; @@ -26,195 +27,215 @@ import retrofit2.Response; public class DesafiosActivity extends AppCompatActivity { - private ProgressBar progressAgua; - private TextView tvStatusAgua; - private Button btnGravarAgua, btnGravarEx1, btnGravarEx2; - private int coposBebidos = 0; - private final int META_COPOS = 8; + private TextView tvStatusGeralIA; + private TextView tvStatusAgua, tvStatusD1, tvStatusD2, tvStatusD3, tvStatusD4; + private Button btnVideoAgua, btnVideoD1, btnVideoD2, btnVideoD3, btnVideoD4; - // Variável para sabermos qual botão o utilizador clicou - private String desafioAtual = ""; + private int desafioAtualSendoGravado = -1; // 0=Agua, 1=D1, 2=D2, 3=D3, 4=D4 + private float litrosAgua = 0.0f; - // COLA A TUA CHAVE AQUI - private final String MINHA_API_KEY = "sk-or-v1-e65c704789ff164d6ed1be48881dcfa83d9e7f359650f16cf7680dd822e5592bA"; + private final String MINHA_API_KEY = "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"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_desafios); - progressAgua = findViewById(R.id.progressAgua); + tvStatusGeralIA = findViewById(R.id.tvStatusGeralIA); tvStatusAgua = findViewById(R.id.tvStatusAgua); - btnGravarAgua = findViewById(R.id.btnGravarAgua); - btnGravarEx1 = findViewById(R.id.btnGravarEx1); - btnGravarEx2 = findViewById(R.id.btnGravarEx2); + tvStatusD1 = findViewById(R.id.tvStatusD1); + tvStatusD2 = findViewById(R.id.tvStatusD2); + tvStatusD3 = findViewById(R.id.tvStatusD3); + tvStatusD4 = findViewById(R.id.tvStatusD4); - // Carregar a água que já bebeu hoje - SharedPreferences prefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE); - coposBebidos = prefs.getInt("agua_hoje", 0); - atualizarProgressoAgua(); + 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); - // Launcher que recebe o vídeo da câmara + findViewById(R.id.btnVoltarDesafios).setOnClickListener(v -> finish()); + + verificarResetMeiaNoite(); + + // Launcher da Câmara ActivityResultLauncher videoLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == RESULT_OK && result.getData() != null) { - Uri videoUri = result.getData().getData(); - extrairFrameEEnviarIA(videoUri); - } else { - Toast.makeText(this, "Vídeo cancelado.", Toast.LENGTH_SHORT).show(); - desbloquearBotoes(); - } - }); - - // Configurar Botões (Avisamos qual é o desafio antes de abrir a câmara) - btnGravarAgua.setOnClickListener(v -> { - desafioAtual = "agua"; - bloquearBotoes(); - Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); - intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 5); // 5 Segundos chega para beber água - videoLauncher.launch(intent); - }); - - btnGravarEx1.setOnClickListener(v -> { - desafioAtual = "agachamento"; - bloquearBotoes(); - Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); - intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10); - videoLauncher.launch(intent); - }); - - btnGravarEx2.setOnClickListener(v -> { - desafioAtual = "flexoes"; - bloquearBotoes(); - Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); - intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10); - videoLauncher.launch(intent); - }); - - findViewById(R.id.btnVoltarDesafios).setOnClickListener(v -> finish()); - } - - private void extrairFrameEEnviarIA(Uri videoUri) { - Toast.makeText(this, "A extrair frame do vídeo...", Toast.LENGTH_SHORT).show(); - - try { - // Isto vai ao vídeo e tira uma "foto" a meio do tempo - MediaMetadataRetriever retriever = new MediaMetadataRetriever(); - retriever.setDataSource(this, videoUri); - - // Pega num frame do segundo 2 (2000000 microsegundos) - Bitmap frame = retriever.getFrameAtTime(2000000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC); - - if (frame != null) { - enviarParaIA(frame); - } else { - Toast.makeText(this, "Erro ao ler vídeo.", Toast.LENGTH_SHORT).show(); - desbloquearBotoes(); - } - } catch (Exception e) { - Toast.makeText(this, "Erro técnico no vídeo.", Toast.LENGTH_SHORT).show(); - desbloquearBotoes(); - } - } - - private void enviarParaIA(Bitmap bitmap) { - Toast.makeText(this, "IA a avaliar o teu desafio... ⏳", Toast.LENGTH_LONG).show(); - - ByteArrayOutputStream os = new ByteArrayOutputStream(); - bitmap.compress(Bitmap.CompressFormat.JPEG, 50, os); - String base64 = Base64.encodeToString(os.toByteArray(), Base64.NO_WRAP); - String dataUrl = "data:image/jpeg;base64," + base64; - - // O SEGREDO ESTÁ AQUI: Perguntas diferentes para desafios diferentes - String ordem = ""; - int pontosGanhos = 0; - - if (desafioAtual.equals("agua")) { - ordem = "Verifica se há uma pessoa a beber água ou com um copo/garrafa na mão. Responde APENAS 'SIM' se houver, ou 'NAO' se não houver. Não digas mais nada."; - pontosGanhos = 10; - } else if (desafioAtual.equals("agachamento")) { - ordem = "Verifica se há uma pessoa a fazer desporto ou na posição de agachamento. Responde APENAS 'SIM' ou 'NAO'."; - pontosGanhos = 50; - } else if (desafioAtual.equals("flexoes")) { - ordem = "Verifica se há uma pessoa no chão a fazer flexões ou desporto. Responde APENAS 'SIM' ou 'NAO'."; - pontosGanhos = 60; - } - - AiRequest request = new AiRequest(Collections.singletonList( - new Message("user", java.util.Arrays.asList( - new ContentPart("text", ordem), - new ContentPart("image_url", new ImageUrl(dataUrl)) - )) - )); - - // Guarda as variáveis para usar dentro da resposta - final int pontosDar = pontosGanhos; - - AiConfig.getRetrofit().create(AiApi.class) - .analisarImagem("Bearer " + MINHA_API_KEY, request) - .enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - desbloquearBotoes(); - if (response.isSuccessful() && response.body() != null) { - String respostaIA = response.body().choices.get(0).message.content.trim().toUpperCase(); - - if (respostaIA.contains("SIM")) { - sucessoDesafio(pontosDar); - } else { - Toast.makeText(DesafiosActivity.this, "A IA diz que NÃO estás a fazer o desafio! ❌", Toast.LENGTH_LONG).show(); - } - } else { - Toast.makeText(DesafiosActivity.this, "Erro no servidor da IA.", Toast.LENGTH_SHORT).show(); + Uri uriVideo = result.getData().getData(); + if (uriVideo != null) { + enviarVideoParaIA(uriVideo); } } - - @Override - public void onFailure(Call call, Throwable t) { - desbloquearBotoes(); - Toast.makeText(DesafiosActivity.this, "Falha na Internet.", Toast.LENGTH_SHORT).show(); - } }); + + // Configurar Botões + btnVideoAgua.setOnClickListener(v -> { desafioAtualSendoGravado = 0; abrirCamera(videoLauncher); }); + btnVideoD1.setOnClickListener(v -> { desafioAtualSendoGravado = 1; abrirCamera(videoLauncher); }); + btnVideoD2.setOnClickListener(v -> { desafioAtualSendoGravado = 2; abrirCamera(videoLauncher); }); + btnVideoD3.setOnClickListener(v -> { desafioAtualSendoGravado = 3; abrirCamera(videoLauncher); }); + btnVideoD4.setOnClickListener(v -> { desafioAtualSendoGravado = 4; abrirCamera(videoLauncher); }); } - private void sucessoDesafio(int pontos) { - Toast.makeText(this, "✅ IA Aprovou! Ganhaste " + pontos + " pontos!", Toast.LENGTH_LONG).show(); + private void abrirCamera(ActivityResultLauncher launcher) { + Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); + intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10); + intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0); + launcher.launch(intent); + } + 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)) { + // Limpar tudo + 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); + // Zera a água para as estatísticas + editor.putInt("agua_hoje", 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: %.1f / 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")); // Verde + } else { + tv.setText("Estado: Pendente"); + tv.setTextColor(Color.parseColor("#EF4444")); // Vermelho + } + } + + private void enviarVideoParaIA(Uri uri) { + tvStatusGeralIA.setText("A processar vídeo e enviar para a IA... ⏳"); + bloquearBotoes(false); + + new Thread(() -> { + String base64Video = converterVideo(uri); + if (base64Video == null) { + runOnUiThread(() -> { tvStatusGeralIA.setText("Erro ao ler vídeo."); bloquearBotoes(true); }); + return; + } + + String instrucao = ""; + 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"; + } + + 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() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful() && response.body() != null) { + String respostaIA = response.body().choices.get(0).message.content; + processarResposta(respostaIA); + } else { + runOnUiThread(() -> { tvStatusGeralIA.setText("Erro na IA: " + response.code()); bloquearBotoes(true); }); + } + } + @Override + public void onFailure(Call call, Throwable t) { + runOnUiThread(() -> { tvStatusGeralIA.setText("Erro de rede."); bloquearBotoes(true); }); + } + }); + }).start(); + } + + private void processarResposta(String texto) { SharedPreferences prefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit(); - // Dá os pontos e sobe o contador de desafios - int pontosAtuais = prefs.getInt("pontos", 0); - int desafiosAtuais = prefs.getInt("desafios", 0); - editor.putInt("pontos", pontosAtuais + pontos); - editor.putInt("desafios", desafiosAtuais + 1); + // Dar pontos no perfil + SharedPreferences perfilPrefs = getSharedPreferences("MeusDadosApp", MODE_PRIVATE); + SharedPreferences.Editor perfilEditor = perfilPrefs.edit(); - // Se foi o desafio da água, sobe a barra de progresso - if (desafioAtual.equals("agua")) { - coposBebidos++; - if (coposBebidos > META_COPOS) coposBebidos = META_COPOS; - editor.putInt("agua_hoje", coposBebidos); - atualizarProgressoAgua(); - } + runOnUiThread(() -> { + 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.apply(); // Guarda tudo! + editor.putFloat("agua_litros", litrosAgua); + editor.putInt("agua_hoje", (int) (litrosAgua / 0.25f)); // Atualiza Estatísticas + + tvStatusGeralIA.setText("IA leu: +" + lido + " Litros!"); + } catch (Exception e) { + tvStatusGeralIA.setText("Erro a ler os litros. Tenta de novo."); + } + } + } 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); + + perfilEditor.putInt("pontos", perfilPrefs.getInt("pontos", 0) + 50); + perfilEditor.putInt("desafios_concluidos", perfilPrefs.getInt("desafios_concluidos", 0) + 1); + perfilEditor.apply(); + } else { + tvStatusGeralIA.setText("IA: Desafio Falhou ou vídeo pouco claro. ❌"); + } + } + editor.apply(); + carregarEstadosNaTela(); + bloquearBotoes(true); + }); } - private void atualizarProgressoAgua() { - progressAgua.setProgress(coposBebidos); - tvStatusAgua.setText(coposBebidos + " de " + META_COPOS + " copos (" + (coposBebidos * 250) + "ml / 2L)"); + private void bloquearBotoes(boolean estado) { + btnVideoAgua.setEnabled(estado); + btnVideoD1.setEnabled(estado); + btnVideoD2.setEnabled(estado); + btnVideoD3.setEnabled(estado); + btnVideoD4.setEnabled(estado); } - private void bloquearBotoes() { - btnGravarAgua.setEnabled(false); - btnGravarEx1.setEnabled(false); - btnGravarEx2.setEnabled(false); - } - - private void desbloquearBotoes() { - btnGravarAgua.setEnabled(true); - btnGravarEx1.setEnabled(true); - btnGravarEx2.setEnabled(true); + 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; } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/pap/RegisterActivity.java b/app/src/main/java/com/example/pap/RegisterActivity.java index 4074d00..35c175b 100644 --- a/app/src/main/java/com/example/pap/RegisterActivity.java +++ b/app/src/main/java/com/example/pap/RegisterActivity.java @@ -5,7 +5,6 @@ import android.content.SharedPreferences; import android.os.Bundle; import android.widget.Button; import android.widget.EditText; -import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.TextView; import android.widget.Toast; @@ -27,7 +26,6 @@ public class RegisterActivity extends AppCompatActivity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_register); - // Ligar o código aos IDs do ecrã etRegNome = findViewById(R.id.etRegNome); etRegEmail = findViewById(R.id.etRegEmail); etRegPassword = findViewById(R.id.etRegPassword); @@ -38,10 +36,8 @@ public class RegisterActivity extends AppCompatActivity { btnRegister = findViewById(R.id.btnRegister); tvGoToLogin = findViewById(R.id.tvGoToLogin); - // Se o utilizador já tem conta, volta para o Login tvGoToLogin.setOnClickListener(v -> finish()); - // Quando clica no botão de Registar btnRegister.setOnClickListener(v -> { String nome = etRegNome.getText().toString().trim(); String email = etRegEmail.getText().toString().trim(); @@ -50,65 +46,54 @@ public class RegisterActivity extends AppCompatActivity { String alturaStr = etRegAltura.getText().toString().trim(); String pesoStr = etRegPeso.getText().toString().trim(); - // 1. Verificar se não há campos vazios if (nome.isEmpty() || email.isEmpty() || password.isEmpty() || idadeStr.isEmpty() || alturaStr.isEmpty() || pesoStr.isEmpty()) { Toast.makeText(this, "Por favor, preenche todos os campos!", Toast.LENGTH_SHORT).show(); return; } - // 1.1 Verificar se o utilizador escolheu o sexo int selectedSexoId = radioGroupSexo.getCheckedRadioButtonId(); if (selectedSexoId == -1) { Toast.makeText(this, "Por favor, escolhe o teu sexo!", Toast.LENGTH_SHORT).show(); return; } - String sexoSelecionado = ""; - if (selectedSexoId == R.id.radioMasculino) { - sexoSelecionado = "Masculino"; - } else if (selectedSexoId == R.id.radioFeminino) { - sexoSelecionado = "Feminino"; - } + String sexoSelecionado = (selectedSexoId == R.id.radioMasculino) ? "Masculino" : "Feminino"; + int idade = Integer.parseInt(idadeStr); + float altura = Float.parseFloat(alturaStr); + float peso = Float.parseFloat(pesoStr); - // 2. GUARDAR TODOS OS DADOS NA MEMÓRIA (SharedPreferences) + // Grava no telemóvel para acesso rápido SharedPreferences prefs = getSharedPreferences("MeusDadosApp", MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit(); editor.putString("nome", nome); editor.putString("email", email); editor.putString("sexo", sexoSelecionado); - editor.putInt("idade", Integer.parseInt(idadeStr)); - editor.putFloat("altura", Float.parseFloat(alturaStr)); - editor.putFloat("peso", Float.parseFloat(pesoStr)); + editor.putInt("idade", idade); + editor.putFloat("altura", altura); + editor.putFloat("peso", peso); editor.apply(); - // 3. Preparar os dados para enviar para o Supabase - UserCredentials credentials = new UserCredentials(email, password); - - // Vai buscar o Retrofit ao ficheiro SupabaseConfig + // Empacota tudo para enviar para o Supabase + UserCredentials credentials = new UserCredentials(email, password, nome, idade, altura, peso, sexoSelecionado); SupabaseApi api = SupabaseConfig.getRetrofit().create(SupabaseApi.class); - // 4. Fazer o Registo na Internet usando a chave configurada api.signUp(SupabaseConfig.SUPABASE_KEY, credentials).enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { if (response.isSuccessful()) { - Toast.makeText(RegisterActivity.this, "Conta criada! Verifica o teu email.", Toast.LENGTH_LONG).show(); - - // Mandar para o ecrã de espera + Toast.makeText(RegisterActivity.this, "Conta criada no Supabase! Verifica o teu email.", Toast.LENGTH_LONG).show(); Intent intent = new Intent(RegisterActivity.this, VerificacaoActivity.class); intent.putExtra("email_registo", email); intent.putExtra("password_registo", password); startActivity(intent); finish(); - } else { - Toast.makeText(RegisterActivity.this, "Erro ao criar conta. O email já existe?", Toast.LENGTH_LONG).show(); + Toast.makeText(RegisterActivity.this, "Erro ao criar conta online.", Toast.LENGTH_LONG).show(); } } - @Override public void onFailure(Call call, Throwable t) { - Toast.makeText(RegisterActivity.this, "Falha na ligação! Verifica a tua internet.", Toast.LENGTH_LONG).show(); + Toast.makeText(RegisterActivity.this, "Falha na ligação à internet.", Toast.LENGTH_LONG).show(); } }); }); diff --git a/app/src/main/java/com/example/pap/SupabaseApi.java b/app/src/main/java/com/example/pap/SupabaseApi.java index 2604e8c..7859351 100644 --- a/app/src/main/java/com/example/pap/SupabaseApi.java +++ b/app/src/main/java/com/example/pap/SupabaseApi.java @@ -5,6 +5,8 @@ import retrofit2.http.Body; import retrofit2.http.Header; import retrofit2.http.PUT; import retrofit2.http.POST; +import java.util.HashMap; +import java.util.Map; public interface SupabaseApi { @@ -16,7 +18,7 @@ public interface SupabaseApi { @POST("auth/v1/token?grant_type=password") Call login(@Header("apikey") String apiKey, @Body UserCredentials credentials); - // 3. Rota para atualizar a palavra-passe ou dados do utilizador (CORRIGIDO PARA @PUT) + // 3. Rota para atualizar a palavra-passe ou dados do utilizador @PUT("auth/v1/user") Call updateUserData( @Header("apikey") String apikey, @@ -30,11 +32,27 @@ public interface SupabaseApi { class UserCredentials { String email; String password; + Map data; // O Supabase exige que os dados extras fiquem aqui dentro! + // Construtor 1: Usado para o LOGIN (só precisa de email e password) public UserCredentials(String email, String password) { this.email = email; 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) { + this.email = email; + this.password = password; + + // Empacotar os dados exatamente como o Supabase pede + this.data = new HashMap<>(); + this.data.put("nome", nome); + this.data.put("idade", idade); + this.data.put("altura", altura); + this.data.put("peso", peso); + this.data.put("sexo", sexo); + } } class SupabaseResponse { diff --git a/app/src/main/res/layout/activity_desafios.xml b/app/src/main/res/layout/activity_desafios.xml index 0ec461a..c9a3478 100644 --- a/app/src/main/res/layout/activity_desafios.xml +++ b/app/src/main/res/layout/activity_desafios.xml @@ -5,12 +5,12 @@ android:layout_height="match_parent" android:orientation="vertical" android:background="#FFFFFF" - android:padding="24dp"> + android:padding="20dp"> + android:layout_marginBottom="16dp"> + android:padding="8dp"/> + + - - - - - - - - - - - - - - -