melhorar o calendario

This commit is contained in:
MeuNome
2026-05-06 12:42:58 +01:00
parent 2c7d1a854f
commit 64f317c073
6 changed files with 334 additions and 186 deletions

View File

@@ -1230,6 +1230,18 @@
<option name="screenX" value="1080" /> <option name="screenX" value="1080" />
<option name="screenY" value="2400" /> <option name="screenY" value="2400" />
</PersistentDeviceSelectionData> </PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="36" />
<option name="brand" value="samsung" />
<option name="codename" value="m2q" />
<option name="id" value="m2q" />
<option name="labId" value="google" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S26+" />
<option name="screenDensity" value="450" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData> <PersistentDeviceSelectionData>
<option name="api" value="34" /> <option name="api" value="34" />
<option name="brand" value="motorola" /> <option name="brand" value="motorola" />

View File

@@ -237,7 +237,7 @@ public class FirestoreManager {
.get() .get()
.addOnSuccessListener(snapshots -> { .addOnSuccessListener(snapshots -> {
Map<String, DailyProgress> progressMap = new java.util.HashMap<>(); Map<String, DailyProgress> 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) { if (snapshots != null) {
for (com.google.firebase.firestore.QueryDocumentSnapshot doc : snapshots) { for (com.google.firebase.firestore.QueryDocumentSnapshot doc : snapshots) {
@@ -294,7 +294,7 @@ public class FirestoreManager {
java.util.Collections.sort(sortedDates, java.util.Collections.reverseOrder()); java.util.Collections.sort(sortedDates, java.util.Collections.reverseOrder());
int streak = 0; 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(); Calendar checkCal = Calendar.getInstance();
// Check today // Check today

View File

@@ -56,6 +56,8 @@ public class InicioFragment extends Fragment {
private ListenerRegistration tasksListener, userListener, rankingListener; private ListenerRegistration tasksListener, userListener, rankingListener;
private List<Task> currentTasks = new ArrayList<>(); private List<Task> currentTasks = new ArrayList<>();
private Task selectedTaskForFocus = null; private Task selectedTaskForFocus = null;
private TextView tvFocusPauseCount, tvFocusPenaltyWarning, tvFocusXpReward;
private int pauseCount = 0;
private boolean isCompletingFocus = false; private boolean isCompletingFocus = false;
private boolean isTimerRunning = false; private boolean isTimerRunning = false;
@@ -74,6 +76,12 @@ public class InicioFragment extends Fragment {
}; };
@Override
public void onResume() {
super.onResume();
refreshTodayStats();
}
@Nullable @Nullable
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 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); tvTimer = view.findViewById(R.id.tvTimer);
tvFocusStatus = view.findViewById(R.id.tvFocusStatus); tvFocusStatus = view.findViewById(R.id.tvFocusStatus);
tvFocusTitle = view.findViewById(R.id.tvFocusTitle); 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); btnStartFocus = view.findViewById(R.id.btnStartFocus);
btnSecondaryFocus = view.findViewById(R.id.btnSecondaryFocus); btnSecondaryFocus = view.findViewById(R.id.btnSecondaryFocus);
@@ -182,36 +193,89 @@ public class InicioFragment extends Fragment {
if (tvGreeting != null) { if (tvGreeting != null) {
tvGreeting.setText("Olá, " + user.usuario + "!"); tvGreeting.setText("Olá, " + user.usuario + "!");
} }
if (tvTodayStreak != null) {
syncDailyStreak(user);
}
refreshTodayStats(user);
// Update Reward Button State refreshHomeStats();
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);
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); checkDailyResetAndStreak(user);
loadWeeklyProgress(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) { private void loadWeeklyProgress(Usuario user) {
Calendar cal = Calendar.getInstance(); Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0); 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); 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 : 3, progressMap -> {
if (!isAdded()) return; if (isAdded()) {
updateProgressPath(progressMap, user);
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);
}); });
} }
@@ -248,29 +307,23 @@ public class InicioFragment extends Fragment {
if (tasksAdapter != null) { if (tasksAdapter != null) {
tasksAdapter.setTasks(currentTasks); 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() { private void refreshTodayStats() {
FirebaseUser currentUser = AuthManager.getInstance().getCurrentUser(); refreshHomeStats();
if (currentUser == null) return;
FirestoreManager.getInstance().getUser(currentUser.getUid(), this::refreshTodayStats);
} }
private void refreshTodayStats(Usuario user) { private void refreshTodayStats(Usuario user) {
if (user == null || !isAdded()) return; refreshHomeStats();
// 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);
}
});
} }
private void selectTaskForFocus(Task task) { private void selectTaskForFocus(Task task) {
@@ -337,7 +390,7 @@ public class InicioFragment extends Fragment {
private void syncDailyStreak(Usuario user) { private void syncDailyStreak(Usuario user) {
if (user == null) return; 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 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 : 3;
int currentStreak = user.streak; int currentStreak = user.streak;
@@ -362,7 +415,7 @@ public class InicioFragment extends Fragment {
} }
FirestoreManager.getInstance().updateUserStats(user.id_usuario, updates); FirestoreManager.getInstance().updateUserStats(user.id_usuario, updates);
// Atualizar objeto local para evitar loops ou UI atrasada // Atualizar objeto local
user.streak = newStreak; user.streak = newStreak;
user.last_streak_completed_date = today; user.last_streak_completed_date = today;
} else { } 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) { if (tvTodayStreak != null) {
tvTodayStreak.setText(displayedStreak + " dias"); tvTodayStreak.setText(displayedStreak + " dias");
} }
@@ -421,13 +464,13 @@ public class InicioFragment extends Fragment {
} }
private void checkDailyResetAndStreak(Usuario user) { 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)) { if (!today.equals(user.last_active_date)) {
Map<String, Object> updates = new HashMap<>(); Map<String, Object> updates = new HashMap<>();
// Streak logic // Streak logic
if (!user.last_active_date.isEmpty()) { 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 { try {
java.util.Date lastDate = sdf.parse(user.last_active_date); java.util.Date lastDate = sdf.parse(user.last_active_date);
java.util.Date todayDate = sdf.parse(today); java.util.Date todayDate = sdf.parse(today);
@@ -545,7 +588,7 @@ public class InicioFragment extends Fragment {
} }
} }
private void updateProgressPath(Map<String, DailyProgress> progressMap) { private void updateProgressPath(Map<String, DailyProgress> progressMap, Usuario user) {
if (getContext() == null || dayNodes == null || dayNodes.isEmpty()) return; if (getContext() == null || dayNodes == null || dayNodes.isEmpty()) return;
Calendar cal = Calendar.getInstance(); Calendar cal = Calendar.getInstance();
@@ -560,7 +603,7 @@ public class InicioFragment extends Fragment {
Calendar startCal = (Calendar) cal.clone(); Calendar startCal = (Calendar) cal.clone();
startCal.add(Calendar.DAY_OF_YEAR, -daysToSubtract); 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++) { for (int i = 0; i < 7; i++) {
Calendar dayCal = (Calendar) startCal.clone(); Calendar dayCal = (Calendar) startCal.clone();
@@ -575,43 +618,66 @@ public class InicioFragment extends Fragment {
ProgressBar nodeProgress = node.findViewById(R.id.nodeProgress); ProgressBar nodeProgress = node.findViewById(R.id.nodeProgress);
View rightConnector = node.findViewById(R.id.rightConnector); 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)); nodeCircle.getBackground().setTint(ContextCompat.getColor(getContext(), R.color.success_green));
nodeDayInitial.setTextColor(ContextCompat.getColor(getContext(), R.color.white)); 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")); nodeCircle.getBackground().setTint(android.graphics.Color.parseColor("#4FC3F7"));
nodeDayInitial.setTextColor(ContextCompat.getColor(getContext(), R.color.white)); nodeDayInitial.setTextColor(ContextCompat.getColor(getContext(), R.color.white));
if (rightConnector != null) rightConnector.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.border_color));
} else { } else {
nodeCircle.getBackground().setTint(android.graphics.Color.parseColor("#E0E0E0")); nodeCircle.getBackground().setTint(android.graphics.Color.parseColor("#E0E0E0"));
nodeDayInitial.setTextColor(ContextCompat.getColor(getContext(), R.color.text_primary)); 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 // Visibilidade de labels e progresso
if (i < 6) { if (isToday) {
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) {
nodeDayLabel.setVisibility(View.VISIBLE); nodeDayLabel.setVisibility(View.VISIBLE);
nodeDayLabel.setTextColor(ContextCompat.getColor(getContext(), R.color.primary_purple)); 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); nodeProgress.setVisibility(View.VISIBLE);
if (dp != null && dp.dailyGoal > 0) { nodeProgress.setProgress(completedTasksForDay * 100 / dailyTaskGoal);
nodeProgress.setProgress(dp.completedTasks * 100 / dp.dailyGoal);
} else {
nodeProgress.setProgress(0);
}
} else { } else {
nodeDayLabel.setVisibility(View.GONE); nodeDayLabel.setVisibility(View.GONE);
nodeProgress.setVisibility(View.GONE); nodeProgress.setVisibility(View.GONE);
@@ -706,7 +772,7 @@ public class InicioFragment extends Fragment {
private void claimDailyReward() { private void claimDailyReward() {
FirebaseUser currentUser = AuthManager.getInstance().getCurrentUser(); FirebaseUser currentUser = AuthManager.getInstance().getCurrentUser();
if (currentUser != null) { 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<String, Object> updates = new HashMap<>(); Map<String, Object> updates = new HashMap<>();
updates.put("last_reward_claim_date", today); updates.put("last_reward_claim_date", today);
FirestoreManager.getInstance().updateUserStats(currentUser.getUid(), updates); FirestoreManager.getInstance().updateUserStats(currentUser.getUid(), updates);
@@ -727,8 +793,9 @@ public class InicioFragment extends Fragment {
.setTitle("Eliminar Tarefa") .setTitle("Eliminar Tarefa")
.setMessage("Tens a certeza que queres eliminar esta tarefa?") .setMessage("Tens a certeza que queres eliminar esta tarefa?")
.setNegativeButton("Cancelar", null) .setNegativeButton("Cancelar", null)
.setPositiveButton("Eliminar", (dialog, which) -> { .setPositiveButton("Sim", (dialog, which) -> {
FirestoreManager.getInstance().deleteTask(task.id); FirestoreManager.getInstance().deleteTask(task.id);
refreshHomeStats();
}) })
.show(); .show();
} }
@@ -802,6 +869,10 @@ public class InicioFragment extends Fragment {
tvFocusStatus.setTextColor(ContextCompat.getColor(getContext(), R.color.text_secondary)); tvFocusStatus.setTextColor(ContextCompat.getColor(getContext(), R.color.text_secondary));
btnStartFocus.setText("Começar Foco"); btnStartFocus.setText("Começar Foco");
btnSecondaryFocus.setVisibility(View.GONE); btnSecondaryFocus.setVisibility(View.GONE);
tvFocusPauseCount.setVisibility(View.GONE);
tvFocusPenaltyWarning.setVisibility(View.GONE);
pauseCount = 0;
updateXpPenaltyUI();
break; break;
case RUNNING: case RUNNING:
tvFocusStatus.setText("• EM FOCO"); tvFocusStatus.setText("• EM FOCO");
@@ -809,6 +880,8 @@ public class InicioFragment extends Fragment {
btnStartFocus.setText("Pausar"); btnStartFocus.setText("Pausar");
btnSecondaryFocus.setText("Concluir"); btnSecondaryFocus.setText("Concluir");
btnSecondaryFocus.setVisibility(View.VISIBLE); btnSecondaryFocus.setVisibility(View.VISIBLE);
tvFocusPauseCount.setVisibility(View.VISIBLE);
updateXpPenaltyUI();
break; break;
case PAUSED: case PAUSED:
tvFocusStatus.setText("• PAUSADO"); tvFocusStatus.setText("• PAUSADO");
@@ -816,10 +889,44 @@ public class InicioFragment extends Fragment {
btnStartFocus.setText("Continuar"); btnStartFocus.setText("Continuar");
btnSecondaryFocus.setText("Cancelar"); btnSecondaryFocus.setText("Cancelar");
btnSecondaryFocus.setVisibility(View.VISIBLE); btnSecondaryFocus.setVisibility(View.VISIBLE);
tvFocusPauseCount.setVisibility(View.VISIBLE);
updateXpPenaltyUI();
break; 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() { private void startTimer() {
if (selectedTaskForFocus == null) return; if (selectedTaskForFocus == null) return;
@@ -846,6 +953,7 @@ public class InicioFragment extends Fragment {
if (countDownTimer != null) { if (countDownTimer != null) {
countDownTimer.cancel(); countDownTimer.cancel();
} }
pauseCount++;
isTimerRunning = false; isTimerRunning = false;
updateFocusUI(FocusState.PAUSED); updateFocusUI(FocusState.PAUSED);
} }
@@ -919,14 +1027,17 @@ public class InicioFragment extends Fragment {
final Task task = selectedTaskForFocus; final Task task = selectedTaskForFocus;
final String taskId = task.id; final String taskId = task.id;
final int finalXp = calculateFocusXp();
android.util.Log.d("FLUXUP_DEBUG", "TASK_UPDATE_START"); android.util.Log.d("FLUXUP_DEBUG", "TASK_UPDATE_START");
task.completed = true; task.completed = true;
task.completedDate = System.currentTimeMillis();
FirestoreManager.getInstance().updateTask(task, () -> { FirestoreManager.getInstance().updateTask(task, () -> {
android.util.Log.d("FLUXUP_DEBUG", "Tarefa concluída: " + taskId);
// Task update success is logged in FirestoreManager // Task update success is logged in FirestoreManager
android.util.Log.d("FLUXUP_DEBUG", "XP_LOG_INSERT_START"); 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 -> { FirestoreManager.getInstance().getUser(userId, user -> {
if (!isAdded()) { if (!isAdded()) {
@@ -941,9 +1052,9 @@ public class InicioFragment extends Fragment {
} }
Map<String, Object> updates = new HashMap<>(); Map<String, Object> updates = new HashMap<>();
updates.put("xp", 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(50)); updates.put("xp_hoje", com.google.firebase.firestore.FieldValue.increment(finalXp));
updates.put("xp_semanal", com.google.firebase.firestore.FieldValue.increment(50)); 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_total", com.google.firebase.firestore.FieldValue.increment(task.duration));
updates.put("tempo_foco_hoje", 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)); 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 currentLevel = user.level;
int threshold = (currentLevel * (currentLevel + 1) / 2) * 100; int threshold = (currentLevel * (currentLevel + 1) / 2) * 100;
if (user.xp + 50 >= threshold) { if (user.xp + finalXp >= threshold) {
updates.put("level", currentLevel + 1); updates.put("level", currentLevel + 1);
showLevelUpAnimation(currentLevel + 1); showLevelUpAnimation(currentLevel + 1);
} }
FirestoreManager.getInstance().updateUserStats(userId, updates, () -> { FirestoreManager.getInstance().updateUserStats(userId, updates, () -> {
android.util.Log.d("FLUXUP_DEBUG", "REFRESH_HOME_START"); android.util.Log.d("FLUXUP_DEBUG", "FOCUS_COMPLETE_SUCCESS");
refreshTodayStats(); android.util.Log.d("FLUXUP_DEBUG", "CALLING_REFRESH_HOME_STATS");
if (isAdded()) { if (isAdded()) {
android.util.Log.d("FLUXUP_DEBUG", "HOME_STATE_UPDATED"); refreshHomeStats();
Toast.makeText(getContext(), "Boa! Tarefa concluída +50 XP", Toast.LENGTH_LONG).show(); Toast.makeText(getContext(), "Boa! Tarefa concluída +" + finalXp + " XP", Toast.LENGTH_LONG).show();
triggerVibration(); triggerVibration();
selectedTaskForFocus = null; selectedTaskForFocus = null;
timeLeftInMillis = 25 * 60 * 1000; timeLeftInMillis = 25 * 60 * 1000;
pauseCount = 0;
updateCountDownText(); updateCountDownText();
updateFocusUI(FocusState.NOT_STARTED); updateFocusUI(FocusState.NOT_STARTED);
android.util.Log.d("FLUXUP_DEBUG", "FOCUS_COMPLETE_SUCCESS");
} }
isCompletingFocus = false; isCompletingFocus = false;
}); });
@@ -1030,6 +1141,7 @@ public class InicioFragment extends Fragment {
} }
private void showAddTaskDialog() { private void showAddTaskDialog() {
android.util.Log.d("FLUXUP_DEBUG", "Botão clicado: showAddTaskDialog");
View dialogView = getLayoutInflater().inflate(R.layout.dialog_add_task, null); View dialogView = getLayoutInflater().inflate(R.layout.dialog_add_task, null);
android.widget.EditText etTitle = dialogView.findViewById(R.id.etTaskTitle); android.widget.EditText etTitle = dialogView.findViewById(R.id.etTaskTitle);
android.widget.EditText etDuration = dialogView.findViewById(R.id.etTaskDuration); 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) { private void saveNewTask(String title, int duration) {
android.util.Log.d("FLUXUP_DEBUG", "Criando tarefa: " + title);
FirebaseUser currentUser = AuthManager.getInstance().getCurrentUser(); 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 uid = currentUser.getUid();
String taskId = com.google.firebase.firestore.FirebaseFirestore.getInstance().collection("tasks").document().getId(); String taskId = com.google.firebase.firestore.FirebaseFirestore.getInstance().collection("tasks").document().getId();
Task task = new Task(taskId, title, 30, duration, uid); Task task = new Task(taskId, title, 30, duration, uid);
FirestoreManager.getInstance().addTask(task); FirestoreManager.getInstance().addTask(task);
android.util.Log.d("FLUXUP_DEBUG", "Tarefa salva: " + taskId);
// Refresh local stats
refreshHomeStats();
} }
} }

View File

@@ -37,6 +37,7 @@ public class StreakActivity extends AppCompatActivity {
private Calendar currentCalendar; private Calendar currentCalendar;
private String currentUserId; private String currentUserId;
private int currentDailyGoal = 3; private int currentDailyGoal = 3;
private Usuario currentUserObj;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@@ -89,6 +90,7 @@ public class StreakActivity extends AppCompatActivity {
private void loadUserData() { private void loadUserData() {
FirestoreManager.getInstance().getUser(currentUserId, user -> { FirestoreManager.getInstance().getUser(currentUserId, user -> {
if (user != null && !isDestroyed()) { if (user != null && !isDestroyed()) {
currentUserObj = user;
tvStreakCount.setText(user.streak + " dias de ofensiva!"); 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 : 3;
loadMonthData(); loadMonthData();
@@ -111,42 +113,62 @@ public class StreakActivity extends AppCompatActivity {
java.util.Date startDate = startCal.getTime(); java.util.Date startDate = startCal.getTime();
Calendar endCal = (Calendar) startCal.clone(); Calendar endCal = (Calendar) startCal.clone();
endCal.set(Calendar.DAY_OF_MONTH, startCal.getActualMaximum(Calendar.DAY_OF_MONTH)); endCal.add(Calendar.MONTH, 1);
endCal.set(Calendar.HOUR_OF_DAY, 23);
endCal.set(Calendar.MINUTE, 59);
endCal.set(Calendar.SECOND, 59);
endCal.set(Calendar.MILLISECOND, 999);
java.util.Date endDate = endCal.getTime(); 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 -> { FirestoreManager.getInstance().getDailyProgress(currentUserId, startDate, endDate, currentDailyGoal, progressMap -> {
if (isDestroyed()) return; 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 focusSessionsCount = 0;
int activeDaysCount = 0;
Map<Integer, Integer> completedTasksPerDay = new HashMap<>(); Map<Integer, Integer> completedTasksPerDay = new HashMap<>();
for (Map.Entry<String, DailyProgress> entry : progressMap.entrySet()) { for (Map.Entry<String, DailyProgress> entry : progressMap.entrySet()) {
DailyProgress dp = entry.getValue(); DailyProgress dp = entry.getValue();
focusSessionsCount += dp.focusSessions; focusSessionsCount += dp.focusSessions;
if (dp.completedTasks > 0) activeDaysCount++;
String[] parts = entry.getKey().split("-"); String[] parts = entry.getKey().split("-");
if (parts.length == 3) { if (parts.length == 3) {
int day = Integer.parseInt(parts[2]); int y = Integer.parseInt(parts[0]);
completedTasksPerDay.put(day, dp.completedTasks); int m = Integer.parseInt(parts[1]) - 1; // Calendar.MONTH is 0-indexed
android.util.Log.d("FLUXUP_DEBUG", "COMPLETED_TASKS_BY_DATE: " + entry.getKey() + " -> " + dp.completedTasks); int d = Integer.parseInt(parts[2]);
android.util.Log.d("FLUXUP_DEBUG", "DAY_STATUS_CALCULATED: " + entry.getKey() + " -> " + dp.status);
// 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)); tvFocusSessions.setText(String.valueOf(focusSessionsCount));
updateCalendar(completedTasksPerDay); updateCalendar(completedTasksPerDay);
@@ -180,58 +202,36 @@ public class StreakActivity extends AppCompatActivity {
boolean isCurrentMonth = (todayYear == calYear && todayMonth == calMonth); boolean isCurrentMonth = (todayYear == calYear && todayMonth == calMonth);
boolean started = false;
int missedDaysInRow = 0;
for (int i = 1; i <= maxDays; i++) { for (int i = 1; i <= maxDays; i++) {
int completed = completedTasksPerDay.getOrDefault(i, 0); int completed = completedTasksPerDay.getOrDefault(i, 0);
boolean isCurrent = (isCurrentMonth && i == todayDay); boolean isCurrent = (isCurrentMonth && i == todayDay);
boolean isPastOrToday = false;
boolean isFuture = false; boolean isFuture = false;
if (calYear < todayYear) { 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 {
isFuture = true; isFuture = true;
} } else if (calYear == todayYear) {
if (calMonth > todayMonth) {
boolean isComplete = completed >= currentDailyGoal; isFuture = true;
String status = "normal"; } else if (calMonth == todayMonth) {
if (i > todayDay) isFuture = true;
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";
} }
} }
if (i == 30) { // Regra: meta atingida -> complete (verde), caso contrário -> empty (cinzento)
android.util.Log.d("FLUXUP_DEBUG", "OFFENSIVA_DAY_30_STATUS: " + status); 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); rvCalendar.setAdapter(adapter);
} }
@@ -241,25 +241,23 @@ public class StreakActivity extends AppCompatActivity {
int dayNumber; int dayNumber;
int completedTasks; int completedTasks;
boolean isCurrent; boolean isCurrent;
boolean isPastOrToday; boolean isFuture;
String status; 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.dayNumber = dayNumber;
this.completedTasks = completedTasks; this.completedTasks = completedTasks;
this.isCurrent = isCurrent; this.isCurrent = isCurrent;
this.isPastOrToday = isPastOrToday; this.isFuture = isFuture;
this.status = status; this.status = status;
} }
} }
private class CalendarAdapter extends RecyclerView.Adapter<CalendarAdapter.ViewHolder> { private class CalendarAdapter extends RecyclerView.Adapter<CalendarAdapter.ViewHolder> {
private final List<CalendarDay> days; private final List<CalendarDay> days;
private final int dailyGoal;
CalendarAdapter(List<CalendarDay> days, int dailyGoal) { CalendarAdapter(List<CalendarDay> days) {
this.days = days; this.days = days;
this.dailyGoal = dailyGoal;
} }
@NonNull @NonNull
@@ -283,40 +281,37 @@ public class StreakActivity extends AppCompatActivity {
holder.tvDayNumber.setText(String.valueOf(day.dayNumber)); holder.tvDayNumber.setText(String.valueOf(day.dayNumber));
if (holder.tvEmoji != null) holder.tvEmoji.setVisibility(View.GONE); if (holder.tvEmoji != null) holder.tvEmoji.setVisibility(View.GONE);
if ("fire".equals(day.status)) { if (day.isFuture) {
// AMARELO / FOGO // DIAS FUTUROS: CINZENTO CLARO
holder.dayBackground.setVisibility(View.VISIBLE); holder.dayBackground.setVisibility(View.VISIBLE);
holder.dayBackground.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#FFB020"))); holder.dayBackground.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#F5F5F5")));
holder.tvDayNumber.setTextColor(Color.BLACK); 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) { if (holder.tvEmoji != null) {
holder.tvEmoji.setVisibility(View.VISIBLE); holder.tvEmoji.setVisibility(View.VISIBLE);
holder.tvEmoji.setText("🔥"); holder.tvEmoji.setText("🔥");
} }
} else if (day.isCurrent) {
if (position > 0 && "fire".equals(days.get(position-1).status) && days.get(position-1).dayNumber != 0) { // HOJE SEM META: ROXO
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
holder.dayBackground.setVisibility(View.VISIBLE); 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); holder.tvDayNumber.setTextColor(Color.WHITE);
if (holder.tvEmoji != null) {
holder.tvEmoji.setVisibility(View.VISIBLE);
holder.tvEmoji.setText("🧊");
}
holder.streakConnector.setVisibility(View.GONE); holder.streakConnector.setVisibility(View.GONE);
} else { } else {
// CINZENTO (NORMAL / FUTURO) // META NÃO CUMPRIDA (PASSADO): CINZENTO
holder.dayBackground.setVisibility(View.VISIBLE); holder.dayBackground.setVisibility(View.VISIBLE);
holder.dayBackground.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#E0E0E0"))); holder.dayBackground.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#E0E0E0")));
holder.tvDayNumber.setTextColor(Color.BLACK); holder.tvDayNumber.setTextColor(Color.BLACK);
holder.streakConnector.setVisibility(View.GONE); holder.streakConnector.setVisibility(View.GONE);
} }
// Opcional: indicador adicional para hoje
if (day.isCurrent) { if (day.isCurrent) {
holder.dayIndicator.setVisibility(View.VISIBLE); holder.dayIndicator.setVisibility(View.VISIBLE);
} else { } else {

View File

@@ -200,7 +200,7 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Dias de prática" android:text="Dias cumpridos"
android:textColor="@color/text_secondary" android:textColor="@color/text_secondary"
android:textSize="12sp" /> android:textSize="12sp" />
<TextView <TextView

View File

@@ -252,12 +252,31 @@
android:id="@+id/tvFocusStatus" android:id="@+id/tvFocusStatus"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="Sessão de foco" android:text="Sessão de foco"
android:textColor="@color/text_secondary" android:textColor="@color/text_secondary"
android:textSize="14sp" android:textSize="14sp"
android:visibility="visible" /> android:visibility="visible" />
<TextView
android:id="@+id/tvFocusPauseCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pausas: 0"
android:textColor="@color/text_secondary"
android:textSize="12sp"
android:visibility="gone" />
<TextView
android:id="@+id/tvFocusPenaltyWarning"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="⚠ Muitas pausas: -5 XP"
android:textColor="@color/error_red"
android:textSize="12sp"
android:textStyle="bold"
android:visibility="gone" />
<FrameLayout <FrameLayout
android:id="@+id/timerBlock" android:id="@+id/timerBlock"
android:layout_width="200dp" android:layout_width="200dp"
@@ -283,6 +302,7 @@
android:textStyle="bold" /> android:textStyle="bold" />
<TextView <TextView
android:id="@+id/tvFocusXpReward"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="+50 XP" android:text="+50 XP"