erro
This commit is contained in:
12
.idea/caches/deviceStreaming.xml
generated
12
.idea/caches/deviceStreaming.xml
generated
@@ -682,6 +682,18 @@
|
|||||||
<option name="screenX" value="2076" />
|
<option name="screenX" value="2076" />
|
||||||
<option name="screenY" value="2152" />
|
<option name="screenY" value="2152" />
|
||||||
</PersistentDeviceSelectionData>
|
</PersistentDeviceSelectionData>
|
||||||
|
<PersistentDeviceSelectionData>
|
||||||
|
<option name="api" value="36" />
|
||||||
|
<option name="brand" value="google" />
|
||||||
|
<option name="codename" value="comet" />
|
||||||
|
<option name="id" value="comet" />
|
||||||
|
<option name="labId" value="google" />
|
||||||
|
<option name="manufacturer" value="Google" />
|
||||||
|
<option name="name" value="Pixel 9 Pro Fold" />
|
||||||
|
<option name="screenDensity" value="390" />
|
||||||
|
<option name="screenX" value="2076" />
|
||||||
|
<option name="screenY" value="2152" />
|
||||||
|
</PersistentDeviceSelectionData>
|
||||||
<PersistentDeviceSelectionData>
|
<PersistentDeviceSelectionData>
|
||||||
<option name="api" value="35" />
|
<option name="api" value="35" />
|
||||||
<option name="brand" value="motorola" />
|
<option name="brand" value="motorola" />
|
||||||
|
|||||||
@@ -31,7 +31,6 @@
|
|||||||
<activity android:name=".StatisticsActivity" />
|
<activity android:name=".StatisticsActivity" />
|
||||||
<activity android:name=".FindFriendsActivity" />
|
<activity android:name=".FindFriendsActivity" />
|
||||||
<activity android:name=".TrophiesActivity" />
|
<activity android:name=".TrophiesActivity" />
|
||||||
<activity android:name=".MyFriendsActivity" />
|
|
||||||
<activity android:name=".AvatarEditorActivity" />
|
<activity android:name=".AvatarEditorActivity" />
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|||||||
@@ -1,40 +1,60 @@
|
|||||||
package com.fluxup.app;
|
package com.fluxup.app;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.text.Editable;
|
||||||
|
import android.text.TextWatcher;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import com.google.android.material.tabs.TabLayout;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import com.google.firebase.auth.FirebaseAuth;
|
||||||
|
import com.google.firebase.firestore.DocumentSnapshot;
|
||||||
|
import com.google.firebase.firestore.FieldValue;
|
||||||
|
import com.google.firebase.firestore.FirebaseFirestore;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class FindFriendsActivity extends AppCompatActivity {
|
public class FindFriendsActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private EditText etSearch;
|
private EditText etSearch;
|
||||||
private LinearLayout resultsContainer;
|
private LinearLayout resultsContainer;
|
||||||
private com.google.android.material.tabs.TabLayout tabLayout;
|
private TabLayout tabLayout;
|
||||||
private ImageButton btnClose;
|
private ImageButton btnClose;
|
||||||
private String currentTab = "Sugestões";
|
|
||||||
|
private FirebaseFirestore db;
|
||||||
|
private String myUid;
|
||||||
|
private int activeTabPosition = 0; // 0: Sugestões, 1: Os meus amigos, 2: Pendentes
|
||||||
|
|
||||||
|
private List<Usuario> allFriends = new ArrayList<>();
|
||||||
|
|
||||||
|
private static class PendingRequest {
|
||||||
|
Usuario sender;
|
||||||
|
String requestId;
|
||||||
|
PendingRequest(Usuario sender, String requestId) {
|
||||||
|
this.sender = sender;
|
||||||
|
this.requestId = requestId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private List<PendingRequest> allRequests = new ArrayList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_find_friends);
|
setContentView(R.layout.activity_find_friends);
|
||||||
|
|
||||||
|
db = FirebaseFirestore.getInstance();
|
||||||
|
myUid = FirebaseAuth.getInstance().getUid();
|
||||||
|
|
||||||
initViews();
|
initViews();
|
||||||
setupListeners();
|
setupListeners();
|
||||||
loadSuggestions();
|
loadTabContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initViews() {
|
private void initViews() {
|
||||||
@@ -47,62 +67,152 @@ public class FindFriendsActivity extends AppCompatActivity {
|
|||||||
private void setupListeners() {
|
private void setupListeners() {
|
||||||
btnClose.setOnClickListener(v -> finish());
|
btnClose.setOnClickListener(v -> finish());
|
||||||
|
|
||||||
etSearch.addTextChangedListener(new android.text.TextWatcher() {
|
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||||
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
@Override
|
||||||
@Override public void onTextChanged(CharSequence s, int start, int before, int count) {
|
public void onTabSelected(TabLayout.Tab tab) {
|
||||||
if (s.length() > 0) {
|
activeTabPosition = tab.getPosition();
|
||||||
performSearch(s.toString());
|
etSearch.setText(""); // Clear search when switching tabs
|
||||||
} else {
|
updateSearchHint();
|
||||||
loadSuggestions();
|
loadTabContent();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@Override public void afterTextChanged(android.text.Editable s) {}
|
|
||||||
|
@Override
|
||||||
|
public void onTabUnselected(TabLayout.Tab tab) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTabReselected(TabLayout.Tab tab) {}
|
||||||
});
|
});
|
||||||
|
|
||||||
tabLayout.addOnTabSelectedListener(new com.google.android.material.tabs.TabLayout.OnTabSelectedListener() {
|
etSearch.addTextChangedListener(new TextWatcher() {
|
||||||
@Override
|
@Override
|
||||||
public void onTabSelected(com.google.android.material.tabs.TabLayout.Tab tab) {
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||||
currentTab = tab.getText().toString();
|
|
||||||
if (currentTab.equals("Sugestões")) loadSuggestions();
|
@Override
|
||||||
else resultsContainer.removeAllViews(); // Placeholder for others
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
performSearch(s.toString());
|
||||||
}
|
}
|
||||||
@Override public void onTabUnselected(com.google.android.material.tabs.TabLayout.Tab tab) {}
|
|
||||||
@Override public void onTabReselected(com.google.android.material.tabs.TabLayout.Tab tab) {}
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateSearchHint() {
|
||||||
|
if (activeTabPosition == 0) {
|
||||||
|
etSearch.setHint("Procurar novas pessoas...");
|
||||||
|
} else if (activeTabPosition == 1) {
|
||||||
|
etSearch.setHint("Procurar amigos...");
|
||||||
|
} else {
|
||||||
|
etSearch.setHint("Procurar pedidos...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadTabContent() {
|
||||||
|
if (myUid == null) return;
|
||||||
|
|
||||||
|
resultsContainer.removeAllViews();
|
||||||
|
|
||||||
|
if (activeTabPosition == 0) {
|
||||||
|
loadSuggestionsTab("");
|
||||||
|
} else if (activeTabPosition == 1) {
|
||||||
|
loadFriendsTab();
|
||||||
|
} else {
|
||||||
|
loadRequestsTab();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void performSearch(String query) {
|
private void performSearch(String query) {
|
||||||
com.google.firebase.firestore.FirebaseFirestore.getInstance()
|
if (activeTabPosition == 0) {
|
||||||
.collection("users")
|
loadSuggestionsTab(query);
|
||||||
.orderBy("usuario")
|
} else if (activeTabPosition == 1) {
|
||||||
.startAt(query)
|
filterFriends(query);
|
||||||
.endAt(query + "\uf8ff")
|
} else {
|
||||||
.limit(10)
|
filterRequests(query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// TAB 0: SUGESTÕES (Discover)
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
private void loadSuggestionsTab(String query) {
|
||||||
|
// Fetch all friend IDs + sent/received request IDs to exclude
|
||||||
|
db.collection("friendships")
|
||||||
|
.whereArrayContains("users", myUid)
|
||||||
.get()
|
.get()
|
||||||
.addOnSuccessListener(snapshots -> {
|
.addOnSuccessListener(friendSnapshots -> {
|
||||||
resultsContainer.removeAllViews();
|
List<String> excludedIds = new ArrayList<>();
|
||||||
for (com.google.firebase.firestore.DocumentSnapshot doc : snapshots.getDocuments()) {
|
excludedIds.add(myUid);
|
||||||
Usuario u = doc.toObject(Usuario.class);
|
|
||||||
if (u != null) addFriendItem(u);
|
for (DocumentSnapshot doc : friendSnapshots.getDocuments()) {
|
||||||
|
List<String> users = (List<String>) doc.get("users");
|
||||||
|
if (users != null) {
|
||||||
|
for (String uId : users) {
|
||||||
|
if (!uId.equals(myUid)) excludedIds.add(uId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch sent requests
|
||||||
|
db.collection("friend_requests")
|
||||||
|
.whereEqualTo("fromUserId", myUid)
|
||||||
|
.get()
|
||||||
|
.addOnSuccessListener(sentSnap -> {
|
||||||
|
for (DocumentSnapshot doc : sentSnap.getDocuments()) {
|
||||||
|
String toUser = doc.getString("toUserId");
|
||||||
|
if (toUser != null) excludedIds.add(toUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch received requests
|
||||||
|
db.collection("friend_requests")
|
||||||
|
.whereEqualTo("toUserId", myUid)
|
||||||
|
.get()
|
||||||
|
.addOnSuccessListener(recvSnap -> {
|
||||||
|
for (DocumentSnapshot doc : recvSnap.getDocuments()) {
|
||||||
|
String fromUser = doc.getString("fromUserId");
|
||||||
|
if (fromUser != null) excludedIds.add(fromUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now query users
|
||||||
|
queryDiscoverUsers(excludedIds, query);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadSuggestions() {
|
private void queryDiscoverUsers(List<String> excludedIds, String query) {
|
||||||
com.google.firebase.firestore.FirebaseFirestore.getInstance()
|
if (query.isEmpty()) {
|
||||||
.collection("users")
|
db.collection("users")
|
||||||
.limit(10)
|
.limit(50)
|
||||||
.get()
|
.get()
|
||||||
.addOnSuccessListener(snapshots -> {
|
.addOnSuccessListener(snapshots -> {
|
||||||
resultsContainer.removeAllViews();
|
resultsContainer.removeAllViews();
|
||||||
for (com.google.firebase.firestore.DocumentSnapshot doc : snapshots.getDocuments()) {
|
for (DocumentSnapshot doc : snapshots.getDocuments()) {
|
||||||
Usuario u = doc.toObject(Usuario.class);
|
Usuario u = doc.toObject(Usuario.class);
|
||||||
if (u != null) addFriendItem(u);
|
if (u != null && !excludedIds.contains(u.id_usuario)) {
|
||||||
}
|
addDiscoverItem(u);
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
db.collection("users")
|
||||||
|
.orderBy("usuario")
|
||||||
|
.startAt(query)
|
||||||
|
.endAt(query + "\uf8ff")
|
||||||
|
.limit(50)
|
||||||
|
.get()
|
||||||
|
.addOnSuccessListener(snapshots -> {
|
||||||
|
resultsContainer.removeAllViews();
|
||||||
|
for (DocumentSnapshot doc : snapshots.getDocuments()) {
|
||||||
|
Usuario u = doc.toObject(Usuario.class);
|
||||||
|
if (u != null && !excludedIds.contains(u.id_usuario)) {
|
||||||
|
addDiscoverItem(u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFriendItem(Usuario user) {
|
private void addDiscoverItem(Usuario user) {
|
||||||
View view = getLayoutInflater().inflate(R.layout.item_friend_action, resultsContainer, false);
|
View view = getLayoutInflater().inflate(R.layout.item_friend_action, resultsContainer, false);
|
||||||
TextView tvName = view.findViewById(R.id.tvFriendName);
|
TextView tvName = view.findViewById(R.id.tvFriendName);
|
||||||
TextView tvStats = view.findViewById(R.id.tvFriendStats);
|
TextView tvStats = view.findViewById(R.id.tvFriendStats);
|
||||||
@@ -110,18 +220,239 @@ public class FindFriendsActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
tvName.setText(user.usuario);
|
tvName.setText(user.usuario);
|
||||||
tvStats.setText("Nível " + user.level + " • " + user.xp + " XP");
|
tvStats.setText("Nível " + user.level + " • " + user.xp + " XP");
|
||||||
|
btnAction.setText("Adicionar");
|
||||||
|
|
||||||
AvatarView ivAvatar = view.findViewById(R.id.ivFriendAvatar);
|
AvatarView ivAvatar = view.findViewById(R.id.ivFriendAvatar);
|
||||||
if (ivAvatar != null && user.avatar != null) {
|
if (ivAvatar != null && user.avatar != null) {
|
||||||
ivAvatar.setAvatarData(user.avatar);
|
ivAvatar.setAvatarData(user.avatar);
|
||||||
ivAvatar.setLeague(user.league);
|
ivAvatar.setLeague(user.league);
|
||||||
}
|
}
|
||||||
|
|
||||||
btnAction.setOnClickListener(v -> {
|
btnAction.setOnClickListener(v -> {
|
||||||
btnAction.setText("Pendente");
|
btnAction.setText("Pendente");
|
||||||
btnAction.setEnabled(false);
|
btnAction.setEnabled(false);
|
||||||
btnAction.setAlpha(0.5f);
|
btnAction.setAlpha(0.5f);
|
||||||
Toast.makeText(this, "Pedido enviado para " + user.usuario, Toast.LENGTH_SHORT).show();
|
|
||||||
|
Map<String, Object> req = new HashMap<>();
|
||||||
|
req.put("fromUserId", myUid);
|
||||||
|
req.put("toUserId", user.id_usuario);
|
||||||
|
req.put("status", "pending");
|
||||||
|
req.put("timestamp", FieldValue.serverTimestamp());
|
||||||
|
|
||||||
|
String reqId = myUid + "_" + user.id_usuario;
|
||||||
|
db.collection("friend_requests").document(reqId).set(req)
|
||||||
|
.addOnSuccessListener(aVoid -> {
|
||||||
|
Toast.makeText(this, "Pedido enviado para " + user.usuario, Toast.LENGTH_SHORT).show();
|
||||||
|
})
|
||||||
|
.addOnFailureListener(e -> {
|
||||||
|
btnAction.setText("Adicionar");
|
||||||
|
btnAction.setEnabled(true);
|
||||||
|
btnAction.setAlpha(1.0f);
|
||||||
|
Toast.makeText(this, "Erro ao enviar pedido.", Toast.LENGTH_SHORT).show();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
resultsContainer.addView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// TAB 1: OS MEUS AMIGOS
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
private void loadFriendsTab() {
|
||||||
|
db.collection("friendships")
|
||||||
|
.whereArrayContains("users", myUid)
|
||||||
|
.get()
|
||||||
|
.addOnSuccessListener(snapshots -> {
|
||||||
|
allFriends.clear();
|
||||||
|
if (snapshots.isEmpty()) {
|
||||||
|
resultsContainer.removeAllViews();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> friendIds = new ArrayList<>();
|
||||||
|
for (DocumentSnapshot doc : snapshots.getDocuments()) {
|
||||||
|
List<String> users = (List<String>) doc.get("users");
|
||||||
|
if (users != null) {
|
||||||
|
for (String uId : users) {
|
||||||
|
if (!uId.equals(myUid)) friendIds.add(uId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (friendIds.isEmpty()) {
|
||||||
|
resultsContainer.removeAllViews();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int[] remaining = {friendIds.size()};
|
||||||
|
for (String friendId : friendIds) {
|
||||||
|
db.collection("users").document(friendId).get().addOnSuccessListener(snapshot -> {
|
||||||
|
Usuario friend = snapshot.toObject(Usuario.class);
|
||||||
|
if (friend != null) {
|
||||||
|
allFriends.add(friend);
|
||||||
|
}
|
||||||
|
remaining[0]--;
|
||||||
|
if (remaining[0] == 0) {
|
||||||
|
filterFriends(etSearch.getText().toString());
|
||||||
|
}
|
||||||
|
}).addOnFailureListener(e -> {
|
||||||
|
remaining[0]--;
|
||||||
|
if (remaining[0] == 0) {
|
||||||
|
filterFriends(etSearch.getText().toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void filterFriends(String query) {
|
||||||
|
resultsContainer.removeAllViews();
|
||||||
|
for (Usuario friend : allFriends) {
|
||||||
|
if (query.isEmpty() || friend.usuario.toLowerCase().contains(query.toLowerCase())) {
|
||||||
|
addFriendItem(friend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFriendItem(Usuario friend) {
|
||||||
|
View view = getLayoutInflater().inflate(R.layout.item_friend_action, resultsContainer, false);
|
||||||
|
TextView tvName = view.findViewById(R.id.tvFriendName);
|
||||||
|
TextView tvStats = view.findViewById(R.id.tvFriendStats);
|
||||||
|
Button btnAction = view.findViewById(R.id.btnFriendAction);
|
||||||
|
|
||||||
|
tvName.setText(friend.usuario);
|
||||||
|
tvStats.setText("Nível " + friend.level + " • " + friend.xp + " XP • 🔥 " + friend.streak);
|
||||||
|
btnAction.setText("Ver perfil");
|
||||||
|
|
||||||
|
AvatarView ivAvatar = view.findViewById(R.id.ivFriendAvatar);
|
||||||
|
if (ivAvatar != null && friend.avatar != null) {
|
||||||
|
ivAvatar.setAvatarData(friend.avatar);
|
||||||
|
ivAvatar.setLeague(friend.league);
|
||||||
|
}
|
||||||
|
|
||||||
|
View.OnClickListener clickListener = v -> {
|
||||||
|
Toast.makeText(this, "Perfil de " + friend.usuario, Toast.LENGTH_SHORT).show();
|
||||||
|
};
|
||||||
|
|
||||||
|
btnAction.setOnClickListener(clickListener);
|
||||||
|
view.setOnClickListener(clickListener);
|
||||||
|
|
||||||
|
resultsContainer.addView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// TAB 2: PENDENTES (Requests)
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
private void loadRequestsTab() {
|
||||||
|
db.collection("friend_requests")
|
||||||
|
.whereEqualTo("toUserId", myUid)
|
||||||
|
.whereEqualTo("status", "pending")
|
||||||
|
.get()
|
||||||
|
.addOnSuccessListener(snapshots -> {
|
||||||
|
allRequests.clear();
|
||||||
|
if (snapshots.isEmpty()) {
|
||||||
|
resultsContainer.removeAllViews();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> senderIds = new ArrayList<>();
|
||||||
|
Map<String, String> requestMap = new HashMap<>(); // senderId -> requestId
|
||||||
|
|
||||||
|
for (DocumentSnapshot doc : snapshots.getDocuments()) {
|
||||||
|
String fromUserId = doc.getString("fromUserId");
|
||||||
|
if (fromUserId != null) {
|
||||||
|
senderIds.add(fromUserId);
|
||||||
|
requestMap.put(fromUserId, doc.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final int[] remaining = {senderIds.size()};
|
||||||
|
for (String senderId : senderIds) {
|
||||||
|
db.collection("users").document(senderId).get().addOnSuccessListener(userSnap -> {
|
||||||
|
Usuario sender = userSnap.toObject(Usuario.class);
|
||||||
|
if (sender != null) {
|
||||||
|
allRequests.add(new PendingRequest(sender, requestMap.get(senderId)));
|
||||||
|
}
|
||||||
|
remaining[0]--;
|
||||||
|
if (remaining[0] == 0) {
|
||||||
|
filterRequests(etSearch.getText().toString());
|
||||||
|
}
|
||||||
|
}).addOnFailureListener(e -> {
|
||||||
|
remaining[0]--;
|
||||||
|
if (remaining[0] == 0) {
|
||||||
|
filterRequests(etSearch.getText().toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void filterRequests(String query) {
|
||||||
|
resultsContainer.removeAllViews();
|
||||||
|
for (PendingRequest req : allRequests) {
|
||||||
|
if (query.isEmpty() || req.sender.usuario.toLowerCase().contains(query.toLowerCase())) {
|
||||||
|
addRequestItem(req.sender, req.requestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addRequestItem(Usuario sender, String requestId) {
|
||||||
|
View view = getLayoutInflater().inflate(R.layout.item_friend_request, resultsContainer, false);
|
||||||
|
TextView tvName = view.findViewById(R.id.tvFriendName);
|
||||||
|
TextView tvStats = view.findViewById(R.id.tvFriendStats);
|
||||||
|
Button btnAccept = view.findViewById(R.id.btnAcceptFriend);
|
||||||
|
Button btnReject = view.findViewById(R.id.btnRejectFriend);
|
||||||
|
|
||||||
|
tvName.setText(sender.usuario);
|
||||||
|
tvStats.setText(sender.xp + " XP");
|
||||||
|
|
||||||
|
AvatarView ivAvatar = view.findViewById(R.id.ivFriendAvatar);
|
||||||
|
if (ivAvatar != null && sender.avatar != null) {
|
||||||
|
ivAvatar.setAvatarData(sender.avatar);
|
||||||
|
ivAvatar.setLeague(sender.league);
|
||||||
|
}
|
||||||
|
|
||||||
|
btnAccept.setOnClickListener(v -> {
|
||||||
|
btnAccept.setEnabled(false);
|
||||||
|
btnReject.setEnabled(false);
|
||||||
|
|
||||||
|
String friendshipId = myUid.compareTo(sender.id_usuario) < 0 ? myUid + "_" + sender.id_usuario : sender.id_usuario + "_" + myUid;
|
||||||
|
Map<String, Object> friendship = new HashMap<>();
|
||||||
|
List<String> users = new ArrayList<>();
|
||||||
|
users.add(myUid);
|
||||||
|
users.add(sender.id_usuario);
|
||||||
|
friendship.put("users", users);
|
||||||
|
friendship.put("timestamp", FieldValue.serverTimestamp());
|
||||||
|
|
||||||
|
db.collection("friendships").document(friendshipId).set(friendship)
|
||||||
|
.addOnSuccessListener(aVoid -> {
|
||||||
|
db.collection("friend_requests").document(requestId).delete()
|
||||||
|
.addOnSuccessListener(aVoid2 -> {
|
||||||
|
Toast.makeText(this, "Pedido de " + sender.usuario + " aceite!", Toast.LENGTH_SHORT).show();
|
||||||
|
loadTabContent();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.addOnFailureListener(e -> {
|
||||||
|
btnAccept.setEnabled(true);
|
||||||
|
btnReject.setEnabled(true);
|
||||||
|
Toast.makeText(this, "Erro ao aceitar pedido.", Toast.LENGTH_SHORT).show();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
btnReject.setOnClickListener(v -> {
|
||||||
|
btnAccept.setEnabled(false);
|
||||||
|
btnReject.setEnabled(false);
|
||||||
|
|
||||||
|
db.collection("friend_requests").document(requestId).delete()
|
||||||
|
.addOnSuccessListener(aVoid -> {
|
||||||
|
Toast.makeText(this, "Pedido recusado.", Toast.LENGTH_SHORT).show();
|
||||||
|
loadTabContent();
|
||||||
|
})
|
||||||
|
.addOnFailureListener(e -> {
|
||||||
|
btnAccept.setEnabled(true);
|
||||||
|
btnReject.setEnabled(true);
|
||||||
|
Toast.makeText(this, "Erro ao recusar pedido.", Toast.LENGTH_SHORT).show();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
resultsContainer.addView(view);
|
resultsContainer.addView(view);
|
||||||
|
|||||||
@@ -42,12 +42,11 @@ public class InicioFragment extends Fragment {
|
|||||||
private TextView tvTimer, tvGreeting, tvMotivationalSubtitle, tvFocusStatus, tvFocusTitle;
|
private TextView tvTimer, tvGreeting, tvMotivationalSubtitle, tvFocusStatus, tvFocusTitle;
|
||||||
private AvatarView ivUserAvatar;
|
private AvatarView ivUserAvatar;
|
||||||
private TextView tvTodayStreak, tvTodayXP, tvTodayTasksCount, tvNoTasksIncentive;
|
private TextView tvTodayStreak, tvTodayXP, tvTodayTasksCount, tvNoTasksIncentive;
|
||||||
private TextView tvDailyRewardGoal;
|
|
||||||
private ProgressBar pbDailyTasksProgress;
|
private ProgressBar pbDailyTasksProgress;
|
||||||
private androidx.recyclerview.widget.RecyclerView rvTasks;
|
private androidx.recyclerview.widget.RecyclerView rvTasks;
|
||||||
private TasksAdapter tasksAdapter;
|
private TasksAdapter tasksAdapter;
|
||||||
private LinearLayout miniRankingContainer, layoutTasksSection;
|
private LinearLayout miniRankingContainer, layoutTasksSection;
|
||||||
private Button btnStartFocus, btnSecondaryFocus, btnAddTasks, btnClaimReward;
|
private Button btnStartFocus, btnSecondaryFocus, btnAddTasks;
|
||||||
private androidx.cardview.widget.CardView btnStreakPage;
|
private androidx.cardview.widget.CardView btnStreakPage;
|
||||||
|
|
||||||
private CountDownTimer countDownTimer;
|
private CountDownTimer countDownTimer;
|
||||||
@@ -145,10 +144,15 @@ public class InicioFragment extends Fragment {
|
|||||||
startActivity(new android.content.Intent(getActivity(), TrophiesActivity.class));
|
startActivity(new android.content.Intent(getActivity(), TrophiesActivity.class));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reward
|
// Promo Card to Rewards Tab
|
||||||
tvDailyRewardGoal = view.findViewById(R.id.tvDailyRewardGoal);
|
view.findViewById(R.id.cardRewardsPromo).setOnClickListener(v -> {
|
||||||
btnClaimReward = view.findViewById(R.id.btnClaimReward);
|
if (getActivity() instanceof MainActivity) {
|
||||||
btnClaimReward.setOnClickListener(v -> claimDailyReward());
|
BottomNavigationView nav = ((MainActivity) getActivity()).findViewById(R.id.bottom_navigation);
|
||||||
|
if (nav != null) {
|
||||||
|
nav.setSelectedItemId(R.id.nav_rewards);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Streak Page
|
// Streak Page
|
||||||
btnStreakPage = view.findViewById(R.id.btnStreakPage);
|
btnStreakPage = view.findViewById(R.id.btnStreakPage);
|
||||||
@@ -797,33 +801,27 @@ public class InicioFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void claimDailyReward() {
|
|
||||||
FirebaseUser currentUser = AuthManager.getInstance().getCurrentUser();
|
|
||||||
if (currentUser != null) {
|
|
||||||
String today = new java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.US).format(new java.util.Date());
|
|
||||||
Map<String, Object> updates = new HashMap<>();
|
|
||||||
updates.put("last_reward_claim_date", today);
|
|
||||||
FirestoreManager.getInstance().updateUserStats(currentUser.getUid(), updates);
|
|
||||||
addXP(100);
|
|
||||||
|
|
||||||
btnClaimReward.setEnabled(false);
|
|
||||||
btnClaimReward.setText("Resgatado");
|
|
||||||
btnClaimReward.setAlpha(0.5f);
|
|
||||||
|
|
||||||
if (getContext() != null) {
|
|
||||||
Toast.makeText(getContext(), "Recompensa diária resgatada! +100 XP", Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showDeleteConfirmDialog(Task task) {
|
private void showDeleteConfirmDialog(Task task) {
|
||||||
new com.google.android.material.dialog.MaterialAlertDialogBuilder(getContext())
|
new com.google.android.material.dialog.MaterialAlertDialogBuilder(getContext())
|
||||||
.setTitle("Eliminar Tarefa")
|
.setTitle("Apagar Tarefa")
|
||||||
.setMessage("Tens a certeza que queres eliminar esta tarefa?")
|
.setMessage("Tens a certeza que queres apagar esta tarefa?")
|
||||||
.setNegativeButton("Cancelar", null)
|
.setNegativeButton("Cancelar", null)
|
||||||
.setPositiveButton("Sim", (dialog, which) -> {
|
.setPositiveButton("Apagar", (dialog, which) -> {
|
||||||
FirestoreManager.getInstance().deleteTask(task.id);
|
com.google.firebase.firestore.FirebaseFirestore.getInstance()
|
||||||
refreshHomeStats();
|
.collection("tasks").document(task.id).delete()
|
||||||
|
.addOnSuccessListener(aVoid -> {
|
||||||
|
refreshHomeStats();
|
||||||
|
if (getContext() != null) {
|
||||||
|
Toast.makeText(getContext(), "Tarefa apagada.", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.addOnFailureListener(e -> {
|
||||||
|
if (getContext() != null) {
|
||||||
|
Toast.makeText(getContext(), "Erro ao apagar tarefa: " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
@@ -1150,6 +1148,7 @@ public class InicioFragment extends Fragment {
|
|||||||
new com.google.android.material.dialog.MaterialAlertDialogBuilder(getContext())
|
new com.google.android.material.dialog.MaterialAlertDialogBuilder(getContext())
|
||||||
.setTitle("Editar Tarefa")
|
.setTitle("Editar Tarefa")
|
||||||
.setView(dialogView)
|
.setView(dialogView)
|
||||||
|
.setNeutralButton("Apagar", (dialog, which) -> showDeleteConfirmDialog(task))
|
||||||
.setNegativeButton("Cancelar", null)
|
.setNegativeButton("Cancelar", null)
|
||||||
.setPositiveButton("Atualizar", (dialog, which) -> {
|
.setPositiveButton("Atualizar", (dialog, which) -> {
|
||||||
String title = etTitle.getText().toString().trim();
|
String title = etTitle.getText().toString().trim();
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
} else if (itemId == R.id.nav_trophies) {
|
} else if (itemId == R.id.nav_trophies) {
|
||||||
startActivity(new android.content.Intent(this, TrophiesActivity.class));
|
startActivity(new android.content.Intent(this, TrophiesActivity.class));
|
||||||
return true;
|
return true;
|
||||||
|
} else if (itemId == R.id.nav_rewards) {
|
||||||
|
selectedFragment = new RewardsFragment();
|
||||||
} else if (itemId == R.id.nav_profile) {
|
} else if (itemId == R.id.nav_profile) {
|
||||||
selectedFragment = new ProfileFragment();
|
selectedFragment = new ProfileFragment();
|
||||||
} else if (itemId == R.id.nav_search) {
|
} else if (itemId == R.id.nav_search) {
|
||||||
|
|||||||
@@ -1,109 +0,0 @@
|
|||||||
package com.fluxup.app;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import com.google.firebase.auth.FirebaseAuth;
|
|
||||||
import com.google.firebase.firestore.FirebaseFirestore;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class MyFriendsActivity extends AppCompatActivity {
|
|
||||||
|
|
||||||
private EditText etSearch;
|
|
||||||
private LinearLayout friendsContainer, emptyState;
|
|
||||||
private TextView tvFriendsCount;
|
|
||||||
private FirebaseFirestore db;
|
|
||||||
private String myUid;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.activity_my_friends);
|
|
||||||
|
|
||||||
db = FirebaseFirestore.getInstance();
|
|
||||||
myUid = FirebaseAuth.getInstance().getUid();
|
|
||||||
|
|
||||||
etSearch = findViewById(R.id.etSearchFriends);
|
|
||||||
friendsContainer = findViewById(R.id.friendsListContainer);
|
|
||||||
emptyState = findViewById(R.id.emptyStateContainer);
|
|
||||||
tvFriendsCount = findViewById(R.id.tvFriendsCount);
|
|
||||||
|
|
||||||
findViewById(R.id.btnBack).setOnClickListener(v -> finish());
|
|
||||||
findViewById(R.id.btnFindNewFriends).setOnClickListener(v -> startActivity(new Intent(this, FindFriendsActivity.class)));
|
|
||||||
findViewById(R.id.btnGoToFindFriends).setOnClickListener(v -> startActivity(new Intent(this, FindFriendsActivity.class)));
|
|
||||||
|
|
||||||
loadFriends();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadFriends() {
|
|
||||||
if (myUid == null) return;
|
|
||||||
|
|
||||||
// Fetching users I follow
|
|
||||||
db.collection("follows")
|
|
||||||
.whereEqualTo("followerId", myUid)
|
|
||||||
.get()
|
|
||||||
.addOnSuccessListener(snapshots -> {
|
|
||||||
if (snapshots.isEmpty()) {
|
|
||||||
showEmptyState(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
showEmptyState(false);
|
|
||||||
tvFriendsCount.setText(snapshots.size() + " Amigos");
|
|
||||||
friendsContainer.removeAllViews();
|
|
||||||
|
|
||||||
for (com.google.firebase.firestore.DocumentSnapshot doc : snapshots.getDocuments()) {
|
|
||||||
String friendId = doc.getString("followingId");
|
|
||||||
if (friendId != null) {
|
|
||||||
fetchFriendDetails(friendId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fetchFriendDetails(String friendId) {
|
|
||||||
db.collection("users").document(friendId).get().addOnSuccessListener(snapshot -> {
|
|
||||||
Usuario friend = snapshot.toObject(Usuario.class);
|
|
||||||
if (friend != null) {
|
|
||||||
addFriendItem(friend);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addFriendItem(Usuario friend) {
|
|
||||||
View view = getLayoutInflater().inflate(R.layout.item_ranking_user, friendsContainer, false);
|
|
||||||
TextView tvName = view.findViewById(R.id.tvRankingName);
|
|
||||||
TextView tvXP = view.findViewById(R.id.tvRankingXP);
|
|
||||||
TextView tvLabel = view.findViewById(R.id.tvRankingLabelTu);
|
|
||||||
|
|
||||||
tvName.setText(friend.usuario);
|
|
||||||
tvXP.setText(friend.xp + " XP");
|
|
||||||
tvLabel.setText("Nível " + friend.level);
|
|
||||||
tvLabel.setVisibility(View.VISIBLE);
|
|
||||||
tvLabel.setTextColor(getResources().getColor(R.color.primary_purple));
|
|
||||||
|
|
||||||
AvatarView ivAvatar = view.findViewById(R.id.ivRankingAvatar);
|
|
||||||
if (ivAvatar != null && friend.avatar != null) {
|
|
||||||
ivAvatar.setAvatarData(friend.avatar);
|
|
||||||
ivAvatar.setLeague(friend.league);
|
|
||||||
}
|
|
||||||
|
|
||||||
view.setOnClickListener(v -> {
|
|
||||||
// Open public profile (future)
|
|
||||||
Toast.makeText(this, "Perfil de " + friend.usuario, Toast.LENGTH_SHORT).show();
|
|
||||||
});
|
|
||||||
|
|
||||||
friendsContainer.addView(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showEmptyState(boolean show) {
|
|
||||||
emptyState.setVisibility(show ? View.VISIBLE : View.GONE);
|
|
||||||
friendsContainer.setVisibility(show ? View.GONE : View.VISIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -134,19 +134,19 @@ public class ProfileFragment extends Fragment {
|
|||||||
// Add Friends (+)
|
// Add Friends (+)
|
||||||
View btnAddFriends = view.findViewById(R.id.btnAddFriends);
|
View btnAddFriends = view.findViewById(R.id.btnAddFriends);
|
||||||
if (btnAddFriends != null) {
|
if (btnAddFriends != null) {
|
||||||
btnAddFriends.setOnClickListener(v -> startActivity(new Intent(getActivity(), MyFriendsActivity.class)));
|
btnAddFriends.setOnClickListener(v -> startActivity(new Intent(getActivity(), FindFriendsActivity.class)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// View All Friends
|
// View All Friends
|
||||||
View btnViewAllFriends = view.findViewById(R.id.btnViewAllFriends);
|
View btnViewAllFriends = view.findViewById(R.id.btnViewAllFriends);
|
||||||
if (btnViewAllFriends != null) {
|
if (btnViewAllFriends != null) {
|
||||||
btnViewAllFriends.setOnClickListener(v -> startActivity(new Intent(getActivity(), MyFriendsActivity.class)));
|
btnViewAllFriends.setOnClickListener(v -> startActivity(new Intent(getActivity(), FindFriendsActivity.class)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find Friends (ADICIONAR AMIGOS)
|
// Find Friends (ADICIONAR AMIGOS)
|
||||||
View btnFindFriends = view.findViewById(R.id.btnFindFriends);
|
View btnFindFriends = view.findViewById(R.id.btnFindFriends);
|
||||||
if (btnFindFriends != null) {
|
if (btnFindFriends != null) {
|
||||||
btnFindFriends.setOnClickListener(v -> startActivity(new Intent(getActivity(), MyFriendsActivity.class)));
|
btnFindFriends.setOnClickListener(v -> startActivity(new Intent(getActivity(), FindFriendsActivity.class)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// View All Badges
|
// View All Badges
|
||||||
@@ -408,21 +408,39 @@ public class ProfileFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void startObservingFriends() {
|
private void startObservingFriends() {
|
||||||
|
if (AuthManager.getInstance().getCurrentUser() == null) return;
|
||||||
|
String myUid = AuthManager.getInstance().getCurrentUser().getUid();
|
||||||
friendsListener = com.google.firebase.firestore.FirebaseFirestore.getInstance()
|
friendsListener = com.google.firebase.firestore.FirebaseFirestore.getInstance()
|
||||||
.collection("users")
|
.collection("friendships")
|
||||||
|
.whereArrayContains("users", myUid)
|
||||||
.limit(3)
|
.limit(3)
|
||||||
.addSnapshotListener((snapshots, e) -> {
|
.addSnapshotListener((snapshots, e) -> {
|
||||||
if (e != null || snapshots == null) return;
|
if (e != null || snapshots == null) return;
|
||||||
friendsListContainer.removeAllViews();
|
friendsListContainer.removeAllViews();
|
||||||
for (com.google.firebase.firestore.DocumentSnapshot doc : snapshots.getDocuments()) {
|
for (com.google.firebase.firestore.DocumentSnapshot doc : snapshots.getDocuments()) {
|
||||||
Usuario f = doc.toObject(Usuario.class);
|
List<String> users = (List<String>) doc.get("users");
|
||||||
if (f != null && !f.id_usuario.equals(AuthManager.getInstance().getCurrentUser().getUid())) {
|
if (users != null) {
|
||||||
addFriendItem(f);
|
for (String uId : users) {
|
||||||
|
if (!uId.equals(myUid)) {
|
||||||
|
fetchAndAddProfileFriendItem(uId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fetchAndAddProfileFriendItem(String friendId) {
|
||||||
|
com.google.firebase.firestore.FirebaseFirestore.getInstance()
|
||||||
|
.collection("users").document(friendId).get().addOnSuccessListener(snapshot -> {
|
||||||
|
if (getContext() == null || view == null) return;
|
||||||
|
Usuario friend = snapshot.toObject(Usuario.class);
|
||||||
|
if (friend != null) {
|
||||||
|
addFriendItem(friend);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void addFriendItem(Usuario friend) {
|
private void addFriendItem(Usuario friend) {
|
||||||
View v = getLayoutInflater().inflate(R.layout.item_ranking_user, friendsListContainer, false);
|
View v = getLayoutInflater().inflate(R.layout.item_ranking_user, friendsListContainer, false);
|
||||||
((TextView) v.findViewById(R.id.tvRankingName)).setText(friend.usuario);
|
((TextView) v.findViewById(R.id.tvRankingName)).setText(friend.usuario);
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import com.google.firebase.auth.FirebaseAuth;
|
import com.google.firebase.auth.FirebaseAuth;
|
||||||
import com.google.firebase.firestore.ListenerRegistration;
|
import com.google.firebase.firestore.ListenerRegistration;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
@@ -219,26 +221,94 @@ public class TrophiesActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void observeRanking(String filter) {
|
private void observeRanking(String filter) {
|
||||||
if (rankingListener != null) rankingListener.remove();
|
if (rankingListener != null) {
|
||||||
|
rankingListener.remove();
|
||||||
|
rankingListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
com.google.firebase.firestore.Query query = com.google.firebase.firestore.FirebaseFirestore.getInstance()
|
String myUid = mAuth.getUid();
|
||||||
.collection("users")
|
android.util.Log.d("FLUXUP_DEBUG", "CURRENT_USER_ID: " + myUid);
|
||||||
.orderBy("xp_semanal", com.google.firebase.firestore.Query.Direction.DESCENDING)
|
android.util.Log.d("FLUXUP_DEBUG", "LEAGUE_TAB_SELECTED: " + filter);
|
||||||
.limit(20);
|
|
||||||
|
|
||||||
rankingListener = query.addSnapshotListener((snapshots, e) -> {
|
if ("friends".equals(filter)) {
|
||||||
if (e != null || snapshots == null) return;
|
// Load accepted friends from "friendships"
|
||||||
rankingContainer.removeAllViews();
|
com.google.firebase.firestore.FirebaseFirestore.getInstance()
|
||||||
|
.collection("friendships")
|
||||||
int position = 1;
|
.whereArrayContains("users", myUid)
|
||||||
String myUid = mAuth.getUid();
|
.get()
|
||||||
|
.addOnSuccessListener(snapshots -> {
|
||||||
|
List<String> friendIds = new ArrayList<>();
|
||||||
|
for (com.google.firebase.firestore.DocumentSnapshot doc : snapshots.getDocuments()) {
|
||||||
|
List<String> users = (List<String>) doc.get("users");
|
||||||
|
if (users != null) {
|
||||||
|
for (String uId : users) {
|
||||||
|
if (!uId.equals(myUid)) {
|
||||||
|
friendIds.add(uId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (com.google.firebase.firestore.DocumentSnapshot doc : snapshots.getDocuments()) {
|
android.util.Log.d("FLUXUP_DEBUG", "MY_ACCEPTED_FRIENDS_COUNT: " + friendIds.size());
|
||||||
Usuario user = doc.toObject(Usuario.class);
|
android.util.Log.d("FLUXUP_DEBUG", "LEAGUE_FRIENDS_LIST: " + friendIds.toString());
|
||||||
if (user == null) continue;
|
|
||||||
addRankingItem(position++, user, myUid);
|
rankingContainer.removeAllViews();
|
||||||
}
|
if (friendIds.isEmpty()) {
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch details of all friends and sort by xp_semanal desc
|
||||||
|
List<Usuario> friendList = new ArrayList<>();
|
||||||
|
final int[] remaining = {friendIds.size()};
|
||||||
|
for (String friendId : friendIds) {
|
||||||
|
com.google.firebase.firestore.FirebaseFirestore.getInstance()
|
||||||
|
.collection("users").document(friendId).get().addOnSuccessListener(userSnap -> {
|
||||||
|
Usuario friend = userSnap.toObject(Usuario.class);
|
||||||
|
if (friend != null) {
|
||||||
|
friendList.add(friend);
|
||||||
|
}
|
||||||
|
remaining[0]--;
|
||||||
|
if (remaining[0] == 0) {
|
||||||
|
// Sort by xp_semanal descending
|
||||||
|
friendList.sort((u1, u2) -> Integer.compare(u2.xp_semanal, u1.xp_semanal));
|
||||||
|
int pos = 1;
|
||||||
|
for (Usuario u : friendList) {
|
||||||
|
addRankingItem(pos++, u, myUid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).addOnFailureListener(e -> {
|
||||||
|
remaining[0]--;
|
||||||
|
if (remaining[0] == 0) {
|
||||||
|
friendList.sort((u1, u2) -> Integer.compare(u2.xp_semanal, u1.xp_semanal));
|
||||||
|
int pos = 1;
|
||||||
|
for (Usuario u : friendList) {
|
||||||
|
addRankingItem(pos++, u, myUid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Global ranking
|
||||||
|
com.google.firebase.firestore.Query query = com.google.firebase.firestore.FirebaseFirestore.getInstance()
|
||||||
|
.collection("users")
|
||||||
|
.orderBy("xp_semanal", com.google.firebase.firestore.Query.Direction.DESCENDING)
|
||||||
|
.limit(20);
|
||||||
|
|
||||||
|
rankingListener = query.addSnapshotListener((snapshots, e) -> {
|
||||||
|
if (e != null || snapshots == null) return;
|
||||||
|
|
||||||
|
android.util.Log.d("FLUXUP_DEBUG", "GLOBAL_RANKING_COUNT: " + snapshots.size());
|
||||||
|
|
||||||
|
rankingContainer.removeAllViews();
|
||||||
|
int position = 1;
|
||||||
|
for (com.google.firebase.firestore.DocumentSnapshot doc : snapshots.getDocuments()) {
|
||||||
|
Usuario user = doc.toObject(Usuario.class);
|
||||||
|
if (user == null) continue;
|
||||||
|
addRankingItem(position++, user, myUid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addRankingItem(int pos, Usuario user, String myUid) {
|
private void addRankingItem(int pos, Usuario user, String myUid) {
|
||||||
|
|||||||
@@ -40,6 +40,15 @@ public class Usuario {
|
|||||||
public AvatarData avatar = new AvatarData(); // Avatar gamificado
|
public AvatarData avatar = new AvatarData(); // Avatar gamificado
|
||||||
public java.util.List<String> dias_concluidos = new java.util.ArrayList<>();
|
public java.util.List<String> dias_concluidos = new java.util.ArrayList<>();
|
||||||
|
|
||||||
|
// Gamification & Rewards
|
||||||
|
public int login_streak = 0;
|
||||||
|
public String last_login_claim_date = ""; // YYYY-MM-DD
|
||||||
|
public java.util.List<String> claimed_missions_today = new java.util.ArrayList<>();
|
||||||
|
public String claimed_missions_date = ""; // YYYY-MM-DD
|
||||||
|
public java.util.List<String> claimed_streak_rewards = new java.util.ArrayList<>();
|
||||||
|
public String last_box_open_date = ""; // YYYY-MM-DD
|
||||||
|
public int coins = 0;
|
||||||
|
|
||||||
public Usuario() {}
|
public Usuario() {}
|
||||||
|
|
||||||
public Usuario(String id_usuario, String usuario, String email, String palavra_passe, String numero) {
|
public Usuario(String id_usuario, String usuario, String email, String palavra_passe, String numero) {
|
||||||
|
|||||||
@@ -1,122 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@color/background_light">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@color/card_background"
|
|
||||||
app:elevation="0dp">
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="64dp"
|
|
||||||
android:paddingHorizontal="16dp">
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/btnBack"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:src="@drawable/ic_back"
|
|
||||||
app:tint="@color/text_primary" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:text="Os Meus Amigos"
|
|
||||||
android:textColor="@color/text_primary"
|
|
||||||
android:textSize="20sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
</RelativeLayout>
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="20dp">
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/etSearchFriends"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="50dp"
|
|
||||||
android:background="@drawable/edittext_bg"
|
|
||||||
android:hint="Pesquisar amigos..."
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:layout_marginBottom="20dp"
|
|
||||||
android:drawableStart="@drawable/ic_nav_search"
|
|
||||||
android:drawablePadding="12dp"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:inputType="text"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_marginBottom="16dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvFriendsCount"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="0 Amigos"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:textColor="@color/text_primary"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/btnFindNewFriends"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Encontrar Novos"
|
|
||||||
android:textColor="@color/primary_purple"
|
|
||||||
android:textStyle="bold"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/friendsListContainer"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/emptyStateContainer"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="40dp"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Ainda não tens amigos adicionados."
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textColor="@color/text_secondary"
|
|
||||||
android:layout_marginBottom="20dp"/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/btnGoToFindFriends"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Encontrar Amigos"
|
|
||||||
android:backgroundTint="@color/primary_purple"
|
|
||||||
android:textAllCaps="false"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
||||||
@@ -443,14 +443,17 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
<!-- 7. 🎁 RECOMPENSA DIÁRIA -->
|
<!-- 7. 🎁 ACESSO ÀS RECOMPENSAS -->
|
||||||
<androidx.cardview.widget.CardView
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/cardRewardsPromo"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="32dp"
|
android:layout_marginBottom="32dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
app:cardCornerRadius="@dimen/radius_duo"
|
app:cardCornerRadius="@dimen/radius_duo"
|
||||||
app:cardElevation="2dp"
|
app:cardElevation="2dp">
|
||||||
app:cardBackgroundColor="@color/primary_purple">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -471,36 +474,30 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_marginStart="16dp">
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="8dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Presente diário"
|
android:text="Central de Recompensas"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/text_primary"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textSize="16sp"/>
|
android:textSize="16sp"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvDailyRewardGoal"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Completa 3 tarefas hoje para ganhar +100 XP"
|
android:text="Resgata prémios, missões e sequências diárias!"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/text_secondary"
|
||||||
android:alpha="0.8"
|
|
||||||
android:textSize="12sp"/>
|
android:textSize="12sp"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<Button
|
<ImageView
|
||||||
android:id="@+id/btnClaimReward"
|
android:layout_width="24dp"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="24dp"
|
||||||
android:layout_height="wrap_content"
|
android:src="@drawable/ic_arrow_right"
|
||||||
android:text="Resgatar"
|
app:tint="@color/primary_purple"/>
|
||||||
android:textSize="12sp"
|
|
||||||
android:textColor="@color/primary_purple"
|
|
||||||
android:backgroundTint="@color/white"
|
|
||||||
android:enabled="false"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.UnelevatedButton"/>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
android:id="@+id/nav_trophies"
|
android:id="@+id/nav_trophies"
|
||||||
android:icon="@drawable/ic_nav_trophy"
|
android:icon="@drawable/ic_nav_trophy"
|
||||||
android:title="Troféus" />
|
android:title="Troféus" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_rewards"
|
||||||
|
android:icon="@drawable/ic_nav_rewards"
|
||||||
|
android:title="Recompensas" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_profile"
|
android:id="@+id/nav_profile"
|
||||||
android:icon="@drawable/ic_nav_profile"
|
android:icon="@drawable/ic_nav_profile"
|
||||||
|
|||||||
Reference in New Issue
Block a user