adicionar loja
This commit is contained in:
24
.idea/caches/deviceStreaming.xml
generated
24
.idea/caches/deviceStreaming.xml
generated
@@ -922,6 +922,18 @@
|
||||
<option name="screenX" value="2208" />
|
||||
<option name="screenY" value="1840" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="36" />
|
||||
<option name="brand" value="google" />
|
||||
<option name="codename" value="felix" />
|
||||
<option name="id" value="felix" />
|
||||
<option name="labId" value="google" />
|
||||
<option name="manufacturer" value="Google" />
|
||||
<option name="name" value="Pixel Fold" />
|
||||
<option name="screenDensity" value="420" />
|
||||
<option name="screenX" value="2208" />
|
||||
<option name="screenY" value="1840" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="33" />
|
||||
<option name="brand" value="google" />
|
||||
@@ -1476,6 +1488,18 @@
|
||||
<option name="screenX" value="1440" />
|
||||
<option name="screenY" value="3120" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="36" />
|
||||
<option name="brand" value="samsung" />
|
||||
<option name="codename" value="q4qksx" />
|
||||
<option name="id" value="q4qksx" />
|
||||
<option name="labId" value="google" />
|
||||
<option name="manufacturer" value="Samsung" />
|
||||
<option name="name" value="Galaxy Z Fold4" />
|
||||
<option name="screenDensity" value="420" />
|
||||
<option name="screenX" value="1812" />
|
||||
<option name="screenY" value="2176" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="34" />
|
||||
<option name="brand" value="samsung" />
|
||||
|
||||
@@ -188,7 +188,7 @@ public class FindFriendsActivity extends AppCompatActivity {
|
||||
resultsContainer.removeAllViews();
|
||||
for (DocumentSnapshot doc : snapshots.getDocuments()) {
|
||||
Usuario u = doc.toObject(Usuario.class);
|
||||
if (u != null && !excludedIds.contains(u.id_usuario)) {
|
||||
if (u != null && u.public_profile && !u.incognito && !excludedIds.contains(u.id_usuario)) {
|
||||
addDiscoverItem(u);
|
||||
}
|
||||
}
|
||||
@@ -204,7 +204,7 @@ public class FindFriendsActivity extends AppCompatActivity {
|
||||
resultsContainer.removeAllViews();
|
||||
for (DocumentSnapshot doc : snapshots.getDocuments()) {
|
||||
Usuario u = doc.toObject(Usuario.class);
|
||||
if (u != null && !excludedIds.contains(u.id_usuario)) {
|
||||
if (u != null && u.public_profile && !u.incognito && !excludedIds.contains(u.id_usuario)) {
|
||||
addDiscoverItem(u);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,6 +145,28 @@ public class FirestoreManager {
|
||||
addXpLog(uid, amount, type, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adiciona moedas ao utilizador e regista a transação.
|
||||
*/
|
||||
public void addCoins(String uid, int amount, String reason) {
|
||||
if (uid == null) return;
|
||||
|
||||
// Atualizar saldo
|
||||
java.util.Map<String, Object> updates = new java.util.HashMap<>();
|
||||
updates.put("coins", com.google.firebase.firestore.FieldValue.increment(amount));
|
||||
updateUserStats(uid, updates);
|
||||
|
||||
// Registar transação
|
||||
java.util.Map<String, Object> log = new java.util.HashMap<>();
|
||||
log.put("userId", uid);
|
||||
log.put("amount", amount);
|
||||
log.put("reason", reason);
|
||||
log.put("created_at", com.google.firebase.firestore.FieldValue.serverTimestamp());
|
||||
db.collection("coin_logs").add(log)
|
||||
.addOnSuccessListener(ref -> android.util.Log.d("FLUXUP_DEBUG", "COIN_LOG_INSERT_SUCCESS"))
|
||||
.addOnFailureListener(e -> android.util.Log.e("FLUXUP_DEBUG", "COIN_LOG_INSERT_FAIL: " + e.getMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcula o XP total ganho hoje a partir dos logs.
|
||||
*/
|
||||
|
||||
@@ -22,10 +22,14 @@ public class FluxupApplication extends Application {
|
||||
|
||||
// Aplicar preferências de tema
|
||||
SharedPreferences prefs = getSharedPreferences("FluxupSettings", Context.MODE_PRIVATE);
|
||||
if (prefs.getBoolean("darkMode", false)) {
|
||||
boolean darkMode = prefs.getBoolean("dark_mode_enabled", false);
|
||||
Log.d(TAG, "APP_THEME_IS_DAYNIGHT | dark_mode_enabled=" + darkMode);
|
||||
if (darkMode) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
Log.d(TAG, "DARK_MODE_APPLIED | mode=MODE_NIGHT_YES");
|
||||
} else {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||
Log.d(TAG, "DARK_MODE_APPLIED | mode=MODE_NIGHT_NO");
|
||||
}
|
||||
|
||||
// Inicializar Firebase
|
||||
|
||||
@@ -385,6 +385,7 @@ public class InicioFragment extends Fragment {
|
||||
if (user.xp + amount >= threshold) {
|
||||
updates.put("level", currentLevel + 1);
|
||||
showLevelUpAnimation(currentLevel + 1);
|
||||
FirestoreManager.getInstance().addCoins(uid, 50, "level_up");
|
||||
}
|
||||
FirestoreManager.getInstance().updateUserStats(uid, updates);
|
||||
refreshTodayStats();
|
||||
@@ -527,8 +528,9 @@ public class InicioFragment extends Fragment {
|
||||
|
||||
// Login reward
|
||||
addXP(10);
|
||||
FirestoreManager.getInstance().addCoins(user.id_usuario, 10, "daily_login");
|
||||
if (getContext() != null) {
|
||||
Toast.makeText(getContext(), "Recompensa de login: +10 XP!", Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(getContext(), "Recompensa de login: +10 XP e +10 moedas!", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -537,14 +539,15 @@ public class InicioFragment extends Fragment {
|
||||
rankingListener = com.google.firebase.firestore.FirebaseFirestore.getInstance()
|
||||
.collection("users")
|
||||
.orderBy("xp_hoje", com.google.firebase.firestore.Query.Direction.DESCENDING)
|
||||
.limit(3)
|
||||
.limit(10)
|
||||
.addSnapshotListener((snapshots, e) -> {
|
||||
if (e != null || snapshots == null) return;
|
||||
miniRankingContainer.removeAllViews();
|
||||
int rank = 1;
|
||||
for (com.google.firebase.firestore.DocumentSnapshot doc : snapshots.getDocuments()) {
|
||||
if (rank > 3) break;
|
||||
Usuario u = doc.toObject(Usuario.class);
|
||||
if (u != null) {
|
||||
if (u != null && u.public_profile && !u.incognito) {
|
||||
addMiniRankingItem(rank++, u);
|
||||
}
|
||||
}
|
||||
@@ -743,6 +746,7 @@ public class InicioFragment extends Fragment {
|
||||
|
||||
// Adicionar log de XP mesmo em manual para permitir recálculo se necessário
|
||||
FirestoreManager.getInstance().addXpLog(uid, 0, "task_manual_completion");
|
||||
FirestoreManager.getInstance().addCoins(uid, 3, "task_completion");
|
||||
|
||||
FirestoreManager.getInstance().updateUserStats(uid, updates, () -> {
|
||||
if (isAdded()) refreshTodayStats();
|
||||
@@ -1064,6 +1068,7 @@ public class InicioFragment extends Fragment {
|
||||
|
||||
android.util.Log.d("FLUXUP_DEBUG", "XP_LOG_INSERT_START");
|
||||
FirestoreManager.getInstance().addXpLog(userId, finalXp, "focus_task", taskId);
|
||||
FirestoreManager.getInstance().addCoins(userId, 5, "focus_session");
|
||||
|
||||
FirestoreManager.getInstance().getUser(userId, user -> {
|
||||
if (user == null) {
|
||||
@@ -1087,6 +1092,7 @@ public class InicioFragment extends Fragment {
|
||||
if (user.xp + finalXp >= threshold) {
|
||||
updates.put("level", currentLevel + 1);
|
||||
showLevelUpAnimation(currentLevel + 1);
|
||||
FirestoreManager.getInstance().addCoins(userId, 50, "level_up");
|
||||
}
|
||||
|
||||
FirestoreManager.getInstance().updateUserStats(userId, updates, () -> {
|
||||
|
||||
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
android.content.SharedPreferences prefs = getSharedPreferences("FluxupSettings", android.content.Context.MODE_PRIVATE);
|
||||
|
||||
// Tema
|
||||
if (prefs.getBoolean("darkMode", false)) {
|
||||
if (prefs.getBoolean("dark_mode_enabled", false)) {
|
||||
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);
|
||||
|
||||
@@ -159,7 +159,7 @@ public class SearchFragment extends Fragment {
|
||||
List<Usuario> users = new ArrayList<>();
|
||||
for (com.google.firebase.firestore.DocumentSnapshot doc : snapshots) {
|
||||
Usuario u = doc.toObject(Usuario.class);
|
||||
if (u != null) users.add(u);
|
||||
if (u != null && u.public_profile && !u.incognito) users.add(u);
|
||||
}
|
||||
userAdapter.updateList(users);
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
@@ -22,13 +23,22 @@ import com.google.firebase.auth.FirebaseAuth;
|
||||
|
||||
public class SettingsActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = "DARK_MODE";
|
||||
|
||||
private SharedPreferences sharedPreferences;
|
||||
private static final String PREFS_NAME = "FluxupSettings";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
sharedPreferences = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||
|
||||
// Aplicar o modo escuro antes de criar a activity
|
||||
boolean isDarkMode = sharedPreferences.getBoolean("dark_mode_enabled", false);
|
||||
Log.d(TAG, "APP_THEME_IS_DAYNIGHT | dark_mode_enabled=" + isDarkMode);
|
||||
AppCompatDelegate.setDefaultNightMode(isDarkMode ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
|
||||
Log.d(TAG, "DARK_MODE_APPLIED | mode=" + (isDarkMode ? "MODE_NIGHT_YES" : "MODE_NIGHT_NO"));
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_settings);
|
||||
|
||||
initSettings();
|
||||
@@ -40,13 +50,33 @@ public class SettingsActivity extends AppCompatActivity {
|
||||
setupClickable(R.id.settingEditProfile, "Editar Perfil", "Nome, Bio, Avatar", v -> showEditProfileDialog());
|
||||
setupClickable(R.id.settingEmail, "Email", FirebaseAuth.getInstance().getCurrentUser().getEmail(), v -> showChangeEmailDialog());
|
||||
setupClickable(R.id.settingPassword, "Alterar Palavra-passe", "********", v -> resetPassword());
|
||||
setupSwitch(R.id.settingPublicProfile, "Perfil Público", "public_profile", true);
|
||||
setupSwitch(R.id.settingPublicProfile, "Perfil Público", "public_profile", true, (v, isChecked) -> {
|
||||
String uid = FirebaseAuth.getInstance().getUid();
|
||||
if (uid != null) {
|
||||
java.util.Map<String, Object> updates = new java.util.HashMap<>();
|
||||
updates.put("public_profile", isChecked);
|
||||
FirestoreManager.getInstance().updateUserStats(uid, updates);
|
||||
}
|
||||
});
|
||||
|
||||
// --- APARÊNCIA ---
|
||||
setupSwitch(R.id.settingDarkMode, "Modo Escuro", "darkMode", false, (v, isChecked) -> {
|
||||
AppCompatDelegate.setDefaultNightMode(isChecked ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
|
||||
setupSwitch(R.id.settingDarkMode, "Modo Escuro", "dark_mode_enabled", false, (v, isChecked) -> {
|
||||
Log.d(TAG, "DARK_MODE_SWITCH_CHANGED | isChecked=" + isChecked);
|
||||
// Guardar valor (feito pelo setupSwitch genérico, mas confirmamos aqui)
|
||||
sharedPreferences.edit().putBoolean("dark_mode_enabled", isChecked).apply();
|
||||
boolean saved = sharedPreferences.getBoolean("dark_mode_enabled", false);
|
||||
Log.d(TAG, "DARK_MODE_SAVED_VALUE | saved=" + saved);
|
||||
// Aplicar o modo globalmente
|
||||
AppCompatDelegate.setDefaultNightMode(
|
||||
isChecked ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO
|
||||
);
|
||||
Log.d(TAG, "DARK_MODE_APPLIED | mode=" + (isChecked ? "MODE_NIGHT_YES" : "MODE_NIGHT_NO"));
|
||||
// Recriar a Activity para aplicar o novo tema imediatamente
|
||||
recreate();
|
||||
});
|
||||
setupClickable(R.id.settingThemeColor, "Cor do Tema", "Roxo (Padrão)", null);
|
||||
|
||||
String themeColorValue = sharedPreferences.getString("theme_color", "purple");
|
||||
setupClickable(R.id.settingThemeColor, "Cor Principal da App", getColorLabel(themeColorValue), v -> showThemeColorDialog());
|
||||
|
||||
// --- NOTIFICAÇÕES ---
|
||||
setupSwitch(R.id.settingDailyReminders, "Lembretes Diários", "daily_reminders", true);
|
||||
@@ -58,17 +88,166 @@ public class SettingsActivity extends AppCompatActivity {
|
||||
setupSwitch(R.id.settingVibration, "Vibração ao Terminar", "vibration_on_finish", true);
|
||||
|
||||
// --- PRIVACIDADE ---
|
||||
setupSwitch(R.id.settingIncognito, "Modo Incógnito", "incognito", false);
|
||||
setupClickable(R.id.settingExportData, "Exportar Dados", "JSON/CSV", null);
|
||||
setupSwitch(R.id.settingIncognito, "Modo Incógnito", "incognito", false, (v, isChecked) -> {
|
||||
String uid = FirebaseAuth.getInstance().getUid();
|
||||
if (uid != null) {
|
||||
java.util.Map<String, Object> updates = new java.util.HashMap<>();
|
||||
updates.put("incognito", isChecked);
|
||||
FirestoreManager.getInstance().updateUserStats(uid, updates);
|
||||
}
|
||||
});
|
||||
setupClickable(R.id.settingExportData, "Exportar Dados", "JSON/CSV", v -> exportUserData());
|
||||
|
||||
findViewById(R.id.btnDeleteAccount).setOnClickListener(v -> {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Eliminar Conta")
|
||||
.setMessage("Tens a certeza? Todos os teus dados serão apagados permanentemente.")
|
||||
.setNegativeButton("Cancelar", null)
|
||||
.setPositiveButton("Sim, Eliminar", (dialog, which) -> deleteAccount())
|
||||
.setPositiveButton("Sim, Eliminar", (dialog, which) -> {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Confirmação Final")
|
||||
.setMessage("Esta ação é irreversível e apagará TODO o teu histórico e progresso. Tens a certeza absoluta?")
|
||||
.setNegativeButton("Cancelar", null)
|
||||
.setPositiveButton("Eliminar Definitivamente", (dialog2, which2) -> deleteAccount())
|
||||
.show();
|
||||
})
|
||||
.show();
|
||||
});
|
||||
|
||||
// Sync initial values from Firestore
|
||||
String uid = FirebaseAuth.getInstance().getUid();
|
||||
if (uid != null) {
|
||||
FirestoreManager.getInstance().getUser(uid, user -> {
|
||||
if (user != null) {
|
||||
sharedPreferences.edit()
|
||||
.putBoolean("public_profile", user.public_profile)
|
||||
.putBoolean("incognito", user.incognito)
|
||||
.putInt("focus_duration", user.meta_diaria_foco)
|
||||
.apply();
|
||||
|
||||
updateClickableValue(R.id.settingFocusDuration, user.meta_diaria_foco + " min");
|
||||
|
||||
SwitchMaterial swPublic = findViewById(R.id.settingPublicProfile).findViewById(R.id.switchSetting);
|
||||
if (swPublic != null) swPublic.setChecked(user.public_profile);
|
||||
|
||||
SwitchMaterial swIncognito = findViewById(R.id.settingIncognito).findViewById(R.id.switchSetting);
|
||||
if (swIncognito != null) swIncognito.setChecked(user.incognito);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void updateClickableValue(int id, String value) {
|
||||
View view = findViewById(id);
|
||||
if (view != null) {
|
||||
TextView tvValue = view.findViewById(R.id.tvSettingValue);
|
||||
if (tvValue != null) tvValue.setText(value);
|
||||
}
|
||||
}
|
||||
|
||||
private String getColorLabel(String key) {
|
||||
switch (key) {
|
||||
case "blue": return "Azul";
|
||||
case "green": return "Verde";
|
||||
case "orange": return "Laranja";
|
||||
case "red": return "Vermelho";
|
||||
case "purple":
|
||||
default:
|
||||
return "Roxo (Padrão)";
|
||||
}
|
||||
}
|
||||
|
||||
private void showThemeColorDialog() {
|
||||
String[] colors = {"Roxo (Padrão)", "Azul", "Verde", "Laranja", "Vermelho"};
|
||||
String[] keys = {"purple", "blue", "green", "orange", "red"};
|
||||
|
||||
String currentColor = sharedPreferences.getString("theme_color", "purple");
|
||||
int checkedItem = 0;
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
if (keys[i].equals(currentColor)) {
|
||||
checkedItem = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Escolher Cor Principal")
|
||||
.setSingleChoiceItems(colors, checkedItem, (dialog, which) -> {
|
||||
String selectedKey = keys[which];
|
||||
sharedPreferences.edit().putString("theme_color", selectedKey).apply();
|
||||
updateClickableValue(R.id.settingThemeColor, colors[which]);
|
||||
Toast.makeText(this, "Cor do tema atualizada!", Toast.LENGTH_SHORT).show();
|
||||
dialog.dismiss();
|
||||
})
|
||||
.setNegativeButton("Cancelar", null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void exportUserData() {
|
||||
String uid = FirebaseAuth.getInstance().getUid();
|
||||
if (uid == null) {
|
||||
Toast.makeText(this, "Utilizador não autenticado", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.makeText(this, "A exportar dados...", Toast.LENGTH_SHORT).show();
|
||||
|
||||
FirestoreManager.getInstance().getUser(uid, user -> {
|
||||
if (user == null) {
|
||||
Toast.makeText(this, "Erro ao obter dados do utilizador", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
com.google.firebase.firestore.FirebaseFirestore.getInstance()
|
||||
.collection("tasks")
|
||||
.whereEqualTo("userId", uid)
|
||||
.get()
|
||||
.addOnSuccessListener(queryDocumentSnapshots -> {
|
||||
try {
|
||||
org.json.JSONObject exportObj = new org.json.JSONObject();
|
||||
|
||||
org.json.JSONObject profileObj = new org.json.JSONObject();
|
||||
profileObj.put("usuario", user.usuario);
|
||||
profileObj.put("email", user.email);
|
||||
profileObj.put("level", user.level);
|
||||
profileObj.put("xp", user.xp);
|
||||
profileObj.put("streak", user.streak);
|
||||
profileObj.put("melhor_streak", user.melhor_streak);
|
||||
profileObj.put("total_tasks_concluidas", user.total_tasks_concluidas);
|
||||
profileObj.put("tempo_foco_total_minutos", user.tempo_foco_total);
|
||||
exportObj.put("perfil", profileObj);
|
||||
|
||||
org.json.JSONArray tasksArray = new org.json.JSONArray();
|
||||
for (com.google.firebase.firestore.DocumentSnapshot doc : queryDocumentSnapshots.getDocuments()) {
|
||||
org.json.JSONObject taskObj = new org.json.JSONObject();
|
||||
taskObj.put("id", doc.getId());
|
||||
taskObj.put("title", doc.getString("title"));
|
||||
taskObj.put("duration", doc.getLong("duration"));
|
||||
taskObj.put("completed", doc.getBoolean("completed"));
|
||||
Long completedDate = doc.getLong("completedDate");
|
||||
taskObj.put("completedDate", completedDate != null ? completedDate : 0);
|
||||
tasksArray.put(taskObj);
|
||||
}
|
||||
exportObj.put("tarefas", tasksArray);
|
||||
|
||||
String jsonString = exportObj.toString(4);
|
||||
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, jsonString);
|
||||
sendIntent.setType("text/plain");
|
||||
|
||||
Intent shareIntent = Intent.createChooser(sendIntent, "Exportar Dados Fluxup");
|
||||
startActivity(shareIntent);
|
||||
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(SettingsActivity.this, "Erro ao exportar: " + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
})
|
||||
.addOnFailureListener(e -> {
|
||||
Toast.makeText(SettingsActivity.this, "Erro ao obter tarefas: " + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void setupClickable(int id, String title, String value, View.OnClickListener listener) {
|
||||
@@ -149,29 +328,48 @@ public class SettingsActivity extends AppCompatActivity {
|
||||
|
||||
private void deleteAccount() {
|
||||
String uid = FirebaseAuth.getInstance().getUid();
|
||||
com.google.firebase.firestore.FirebaseFirestore.getInstance().collection("users").document(uid).delete();
|
||||
FirebaseAuth.getInstance().getCurrentUser().delete()
|
||||
com.google.firebase.firestore.FirebaseFirestore.getInstance().collection("users").document(uid).delete()
|
||||
.addOnSuccessListener(aVoid -> {
|
||||
Intent intent = new Intent(this, LoginActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
startActivity(intent);
|
||||
FirebaseAuth.getInstance().getCurrentUser().delete()
|
||||
.addOnSuccessListener(aVoid2 -> {
|
||||
Intent intent = new Intent(this, LoginActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
startActivity(intent);
|
||||
})
|
||||
.addOnFailureListener(e -> {
|
||||
Toast.makeText(this, "Erro ao eliminar autenticação: " + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
});
|
||||
})
|
||||
.addOnFailureListener(e -> {
|
||||
Toast.makeText(this, "Erro ao eliminar dados da conta: " + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
});
|
||||
}
|
||||
|
||||
private void showDurationDialog(String key, String title, int current) {
|
||||
EditText input = new EditText(this);
|
||||
input.setInputType(android.text.InputType.TYPE_CLASS_NUMBER);
|
||||
input.setText(String.valueOf(sharedPreferences.getInt(key, current)));
|
||||
View dialogView = getLayoutInflater().inflate(R.layout.dialog_duration_picker, null);
|
||||
TextView tvTitle = dialogView.findViewById(R.id.tvDurationTitle);
|
||||
tvTitle.setText(title);
|
||||
|
||||
com.google.android.material.textfield.TextInputLayout til = dialogView.findViewById(R.id.tilDuration);
|
||||
til.setHint("Minutos");
|
||||
|
||||
com.google.android.material.textfield.TextInputEditText etDuration = dialogView.findViewById(R.id.etDuration);
|
||||
etDuration.setText(String.valueOf(sharedPreferences.getInt(key, current)));
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(title)
|
||||
.setView(input)
|
||||
.setView(dialogView)
|
||||
.setPositiveButton("Guardar", (dialog, which) -> {
|
||||
try {
|
||||
int val = Integer.parseInt(input.getText().toString());
|
||||
String valStr = etDuration.getText().toString();
|
||||
if (valStr.isEmpty()) return;
|
||||
int val = Integer.parseInt(valStr);
|
||||
if (val <= 0) {
|
||||
Toast.makeText(this, "A duração deve ser superior a zero", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
sharedPreferences.edit().putInt(key, val).apply();
|
||||
updateClickableValue(key.equals("focus_duration") ? R.id.settingFocusDuration : R.id.settingBreakDuration, val + " min");
|
||||
|
||||
// Also update in Firestore if user is logged in
|
||||
String uid = FirebaseAuth.getInstance().getUid();
|
||||
if (uid != null) {
|
||||
java.util.Map<String, Object> updates = new java.util.HashMap<>();
|
||||
@@ -179,7 +377,7 @@ public class SettingsActivity extends AppCompatActivity {
|
||||
FirestoreManager.getInstance().updateUserStats(uid, updates);
|
||||
}
|
||||
|
||||
recreate();
|
||||
Toast.makeText(this, "Duração atualizada!", Toast.LENGTH_SHORT).show();
|
||||
} catch (Exception e) {}
|
||||
})
|
||||
.setNegativeButton("Cancelar", null)
|
||||
|
||||
@@ -39,6 +39,8 @@ public class Usuario {
|
||||
public String avatar_url = "";
|
||||
public AvatarData avatar = new AvatarData(); // Avatar gamificado
|
||||
public java.util.List<String> dias_concluidos = new java.util.ArrayList<>();
|
||||
public boolean public_profile = true;
|
||||
public boolean incognito = false;
|
||||
|
||||
// Gamification & Rewards
|
||||
public int login_streak = 0;
|
||||
@@ -48,6 +50,8 @@ public class Usuario {
|
||||
public java.util.List<String> claimed_streak_rewards = new java.util.ArrayList<>();
|
||||
public String last_box_open_date = ""; // YYYY-MM-DD
|
||||
public int coins = 0;
|
||||
public java.util.List<String> unlockedItems = new java.util.ArrayList<>();
|
||||
public java.util.Map<String, Integer> inventory = new java.util.HashMap<>();
|
||||
|
||||
public Usuario() {}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
<androidx.cardview.widget.CardView style="@style/SettingsCard">
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical">
|
||||
<include layout="@layout/item_settings_switch" android:id="@+id/settingDarkMode" />
|
||||
<include layout="@layout/item_settings_clickable" android:id="@+id/settingThemeColor" />
|
||||
<include layout="@layout/item_settings_clickable" android:id="@+id/settingThemeColor" android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -102,21 +102,22 @@
|
||||
<androidx.cardview.widget.CardView style="@style/SettingsCard">
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical">
|
||||
<include layout="@layout/item_settings_switch" android:id="@+id/settingIncognito" />
|
||||
<include layout="@layout/item_settings_clickable" android:id="@+id/settingExportData" />
|
||||
<include layout="@layout/item_settings_clickable" android:id="@+id/settingExportData" android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<!-- Danger Zone -->
|
||||
<Button
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnDeleteAccount"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="Eliminar Conta"
|
||||
android:textColor="@color/error_red"
|
||||
android:backgroundTint="#10EF4444"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_marginBottom="40dp"/>
|
||||
android:textColor="@color/white"
|
||||
app:backgroundTint="@color/error_red"
|
||||
app:cornerRadius="12dp"
|
||||
android:layout_marginBottom="40dp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
@@ -1,17 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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="64dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:paddingHorizontal="16dp">
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingVertical="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSettingTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/tvSettingValue"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="Configuração"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp" />
|
||||
@@ -20,9 +27,11 @@
|
||||
android:id="@+id/tvSettingValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toStartOf="@id/ivChevron"
|
||||
app:layout_constraintEnd_toStartOf="@id/ivChevron"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:layout_goneMarginEnd="0dp"
|
||||
android:text="Valor"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="14sp" />
|
||||
@@ -31,16 +40,11 @@
|
||||
android:id="@+id/ivChevron"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:src="@drawable/ic_back"
|
||||
android:rotation="180"
|
||||
android:alpha="0.3" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:background="@color/border_color"
|
||||
android:layout_marginStart="16dp" />
|
||||
</RelativeLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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="64dp"
|
||||
android:paddingHorizontal="16dp">
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingVertical="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSettingTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/switchSetting"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="Configuração"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp" />
|
||||
@@ -18,14 +24,9 @@
|
||||
android:id="@+id/switchSetting"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:useMaterialThemeColors="true" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:background="@color/border_color"
|
||||
android:layout_marginStart="16dp" />
|
||||
</RelativeLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
<item name="colorSecondary">#FACC15</item>
|
||||
<item name="colorSecondaryVariant">#FACC15</item>
|
||||
<item name="colorOnSecondary">#11181C</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor">#F9FAFB</item>
|
||||
<!-- Status bar color. Uses @color/background_light so values-night can override -->
|
||||
<item name="android:statusBarColor">@color/background_light</item>
|
||||
<item name="android:windowLightStatusBar" tools:targetApi="M">true</item>
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="android:windowBackground">#F9FAFB</item>
|
||||
<!-- Window background. Uses @color/background_light so values-night can override -->
|
||||
<item name="android:windowBackground">@color/background_light</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user