Compare commits
6 Commits
d1e83584e3
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 89dc24cc13 | |||
| e177926b6e | |||
| 937e4e42c2 | |||
| 33a1d49b26 | |||
| 05f30539ad | |||
| f43ce1d70d |
@@ -3,7 +3,14 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||||
|
<uses-feature android:name="android.hardware.camera.any" android:required="false" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@@ -25,9 +32,9 @@
|
|||||||
<activity android:name=".HomeActivity" android:exported="false" />
|
<activity android:name=".HomeActivity" android:exported="false" />
|
||||||
<activity android:name=".RegisterActivity" android:exported="false" />
|
<activity android:name=".RegisterActivity" android:exported="false" />
|
||||||
<activity android:name=".MainActivity" android:exported="false" />
|
<activity android:name=".MainActivity" android:exported="false" />
|
||||||
|
|
||||||
<!-- AQUI ESTÁ A ACTIVITY QUE FALTAVA! -->
|
|
||||||
<activity android:name=".VerificacaoActivity" android:exported="false" />
|
<activity android:name=".VerificacaoActivity" android:exported="false" />
|
||||||
|
<activity android:name=".MudarEmailActivity" android:exported="false" />
|
||||||
|
<activity android:name=".MudarPasswordActivity" android:exported="false" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".LoginActivity"
|
android:name=".LoginActivity"
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package com.example.pap;
|
package com.example.pap;
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
import retrofit2.Retrofit;
|
import retrofit2.Retrofit;
|
||||||
import retrofit2.converter.gson.GsonConverterFactory;
|
import retrofit2.converter.gson.GsonConverterFactory;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class AiConfig {
|
public class AiConfig {
|
||||||
private static Retrofit retrofit;
|
private static Retrofit retrofit;
|
||||||
@@ -9,8 +11,17 @@ public class AiConfig {
|
|||||||
|
|
||||||
public static Retrofit getRetrofit() {
|
public static Retrofit getRetrofit() {
|
||||||
if (retrofit == null) {
|
if (retrofit == null) {
|
||||||
|
|
||||||
|
// NOVO: Adiciona paciência ao Android (Timeout de 60 segundos)
|
||||||
|
OkHttpClient clienteComPaciencia = new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(60, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(60, TimeUnit.SECONDS)
|
||||||
|
.writeTimeout(60, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
|
||||||
retrofit = new Retrofit.Builder()
|
retrofit = new Retrofit.Builder()
|
||||||
.baseUrl(BASE_URL)
|
.baseUrl(BASE_URL)
|
||||||
|
.client(clienteComPaciencia) // Liga o cliente paciente
|
||||||
.addConverterFactory(GsonConverterFactory.create())
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package com.example.pap;
|
package com.example.pap;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.text.method.ScrollingMovementMethod;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -18,7 +20,7 @@ public class ChatActivity extends AppCompatActivity {
|
|||||||
private Button btnEnviar;
|
private Button btnEnviar;
|
||||||
private TextView btnVoltarChat;
|
private TextView btnVoltarChat;
|
||||||
|
|
||||||
// NÃO TE ESQUEÇAS DE COLAR A TUA CHAVE AQUI!
|
// A TUA CHAVE (cuidado na escola com ela)
|
||||||
private final String MINHA_API_KEY = "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";
|
private final String MINHA_API_KEY = "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";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -31,17 +33,17 @@ public class ChatActivity extends AppCompatActivity {
|
|||||||
btnEnviar = findViewById(R.id.btnEnviarChat);
|
btnEnviar = findViewById(R.id.btnEnviarChat);
|
||||||
btnVoltarChat = findViewById(R.id.btnVoltarChat);
|
btnVoltarChat = findViewById(R.id.btnVoltarChat);
|
||||||
|
|
||||||
// --- LÓGICA DO BOTÃO VOLTAR PARA O HOME ---
|
// Faz com que o texto do chat consiga rolar se for muito grande
|
||||||
|
tvChatLog.setMovementMethod(new ScrollingMovementMethod());
|
||||||
|
|
||||||
btnVoltarChat.setOnClickListener(v -> {
|
btnVoltarChat.setOnClickListener(v -> {
|
||||||
// Cria a intenção de ir para a MainActivity (Home)
|
|
||||||
Intent intent = new Intent(ChatActivity.this, HomeActivity.class);
|
Intent intent = new Intent(ChatActivity.this, HomeActivity.class);
|
||||||
// Esta linha garante que não ficas com mil ecrãs abertos uns por cima dos outros
|
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
finish(); // Fecha o Chat
|
finish();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Receber a análise da foto se existir
|
// Receber a análise da foto (se veio de lá)
|
||||||
String analiseComida = getIntent().getStringExtra("analise_comida");
|
String analiseComida = getIntent().getStringExtra("analise_comida");
|
||||||
if (analiseComida != null && !analiseComida.isEmpty()) {
|
if (analiseComida != null && !analiseComida.isEmpty()) {
|
||||||
tvChatLog.setText("IA: Analisei o teu prato.\n" + analiseComida + "\n\nO que queres saber mais?");
|
tvChatLog.setText("IA: Analisei o teu prato.\n" + analiseComida + "\n\nO que queres saber mais?");
|
||||||
@@ -59,9 +61,22 @@ public class ChatActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
private void perguntarIA(String texto) {
|
private void perguntarIA(String texto) {
|
||||||
tvChatLog.append("\n\nIA: A pensar... ⏳");
|
tvChatLog.append("\n\nIA: A pensar... ⏳");
|
||||||
|
btnEnviar.setEnabled(false); // Bloqueia o botão para não haver spam
|
||||||
|
|
||||||
|
// 1. ABRIR A GAVETA PARA A IA SABER QUEM ÉS
|
||||||
|
SharedPreferences prefs = getSharedPreferences("MeusDadosApp", MODE_PRIVATE);
|
||||||
|
float peso = prefs.getFloat("peso", 0);
|
||||||
|
float altura = prefs.getFloat("altura", 0);
|
||||||
|
int idade = prefs.getInt("idade", 20);
|
||||||
|
|
||||||
|
// 2. CRIAR O "CÉREBRO" DO NUTRICIONISTA (com os teus dados injetados)
|
||||||
|
String contextoNutricionista = "És o nutricionista pessoal do utilizador. " +
|
||||||
|
"Dados do paciente hoje: Peso=" + peso + "kg, Altura=" + altura + "m, Idade=" + idade + " anos. " +
|
||||||
|
"Se ele perguntar quanta água beber, usa o cálculo de 35ml por cada kg de peso. " +
|
||||||
|
"Responde SEMPRE de forma muito curta (máximo 3 frases), direta e em Português de Portugal. Nunca uses asteriscos.";
|
||||||
|
|
||||||
AiRequest request = new AiRequest(java.util.Arrays.asList(
|
AiRequest request = new AiRequest(java.util.Arrays.asList(
|
||||||
new Message("system", Collections.singletonList(new ContentPart("text", "És um nutricionista de Portugal. Responde SEMPRE de forma muito curta (máximo 2 frases). Nunca uses asteriscos."))),
|
new Message("system", Collections.singletonList(new ContentPart("text", contextoNutricionista))),
|
||||||
new Message("user", Collections.singletonList(new ContentPart("text", texto)))
|
new Message("user", Collections.singletonList(new ContentPart("text", texto)))
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -70,17 +85,23 @@ public class ChatActivity extends AppCompatActivity {
|
|||||||
.enqueue(new Callback<AiResponse>() {
|
.enqueue(new Callback<AiResponse>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<AiResponse> call, Response<AiResponse> response) {
|
public void onResponse(Call<AiResponse> call, Response<AiResponse> response) {
|
||||||
|
btnEnviar.setEnabled(true);
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
String resposta = response.body().choices.get(0).message.content;
|
String resposta = response.body().choices.get(0).message.content;
|
||||||
String limpa = resposta.replace("**", "").replace("*", "");
|
String limpa = resposta.replace("**", "").replace("*", "");
|
||||||
String atual = tvChatLog.getText().toString();
|
String atual = tvChatLog.getText().toString();
|
||||||
tvChatLog.setText(atual.replace("IA: A pensar... ⏳", "IA: " + limpa));
|
tvChatLog.setText(atual.replace("IA: A pensar... ⏳", "IA: " + limpa));
|
||||||
|
} else {
|
||||||
|
// Se a API chumbou mas houve resposta (Erro 400, 429...)
|
||||||
|
String atual = tvChatLog.getText().toString();
|
||||||
|
tvChatLog.setText(atual.replace("IA: A pensar... ⏳", "IA: Tive um pequeno bloqueio (Erro " + response.code() + "). Tenta outra vez!"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<AiResponse> call, Throwable t) {
|
public void onFailure(Call<AiResponse> call, Throwable t) {
|
||||||
|
btnEnviar.setEnabled(true);
|
||||||
String atual = tvChatLog.getText().toString();
|
String atual = tvChatLog.getText().toString();
|
||||||
tvChatLog.setText(atual.replace("IA: A pensar... ⏳", "IA: Erro de rede."));
|
tvChatLog.setText(atual.replace("IA: A pensar... ⏳", "IA: Erro de comunicação (O servidor demorou muito a responder). Tenta novamente."));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,237 +1,66 @@
|
|||||||
package com.example.pap;
|
package com.example.pap;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.InputType;
|
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.appcompat.app.AppCompatDelegate;
|
|
||||||
import androidx.appcompat.widget.SwitchCompat;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.Callback;
|
|
||||||
import retrofit2.Response;
|
|
||||||
|
|
||||||
public class DefinicoesActivity extends AppCompatActivity {
|
public class DefinicoesActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private SwitchCompat switchDarkMode;
|
private EditText etNovoNome;
|
||||||
private Button btnEditarNome, btnMudarEmail, btnMudarPass, btnVoltarDef;
|
private Button btnGuardarNome, btnSairConta, btnIrMudarEmail, btnIrMudarPassword;
|
||||||
private SharedPreferences sharedPreferences;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_definicoes);
|
setContentView(R.layout.activity_definicoes);
|
||||||
|
|
||||||
// Iniciar a memória local do telemóvel
|
etNovoNome = findViewById(R.id.etNovoNome);
|
||||||
sharedPreferences = getSharedPreferences("MeusDadosApp", MODE_PRIVATE);
|
btnGuardarNome = findViewById(R.id.btnGuardarNome);
|
||||||
|
btnSairConta = findViewById(R.id.btnSairConta);
|
||||||
|
btnIrMudarEmail = findViewById(R.id.btnIrMudarEmail);
|
||||||
|
btnIrMudarPassword = findViewById(R.id.btnIrMudarPassword);
|
||||||
|
|
||||||
// Ligar os elementos do design ao código
|
findViewById(R.id.btnVoltarDefinicoes).setOnClickListener(v -> finish());
|
||||||
switchDarkMode = findViewById(R.id.switchDarkMode);
|
|
||||||
btnEditarNome = findViewById(R.id.btnEditarNome);
|
|
||||||
btnMudarEmail = findViewById(R.id.btnMudarEmail);
|
|
||||||
btnMudarPass = findViewById(R.id.btnMudarPass);
|
|
||||||
btnVoltarDef = findViewById(R.id.btnVoltarDef);
|
|
||||||
|
|
||||||
// 1. Lógica do Modo Escuro
|
SharedPreferences dadosPrefs = getSharedPreferences("MeusDadosApp", MODE_PRIVATE);
|
||||||
boolean isDarkMode = sharedPreferences.getBoolean("dark_mode", false);
|
etNovoNome.setText(dadosPrefs.getString("nome", ""));
|
||||||
switchDarkMode.setChecked(isDarkMode);
|
|
||||||
|
|
||||||
switchDarkMode.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
// Ir para Mudar Email
|
||||||
if (isChecked) {
|
btnIrMudarEmail.setOnClickListener(v -> {
|
||||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
startActivity(new Intent(DefinicoesActivity.this, MudarEmailActivity.class));
|
||||||
} else {
|
|
||||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
|
||||||
}
|
|
||||||
sharedPreferences.edit().putBoolean("dark_mode", isChecked).apply();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Configurar os cliques nos botões
|
// Ir para Mudar Password
|
||||||
btnEditarNome.setOnClickListener(v -> mostrarPopupNome());
|
btnIrMudarPassword.setOnClickListener(v -> {
|
||||||
btnMudarEmail.setOnClickListener(v -> mostrarPopupEmail());
|
startActivity(new Intent(DefinicoesActivity.this, MudarPasswordActivity.class));
|
||||||
btnMudarPass.setOnClickListener(v -> mostrarPopupPassword());
|
});
|
||||||
btnVoltarDef.setOnClickListener(v -> finish());
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- FUNÇÕES DOS POP-UPS ---
|
// Guardar Apenas o Nome (Porque Email e Password têm ecrãs próprios)
|
||||||
|
btnGuardarNome.setOnClickListener(v -> {
|
||||||
private void mostrarPopupNome() {
|
String novoNome = etNovoNome.getText().toString().trim();
|
||||||
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()) {
|
if (!novoNome.isEmpty()) {
|
||||||
sharedPreferences.edit().putString("nome", novoNome).apply();
|
SharedPreferences.Editor editor = dadosPrefs.edit();
|
||||||
Toast.makeText(this, "Nome atualizado com sucesso!", Toast.LENGTH_SHORT).show();
|
editor.putString("nome", novoNome);
|
||||||
|
editor.apply();
|
||||||
|
Toast.makeText(this, "Nome atualizado!", Toast.LENGTH_SHORT).show();
|
||||||
|
finish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
builder.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mostrarPopupEmail() {
|
// Terminar Sessão
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
btnSairConta.setOnClickListener(v -> {
|
||||||
builder.setTitle("Alterar Email");
|
SharedPreferences.Editor editor = dadosPrefs.edit();
|
||||||
|
editor.clear();
|
||||||
LinearLayout layout = new LinearLayout(this);
|
editor.apply();
|
||||||
layout.setOrientation(LinearLayout.VERTICAL);
|
Toast.makeText(this, "Sessão terminada", Toast.LENGTH_SHORT).show();
|
||||||
layout.setPadding(50, 20, 50, 0);
|
Intent intent = new Intent(DefinicoesActivity.this, LoginActivity.class);
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||||
final EditText etPassAtual = new EditText(this);
|
startActivity(intent);
|
||||||
etPassAtual.setHint("A tua Password atual");
|
finish();
|
||||||
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();
|
|
||||||
String novoEmail = etNovoEmail.getText().toString().trim();
|
|
||||||
String emailAtual = sharedPreferences.getString("email", "");
|
|
||||||
|
|
||||||
if (passAtual.isEmpty() || novoEmail.isEmpty()) {
|
|
||||||
Toast.makeText(this, "Preenche todos os campos!", Toast.LENGTH_SHORT).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SupabaseApi api = SupabaseConfig.getRetrofit().create(SupabaseApi.class);
|
|
||||||
UserCredentials creds = new UserCredentials(emailAtual, passAtual);
|
|
||||||
|
|
||||||
// Confirma a identidade do utilizador (Mini-login)
|
|
||||||
api.login(SupabaseConfig.SUPABASE_KEY, creds).enqueue(new Callback<SupabaseResponse>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Call<SupabaseResponse> call, Response<SupabaseResponse> 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<String, String> updates = new HashMap<>();
|
|
||||||
updates.put("email", novoEmail);
|
|
||||||
|
|
||||||
api.updateUserData(SupabaseConfig.SUPABASE_KEY, "Bearer " + freshToken, updates).enqueue(new Callback<Void>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Call<Void> call, Response<Void> 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<Void> 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<SupabaseResponse> call, Throwable t) {
|
|
||||||
Toast.makeText(DefinicoesActivity.this, "Verifica a tua ligação à internet!", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
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<SupabaseResponse>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Call<SupabaseResponse> call, Response<SupabaseResponse> response) {
|
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
|
||||||
String freshToken = response.body().access_token;
|
|
||||||
|
|
||||||
// Atualiza a palavra-passe no Supabase
|
|
||||||
Map<String, String> updates = new HashMap<>();
|
|
||||||
updates.put("password", pNova);
|
|
||||||
|
|
||||||
api.updateUserData(SupabaseConfig.SUPABASE_KEY, "Bearer " + freshToken, updates).enqueue(new Callback<Void>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Call<Void> call, Response<Void> 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<Void> 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<SupabaseResponse> call, Throwable t) {
|
|
||||||
Toast.makeText(DefinicoesActivity.this, "Verifica a tua ligação à internet!", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
builder.show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,26 @@
|
|||||||
package com.example.pap;
|
package com.example.pap;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -34,6 +42,9 @@ public class DesafiosActivity extends AppCompatActivity {
|
|||||||
private int desafioAtualSendoGravado = -1; // 0=Agua, 1=D1, 2=D2, 3=D3, 4=D4
|
private int desafioAtualSendoGravado = -1; // 0=Agua, 1=D1, 2=D2, 3=D3, 4=D4
|
||||||
private float litrosAgua = 0.0f;
|
private float litrosAgua = 0.0f;
|
||||||
|
|
||||||
|
private ActivityResultLauncher<Intent> videoLauncher;
|
||||||
|
private AlertDialog popupCarregamento; // A janela de loading
|
||||||
|
|
||||||
private final String MINHA_API_KEY = "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";
|
private final String MINHA_API_KEY = "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";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -42,6 +53,9 @@ 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);
|
||||||
|
|
||||||
tvStatusAgua = findViewById(R.id.tvStatusAgua);
|
tvStatusAgua = findViewById(R.id.tvStatusAgua);
|
||||||
tvStatusD1 = findViewById(R.id.tvStatusD1);
|
tvStatusD1 = findViewById(R.id.tvStatusD1);
|
||||||
tvStatusD2 = findViewById(R.id.tvStatusD2);
|
tvStatusD2 = findViewById(R.id.tvStatusD2);
|
||||||
@@ -58,8 +72,7 @@ public class DesafiosActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
verificarResetMeiaNoite();
|
verificarResetMeiaNoite();
|
||||||
|
|
||||||
// Launcher da Câmara
|
videoLauncher = registerForActivityResult(
|
||||||
ActivityResultLauncher<Intent> videoLauncher = registerForActivityResult(
|
|
||||||
new ActivityResultContracts.StartActivityForResult(),
|
new ActivityResultContracts.StartActivityForResult(),
|
||||||
result -> {
|
result -> {
|
||||||
if (result.getResultCode() == RESULT_OK && result.getData() != null) {
|
if (result.getResultCode() == RESULT_OK && result.getData() != null) {
|
||||||
@@ -70,19 +83,41 @@ public class DesafiosActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Configurar Botões
|
btnVideoAgua.setOnClickListener(v -> { desafioAtualSendoGravado = 0; verificarPermissaoEAbrir(); });
|
||||||
btnVideoAgua.setOnClickListener(v -> { desafioAtualSendoGravado = 0; abrirCamera(videoLauncher); });
|
btnVideoD1.setOnClickListener(v -> { desafioAtualSendoGravado = 1; verificarPermissaoEAbrir(); });
|
||||||
btnVideoD1.setOnClickListener(v -> { desafioAtualSendoGravado = 1; abrirCamera(videoLauncher); });
|
btnVideoD2.setOnClickListener(v -> { desafioAtualSendoGravado = 2; verificarPermissaoEAbrir(); });
|
||||||
btnVideoD2.setOnClickListener(v -> { desafioAtualSendoGravado = 2; abrirCamera(videoLauncher); });
|
btnVideoD3.setOnClickListener(v -> { desafioAtualSendoGravado = 3; verificarPermissaoEAbrir(); });
|
||||||
btnVideoD3.setOnClickListener(v -> { desafioAtualSendoGravado = 3; abrirCamera(videoLauncher); });
|
btnVideoD4.setOnClickListener(v -> { desafioAtualSendoGravado = 4; verificarPermissaoEAbrir(); });
|
||||||
btnVideoD4.setOnClickListener(v -> { desafioAtualSendoGravado = 4; abrirCamera(videoLauncher); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void abrirCamera(ActivityResultLauncher<Intent> launcher) {
|
private void verificarPermissaoEAbrir() {
|
||||||
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
|
||||||
intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10);
|
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 100);
|
||||||
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
|
} else {
|
||||||
launcher.launch(intent);
|
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() {
|
private void verificarResetMeiaNoite() {
|
||||||
@@ -91,7 +126,6 @@ public class DesafiosActivity extends AppCompatActivity {
|
|||||||
String dataGuardada = prefs.getString("data_5_desafios", "");
|
String dataGuardada = prefs.getString("data_5_desafios", "");
|
||||||
|
|
||||||
if (!dataHoje.equals(dataGuardada)) {
|
if (!dataHoje.equals(dataGuardada)) {
|
||||||
// Limpar tudo
|
|
||||||
SharedPreferences.Editor editor = prefs.edit();
|
SharedPreferences.Editor editor = prefs.edit();
|
||||||
editor.putString("data_5_desafios", dataHoje);
|
editor.putString("data_5_desafios", dataHoje);
|
||||||
editor.putFloat("agua_litros", 0.0f);
|
editor.putFloat("agua_litros", 0.0f);
|
||||||
@@ -99,8 +133,9 @@ public class DesafiosActivity extends AppCompatActivity {
|
|||||||
editor.putBoolean("d2_concluido", false);
|
editor.putBoolean("d2_concluido", false);
|
||||||
editor.putBoolean("d3_concluido", false);
|
editor.putBoolean("d3_concluido", false);
|
||||||
editor.putBoolean("d4_concluido", false);
|
editor.putBoolean("d4_concluido", false);
|
||||||
// Zera a água para as estatísticas
|
|
||||||
editor.putInt("agua_hoje", 0);
|
editor.putInt("agua_hoje", 0);
|
||||||
|
editor.putInt("calorias_desafios", 0);
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,21 +157,53 @@ public class DesafiosActivity extends AppCompatActivity {
|
|||||||
private void atualizarTextoDesafio(TextView tv, boolean concluido) {
|
private void atualizarTextoDesafio(TextView tv, boolean concluido) {
|
||||||
if (concluido) {
|
if (concluido) {
|
||||||
tv.setText("Estado: Concluído ✅");
|
tv.setText("Estado: Concluído ✅");
|
||||||
tv.setTextColor(Color.parseColor("#10B981")); // Verde
|
tv.setTextColor(Color.parseColor("#10B981"));
|
||||||
} else {
|
} else {
|
||||||
tv.setText("Estado: Pendente");
|
tv.setText("Estado: Pendente");
|
||||||
tv.setTextColor(Color.parseColor("#EF4444")); // Vermelho
|
tv.setTextColor(Color.parseColor("#EF4444"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==========================================
|
||||||
|
// NOVOS POP-UPS DE LOADING E RESULTADOS
|
||||||
|
// ==========================================
|
||||||
|
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); // Impede que o utilizador feche sem querer
|
||||||
|
|
||||||
|
popupCarregamento = builder.create();
|
||||||
|
popupCarregamento.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mostrarResultadoFinal(String titulo, String mensagem) {
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
// Fecha a janela de "A aguardar..."
|
||||||
|
if (popupCarregamento != null && popupCarregamento.isShowing()) {
|
||||||
|
popupCarregamento.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abre a janela com o resultado final
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
|
builder.setTitle(titulo);
|
||||||
|
builder.setMessage(mensagem);
|
||||||
|
builder.setPositiveButton("OK", null);
|
||||||
|
builder.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void enviarVideoParaIA(Uri uri) {
|
private void enviarVideoParaIA(Uri uri) {
|
||||||
tvStatusGeralIA.setText("A processar vídeo e enviar para a IA... ⏳");
|
|
||||||
bloquearBotoes(false);
|
bloquearBotoes(false);
|
||||||
|
mostrarLoading(); // Mostra a janela de loading logo aqui!
|
||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
String base64Video = converterVideo(uri);
|
String base64Video = converterVideo(uri);
|
||||||
if (base64Video == null) {
|
if (base64Video == null) {
|
||||||
runOnUiThread(() -> { tvStatusGeralIA.setText("Erro ao ler vídeo."); bloquearBotoes(true); });
|
mostrarResultadoFinal("Erro no Vídeo ⚠️", "Não foi possível ler o vídeo gravado.");
|
||||||
|
runOnUiThread(() -> bloquearBotoes(true));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,12 +230,14 @@ public class DesafiosActivity extends AppCompatActivity {
|
|||||||
String respostaIA = response.body().choices.get(0).message.content;
|
String respostaIA = response.body().choices.get(0).message.content;
|
||||||
processarResposta(respostaIA);
|
processarResposta(respostaIA);
|
||||||
} else {
|
} else {
|
||||||
runOnUiThread(() -> { tvStatusGeralIA.setText("Erro na IA: " + response.code()); bloquearBotoes(true); });
|
mostrarResultadoFinal("Erro de Servidor ⚠️", "Erro ao contactar a IA. Código: " + response.code());
|
||||||
|
runOnUiThread(() -> bloquearBotoes(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<AiResponse> call, Throwable t) {
|
public void onFailure(Call<AiResponse> call, Throwable t) {
|
||||||
runOnUiThread(() -> { tvStatusGeralIA.setText("Erro de rede."); bloquearBotoes(true); });
|
mostrarResultadoFinal("Sem Internet 🌐", "Não conseguimos ligar à IA. Verifica a tua rede.");
|
||||||
|
runOnUiThread(() -> bloquearBotoes(true));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).start();
|
}).start();
|
||||||
@@ -178,7 +247,6 @@ public class DesafiosActivity extends AppCompatActivity {
|
|||||||
SharedPreferences prefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE);
|
SharedPreferences prefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE);
|
||||||
SharedPreferences.Editor editor = prefs.edit();
|
SharedPreferences.Editor editor = prefs.edit();
|
||||||
|
|
||||||
// Dar pontos no perfil
|
|
||||||
SharedPreferences perfilPrefs = getSharedPreferences("MeusDadosApp", MODE_PRIVATE);
|
SharedPreferences perfilPrefs = getSharedPreferences("MeusDadosApp", MODE_PRIVATE);
|
||||||
SharedPreferences.Editor perfilEditor = perfilPrefs.edit();
|
SharedPreferences.Editor perfilEditor = perfilPrefs.edit();
|
||||||
|
|
||||||
@@ -191,27 +259,36 @@ public class DesafiosActivity extends AppCompatActivity {
|
|||||||
litrosAgua += lido;
|
litrosAgua += lido;
|
||||||
|
|
||||||
editor.putFloat("agua_litros", litrosAgua);
|
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!");
|
// Mostra o resultado da Água!
|
||||||
|
mostrarResultadoFinal("Bom trabalho! 💧", "A IA detetou que bebeste +" + lido + " Litros!");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
tvStatusGeralIA.setText("Erro a ler os litros. Tenta de novo.");
|
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 {
|
||||||
if (texto.contains("Status: Concluido")) {
|
if (texto.contains("Status: Concluido")) {
|
||||||
tvStatusGeralIA.setText("IA: Desafio Validado! ✅ +50 Pontos");
|
|
||||||
|
|
||||||
if (desafioAtualSendoGravado == 1) editor.putBoolean("d1_concluido", true);
|
int caloriasAQueimar = 0;
|
||||||
if (desafioAtualSendoGravado == 2) editor.putBoolean("d2_concluido", true);
|
if (desafioAtualSendoGravado == 1) { editor.putBoolean("d1_concluido", true); caloriasAQueimar = 2; }
|
||||||
if (desafioAtualSendoGravado == 3) editor.putBoolean("d3_concluido", true);
|
if (desafioAtualSendoGravado == 2) { editor.putBoolean("d2_concluido", true); caloriasAQueimar = 2; }
|
||||||
if (desafioAtualSendoGravado == 4) editor.putBoolean("d4_concluido", true);
|
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("pontos", perfilPrefs.getInt("pontos", 0) + 50);
|
||||||
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!");
|
||||||
} else {
|
} else {
|
||||||
tvStatusGeralIA.setText("IA: Desafio Falhou ou vídeo pouco claro. ❌");
|
mostrarResultadoFinal("Desafio Falhou ❌", "A IA acha que o movimento não foi claro ou bem feito. Tenta outra vez!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
editor.apply();
|
editor.apply();
|
||||||
|
|||||||
@@ -7,44 +7,63 @@ import android.widget.ProgressBar;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
public class EstatisticasActivity extends AppCompatActivity {
|
public class EstatisticasActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private TextView tvValorIMC, tvStatusIMC, tvCaloriasMeta;
|
private TextView tvValorIMC, tvStatusIMC, tvCaloriasMeta, tvCaloriasQueimadas;
|
||||||
private TextView tvProtGramas, tvHidrGramas, tvGordGramas, tvComida1;
|
private TextView tvProtGramas, tvHidrGramas, tvGordGramas, tvComida1, tvCaloriasConsumidas;
|
||||||
private TextView tvAguaStats;
|
private TextView tvAguaStats;
|
||||||
private ProgressBar progressProt, progressHidr, progressGord;
|
private ProgressBar progressProt, progressHidr, progressGord;
|
||||||
|
|
||||||
|
// AS 3 TEXTVIEWS DAS NOSSAS IAS ESPECIALIZADAS
|
||||||
|
private TextView tvAiTopGeral, tvAiMacrosConselho, tvAiProximaRefeicao;
|
||||||
|
|
||||||
|
private int metaCaloriasDiarias = 0;
|
||||||
|
private final String MINHA_API_KEY = "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";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_estatisticas);
|
setContentView(R.layout.activity_estatisticas);
|
||||||
|
|
||||||
// Ligar o layout (XML) às variáveis do Java
|
|
||||||
tvValorIMC = findViewById(R.id.tvValorIMC);
|
tvValorIMC = findViewById(R.id.tvValorIMC);
|
||||||
tvStatusIMC = findViewById(R.id.tvStatusIMC);
|
tvStatusIMC = findViewById(R.id.tvStatusIMC);
|
||||||
tvCaloriasMeta = findViewById(R.id.tvCaloriasMeta);
|
tvCaloriasMeta = findViewById(R.id.tvCaloriasMeta);
|
||||||
|
tvCaloriasConsumidas = findViewById(R.id.tvCaloriasConsumidas);
|
||||||
|
tvCaloriasQueimadas = findViewById(R.id.tvCaloriasQueimadas);
|
||||||
|
|
||||||
tvProtGramas = findViewById(R.id.tvProtGramas);
|
tvProtGramas = findViewById(R.id.tvProtGramas);
|
||||||
tvHidrGramas = findViewById(R.id.tvHidrGramas);
|
tvHidrGramas = findViewById(R.id.tvHidrGramas);
|
||||||
tvGordGramas = findViewById(R.id.tvGordGramas);
|
tvGordGramas = findViewById(R.id.tvGordGramas);
|
||||||
tvComida1 = findViewById(R.id.tvComida1);
|
tvComida1 = findViewById(R.id.tvComida1);
|
||||||
|
|
||||||
tvAguaStats = findViewById(R.id.tvAguaStats);
|
tvAguaStats = findViewById(R.id.tvAguaStats);
|
||||||
|
|
||||||
progressProt = findViewById(R.id.progressProt);
|
progressProt = findViewById(R.id.progressProt);
|
||||||
progressHidr = findViewById(R.id.progressHidr);
|
progressHidr = findViewById(R.id.progressHidr);
|
||||||
progressGord = findViewById(R.id.progressGord);
|
progressGord = findViewById(R.id.progressGord);
|
||||||
|
|
||||||
// Botão voltar
|
// Ligar os IDs das 3 novas caixas de IA
|
||||||
|
tvAiTopGeral = findViewById(R.id.tvAiTopGeral);
|
||||||
|
tvAiMacrosConselho = findViewById(R.id.tvAiMacrosConselho);
|
||||||
|
tvAiProximaRefeicao = findViewById(R.id.tvAiProximaRefeicao);
|
||||||
|
|
||||||
findViewById(R.id.btnVoltarStats).setOnClickListener(v -> finish());
|
findViewById(R.id.btnVoltarStats).setOnClickListener(v -> finish());
|
||||||
|
|
||||||
// Chamar as funções que preenchem os dados
|
// Atualizar painéis locais
|
||||||
calcularIMC();
|
calcularIMC();
|
||||||
calcularTMB();
|
calcularTMB();
|
||||||
carregarMacrosDaIA();
|
carregarMacrosDaIA();
|
||||||
carregarAgua();
|
carregarAgua();
|
||||||
|
carregarCaloriasQueimadas();
|
||||||
|
|
||||||
|
// ARRANCAR AS 3 IAS EM SIMULTÂNEO!
|
||||||
|
iniciarComiteIAs();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void calcularIMC() {
|
private void calcularIMC() {
|
||||||
@@ -79,26 +98,22 @@ public class EstatisticasActivity extends AppCompatActivity {
|
|||||||
SharedPreferences prefs = getSharedPreferences("MeusDadosApp", MODE_PRIVATE);
|
SharedPreferences prefs = getSharedPreferences("MeusDadosApp", MODE_PRIVATE);
|
||||||
float peso = prefs.getFloat("peso", 0);
|
float peso = prefs.getFloat("peso", 0);
|
||||||
float alturaMetros = prefs.getFloat("altura", 0);
|
float alturaMetros = prefs.getFloat("altura", 0);
|
||||||
String sexo = prefs.getString("sexo", "");
|
String sexo = prefs.getString("sexo", "Masculino");
|
||||||
|
|
||||||
// Puxa a idade real. Se der erro ou não existir, assume 20.
|
|
||||||
int idade = prefs.getInt("idade", 20);
|
int idade = prefs.getInt("idade", 20);
|
||||||
|
|
||||||
if (peso > 0 && alturaMetros > 0 && !sexo.isEmpty()) {
|
if (peso > 0 && alturaMetros > 0) {
|
||||||
float alturaCm = alturaMetros * 100; // Passar para centímetros
|
float alturaCm = alturaMetros * 100;
|
||||||
double tmb;
|
double tmb;
|
||||||
|
|
||||||
// Fórmula de Harris-Benedict
|
|
||||||
if (sexo.equals("Masculino")) {
|
if (sexo.equals("Masculino")) {
|
||||||
tmb = (10 * peso) + (6.25 * alturaCm) - (5 * idade) + 5;
|
tmb = (10 * peso) + (6.25 * alturaCm) - (5 * idade) + 5;
|
||||||
} else {
|
} else {
|
||||||
tmb = (10 * peso) + (6.25 * alturaCm) - (5 * idade) - 161;
|
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;
|
double caloriasTotais = tmb * 1.2;
|
||||||
|
metaCaloriasDiarias = (int) caloriasTotais;
|
||||||
tvCaloriasMeta.setText(String.valueOf((int) caloriasTotais));
|
tvCaloriasMeta.setText(String.valueOf(metaCaloriasDiarias));
|
||||||
} else {
|
} else {
|
||||||
tvCaloriasMeta.setText("--");
|
tvCaloriasMeta.setText("--");
|
||||||
}
|
}
|
||||||
@@ -107,11 +122,16 @@ public class EstatisticasActivity extends AppCompatActivity {
|
|||||||
private void carregarMacrosDaIA() {
|
private void carregarMacrosDaIA() {
|
||||||
SharedPreferences prefs = getSharedPreferences("DadosSaude", MODE_PRIVATE);
|
SharedPreferences prefs = getSharedPreferences("DadosSaude", MODE_PRIVATE);
|
||||||
|
|
||||||
|
int caloriasConsumidasHoje = prefs.getInt("cal_hoje", 0);
|
||||||
int prot = prefs.getInt("prot_hoje", 0);
|
int prot = prefs.getInt("prot_hoje", 0);
|
||||||
int hidr = prefs.getInt("hidr_hoje", 0);
|
int hidr = prefs.getInt("hidr_hoje", 0);
|
||||||
int gord = prefs.getInt("gord_hoje", 0);
|
int gord = prefs.getInt("gord_hoje", 0);
|
||||||
String ultimaComida = prefs.getString("ultimo_prato", "Ainda não leste nada hoje.");
|
String ultimaComida = prefs.getString("ultimo_prato", "Ainda não leste nada hoje.");
|
||||||
|
|
||||||
|
int caloriasQueFaltam = metaCaloriasDiarias - caloriasConsumidasHoje;
|
||||||
|
if (caloriasQueFaltam < 0) caloriasQueFaltam = 0;
|
||||||
|
tvCaloriasConsumidas.setText("Consumido: " + caloriasConsumidasHoje + " kcal / Faltam: " + caloriasQueFaltam + " kcal");
|
||||||
|
|
||||||
tvProtGramas.setText("Proteína: " + prot + "g");
|
tvProtGramas.setText("Proteína: " + prot + "g");
|
||||||
tvHidrGramas.setText("Hidratos: " + hidr + "g");
|
tvHidrGramas.setText("Hidratos: " + hidr + "g");
|
||||||
tvGordGramas.setText("Gordura: " + gord + "g");
|
tvGordGramas.setText("Gordura: " + gord + "g");
|
||||||
@@ -126,9 +146,125 @@ public class EstatisticasActivity extends AppCompatActivity {
|
|||||||
private void carregarAgua() {
|
private void carregarAgua() {
|
||||||
SharedPreferences prefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE);
|
SharedPreferences prefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE);
|
||||||
int coposBebidos = prefs.getInt("agua_hoje", 0);
|
int coposBebidos = prefs.getInt("agua_hoje", 0);
|
||||||
|
|
||||||
float litrosTotais = coposBebidos * 0.25f;
|
float litrosTotais = coposBebidos * 0.25f;
|
||||||
|
|
||||||
tvAguaStats.setText(String.format(Locale.getDefault(), "💧 %.2f L", litrosTotais));
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================
|
||||||
|
// FUNÇÃO MASTER: GERE AS 3 IAS DE SEGUIDA
|
||||||
|
// ==========================================
|
||||||
|
private void iniciarComiteIAs() {
|
||||||
|
// Puxar os dados locais necessários
|
||||||
|
SharedPreferences prefsDados = getSharedPreferences("MeusDadosApp", MODE_PRIVATE);
|
||||||
|
SharedPreferences prefsSaude = getSharedPreferences("DadosSaude", MODE_PRIVATE);
|
||||||
|
SharedPreferences prefsGam = getSharedPreferences("DadosGamificacao", MODE_PRIVATE);
|
||||||
|
|
||||||
|
float peso = prefsDados.getFloat("peso", 0);
|
||||||
|
float altura = prefsDados.getFloat("altura", 0);
|
||||||
|
float imc = (peso > 0 && altura > 0) ? (peso / (altura * altura)) : 0;
|
||||||
|
|
||||||
|
int calConsumidas = prefsSaude.getInt("cal_hoje", 0);
|
||||||
|
int prot = prefsSaude.getInt("prot_hoje", 0);
|
||||||
|
int hidr = prefsSaude.getInt("hidr_hoje", 0);
|
||||||
|
int gord = prefsSaude.getInt("gord_hoje", 0);
|
||||||
|
String ultimaComida = prefsSaude.getString("ultimo_prato", "Nenhuma");
|
||||||
|
|
||||||
|
float litrosAgua = prefsGam.getInt("agua_hoje", 0) * 0.25f;
|
||||||
|
int kcalQueimadas = prefsGam.getInt("calorias_desafios", 0);
|
||||||
|
|
||||||
|
// Chamar os 3 consultores assíncronos
|
||||||
|
chamarIa3TopGeral(imc, litrosAgua, kcalQueimadas, calConsumidas);
|
||||||
|
chamarIa1Macros(prot, hidr, gord);
|
||||||
|
chamarIa2ProximaRefeicao(ultimaComida);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- IA 3: O DIAGNÓSTICO DO TOPO ---
|
||||||
|
private void chamarIa3TopGeral(float imc, float agua, int queimadas, int consumidas) {
|
||||||
|
tvAiTopGeral.setText("A avaliar o teu dia geral... ⏳");
|
||||||
|
|
||||||
|
String prompt = "És um Médico Nutricionista Clínico. Analisa estes dados globais de hoje do paciente: " +
|
||||||
|
"IMC=" + String.format(Locale.getDefault(), "%.1f", imc) + ", Água=" + agua + "L, " +
|
||||||
|
"Calorias Gastas em Exercício=" + queimadas + "kcal, Calorias Consumidas=" + consumidas + "kcal (Meta=" + metaCaloriasDiarias + "). " +
|
||||||
|
"Dá um diagnóstico curto, sério e aponta os riscos de saúde imediatos se os valores forem maus. " +
|
||||||
|
"Regra: Apenas 2 frases em Português de Portugal. Não uses asteriscos.";
|
||||||
|
|
||||||
|
fazerPedidoIA(prompt, new AiCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSucesso(String resposta) { tvAiTopGeral.setText(resposta); }
|
||||||
|
@Override
|
||||||
|
public void onFalha() { tvAiTopGeral.setText("Não foi possível processar o diagnóstico geral de saúde."); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- IA 1: O AJUSTADOR DE MACROS ---
|
||||||
|
private void chamarIa1Macros(int prot, int hidr, int gord) {
|
||||||
|
tvAiMacrosConselho.setText("A analisar balanço de macronutrientes... ⏳");
|
||||||
|
|
||||||
|
String prompt = "És um Especialista em Macronutrientes de Alta Performance. O atleta consumiu hoje: " +
|
||||||
|
"Proteína=" + prot + "g, Hidratos=" + hidr + "g, Gordura=" + gord + "g. " +
|
||||||
|
"Com base nestes números exatos, diz o que ele deve ajustar ou cortar na próxima refeição de hoje. " +
|
||||||
|
"Regra: Resposta direta, sem saudações, apenas 2 frases em Português de Portugal. Não uses asteriscos.";
|
||||||
|
|
||||||
|
fazerPedidoIA(prompt, new AiCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSucesso(String resposta) { tvAiMacrosConselho.setText(resposta); }
|
||||||
|
@Override
|
||||||
|
public void onFalha() { tvAiMacrosConselho.setText("Impossível ligar ao consultor de macros."); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- IA 2: O PLANER DE REFEIÇÕES ---
|
||||||
|
private void chamarIa2ProximaRefeicao(String ultimaComida) {
|
||||||
|
tvAiProximaRefeicao.setText("A planear receita de compensação... ⏳");
|
||||||
|
|
||||||
|
String prompt = "És um Chef Nutricional Inteligente. A última refeição que o utilizador registou foi: '" + ultimaComida + "'. " +
|
||||||
|
"Com base apenas nisto, sugere concretamente uma opção de refeição (ou snack) saudável e equilibrada para ele comer a seguir. " +
|
||||||
|
"Regra: Dá uma sugestão específica de comida em 2 frases curtas, em Português de Portugal. Não uses asteriscos.";
|
||||||
|
|
||||||
|
fazerPedidoIA(prompt, new AiCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSucesso(String resposta) { tvAiProximaRefeicao.setText(resposta); }
|
||||||
|
@Override
|
||||||
|
public void onFalha() { tvAiProximaRefeicao.setText("Ativa a internet para veres a sugestão do Chef IA."); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- MOTOR GENÉRICO DE NETWORK PARA RETROFIT ---
|
||||||
|
private void fazerPedidoIA(String prompt, final AiCallback callback) {
|
||||||
|
AiRequest request = new AiRequest(Collections.singletonList(
|
||||||
|
new Message("user", Collections.singletonList(new ContentPart("text", prompt)))
|
||||||
|
));
|
||||||
|
|
||||||
|
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) {
|
||||||
|
try {
|
||||||
|
String texto = response.body().choices.get(0).message.content;
|
||||||
|
String limpo = texto.replace("**", "").replace("*", "");
|
||||||
|
callback.onSucesso(limpo.trim());
|
||||||
|
} catch (Exception e) { callback.onFalha(); }
|
||||||
|
} else { callback.onFalha(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<AiResponse> call, Throwable t) {
|
||||||
|
callback.onFalha();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface interna para gerir as respostas assíncronas em paralelo
|
||||||
|
interface AiCallback {
|
||||||
|
void onSucesso(String resposta);
|
||||||
|
void onFalha();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -11,10 +11,15 @@ import android.provider.MediaStore;
|
|||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -28,12 +33,12 @@ import retrofit2.Response;
|
|||||||
public class FotoActivity extends AppCompatActivity {
|
public class FotoActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private ImageView ivFotoComida;
|
private ImageView ivFotoComida;
|
||||||
private Button btnTirarFoto, btnGaleria, btnAnalisarIA, btnIrParaChat;
|
private Button btnTirarFoto, btnGaleria, btnAnalisarIA, btnIrParaChat, btnCorrigir;
|
||||||
private TextView tvResultadoIA;
|
private TextView tvResultadoIA;
|
||||||
private Bitmap imagemCapturada;
|
private Bitmap imagemCapturada;
|
||||||
private String textoAnalise = "";
|
private String textoAnalise = "";
|
||||||
|
|
||||||
// MANTÉM A TUA CHAVE (cuidado para não partilhar no futuro)
|
// A TUA CHAVE DA API
|
||||||
private final String MINHA_API_KEY = "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";
|
private final String MINHA_API_KEY = "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";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -41,11 +46,13 @@ public class FotoActivity extends AppCompatActivity {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_foto);
|
setContentView(R.layout.activity_foto);
|
||||||
|
|
||||||
|
// Ligar ao XML
|
||||||
ivFotoComida = findViewById(R.id.ivFotoComida);
|
ivFotoComida = findViewById(R.id.ivFotoComida);
|
||||||
btnTirarFoto = findViewById(R.id.btnTirarFoto);
|
btnTirarFoto = findViewById(R.id.btnTirarFoto);
|
||||||
btnGaleria = findViewById(R.id.btnGaleria);
|
btnGaleria = findViewById(R.id.btnGaleria);
|
||||||
btnAnalisarIA = findViewById(R.id.btnAnalisarIA);
|
btnAnalisarIA = findViewById(R.id.btnAnalisarIA);
|
||||||
btnIrParaChat = findViewById(R.id.btnIrParaChat);
|
btnIrParaChat = findViewById(R.id.btnIrParaChat);
|
||||||
|
btnCorrigir = findViewById(R.id.btnCorrigir);
|
||||||
tvResultadoIA = findViewById(R.id.tvResultadoIA);
|
tvResultadoIA = findViewById(R.id.tvResultadoIA);
|
||||||
|
|
||||||
ActivityResultLauncher<Intent> camLauncher = registerForActivityResult(
|
ActivityResultLauncher<Intent> camLauncher = registerForActivityResult(
|
||||||
@@ -80,12 +87,14 @@ public class FotoActivity extends AppCompatActivity {
|
|||||||
});
|
});
|
||||||
|
|
||||||
btnTirarFoto.setOnClickListener(v -> camLauncher.launch(new Intent(MediaStore.ACTION_IMAGE_CAPTURE)));
|
btnTirarFoto.setOnClickListener(v -> camLauncher.launch(new Intent(MediaStore.ACTION_IMAGE_CAPTURE)));
|
||||||
|
|
||||||
btnGaleria.setOnClickListener(v -> {
|
btnGaleria.setOnClickListener(v -> {
|
||||||
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||||
galLauncher.launch(intent);
|
galLauncher.launch(intent);
|
||||||
});
|
});
|
||||||
|
|
||||||
btnAnalisarIA.setOnClickListener(v -> enviarParaIA());
|
// Clique para analisar pela primeira vez
|
||||||
|
btnAnalisarIA.setOnClickListener(v -> enviarParaIA(null));
|
||||||
|
|
||||||
btnIrParaChat.setOnClickListener(v -> {
|
btnIrParaChat.setOnClickListener(v -> {
|
||||||
Intent intent = new Intent(FotoActivity.this, ChatActivity.class);
|
Intent intent = new Intent(FotoActivity.this, ChatActivity.class);
|
||||||
@@ -93,6 +102,9 @@ public class FotoActivity extends AppCompatActivity {
|
|||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Clique para corrigir o erro da IA
|
||||||
|
btnCorrigir.setOnClickListener(v -> mostrarPopupCorrecao());
|
||||||
|
|
||||||
findViewById(R.id.btnVoltarFoto).setOnClickListener(v -> finish());
|
findViewById(R.id.btnVoltarFoto).setOnClickListener(v -> finish());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,26 +115,41 @@ public class FotoActivity extends AppCompatActivity {
|
|||||||
ivFotoComida.setImageBitmap(imagemCapturada);
|
ivFotoComida.setImageBitmap(imagemCapturada);
|
||||||
btnAnalisarIA.setVisibility(View.VISIBLE);
|
btnAnalisarIA.setVisibility(View.VISIBLE);
|
||||||
btnIrParaChat.setVisibility(View.GONE);
|
btnIrParaChat.setVisibility(View.GONE);
|
||||||
|
btnCorrigir.setVisibility(View.GONE);
|
||||||
tvResultadoIA.setText("Pronto para analisar.");
|
tvResultadoIA.setText("Pronto para analisar.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enviarParaIA() {
|
// Função blindada contra erros da IA
|
||||||
|
private void enviarParaIA(String comidaCerta) {
|
||||||
tvResultadoIA.setText("A processar... ⏳");
|
tvResultadoIA.setText("A processar... ⏳");
|
||||||
btnAnalisarIA.setEnabled(false);
|
btnAnalisarIA.setEnabled(false);
|
||||||
btnIrParaChat.setVisibility(View.GONE);
|
btnIrParaChat.setVisibility(View.GONE);
|
||||||
|
btnCorrigir.setVisibility(View.GONE);
|
||||||
|
|
||||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
imagemCapturada.compress(Bitmap.CompressFormat.JPEG, 50, os);
|
imagemCapturada.compress(Bitmap.CompressFormat.JPEG, 50, os);
|
||||||
String base64 = Base64.encodeToString(os.toByteArray(), Base64.NO_WRAP);
|
String base64 = Base64.encodeToString(os.toByteArray(), Base64.NO_WRAP);
|
||||||
|
|
||||||
String ordemParaIA = "És um nutricionista prático. Identifica a comida e dá os valores de forma SUPER RESUMIDA. " +
|
String ordemParaIA;
|
||||||
"REGRAS: 1. Português de Portugal. 2. SEM asteriscos. 3. Máximo 4 linhas. " +
|
if (comidaCerta == null) {
|
||||||
"Formato exato: \n" +
|
// Regras super restritas para a primeira análise
|
||||||
"Prato: [Nome]\n" +
|
ordemParaIA = "És uma API de nutrição. Avalia a foto. É ESTRITAMENTE PROIBIDO usar texto de conversa, saudações ou tags de segurança. " +
|
||||||
"Calorias: [Valor] kcal\n" +
|
"Responde APENAS E SÓ neste formato exato:\n" +
|
||||||
"Macros: [X]g Proteína, [X]g Hidratos, [X]g Gordura\n" +
|
"Prato: [Nome]\n" +
|
||||||
"Dica: [Uma frase curta].";
|
"Calorias: [Valor] kcal\n" +
|
||||||
|
"Macros: [X]g Proteína, [X]g Hidratos, [X]g Gordura\n" +
|
||||||
|
"Dica: [Frase curta sem asteriscos].";
|
||||||
|
} else {
|
||||||
|
// Regras super restritas para a correção
|
||||||
|
ordemParaIA = "Atenção: ignora a imagem. O utilizador confirmou que o prato é '" + comidaCerta + "'. " +
|
||||||
|
"É ESTRITAMENTE PROIBIDO usar texto de conversa ou avisos de segurança (ex: User:safe). " +
|
||||||
|
"Responde APENAS E SÓ com os valores nutricionais médios para '" + comidaCerta + "' neste formato exato:\n" +
|
||||||
|
"Prato: " + comidaCerta + "\n" +
|
||||||
|
"Calorias: [Valor] kcal\n" +
|
||||||
|
"Macros: [X]g Proteína, [X]g Hidratos, [X]g Gordura\n" +
|
||||||
|
"Dica: [Frase curta sem asteriscos].";
|
||||||
|
}
|
||||||
|
|
||||||
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(
|
||||||
@@ -141,14 +168,28 @@ public class FotoActivity extends AppCompatActivity {
|
|||||||
try {
|
try {
|
||||||
String resposta = response.body().choices.get(0).message.content;
|
String resposta = response.body().choices.get(0).message.content;
|
||||||
textoAnalise = resposta.replace("**", "").replace("*", "");
|
textoAnalise = resposta.replace("**", "").replace("*", "");
|
||||||
|
|
||||||
|
// O NOSSO ESCUDO: Se a resposta não tiver a palavra "Calorias", a IA deu tilt!
|
||||||
|
if (!textoAnalise.contains("Calorias:") || !textoAnalise.contains("Macros:")) {
|
||||||
|
tvResultadoIA.setText("A IA ficou confusa com o prato 😵\u200D💫. Clica em 'Corrigir' e tenta ser mais específico (Ex: Bife com Arroz).");
|
||||||
|
btnCorrigir.setVisibility(View.VISIBLE);
|
||||||
|
return; // Pára tudo aqui, não guarda lixo na memória!
|
||||||
|
}
|
||||||
|
|
||||||
tvResultadoIA.setText(textoAnalise);
|
tvResultadoIA.setText(textoAnalise);
|
||||||
btnIrParaChat.setVisibility(View.VISIBLE);
|
btnIrParaChat.setVisibility(View.VISIBLE);
|
||||||
|
btnCorrigir.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
// A MAGIA ACONTECE AQUI!
|
// Se ele estiver a corrigir, apagamos o erro passado!
|
||||||
|
if (comidaCerta != null) {
|
||||||
|
desfazerUltimoErro();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guarda a nova resposta
|
||||||
extrairEGuardarDados(textoAnalise);
|
extrairEGuardarDados(textoAnalise);
|
||||||
|
|
||||||
} catch (Exception e) { tvResultadoIA.setText("Erro na resposta."); }
|
} catch (Exception e) { tvResultadoIA.setText("Erro na leitura da resposta."); }
|
||||||
} else { tvResultadoIA.setText("Erro: " + response.code()); }
|
} else { tvResultadoIA.setText("Erro no servidor: " + response.code()); }
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<AiResponse> call, Throwable t) {
|
public void onFailure(Call<AiResponse> call, Throwable t) {
|
||||||
@@ -158,50 +199,99 @@ public class FotoActivity extends AppCompatActivity {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Função que "lê" a resposta da IA e guarda os números
|
// --- POPUP PARA CORREÇÃO MANUAL ---
|
||||||
|
private void mostrarPopupCorrecao() {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
|
builder.setTitle("Corrigir a IA 🤔");
|
||||||
|
builder.setMessage("A IA enganou-se? O que estava realmente no teu prato?");
|
||||||
|
|
||||||
|
final EditText input = new EditText(this);
|
||||||
|
input.setHint("Ex: Hambúrguer de Frango");
|
||||||
|
|
||||||
|
LinearLayout layout = new LinearLayout(this);
|
||||||
|
layout.setPadding(50, 20, 50, 0);
|
||||||
|
layout.addView(input);
|
||||||
|
builder.setView(layout);
|
||||||
|
|
||||||
|
builder.setPositiveButton("Re-Analisar", (dialog, which) -> {
|
||||||
|
String comidaCerta = input.getText().toString().trim();
|
||||||
|
if (!comidaCerta.isEmpty()) {
|
||||||
|
enviarParaIA(comidaCerta);
|
||||||
|
} else {
|
||||||
|
Toast.makeText(FotoActivity.this, "Tens de escrever a comida!", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.setNegativeButton("Cancelar", null);
|
||||||
|
builder.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- FUNÇÃO PARA SALVAR OS DADOS E A DICA ---
|
||||||
private void extrairEGuardarDados(String texto) {
|
private void extrairEGuardarDados(String texto) {
|
||||||
try {
|
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 indexNomeStart = texto.indexOf("Prato: ") + 7;
|
||||||
int indexNomeEnd = texto.indexOf("\n", indexNomeStart);
|
int indexNomeEnd = texto.indexOf("\n", indexNomeStart);
|
||||||
String nomePrato = texto.substring(indexNomeStart, indexNomeEnd).trim();
|
String nomePrato = texto.substring(indexNomeStart, indexNomeEnd).trim();
|
||||||
|
|
||||||
// Apanhar os números
|
|
||||||
int calorias = extrairNumero(texto, "Calorias: ", " kcal");
|
int calorias = extrairNumero(texto, "Calorias: ", " kcal");
|
||||||
int proteina = extrairNumero(texto, "Macros: ", "g Proteína");
|
int proteina = extrairNumero(texto, "Macros: ", "g Proteína");
|
||||||
int hidratos = extrairNumero(texto, "Proteína, ", "g Hidratos");
|
int hidratos = extrairNumero(texto, "Proteína, ", "g Hidratos");
|
||||||
int gordura = extrairNumero(texto, "Hidratos, ", "g Gordura");
|
int gordura = extrairNumero(texto, "Hidratos, ", "g Gordura");
|
||||||
|
|
||||||
// Abrir a memória
|
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 prefs = getSharedPreferences("DadosSaude", MODE_PRIVATE);
|
||||||
SharedPreferences.Editor editor = prefs.edit();
|
SharedPreferences.Editor editor = prefs.edit();
|
||||||
|
|
||||||
// Guardar nome do último prato
|
|
||||||
editor.putString("ultimo_prato", nomePrato);
|
editor.putString("ultimo_prato", nomePrato);
|
||||||
|
editor.putString("ultima_dica_ia", dicaIA);
|
||||||
|
|
||||||
// Somar aos valores do dia
|
|
||||||
editor.putInt("cal_hoje", prefs.getInt("cal_hoje", 0) + calorias);
|
editor.putInt("cal_hoje", prefs.getInt("cal_hoje", 0) + calorias);
|
||||||
editor.putInt("prot_hoje", prefs.getInt("prot_hoje", 0) + proteina);
|
editor.putInt("prot_hoje", prefs.getInt("prot_hoje", 0) + proteina);
|
||||||
editor.putInt("hidr_hoje", prefs.getInt("hidr_hoje", 0) + hidratos);
|
editor.putInt("hidr_hoje", prefs.getInt("hidr_hoje", 0) + hidratos);
|
||||||
editor.putInt("gord_hoje", prefs.getInt("gord_hoje", 0) + gordura);
|
editor.putInt("gord_hoje", prefs.getInt("gord_hoje", 0) + gordura);
|
||||||
|
|
||||||
|
// GUAAAAARDA O ERRO PARA PODERMOS APAGAR SE O GAJO CLICAR EM "CORRIGIR"
|
||||||
|
editor.putInt("ultimo_erro_cal", calorias);
|
||||||
|
editor.putInt("ultimo_erro_prot", proteina);
|
||||||
|
editor.putInt("ultimo_erro_hidr", hidratos);
|
||||||
|
editor.putInt("ultimo_erro_gord", gordura);
|
||||||
|
|
||||||
editor.apply();
|
editor.apply();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {}
|
||||||
// Ignora se a IA responder noutro formato para não crashar
|
}
|
||||||
}
|
|
||||||
|
// --- FUNÇÃO PARA REMOVER O ÚLTIMO PRATO QUE FOI MAL LIDO ---
|
||||||
|
private void desfazerUltimoErro() {
|
||||||
|
SharedPreferences prefs = getSharedPreferences("DadosSaude", MODE_PRIVATE);
|
||||||
|
SharedPreferences.Editor editor = prefs.edit();
|
||||||
|
|
||||||
|
int calAntiga = prefs.getInt("ultimo_erro_cal", 0);
|
||||||
|
int protAntiga = prefs.getInt("ultimo_erro_prot", 0);
|
||||||
|
int hidrAntiga = prefs.getInt("ultimo_erro_hidr", 0);
|
||||||
|
int gordAntiga = prefs.getInt("ultimo_erro_gord", 0);
|
||||||
|
|
||||||
|
editor.putInt("cal_hoje", prefs.getInt("cal_hoje", 0) - calAntiga);
|
||||||
|
editor.putInt("prot_hoje", prefs.getInt("prot_hoje", 0) - protAntiga);
|
||||||
|
editor.putInt("hidr_hoje", prefs.getInt("hidr_hoje", 0) - hidrAntiga);
|
||||||
|
editor.putInt("gord_hoje", prefs.getInt("gord_hoje", 0) - gordAntiga);
|
||||||
|
|
||||||
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ferramenta que corta a fatia certa de texto para tirar os números
|
|
||||||
private int extrairNumero(String texto, String inicio, String fim) {
|
private int extrairNumero(String texto, String inicio, String fim) {
|
||||||
try {
|
try {
|
||||||
int start = texto.indexOf(inicio) + inicio.length();
|
int start = texto.indexOf(inicio) + inicio.length();
|
||||||
int end = texto.indexOf(fim, start);
|
int end = texto.indexOf(fim, start);
|
||||||
String valorString = texto.substring(start, end).trim();
|
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]", "");
|
valorString = valorString.replaceAll("[^0-9]", "");
|
||||||
return Integer.parseInt(valorString);
|
return Integer.parseInt(valorString);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return 0; // Se não encontrar, assume 0
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
88
app/src/main/java/com/example/pap/MudarEmailActivity.java
Normal file
88
app/src/main/java/com/example/pap/MudarEmailActivity.java
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
package com.example.pap;
|
||||||
|
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
public class MudarEmailActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
private EditText etAlterarEmail, etAlterarPassword1, etAlterarPassword2;
|
||||||
|
private Button btnConfirmarEmailNovo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_mudar_email);
|
||||||
|
|
||||||
|
etAlterarEmail = findViewById(R.id.etAlterarEmail);
|
||||||
|
etAlterarPassword1 = findViewById(R.id.etAlterarPassword1);
|
||||||
|
etAlterarPassword2 = findViewById(R.id.etAlterarPassword2);
|
||||||
|
btnConfirmarEmailNovo = findViewById(R.id.btnConfirmarEmailNovo);
|
||||||
|
|
||||||
|
findViewById(R.id.btnVoltarMudarEmail).setOnClickListener(v -> finish());
|
||||||
|
|
||||||
|
SharedPreferences dadosPrefs = getSharedPreferences("MeusDadosApp", MODE_PRIVATE);
|
||||||
|
|
||||||
|
btnConfirmarEmailNovo.setOnClickListener(v -> {
|
||||||
|
String novoEmail = etAlterarEmail.getText().toString().trim();
|
||||||
|
String pass1 = etAlterarPassword1.getText().toString().trim();
|
||||||
|
String pass2 = etAlterarPassword2.getText().toString().trim();
|
||||||
|
|
||||||
|
if (novoEmail.isEmpty() || pass1.isEmpty() || pass2.isEmpty()) {
|
||||||
|
Toast.makeText(this, "Preenche todos os campos!", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Validação: Verifica se os dois campos de password antiga coincidem
|
||||||
|
if (!pass1.equals(pass2)) {
|
||||||
|
Toast.makeText(this, "As confirmações de password não coincidem!", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Validação: Verifica se a password escrita é mesmo a senha correta da conta
|
||||||
|
String passwordReal = dadosPrefs.getString("password", "");
|
||||||
|
if (!passwordReal.isEmpty() && !pass1.equals(passwordReal)) {
|
||||||
|
Toast.makeText(this, "A password atual introduzida está errada!", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String token = dadosPrefs.getString("access_token", "");
|
||||||
|
if (token.isEmpty()) {
|
||||||
|
Toast.makeText(this, "Erro: Faz login novamente.", Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Envia as alterações para o Supabase
|
||||||
|
Map<String, String> updates = new HashMap<>();
|
||||||
|
updates.put("email", novoEmail);
|
||||||
|
|
||||||
|
SupabaseApi api = SupabaseConfig.getRetrofit().create(SupabaseApi.class);
|
||||||
|
api.updateUserData(SupabaseConfig.SUPABASE_KEY, "Bearer " + token, updates).enqueue(new Callback<Void>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<Void> call, Response<Void> response) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
Toast.makeText(MudarEmailActivity.this, "Vai à caixa do novo email confirmar!", Toast.LENGTH_LONG).show();
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(MudarEmailActivity.this, "Erro ao mudar o email no Supabase.", Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<Void> call, Throwable t) {
|
||||||
|
Toast.makeText(MudarEmailActivity.this, "Falha na internet.", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
93
app/src/main/java/com/example/pap/MudarPasswordActivity.java
Normal file
93
app/src/main/java/com/example/pap/MudarPasswordActivity.java
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
package com.example.pap;
|
||||||
|
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
public class MudarPasswordActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
private EditText etPasswordAntiga, etNovaPassword1, etNovaPassword2;
|
||||||
|
private Button btnConfirmarPassword;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_mudar_password);
|
||||||
|
|
||||||
|
etPasswordAntiga = findViewById(R.id.etPasswordAntiga);
|
||||||
|
etNovaPassword1 = findViewById(R.id.etNovaPassword1);
|
||||||
|
etNovaPassword2 = findViewById(R.id.etNovaPassword2);
|
||||||
|
btnConfirmarPassword = findViewById(R.id.btnConfirmarPassword);
|
||||||
|
|
||||||
|
findViewById(R.id.btnVoltarMudarPassword).setOnClickListener(v -> finish());
|
||||||
|
|
||||||
|
SharedPreferences dadosPrefs = getSharedPreferences("MeusDadosApp", MODE_PRIVATE);
|
||||||
|
|
||||||
|
btnConfirmarPassword.setOnClickListener(v -> {
|
||||||
|
String passAntiga = etPasswordAntiga.getText().toString().trim();
|
||||||
|
String novaPass1 = etNovaPassword1.getText().toString().trim();
|
||||||
|
String novaPass2 = etNovaPassword2.getText().toString().trim();
|
||||||
|
|
||||||
|
if (passAntiga.isEmpty() || novaPass1.isEmpty() || novaPass2.isEmpty()) {
|
||||||
|
Toast.makeText(this, "Preenche todos os campos!", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirma se as duas passwords novas são iguais
|
||||||
|
if (!novaPass1.equals(novaPass2)) {
|
||||||
|
Toast.makeText(this, "As passwords novas não coincidem!", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirma se a password antiga escrita bate certo com a guardada no telemóvel
|
||||||
|
String passwordReal = dadosPrefs.getString("password", "");
|
||||||
|
if (!passwordReal.isEmpty() && !passAntiga.equals(passwordReal)) {
|
||||||
|
Toast.makeText(this, "A password antiga está errada!", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String token = dadosPrefs.getString("access_token", "");
|
||||||
|
if (token.isEmpty()) {
|
||||||
|
Toast.makeText(this, "Erro: Faz login novamente.", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Atualizar na nuvem
|
||||||
|
Map<String, String> updates = new HashMap<>();
|
||||||
|
updates.put("password", novaPass1);
|
||||||
|
|
||||||
|
SupabaseApi api = SupabaseConfig.getRetrofit().create(SupabaseApi.class);
|
||||||
|
api.updateUserData(SupabaseConfig.SUPABASE_KEY, "Bearer " + token, updates).enqueue(new Callback<Void>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<Void> call, Response<Void> response) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
// Guardar a nova password na memória para os próximos testes
|
||||||
|
SharedPreferences.Editor editor = dadosPrefs.edit();
|
||||||
|
editor.putString("password", novaPass1);
|
||||||
|
editor.apply();
|
||||||
|
|
||||||
|
Toast.makeText(MudarPasswordActivity.this, "Password alterada com sucesso!", Toast.LENGTH_SHORT).show();
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(MudarPasswordActivity.this, "Erro ao mudar password.", Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<Void> call, Throwable t) {
|
||||||
|
Toast.makeText(MudarPasswordActivity.this, "Falha na internet.", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,44 +10,79 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||||||
|
|
||||||
public class PerfilActivity extends AppCompatActivity {
|
public class PerfilActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private TextView tvPerfilPontos, tvPerfilDesafios, tvPerfilSequencia;
|
private TextView tvPerfilNome, tvPerfilPontos, tvPerfilDesafios, tvPerfilSequencia;
|
||||||
|
private TextView tvPerfilEmail, tvPerfilPassword;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_perfil);
|
setContentView(R.layout.activity_perfil);
|
||||||
|
|
||||||
tvPerfilPontos = findViewById(R.id.tvPerfilPontos);
|
try {
|
||||||
tvPerfilDesafios = findViewById(R.id.tvPerfilDesafios);
|
tvPerfilNome = findViewById(R.id.tvPerfilNome);
|
||||||
tvPerfilSequencia = findViewById(R.id.tvPerfilSequencia);
|
tvPerfilSequencia = findViewById(R.id.tvPerfilSequencia);
|
||||||
|
|
||||||
Button btnDefinicoes = findViewById(R.id.btnDefinicoes);
|
// Ligar os novos textos do Email e Password
|
||||||
TextView btnVoltar = findViewById(R.id.btnVoltarPerfil);
|
tvPerfilEmail = findViewById(R.id.tvPerfilEmail);
|
||||||
|
tvPerfilPassword = findViewById(R.id.tvPerfilPassword);
|
||||||
|
|
||||||
// Ler a pontuação guardada (vamos ligar isto mais à frente)
|
Button btnDefinicoes = findViewById(R.id.btnDefinicoes);
|
||||||
|
TextView btnVoltar = findViewById(R.id.btnVoltarPerfil);
|
||||||
|
|
||||||
|
if (btnDefinicoes != null) {
|
||||||
|
btnDefinicoes.setOnClickListener(v -> {
|
||||||
|
Intent intent = new Intent(PerfilActivity.this, DefinicoesActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btnVoltar != null) {
|
||||||
|
btnVoltar.setOnClickListener(v -> finish());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Toast.makeText(this, "Erro visual. Verifica o layout.", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
carregarProgresso();
|
carregarProgresso();
|
||||||
|
|
||||||
// Botão Definições
|
|
||||||
btnDefinicoes.setOnClickListener(v -> {
|
|
||||||
// Quando tiveres o ecrã de definições criado, trocas o Toast por isto:
|
|
||||||
// Intent intent = new Intent(PerfilActivity.this, DefinicoesActivity.class);
|
|
||||||
// startActivity(intent);
|
|
||||||
Toast.makeText(this, "A abrir Definições...", Toast.LENGTH_SHORT).show();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Botão Voltar (manda-te de volta para o Home/Menu)
|
|
||||||
btnVoltar.setOnClickListener(v -> finish());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void carregarProgresso() {
|
private void carregarProgresso() {
|
||||||
SharedPreferences prefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE);
|
try {
|
||||||
|
// Puxa o nome, email e password
|
||||||
|
SharedPreferences perfilPrefs = getSharedPreferences("MeusDadosApp", MODE_PRIVATE);
|
||||||
|
|
||||||
int pontos = prefs.getInt("pontos", 0);
|
if (tvPerfilNome != null) tvPerfilNome.setText(perfilPrefs.getString("nome", "Utilizador"));
|
||||||
int desafios = prefs.getInt("desafios", 0);
|
if (tvPerfilEmail != null) tvPerfilEmail.setText(perfilPrefs.getString("email", "Sem Email"));
|
||||||
int sequencia = prefs.getInt("sequencia", 1);
|
if (tvPerfilPassword != null) tvPerfilPassword.setText(perfilPrefs.getString("password", "********"));
|
||||||
|
|
||||||
tvPerfilPontos.setText(String.valueOf(pontos));
|
// Puxa pontos e desafios
|
||||||
tvPerfilDesafios.setText(String.valueOf(desafios));
|
int pontos = 0;
|
||||||
tvPerfilSequencia.setText(String.valueOf(sequencia));
|
int desafios = 0;
|
||||||
|
try {
|
||||||
|
pontos = perfilPrefs.getInt("pontos", 0);
|
||||||
|
desafios = perfilPrefs.getInt("desafios_concluidos", 0);
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
String pts = perfilPrefs.getString("pontos", "0");
|
||||||
|
pontos = Integer.parseInt(pts.replaceAll("[^0-9]", ""));
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Puxa a sequência
|
||||||
|
SharedPreferences gamificacaoPrefs = getSharedPreferences("DadosGamificacao", MODE_PRIVATE);
|
||||||
|
int sequencia = gamificacaoPrefs.getInt("sequencia", 1);
|
||||||
|
|
||||||
|
if (tvPerfilPontos != null) tvPerfilPontos.setText(String.valueOf(pontos));
|
||||||
|
if (tvPerfilDesafios != null) tvPerfilDesafios.setText(String.valueOf(desafios));
|
||||||
|
if (tvPerfilSequencia != null) tvPerfilSequencia.setText(String.valueOf(sequencia));
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIN
app/src/main/res/drawable/logo_app.png
Normal file
BIN
app/src/main/res/drawable/logo_app.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 350 KiB |
@@ -4,27 +4,36 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:background="#F8FAFC">
|
android:background="#FFFFFF"
|
||||||
|
android:padding="24dp">
|
||||||
|
|
||||||
<LinearLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="20dp"
|
android:layout_marginBottom="24dp">
|
||||||
android:background="#FFFFFF"
|
<TextView
|
||||||
android:elevation="4dp">
|
android:id="@+id/btnVoltarDefinicoes"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Voltar"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="#8E8E93"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:padding="8dp"/>
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Definições"
|
android:text="Definições"
|
||||||
android:textSize="22sp"
|
android:textSize="18sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textColor="#0F172A"/>
|
android:textColor="#1C1C1E"
|
||||||
</LinearLayout>
|
android:layout_centerInParent="true" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:padding="16dp">
|
android:scrollbars="none">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -34,92 +43,85 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="APARÊNCIA"
|
android:text="Dados da Conta"
|
||||||
android:textSize="12sp"
|
android:textSize="14sp"
|
||||||
|
android:textColor="#8E8E93"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textColor="#64748B"
|
android:layout_marginBottom="12dp"/>
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:layout_marginStart="8dp"/>
|
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
<androidx.cardview.widget.CardView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:cardCornerRadius="12dp"
|
android:layout_marginBottom="24dp"
|
||||||
android:layout_marginBottom="24dp">
|
app:cardCornerRadius="16dp"
|
||||||
|
app:cardElevation="0dp"
|
||||||
|
app:cardBackgroundColor="#F2F2F7">
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="16dp"
|
android:orientation="vertical"
|
||||||
android:gravity="center_vertical">
|
android:padding="20dp">
|
||||||
<TextView
|
|
||||||
android:layout_width="0dp"
|
<EditText
|
||||||
android:layout_height="wrap_content"
|
android:id="@+id/etNovoNome"
|
||||||
android:layout_weight="1"
|
android:layout_width="match_parent"
|
||||||
android:text="Modo Escuro"
|
android:layout_height="50dp"
|
||||||
android:textSize="16sp"
|
android:hint="Novo Nome"
|
||||||
android:textColor="#0F172A"/>
|
android:textColor="#1C1C1E"
|
||||||
<androidx.appcompat.widget.SwitchCompat
|
android:background="@android:color/transparent"
|
||||||
android:id="@+id/switchDarkMode"
|
android:inputType="textPersonName"
|
||||||
android:layout_width="wrap_content"
|
android:layout_marginBottom="8dp"/>
|
||||||
android:layout_height="wrap_content" />
|
<View android:layout_width="match_parent" android:layout_height="1dp" android:background="#E5E5EA" android:layout_marginBottom="8dp"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnIrMudarEmail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:text="Mudar Email"
|
||||||
|
android:textColor="#1C1C1E"
|
||||||
|
android:backgroundTint="#E5E5EA"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:cornerRadius="8dp"
|
||||||
|
android:elevation="0dp"
|
||||||
|
style="?android:attr/borderlessButtonStyle"/>
|
||||||
|
<View android:layout_width="match_parent" android:layout_height="1dp" android:background="#E5E5EA" android:layout_marginBottom="8dp"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnIrMudarPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:text="Mudar Palavra-passe"
|
||||||
|
android:textColor="#1C1C1E"
|
||||||
|
android:backgroundTint="#E5E5EA"
|
||||||
|
app:cornerRadius="8dp"
|
||||||
|
android:elevation="0dp"
|
||||||
|
style="?android:attr/borderlessButtonStyle"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
<TextView
|
<Button
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/btnGuardarNome"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:text="CONTA E SEGURANÇA"
|
android:layout_height="60dp"
|
||||||
android:textSize="12sp"
|
android:text="Guardar Nome"
|
||||||
|
android:backgroundTint="#03A9F4"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
android:textSize="16sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textColor="#64748B"
|
app:cornerRadius="16dp"/>
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:layout_marginStart="8dp"/>
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/btnEditarNome"
|
android:id="@+id/btnSairConta"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="55dp"
|
android:layout_height="60dp"
|
||||||
android:text="Mudar Nome"
|
android:layout_marginTop="16dp"
|
||||||
android:backgroundTint="#FFFFFF"
|
android:text="Terminar Sessão"
|
||||||
android:textColor="#0F172A"
|
android:backgroundTint="#FF3B30"
|
||||||
android:layout_marginBottom="8dp"
|
android:textColor="#FFFFFF"
|
||||||
app:cornerRadius="12dp"
|
android:textSize="16sp"
|
||||||
android:gravity="start|center_vertical"
|
android:textStyle="bold"
|
||||||
android:paddingStart="16dp"/>
|
app:cornerRadius="16dp"
|
||||||
|
android:layout_marginBottom="24dp"/>
|
||||||
<Button
|
|
||||||
android:id="@+id/btnMudarEmail"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="55dp"
|
|
||||||
android:text="Alterar Email"
|
|
||||||
android:backgroundTint="#FFFFFF"
|
|
||||||
android:textColor="#0F172A"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
app:cornerRadius="12dp"
|
|
||||||
android:gravity="start|center_vertical"
|
|
||||||
android:paddingStart="16dp"/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/btnMudarPass"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="55dp"
|
|
||||||
android:text="Alterar Palavra-Passe"
|
|
||||||
android:backgroundTint="#FFFFFF"
|
|
||||||
android:textColor="#0F172A"
|
|
||||||
android:layout_marginBottom="24dp"
|
|
||||||
app:cornerRadius="12dp"
|
|
||||||
android:gravity="start|center_vertical"
|
|
||||||
android:paddingStart="16dp"/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/btnVoltarDef"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="55dp"
|
|
||||||
android:text="Voltar"
|
|
||||||
android:backgroundTint="#E2E8F0"
|
|
||||||
android:textColor="#0F172A"
|
|
||||||
app:cornerRadius="12dp"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -53,10 +53,10 @@
|
|||||||
app:cardElevation="0dp"
|
app:cardElevation="0dp"
|
||||||
app:cardBackgroundColor="#F8FAFC">
|
app:cardBackgroundColor="#F8FAFC">
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="16dp" android:gravity="center_vertical">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="16dp" android:gravity="center_vertical">
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="✨" android:textSize="24sp" android:layout_marginEnd="12dp"/>
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="👑" android:textSize="24sp" android:layout_marginEnd="12dp"/>
|
||||||
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical">
|
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical">
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Insight da IA" android:textSize="12sp" android:textStyle="bold" android:textColor="#0284C7"/>
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Diagnóstico Geral da IA" android:textSize="12sp" android:textStyle="bold" android:textColor="#0284C7"/>
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Continua a registar as tuas refeições para ver dicas." android:textSize="14sp" android:textColor="#334155" android:layout_marginTop="2dp"/>
|
<TextView android:id="@+id/tvAiTopGeral" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="A calcular o teu diagnóstico de saúde hoje..." android:textSize="14sp" android:textColor="#334155" android:layout_marginTop="2dp"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
@@ -125,7 +125,6 @@
|
|||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:baselineAligned="false">
|
android:baselineAligned="false">
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
<androidx.cardview.widget.CardView
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@@ -147,11 +146,11 @@
|
|||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
app:cardCornerRadius="20dp"
|
app:cardCornerRadius="20dp"
|
||||||
app:cardElevation="0dp"
|
app:cardElevation="0dp"
|
||||||
app:cardBackgroundColor="#F2F2F7">
|
app:cardBackgroundColor="#FEF2F2">
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp" android:gravity="center">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp" android:gravity="center">
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="👟" android:textSize="20sp"/>
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="🔥" android:textSize="20sp"/>
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="0" android:textSize="18sp" android:textStyle="bold" android:textColor="#1C1C1E" android:layout_marginTop="4dp"/>
|
<TextView android:id="@+id/tvCaloriasQueimadas" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="0 kcal" android:textSize="18sp" android:textStyle="bold" android:textColor="#1C1C1E" android:layout_marginTop="4dp"/>
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Passos" android:textSize="12sp" android:textColor="#8E8E93"/>
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Desafios" android:textSize="12sp" android:textColor="#8E8E93"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -159,28 +158,41 @@
|
|||||||
<androidx.cardview.widget.CardView
|
<androidx.cardview.widget.CardView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="8dp"
|
||||||
app:cardCornerRadius="24dp"
|
app:cardCornerRadius="24dp"
|
||||||
app:cardElevation="0dp"
|
app:cardElevation="0dp"
|
||||||
app:cardBackgroundColor="#F2F2F7">
|
app:cardBackgroundColor="#F2F2F7">
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="20dp">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="20dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Macronutrientes Hoje" android:textStyle="bold" android:textColor="#1C1C1E" android:textSize="16sp" />
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Macronutrientes Hoje" android:textStyle="bold" android:textColor="#1C1C1E" android:textSize="16sp" android:layout_marginBottom="12dp"/>
|
<TextView android:id="@+id/tvCaloriasConsumidas" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Consumido: 0 / Faltam: -- kcal" android:textSize="13sp" android:textColor="#8E8E93" android:layout_marginBottom="12dp"/>
|
||||||
|
|
||||||
<TextView android:id="@+id/tvProtGramas" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Proteína: 0g" android:textSize="13sp" android:textColor="#3A3A3C"/>
|
<TextView android:id="@+id/tvProtGramas" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Proteína: 0g" android:textSize="13sp" android:textColor="#3A3A3C"/>
|
||||||
<ProgressBar android:id="@+id/progressProt" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="6dp" android:max="150" android:progress="0" android:progressTint="#1C1C1E" android:layout_marginBottom="12dp"/>
|
<ProgressBar android:id="@+id/progressProt" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="6dp" android:max="150" android:progress="0" android:progressTint="#3B82F6" android:layout_marginBottom="12dp"/>
|
||||||
|
|
||||||
<TextView android:id="@+id/tvHidrGramas" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hidratos: 0g" android:textSize="13sp" android:textColor="#3A3A3C"/>
|
<TextView android:id="@+id/tvHidrGramas" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hidratos: 0g" android:textSize="13sp" android:textColor="#3A3A3C"/>
|
||||||
<ProgressBar android:id="@+id/progressHidr" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="6dp" android:max="250" android:progress="0" android:progressTint="#1C1C1E" android:layout_marginBottom="12dp"/>
|
<ProgressBar android:id="@+id/progressHidr" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="6dp" android:max="250" android:progress="0" android:progressTint="#F59E0B" android:layout_marginBottom="12dp"/>
|
||||||
|
|
||||||
<TextView android:id="@+id/tvGordGramas" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Gordura: 0g" android:textSize="13sp" android:textColor="#3A3A3C"/>
|
<TextView android:id="@+id/tvGordGramas" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Gordura: 0g" android:textSize="13sp" android:textColor="#3A3A3C"/>
|
||||||
<ProgressBar android:id="@+id/progressGord" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="6dp" android:max="80" android:progress="0" android:progressTint="#1C1C1E" android:layout_marginBottom="8dp"/>
|
<ProgressBar android:id="@+id/progressGord" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="6dp" android:max="80" android:progress="0" android:progressTint="#EF4444" android:layout_marginBottom="8dp"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
<androidx.cardview.widget.CardView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
app:cardCornerRadius="20dp"
|
||||||
|
app:cardElevation="0dp"
|
||||||
|
app:cardBackgroundColor="#F0FDF4"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="16dp" android:gravity="center_vertical">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="📊" android:textSize="24sp" android:layout_marginEnd="12dp"/>
|
||||||
|
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Ajustador de Macros IA" android:textSize="12sp" android:textStyle="bold" android:textColor="#16A34A"/>
|
||||||
|
<TextView android:id="@+id/tvAiMacrosConselho" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="A ler os teus rácios de macros..." android:textSize="14sp" android:textColor="#166534" android:layout_marginTop="2dp"/>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
app:cardCornerRadius="24dp"
|
app:cardCornerRadius="24dp"
|
||||||
app:cardElevation="0dp"
|
app:cardElevation="0dp"
|
||||||
app:cardBackgroundColor="#F2F2F7">
|
app:cardBackgroundColor="#F2F2F7">
|
||||||
@@ -190,6 +202,20 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:cardCornerRadius="20dp"
|
||||||
|
app:cardElevation="0dp"
|
||||||
|
app:cardBackgroundColor="#FFF7ED"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="16dp" android:gravity="center_vertical">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="💡" android:textSize="24sp" android:layout_marginEnd="12dp"/>
|
||||||
|
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Sugestão de Próxima Refeição IA" android:textSize="12sp" android:textStyle="bold" android:textColor="#EA580C"/>
|
||||||
|
<TextView android:id="@+id/tvAiProximaRefeicao" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="A planear o teu próximo prato..." android:textSize="14sp" android:textColor="#9A3412" android:layout_marginTop="2dp"/>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -114,7 +114,19 @@
|
|||||||
android:backgroundTint="#F2F2F7"
|
android:backgroundTint="#F2F2F7"
|
||||||
android:textColor="#1C1C1E"
|
android:textColor="#1C1C1E"
|
||||||
app:cornerRadius="16dp"
|
app:cornerRadius="16dp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone"
|
||||||
|
android:layout_marginBottom="12dp"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnCorrigir"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:text="A IA errou? Corrigir"
|
||||||
|
android:textColor="#EF4444"
|
||||||
|
android:backgroundTint="#FEF2F2"
|
||||||
|
app:cornerRadius="16dp"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -15,23 +15,49 @@
|
|||||||
android:paddingTop="40dp"
|
android:paddingTop="40dp"
|
||||||
android:paddingBottom="40dp">
|
android:paddingBottom="40dp">
|
||||||
|
|
||||||
<TextView
|
<!-- CABEÇALHO COM O TEXTO À ESQUERDA E A LOGO À DIREITA -->
|
||||||
android:layout_width="wrap_content"
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="A tua jornada começa aqui,"
|
android:layout_marginBottom="40dp">
|
||||||
android:textSize="16sp"
|
|
||||||
android:textColor="#8E8E93"
|
|
||||||
android:layout_marginBottom="4dp"/>
|
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/tvSaudacaoHome"
|
android:layout_width="wrap_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:orientation="vertical"
|
||||||
android:text="Carregando..."
|
android:layout_alignParentStart="true"
|
||||||
android:textSize="32sp"
|
android:layout_centerVertical="true"
|
||||||
android:textStyle="bold"
|
android:layout_toStartOf="@+id/ivLogoHome"
|
||||||
android:textColor="#1C1C1E"
|
android:layout_marginEnd="16dp">
|
||||||
android:layout_marginBottom="40dp"/>
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="A tua jornada começa aqui,"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="#8E8E93"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvSaudacaoHome"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Carregando..."
|
||||||
|
android:textSize="32sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="#1C1C1E" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- A TUA LOGO NO CANTO DIREITO -->
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivLogoHome"
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="70dp"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:src="@drawable/logo_app"
|
||||||
|
android:adjustViewBounds="true" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
<androidx.cardview.widget.CardView
|
||||||
android:id="@+id/cardTirarFoto"
|
android:id="@+id/cardTirarFoto"
|
||||||
@@ -43,7 +69,7 @@
|
|||||||
android:foreground="?android:attr/selectableItemBackground"
|
android:foreground="?android:attr/selectableItemBackground"
|
||||||
app:cardCornerRadius="24dp"
|
app:cardCornerRadius="24dp"
|
||||||
app:cardElevation="0dp"
|
app:cardElevation="0dp"
|
||||||
app:cardBackgroundColor="#1C1C1E">
|
app:cardBackgroundColor="#000000">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -68,7 +94,7 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Escanear Comida"
|
android:text="Digitalizar Alimentos"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textColor="#FFFFFF"/>
|
android:textColor="#FFFFFF"/>
|
||||||
@@ -198,7 +224,7 @@
|
|||||||
android:layout_marginStart="20dp">
|
android:layout_marginStart="20dp">
|
||||||
|
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Desafios Diários" android:textSize="17sp" android:textStyle="bold" android:textColor="#1C1C1E"/>
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Desafios Diários" android:textSize="17sp" android:textStyle="bold" android:textColor="#1C1C1E"/>
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Ganha pontos de recompensa" android:textSize="13sp" android:textColor="#8E8E93" android:layout_marginTop="2dp"/>
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Faça desafios para melhor o seu desempenho" android:textSize="13sp" android:textColor="#8E8E93" android:layout_marginTop="2dp"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="›" android:textSize="28sp" android:textColor="#C7C7CC" android:layout_marginStart="8dp"/>
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="›" android:textSize="28sp" android:textColor="#C7C7CC" android:layout_marginStart="8dp"/>
|
||||||
@@ -238,7 +264,7 @@
|
|||||||
android:layout_marginStart="20dp">
|
android:layout_marginStart="20dp">
|
||||||
|
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="O Meu Perfil" android:textSize="17sp" android:textStyle="bold" android:textColor="#1C1C1E"/>
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="O Meu Perfil" android:textSize="17sp" android:textStyle="bold" android:textColor="#1C1C1E"/>
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Dados, pontuação e definições" android:textSize="13sp" android:textColor="#8E8E93" android:layout_marginTop="2dp"/>
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Dados e definições" android:textSize="13sp" android:textColor="#8E8E93" android:layout_marginTop="2dp"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="›" android:textSize="28sp" android:textColor="#C7C7CC" android:layout_marginStart="8dp"/>
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="›" android:textSize="28sp" android:textColor="#C7C7CC" android:layout_marginStart="8dp"/>
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="55dp"
|
android:layout_height="55dp"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:hint="A tua Password"
|
android:hint="A tua Palavra-passe"
|
||||||
android:inputType="textPassword"
|
android:inputType="textPassword"
|
||||||
android:paddingStart="16dp"
|
android:paddingStart="16dp"
|
||||||
android:paddingEnd="16dp"
|
android:paddingEnd="16dp"
|
||||||
|
|||||||
90
app/src/main/res/layout/activity_mudar_email.xml
Normal file
90
app/src/main/res/layout/activity_mudar_email.xml
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="#FFFFFF"
|
||||||
|
android:padding="24dp">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="32dp">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/btnVoltarMudarEmail"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Cancelar"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="#FF3B30"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:padding="8dp"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Mudar Email"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="#1C1C1E"
|
||||||
|
android:layout_centerInParent="true" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
|
app:cardCornerRadius="16dp"
|
||||||
|
app:cardElevation="0dp"
|
||||||
|
app:cardBackgroundColor="#F2F2F7">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="20dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etAlterarEmail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:hint="Novo Email"
|
||||||
|
android:textColor="#1C1C1E"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:inputType="textEmailAddress"
|
||||||
|
android:layout_marginBottom="8dp"/>
|
||||||
|
<View android:layout_width="match_parent" android:layout_height="1dp" android:background="#E5E5EA" android:layout_marginBottom="8dp"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etAlterarPassword1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:hint="Escreve a tua Palavra-passe Atual"
|
||||||
|
android:textColor="#1C1C1E"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:layout_marginBottom="8dp"/>
|
||||||
|
<View android:layout_width="match_parent" android:layout_height="1dp" android:background="#E5E5EA" android:layout_marginBottom="8dp"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etAlterarPassword2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:hint="Confirma a tua Palavra-passe Atual"
|
||||||
|
android:textColor="#1C1C1E"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:inputType="textPassword"/>
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnConfirmarEmailNovo"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:text="Confirmar Alteração"
|
||||||
|
android:backgroundTint="#03A9F4"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:cornerRadius="16dp"/>
|
||||||
|
</LinearLayout>
|
||||||
90
app/src/main/res/layout/activity_mudar_password.xml
Normal file
90
app/src/main/res/layout/activity_mudar_password.xml
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="#FFFFFF"
|
||||||
|
android:padding="24dp">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="32dp">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/btnVoltarMudarPassword"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Cancelar"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="#FF3B30"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:padding="8dp"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Mudar Palavra-passe"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="#1C1C1E"
|
||||||
|
android:layout_centerInParent="true" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
|
app:cardCornerRadius="16dp"
|
||||||
|
app:cardElevation="0dp"
|
||||||
|
app:cardBackgroundColor="#F2F2F7">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="20dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etPasswordAntiga"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:hint="Palavra-passe Antiga"
|
||||||
|
android:textColor="#1C1C1E"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:layout_marginBottom="8dp"/>
|
||||||
|
<View android:layout_width="match_parent" android:layout_height="1dp" android:background="#E5E5EA" android:layout_marginBottom="8dp"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etNovaPassword1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:hint="Nova Palavra-passe"
|
||||||
|
android:textColor="#1C1C1E"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:layout_marginBottom="8dp"/>
|
||||||
|
<View android:layout_width="match_parent" android:layout_height="1dp" android:background="#E5E5EA" android:layout_marginBottom="8dp"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etNovaPassword2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:hint="Confirma a Nova Palavra-passe"
|
||||||
|
android:textColor="#1C1C1E"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:inputType="textPassword"/>
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnConfirmarPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:text="Guardar Password"
|
||||||
|
android:backgroundTint="#03A9F4"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:cornerRadius="16dp"/>
|
||||||
|
</LinearLayout>
|
||||||
@@ -47,32 +47,15 @@
|
|||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:gravity="center_horizontal">
|
android:gravity="center_horizontal">
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
|
||||||
android:layout_width="120dp"
|
|
||||||
android:layout_height="120dp"
|
|
||||||
app:cardCornerRadius="60dp"
|
|
||||||
app:cardElevation="0dp"
|
|
||||||
app:cardBackgroundColor="#F2F2F7"
|
|
||||||
android:layout_marginTop="10dp">
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/ivFotoPerfil"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:src="@android:drawable/ic_menu_gallery"
|
|
||||||
android:scaleType="centerCrop"
|
|
||||||
android:padding="30dp"
|
|
||||||
app:tint="#C7C7CC"/>
|
|
||||||
</androidx.cardview.widget.CardView>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvPerfilNome"
|
android:id="@+id/tvPerfilNome"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Nome do Utilizador"
|
android:text="Nome do Utilizador"
|
||||||
android:textSize="22sp"
|
android:textSize="24sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textColor="#1C1C1E"
|
android:textColor="#1C1C1E"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="20dp"
|
||||||
android:layout_marginBottom="32dp"/>
|
android:layout_marginBottom="32dp"/>
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
<androidx.cardview.widget.CardView
|
||||||
@@ -81,51 +64,49 @@
|
|||||||
app:cardCornerRadius="24dp"
|
app:cardCornerRadius="24dp"
|
||||||
app:cardElevation="0dp"
|
app:cardElevation="0dp"
|
||||||
app:cardBackgroundColor="#F2F2F7"
|
app:cardBackgroundColor="#F2F2F7"
|
||||||
android:layout_marginBottom="32dp">
|
android:layout_marginBottom="24dp">
|
||||||
|
|
||||||
|
<!-- DEIXEI APENAS A SEQUÊNCIA AQUI NO MEIO -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:padding="20dp"
|
android:padding="20dp"
|
||||||
android:weightSum="3">
|
android:gravity="center">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:gravity="center">
|
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="⭐" android:textSize="24sp" android:layout_marginBottom="4dp"/>
|
|
||||||
<TextView android:id="@+id/tvPerfilPontos" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="1450" android:textSize="20sp" android:textStyle="bold" android:textColor="#1C1C1E"/>
|
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Pontos" android:textSize="12sp" android:textColor="#8E8E93"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<View android:layout_width="1dp" android:layout_height="match_parent" android:background="#E5E5EA" android:layout_marginVertical="8dp"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:gravity="center">
|
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="🏆" android:textSize="24sp" android:layout_marginBottom="4dp"/>
|
|
||||||
<TextView android:id="@+id/tvPerfilDesafios" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="28" android:textSize="20sp" android:textStyle="bold" android:textColor="#1C1C1E"/>
|
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Desafios" android:textSize="12sp" android:textColor="#8E8E93"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<View android:layout_width="1dp" android:layout_height="match_parent" android:background="#E5E5EA" android:layout_marginVertical="8dp"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:gravity="center">
|
android:gravity="center">
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="🔥" android:textSize="24sp" android:layout_marginBottom="4dp"/>
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="🔥" android:textSize="24sp" android:layout_marginBottom="4dp"/>
|
||||||
<TextView android:id="@+id/tvPerfilSequencia" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="5" android:textSize="20sp" android:textStyle="bold" android:textColor="#1C1C1E"/>
|
<TextView android:id="@+id/tvPerfilSequencia" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="1" android:textSize="20sp" android:textStyle="bold" android:textColor="#1C1C1E"/>
|
||||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Sequência" android:textSize="12sp" android:textColor="#8E8E93"/>
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Sequência" android:textSize="12sp" android:textColor="#8E8E93"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:cardCornerRadius="24dp"
|
||||||
|
app:cardElevation="0dp"
|
||||||
|
app:cardBackgroundColor="#F8FAFC"
|
||||||
|
android:layout_marginBottom="24dp">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="20dp">
|
||||||
|
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Email Registado" android:textSize="12sp" android:textColor="#8E8E93" android:textStyle="bold"/>
|
||||||
|
<TextView android:id="@+id/tvPerfilEmail" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="email@exemplo.com" android:textSize="16sp" android:textColor="#1C1C1E" android:layout_marginBottom="12dp" android:layout_marginTop="2dp"/>
|
||||||
|
|
||||||
|
<View android:layout_width="match_parent" android:layout_height="1dp" android:background="#E2E8F0" android:layout_marginBottom="12dp"/>
|
||||||
|
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Palavra-passe" android:textSize="12sp" android:textColor="#8E8E93" android:textStyle="bold"/>
|
||||||
|
<TextView android:id="@+id/tvPerfilPassword" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="********" android:textSize="16sp" android:textColor="#1C1C1E" android:layout_marginTop="2dp"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
@@ -133,7 +114,7 @@
|
|||||||
android:id="@+id/btnDefinicoes"
|
android:id="@+id/btnDefinicoes"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="60dp"
|
android:layout_height="60dp"
|
||||||
android:text="Definições da Conta"
|
android:text="Editar Conta"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textColor="#FFFFFF"
|
android:textColor="#FFFFFF"
|
||||||
|
|||||||
@@ -77,7 +77,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="55dp"
|
android:layout_height="55dp"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:hint="Password (mín. 6 letras)"
|
android:hint="Palavra-passe (mín. 6 letras)"
|
||||||
android:inputType="textPassword"
|
android:inputType="textPassword"
|
||||||
android:paddingStart="16dp"
|
android:paddingStart="16dp"
|
||||||
android:paddingEnd="16dp"/>
|
android:paddingEnd="16dp"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user