melhorar o calendario
This commit is contained in:
@@ -172,4 +172,96 @@ public class FirestoreManager {
|
||||
callback.accept(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtém os logs de XP de um determinado mês e ano.
|
||||
*/
|
||||
public void getMonthXpLogs(String uid, int year, int month, Consumer<List<Map<String, Object>>> callback) {
|
||||
if (uid == null) {
|
||||
callback.accept(new ArrayList<>());
|
||||
return;
|
||||
}
|
||||
|
||||
java.util.Calendar cal = java.util.Calendar.getInstance();
|
||||
cal.set(year, month, 1, 0, 0, 0);
|
||||
cal.set(java.util.Calendar.MILLISECOND, 0);
|
||||
java.util.Date start = cal.getTime();
|
||||
|
||||
cal.add(java.util.Calendar.MONTH, 1);
|
||||
java.util.Date end = cal.getTime();
|
||||
|
||||
db.collection("xp_logs")
|
||||
.whereEqualTo("userId", uid)
|
||||
.whereGreaterThanOrEqualTo("created_at", start)
|
||||
.whereLessThan("created_at", end)
|
||||
.get()
|
||||
.addOnSuccessListener(snapshots -> {
|
||||
List<Map<String, Object>> logs = new ArrayList<>();
|
||||
if (snapshots != null) {
|
||||
for (com.google.firebase.firestore.QueryDocumentSnapshot doc : snapshots) {
|
||||
Map<String, Object> log = doc.getData();
|
||||
logs.add(log);
|
||||
}
|
||||
}
|
||||
callback.accept(logs);
|
||||
})
|
||||
.addOnFailureListener(e -> {
|
||||
android.util.Log.e("FLUXUP_DEBUG", "MONTH_XP_QUERY_FAIL: " + e.getMessage());
|
||||
callback.accept(new ArrayList<>());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates daily progress (completed tasks, focus sessions, xp) for a date range
|
||||
*/
|
||||
public void getDailyProgress(String uid, java.util.Date startDate, java.util.Date endDate, int dailyGoal, Consumer<Map<String, DailyProgress>> callback) {
|
||||
if (uid == null) {
|
||||
callback.accept(new java.util.HashMap<>());
|
||||
return;
|
||||
}
|
||||
|
||||
db.collection("xp_logs")
|
||||
.whereEqualTo("userId", uid)
|
||||
.whereGreaterThanOrEqualTo("created_at", startDate)
|
||||
.whereLessThanOrEqualTo("created_at", endDate)
|
||||
.get()
|
||||
.addOnSuccessListener(snapshots -> {
|
||||
Map<String, DailyProgress> progressMap = new java.util.HashMap<>();
|
||||
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.getDefault());
|
||||
|
||||
if (snapshots != null) {
|
||||
for (com.google.firebase.firestore.QueryDocumentSnapshot doc : snapshots) {
|
||||
com.google.firebase.Timestamp ts = doc.getTimestamp("created_at");
|
||||
if (ts != null) {
|
||||
String dateStr = sdf.format(ts.toDate());
|
||||
DailyProgress dp = progressMap.get(dateStr);
|
||||
if (dp == null) {
|
||||
dp = new DailyProgress(dateStr, dailyGoal);
|
||||
progressMap.put(dateStr, dp);
|
||||
}
|
||||
|
||||
String type = doc.getString("type");
|
||||
Long amount = doc.getLong("amount");
|
||||
if (amount != null) {
|
||||
dp.xp += amount.intValue();
|
||||
}
|
||||
if ("focus_task".equals(type)) {
|
||||
dp.completedTasks++;
|
||||
dp.focusSessions++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (DailyProgress dp : progressMap.values()) {
|
||||
dp.updateStatus();
|
||||
}
|
||||
|
||||
callback.accept(progressMap);
|
||||
})
|
||||
.addOnFailureListener(e -> {
|
||||
android.util.Log.e("FLUXUP_DEBUG", "DAILY_PROGRESS_QUERY_FAIL: " + e.getMessage());
|
||||
callback.accept(new java.util.HashMap<>());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ public class InicioFragment extends Fragment {
|
||||
private TasksAdapter tasksAdapter;
|
||||
private LinearLayout miniRankingContainer, layoutTasksSection;
|
||||
private Button btnStartFocus, btnAddTasks, btnClaimReward;
|
||||
private androidx.cardview.widget.CardView btnStreakPage;
|
||||
|
||||
private CountDownTimer countDownTimer;
|
||||
private LinearLayout progressPathContainer;
|
||||
@@ -139,6 +140,12 @@ public class InicioFragment extends Fragment {
|
||||
btnClaimReward = view.findViewById(R.id.btnClaimReward);
|
||||
btnClaimReward.setOnClickListener(v -> claimDailyReward());
|
||||
|
||||
// Streak Page
|
||||
btnStreakPage = view.findViewById(R.id.btnStreakPage);
|
||||
btnStreakPage.setOnClickListener(v -> {
|
||||
startActivity(new android.content.Intent(getActivity(), StreakActivity.class));
|
||||
});
|
||||
|
||||
setRandomMotivationalQuote();
|
||||
initProgressPath();
|
||||
startObservingTasks();
|
||||
@@ -203,10 +210,43 @@ public class InicioFragment extends Fragment {
|
||||
|
||||
updateTodayCard(user);
|
||||
checkDailyResetAndStreak(user);
|
||||
loadWeeklyProgress(user);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void loadWeeklyProgress(Usuario user) {
|
||||
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);
|
||||
|
||||
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); // 1 = Sunday, 2 = Monday
|
||||
int daysToSubtract = (dayOfWeek + 5) % 7; // Monday = 0, Sunday = 6
|
||||
|
||||
Calendar startCal = (Calendar) cal.clone();
|
||||
startCal.add(Calendar.DAY_OF_YEAR, -daysToSubtract);
|
||||
java.util.Date startDate = startCal.getTime();
|
||||
|
||||
Calendar endCal = (Calendar) startCal.clone();
|
||||
endCal.add(Calendar.DAY_OF_YEAR, 7);
|
||||
java.util.Date endDate = endCal.getTime();
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
private void updateTasksUI() {
|
||||
if (tasksAdapter != null) {
|
||||
tasksAdapter.setTasks(currentTasks);
|
||||
@@ -435,35 +475,100 @@ public class InicioFragment extends Fragment {
|
||||
if (i == 0) leftConnector.setVisibility(View.INVISIBLE);
|
||||
if (i == 6) rightConnector.setVisibility(View.INVISIBLE);
|
||||
|
||||
// Style based on state
|
||||
if (i < currentDayIndex) {
|
||||
// Past day - Assume completed for demo
|
||||
nodeCircle.setBackgroundResource(R.drawable.node_circle_bg);
|
||||
if (getContext() != null) {
|
||||
nodeCircle.getBackground().setTint(ContextCompat.getColor(getContext(), R.color.success_green));
|
||||
nodeDayInitial.setTextColor(ContextCompat.getColor(getContext(), R.color.white));
|
||||
}
|
||||
nodeProgress.setVisibility(View.GONE);
|
||||
} else if (i == currentDayIndex) {
|
||||
// Today
|
||||
nodeCircle.setBackgroundResource(R.drawable.node_circle_bg);
|
||||
if (getContext() != null) {
|
||||
nodeCircle.getBackground().setTint(ContextCompat.getColor(getContext(), R.color.primary_purple));
|
||||
nodeDayInitial.setTextColor(ContextCompat.getColor(getContext(), R.color.white));
|
||||
nodeDayLabel.setTextColor(ContextCompat.getColor(getContext(), R.color.primary_purple));
|
||||
}
|
||||
nodeProgress.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
// Future
|
||||
node.setAlpha(0.4f);
|
||||
nodeProgress.setVisibility(View.GONE);
|
||||
// Default empty state
|
||||
nodeCircle.setBackgroundResource(R.drawable.node_circle_bg);
|
||||
if (getContext() != null) {
|
||||
nodeCircle.getBackground().setTint(android.graphics.Color.parseColor("#E0E0E0"));
|
||||
nodeDayInitial.setTextColor(ContextCompat.getColor(getContext(), R.color.text_secondary));
|
||||
nodeDayLabel.setTextColor(ContextCompat.getColor(getContext(), R.color.text_secondary));
|
||||
}
|
||||
nodeProgress.setVisibility(View.GONE);
|
||||
|
||||
dayNodes.add(node);
|
||||
progressPathContainer.addView(node);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProgressPath(Map<String, DailyProgress> progressMap) {
|
||||
if (getContext() == null || dayNodes == null || dayNodes.isEmpty()) 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);
|
||||
|
||||
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
|
||||
int daysToSubtract = (dayOfWeek + 5) % 7;
|
||||
|
||||
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());
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
Calendar dayCal = (Calendar) startCal.clone();
|
||||
dayCal.add(Calendar.DAY_OF_YEAR, i);
|
||||
String dateStr = sdf.format(dayCal.getTime());
|
||||
DailyProgress dp = progressMap.get(dateStr);
|
||||
|
||||
View node = dayNodes.get(i);
|
||||
View nodeCircle = node.findViewById(R.id.nodeCircle);
|
||||
TextView nodeDayInitial = node.findViewById(R.id.nodeDayInitial);
|
||||
TextView nodeDayLabel = node.findViewById(R.id.nodeDayLabel);
|
||||
ProgressBar nodeProgress = node.findViewById(R.id.nodeProgress);
|
||||
View rightConnector = node.findViewById(R.id.rightConnector);
|
||||
|
||||
if (dp != null && "complete".equals(dp.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)) {
|
||||
nodeCircle.getBackground().setTint(android.graphics.Color.parseColor("#4FC3F7"));
|
||||
nodeDayInitial.setTextColor(ContextCompat.getColor(getContext(), R.color.white));
|
||||
} else {
|
||||
nodeCircle.getBackground().setTint(android.graphics.Color.parseColor("#E0E0E0"));
|
||||
nodeDayInitial.setTextColor(ContextCompat.getColor(getContext(), R.color.text_primary));
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
nodeDayLabel.setVisibility(View.GONE);
|
||||
nodeProgress.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (i > currentDayIndex) {
|
||||
node.setAlpha(0.4f);
|
||||
} else {
|
||||
node.setAlpha(1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void completeTask(Task task) {
|
||||
task.completed = true;
|
||||
FirestoreManager.getInstance().updateTask(task);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.fluxup.app;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -11,8 +13,14 @@ import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.firebase.auth.FirebaseUser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class StreakActivity extends AppCompatActivity {
|
||||
|
||||
@@ -20,6 +28,15 @@ public class StreakActivity extends AppCompatActivity {
|
||||
private TextView tvStreakCount;
|
||||
private ImageButton btnClose;
|
||||
private TabLayout tabLayout;
|
||||
private TextView tvMonthName;
|
||||
private ImageButton btnPrevMonth;
|
||||
private ImageButton btnNextMonth;
|
||||
private TextView tvDaysOfPractice;
|
||||
private TextView tvFocusSessions;
|
||||
|
||||
private Calendar currentCalendar;
|
||||
private String currentUserId;
|
||||
private int currentDailyGoal = 3;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -30,46 +47,191 @@ public class StreakActivity extends AppCompatActivity {
|
||||
tvStreakCount = findViewById(R.id.tvStreakCount);
|
||||
btnClose = findViewById(R.id.btnClose);
|
||||
tabLayout = findViewById(R.id.tabLayout);
|
||||
tvMonthName = findViewById(R.id.tvMonthName);
|
||||
btnPrevMonth = findViewById(R.id.btnPrevMonth);
|
||||
btnNextMonth = findViewById(R.id.btnNextMonth);
|
||||
tvDaysOfPractice = findViewById(R.id.tvDaysOfPractice);
|
||||
tvFocusSessions = findViewById(R.id.tvFocusSessions);
|
||||
|
||||
btnClose.setOnClickListener(v -> finish());
|
||||
|
||||
setupCalendar();
|
||||
currentCalendar = Calendar.getInstance();
|
||||
FirebaseUser user = AuthManager.getInstance().getCurrentUser();
|
||||
if (user != null) {
|
||||
currentUserId = user.getUid();
|
||||
loadUserData();
|
||||
}
|
||||
|
||||
btnPrevMonth.setOnClickListener(v -> {
|
||||
currentCalendar.add(Calendar.MONTH, -1);
|
||||
loadMonthData();
|
||||
});
|
||||
|
||||
btnNextMonth.setOnClickListener(v -> {
|
||||
currentCalendar.add(Calendar.MONTH, 1);
|
||||
loadMonthData();
|
||||
});
|
||||
|
||||
setupTabs();
|
||||
}
|
||||
|
||||
private void setupTabs() {
|
||||
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||
@Override
|
||||
public void onTabSelected(TabLayout.Tab tab) {
|
||||
// Future: toggle between personal and friends stats
|
||||
}
|
||||
|
||||
public void onTabSelected(TabLayout.Tab tab) {}
|
||||
@Override
|
||||
public void onTabUnselected(TabLayout.Tab tab) {}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(TabLayout.Tab tab) {}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupCalendar() {
|
||||
private void loadUserData() {
|
||||
FirestoreManager.getInstance().getUser(currentUserId, user -> {
|
||||
if (user != null && !isDestroyed()) {
|
||||
tvStreakCount.setText(user.streak + " dias de ofensiva!");
|
||||
currentDailyGoal = user.meta_diaria_tarefas > 0 ? user.meta_diaria_tarefas : 3;
|
||||
loadMonthData();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadMonthData() {
|
||||
int year = currentCalendar.get(Calendar.YEAR);
|
||||
int month = currentCalendar.get(Calendar.MONTH);
|
||||
|
||||
String monthName = currentCalendar.getDisplayName(Calendar.MONTH, Calendar.LONG, new Locale("pt", "PT"));
|
||||
if (monthName != null && monthName.length() > 0) {
|
||||
tvMonthName.setText(monthName.substring(0, 1).toUpperCase() + monthName.substring(1) + " de " + year);
|
||||
}
|
||||
|
||||
Calendar startCal = Calendar.getInstance();
|
||||
startCal.set(year, month, 1, 0, 0, 0);
|
||||
startCal.set(Calendar.MILLISECOND, 0);
|
||||
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);
|
||||
java.util.Date endDate = endCal.getTime();
|
||||
|
||||
android.util.Log.d("FLUXUP_DEBUG", "CURRENT_MONTH_RANGE: " + startDate + " to " + endDate);
|
||||
|
||||
FirestoreManager.getInstance().getDailyProgress(currentUserId, startDate, endDate, currentDailyGoal, progressMap -> {
|
||||
if (isDestroyed()) return;
|
||||
|
||||
android.util.Log.d("FLUXUP_DEBUG", "OFFENSIVA_PROGRESS_DATA: " + progressMap.size());
|
||||
|
||||
int focusSessionsCount = 0;
|
||||
int activeDaysCount = 0;
|
||||
|
||||
Map<Integer, Integer> completedTasksPerDay = new HashMap<>();
|
||||
|
||||
for (Map.Entry<String, DailyProgress> 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);
|
||||
}
|
||||
}
|
||||
|
||||
android.util.Log.d("FLUXUP_DEBUG", "OFFENSIVA_DAY_30_COMPLETED_TASKS: " + completedTasksPerDay.getOrDefault(30, 0));
|
||||
|
||||
tvDaysOfPractice.setText(String.valueOf(activeDaysCount));
|
||||
tvFocusSessions.setText(String.valueOf(focusSessionsCount));
|
||||
|
||||
updateCalendar(completedTasksPerDay);
|
||||
});
|
||||
}
|
||||
|
||||
private void updateCalendar(Map<Integer, Integer> completedTasksPerDay) {
|
||||
rvCalendar.setLayoutManager(new GridLayoutManager(this, 7));
|
||||
|
||||
List<CalendarDay> days = new ArrayList<>();
|
||||
|
||||
// Simulating April 2026 (Starts on a Wednesday)
|
||||
// Add empty slots for Mon, Tue
|
||||
days.add(new CalendarDay(0, false, false)); // Mon
|
||||
days.add(new CalendarDay(0, false, false)); // Tue
|
||||
Calendar calcCal = (Calendar) currentCalendar.clone();
|
||||
calcCal.set(Calendar.DAY_OF_MONTH, 1);
|
||||
int maxDays = calcCal.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||||
|
||||
// Days 1 to 30
|
||||
for (int i = 1; i <= 30; i++) {
|
||||
boolean isActive = (i >= 1 && i <= 7); // 7-day streak for demo
|
||||
boolean isCurrent = (i == 7);
|
||||
days.add(new CalendarDay(i, isActive, isCurrent));
|
||||
int startDayOfWeek = calcCal.get(Calendar.DAY_OF_WEEK);
|
||||
int emptySlots = startDayOfWeek - 2;
|
||||
if (emptySlots < 0) emptySlots = 6;
|
||||
|
||||
for (int i = 0; i < emptySlots; i++) {
|
||||
days.add(new CalendarDay(0, 0, false, false, "empty"));
|
||||
}
|
||||
|
||||
CalendarAdapter adapter = new CalendarAdapter(days);
|
||||
Calendar todayCal = Calendar.getInstance();
|
||||
int todayYear = todayCal.get(Calendar.YEAR);
|
||||
int todayMonth = todayCal.get(Calendar.MONTH);
|
||||
int todayDay = todayCal.get(Calendar.DAY_OF_MONTH);
|
||||
|
||||
int calYear = currentCalendar.get(Calendar.YEAR);
|
||||
int calMonth = currentCalendar.get(Calendar.MONTH);
|
||||
|
||||
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 {
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 30) {
|
||||
android.util.Log.d("FLUXUP_DEBUG", "OFFENSIVA_DAY_30_STATUS: " + status);
|
||||
}
|
||||
|
||||
days.add(new CalendarDay(i, completed, isCurrent, isPastOrToday, status));
|
||||
}
|
||||
|
||||
CalendarAdapter adapter = new CalendarAdapter(days, currentDailyGoal);
|
||||
rvCalendar.setAdapter(adapter);
|
||||
}
|
||||
|
||||
@@ -77,21 +239,27 @@ public class StreakActivity extends AppCompatActivity {
|
||||
|
||||
private static class CalendarDay {
|
||||
int dayNumber;
|
||||
boolean isActive;
|
||||
int completedTasks;
|
||||
boolean isCurrent;
|
||||
boolean isPastOrToday;
|
||||
String status;
|
||||
|
||||
CalendarDay(int dayNumber, boolean isActive, boolean isCurrent) {
|
||||
CalendarDay(int dayNumber, int completedTasks, boolean isCurrent, boolean isPastOrToday, String status) {
|
||||
this.dayNumber = dayNumber;
|
||||
this.isActive = isActive;
|
||||
this.completedTasks = completedTasks;
|
||||
this.isCurrent = isCurrent;
|
||||
this.isPastOrToday = isPastOrToday;
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
private class CalendarAdapter extends RecyclerView.Adapter<CalendarAdapter.ViewHolder> {
|
||||
private final List<CalendarDay> days;
|
||||
private final int dailyGoal;
|
||||
|
||||
CalendarAdapter(List<CalendarDay> days) {
|
||||
CalendarAdapter(List<CalendarDay> days, int dailyGoal) {
|
||||
this.days = days;
|
||||
this.dailyGoal = dailyGoal;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -109,23 +277,44 @@ public class StreakActivity extends AppCompatActivity {
|
||||
holder.tvDayNumber.setText("");
|
||||
holder.dayBackground.setVisibility(View.GONE);
|
||||
holder.streakConnector.setVisibility(View.GONE);
|
||||
holder.dayIndicator.setVisibility(View.GONE);
|
||||
if (holder.tvEmoji != null) holder.tvEmoji.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.tvDayNumber.setText(String.valueOf(day.dayNumber));
|
||||
if (holder.tvEmoji != null) holder.tvEmoji.setVisibility(View.GONE);
|
||||
|
||||
if (day.isActive) {
|
||||
if ("fire".equals(day.status)) {
|
||||
// AMARELO / FOGO
|
||||
holder.dayBackground.setVisibility(View.VISIBLE);
|
||||
holder.tvDayNumber.setTextColor(getResources().getColor(R.color.white));
|
||||
holder.dayBackground.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#FFB020")));
|
||||
holder.tvDayNumber.setTextColor(Color.BLACK);
|
||||
if (holder.tvEmoji != null) {
|
||||
holder.tvEmoji.setVisibility(View.VISIBLE);
|
||||
holder.tvEmoji.setText("🔥");
|
||||
}
|
||||
|
||||
// Simple logic for streak connection: if previous day was also active
|
||||
if (position > 0 && days.get(position-1).isActive && day.dayNumber > 1) {
|
||||
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 {
|
||||
holder.dayBackground.setVisibility(View.GONE);
|
||||
} else if ("ice".equals(day.status)) {
|
||||
// AZUL / GELO
|
||||
holder.dayBackground.setVisibility(View.VISIBLE);
|
||||
holder.dayBackground.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#4FC3F7")));
|
||||
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)
|
||||
holder.dayBackground.setVisibility(View.VISIBLE);
|
||||
holder.dayBackground.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#E0E0E0")));
|
||||
holder.tvDayNumber.setTextColor(Color.BLACK);
|
||||
holder.streakConnector.setVisibility(View.GONE);
|
||||
holder.tvDayNumber.setTextColor(getResources().getColor(R.color.text_primary));
|
||||
}
|
||||
|
||||
if (day.isCurrent) {
|
||||
@@ -143,6 +332,7 @@ public class StreakActivity extends AppCompatActivity {
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView tvDayNumber;
|
||||
TextView tvEmoji;
|
||||
View dayBackground;
|
||||
View streakConnector;
|
||||
View dayIndicator;
|
||||
@@ -150,6 +340,7 @@ public class StreakActivity extends AppCompatActivity {
|
||||
ViewHolder(View view) {
|
||||
super(view);
|
||||
tvDayNumber = view.findViewById(R.id.tvDayNumber);
|
||||
tvEmoji = view.findViewById(R.id.tvEmoji);
|
||||
dayBackground = view.findViewById(R.id.dayBackground);
|
||||
streakConnector = view.findViewById(R.id.streakConnector);
|
||||
dayIndicator = view.findViewById(R.id.dayIndicator);
|
||||
|
||||
@@ -134,6 +134,7 @@
|
||||
android:layout_alignParentEnd="true">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnPrevMonth"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
@@ -141,6 +142,7 @@
|
||||
app:tint="@color/text_secondary" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnNextMonth"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="16dp"
|
||||
@@ -202,9 +204,10 @@
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="12sp" />
|
||||
<TextView
|
||||
android:id="@+id/tvDaysOfPractice"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="12"
|
||||
android:text="0"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
@@ -234,9 +237,10 @@
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="12sp" />
|
||||
<TextView
|
||||
android:id="@+id/tvFocusSessions"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="24"
|
||||
android:text="0"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
|
||||
@@ -296,14 +296,41 @@
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<!-- 5. 📊 PROGRESSO DIÁRIO -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:text="Progresso Semanal"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:text="Progresso Semanal"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/btnStreakPage"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
app:cardBackgroundColor="@color/card_background"
|
||||
app:cardCornerRadius="18dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="🔥"
|
||||
android:textSize="18sp" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
</RelativeLayout>
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -34,6 +34,18 @@
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<!-- Emoji Overlay -->
|
||||
<TextView
|
||||
android:id="@+id/tvEmoji"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top|end"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="🔥"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Indicator Dot (Optional) -->
|
||||
<View
|
||||
android:id="@+id/dayIndicator"
|
||||
|
||||
Reference in New Issue
Block a user