alteracoes precisas na app

This commit is contained in:
2026-02-24 17:17:47 +00:00
parent 421ba7c2e2
commit 337440eb91
4 changed files with 92 additions and 218 deletions

View File

@@ -46,6 +46,18 @@ public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Carregar preferência do Dark Mode
android.content.SharedPreferences prefs = getSharedPreferences("SettingsPrefs",
android.content.Context.MODE_PRIVATE);
boolean isDarkMode = prefs.getBoolean("dark_mode", false);
if (isDarkMode) {
androidx.appcompat.app.AppCompatDelegate
.setDefaultNightMode(androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES);
} else {
androidx.appcompat.app.AppCompatDelegate
.setDefaultNightMode(androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO);
}
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
@@ -155,37 +167,7 @@ public class MainActivity extends AppCompatActivity {
}
private void showChangeProfilePhotoDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Alterar Foto de Perfil");
String[] options = { "Escolher da Galeria", "Inserir URL" };
builder.setItems(options, (dialog, which) -> {
if (which == 0) {
mGetContent.launch("image/*");
} else {
showUrlDialog();
}
});
builder.show();
}
private void showUrlDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Inserir URL da Imagem");
final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
input.setHint("https://exemplo.com/foto.jpg");
builder.setView(input);
builder.setPositiveButton("OK", (dialog, which) -> {
String url = input.getText().toString();
if (!url.isEmpty()) {
updateUserProfile(Uri.parse(url));
}
});
builder.setNegativeButton("Cancelar", (dialog, which) -> dialog.cancel());
builder.show();
}
private void uploadImageToStorage(Uri imageUri) {

View File

@@ -46,10 +46,8 @@ public class ContaActivity extends AppCompatActivity {
private ImageView imageProfile;
private TextInputEditText editName;
private TextInputEditText editImageUrl;
private TextView textEmail;
private Button btnSaveAll;
private Button btnLoadImageUrl;
private Button btnChangeEmail;
private Button btnChangePassword;
private Button btnLogout;
@@ -64,7 +62,6 @@ public class ContaActivity extends AppCompatActivity {
private ActivityResultLauncher<Intent> imagePickerLauncher;
private ActivityResultLauncher<String> permissionLauncher;
private Uri selectedImageUri;
private String imageUrlFromGoogle;
private static final String PREFS_NAME = "LoginPrefs";
@@ -98,13 +95,10 @@ public class ContaActivity extends AppCompatActivity {
imageProfile = findViewById(R.id.imageProfile);
editName = findViewById(R.id.editName);
editImageUrl = findViewById(R.id.editImageUrl);
// textEmail removed from class fields if not used, or kept if used.
// In XML it is present as @+id/textEmail inside cardSecurity.
textEmail = findViewById(R.id.textEmail);
btnSaveAll = findViewById(R.id.btnSaveAll);
btnLoadImageUrl = findViewById(R.id.btnLoadImageUrl);
btnChangeEmail = findViewById(R.id.btnChangeEmail);
btnChangePassword = findViewById(R.id.btnChangePassword);
btnLogout = findViewById(R.id.btnLogout);
@@ -146,7 +140,7 @@ public class ContaActivity extends AppCompatActivity {
inputStream.close();
if (bitmap != null) {
imageProfile.setImageBitmap(bitmap);
uploadProfileImage();
// Não fazemos upload até clicar em Gravar
} else {
Toast.makeText(this, "Erro ao carregar imagem", Toast.LENGTH_SHORT).show();
}
@@ -250,9 +244,6 @@ public class ContaActivity extends AppCompatActivity {
if (btnSaveAll != null) {
btnSaveAll.setOnClickListener(v -> saveAllChanges());
}
if (btnLoadImageUrl != null) {
btnLoadImageUrl.setOnClickListener(v -> loadImageFromUrl());
}
if (btnChangeEmail != null) {
btnChangeEmail.setOnClickListener(v -> sendEmailVerificationForEmailChange());
}
@@ -279,100 +270,57 @@ public class ContaActivity extends AppCompatActivity {
}
}
private void loadImageFromUrl() {
if (editImageUrl == null)
private void saveAllChanges() {
if (editName == null)
return;
String imageUrl = editImageUrl.getText().toString().trim();
String newName = editName.getText().toString().trim();
if (imageUrl.isEmpty()) {
Toast.makeText(this, "Por favor, insira uma URL válida", Toast.LENGTH_SHORT).show();
if (newName.isEmpty() && selectedImageUri == null) {
Toast.makeText(this, "Nenhuma alteração a guardar", Toast.LENGTH_SHORT).show();
return;
}
if (!imageUrl.startsWith("http://") && !imageUrl.startsWith("https://")) {
Toast.makeText(this, "URL inválida. Deve começar com http:// ou https://", Toast.LENGTH_SHORT).show();
return;
}
progressDialog.show();
// Carregar imagem da URL
new Thread(() -> {
try {
java.net.URL url = new java.net.URL(imageUrl);
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(input);
runOnUiThread(() -> {
progressDialog.dismiss();
if (bitmap != null && imageProfile != null) {
imageProfile.setImageBitmap(bitmap);
// Guardar URL para usar diretamente no perfil
imageUrlFromGoogle = imageUrl;
// Atualizar perfil com a URL diretamente
updateProfileWithImageUrl(imageUrl);
} else {
Toast.makeText(this, "Erro ao carregar imagem da URL", Toast.LENGTH_SHORT).show();
}
});
if (input != null) {
input.close();
}
} catch (Exception e) {
runOnUiThread(() -> {
progressDialog.dismiss();
Toast.makeText(this, "Erro ao carregar imagem: " + e.getMessage(), Toast.LENGTH_SHORT).show();
});
}
}).start();
}
private void updateProfileWithImageUrl(String imageUrl) {
FirebaseUser user = mAuth.getCurrentUser();
if (user == null)
if (user == null) {
Toast.makeText(this, "Utilizador não autenticado", Toast.LENGTH_SHORT).show();
return;
}
progressDialog.show();
try {
Uri imageUri = Uri.parse(imageUrl);
// Se tiver foto nova, primeiro faz upload
if (selectedImageUri != null) {
uploadNewProfileImageAndSaveName(user, newName);
} else {
// Só muda o nome
saveNameOnly(user, newName);
}
}
private void saveNameOnly(FirebaseUser user, String newName) {
if (newName.isEmpty()) {
progressDialog.dismiss();
return; // Se não houver nome para trocar nem imagem, já barrámos em saveAllChanges.
}
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setPhotoUri(imageUri)
.setDisplayName(newName)
.build();
user.updateProfile(profileUpdates).addOnCompleteListener(task -> {
progressDialog.dismiss();
if (task.isSuccessful()) {
Toast.makeText(this, "Foto de perfil atualizada com sucesso!", Toast.LENGTH_SHORT).show();
editImageUrl.setText("");
loadProfileImage(imageUrl);
Toast.makeText(this, "Alterações guardadas com sucesso!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Erro ao atualizar foto: " +
Toast.makeText(this, "Erro ao guardar alterações: " +
(task.getException() != null ? task.getException().getMessage() : "Erro desconhecido"),
Toast.LENGTH_SHORT).show();
}
});
} catch (Exception e) {
progressDialog.dismiss();
Toast.makeText(this, "Erro ao processar URL: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
private void uploadProfileImage() {
if (selectedImageUri == null)
return;
FirebaseUser user = mAuth.getCurrentUser();
if (user == null)
return;
progressDialog.show();
private void uploadNewProfileImageAndSaveName(FirebaseUser user, String newName) {
InputStream inputStream = null;
try {
inputStream = getContentResolver().openInputStream(selectedImageUri);
@@ -389,7 +337,7 @@ public class ContaActivity extends AppCompatActivity {
return;
}
// Redimensionar se muito grande
// Redimensionar
int maxSize = 1024;
if (bitmap.getWidth() > maxSize || bitmap.getHeight() > maxSize) {
float scale = Math.min((float) maxSize / bitmap.getWidth(), (float) maxSize / bitmap.getHeight());
@@ -402,31 +350,32 @@ public class ContaActivity extends AppCompatActivity {
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, baos);
byte[] imageData = baos.toByteArray();
// Upload para Firebase Storage
StorageReference profileImageRef = storageRef.child("profile_images/" + user.getUid() + ".jpg");
UploadTask uploadTask = profileImageRef.putBytes(imageData);
uploadTask.addOnSuccessListener(taskSnapshot -> {
profileImageRef.getDownloadUrl().addOnSuccessListener(uri -> {
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setPhotoUri(uri)
.build();
UserProfileChangeRequest.Builder builder = new UserProfileChangeRequest.Builder();
builder.setPhotoUri(uri);
if (!newName.isEmpty()) {
builder.setDisplayName(newName);
}
UserProfileChangeRequest profileUpdates = builder.build();
user.updateProfile(profileUpdates).addOnCompleteListener(task -> {
progressDialog.dismiss();
if (task.isSuccessful()) {
Toast.makeText(this, "Foto de perfil atualizada com sucesso!", Toast.LENGTH_SHORT).show();
Toast.makeText(this, "As definições foram guardadas!", Toast.LENGTH_SHORT).show();
loadProfileImage(uri.toString());
selectedImageUri = null; // reset
} else {
Toast.makeText(this, "Erro ao atualizar foto: " +
(task.getException() != null ? task.getException().getMessage()
: "Erro desconhecido"),
Toast.LENGTH_SHORT).show();
Toast.makeText(this, "Erro ao atualizar perfil", Toast.LENGTH_SHORT).show();
}
});
}).addOnFailureListener(e -> {
progressDialog.dismiss();
Toast.makeText(this, "Erro ao obter URL da imagem: " + e.getMessage(), Toast.LENGTH_SHORT).show();
Toast.makeText(this, "Erro ao obter URL: " + e.getMessage(), Toast.LENGTH_SHORT).show();
});
}).addOnFailureListener(e -> {
progressDialog.dismiss();
@@ -435,53 +384,17 @@ public class ContaActivity extends AppCompatActivity {
} catch (Exception e) {
progressDialog.dismiss();
Toast.makeText(this, "Erro ao processar imagem: " + e.getMessage(), Toast.LENGTH_SHORT).show();
Toast.makeText(this, "Erro: " + e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (Exception e) {
// Ignorar erro ao fechar
}
}
}
}
private void saveAllChanges() {
if (editName == null)
return;
String newName = editName.getText().toString().trim();
if (newName.isEmpty()) {
Toast.makeText(this, "Por favor, insira um nome", Toast.LENGTH_SHORT).show();
return;
}
FirebaseUser user = mAuth.getCurrentUser();
if (user == null) {
Toast.makeText(this, "Utilizador não autenticado", Toast.LENGTH_SHORT).show();
return;
}
progressDialog.show();
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setDisplayName(newName)
.build();
user.updateProfile(profileUpdates).addOnCompleteListener(task -> {
progressDialog.dismiss();
if (task.isSuccessful()) {
Toast.makeText(this, "Alterações guardadas com sucesso!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Erro ao guardar alterações: " +
(task.getException() != null ? task.getException().getMessage() : "Erro desconhecido"),
Toast.LENGTH_SHORT).show();
}
});
}
private void sendPasswordResetEmail() {
FirebaseUser user = mAuth.getCurrentUser();
if (user == null || user.getEmail() == null) {

View File

@@ -30,6 +30,7 @@ public class DefinicoesFragment extends Fragment {
setupUi();
return binding.getRoot();
}
// teste
private void setupUi() {
binding.cardConta.setOnClickListener(new View.OnClickListener() {
@@ -44,14 +45,35 @@ public class DefinicoesFragment extends Fragment {
}
});
binding.switchNotifications.setOnCheckedChangeListener((buttonView, isChecked) ->
binding.textNotificationsStatus.setText(
binding.switchNotifications
.setOnCheckedChangeListener((buttonView, isChecked) -> binding.textNotificationsStatus.setText(
isChecked ? "Ativadas" : "Desativadas"));
binding.switchDarkMode.setOnCheckedChangeListener((buttonView, isChecked) ->
binding.textDarkModeStatus.setText(
isChecked ? "Ativo" : "Inativo"));
// Obter SharedPreferences
android.content.SharedPreferences prefs = requireActivity().getSharedPreferences("SettingsPrefs",
android.content.Context.MODE_PRIVATE);
boolean isDarkMode = prefs.getBoolean("dark_mode", false);
binding.switchDarkMode.setChecked(isDarkMode);
binding.textDarkModeStatus.setText(isDarkMode ? "Ativo" : "Inativo");
binding.switchDarkMode.setOnCheckedChangeListener((buttonView, isChecked) -> {
binding.textDarkModeStatus.setText(isChecked ? "Ativo" : "Inativo");
// Guardar preferência
android.content.SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("dark_mode", isChecked);
editor.apply();
// Aplicar modo escuro
if (isChecked) {
androidx.appcompat.app.AppCompatDelegate
.setDefaultNightMode(androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES);
} else {
androidx.appcompat.app.AppCompatDelegate
.setDefaultNightMode(androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO);
}
});
binding.btnOpenSystemSettings.setOnClickListener(v -> {
Intent intent = new Intent(Settings.ACTION_SETTINGS);
@@ -66,4 +88,3 @@ public class DefinicoesFragment extends Fragment {
binding = null;
}
}

View File

@@ -121,48 +121,6 @@
android:padding="8dp"
android:background="?attr/selectableItemBackgroundBorderless" />
<!-- URL Input Section -->
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:hint="URL da Imagem (Google)"
app:boxCornerRadiusTopStart="12dp"
app:boxCornerRadiusTopEnd="12dp"
app:boxCornerRadiusBottomStart="12dp"
app:boxCornerRadiusBottomEnd="12dp"
app:boxStrokeWidth="1dp"
app:boxStrokeColor="@color/divider"
app:startIconDrawable="@android:drawable/ic_menu_view"
app:startIconTint="@color/text_secondary"
app:boxBackgroundMode="outline"
style="@style/Widget.Material3.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editImageUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textUri"
android:textColor="@color/text_primary"
android:textColorHint="@color/text_secondary"
android:textSize="14sp"
android:padding="14dp"
android:background="@android:color/transparent"
android:hint="https://..." />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btnLoadImageUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:backgroundTint="@color/primary_light"
android:text="Carregar Imagem da URL"
android:textColor="@color/white"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>