continuar utilizador

This commit is contained in:
MeuNome
2026-04-23 10:40:44 +01:00
parent 187e070317
commit 7c05b71152
709 changed files with 168 additions and 102932 deletions

View File

@@ -27,6 +27,8 @@
<activity android:name=".MainActivity" />
<activity android:name=".SettingsActivity" />
<activity android:name=".StreakActivity" />
<activity android:name=".FindFriendsActivity" />
</application>

View File

@@ -11,6 +11,10 @@ import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.firestore.ListenerRegistration;
import java.util.HashMap;
import java.util.Map;
import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -27,14 +31,16 @@ import java.util.List;
public class InicioFragment extends Fragment {
private TextView tvTimer, tvProgressText;
private TextView tvTimer, tvProgressText, tvGreeting;
private FrameLayout timerBlock;
private LinearLayout tasksContainer;
private ProgressBar pbDailyTasks;
private CountDownTimer countDownTimer;
private LinearLayout progressPathContainer;
private List<View> dayNodes = new ArrayList<>();
private int currentDayIndex = 0; // 0-based index for the current day in the path
private int currentDayIndex = 0;
private ListenerRegistration tasksListener, userListener;
private List<Task> currentTasks = new ArrayList<>();
private boolean isTimerRunning = false;
private long timeLeftInMillis = 25 * 60 * 1000; // 25 minutos
@@ -46,14 +52,18 @@ public class InicioFragment extends Fragment {
View view = inflater.inflate(R.layout.fragment_inicio, container, false);
tvTimer = view.findViewById(R.id.tvTimer);
tvGreeting = view.findViewById(R.id.tvGreeting);
timerBlock = view.findViewById(R.id.timerBlock);
tasksContainer = view.findViewById(R.id.tasksContainer);
tvProgressText = view.findViewById(R.id.tvProgressText);
pbDailyTasks = view.findViewById(R.id.pbDailyTasks);
progressPathContainer = view.findViewById(R.id.progressPathContainer);
progressPathContainer = view.findViewById(R.id.progressPathContainer);
initProgressPath();
addSampleTasks();
startObservingTasks();
startObservingUser();
View btnStartFocus = view.findViewById(R.id.btnStartFocus);
@@ -87,20 +97,32 @@ public class InicioFragment extends Fragment {
return view;
}
private void addSampleTasks() {
if(getContext() == null) return;
String[] sampleTasks = {
"Estudar para intermédio",
"Ler artigo técnico",
"Fazer exercícios"
};
private void startObservingTasks() {
FirebaseUser currentUser = AuthManager.getInstance().getCurrentUser();
if (currentUser != null) {
tasksListener = FirestoreManager.getInstance().observeTasks(currentUser.getUid(), tasks -> {
currentTasks = tasks;
updateTasksUI();
});
}
}
private void startObservingUser() {
FirebaseUser currentUser = AuthManager.getInstance().getCurrentUser();
if (currentUser != null) {
userListener = FirestoreManager.getInstance().observeUser(currentUser.getUid(), user -> {
if (tvGreeting != null) {
tvGreeting.setText("Olá, " + user.usuario + "!");
}
});
}
}
private void updateTasksUI() {
if (getContext() == null || tasksContainer == null) return;
tasksContainer.removeAllViews();
int completedCount = 0;
for (int i = 0; i < sampleTasks.length; i++) {
String taskLabel = sampleTasks[i];
// Create a custom Duo-style card for each task
for (Task task : currentTasks) {
androidx.cardview.widget.CardView card = new androidx.cardview.widget.CardView(getContext());
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
@@ -117,45 +139,46 @@ public class InicioFragment extends Fragment {
layout.setGravity(android.view.Gravity.CENTER_VERTICAL);
CheckBox cb = new CheckBox(getContext());
cb.setText(taskLabel);
cb.setText(task.title);
cb.setTextColor(getResources().getColor(R.color.text_primary));
cb.setTextSize(16);
cb.setChecked(task.completed);
// Simulated check for one task
if (i == 0) {
cb.setChecked(true);
completedCount++;
card.setCardBackgroundColor(getResources().getColor(R.color.background_light));
if (task.completed) {
cb.setTextColor(getResources().getColor(R.color.success_green));
}
cb.setOnCheckedChangeListener((buttonView, isChecked) -> {
task.completed = isChecked;
FirestoreManager.getInstance().updateTask(task);
// The observer will trigger updateTasksUI again, so we don't need manual UI update here
if (isChecked) {
addXP(task.xpReward);
}
});
layout.addView(cb);
card.addView(layout);
tasksContainer.addView(card);
final int finalI = i;
cb.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked) {
cb.setTextColor(getResources().getColor(R.color.success_green));
} else {
cb.setTextColor(getResources().getColor(R.color.text_primary));
}
updateProgress();
});
}
updateProgress();
}
private void addXP(int amount) {
FirebaseUser currentUser = AuthManager.getInstance().getCurrentUser();
if (currentUser != null) {
com.google.firebase.firestore.FirebaseFirestore.getInstance()
.collection("users").document(currentUser.getUid())
.update("xp", com.google.firebase.firestore.FieldValue.increment(amount));
}
}
private void updateProgress() {
int total = tasksContainer.getChildCount();
int total = currentTasks.size();
int completed = 0;
for (int i = 0; i < total; i++) {
View child = tasksContainer.getChildAt(i);
if (child instanceof androidx.cardview.widget.CardView) {
CheckBox cb = (CheckBox) ((LinearLayout)((androidx.cardview.widget.CardView) child).getChildAt(0)).getChildAt(0);
if (cb.isChecked()) completed++;
}
for (Task task : currentTasks) {
if (task.completed) completed++;
}
if (tvProgressText != null) {
@@ -271,7 +294,10 @@ public class InicioFragment extends Fragment {
@Override
public void onFinish() {
isTimerRunning = false;
if(getContext() != null) Toast.makeText(getContext(), "Foco concluído! +50 XP", Toast.LENGTH_LONG).show();
if(getContext() != null) {
Toast.makeText(getContext(), "Foco concluído! +50 XP", Toast.LENGTH_LONG).show();
addXP(50);
}
}
}.start();
@@ -297,6 +323,12 @@ public class InicioFragment extends Fragment {
@Override
public void onDestroyView() {
super.onDestroyView();
if (tasksListener != null) {
tasksListener.remove();
}
if (userListener != null) {
userListener.remove();
}
pauseTimer(); // Parar o timer se a view for destruída
}
}

View File

@@ -10,9 +10,15 @@ import android.widget.ImageButton;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.widget.TextView;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.firestore.ListenerRegistration;
public class ProfileFragment extends Fragment {
private TextView tvUsername, tvHandle, tvStreakValue, tvTotalXP, tvLeagueName, tvAchievementsCount;
private ListenerRegistration userListener;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@@ -24,6 +30,52 @@ public class ProfileFragment extends Fragment {
startActivity(intent);
});
View btnInviteCard = view.findViewById(R.id.btnInviteCard);
btnInviteCard.setOnClickListener(v -> openFindFriends());
View btnInviteFriends = view.findViewById(R.id.btnInviteFriends);
btnInviteFriends.setOnClickListener(v -> openFindFriends());
// Initialize UI components
tvUsername = view.findViewById(R.id.tvUsername);
tvHandle = view.findViewById(R.id.tvHandle);
tvStreakValue = view.findViewById(R.id.tvStreakValue);
tvTotalXP = view.findViewById(R.id.tvTotalXP);
tvLeagueName = view.findViewById(R.id.tvLeagueName);
tvAchievementsCount = view.findViewById(R.id.tvAchievementsCount);
startObservingUser();
return view;
}
private void startObservingUser() {
FirebaseUser currentUser = AuthManager.getInstance().getCurrentUser();
if (currentUser != null) {
userListener = FirestoreManager.getInstance().observeUser(currentUser.getUid(), this::updateUI);
}
}
private void updateUI(Usuario user) {
if (getContext() == null) return;
tvUsername.setText(user.usuario);
tvHandle.setText(user.handle);
tvStreakValue.setText(String.valueOf(user.streak));
tvTotalXP.setText(String.valueOf(user.xp));
tvLeagueName.setText(user.league);
tvAchievementsCount.setText(String.valueOf(user.achievementsCount));
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (userListener != null) {
userListener.remove();
}
}
private void openFindFriends() {
Intent intent = new Intent(getActivity(), FindFriendsActivity.class);
startActivity(intent);
}
}

View File

@@ -10,6 +10,14 @@ public class Usuario {
public String created_at;
public String updated_at;
// Stats and Social
public int xp = 0;
public int streak = 0;
public String league = "Bronze";
public String handle = "";
public String bio = "";
public int achievementsCount = 0;
public Usuario() {}
public Usuario(String id_usuario, String usuario, String email, String palavra_passe, String numero) {
@@ -18,5 +26,6 @@ public class Usuario {
this.email = email;
this.palavra_passe = palavra_passe;
this.numero = numero;
this.handle = "@" + usuario.toLowerCase().replace(" ", "_");
}
}

View File

@@ -71,7 +71,8 @@ public class UsuariosService {
android.util.Log.d("FLUXUP_SERVICE", "A guardar utilizador no Firestore (Coleção: users, ID: " + uid + ")...");
getFirestore().collection("users").document(uid).set(usuario)
.addOnSuccessListener(aVoid -> {
android.util.Log.d("FLUXUP_SERVICE", "Utilizador guardado no Firestore com sucesso.");
android.util.Log.d("FLUXUP_SERVICE", "Utilizador guardado no Firestore com sucesso. A criar tarefas iniciais...");
createInitialTasks(uid);
usuario.palavra_passe = tempPass;
callback.onSuccess(usuario);
})
@@ -89,6 +90,19 @@ public class UsuariosService {
});
}
private static void createInitialTasks(String uid) {
String[] defaultTasks = {
"Completar o perfil",
"Iniciar primeira sessão de foco",
"Definir objetivo diário"
};
for (String title : defaultTasks) {
String taskId = getFirestore().collection("tasks").document().getId();
Task task = new Task(taskId, title, 50, uid);
getFirestore().collection("tasks").document(taskId).set(task);
}
}
public static void recuperarPalavraPasse(Context context, String email, ServiceCallback<Void> callback) {
FirebaseAuth.getInstance().sendPasswordResetEmail(email)
.addOnCompleteListener(task -> {

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#F9F9F9" />
<stroke android:width="1dp" android:color="#DDDDDD" />
<solid android:color="@color/white" />
<stroke android:width="1dp" android:color="@color/border_color" />
<corners android:radius="8dp" />
</shape>

View File

@@ -5,7 +5,7 @@
android:orientation="vertical"
android:padding="20dp"
android:gravity="center"
android:background="@color/white">
android:background="@color/background_light">
<TextView
android:layout_width="wrap_content"

View File

@@ -5,7 +5,7 @@
android:orientation="vertical"
android:padding="20dp"
android:gravity="center"
android:background="@color/white">
android:background="@color/background_light">
<TextView
android:id="@+id/tvTitle"

View File

@@ -2,7 +2,7 @@
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
android:background="@color/background_light">
<LinearLayout
android:layout_width="match_parent"

View File

@@ -11,7 +11,7 @@
android:layout_width="match_parent"
android:layout_height="64dp"
android:paddingHorizontal="16dp"
android:background="@color/white"
android:background="@color/card_background"
android:elevation="4dp">
<ImageButton
@@ -62,7 +62,7 @@
android:layout_height="wrap_content"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
android:backgroundTint="@color/white"
android:backgroundTint="@color/card_background"
android:layout_marginBottom="24dp">
<LinearLayout
@@ -110,7 +110,7 @@
android:layout_height="wrap_content"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
android:backgroundTint="@color/white"
android:backgroundTint="@color/card_background"
android:layout_marginBottom="24dp">
<LinearLayout
@@ -167,7 +167,7 @@
android:layout_height="wrap_content"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
android:backgroundTint="@color/white"
android:backgroundTint="@color/card_background"
android:layout_marginBottom="24dp">
<LinearLayout
@@ -215,7 +215,7 @@
android:layout_height="wrap_content"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
android:backgroundTint="@color/white"
android:backgroundTint="@color/card_background"
android:layout_marginBottom="24dp">
<LinearLayout
@@ -263,7 +263,7 @@
android:layout_height="wrap_content"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
android:backgroundTint="@color/white"
android:backgroundTint="@color/card_background"
android:layout_marginBottom="40dp">
<LinearLayout

View File

@@ -231,7 +231,7 @@
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardBackgroundColor="@color/white"
app:cardBackgroundColor="@color/card_background"
app:cardCornerRadius="20dp"
app:cardElevation="2dp">

View File

@@ -296,11 +296,15 @@
android:orientation="vertical">
<androidx.cardview.widget.CardView
android:id="@+id/btnInviteCard"
android:layout_width="60dp"
android:layout_height="60dp"
app:cardCornerRadius="30dp"
app:cardElevation="0dp"
app:cardBackgroundColor="@color/border_color">
app:cardBackgroundColor="@color/border_color"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground">
<TextView
android:layout_width="wrap_content"

View File

@@ -1,6 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.Fluxup" parent="Theme.MaterialComponents.Light.NoActionBar">
<style name="Theme.Fluxup" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">#7C3AED</item>
<item name="colorPrimaryVariant">#6D28D9</item>