diff --git a/.idea/caches/deviceStreaming.xml b/.idea/caches/deviceStreaming.xml
index b38b9b7..8efc3b6 100644
--- a/.idea/caches/deviceStreaming.xml
+++ b/.idea/caches/deviceStreaming.xml
@@ -1230,6 +1230,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/fluxup/app/FirestoreManager.java b/app/src/main/java/com/fluxup/app/FirestoreManager.java
index e85beb1..e12b2bb 100644
--- a/app/src/main/java/com/fluxup/app/FirestoreManager.java
+++ b/app/src/main/java/com/fluxup/app/FirestoreManager.java
@@ -237,7 +237,7 @@ public class FirestoreManager {
.get()
.addOnSuccessListener(snapshots -> {
Map progressMap = new java.util.HashMap<>();
- java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.getDefault());
+ java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.US);
if (snapshots != null) {
for (com.google.firebase.firestore.QueryDocumentSnapshot doc : snapshots) {
@@ -294,7 +294,7 @@ public class FirestoreManager {
java.util.Collections.sort(sortedDates, java.util.Collections.reverseOrder());
int streak = 0;
- java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.getDefault());
+ java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.US);
Calendar checkCal = Calendar.getInstance();
// Check today
diff --git a/app/src/main/java/com/fluxup/app/InicioFragment.java b/app/src/main/java/com/fluxup/app/InicioFragment.java
index 7b7d7e2..ce5455b 100644
--- a/app/src/main/java/com/fluxup/app/InicioFragment.java
+++ b/app/src/main/java/com/fluxup/app/InicioFragment.java
@@ -56,6 +56,8 @@ public class InicioFragment extends Fragment {
private ListenerRegistration tasksListener, userListener, rankingListener;
private List currentTasks = new ArrayList<>();
private Task selectedTaskForFocus = null;
+ private TextView tvFocusPauseCount, tvFocusPenaltyWarning, tvFocusXpReward;
+ private int pauseCount = 0;
private boolean isCompletingFocus = false;
private boolean isTimerRunning = false;
@@ -74,6 +76,12 @@ public class InicioFragment extends Fragment {
};
+ @Override
+ public void onResume() {
+ super.onResume();
+ refreshTodayStats();
+ }
+
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@@ -117,6 +125,9 @@ public class InicioFragment extends Fragment {
tvTimer = view.findViewById(R.id.tvTimer);
tvFocusStatus = view.findViewById(R.id.tvFocusStatus);
tvFocusTitle = view.findViewById(R.id.tvFocusTitle);
+ tvFocusPauseCount = view.findViewById(R.id.tvFocusPauseCount);
+ tvFocusPenaltyWarning = view.findViewById(R.id.tvFocusPenaltyWarning);
+ tvFocusXpReward = view.findViewById(R.id.tvFocusXpReward);
btnStartFocus = view.findViewById(R.id.btnStartFocus);
btnSecondaryFocus = view.findViewById(R.id.btnSecondaryFocus);
@@ -182,36 +193,89 @@ public class InicioFragment extends Fragment {
if (tvGreeting != null) {
tvGreeting.setText("Olá, " + user.usuario + "!");
}
- if (tvTodayStreak != null) {
- syncDailyStreak(user);
- }
- refreshTodayStats(user);
- // Update Reward Button State
- String today = new java.text.SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new java.util.Date());
- boolean alreadyClaimed = today.equals(user.last_reward_claim_date);
+ refreshHomeStats();
- if (user.tasks_concluidas_hoje >= user.meta_diaria_tarefas && !alreadyClaimed) {
- btnClaimReward.setEnabled(true);
- btnClaimReward.setAlpha(1.0f);
- btnClaimReward.setText("Resgatar");
- } else if (alreadyClaimed) {
- btnClaimReward.setEnabled(false);
- btnClaimReward.setAlpha(0.5f);
- btnClaimReward.setText("Resgatado");
- } else {
- btnClaimReward.setEnabled(false);
- btnClaimReward.setAlpha(0.5f);
- btnClaimReward.setText("Resgatar");
- }
-
- updateTodayCard(user);
checkDailyResetAndStreak(user);
loadWeeklyProgress(user);
});
}
}
+ private void refreshHomeStats() {
+ FirebaseUser currentUser = AuthManager.getInstance().getCurrentUser();
+ if (currentUser == null) return;
+ String userId = currentUser.getUid();
+
+ android.util.Log.d("FLUXUP_DEBUG", "HOME_REFRESH_START");
+ android.util.Log.d("FLUXUP_DEBUG", "USER_ID: " + userId);
+
+ FirestoreManager.getInstance().getUser(userId, user -> {
+ if (user == null || !isAdded()) return;
+
+ Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.HOUR_OF_DAY, 0);
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ java.util.Date startDate = cal.getTime();
+
+ cal.add(Calendar.DAY_OF_MONTH, 1);
+ java.util.Date endDate = cal.getTime();
+
+ FirestoreManager.getInstance().getDailyProgress(userId, startDate, endDate, user.meta_diaria_tarefas > 0 ? user.meta_diaria_tarefas : 3, progressMap -> {
+ if (!isAdded()) return;
+
+ java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.US);
+ String todayStr = sdf.format(new java.util.Date());
+ DailyProgress todayDp = progressMap.get(todayStr);
+
+ int completedTasksFromLogs = (todayDp != null) ? todayDp.completedTasks : 0;
+ int dailyGoal = user.meta_diaria_tarefas > 0 ? user.meta_diaria_tarefas : 3;
+
+ // Usamos o maior valor entre o campo do usuário e os logs para evitar atrasos de indexação
+ int completedTasksToday = Math.max(user.tasks_concluidas_hoje, completedTasksFromLogs);
+
+ float progressValue = (float) completedTasksToday / dailyGoal;
+ if (progressValue > 1.0f) progressValue = 1.0f;
+
+ android.util.Log.d("FLUXUP_DEBUG", "PENDING_TASKS_TODAY_COUNT: " + currentTasks.size());
+ android.util.Log.d("FLUXUP_DEBUG", "completedTasksToday = " + completedTasksToday);
+ android.util.Log.d("FLUXUP_DEBUG", "DAILY_TASK_GOAL: " + dailyGoal);
+ android.util.Log.d("FLUXUP_DEBUG", "PROGRESS_VALUE: " + progressValue);
+ android.util.Log.d("FLUXUP_DEBUG", "XP_VALUE: " + user.xp);
+ android.util.Log.d("FLUXUP_DEBUG", "Meta diária atualizada");
+
+ // Sincronizar o contador no objeto user para o resto da UI
+ user.tasks_concluidas_hoje = completedTasksToday;
+
+ // Atualizar UI dos Contadores
+ if (tvTodayTasksCount != null) {
+ tvTodayTasksCount.setText(completedTasksToday + "/" + dailyGoal);
+ }
+ if (pbDailyTasksProgress != null) {
+ pbDailyTasksProgress.setProgress((int) (progressValue * 100));
+ }
+ if (tvTodayXP != null) {
+ tvTodayXP.setText(String.valueOf(user.xp));
+ }
+
+ // Atualizar Streak seguindo a regra: <3 -> 0, >=3 -> conta dia
+ syncDailyStreak(user);
+ android.util.Log.d("FLUXUP_DEBUG", "Streak atualizado: " + user.streak);
+
+ // Atualizar o histórico semanal
+ loadWeeklyProgress(user);
+
+ // Atualizar lista de tarefas (hider concluídas)
+ updateTasksUI();
+
+ android.util.Log.d("FLUXUP_DEBUG", "STREAK_VALUE: " + user.streak);
+ android.util.Log.d("FLUXUP_DEBUG", "HOME_REFRESH_DONE");
+ });
+ });
+ }
+
private void loadWeeklyProgress(Usuario user) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
@@ -233,14 +297,9 @@ public class InicioFragment extends Fragment {
android.util.Log.d("FLUXUP_DEBUG", "CURRENT_WEEK_RANGE: " + startDate + " to " + endDate);
FirestoreManager.getInstance().getDailyProgress(user.id_usuario, startDate, endDate, user.meta_diaria_tarefas > 0 ? user.meta_diaria_tarefas : 3, progressMap -> {
- if (!isAdded()) return;
-
- String todayStr = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.getDefault()).format(new java.util.Date());
- DailyProgress dpToday = progressMap.get(todayStr);
- android.util.Log.d("FLUXUP_DEBUG", "HOME_TODAY_COMPLETED_TASKS: " + (dpToday != null ? dpToday.completedTasks : 0));
-
- android.util.Log.d("FLUXUP_DEBUG", "HOME_PROGRESS_DATA: " + progressMap.size());
- updateProgressPath(progressMap);
+ if (isAdded()) {
+ updateProgressPath(progressMap, user);
+ }
});
}
@@ -248,29 +307,23 @@ public class InicioFragment extends Fragment {
if (tasksAdapter != null) {
tasksAdapter.setTasks(currentTasks);
}
- refreshTodayStats();
+
+ // Atualizar visibilidade das seções baseada no número de tarefas
+ if (currentTasks != null && !currentTasks.isEmpty()) {
+ if (layoutTasksSection != null) layoutTasksSection.setVisibility(View.VISIBLE);
+ if (tvNoTasksIncentive != null) tvNoTasksIncentive.setVisibility(View.GONE);
+ } else {
+ if (layoutTasksSection != null) layoutTasksSection.setVisibility(View.GONE);
+ if (tvNoTasksIncentive != null) tvNoTasksIncentive.setVisibility(View.VISIBLE);
+ }
}
private void refreshTodayStats() {
- FirebaseUser currentUser = AuthManager.getInstance().getCurrentUser();
- if (currentUser == null) return;
- FirestoreManager.getInstance().getUser(currentUser.getUid(), this::refreshTodayStats);
+ refreshHomeStats();
}
private void refreshTodayStats(Usuario user) {
- if (user == null || !isAdded()) return;
-
- // Update basic card info (Tasks, Progress)
- updateTodayCard(user);
-
- // Update XP specifically from logs
- FirestoreManager.getInstance().getTodayXp(user.id_usuario, todayXp -> {
- if (isAdded() && tvTodayXP != null) {
- tvTodayXP.setText(String.valueOf(todayXp));
- android.util.Log.d("FLUXUP_DEBUG", "XP_STATE_UPDATED: " + todayXp);
- android.util.Log.d("FLUXUP_DEBUG", "XP_VALUE_RENDERED_IN_CARD: " + todayXp);
- }
- });
+ refreshHomeStats();
}
private void selectTaskForFocus(Task task) {
@@ -337,7 +390,7 @@ public class InicioFragment extends Fragment {
private void syncDailyStreak(Usuario user) {
if (user == null) return;
- String today = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.getDefault()).format(new java.util.Date());
+ String today = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.US).format(new java.util.Date());
int completedTasksToday = user.tasks_concluidas_hoje;
int dailyTaskGoal = user.meta_diaria_tarefas > 0 ? user.meta_diaria_tarefas : 3;
int currentStreak = user.streak;
@@ -362,7 +415,7 @@ public class InicioFragment extends Fragment {
}
FirestoreManager.getInstance().updateUserStats(user.id_usuario, updates);
- // Atualizar objeto local para evitar loops ou UI atrasada
+ // Atualizar objeto local
user.streak = newStreak;
user.last_streak_completed_date = today;
} else {
@@ -370,16 +423,6 @@ public class InicioFragment extends Fragment {
}
}
- // Debug Logs solicitados
- android.util.Log.d("FLUXUP_STREAK_DEBUG", "--- syncDailyStreak ---");
- android.util.Log.d("FLUXUP_STREAK_DEBUG", "completedTasksToday = " + completedTasksToday);
- android.util.Log.d("FLUXUP_STREAK_DEBUG", "dailyTaskGoal = " + dailyTaskGoal);
- android.util.Log.d("FLUXUP_STREAK_DEBUG", "currentStreak = " + currentStreak);
- android.util.Log.d("FLUXUP_STREAK_DEBUG", "lastStreakDate = " + lastStreakDate);
- android.util.Log.d("FLUXUP_STREAK_DEBUG", "today = " + today);
- android.util.Log.d("FLUXUP_STREAK_DEBUG", "willIncrement = " + willIncrement);
- android.util.Log.d("FLUXUP_STREAK_DEBUG", "displayedStreak = " + displayedStreak);
-
if (tvTodayStreak != null) {
tvTodayStreak.setText(displayedStreak + " dias");
}
@@ -421,13 +464,13 @@ public class InicioFragment extends Fragment {
}
private void checkDailyResetAndStreak(Usuario user) {
- String today = new java.text.SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new java.util.Date());
+ String today = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.US).format(new java.util.Date());
if (!today.equals(user.last_active_date)) {
Map updates = new HashMap<>();
// Streak logic
if (!user.last_active_date.isEmpty()) {
- java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
+ java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.US);
try {
java.util.Date lastDate = sdf.parse(user.last_active_date);
java.util.Date todayDate = sdf.parse(today);
@@ -545,7 +588,7 @@ public class InicioFragment extends Fragment {
}
}
- private void updateProgressPath(Map progressMap) {
+ private void updateProgressPath(Map progressMap, Usuario user) {
if (getContext() == null || dayNodes == null || dayNodes.isEmpty()) return;
Calendar cal = Calendar.getInstance();
@@ -560,7 +603,7 @@ public class InicioFragment extends Fragment {
Calendar startCal = (Calendar) cal.clone();
startCal.add(Calendar.DAY_OF_YEAR, -daysToSubtract);
- java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
+ java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.US);
for (int i = 0; i < 7; i++) {
Calendar dayCal = (Calendar) startCal.clone();
@@ -575,43 +618,66 @@ public class InicioFragment extends Fragment {
ProgressBar nodeProgress = node.findViewById(R.id.nodeProgress);
View rightConnector = node.findViewById(R.id.rightConnector);
- if (dp != null && "complete".equals(dp.status)) {
+ // LÓGICA DE STATUS SOLICITADA
+ boolean isToday = (i == currentDayIndex);
+ int completedTasksFromLogs = (dp != null) ? dp.completedTasks : 0;
+
+ // Se for hoje, usamos o valor mais atualizado do objeto user
+ int completedTasksForDay = isToday ? Math.max(completedTasksFromLogs, (user != null ? user.tasks_concluidas_hoje : 0)) : completedTasksFromLogs;
+
+ int dailyTaskGoal = (dp != null && dp.dailyGoal > 0) ? dp.dailyGoal : 3;
+ if (dailyTaskGoal <= 0) dailyTaskGoal = 3;
+
+ String status = "empty";
+ if (completedTasksForDay >= dailyTaskGoal) {
+ status = "completed";
+ } else if (isToday) {
+ status = "today";
+ } else if (completedTasksForDay > 0) {
+ status = "partial";
+ }
+
+ android.util.Log.d("FLUXUP_DEBUG", "WEEK_DAY_DATE: " + dateStr);
+ android.util.Log.d("FLUXUP_DEBUG", "COMPLETED_TASKS_FOR_DAY: " + completedTasksForDay);
+ android.util.Log.d("FLUXUP_DEBUG", "DAILY_TASK_GOAL: " + dailyTaskGoal);
+ android.util.Log.d("FLUXUP_DEBUG", "IS_TODAY: " + isToday);
+ android.util.Log.d("FLUXUP_DEBUG", "DAY_STATUS: " + status);
+
+ // RENDERIZAÇÃO
+ if ("completed".equals(status)) {
nodeCircle.getBackground().setTint(ContextCompat.getColor(getContext(), R.color.success_green));
nodeDayInitial.setTextColor(ContextCompat.getColor(getContext(), R.color.white));
- } else if (dp != null && "partial".equals(dp.status)) {
+ if (rightConnector != null) {
+ // Verificação para conector verde (dia seguinte também completo)
+ Calendar nextDayCal = (Calendar) dayCal.clone();
+ nextDayCal.add(Calendar.DAY_OF_YEAR, 1);
+ DailyProgress nextDp = progressMap.get(sdf.format(nextDayCal.getTime()));
+ if (nextDp != null && nextDp.completedTasks >= nextDp.dailyGoal && nextDp.dailyGoal > 0) {
+ rightConnector.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.success_green));
+ } else {
+ rightConnector.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.border_color));
+ }
+ }
+ } else if ("today".equals(status)) {
+ nodeCircle.getBackground().setTint(ContextCompat.getColor(getContext(), R.color.primary_purple));
+ nodeDayInitial.setTextColor(ContextCompat.getColor(getContext(), R.color.white));
+ if (rightConnector != null) rightConnector.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.border_color));
+ } else if ("partial".equals(status)) {
nodeCircle.getBackground().setTint(android.graphics.Color.parseColor("#4FC3F7"));
nodeDayInitial.setTextColor(ContextCompat.getColor(getContext(), R.color.white));
+ if (rightConnector != null) rightConnector.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.border_color));
} else {
nodeCircle.getBackground().setTint(android.graphics.Color.parseColor("#E0E0E0"));
nodeDayInitial.setTextColor(ContextCompat.getColor(getContext(), R.color.text_primary));
+ if (rightConnector != null) rightConnector.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.border_color));
}
- // Streak connector color logic
- if (i < 6) {
- Calendar nextDayCal = (Calendar) dayCal.clone();
- nextDayCal.add(Calendar.DAY_OF_YEAR, 1);
- DailyProgress nextDp = progressMap.get(sdf.format(nextDayCal.getTime()));
- if (dp != null && "complete".equals(dp.status) && nextDp != null && "complete".equals(nextDp.status)) {
- rightConnector.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.success_green));
- } else {
- rightConnector.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.border_color));
- }
- }
-
- if (i == currentDayIndex) {
+ // Visibilidade de labels e progresso
+ if (isToday) {
nodeDayLabel.setVisibility(View.VISIBLE);
nodeDayLabel.setTextColor(ContextCompat.getColor(getContext(), R.color.primary_purple));
-
- if (dp == null || !"complete".equals(dp.status)) {
- nodeCircle.getBackground().setTint(ContextCompat.getColor(getContext(), R.color.primary_purple));
- nodeDayInitial.setTextColor(ContextCompat.getColor(getContext(), R.color.white));
- }
nodeProgress.setVisibility(View.VISIBLE);
- if (dp != null && dp.dailyGoal > 0) {
- nodeProgress.setProgress(dp.completedTasks * 100 / dp.dailyGoal);
- } else {
- nodeProgress.setProgress(0);
- }
+ nodeProgress.setProgress(completedTasksForDay * 100 / dailyTaskGoal);
} else {
nodeDayLabel.setVisibility(View.GONE);
nodeProgress.setVisibility(View.GONE);
@@ -706,7 +772,7 @@ public class InicioFragment extends Fragment {
private void claimDailyReward() {
FirebaseUser currentUser = AuthManager.getInstance().getCurrentUser();
if (currentUser != null) {
- String today = new java.text.SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new java.util.Date());
+ String today = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.US).format(new java.util.Date());
Map updates = new HashMap<>();
updates.put("last_reward_claim_date", today);
FirestoreManager.getInstance().updateUserStats(currentUser.getUid(), updates);
@@ -727,8 +793,9 @@ public class InicioFragment extends Fragment {
.setTitle("Eliminar Tarefa")
.setMessage("Tens a certeza que queres eliminar esta tarefa?")
.setNegativeButton("Cancelar", null)
- .setPositiveButton("Eliminar", (dialog, which) -> {
+ .setPositiveButton("Sim", (dialog, which) -> {
FirestoreManager.getInstance().deleteTask(task.id);
+ refreshHomeStats();
})
.show();
}
@@ -802,6 +869,10 @@ public class InicioFragment extends Fragment {
tvFocusStatus.setTextColor(ContextCompat.getColor(getContext(), R.color.text_secondary));
btnStartFocus.setText("Começar Foco");
btnSecondaryFocus.setVisibility(View.GONE);
+ tvFocusPauseCount.setVisibility(View.GONE);
+ tvFocusPenaltyWarning.setVisibility(View.GONE);
+ pauseCount = 0;
+ updateXpPenaltyUI();
break;
case RUNNING:
tvFocusStatus.setText("• EM FOCO");
@@ -809,6 +880,8 @@ public class InicioFragment extends Fragment {
btnStartFocus.setText("Pausar");
btnSecondaryFocus.setText("Concluir");
btnSecondaryFocus.setVisibility(View.VISIBLE);
+ tvFocusPauseCount.setVisibility(View.VISIBLE);
+ updateXpPenaltyUI();
break;
case PAUSED:
tvFocusStatus.setText("• PAUSADO");
@@ -816,10 +889,44 @@ public class InicioFragment extends Fragment {
btnStartFocus.setText("Continuar");
btnSecondaryFocus.setText("Cancelar");
btnSecondaryFocus.setVisibility(View.VISIBLE);
+ tvFocusPauseCount.setVisibility(View.VISIBLE);
+ updateXpPenaltyUI();
break;
}
}
+ private int calculateFocusXp() {
+ int baseXp = 50;
+ if (pauseCount <= 2) return baseXp;
+ int penalty = (pauseCount - 2) * 5;
+ return Math.max(10, baseXp - penalty);
+ }
+
+ private void updateXpPenaltyUI() {
+ if (tvFocusPauseCount != null) {
+ tvFocusPauseCount.setText("Pausas: " + pauseCount);
+ }
+
+ int currentXp = calculateFocusXp();
+ if (tvFocusXpReward != null) {
+ tvFocusXpReward.setText("+" + currentXp + " XP");
+ }
+
+ if (tvFocusPenaltyWarning != null) {
+ if (pauseCount > 2) {
+ tvFocusPenaltyWarning.setVisibility(View.VISIBLE);
+ int penalty = (pauseCount - 2) * 5;
+ if (currentXp > 10) {
+ tvFocusPenaltyWarning.setText("⚠ Muitas pausas: -" + penalty + " XP");
+ } else {
+ tvFocusPenaltyWarning.setText("⚠ Penalização de foco aplicada (Min 10 XP)");
+ }
+ } else {
+ tvFocusPenaltyWarning.setVisibility(View.GONE);
+ }
+ }
+ }
+
private void startTimer() {
if (selectedTaskForFocus == null) return;
@@ -846,6 +953,7 @@ public class InicioFragment extends Fragment {
if (countDownTimer != null) {
countDownTimer.cancel();
}
+ pauseCount++;
isTimerRunning = false;
updateFocusUI(FocusState.PAUSED);
}
@@ -919,14 +1027,17 @@ public class InicioFragment extends Fragment {
final Task task = selectedTaskForFocus;
final String taskId = task.id;
+ final int finalXp = calculateFocusXp();
android.util.Log.d("FLUXUP_DEBUG", "TASK_UPDATE_START");
task.completed = true;
+ task.completedDate = System.currentTimeMillis();
FirestoreManager.getInstance().updateTask(task, () -> {
+ android.util.Log.d("FLUXUP_DEBUG", "Tarefa concluída: " + taskId);
// Task update success is logged in FirestoreManager
android.util.Log.d("FLUXUP_DEBUG", "XP_LOG_INSERT_START");
- FirestoreManager.getInstance().addXpLog(userId, 50, "focus_task", taskId);
+ FirestoreManager.getInstance().addXpLog(userId, finalXp, "focus_task", taskId);
FirestoreManager.getInstance().getUser(userId, user -> {
if (!isAdded()) {
@@ -941,9 +1052,9 @@ public class InicioFragment extends Fragment {
}
Map updates = new HashMap<>();
- updates.put("xp", com.google.firebase.firestore.FieldValue.increment(50));
- updates.put("xp_hoje", com.google.firebase.firestore.FieldValue.increment(50));
- updates.put("xp_semanal", com.google.firebase.firestore.FieldValue.increment(50));
+ updates.put("xp", com.google.firebase.firestore.FieldValue.increment(finalXp));
+ updates.put("xp_hoje", com.google.firebase.firestore.FieldValue.increment(finalXp));
+ updates.put("xp_semanal", com.google.firebase.firestore.FieldValue.increment(finalXp));
updates.put("tempo_foco_total", com.google.firebase.firestore.FieldValue.increment(task.duration));
updates.put("tempo_foco_hoje", com.google.firebase.firestore.FieldValue.increment(task.duration));
updates.put("sessoes_foco_completas", com.google.firebase.firestore.FieldValue.increment(1));
@@ -952,25 +1063,25 @@ public class InicioFragment extends Fragment {
int currentLevel = user.level;
int threshold = (currentLevel * (currentLevel + 1) / 2) * 100;
- if (user.xp + 50 >= threshold) {
+ if (user.xp + finalXp >= threshold) {
updates.put("level", currentLevel + 1);
showLevelUpAnimation(currentLevel + 1);
}
FirestoreManager.getInstance().updateUserStats(userId, updates, () -> {
- android.util.Log.d("FLUXUP_DEBUG", "REFRESH_HOME_START");
- refreshTodayStats();
+ android.util.Log.d("FLUXUP_DEBUG", "FOCUS_COMPLETE_SUCCESS");
+ android.util.Log.d("FLUXUP_DEBUG", "CALLING_REFRESH_HOME_STATS");
if (isAdded()) {
- android.util.Log.d("FLUXUP_DEBUG", "HOME_STATE_UPDATED");
- Toast.makeText(getContext(), "Boa! Tarefa concluída +50 XP", Toast.LENGTH_LONG).show();
+ refreshHomeStats();
+ Toast.makeText(getContext(), "Boa! Tarefa concluída +" + finalXp + " XP", Toast.LENGTH_LONG).show();
triggerVibration();
selectedTaskForFocus = null;
timeLeftInMillis = 25 * 60 * 1000;
+ pauseCount = 0;
updateCountDownText();
updateFocusUI(FocusState.NOT_STARTED);
- android.util.Log.d("FLUXUP_DEBUG", "FOCUS_COMPLETE_SUCCESS");
}
isCompletingFocus = false;
});
@@ -1030,6 +1141,7 @@ public class InicioFragment extends Fragment {
}
private void showAddTaskDialog() {
+ android.util.Log.d("FLUXUP_DEBUG", "Botão clicado: showAddTaskDialog");
View dialogView = getLayoutInflater().inflate(R.layout.dialog_add_task, null);
android.widget.EditText etTitle = dialogView.findViewById(R.id.etTaskTitle);
android.widget.EditText etDuration = dialogView.findViewById(R.id.etTaskDuration);
@@ -1066,11 +1178,20 @@ public class InicioFragment extends Fragment {
}
private void saveNewTask(String title, int duration) {
+ android.util.Log.d("FLUXUP_DEBUG", "Criando tarefa: " + title);
FirebaseUser currentUser = AuthManager.getInstance().getCurrentUser();
- if (currentUser == null) return;
+ if (currentUser == null) {
+ android.util.Log.d("FLUXUP_DEBUG", "Erro ao salvar: Usuário nulo");
+ return;
+ }
String uid = currentUser.getUid();
String taskId = com.google.firebase.firestore.FirebaseFirestore.getInstance().collection("tasks").document().getId();
Task task = new Task(taskId, title, 30, duration, uid);
+
FirestoreManager.getInstance().addTask(task);
+ android.util.Log.d("FLUXUP_DEBUG", "Tarefa salva: " + taskId);
+
+ // Refresh local stats
+ refreshHomeStats();
}
}
diff --git a/app/src/main/java/com/fluxup/app/StreakActivity.java b/app/src/main/java/com/fluxup/app/StreakActivity.java
index 9a66e63..7489194 100644
--- a/app/src/main/java/com/fluxup/app/StreakActivity.java
+++ b/app/src/main/java/com/fluxup/app/StreakActivity.java
@@ -37,6 +37,7 @@ public class StreakActivity extends AppCompatActivity {
private Calendar currentCalendar;
private String currentUserId;
private int currentDailyGoal = 3;
+ private Usuario currentUserObj;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -89,6 +90,7 @@ public class StreakActivity extends AppCompatActivity {
private void loadUserData() {
FirestoreManager.getInstance().getUser(currentUserId, user -> {
if (user != null && !isDestroyed()) {
+ currentUserObj = user;
tvStreakCount.setText(user.streak + " dias de ofensiva!");
currentDailyGoal = user.meta_diaria_tarefas > 0 ? user.meta_diaria_tarefas : 3;
loadMonthData();
@@ -111,42 +113,62 @@ public class StreakActivity extends AppCompatActivity {
java.util.Date startDate = startCal.getTime();
Calendar endCal = (Calendar) startCal.clone();
- endCal.set(Calendar.DAY_OF_MONTH, startCal.getActualMaximum(Calendar.DAY_OF_MONTH));
- endCal.set(Calendar.HOUR_OF_DAY, 23);
- endCal.set(Calendar.MINUTE, 59);
- endCal.set(Calendar.SECOND, 59);
- endCal.set(Calendar.MILLISECOND, 999);
+ endCal.add(Calendar.MONTH, 1);
java.util.Date endDate = endCal.getTime();
- android.util.Log.d("FLUXUP_DEBUG", "CURRENT_MONTH_RANGE: " + startDate + " to " + endDate);
+ android.util.Log.d("FLUXUP_DEBUG", "OFFENSIVA_LOAD_MONTH_START");
+ android.util.Log.d("FLUXUP_DEBUG", "USER_ID: " + currentUserId);
+ android.util.Log.d("FLUXUP_DEBUG", "MONTH_START: " + startDate);
+ android.util.Log.d("FLUXUP_DEBUG", "MONTH_END: " + endDate);
FirestoreManager.getInstance().getDailyProgress(currentUserId, startDate, endDate, currentDailyGoal, progressMap -> {
if (isDestroyed()) return;
- android.util.Log.d("FLUXUP_DEBUG", "OFFENSIVA_PROGRESS_DATA: " + progressMap.size());
+ android.util.Log.d("FLUXUP_DEBUG", "OFFENSIVA_PROGRESS_DATA_SIZE: " + progressMap.size());
int focusSessionsCount = 0;
- int activeDaysCount = 0;
-
Map completedTasksPerDay = new HashMap<>();
for (Map.Entry entry : progressMap.entrySet()) {
DailyProgress dp = entry.getValue();
focusSessionsCount += dp.focusSessions;
- if (dp.completedTasks > 0) activeDaysCount++;
String[] parts = entry.getKey().split("-");
if (parts.length == 3) {
- int day = Integer.parseInt(parts[2]);
- completedTasksPerDay.put(day, dp.completedTasks);
- android.util.Log.d("FLUXUP_DEBUG", "COMPLETED_TASKS_BY_DATE: " + entry.getKey() + " -> " + dp.completedTasks);
- android.util.Log.d("FLUXUP_DEBUG", "DAY_STATUS_CALCULATED: " + entry.getKey() + " -> " + dp.status);
+ int y = Integer.parseInt(parts[0]);
+ int m = Integer.parseInt(parts[1]) - 1; // Calendar.MONTH is 0-indexed
+ int d = Integer.parseInt(parts[2]);
+
+ // Filtrar apenas para o mês e ano que estão a ser visualizados
+ if (y == year && m == month) {
+ completedTasksPerDay.put(d, dp.completedTasks);
+ }
}
}
- android.util.Log.d("FLUXUP_DEBUG", "OFFENSIVA_DAY_30_COMPLETED_TASKS: " + completedTasksPerDay.getOrDefault(30, 0));
+ // Aplicar o fallback seguro para HOJE usando o tasks_concluidas_hoje do utilizador
+ // devido a potenciais atrasos na indexação dos xp_logs com serverTimestamp
+ Calendar todayCal = Calendar.getInstance();
+ if (todayCal.get(Calendar.YEAR) == year && todayCal.get(Calendar.MONTH) == month) {
+ int todayDay = todayCal.get(Calendar.DAY_OF_MONTH);
+ int logsToday = completedTasksPerDay.getOrDefault(todayDay, 0);
+ int userObjectToday = (currentUserObj != null) ? currentUserObj.tasks_concluidas_hoje : 0;
+ completedTasksPerDay.put(todayDay, Math.max(logsToday, userObjectToday));
+ }
- tvDaysOfPractice.setText(String.valueOf(activeDaysCount));
+ // Contar quantos dias no mês atingiram a meta
+ int completedDaysCount = 0;
+ Calendar calcCal = (Calendar) currentCalendar.clone();
+ int maxDaysInMonth = calcCal.getActualMaximum(Calendar.DAY_OF_MONTH);
+
+ for (int d = 1; d <= maxDaysInMonth; d++) {
+ int completedTasks = completedTasksPerDay.getOrDefault(d, 0);
+ if (completedTasks >= currentDailyGoal) {
+ completedDaysCount++;
+ }
+ }
+
+ tvDaysOfPractice.setText(String.valueOf(completedDaysCount));
tvFocusSessions.setText(String.valueOf(focusSessionsCount));
updateCalendar(completedTasksPerDay);
@@ -180,58 +202,36 @@ public class StreakActivity extends AppCompatActivity {
boolean isCurrentMonth = (todayYear == calYear && todayMonth == calMonth);
- boolean started = false;
- int missedDaysInRow = 0;
-
for (int i = 1; i <= maxDays; i++) {
int completed = completedTasksPerDay.getOrDefault(i, 0);
boolean isCurrent = (isCurrentMonth && i == todayDay);
- boolean isPastOrToday = false;
boolean isFuture = false;
- if (calYear < todayYear) {
- isPastOrToday = true;
- } else if (calYear == todayYear) {
- if (calMonth < todayMonth) {
- isPastOrToday = true;
- } else if (calMonth == todayMonth) {
- if (i <= todayDay) isPastOrToday = true;
- else isFuture = true;
- } else {
- isFuture = true;
- }
- } else {
+ if (calYear > todayYear) {
isFuture = true;
- }
-
- boolean isComplete = completed >= currentDailyGoal;
- String status = "normal";
-
- if (isFuture) {
- status = "normal";
- } else if (isComplete) {
- started = true;
- missedDaysInRow = 0;
- status = "fire";
- } else if (!started) {
- status = "normal";
- } else {
- if (missedDaysInRow < 2) {
- missedDaysInRow++;
- status = "ice";
- } else {
- status = "normal";
+ } else if (calYear == todayYear) {
+ if (calMonth > todayMonth) {
+ isFuture = true;
+ } else if (calMonth == todayMonth) {
+ if (i > todayDay) isFuture = true;
}
}
-
- if (i == 30) {
- android.util.Log.d("FLUXUP_DEBUG", "OFFENSIVA_DAY_30_STATUS: " + status);
+
+ // Regra: meta atingida -> complete (verde), caso contrário -> empty (cinzento)
+ String status = "empty";
+ if (completed >= currentDailyGoal) {
+ status = "complete";
}
- days.add(new CalendarDay(i, completed, isCurrent, isPastOrToday, status));
+ if (i == 6 && isCurrentMonth) {
+ android.util.Log.d("FLUXUP_DEBUG", "DAY_6_COMPLETED_TASKS: " + completed);
+ android.util.Log.d("FLUXUP_DEBUG", "DAY_6_STATUS: " + (completed >= currentDailyGoal ? "COMPLETE" : "EMPTY"));
+ }
+
+ days.add(new CalendarDay(i, completed, isCurrent, isFuture, status));
}
- CalendarAdapter adapter = new CalendarAdapter(days, currentDailyGoal);
+ CalendarAdapter adapter = new CalendarAdapter(days);
rvCalendar.setAdapter(adapter);
}
@@ -241,25 +241,23 @@ public class StreakActivity extends AppCompatActivity {
int dayNumber;
int completedTasks;
boolean isCurrent;
- boolean isPastOrToday;
+ boolean isFuture;
String status;
- CalendarDay(int dayNumber, int completedTasks, boolean isCurrent, boolean isPastOrToday, String status) {
+ CalendarDay(int dayNumber, int completedTasks, boolean isCurrent, boolean isFuture, String status) {
this.dayNumber = dayNumber;
this.completedTasks = completedTasks;
this.isCurrent = isCurrent;
- this.isPastOrToday = isPastOrToday;
+ this.isFuture = isFuture;
this.status = status;
}
}
private class CalendarAdapter extends RecyclerView.Adapter {
private final List days;
- private final int dailyGoal;
- CalendarAdapter(List days, int dailyGoal) {
+ CalendarAdapter(List days) {
this.days = days;
- this.dailyGoal = dailyGoal;
}
@NonNull
@@ -283,40 +281,37 @@ public class StreakActivity extends AppCompatActivity {
holder.tvDayNumber.setText(String.valueOf(day.dayNumber));
if (holder.tvEmoji != null) holder.tvEmoji.setVisibility(View.GONE);
- if ("fire".equals(day.status)) {
- // AMARELO / FOGO
+ if (day.isFuture) {
+ // DIAS FUTUROS: CINZENTO CLARO
holder.dayBackground.setVisibility(View.VISIBLE);
- holder.dayBackground.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#FFB020")));
- holder.tvDayNumber.setTextColor(Color.BLACK);
+ holder.dayBackground.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#F5F5F5")));
+ holder.tvDayNumber.setTextColor(Color.parseColor("#BDBDBD"));
+ holder.streakConnector.setVisibility(View.GONE);
+ } else if ("complete".equals(day.status)) {
+ // META CUMPRIDA: VERDE
+ holder.dayBackground.setVisibility(View.VISIBLE);
+ holder.dayBackground.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#4CAF50")));
+ holder.tvDayNumber.setTextColor(Color.WHITE);
+ holder.streakConnector.setVisibility(View.GONE);
if (holder.tvEmoji != null) {
holder.tvEmoji.setVisibility(View.VISIBLE);
holder.tvEmoji.setText("🔥");
}
-
- if (position > 0 && "fire".equals(days.get(position-1).status) && days.get(position-1).dayNumber != 0) {
- holder.streakConnector.setVisibility(View.VISIBLE);
- holder.streakConnector.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#FFB020")));
- } else {
- holder.streakConnector.setVisibility(View.GONE);
- }
- } else if ("ice".equals(day.status)) {
- // AZUL / GELO
+ } else if (day.isCurrent) {
+ // HOJE SEM META: ROXO
holder.dayBackground.setVisibility(View.VISIBLE);
- holder.dayBackground.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#4FC3F7")));
+ holder.dayBackground.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#A35AFF")));
holder.tvDayNumber.setTextColor(Color.WHITE);
- if (holder.tvEmoji != null) {
- holder.tvEmoji.setVisibility(View.VISIBLE);
- holder.tvEmoji.setText("🧊");
- }
holder.streakConnector.setVisibility(View.GONE);
} else {
- // CINZENTO (NORMAL / FUTURO)
+ // META NÃO CUMPRIDA (PASSADO): CINZENTO
holder.dayBackground.setVisibility(View.VISIBLE);
holder.dayBackground.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#E0E0E0")));
holder.tvDayNumber.setTextColor(Color.BLACK);
holder.streakConnector.setVisibility(View.GONE);
}
+ // Opcional: indicador adicional para hoje
if (day.isCurrent) {
holder.dayIndicator.setVisibility(View.VISIBLE);
} else {
diff --git a/app/src/main/res/layout/activity_streak.xml b/app/src/main/res/layout/activity_streak.xml
index efd24c3..c9ff45d 100644
--- a/app/src/main/res/layout/activity_streak.xml
+++ b/app/src/main/res/layout/activity_streak.xml
@@ -200,7 +200,7 @@
+
+
+
+