diff --git a/app/src/main/java/com/fluxup/app/DailyProgress.java b/app/src/main/java/com/fluxup/app/DailyProgress.java index b2541b5..39a0d23 100644 --- a/app/src/main/java/com/fluxup/app/DailyProgress.java +++ b/app/src/main/java/com/fluxup/app/DailyProgress.java @@ -7,6 +7,7 @@ public class DailyProgress { public int focusSessions; public int xp; public String status; // "complete", "partial", "empty" + public boolean isGoalReached; public DailyProgress() {} @@ -17,10 +18,11 @@ public class DailyProgress { this.focusSessions = 0; this.xp = 0; this.status = "empty"; + this.isGoalReached = false; } public void updateStatus() { - if (completedTasks >= dailyGoal && dailyGoal > 0) { + if (isGoalReached || (completedTasks >= dailyGoal && dailyGoal > 0)) { status = "complete"; } else if (completedTasks > 0) { status = "partial"; diff --git a/app/src/main/java/com/fluxup/app/FirestoreManager.java b/app/src/main/java/com/fluxup/app/FirestoreManager.java index e12b2bb..ecce1d6 100644 --- a/app/src/main/java/com/fluxup/app/FirestoreManager.java +++ b/app/src/main/java/com/fluxup/app/FirestoreManager.java @@ -258,16 +258,55 @@ public class FirestoreManager { if ("focus_task".equals(type) || "task_manual_completion".equals(type)) { dp.completedTasks++; if ("focus_task".equals(type)) dp.focusSessions++; + } else if ("daily_goal_reached".equals(type)) { + dp.isGoalReached = true; } } } } - for (DailyProgress dp : progressMap.values()) { - dp.updateStatus(); - } + // Backup: Buscar tarefas concluídas para preencher lacunas nos logs + db.collection("tasks") + .whereEqualTo("userId", uid) + .whereEqualTo("completed", true) + .whereGreaterThanOrEqualTo("completedDate", startDate.getTime()) + .whereLessThanOrEqualTo("completedDate", endDate.getTime()) + .get() + .addOnSuccessListener(taskSnapshots -> { + if (taskSnapshots != null) { + Map tasksPerDay = new java.util.HashMap<>(); + for (com.google.firebase.firestore.QueryDocumentSnapshot doc : taskSnapshots) { + Long cDate = doc.getLong("completedDate"); + if (cDate != null) { + String dateStr = sdf.format(new java.util.Date(cDate)); + tasksPerDay.put(dateStr, tasksPerDay.getOrDefault(dateStr, 0) + 1); + } + } - callback.accept(progressMap); + for (Map.Entry entry : tasksPerDay.entrySet()) { + String dateStr = entry.getKey(); + int taskCount = entry.getValue(); + DailyProgress dp = progressMap.get(dateStr); + if (dp == null) { + dp = new DailyProgress(dateStr, dailyGoal); + progressMap.put(dateStr, dp); + } + // Usar o maior valor para garantir que não perdemos progresso + dp.completedTasks = Math.max(dp.completedTasks, taskCount); + } + } + + for (DailyProgress dp : progressMap.values()) { + dp.updateStatus(); + } + callback.accept(progressMap); + }) + .addOnFailureListener(e -> { + for (DailyProgress dp : progressMap.values()) { + dp.updateStatus(); + } + callback.accept(progressMap); + }); }) .addOnFailureListener(e -> { android.util.Log.e("FLUXUP_DEBUG", "DAILY_PROGRESS_QUERY_FAIL: " + e.getMessage()); @@ -300,7 +339,8 @@ public class FirestoreManager { // Check today String todayStr = sdf.format(checkCal.getTime()); DailyProgress todayDp = progressMap.get(todayStr); - boolean isTodayComplete = todayDp != null && todayDp.completedTasks >= dailyGoal; + if (todayDp != null) todayDp.updateStatus(); + boolean isTodayComplete = todayDp != null && "complete".equals(todayDp.status); if (isTodayComplete) { streak = 1; @@ -313,7 +353,8 @@ public class FirestoreManager { while (true) { String dateStr = sdf.format(checkCal.getTime()); DailyProgress dp = progressMap.get(dateStr); - if (dp != null && dp.completedTasks >= dailyGoal) { + if (dp != null) dp.updateStatus(); + if (dp != null && "complete".equals(dp.status)) { if (!dateStr.equals(todayStr)) streak++; checkCal.add(Calendar.DAY_OF_YEAR, -1); } else { diff --git a/app/src/main/java/com/fluxup/app/InicioFragment.java b/app/src/main/java/com/fluxup/app/InicioFragment.java index 3b90707..e753aef 100644 --- a/app/src/main/java/com/fluxup/app/InicioFragment.java +++ b/app/src/main/java/com/fluxup/app/InicioFragment.java @@ -223,7 +223,7 @@ public class InicioFragment extends Fragment { 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 -> { + FirestoreManager.getInstance().getDailyProgress(userId, startDate, endDate, user.meta_diaria_tarefas > 0 ? user.meta_diaria_tarefas : 4, progressMap -> { if (!isAdded()) return; java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.US); @@ -231,7 +231,7 @@ public class InicioFragment extends Fragment { DailyProgress todayDp = progressMap.get(todayStr); int completedTasksFromLogs = (todayDp != null) ? todayDp.completedTasks : 0; - int dailyGoal = user.meta_diaria_tarefas > 0 ? user.meta_diaria_tarefas : 3; + int dailyGoal = user.meta_diaria_tarefas > 0 ? user.meta_diaria_tarefas : 4; // 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); @@ -260,7 +260,7 @@ public class InicioFragment extends Fragment { tvTodayXP.setText(String.valueOf(user.xp)); } - // Atualizar Streak seguindo a regra: <3 -> 0, >=3 -> conta dia + // Atualizar Streak seguindo a regra: <4 -> 0, >=4 -> conta dia syncDailyStreak(user); android.util.Log.d("FLUXUP_DEBUG", "Streak atualizado: " + user.streak); @@ -296,7 +296,7 @@ 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 -> { + FirestoreManager.getInstance().getDailyProgress(user.id_usuario, startDate, endDate, user.meta_diaria_tarefas > 0 ? user.meta_diaria_tarefas : 4, progressMap -> { if (isAdded()) { updateProgressPath(progressMap, user); } @@ -392,7 +392,7 @@ public class InicioFragment extends Fragment { 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 dailyTaskGoal = user.meta_diaria_tarefas > 0 ? user.meta_diaria_tarefas : 4; int currentStreak = user.streak; String lastStreakDate = user.last_streak_completed_date; @@ -414,6 +414,9 @@ public class InicioFragment extends Fragment { updates.put("melhor_streak", newStreak); } FirestoreManager.getInstance().updateUserStats(user.id_usuario, updates); + + // NOVO: Adicionar log de conclusão permanente da meta + FirestoreManager.getInstance().addXpLog(user.id_usuario, 0, "daily_goal_reached"); // Atualizar objeto local user.streak = newStreak; @@ -432,7 +435,7 @@ public class InicioFragment extends Fragment { if (user == null) return; int completed = user.tasks_concluidas_hoje; int goal = user.meta_diaria_tarefas; - if (goal <= 0) goal = 3; // Default fallback + if (goal <= 0) goal = 4; // Default fallback // Sincronizar e mostrar streak syncDailyStreak(user); @@ -625,12 +628,16 @@ public class InicioFragment extends Fragment { // 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; + int dailyTaskGoal = (dp != null && dp.dailyGoal > 0) ? dp.dailyGoal : 4; + if (dailyTaskGoal <= 0) dailyTaskGoal = 4; // LÓGICA DE STATUS SOLICITADA String status = "empty"; - if (completedTasksForDay >= dailyTaskGoal) { + if (dp != null) dp.updateStatus(); + + if (dp != null && "complete".equals(dp.status)) { + status = "completed"; + } else if (completedTasksForDay >= dailyTaskGoal) { status = "completed"; } else if (isToday) { status = "today"; @@ -698,6 +705,7 @@ public class InicioFragment extends Fragment { private void completeTask(Task task) { task.completed = true; + task.completedDate = System.currentTimeMillis(); FirestoreManager.getInstance().updateTask(task); updateUserTaskCount(); triggerVibration(); @@ -709,7 +717,7 @@ public class InicioFragment extends Fragment { if (currentUser != null) { String uid = currentUser.getUid(); FirestoreManager.getInstance().getUser(uid, user -> { - if (user != null && isAdded()) { + if (user != null) { Map updates = new HashMap<>(); updates.put("tasks_concluidas_hoje", com.google.firebase.firestore.FieldValue.increment(1)); updates.put("total_tasks_concluidas", com.google.firebase.firestore.FieldValue.increment(1)); @@ -1045,11 +1053,6 @@ public class InicioFragment extends Fragment { FirestoreManager.getInstance().addXpLog(userId, finalXp, "focus_task", taskId); FirestoreManager.getInstance().getUser(userId, user -> { - if (!isAdded()) { - isCompletingFocus = false; - return; - } - if (user == null) { android.util.Log.e("FLUXUP_DEBUG", "FOCUS_COMPLETE_ERROR: User object null"); isCompletingFocus = false; diff --git a/app/src/main/java/com/fluxup/app/SearchFragment.java b/app/src/main/java/com/fluxup/app/SearchFragment.java index 064fa57..2b08c09 100644 --- a/app/src/main/java/com/fluxup/app/SearchFragment.java +++ b/app/src/main/java/com/fluxup/app/SearchFragment.java @@ -146,7 +146,7 @@ public class SearchFragment extends Fragment { cal.set(Calendar.SECOND, 59); Date endDate = cal.getTime(); - firestoreManager.getDailyProgress(currentUserId, startDate, endDate, 3, progressMap -> { + firestoreManager.getDailyProgress(currentUserId, startDate, endDate, 4, progressMap -> { updateChart(progressMap); }); diff --git a/app/src/main/java/com/fluxup/app/StreakActivity.java b/app/src/main/java/com/fluxup/app/StreakActivity.java index 7489194..ae98b75 100644 --- a/app/src/main/java/com/fluxup/app/StreakActivity.java +++ b/app/src/main/java/com/fluxup/app/StreakActivity.java @@ -36,7 +36,7 @@ public class StreakActivity extends AppCompatActivity { private Calendar currentCalendar; private String currentUserId; - private int currentDailyGoal = 3; + private int currentDailyGoal = 4; private Usuario currentUserObj; @Override @@ -92,7 +92,7 @@ public class StreakActivity extends AppCompatActivity { if (user != null && !isDestroyed()) { currentUserObj = user; tvStreakCount.setText(user.streak + " dias de ofensiva!"); - currentDailyGoal = user.meta_diaria_tarefas > 0 ? user.meta_diaria_tarefas : 3; + currentDailyGoal = user.meta_diaria_tarefas > 0 ? user.meta_diaria_tarefas : 4; loadMonthData(); } }); @@ -117,9 +117,10 @@ public class StreakActivity extends AppCompatActivity { java.util.Date endDate = endCal.getTime(); 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); + android.util.Log.d("FLUXUP_DEBUG", "OFFENSIVA_USER_ID: " + currentUserId); + android.util.Log.d("FLUXUP_DEBUG", "OFFENSIVA_MONTH_START: " + startDate); + android.util.Log.d("FLUXUP_DEBUG", "OFFENSIVA_MONTH_END: " + endDate); + android.util.Log.d("FLUXUP_DEBUG", "OFFENSIVA_CURRENT_DAILY_GOAL: " + currentDailyGoal); FirestoreManager.getInstance().getDailyProgress(currentUserId, startDate, endDate, currentDailyGoal, progressMap -> { if (isDestroyed()) return; @@ -127,11 +128,12 @@ public class StreakActivity extends AppCompatActivity { android.util.Log.d("FLUXUP_DEBUG", "OFFENSIVA_PROGRESS_DATA_SIZE: " + progressMap.size()); int focusSessionsCount = 0; - Map completedTasksPerDay = new HashMap<>(); + Map dailyProgressMap = new HashMap<>(); for (Map.Entry entry : progressMap.entrySet()) { DailyProgress dp = entry.getValue(); focusSessionsCount += dp.focusSessions; + android.util.Log.d("FLUXUP_DEBUG", "TASK_DATE: " + entry.getKey() + " | COMPLETED_TASKS: " + dp.completedTasks + " | GOAL: " + dp.dailyGoal + " | PERMANENT: " + dp.isGoalReached); String[] parts = entry.getKey().split("-"); if (parts.length == 3) { @@ -139,9 +141,8 @@ public class StreakActivity extends AppCompatActivity { 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); + dailyProgressMap.put(d, dp); } } } @@ -151,9 +152,14 @@ public class StreakActivity extends AppCompatActivity { 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); + DailyProgress dpToday = dailyProgressMap.get(todayDay); + if (dpToday == null) { + dpToday = new DailyProgress(year + "-" + (month + 1) + "-" + todayDay, currentDailyGoal); + dailyProgressMap.put(todayDay, dpToday); + } int userObjectToday = (currentUserObj != null) ? currentUserObj.tasks_concluidas_hoje : 0; - completedTasksPerDay.put(todayDay, Math.max(logsToday, userObjectToday)); + dpToday.completedTasks = Math.max(dpToday.completedTasks, userObjectToday); + dpToday.updateStatus(); } // Contar quantos dias no mês atingiram a meta @@ -162,20 +168,29 @@ public class StreakActivity extends AppCompatActivity { 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++; + DailyProgress dp = dailyProgressMap.get(d); + if (dp != null) { + dp.updateStatus(); + boolean isComplete = "complete".equals(dp.status); + if (isComplete) { + completedDaysCount++; + } + if (d == 6 || d == 11) { + android.util.Log.d("FLUXUP_DEBUG", "DAY_" + d + "_COMPLETED_TASKS: " + dp.completedTasks); + android.util.Log.d("FLUXUP_DEBUG", "DAY_" + d + "_IS_COMPLETED: " + isComplete); + } } } + android.util.Log.d("FLUXUP_DEBUG", "DIAS_CUMPRIDOS_COUNT: " + completedDaysCount); tvDaysOfPractice.setText(String.valueOf(completedDaysCount)); tvFocusSessions.setText(String.valueOf(focusSessionsCount)); - updateCalendar(completedTasksPerDay); + updateCalendar(dailyProgressMap); }); } - private void updateCalendar(Map completedTasksPerDay) { + private void updateCalendar(Map dailyProgressMap) { rvCalendar.setLayoutManager(new GridLayoutManager(this, 7)); List days = new ArrayList<>(); @@ -203,7 +218,6 @@ public class StreakActivity extends AppCompatActivity { boolean isCurrentMonth = (todayYear == calYear && todayMonth == calMonth); for (int i = 1; i <= maxDays; i++) { - int completed = completedTasksPerDay.getOrDefault(i, 0); boolean isCurrent = (isCurrentMonth && i == todayDay); boolean isFuture = false; @@ -217,18 +231,19 @@ public class StreakActivity extends AppCompatActivity { } } - // Regra: meta atingida -> complete (verde), caso contrário -> empty (cinzento) + // Regra: status do DailyProgress (respeita a meta permanente se existir) + DailyProgress dp = dailyProgressMap.get(i); String status = "empty"; - if (completed >= currentDailyGoal) { - status = "complete"; + if (dp != null) { + dp.updateStatus(); + status = dp.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")); + android.util.Log.d("FLUXUP_DEBUG", "DAY_6_STATUS: " + status); } - days.add(new CalendarDay(i, completed, isCurrent, isFuture, status)); + days.add(new CalendarDay(i, dp != null ? dp.completedTasks : 0, isCurrent, isFuture, status)); } CalendarAdapter adapter = new CalendarAdapter(days); diff --git a/app/src/main/java/com/fluxup/app/Usuario.java b/app/src/main/java/com/fluxup/app/Usuario.java index 90fa4af..0dbe5f3 100644 --- a/app/src/main/java/com/fluxup/app/Usuario.java +++ b/app/src/main/java/com/fluxup/app/Usuario.java @@ -27,7 +27,7 @@ public class Usuario { public int following = 0; public int tasks_concluidas_hoje = 0; public int total_tasks_concluidas = 0; - public int meta_diaria_tarefas = 3; + public int meta_diaria_tarefas = 4; public int meta_diaria_foco = 60; // em minutos public int tempo_foco_hoje = 0; // em minutos public int tempo_foco_total = 0; // em minutos diff --git a/app/src/main/res/drawable/circle_bg_light.xml b/app/src/main/res/drawable/circle_bg_light.xml new file mode 100644 index 0000000..c930bd5 --- /dev/null +++ b/app/src/main/res/drawable/circle_bg_light.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/src/main/res/layout/fragment_inicio.xml b/app/src/main/res/layout/fragment_inicio.xml index 8298917..e447de4 100644 --- a/app/src/main/res/layout/fragment_inicio.xml +++ b/app/src/main/res/layout/fragment_inicio.xml @@ -143,7 +143,7 @@ android:id="@+id/tvTodayTasksCount" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="0/3" + android:text="0/4" android:textStyle="bold" android:textSize="16sp" android:textColor="@color/success_green"/> diff --git a/app/src/main/res/layout/item_challenge.xml b/app/src/main/res/layout/item_challenge.xml new file mode 100644 index 0000000..19e70c4 --- /dev/null +++ b/app/src/main/res/layout/item_challenge.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + +