Update de muchos cambios, nuevas funcionalidades en la app, juegos finalizados y todos juntos en una app)

This commit is contained in:
Andrés Moran 2025-05-23 17:15:20 +02:00
parent b616edef1f
commit da463260aa
980 changed files with 9129 additions and 10042 deletions

View File

@ -4,7 +4,7 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-04-18T20:03:38.478308800Z">
<DropdownSelection timestamp="2025-05-23T14:38:41.985444400Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\moran\.android\avd\Pixel_9_Pro.avd" />

View File

@ -48,5 +48,9 @@ dependencies {
androidTestImplementation(libs.espresso.core)
implementation("com.github.PhilJay:MPAndroidChart:v3.1.0")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation ("androidx.security:security-crypto:1.1.0-alpha06")
implementation("com.github.bumptech.glide:glide:4.15.1")
}

View File

@ -18,6 +18,7 @@
<activity
android:name=".ui.MainActivity"
android:exported="true"
android:screenOrientation="portrait"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View File

@ -0,0 +1,12 @@
package com.andresgmoran.apptrabajadores.exceptions;
public class ParserException extends RuntimeException {
public ParserException(String message) {
super(message);
}
public ParserException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -6,5 +6,6 @@ import com.andresgmoran.apptrabajadores.models.ActivityResident;
import java.util.List;
public interface IOClickOnActivityListener {
void onClickOnActivity(Activity activity, List<ActivityResident> activityResidents);
void onClickOnActivity(Activity activity , List<ActivityResident> participants);
void onDeleteActivitie(Activity activity);
}

View File

@ -0,0 +1,11 @@
package com.andresgmoran.apptrabajadores.interfaces;
import com.andresgmoran.apptrabajadores.models.Activity;
import com.andresgmoran.apptrabajadores.models.ActivityResident;
import com.andresgmoran.apptrabajadores.models.Resident;
import java.util.List;
public interface IOClickOnAddParticipantListener {
void onClickOnAddParticipant(Activity activity, List<ActivityResident> participants , List<Resident> residents);
}

View File

@ -6,4 +6,5 @@ import com.andresgmoran.apptrabajadores.models.gameStats.GameStat;
public interface IOClickOnGameStatsListener {
void onClickOnLatestGame(GameStat gameStat, Resident gameStatResident, Game gameStatGame);
void onDeleteGameStat(GameStat gameStat, Game gameStatGame);
}

View File

@ -0,0 +1,12 @@
package com.andresgmoran.apptrabajadores.interfaces;
import com.andresgmoran.apptrabajadores.models.ActivityResident;
public interface IOClickOnParticipantListener {
void onClickOnParticipant(ActivityResident participant);
void onClickOnAssistance(ActivityResident participant, boolean isTrue);
void onClickOnOpinion(ActivityResident participant, boolean isPreOpinion);
void onClickOnMaterialHelp(ActivityResident participant, boolean isTrue);
void onClickOnHumanHelp(ActivityResident participant, boolean isTrue);
}

View File

@ -4,4 +4,5 @@ import com.andresgmoran.apptrabajadores.models.Resident;
public interface IOClickOnResidentListener {
void onClickOnResident(Resident resident);
void onTakeOutResident(Resident resident);
}

View File

@ -0,0 +1,8 @@
package com.andresgmoran.apptrabajadores.interfaces;
import com.andresgmoran.apptrabajadores.models.Activity;
import com.andresgmoran.apptrabajadores.models.ActivityState;
public interface IOnChageStateActivityListener {
void onChangeStateActivity(Activity activity, ActivityState state);
}

View File

@ -2,49 +2,60 @@ package com.andresgmoran.apptrabajadores.models;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
public class Activity implements Serializable {
private final Long id;
private final String name;
private final String description;
private final LocalDate date;
private final LocalDateTime date;
private final ActivityState state;
private final List<Resident> residents;
private final List<Long> residentIds;
private final Long residenceId;
public Activity(String name, String description, LocalDate date, ActivityState state, List<Resident> residents) {
public Activity(Long id, String name, String description, LocalDateTime date, ActivityState state, List<Long> residentIds, Long residenceId) {
this.id = id;
this.name = name;
this.description = description;
this.date = date;
this.state = state;
this.residents = residents;
this.residentIds = residentIds;
this.residenceId = residenceId;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public LocalDate getDate() {
public LocalDateTime getDate() {
return date;
}
public ActivityState getState() {
return state;
}
public List<Resident> getResidents() {
return residents;
public List<Long> getResidentIds() {
return residentIds;
}
public Long getResidenceId() {
return residenceId;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
Activity activity = (Activity) o;
return Objects.equals(name, activity.name) && Objects.equals(description, activity.description) && Objects.equals(date, activity.date) && state == activity.state && Objects.equals(residents, activity.residents);
return Objects.equals(id, activity.id) && Objects.equals(name, activity.name) && Objects.equals(description, activity.description) && Objects.equals(date, activity.date) && state == activity.state && Objects.equals(residentIds, activity.residentIds) && Objects.equals(residenceId, activity.residenceId);
}
@Override
public int hashCode() {
return Objects.hash(name, description, date, state, residents);
return Objects.hash(id, name, description, date, state, residentIds, residenceId);
}
}

View File

@ -1,24 +1,48 @@
package com.andresgmoran.apptrabajadores.models;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.Objects;
public class ActivityResident extends Resident{
private boolean asistanceState;
public class ActivityResident implements Serializable {
private final Long id;
private final Long activityId;
private final Long idResident;
private final boolean assistance;
private final boolean humanHelp;
private final boolean materialHelp;
private String preOpinion;
private String postOpinion;
public ActivityResident(Long id, String name, String surnames, LocalDate birthDate, Long residenceId, boolean asistanceState, String preOpinion, String postOpinion) {
super(id, name, surnames, birthDate, residenceId);
this.asistanceState = asistanceState;
public ActivityResident(Long id, Long activityId, Long idResident,boolean assistance, boolean humanHelp, boolean materialHelp, String preOpinion, String postOpinion) {
this.id = id;
this.activityId = activityId;
this.idResident = idResident;
this.assistance = assistance;
this.humanHelp = humanHelp;
this.materialHelp = materialHelp;
this.preOpinion = preOpinion;
this.postOpinion = postOpinion;
}
public boolean isAsistanceState() {
return asistanceState;
public Long getId() {
return id;
}
public void setAsistanceState(boolean asistanceState) {
this.asistanceState = asistanceState;
public Long getActivityId() {
return activityId;
}
public Long getIdResident() {
return idResident;
}
public boolean isAssistance() {
return assistance;
}
public boolean isHumanHelp() {
return humanHelp;
}
public boolean isMaterialHelp() {
return materialHelp;
}
public String getPreOpinion() {
return preOpinion;
@ -36,13 +60,12 @@ public class ActivityResident extends Resident{
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ActivityResident that = (ActivityResident) o;
return asistanceState == that.asistanceState && Objects.equals(preOpinion, that.preOpinion) && Objects.equals(postOpinion, that.postOpinion);
return humanHelp == that.humanHelp && materialHelp == that.materialHelp && Objects.equals(id, that.id) && Objects.equals(activityId, that.activityId) && Objects.equals(idResident, that.idResident) && Objects.equals(preOpinion, that.preOpinion) && Objects.equals(postOpinion, that.postOpinion);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), asistanceState, preOpinion, postOpinion);
return Objects.hash(id, activityId, idResident, humanHelp, materialHelp, preOpinion, postOpinion);
}
}

View File

@ -4,7 +4,9 @@ import com.andresgmoran.apptrabajadores.models.gameStats.Difficulty;
public enum ActivityState {
ABIERTO,
CERRADO;
CERRADO,
EN_CURSO,
FINALIZADA;
public static ActivityState fromString(String value) {
switch (value.toLowerCase()) {
@ -12,6 +14,10 @@ public enum ActivityState {
return ABIERTO;
case "cerrado":
return CERRADO;
case "en_curso":
return EN_CURSO;
case "finalizada":
return FINALIZADA;
default:
throw new IllegalArgumentException("Valor de estado no válido: " + value);
}

View File

@ -7,12 +7,10 @@ import java.util.Objects;
public class Game implements Serializable {
private final Long id;
private final String name;
private final Long residenceId;
public Game(Long id, String name, Long residenceId) {
public Game(Long id, String name) {
this.id = id;
this.name = name;
this.residenceId = residenceId;
}
public Long getId() {
@ -23,19 +21,15 @@ public class Game implements Serializable {
return name;
}
public Long getResidenceId() {
return residenceId;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
Game game = (Game) o;
return Objects.equals(id, game.id) && Objects.equals(name, game.name) && Objects.equals(residenceId, game.residenceId);
return Objects.equals(id, game.id) && Objects.equals(name, game.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name, residenceId);
return Objects.hash(id, name);
}
}

View File

@ -10,13 +10,15 @@ public class Resident implements Serializable {
private final String name;
private final String surnames;
private final LocalDate birthDate;
private final String identityCard;
private final Long residenceId;
public Resident(Long id, String name, String surnames, LocalDate birthDate, Long residenceId) {
public Resident(Long id, String name, String surnames, LocalDate birthDate, String identityCard , Long residenceId) {
this.id = id;
this.name = name;
this.surnames = surnames;
this.birthDate = birthDate;
this.identityCard = identityCard;
this.residenceId = residenceId;
}

View File

@ -10,16 +10,19 @@ public class User implements Serializable {
private final String email;
private final boolean enabled;
private final Long residenceId;
private final String role; //Decirle a kevin que lo ponga
private final String accountImage;
private final boolean takenOut;
public User(Long id, String name, String surnames, String email, boolean enabled, Long residenceId) {
public User(Long id, String name, String surnames, String email, boolean enabled, Long residenceId, String accountImage, boolean takenOut) {
this.id = id;
this.name = name;
this.surnames = surnames;
this.email = email;
this.enabled = enabled;
this.residenceId = residenceId;
this.role = "Trabajador";
this.accountImage = accountImage;
this.takenOut = takenOut;
}
@ -47,19 +50,23 @@ public class User implements Serializable {
return residenceId;
}
public String getRole() {
return role;
public String getAccountImage() {
return accountImage;
}
public boolean isTakenOut() {
return takenOut;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return enabled == user.enabled && Objects.equals(id, user.id) && Objects.equals(name, user.name) && Objects.equals(surnames, user.surnames) && Objects.equals(email, user.email) && Objects.equals(residenceId, user.residenceId) && Objects.equals(role, user.role);
return enabled == user.enabled && takenOut == user.takenOut && Objects.equals(id, user.id) && Objects.equals(name, user.name) && Objects.equals(surnames, user.surnames) && Objects.equals(email, user.email) && Objects.equals(residenceId, user.residenceId) && Objects.equals(accountImage, user.accountImage);
}
@Override
public int hashCode() {
return Objects.hash(id, name, surnames, email, enabled, residenceId, role);
return Objects.hash(id, name, surnames, email, enabled, residenceId, accountImage, takenOut);
}
}

View File

@ -1,49 +1,135 @@
package com.andresgmoran.apptrabajadores.models.adapters;
import static java.security.AccessController.getContext;
import android.app.AlertDialog;
import android.content.Context;
import android.view.ContentInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.PopupMenu;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.andresgmoran.apptrabajadores.R;
import com.andresgmoran.apptrabajadores.interfaces.IOClickOnActivityListener;
import com.andresgmoran.apptrabajadores.interfaces.IOnChageStateActivityListener;
import com.andresgmoran.apptrabajadores.models.Activity;
import com.andresgmoran.apptrabajadores.models.ActivityResident;
import com.andresgmoran.apptrabajadores.models.ActivityState;
import com.andresgmoran.apptrabajadores.models.Game;
import java.util.ArrayList;
import java.util.List;
public class ActivitiesAdapter extends RecyclerView.Adapter<ActivitiesAdapter.ActivitiesViewHolder> {
public ActivitiesAdapter(){
// Constructor implementation
private final Context context;
private List<Activity> activities;
private List<ActivityResident> participants;
private IOClickOnActivityListener listener;
private IOnChageStateActivityListener changeStateListener;
public ActivitiesAdapter(Context context, List<Activity> activities, List<ActivityResident> participants, IOClickOnActivityListener listener, IOnChageStateActivityListener changeStateListener) {
this.context = context;
this.activities = activities;
this.participants = participants;
this.listener = listener;
this.changeStateListener = changeStateListener;
}
@NonNull
@Override
public ActivitiesAdapter.ActivitiesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
final View view = LayoutInflater.from( parent.getContext()).inflate(R.layout.item_resident_activity, parent, false);
final View view = LayoutInflater.from( parent.getContext()).inflate(R.layout.item_activity, parent, false);
return new ActivitiesAdapter.ActivitiesViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ActivitiesViewHolder holder, int position) {
Activity activity = activities.get(position);
holder.bindActivity(activity);
List<ActivityResident> activityResidents = new ArrayList<>();
for (ActivityResident activityResident : participants) {
if (activityResident.getActivityId() == activity.getId()) {
activityResidents.add(activityResident);
}
}
if (activity.getState() != ActivityState.CERRADO){
holder.activityStateButton.setOnClickListener( v -> {
new AlertDialog.Builder(context)
.setTitle("Confirmación")
.setMessage("No se podra cambiar el estado de la actividad una vez cerrada. ¿Desea continuar?")
.setPositiveButton("Aceptar", (dialog, which) -> {
changeStateListener.onChangeStateActivity(activity, ActivityState.CERRADO);
})
.setNegativeButton("Cancelar", (dialog, which) -> {
dialog.dismiss();
})
.show();
});
}
holder.optionsButton.setOnClickListener(v -> {
PopupMenu popupMenu = new PopupMenu(v.getContext(), v);
popupMenu.getMenuInflater().inflate(R.menu.menu_options, popupMenu.getMenu());
popupMenu.setOnMenuItemClickListener(item -> {
if (item.getItemId() == R.id.action_delete) {
if (activities != null)
listener.onDeleteActivitie(activity);
return true;
}
return false;
});
popupMenu.show();
});
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
listener.onClickOnActivity(activity, activityResidents);
}
});
}
@Override
public int getItemCount() {
return 0;
return activities.size();
}
public class ActivitiesViewHolder extends RecyclerView.ViewHolder {
private final TextView activityName;
private final TextView activityDate;
private final ImageButton optionsButton;
private final ImageButton activityStateButton;
public ActivitiesViewHolder(View view) {
super(view);
activityName = itemView.findViewById(R.id.name_salida);
activityDate = itemView.findViewById(R.id.date_text_activityItem);
optionsButton = itemView.findViewById(R.id.more_options_activity_item);
activityStateButton = itemView.findViewById(R.id.activity_status_button);
}
public void bindActivity(Activity activity) {
activityName.setText(activity.getName());
activityDate.setText(activity.getDate().toString());
if (activity.getState() == ActivityState.ABIERTO) {
activityStateButton.setImageResource(R.drawable.open_activity_status);
} else {
activityStateButton.setImageResource(R.drawable.closed_activity_status);
}
}
}
}

View File

@ -3,6 +3,7 @@ package com.andresgmoran.apptrabajadores.models.adapters;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
@ -15,7 +16,7 @@ import com.andresgmoran.apptrabajadores.models.Game;
import java.util.List;
public class GamesAdapter extends RecyclerView.Adapter<GamesAdapter.GamesViewHolder>{
private final List<Game> games;
private List<Game> games;
private final IOClickOnGameListener listener;
public GamesAdapter(List<Game> games, IOClickOnGameListener listener) {
@ -23,6 +24,11 @@ public class GamesAdapter extends RecyclerView.Adapter<GamesAdapter.GamesViewHol
this.listener = listener;
}
public void updateData(List<Game> newGames) {
this.games = newGames;
notifyDataSetChanged();
}
@NonNull
@Override
public GamesAdapter.GamesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
@ -50,15 +56,24 @@ public class GamesAdapter extends RecyclerView.Adapter<GamesAdapter.GamesViewHol
public class GamesViewHolder extends RecyclerView.ViewHolder {
private final TextView gameName;
private final ImageView gameImage;
public GamesViewHolder(View view) {
super(view);
gameName = view.findViewById(R.id.name_list_item);
gameImage = view.findViewById(R.id.item_list_image);
}
public void bindGame(Game game) {
gameName.setText(game.getName());
String name = game.getName();
String formattedName = name.substring(0, 1).toUpperCase() + name.substring(1);
gameName.setText(formattedName);
String resourceName = "logo_" + game.getName().toLowerCase().replace(" ", "_");
int imageResId = itemView.getContext().getResources().getIdentifier(resourceName, "drawable", itemView.getContext().getPackageName());
if (imageResId != 0)
gameImage.setImageResource(imageResId);
}
}
}

View File

@ -4,6 +4,8 @@ import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.PopupMenu;
import android.widget.TextView;
import androidx.annotation.NonNull;
@ -76,9 +78,26 @@ public class LastGamesAdapter extends RecyclerView.Adapter<LastGamesAdapter.Last
holder.bindObservation(gameStat, gameStatResident, gameStatGame);
Resident finalGameStatResident = gameStatResident;
Game finalGameStatGame = gameStatGame;
holder.optionsButton.setOnClickListener(v -> {
PopupMenu popupMenu = new PopupMenu(v.getContext(), v);
popupMenu.getMenuInflater().inflate(R.menu.menu_options, popupMenu.getMenu());
popupMenu.setOnMenuItemClickListener(item -> {
if (item.getItemId() == R.id.action_delete) {
if (finalGameStatResident != null && finalGameStatGame != null)
listener.onDeleteGameStat(gameStat, finalGameStatGame);
return true;
}
return false;
});
popupMenu.show();
});
holder.itemView.setOnClickListener(v -> {
if (finalGameStatResident != null && finalGameStatGame != null)
listener.onClickOnLatestGame(gameStat, finalGameStatResident, finalGameStatGame);
@ -96,6 +115,7 @@ public class LastGamesAdapter extends RecyclerView.Adapter<LastGamesAdapter.Last
private final TextView gameName;
private final TextView date;
private final TextView time;
private final ImageButton optionsButton;
public LastGamesViewHolder(View view) {
super(view);
@ -103,10 +123,11 @@ public class LastGamesAdapter extends RecyclerView.Adapter<LastGamesAdapter.Last
gameName = view.findViewById(R.id.gameName_text_latestGameItem);
date = view.findViewById(R.id.date_text_latestGameItem);
time = view.findViewById(R.id.time_text_latestGameItem);
optionsButton = view.findViewById(R.id.more_options_latestGameItem);
}
public void bindObservation(GameStat gameStat, Resident gameStatResident, Game gameStatGame) {
if (gameStatResident == null || gameStatGame == null) {
if (gameStat == null) {
residentName.setText("Residente no encontrado");
gameName.setText("Juego desconocido");
date.setText("-");
@ -114,8 +135,25 @@ public class LastGamesAdapter extends RecyclerView.Adapter<LastGamesAdapter.Last
return;
}
if (gameStatResident == null) {
residentName.setText("Residente no encontrado");
} else {
residentName.setText(gameStatResident.getName() + " " + gameStatResident.getSurnames());
}
if (gameStatGame == null) {
gameName.setText("Juego desconocido");
} else {
if (gameStatGame.getName().equalsIgnoreCase("flecha y reacciona") || gameStatGame.getName().equalsIgnoreCase("bingo auditivo")){
if (gameStat.getNum() == 0){
gameName.setText(gameStatGame.getName() + " - PERDIDA");
} else if ( gameStat.getNum() == 1){
gameName.setText(gameStatGame.getName() + " - GANADA");
}
} else {
gameName.setText(gameStatGame.getName());
}
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEEE, d 'de' MMMM 'de' yyyy", new Locale("es", "ES"));
String fechaFormateada = gameStat.getDateTime().format(formatter);

View File

@ -1,58 +0,0 @@
package com.andresgmoran.apptrabajadores.models.adapters;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.andresgmoran.apptrabajadores.R;
import com.andresgmoran.apptrabajadores.models.Observation;
import java.util.List;
public class ObservationsAdapter extends RecyclerView.Adapter<ObservationsAdapter.ObservationsViewHolder> {
private final List<Observation> observations;
public ObservationsAdapter(List<Observation> observations){
this.observations = observations;
}
@NonNull
@Override
public ObservationsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
final View view = LayoutInflater.from( parent.getContext()).inflate(R.layout.item_observation, parent, false);
return new ObservationsViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ObservationsViewHolder holder, int position) {
Observation observation = observations.get(position);
holder.bindObservation(observation);
}
@Override
public int getItemCount() {
return observations.size();
}
public class ObservationsViewHolder extends RecyclerView.ViewHolder {
private final TextView observation;
private final TextView observationOwner;
private final TextView observationOwnerRole;
public ObservationsViewHolder(View view) {
super(view);
observation = view.findViewById(R.id.observation_text);
observationOwner = view.findViewById(R.id.home_user_name);
observationOwnerRole = view.findViewById(R.id.observation_person_role);
}
public void bindObservation(Observation observation){
observationOwner.setText(observation.getObservationOwner().getName());
this.observation.setText(observation.getObservationText());
}
}
}

View File

@ -0,0 +1,162 @@
package com.andresgmoran.apptrabajadores.models.adapters;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.andresgmoran.apptrabajadores.R;
import com.andresgmoran.apptrabajadores.interfaces.IOClickOnParticipantListener;
import com.andresgmoran.apptrabajadores.models.Activity;
import com.andresgmoran.apptrabajadores.models.ActivityResident;
import com.andresgmoran.apptrabajadores.models.ActivityState;
import com.andresgmoran.apptrabajadores.models.Resident;
import java.util.List;
public class ParticipantsAdapter extends RecyclerView.Adapter<ParticipantsAdapter.ParticipantsViewHolder> {
private final Context context;
private final Activity activity;
private List<Resident> residents;
private List<ActivityResident> activityResidents;
private IOClickOnParticipantListener listener;
public ParticipantsAdapter(Context context, Activity activity, List<ActivityResident> activityResidents, List<Resident> residents , IOClickOnParticipantListener listener) {
this.context = context;
this.activity = activity;
this.residents = residents;
this.activityResidents = activityResidents;
this.listener = listener;
}
@NonNull
@Override
public ParticipantsAdapter.ParticipantsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
final View view = LayoutInflater.from( parent.getContext()).inflate(R.layout.item_resident_activity, parent, false);
return new ParticipantsAdapter.ParticipantsViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ParticipantsViewHolder holder, int position) {
ActivityResident activityResident = activityResidents.get(position);
holder.bindActivity(activityResident);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
listener.onClickOnParticipant(activityResident);
}
});
holder.assitanceButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (activity.getState() == ActivityState.ABIERTO){
if (activityResident.isAssistance()){
listener.onClickOnAssistance(activityResident, false);
} else {
listener.onClickOnAssistance(activityResident, true);
}
}
}
});
holder.opinionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (activity.getState() == ActivityState.ABIERTO && activityResident.getPreOpinion().isEmpty()) {
// Dejar al usuario añadir un comentario y cambiar boolean de preOpinion a true
listener.onClickOnOpinion(activityResident, true);
} else if (activity.getState() == ActivityState.FINALIZADA && activityResident.getPostOpinion().isEmpty()){
// Dejar al usuario añadir un comentario y cambiar boolean de postOpinion a true
listener.onClickOnOpinion(activityResident, false);
}
}
});
holder.materialHelp.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (activity.getState() == ActivityState.ABIERTO){
if (activityResident.isMaterialHelp()){
listener.onClickOnMaterialHelp(activityResident, false);
} else {
listener.onClickOnMaterialHelp(activityResident, true);
}
}
}
});
holder.humanHelp.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (activity.getState() == ActivityState.ABIERTO){
if (activityResident.isHumanHelp()){
listener.onClickOnHumanHelp(activityResident, false);
} else {
listener.onClickOnHumanHelp(activityResident, true);
}
}
}
});
if (activityResident.isAssistance()){
holder.assitanceButton.setBackgroundResource(R.drawable.activity_button_pressed_background);
}
if (activityResident.isMaterialHelp()){
holder.materialHelp.setBackgroundResource(R.drawable.activity_button_pressed_background);
}
if (activityResident.isHumanHelp()){
holder.humanHelp.setBackgroundResource(R.drawable.activity_button_pressed_background);
}
Log.e( "TAG", "State: " + activity.getState());
Log.e( "TAG", "PreOpinion: " + activityResident.getPreOpinion());
if (activity.getState() == ActivityState.ABIERTO && !activityResident.getPreOpinion().isEmpty()){
holder.opinionButton.setBackgroundResource(R.drawable.activity_button_pressed_background);
}
if (activity.getState() == ActivityState.FINALIZADA && !activityResident.getPostOpinion().isEmpty()){
Log.e( "TAG", "Opinion: " + activityResident.getPostOpinion());
holder.opinionButton.setBackgroundResource(R.drawable.activity_button_pressed_background);
}
}
@Override
public int getItemCount() {
return activityResidents.size();
}
public class ParticipantsViewHolder extends RecyclerView.ViewHolder {
private final TextView name;
private final ImageButton assitanceButton;
private final ImageButton opinionButton;
private final ImageButton materialHelp;
private final ImageButton humanHelp;
public ParticipantsViewHolder(View view) {
super(view);
name = itemView.findViewById(R.id.tv_name_participant_item);
assitanceButton = itemView.findViewById(R.id.participant_asistencia_button);
opinionButton = itemView.findViewById(R.id.participant_opinion_button);
materialHelp = itemView.findViewById(R.id.participant_material_help_button);
humanHelp = itemView.findViewById(R.id.participant_human_help_button);
}
public void bindActivity(ActivityResident activityResident) {
for( Resident resident : residents){
if(resident.getId() == activityResident.getIdResident()){
name.setText(resident.getName() + " " + resident.getSurnames());
break;
}
}
}
}
}

View File

@ -3,6 +3,8 @@ package com.andresgmoran.apptrabajadores.models.adapters;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.PopupMenu;
import android.widget.TextView;
import androidx.annotation.NonNull;
@ -15,7 +17,7 @@ import com.andresgmoran.apptrabajadores.models.Resident;
import java.util.List;
public class ResidentsAdapter extends RecyclerView.Adapter<ResidentsAdapter.ResidentsViewHolder> {
private final List<Resident> residents;
private List<Resident> residents;
private final IOClickOnResidentListener listener;
public ResidentsAdapter(List<Resident> residents, IOClickOnResidentListener listener) {
@ -23,6 +25,11 @@ public class ResidentsAdapter extends RecyclerView.Adapter<ResidentsAdapter.Resi
this.listener = listener;
}
public void updateData(List<Resident> newResidents) {
this.residents = newResidents; // O la lista que uses internamente
notifyDataSetChanged();
}
@NonNull
@Override
public ResidentsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
@ -35,6 +42,21 @@ public class ResidentsAdapter extends RecyclerView.Adapter<ResidentsAdapter.Resi
Resident resident = residents.get(position);
holder.bindResident(resident);
holder.optionsButton.setOnClickListener(v -> {
PopupMenu popupMenu = new PopupMenu(v.getContext(), v);
popupMenu.getMenuInflater().inflate(R.menu.menu_options, popupMenu.getMenu());
popupMenu.setOnMenuItemClickListener(item -> {
if (item.getItemId() == R.id.action_delete) {
listener.onTakeOutResident(resident);
return true;
}
return false;
});
popupMenu.show();
});
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@ -50,11 +72,13 @@ public class ResidentsAdapter extends RecyclerView.Adapter<ResidentsAdapter.Resi
public class ResidentsViewHolder extends RecyclerView.ViewHolder {
private final TextView residentName;
private final ImageButton optionsButton;
public ResidentsViewHolder(View view) {
super(view);
residentName = view.findViewById(R.id.name_list_item);
optionsButton = view.findViewById(R.id.more_options_item_list);
}
public void bindResident(Resident resident) {

View File

@ -1,18 +1,18 @@
package com.andresgmoran.apptrabajadores.models.gameStats;
public enum Difficulty {
FACIL,
MEDIO,
DIFICIL;
DIFICULTAD1,
DIFICULTAD2,
DIFICULTAD3;
public static Difficulty fromString(String value) {
switch (value.toLowerCase()) {
case "facil":
return FACIL;
case "medio":
return MEDIO;
case "dificil":
return DIFICIL;
case "dificultad1":
return DIFICULTAD1;
case "dificultad2":
return DIFICULTAD2;
case "dificultad3":
return DIFICULTAD3;
default:
throw new IllegalArgumentException("Valor de dificultad no válido: " + value);
}

View File

@ -13,8 +13,9 @@ public class GameStat implements Serializable {
private final Double duration;
private final Difficulty difficulty;
private final LocalDateTime dateTime;
private final String observation;
public GameStat(Long id, Long residentId, Long gameId, Long userId, Integer num, Double duration, Difficulty difficulty, LocalDateTime dateTime) {
public GameStat(Long id, Long residentId, Long gameId, Long userId, Integer num, Double duration, Difficulty difficulty, LocalDateTime dateTime, String observation) {
this.id = id;
this.residentId = residentId;
this.gameId = gameId;
@ -23,6 +24,7 @@ public class GameStat implements Serializable {
this.duration = duration;
this.difficulty = difficulty;
this.dateTime = dateTime;
this.observation = observation;
}
public Long getId() {
@ -57,15 +59,19 @@ public class GameStat implements Serializable {
return dateTime;
}
public String getObservation() {
return observation;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
GameStat gameStat = (GameStat) o;
return Objects.equals(id, gameStat.id) && Objects.equals(residentId, gameStat.residentId) && Objects.equals(gameId, gameStat.gameId) && Objects.equals(userId, gameStat.userId) && Objects.equals(num, gameStat.num) && Objects.equals(duration, gameStat.duration) && difficulty == gameStat.difficulty && Objects.equals(dateTime, gameStat.dateTime);
return Objects.equals(id, gameStat.id) && Objects.equals(residentId, gameStat.residentId) && Objects.equals(gameId, gameStat.gameId) && Objects.equals(userId, gameStat.userId) && Objects.equals(num, gameStat.num) && Objects.equals(duration, gameStat.duration) && difficulty == gameStat.difficulty && Objects.equals(dateTime, gameStat.dateTime) && Objects.equals(observation, gameStat.observation);
}
@Override
public int hashCode() {
return Objects.hash(id, residentId, gameId, userId, num, duration, difficulty, dateTime);
return Objects.hash(id, residentId, gameId, userId, num, duration, difficulty, dateTime, observation);
}
}

View File

@ -0,0 +1,63 @@
package com.andresgmoran.apptrabajadores.models.parsers;
import com.andresgmoran.apptrabajadores.exceptions.ParserException;
import com.andresgmoran.apptrabajadores.models.Activity;
import com.andresgmoran.apptrabajadores.models.ActivityResident;
import com.andresgmoran.apptrabajadores.models.ActivityState;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
public class ActivityParser {
public static List<Activity> parseActivities(String jsonText) throws ParserException {
List<Activity> activities = new ArrayList<>();
try {
JSONArray array = new JSONArray(jsonText);
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
Long id = obj.getLong("id");
String name = obj.getString("nombre");
String description = obj.getString("descripcion");
// Asegúrate de que la fecha tenga formato "yyyy-MM-dd"
String fechaStr = obj.getString("fechaInicio").trim();
LocalDateTime date = LocalDateTime.parse(fechaStr);
// Validar estado
ActivityState state = null;
if (obj.has("estado") && !obj.isNull("estado")) {
String estadoStr = obj.getString("estado").trim();
if (!estadoStr.isEmpty()) {
state = ActivityState.fromString(estadoStr);
}
}
Long residenceId = obj.getLong("idResidencia");
JSONArray jsonResidentsArray = obj.getJSONArray("participantes");
List<Long> residentIds = new ArrayList<>();
for (int j = 0; j < jsonResidentsArray.length(); j++) {
residentIds.add(jsonResidentsArray.getLong(j));
}
activities.add(new Activity(id, name, description, date, state, residentIds, residenceId));
}
} catch (JSONException | IllegalArgumentException e) {
throw new ParserException("Error al parsear actividades: " + e.getMessage(), e);
}
return activities;
}
}

View File

@ -0,0 +1,45 @@
package com.andresgmoran.apptrabajadores.models.parsers;
import com.andresgmoran.apptrabajadores.exceptions.ParserException;
import com.andresgmoran.apptrabajadores.models.ActivityResident;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
public class ActivityResidentParser {
public static List<ActivityResident> parseActivityResidents(String jsonText) throws ParserException{
List<ActivityResident> activityResidents = new ArrayList<>();
try {
JSONArray jsonArray = new JSONArray(jsonText);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonResident = jsonArray.getJSONObject(i);
Long id = jsonResident.getLong("id");
Long activityId = jsonResident.getLong("idEvento");
Long residentId = jsonResident.getLong("idResidente");
boolean humanHelp = jsonResident.getBoolean("recursosHumanos");
boolean materialHelp = jsonResident.getBoolean("recursosMateriales");
boolean assistance = jsonResident.getBoolean("asistenciaPermitida");
String preOpinion = jsonResident.optString("preOpinion", "");
String postOpinion = jsonResident.optString("postOpinion", "");
ActivityResident activityResident = new ActivityResident(id, activityId, residentId, assistance, humanHelp, materialHelp, preOpinion, postOpinion);
activityResidents.add(activityResident);
}
} catch (JSONException | IllegalArgumentException e) {
throw new ParserException("Error al parsear residentes de actividades", e);
}
return activityResidents;
}
}

View File

@ -1,5 +1,6 @@
package com.andresgmoran.apptrabajadores.models.parsers;
import com.andresgmoran.apptrabajadores.exceptions.ParserException;
import com.andresgmoran.apptrabajadores.models.Game;
import org.json.JSONArray;
@ -11,7 +12,7 @@ import java.util.List;
public class GameParser {
public static List<Game> parseGames(String jsonText) {
public static List<Game> parseGames(String jsonText) throws ParserException{
List<Game> games = new ArrayList<>();
try {
@ -22,14 +23,13 @@ public class GameParser {
Long id = jsonGame.getLong("id");
String name = jsonGame.getString("nombre");
Long residenceId = jsonGame.getLong("idResidencia");
Game game = new Game(id, name, residenceId);
Game game = new Game(id, name);
games.add(game);
}
} catch (JSONException e) {
e.printStackTrace(); //TODO: Throw personalized exception
} catch (JSONException | IllegalArgumentException e) {
throw new ParserException("Error al parsear juegos", e);
}
return games;

View File

@ -1,6 +1,7 @@
package com.andresgmoran.apptrabajadores.models.parsers;
import com.andresgmoran.apptrabajadores.exceptions.ParserException;
import com.andresgmoran.apptrabajadores.models.gameStats.Difficulty;
import com.andresgmoran.apptrabajadores.models.gameStats.GameStat;
@ -15,7 +16,7 @@ import java.util.List;
public class GameStatParser {
public static List<GameStat> parseStats(String jsonText) {
public static List<GameStat> parseStats(String jsonText) throws ParserException {
List<GameStat> stats = new ArrayList<>();
try {
@ -27,7 +28,7 @@ public class GameStatParser {
Long id = obj.getLong("id");
Long residentId = obj.getLong("idResidente");
Long gameId = obj.getLong("idJuego");
Long userId = obj.getLong("idUsario");
Long userId = obj.getLong("idUsuario");
Integer num = obj.getInt("num");
Double duration = obj.getDouble("duracion");
Difficulty difficulty = null;
@ -41,12 +42,13 @@ public class GameStatParser {
obj.getString("fecha"),
DateTimeFormatter.ISO_DATE_TIME // ejemplo: "2025-04-18T22:31:00"
);
String observation = obj.getString("observacion");
stats.add(new GameStat(id, residentId, gameId, userId, num, duration, difficulty, dateTime));
stats.add(new GameStat(id, residentId, gameId, userId, num, duration, difficulty, dateTime, observation));
}
} catch (JSONException e) {
e.printStackTrace();
} catch (JSONException | IllegalArgumentException e) {
throw new ParserException("Error al parsear partidas", e);
}
return stats;

View File

@ -1,8 +1,10 @@
package com.andresgmoran.apptrabajadores.models.parsers;
import com.andresgmoran.apptrabajadores.exceptions.ParserException;
import com.andresgmoran.apptrabajadores.models.Resident;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.time.LocalDate;
@ -11,7 +13,7 @@ import java.util.List;
public class ResidentParser {
public static List<Resident> parseResidents(String jsonText) {
public static List<Resident> parseResidents(String jsonText) throws ParserException {
List<Resident> residents = new ArrayList<>();
try {
@ -28,12 +30,14 @@ public class ResidentParser {
String birthDateStr = obj.getString("fechaNacimiento");
LocalDate birthDate = LocalDate.parse(birthDateStr); // Usa formato ISO (yyyy-MM-dd)
String identityCard = obj.getString("documentoIdentidad");
Long residenceId = obj.getLong("idResidencia");
residents.add(new Resident(id, name, surnames, birthDate, residenceId));
residents.add(new Resident(id, name, surnames, birthDate, identityCard, residenceId));
}
} catch (Exception e) {
e.printStackTrace(); //TODO: Throw personalized exception
} catch (JSONException | IllegalArgumentException e) {
throw new ParserException("Error al parsear residentes", e);
}
return residents;

View File

@ -1,8 +1,10 @@
package com.andresgmoran.apptrabajadores.models.parsers;
import com.andresgmoran.apptrabajadores.exceptions.ParserException;
import com.andresgmoran.apptrabajadores.models.User;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
@ -10,7 +12,7 @@ import java.util.List;
public class UserParser {
public static List<User> parseUsers(String jsonText) {
public static List<User> parseUsers(String jsonText) throws ParserException {
List<User> usuarios = new ArrayList<>();
try {
@ -25,14 +27,36 @@ public class UserParser {
String email = obj.getString("email");
boolean enabled = obj.getBoolean("enabled");
Long residentId = obj.has("idResidencia") && !obj.isNull("residentId") ? obj.getLong("residentId") : null;
String accountImage = obj.getString("fotoPerfil");
boolean takenOut = obj.getBoolean("baja");
usuarios.add(new User(id, name, surnames, email, enabled, residentId));
usuarios.add(new User(id, name, surnames, email, enabled, residentId, accountImage, takenOut));
}
} catch (Exception e) {
e.printStackTrace(); //TODO: Throw personalized exception
} catch (JSONException | IllegalArgumentException e) {
throw new ParserException("Error al parsear usuarios", e);
}
return usuarios;
}
public static User parseUser(String jsonText) throws ParserException {
try {
JSONObject obj = new JSONObject(jsonText);
Long id = obj.getLong("id");
String name = obj.getString("nombre");
String surnames = obj.getString("apellido");
String email = obj.getString("email");
boolean enabled = obj.getBoolean("enabled");
Long residentId = obj.has("residentId") && !obj.isNull("residentId") ? obj.getLong("residentId") : null;
String accountImage = obj.getString("fotoPerfil");
boolean takenOut = obj.getBoolean("baja");
return new User(id, name, surnames, email, enabled, residentId, accountImage, takenOut);
} catch (JSONException | IllegalArgumentException e) {
throw new ParserException("Error al parsear el usuario", e);
}
}
}

View File

@ -1,39 +1,109 @@
package com.andresgmoran.apptrabajadores.network;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import androidx.security.crypto.EncryptedSharedPreferences;
import androidx.security.crypto.MasterKey;
import com.andresgmoran.apptrabajadores.models.ActivityState;
import com.andresgmoran.apptrabajadores.models.User;
import com.andresgmoran.apptrabajadores.utils.SecurePreferencesUtil;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDate;
import java.time.LocalDateTime;
public class ApiClient {
private static final String BASE_URL = "http://10.0.2.2:8080/resi/";
private static final String BASE_URL = "http://10.0.2.2:8080";
public interface RawCallback {
void onSuccess(String jsonText);
void onError(String error);
}
public static void getUsers(RawCallback callback) {
makeGetRequest("users", callback);
public interface ImageCallback {
void onSuccess(Bitmap bitmap);
void onError(String error);
}
public static void getResidents(RawCallback callback) {
makeGetRequest("residents", callback);
/**
*
* @param context
* @param callback
*/
public static void getUsers(Context context, RawCallback callback) {
long idResidence = SecurePreferencesUtil.getLong(context, "idResidence", -1);
makeGetRequest(context, "/resi/user/getAll", callback);
}
public static void getGames(RawCallback callback) {
makeGetRequest("juegos", callback);
}
public static void getGamesStats(RawCallback callback) {
makeGetRequest("juegos/stats", callback);
public static void getActualUser(Context context, RawCallback callback) {
makeGetRequest(context, "/resi/user/me", callback);
}
private static void makeGetRequest(String endpoint, RawCallback callback) {
/**
*
* @param context
* @param callback
*/
public static void getResidents(Context context, RawCallback callback) {
long idResidence = SecurePreferencesUtil.getLong(context, "idResidence", -1);
makeGetRequest(context, "/resi/resident/getAll", callback);
}
/**
*
* @param context
* @param callback
*/
public static void getGames(Context context, RawCallback callback) {
long idResidence = SecurePreferencesUtil.getLong(context, "idResidence", -1);
makeGetRequest(context, "/resi/juego/getAll", callback);
}
/**
*
* @param context
* @param callback
*/
public static void getGamesStats(Context context, RawCallback callback) {
long idResidence = SecurePreferencesUtil.getLong(context, "idResidence", -1);
makeGetRequest(context, "/resi/registro/getAll", callback);
}
/**
*
* @param context
* @param callback
*/
public static void getAllActivities(Context context, RawCallback callback) {
long idResidence = SecurePreferencesUtil.getLong(context, "idResidence", -1);
makeGetRequest(context, "/resi/evento/getAll", callback);
}
public static void getAllParticipants(Context context, Long idActivity, RawCallback callback) {
long idResidence = SecurePreferencesUtil.getLong(context, "idResidence", -1);
makeGetRequest(context, "/resi/evento/" + idActivity + "/participante/getAll", callback);
}
/**
*
* @param context
* @param endpoint
* @param callback
*/
private static void makeGetRequest(Context context, String endpoint, RawCallback callback) {
new Thread(() -> {
HttpURLConnection connection = null;
BufferedReader reader = null;
@ -43,6 +113,25 @@ public class ApiClient {
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("User-Agent", "Android");
// Obtener el token desde EncryptedSharedPreferences
MasterKey masterKey = new MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build();
SharedPreferences encryptedPrefs = EncryptedSharedPreferences.create(
context,
"secure_auth",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
String token = encryptedPrefs.getString("token", null);
if (token != null) {
connection.setRequestProperty("Authorization", "Bearer " + token);
}
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
@ -56,7 +145,6 @@ public class ApiClient {
json.append(line);
}
// Devolver el JSON plano al hilo principal
new Handler(Looper.getMainLooper()).post(() ->
callback.onSuccess(json.toString()));
} else {
@ -76,5 +164,344 @@ public class ApiClient {
}
}).start();
}
/**
*
* @param email
* @param password
* @param callback
*/
public static void postLogin(String email, String password, RawCallback callback) {
String jsonBody = String.format("{\"email\":\"%s\", \"password\":\"%s\"}", email, password);
makePostRequest("/auth/login", jsonBody, callback);
}
/**
*
* @param context
* @param nombre
* @param descripcion
* @param fecha
* @param callback
*/
public static void postEvento(Context context, String nombre, String descripcion, LocalDateTime fecha, RawCallback callback) {
String jsonBody = String.format("{\"nombre\":\"%s\", \"descripcion\":\"%s\", \"fecha\":\"%s\", \"estado\":\"%s\"}", nombre, descripcion, fecha.toString(), ActivityState.ABIERTO);
makePostRequest(context,"/resi/evento/add", jsonBody, callback);
}
/**
*
* @param context
* @param residentId
* @param asistencia
* @param opinionPre
* @param opinionPost
* @param idActivity
* @param callback
*/
public static void postParticipant( Context context, Long residentId, boolean humanHelp, boolean materialHelp, String opinionPre, String opinionPost, Long idActivity, RawCallback callback) {
String jsonBody = String.format("{\"idResidente\":%d, \"recursosHumanos\":%b, \"recursosMateriales\":%b, \"preOpinion\":\"%s\", \"postOpinion\":\"%s\"}", residentId, humanHelp, materialHelp, opinionPre, opinionPost); long idResidence = SecurePreferencesUtil.getLong(context, "idResidence", -1);
makePostRequest(context,"/resi/evento/" + idActivity + "/participante/add", jsonBody, callback);
}
/**
*
* @param endpoint
* @param jsonBody
* @param callback
*/
public static void makePostRequest(String endpoint, String jsonBody, RawCallback callback) {
new Thread(() -> {
HttpURLConnection connection = null;
try {
URL url = new URL(BASE_URL + endpoint);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json; utf-8");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("User-Agent", "Android");
connection.setDoOutput(true);
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
try (java.io.OutputStream os = connection.getOutputStream()) {
byte[] input = jsonBody.getBytes("utf-8");
os.write(input, 0, input.length);
}
int responseCode = connection.getResponseCode();
java.io.InputStream inputStream = (responseCode >= 200 && responseCode < 300)
? connection.getInputStream()
: connection.getErrorStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line.trim());
}
final String result = response.toString();
new Handler(Looper.getMainLooper()).post(() -> {
if (responseCode >= 200 && responseCode < 300) {
callback.onSuccess(result);
} else {
callback.onError("Error (" + responseCode + "): " + result);
}
});
} catch (Exception e) {
new Handler(Looper.getMainLooper()).post(() ->
callback.onError("Excepción: " + e.getMessage()));
} finally {
if (connection != null) connection.disconnect();
}
}).start();
}
/**
*
* @param context
* @param endpoint
* @param jsonBody
* @param callback
*/
public static void makePostRequest(Context context, String endpoint, String jsonBody, RawCallback callback) {
new Thread(() -> {
HttpURLConnection connection = null;
try {
URL url = new URL(BASE_URL + endpoint);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json; utf-8");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("User-Agent", "Android");
connection.setDoOutput(true);
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
String token = SecurePreferencesUtil.getString(context, "token", null);
if (token != null) {
connection.setRequestProperty("Authorization", "Bearer " + token);
}
try (java.io.OutputStream os = connection.getOutputStream()) {
byte[] input = jsonBody.getBytes("utf-8");
os.write(input, 0, input.length);
}
int responseCode = connection.getResponseCode();
java.io.InputStream inputStream = (responseCode >= 200 && responseCode < 300)
? connection.getInputStream()
: connection.getErrorStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line.trim());
}
final String result = response.toString();
new Handler(Looper.getMainLooper()).post(() -> {
if (responseCode >= 200 && responseCode < 300) {
callback.onSuccess(result);
} else {
callback.onError("Error (" + responseCode + "): " + result);
}
});
} catch (Exception e) {
new Handler(Looper.getMainLooper()).post(() ->
callback.onError("Excepción: " + e.getMessage()));
} finally {
if (connection != null) connection.disconnect();
}
}).start();
}
public static void patchObservation(Context context, String observation, long idGameStat, RawCallback callback) {
String jsonBody = String.format("{\"observacion\":\"%s\"}", observation);
long idResidence = SecurePreferencesUtil.getLong(context, "idResidence", -1);
makePatchRequest(context,"/resi/registro/" + idGameStat + "/addComment", jsonBody, callback);
}
public static void patchActivityState(Context context, long idActivity, ActivityState state, RawCallback callback) {
String jsonBody = String.format("{\"estado\":\"%s\"}", state);
makePatchRequest(context,"/resi/evento/" + idActivity + "/update", jsonBody, callback);
}
public static void patchParticipant( Context context, long idActivity, long idParticipant, String jsonBody, RawCallback callback) {
makePatchRequest(context,"/resi/evento/" + idActivity + "/participante/" + idParticipant + "/update", jsonBody, callback);
}
public static void patchTakeOutResident(Context context,long idResident, RawCallback callback) {
makePatchRequest(context,"/resi/resident/" + idResident + "/baja", "", callback);
}
public static void makePatchRequest(Context context, String endpoint, String jsonBody, RawCallback callback) {
new Thread(() -> {
HttpURLConnection connection = null;
try {
URL url = new URL(BASE_URL + endpoint);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("PATCH");
connection.setRequestProperty("Content-Type", "application/json; utf-8");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("User-Agent", "Android");
connection.setDoOutput(true);
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
String token = SecurePreferencesUtil.getString(context, "token", null);
if (token != null) {
connection.setRequestProperty("Authorization", "Bearer " + token);
}
try (java.io.OutputStream os = connection.getOutputStream()) {
byte[] input = jsonBody.getBytes("utf-8");
os.write(input, 0, input.length);
}
int responseCode = connection.getResponseCode();
java.io.InputStream inputStream = (responseCode >= 200 && responseCode < 300)
? connection.getInputStream()
: connection.getErrorStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line.trim());
}
final String result = response.toString();
new Handler(Looper.getMainLooper()).post(() -> {
if (responseCode >= 200 && responseCode < 300) {
callback.onSuccess(result);
} else {
callback.onError("Error (" + responseCode + "): " + result);
}
});
} catch (Exception e) {
new Handler(Looper.getMainLooper()).post(() ->
callback.onError("Excepción: " + e.getMessage()));
} finally {
if (connection != null) connection.disconnect();
}
}).start();
}
public static void deleteGameStat(Context context, long idGameStat, RawCallback callback) {
makeDeleteRequest(context,"/resi/registro/" + idGameStat + "/delete", callback);
}
public static void deleteActivity(Context context, long idActivity, RawCallback callback) {
makeDeleteRequest(context,"/resi/evento/" + idActivity + "/delete", callback);
}
/**
*
* @param context
* @param endpoint
* @param callback
*/
public static void makeDeleteRequest(Context context, String endpoint, RawCallback callback) {
new Thread(() -> {
HttpURLConnection connection = null;
try {
URL url = new URL(BASE_URL + endpoint);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("DELETE");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("User-Agent", "Android");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
// Añadir el token si está disponible
String token = SecurePreferencesUtil.getString(context, "token", null);
if (token != null) {
connection.setRequestProperty("Authorization", "Bearer " + token);
}
int responseCode = connection.getResponseCode();
java.io.InputStream inputStream = (responseCode >= 200 && responseCode < 300)
? connection.getInputStream()
: connection.getErrorStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line.trim());
}
final String result = response.toString();
new Handler(Looper.getMainLooper()).post(() -> {
if (responseCode >= 200 && responseCode < 300) {
callback.onSuccess(result);
} else {
callback.onError("Error (" + responseCode + "): " + result);
}
});
} catch (Exception e) {
new Handler(Looper.getMainLooper()).post(() ->
callback.onError("Excepción: " + e.getMessage()));
} finally {
if (connection != null) connection.disconnect();
}
}).start();
}
public static void downloadImage(Context context, String imageUrl, ImageCallback callback) {
new Thread(() -> {
try {
URL url = new URL(BASE_URL + imageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
// Headers
MasterKey masterKey = new MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build();
SharedPreferences encryptedPrefs = EncryptedSharedPreferences.create(
context,
"secure_auth",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
String token = encryptedPrefs.getString("token", null);
if (token != null) {
connection.setRequestProperty("Authorization", "Bearer " + token);
}
InputStream inputStream = connection.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
new Handler(Looper.getMainLooper()).post(() -> callback.onSuccess(bitmap));
} catch (Exception e) {
new Handler(Looper.getMainLooper()).post(() -> callback.onError(e.getMessage()));
}
}).start();
}
}

View File

@ -16,7 +16,13 @@ import com.andresgmoran.apptrabajadores.interfaces.IOChangeFragmentListener;
public class AccountFragment extends Fragment {
private Button editAccountButton;
private Button logOutButton;
private IOChangeFragmentListener listener;
private IOAccountFragmentListener accountFragmentListener;
public interface IOAccountFragmentListener {
void onLogOutButtonClicked();
}
@Nullable
@Override
@ -28,17 +34,27 @@ public class AccountFragment extends Fragment {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
editAccountButton = view.findViewById(R.id.edit_account_button);
logOutButton = view.findViewById(R.id.btn_cerrar_sesion);
editAccountButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.changeFragment("AccountFragment");
}
});
logOutButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
accountFragmentListener.onLogOutButtonClicked();
}
});
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
listener = (IOChangeFragmentListener) context;
accountFragmentListener = (IOAccountFragmentListener) context;
}
}

View File

@ -9,10 +9,35 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.andresgmoran.apptrabajadores.R;
import com.andresgmoran.apptrabajadores.interfaces.IOChangeFragmentListener;
import com.andresgmoran.apptrabajadores.interfaces.IOClickOnActivityListener;
import com.andresgmoran.apptrabajadores.interfaces.IOnChageStateActivityListener;
import com.andresgmoran.apptrabajadores.models.Activity;
import com.andresgmoran.apptrabajadores.models.ActivityResident;
import com.andresgmoran.apptrabajadores.models.Resident;
import com.andresgmoran.apptrabajadores.models.adapters.ActivitiesAdapter;
import com.andresgmoran.apptrabajadores.ui.MainActivity;
import com.andresgmoran.apptrabajadores.ui.fragments.residentList.ResidentsListFragment;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.List;
public class ActivitiesFragment extends Fragment {
public interface IOOnAttachListener{
List<Activity> getActivities();
List<ActivityResident> getParticipants();
}
private IOChangeFragmentListener changeFragmentListener;
private List<Activity> activities;
private List<ActivityResident> participants;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@ -22,10 +47,34 @@ public class ActivitiesFragment extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_layout_activities_list);
swipeRefreshLayout.setOnRefreshListener(() -> {
((MainActivity) requireActivity()).refreshActivitiesAndReload();
swipeRefreshLayout.setRefreshing(false);
});
ActivitiesAdapter activitiesAdapter = new ActivitiesAdapter(requireContext(), activities, participants, (IOClickOnActivityListener) requireActivity(), (IOnChageStateActivityListener) requireActivity());
RecyclerView activitiesRecyclerView = view.findViewById(R.id.activities_recycleView);
activitiesRecyclerView.setAdapter(activitiesAdapter);
activitiesRecyclerView.setHasFixedSize(true);
activitiesRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
FloatingActionButton fab = view.findViewById(R.id.add_activity_button);
fab.setOnClickListener(v -> {
if (changeFragmentListener != null) {
changeFragmentListener.changeFragment("ActivitiesFragment");
}
});
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
changeFragmentListener = (IOChangeFragmentListener) context;
ActivitiesFragment.IOOnAttachListener attachListener = (ActivitiesFragment.IOOnAttachListener) context;
activities = attachListener.getActivities();
participants = attachListener.getParticipants();
}
}

View File

@ -0,0 +1,216 @@
package com.andresgmoran.apptrabajadores.ui.fragments.activities;
import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.widget.NestedScrollView;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.andresgmoran.apptrabajadores.R;
import com.andresgmoran.apptrabajadores.interfaces.IOClickOnAddParticipantListener;
import com.andresgmoran.apptrabajadores.interfaces.IOClickOnParticipantListener;
import com.andresgmoran.apptrabajadores.interfaces.IOnChageStateActivityListener;
import com.andresgmoran.apptrabajadores.models.Activity;
import com.andresgmoran.apptrabajadores.models.ActivityResident;
import com.andresgmoran.apptrabajadores.models.ActivityState;
import com.andresgmoran.apptrabajadores.models.Resident;
import com.andresgmoran.apptrabajadores.models.adapters.ParticipantsAdapter;
import com.andresgmoran.apptrabajadores.ui.MainActivity;
import com.google.android.material.button.MaterialButton;
import java.util.ArrayList;
import java.util.List;
public class ActivityDetailFragment extends Fragment {
private Activity activity;
private List<ActivityResident> participants;
private List<Resident> residents;
private ImageButton backButton;
public interface IOOnAttachListener {
List<Resident> getResidents();
}
private IOClickOnAddParticipantListener addParticipantListener;
private IOnChageStateActivityListener changeStateActivityListener;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_activity_detail, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_activity_detail);
swipeRefreshLayout.setOnRefreshListener(() -> {
((MainActivity) requireActivity()).refreshActivitiesAndReload();
swipeRefreshLayout.setRefreshing(false);
});
backButton = view.findViewById(R.id.back_button);
backButton.setOnClickListener(v -> {
requireActivity().getSupportFragmentManager().popBackStack();
});
TextView activityName = view.findViewById(R.id.activitie_detail_name);
MaterialButton startEndButton = view.findViewById(R.id.btn_start_end_activity);
if (activity.getState() == ActivityState.ABIERTO){
startEndButton.setVisibility(View.GONE);
} else {
startEndButton.setVisibility(View.VISIBLE);
ActivityState state = activity.getState();
if (state == ActivityState.CERRADO) {
startEndButton.setText("Iniciar actividad");
startEndButton.setBackgroundTintList(ContextCompat.getColorStateList(requireContext(), R.color.purple_200));
startEndButton.setOnClickListener(v -> {
changeStateActivityListener.onChangeStateActivity(activity, ActivityState.EN_CURSO);
});
} else if (state == ActivityState.EN_CURSO) {
startEndButton.setText("Finalizar actividad");
startEndButton.setBackgroundTintList(ContextCompat.getColorStateList(requireContext(), R.color.teal_200));
startEndButton.setOnClickListener(v -> {
changeStateActivityListener.onChangeStateActivity(activity, ActivityState.FINALIZADA);
});
} else if (state == ActivityState.FINALIZADA) {
startEndButton.setText("Actividad finalizada");
startEndButton.setBackgroundTintList(ContextCompat.getColorStateList(requireContext(), R.color.teal_200));
startEndButton.setEnabled(false);
}
}
TextView description = view.findViewById(R.id.tv_description_activity_detail);
description.setText(activity.getDescription());
TextView activityDate = view.findViewById(R.id.tv_date_activity_detail);
TextView activityExitTime = view.findViewById(R.id.tv_exit_time_activity_detail);
activityName.setText(activity.getName());
activityDate.setText(activity.getDate().toLocalDate().toString());
activityExitTime.setText(activity.getDate().toLocalTime().toString());
List<ActivityResident> activityParticipants = new ArrayList<>();
for (ActivityResident p : participants) {
if (p.getActivityId() == activity.getId()) {
activityParticipants.add(p);
}
}
TextView totalParticipants = view.findViewById(R.id.tv_total_participants_activity_detail);
totalParticipants.setText(String.valueOf(activityParticipants.size()));
TextView confirmedParticipants = view.findViewById(R.id.tv_confirmed_residents);
TextView notGoingParticipants = view.findViewById(R.id.tv_unconfirmed_residents);
int goingCount = 0;
int notGoingCount = 0;
for (ActivityResident p : activityParticipants) {
if (p.isAssistance()) {
goingCount++;
} else {
notGoingCount++;
}
}
confirmedParticipants.setText(String.valueOf(goingCount));
notGoingParticipants.setText(String.valueOf(notGoingCount));
TextView humanAssistance = view.findViewById(R.id.tv_required_human_attendance);
TextView materialAssistance = view.findViewById(R.id.tv_required_material_attendance);
int humanAssistanceCount = 0;
int materialAssistanceCount = 0;
for (ActivityResident p : activityParticipants) {
if (p.isHumanHelp()) {
humanAssistanceCount++;
} else if (p.isMaterialHelp()) {
materialAssistanceCount++;
}
}
humanAssistance.setText(String.valueOf(humanAssistanceCount));
materialAssistance.setText(String.valueOf(materialAssistanceCount));
RecyclerView recyclerView = view.findViewById(R.id.rv_participants);
ParticipantsAdapter participantsAdapter = new ParticipantsAdapter(requireContext() , activity, participants, residents, (IOClickOnParticipantListener) requireActivity());
recyclerView.setAdapter(participantsAdapter);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
MaterialButton fab = view.findViewById(R.id.add_participant_button);
if (activity.getState() == ActivityState.CERRADO) {
fab.setVisibility(View.GONE);
} else {
fab.setOnClickListener(v ->
addParticipantListener.onClickOnAddParticipant(activity, participants, residents)
);
NestedScrollView scrollView = view.findViewById(R.id.nested_scroll_game_detail);
scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
private int lastScrollY = 0;
private boolean isButtonVisible = true;
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
if (scrollY > lastScrollY + 10 && isButtonVisible) {
// Scroll hacia abajo: ocultar con animación
fab.animate().translationY(fab.getHeight() + 50).alpha(0.0f).setDuration(200).withEndAction(() -> fab.setVisibility(View.GONE));
isButtonVisible = false;
} else if (scrollY < lastScrollY - 10 && !isButtonVisible) {
// Scroll hacia arriba: mostrar con animación
fab.setVisibility(View.VISIBLE);
fab.setAlpha(0f);
fab.setTranslationY(fab.getHeight() + 50);
fab.animate().translationY(0).alpha(1.0f).setDuration(200);
isButtonVisible = true;
}
lastScrollY = scrollY;
}
});
}
}
@Override
public void onAttach(@NonNull Context context) {
if (getArguments() != null) {
activity = (Activity) getArguments().getSerializable("activity");
participants = (List<ActivityResident>) getArguments().getSerializable("participants");
}
if (context instanceof IOOnAttachListener) {
residents = ((IOOnAttachListener) context).getResidents();
} else {
throw new RuntimeException(context.toString() + " must implement IOOnAttachListener");
}
addParticipantListener = (IOClickOnAddParticipantListener) context;
changeStateActivityListener = (IOnChageStateActivityListener) context;
super.onAttach(context);
}
}

View File

@ -0,0 +1,91 @@
package com.andresgmoran.apptrabajadores.ui.fragments.activities;
import android.app.DatePickerDialog;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.andresgmoran.apptrabajadores.R;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Calendar;
public class AddActivityFragment extends Fragment {
public interface IOnAddActivity {
void onAddActivity(String activityName, String activityDescription, LocalDateTime date);
}
private IOnAddActivity listener;
private Button buttonFecha;
private LocalDateTime selectedDate;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_add_activity, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
TextView textViewNombre = view.findViewById(R.id.add_activity_name_input);
TextView textViewDescripcion = view.findViewById(R.id.add_activity_description_input);
buttonFecha = view.findViewById(R.id.buttonFecha);
Button buttonAgregar = view.findViewById(R.id.save_new_activity_button);
buttonFecha.setOnClickListener(v -> showDatePickerDialog());
buttonAgregar.setOnClickListener(v -> {
String activityName = textViewNombre.getText().toString();
String activityDescription = textViewDescripcion.getText().toString();
if (activityName.isEmpty() || activityDescription.isEmpty() || selectedDate == null) {
return;
}
if (listener != null) {
listener.onAddActivity(activityName, activityDescription, selectedDate);
}
});
}
private void showDatePickerDialog() {
final Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
DatePickerDialog datePickerDialog = new DatePickerDialog(
requireContext(),
(DatePicker view, int selectedYear, int selectedMonth, int selectedDayOfMonth) -> {
selectedDate = LocalDateTime.of(selectedYear, selectedMonth + 1, selectedDayOfMonth, 0, 0);
buttonFecha.setText(selectedDate.toLocalDate().toString());
},
year, month, day
);
datePickerDialog.show();
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof IOnAddActivity) {
listener = (IOnAddActivity) context;
} else {
throw new RuntimeException(context.toString() + " must implement IOnAddActivity");
}
}
}

View File

@ -0,0 +1,55 @@
package com.andresgmoran.apptrabajadores.ui.fragments.activities;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.andresgmoran.apptrabajadores.R;
import com.andresgmoran.apptrabajadores.models.ActivityResident;
public class OpinionFragment extends Fragment {
private ActivityResident participant;
private boolean isPreOpinion;
public interface OnAddOpinionListener {
void onAddOpinion(ActivityResident participant, boolean isPreOpinion, String opinion);
}
private OnAddOpinionListener listener;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_add_opinion, container, false); }
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
EditText opinionEditText = view.findViewById(R.id.opinion_edit_text);
Button addOpinionButton = view.findViewById(R.id.add_opinion_button);
addOpinionButton.setOnClickListener(v -> {
String opinion = opinionEditText.getText().toString();
requireActivity().getSupportFragmentManager().popBackStack();
listener.onAddOpinion(participant, isPreOpinion, opinion);
});
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
listener = (OnAddOpinionListener) context;
if (getArguments() != null) {
participant = (ActivityResident) getArguments().getSerializable("participant");
isPreOpinion = getArguments().getBoolean("isPreOpinion");
}
}
}

View File

@ -0,0 +1,77 @@
package com.andresgmoran.apptrabajadores.ui.fragments.activities;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import com.andresgmoran.apptrabajadores.models.Activity;
import com.andresgmoran.apptrabajadores.models.ActivityResident;
import com.andresgmoran.apptrabajadores.models.Resident;
import java.util.ArrayList;
import java.util.List;
public class ParticipantSelectionDialogFragment extends DialogFragment {
public interface OnParticipantSelectedListener {
void onParticipantSelected(Activity activity, List<ActivityResident> participants , Resident selectedResident);
}
private OnParticipantSelectedListener listener;
private Activity activityId;
private List<ActivityResident> participants;
private List<Resident> residentList;
public ParticipantSelectionDialogFragment(Activity activityId, List<ActivityResident> participants, List<Resident> residents) {
this.residentList = residents;
this.participants = participants;
this.activityId = activityId;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
List<Resident> filteredResidents = new ArrayList<>();
for (Resident resident : residentList) {
boolean alreadyParticipant = false;
for (ActivityResident activityResident : participants) {
if (activityResident.getIdResident().equals(resident.getId())) {
alreadyParticipant = true;
break;
}
}
if (!alreadyParticipant) {
filteredResidents.add(resident);
}
}
String[] names = new String[filteredResidents.size()];
for (int i = 0; i < filteredResidents.size(); i++) {
Resident r = filteredResidents.get(i);
names[i] = r.getName() + " " + r.getSurnames();
}
return new AlertDialog.Builder(getActivity())
.setTitle("Selecciona un residente")
.setItems(names, (dialog, which) -> {
if (listener != null && which >= 0 && which < filteredResidents.size()) {
listener.onParticipantSelected(activityId, participants, filteredResidents.get(which));
}
})
.create();
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof OnParticipantSelectedListener) {
listener = (OnParticipantSelectedListener) context;
} else {
throw new RuntimeException(context.toString() + " must implement OnParticipantSelectedListener");
}
}
}

View File

@ -1,4 +1,4 @@
package com.andresgmoran.apptrabajadores.ui.fragments.logIn;
package com.andresgmoran.apptrabajadores.ui.fragments.authentication;
import android.content.Context;
import android.os.Bundle;
@ -7,6 +7,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
@ -24,13 +25,12 @@ public class LoginFragment extends Fragment {
private OnLoginListener loginListener;
public interface OnLoginListener {
void onLoginSuccess(String email);
List<User> getUsers();
void onLogin(String email, String password, boolean rememberPassword);
}
private EditText emailInput, passwordInput;
private Button loginButton;
private List<User> users;
private CheckBox rememberPasswordCheckBox;
@Nullable
@Override
@ -43,11 +43,14 @@ public class LoginFragment extends Fragment {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
emailInput = view.findViewById(R.id.email_input);
passwordInput = view.findViewById(R.id.password_input);
emailInput = view.findViewById(R.id.email_input_login);
passwordInput = view.findViewById(R.id.password_input_login);
rememberPasswordCheckBox = view.findViewById(R.id.remember_password_checkBox);
loginButton = view.findViewById(R.id.login_button);
loginButton.setOnClickListener(v -> {
loginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String email = emailInput.getText().toString().trim();
String password = passwordInput.getText().toString();
@ -56,25 +59,14 @@ public class LoginFragment extends Fragment {
return;
}
for (User user : users) {
if (user.getEmail().equals(email)) {
loginListener.onLoginSuccess(email);
return;
loginListener.onLogin(email, password, rememberPasswordCheckBox.isChecked());
}
}
Toast.makeText(getActivity(), "Usuario o contraseña incorrectos", Toast.LENGTH_SHORT).show();
});
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof OnLoginListener) {
users = ((OnLoginListener) context).getUsers();
} else {
throw new RuntimeException(context + " must implement OnLoginListener");
}
if (context instanceof OnLoginListener) {
loginListener = (OnLoginListener) context;
} else {

View File

@ -6,6 +6,7 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
import androidx.annotation.NonNull;
@ -13,20 +14,19 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.andresgmoran.apptrabajadores.R;
import com.andresgmoran.apptrabajadores.interfaces.IOClickOnGameStatsListener;
import com.andresgmoran.apptrabajadores.models.Game;
import com.andresgmoran.apptrabajadores.models.Observation;
import com.andresgmoran.apptrabajadores.models.Resident;
import com.andresgmoran.apptrabajadores.models.adapters.LastGamesAdapter;
import com.andresgmoran.apptrabajadores.models.adapters.ObservationsAdapter;
import com.andresgmoran.apptrabajadores.models.gameStats.GameStat;
import com.andresgmoran.apptrabajadores.ui.MainActivity;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class GameFragment extends Fragment {
private List<GameStat> gameStats;
@ -37,7 +37,7 @@ public class GameFragment extends Fragment {
private TextView numberOfGamesLastWeekTextView;
private TextView totalGamesPlayedTextView;
private TextView topPlayerTextView;
private ImageButton backButton;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@ -52,6 +52,18 @@ public class GameFragment extends Fragment {
totalGamesPlayedTextView = view.findViewById(R.id.tv_total_games_played);
topPlayerTextView = view.findViewById(R.id.tv_top_jugador);
SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_game);
swipeRefreshLayout.setOnRefreshListener(() -> {
((MainActivity) requireActivity()).refreshGameStatsAndReload();
swipeRefreshLayout.setRefreshing(false);
});
backButton = view.findViewById(R.id.back_button);
backButton.setOnClickListener(v -> {
requireActivity().getSupportFragmentManager().popBackStack();
});
List<GameStat> allGameStats = new ArrayList<>();
for (GameStat gs : gameStats){
if (gs.getGameId() == game.getId()){
@ -59,20 +71,24 @@ public class GameFragment extends Fragment {
}
}
gameNameTextView.setText(game.getName());
if (allGameStats.isEmpty()) {
numberOfGamesLastWeekTextView.setText("-");
totalGamesPlayedTextView.setText("-");
topPlayerTextView.setText("-");
view.findViewById(R.id.rv_game_stats).setVisibility( View.GONE );
view.findViewById(R.id.tv_lastgames_empty_game).setVisibility( View.VISIBLE );
return;
}
int numberOfGamesLastWeek = getGamesLastWeek(allGameStats);
numberOfGamesLastWeekTextView.setText(String.valueOf(numberOfGamesLastWeek));
totalGamesPlayedTextView.setText(String.valueOf(allGameStats.size()));
Resident topResident = getTopResident(allGameStats, residents);
if (topResident != null) {
topPlayerTextView.setText(topResident.getName());
} else {
topPlayerTextView.setText("No hay jugadores");
}
LastGamesAdapter lastGamesAdapter = new LastGamesAdapter(gameStats, game, residents, (IOClickOnGameStatsListener) requireActivity());
LastGamesAdapter lastGamesAdapter = new LastGamesAdapter(allGameStats, game, residents, (IOClickOnGameStatsListener) requireActivity());
RecyclerView recyclerView = view.findViewById(R.id.rv_game_stats);
recyclerView.setAdapter( lastGamesAdapter );
recyclerView.setHasFixedSize(true);

View File

@ -5,38 +5,46 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.andresgmoran.apptrabajadores.R;
import com.andresgmoran.apptrabajadores.models.Game;
import com.andresgmoran.apptrabajadores.models.Observation;
import com.andresgmoran.apptrabajadores.models.Resident;
import com.andresgmoran.apptrabajadores.models.adapters.LastGamesAdapter;
import com.andresgmoran.apptrabajadores.models.adapters.ObservationsAdapter;
import com.andresgmoran.apptrabajadores.models.User;
import com.andresgmoran.apptrabajadores.models.gameStats.GameStat;
import com.andresgmoran.apptrabajadores.ui.MainActivity;
import java.util.List;
public class GameDetailFragment extends Fragment {
public interface IOOnAttachListener{
List<Observation> getObservations();
public interface IOnAddObservationListener {
void onAddObservation(String observation, long gameId, long gameStatId);
List<User> getUsers();
}
private IOnAddObservationListener addObservationListener;
private GameStat gameStat;
private Resident gameStatResident;
private Game gameStatGame;
private User actualUser;
private List<User> users;
private TextView residentNameTextView;
private TextView gameNameTextView;
private TextView durationTextView;
private TextView failsTitle;
private TextView failsTextView;
List<Observation> observations;
private ImageButton backButton;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@ -47,15 +55,73 @@ public class GameDetailFragment extends Fragment {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_game_detail);
swipeRefreshLayout.setOnRefreshListener(() -> {
((MainActivity) requireActivity()).refreshGameStatsAndReload();
swipeRefreshLayout.setRefreshing(false);
});
backButton = view.findViewById(R.id.back_button);
backButton.setOnClickListener(v -> {
requireActivity().getSupportFragmentManager().popBackStack();
});
residentNameTextView = view.findViewById(R.id.banner_name_resident);
gameNameTextView = view.findViewById(R.id.game_stats_detail_game_name);
durationTextView = view.findViewById(R.id.tv_duration);
failsTitle = view.findViewById(R.id.label_fails);
failsTextView = view.findViewById(R.id.tv_fails);
residentNameTextView.setText(gameStatResident.getName() + " " + gameStatResident.getSurnames());
gameNameTextView.setText(gameStatGame.getName());
durationTextView.setText(Math.round(gameStat.getDuration()) + " seg");
if (gameStatGame.getName().equals("bingo auditivo") || gameStatGame.getName().equals("flecha y reacciona")) {
failsTitle.setText("Resultado");
if (gameStat.getNum() == 0) {
failsTextView.setText("PERDIDO");
} else {
failsTextView.setText("GANADO");
}
} else {
failsTextView.setText(gameStat.getNum() + " fallos");
}
View observation = view.findViewById(R.id.observation);
TextView observationUserName = observation.findViewById(R.id.observation_user_name);
TextView observationUserRole = observation.findViewById(R.id.observation_person_role);
TextView observationText = observation.findViewById(R.id.observation_text);
EditText observationEditText = observation.findViewById(R.id.observation_input);
Button addObservationButton = observation.findViewById(R.id.add_observation_button);
for (User user : users) {
if (user.getId() == gameStat.getUserId()) {
observationUserName.setText(actualUser.getName());
break;
}
}
if (gameStat.getObservation().isEmpty()) {
if (gameStat.getUserId() == actualUser.getId()) {
observationEditText.setVisibility(View.VISIBLE);
addObservationButton.setVisibility(View.VISIBLE);
addObservationButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addObservationListener.onAddObservation(observationEditText.getText().toString(), gameStatGame.getId(), gameStat.getId());
}
});
} else {
observationUserRole.setText("El usuario encargado no ha añadido ninguna observación");
}
} else {
observationText.setVisibility(View.VISIBLE);
//Añadir rol usuario
observationText.setText(gameStat.getObservation());
}
}
@ -63,12 +129,19 @@ public class GameDetailFragment extends Fragment {
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof IOnAddObservationListener) {
addObservationListener = (IOnAddObservationListener) context;
} else {
throw new RuntimeException(context.toString() + " must implement IOnAddObservationListener");
}
users = addObservationListener.getUsers();
if(getArguments() != null) {
gameStat = (GameStat) getArguments().getSerializable("gameStat");
gameStatResident = (Resident) getArguments().getSerializable("gameStatResident");
gameStatGame = (Game) getArguments().getSerializable("gameStatGame");
actualUser = (User) getArguments().getSerializable("user");
}
GameDetailFragment.IOOnAttachListener attachListener = (GameDetailFragment.IOOnAttachListener) context;
observations = attachListener.getObservations();
}
}

View File

@ -1,17 +1,22 @@
package com.andresgmoran.apptrabajadores.ui.fragments.home;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.andresgmoran.apptrabajadores.R;
import com.andresgmoran.apptrabajadores.interfaces.IOClickOnGameListener;
@ -24,7 +29,13 @@ import com.andresgmoran.apptrabajadores.models.adapters.GamesAdapter;
import com.andresgmoran.apptrabajadores.models.adapters.LastGamesAdapter;
import com.andresgmoran.apptrabajadores.models.adapters.ResidentsAdapter;
import com.andresgmoran.apptrabajadores.models.gameStats.GameStat;
import com.andresgmoran.apptrabajadores.network.ApiClient;
import com.andresgmoran.apptrabajadores.ui.MainActivity;
import com.bumptech.glide.Glide;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class HomeFragment extends Fragment {
@ -32,24 +43,41 @@ public class HomeFragment extends Fragment {
public interface IOOnAttachListenerResidents {
List<Resident> getResidents();
}
public interface IOOnAttachListenerGameStats {
List<GameStat> getGameStats();
}
public interface IOOnAttachListenerGames {
List<Game> getGames();
}
public interface IOOnAttachListenerUser {
User getActualUser();
Bitmap getActualUserImage();
}
private List<Resident> residents;
private List<GameStat> gameStats;
private List<Game> games;
private List<User> users;
private User user;
private Bitmap userImageBitmap;
private String userEmail;
private TextView userNameTextView;
private RecyclerView recyclerViewLastGames;
private TextView emptyLatestGamesText;
private RecyclerView recyclerViewGames;
private TextView emptyGamesText;
private RecyclerView recyclerViewResidents;
private TextView emptyResidentsText;
private ImageView userImage;
private GamesAdapter gamesAdapter;
private ResidentsAdapter residentsAdapter;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_home, container, false);
}
@ -57,50 +85,162 @@ public class HomeFragment extends Fragment {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
userNameTextView = view.findViewById(R.id.home_user_name);
SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_home);
for (User user : users) {
if (user.getEmail().equals(userEmail)) {
swipeRefreshLayout.setOnRefreshListener(() -> {
((MainActivity) requireActivity()).refreshGameStatsAndReload();
swipeRefreshLayout.setRefreshing(false);
});
userNameTextView = view.findViewById(R.id.home_user_name);
String fullName = user.getName() + " " + user.getSurnames();
userNameTextView.setText(fullName);
break;
}
}
userImage = view.findViewById(R.id.user_image_home);
userImage.setImageBitmap(userImageBitmap);
emptyLatestGamesText = view.findViewById(R.id.tv_lastgames_empty_home);
LastGamesAdapter lastGamesAdapter = new LastGamesAdapter(gameStats, games, residents, (IOClickOnGameStatsListener) requireActivity());
RecyclerView recyclerViewLastGames = view.findViewById(R.id.latestGames_recycleView_home);
recyclerViewLastGames = view.findViewById(R.id.latestGames_recycleView_home);
recyclerViewLastGames.setAdapter(lastGamesAdapter);
recyclerViewLastGames.setHasFixedSize(true);
recyclerViewLastGames.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false));
GamesAdapter gamesAdapter = new GamesAdapter(games, (IOClickOnGameListener) requireActivity());
RecyclerView recyclerViewGames = view.findViewById(R.id.games_recycleView_home);
if (gameStats.isEmpty()) {
recyclerViewLastGames.setVisibility(View.GONE);
emptyLatestGamesText.setVisibility(View.VISIBLE);
} else {
recyclerViewLastGames.setVisibility(View.VISIBLE);
emptyLatestGamesText.setVisibility(View.GONE);
}
emptyGamesText = view.findViewById(R.id.tv_games_empty_home);
gamesAdapter = new GamesAdapter(games, (IOClickOnGameListener) requireActivity());
recyclerViewGames = view.findViewById(R.id.games_recycleView_home);
recyclerViewGames.setAdapter(gamesAdapter);
recyclerViewGames.setHasFixedSize(true);
recyclerViewGames.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
ResidentsAdapter adapter = new ResidentsAdapter(residents, (IOClickOnResidentListener) requireActivity());
RecyclerView recyclerView = view.findViewById(R.id.residents_recycleView_home);
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
if (games.isEmpty()) {
recyclerViewGames.setVisibility(View.GONE);
emptyGamesText.setVisibility(View.VISIBLE);
} else {
recyclerViewGames.setVisibility(View.VISIBLE);
emptyGamesText.setVisibility(View.GONE);
}
emptyResidentsText = view.findViewById(R.id.tv_residents_empty_home);
residentsAdapter = new ResidentsAdapter(residents, (IOClickOnResidentListener) requireActivity());
recyclerViewResidents = view.findViewById(R.id.residents_recycleView_home);
recyclerViewResidents.setAdapter(residentsAdapter);
recyclerViewResidents.setHasFixedSize(true);
recyclerViewResidents.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
if (residents.isEmpty()) {
recyclerViewResidents.setVisibility(View.GONE);
emptyResidentsText.setVisibility(View.VISIBLE);
} else {
recyclerViewResidents.setVisibility(View.VISIBLE);
emptyResidentsText.setVisibility(View.GONE);
}
View filterGamesButton = view.findViewById(R.id.filter_games_list_button);
View filterResidentsButton = view.findViewById(R.id.filter_residents_list_button);
filterGamesButton.setOnClickListener(v -> showGamesFilterDialog());
filterResidentsButton.setOnClickListener(v -> showResidentsFilterDialog());
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (getArguments() != null) {
userEmail = getArguments().getString("email");
users = (List<User>) getArguments().getSerializable("users");
}
IOOnAttachListenerUser attachListenerActualUser = (IOOnAttachListenerUser) context;
user = attachListenerActualUser.getActualUser();
userImageBitmap = attachListenerActualUser.getActualUserImage();
IOOnAttachListenerGameStats attachListenerLastGames = (IOOnAttachListenerGameStats) context;
gameStats = attachListenerLastGames.getGameStats();
HomeFragment.IOOnAttachListenerResidents attachListenerResidents = (HomeFragment.IOOnAttachListenerResidents) context;
IOOnAttachListenerResidents attachListenerResidents = (IOOnAttachListenerResidents) context;
residents = attachListenerResidents.getResidents();
IOOnAttachListenerGames attachListenerGames = (IOOnAttachListenerGames) context;
games = attachListenerGames.getGames();
}
private void showGamesFilterDialog() {
String[] options = {"A-Z", "Z-A", "Más jugados"};
new androidx.appcompat.app.AlertDialog.Builder(requireContext())
.setTitle("Filtrar juegos")
.setItems(options, (dialog, which) -> {
String selectedOption = options[which];
filterGamesList(selectedOption);
})
.show();
}
private void showResidentsFilterDialog() {
String[] options = {"A-Z", "Z-A", "Fecha de nacimiento"};
new androidx.appcompat.app.AlertDialog.Builder(requireContext())
.setTitle("Filtrar residentes")
.setItems(options, (dialog, which) -> {
String selectedOption = options[which];
filterResidentsList(selectedOption);
})
.show();
}
private void filterGamesList(String option) {
List<Game> filteredList = new ArrayList<>(games);
switch (option) {
case "A-Z":
Collections.sort(filteredList, Comparator.comparing(Game::getName));
break;
case "Z-A":
Collections.sort(filteredList, (g1, g2) -> g2.getName().compareTo(g1.getName()));
break;
case "Más jugados":
Collections.sort(filteredList, (g1, g2) -> {
int count1 = 0;
int count2 = 0;
for (GameStat stat : gameStats) {
if (stat.getGameId() == g1.getId()) {
count1++;
}
if (stat.getGameId() == g2.getId()) {
count2++;
}
}
return Integer.compare(count2, count1); // Mayor a menor
});
break;
}
gamesAdapter.updateData(filteredList);
recyclerViewGames.scrollToPosition(0);
}
private void filterResidentsList(String option) {
List<Resident> filteredList = new ArrayList<>(residents);
switch (option) {
case "A-Z":
Collections.sort(filteredList, Comparator.comparing(Resident::getName));
break;
case "Z-A":
Collections.sort(filteredList, (r1, r2) -> r2.getName().compareTo(r1.getName()));
break;
case "Fecha de nacimiento":
Collections.sort(filteredList, Comparator.comparing(Resident::getBirthDate));
break;
}
residentsAdapter.updateData(filteredList);
recyclerViewResidents.scrollToPosition(0);
}
}

View File

@ -6,6 +6,7 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
@ -15,6 +16,7 @@ import androidx.cardview.widget.CardView;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.andresgmoran.apptrabajadores.R;
import com.andresgmoran.apptrabajadores.interfaces.IOClickOnGameStatsListener;
@ -22,6 +24,7 @@ import com.andresgmoran.apptrabajadores.models.Game;
import com.andresgmoran.apptrabajadores.models.Resident;
import com.andresgmoran.apptrabajadores.models.adapters.LastGamesAdapter;
import com.andresgmoran.apptrabajadores.models.gameStats.GameStat;
import com.andresgmoran.apptrabajadores.ui.MainActivity;
import com.andresgmoran.apptrabajadores.ui.graphics.CustomBarChartView;
import com.andresgmoran.apptrabajadores.ui.graphics.CustomPieChartView;
import java.util.ArrayList;
@ -35,6 +38,13 @@ public class ResidentFragment extends Fragment {
private List<Game> games;
private List<GameStat> gameStats;
private ImageButton backButton;
private TextView residentName;
private CardView pieCard;
private TextView tvLastGamesEmpty;
private TextView tvStatsEmpty;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@ -44,9 +54,26 @@ public class ResidentFragment extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_resident);
swipeRefreshLayout.setOnRefreshListener(() -> {
((MainActivity) requireActivity()).refreshGameStatsAndReload();
swipeRefreshLayout.setRefreshing(false);
});
pieCard = view.findViewById(R.id.pieCard);
tvLastGamesEmpty = view.findViewById(R.id.tv_lastgames_empty_resident);
tvStatsEmpty = view.findViewById(R.id.tv_stats_empty_resident);
View banner = view.findViewById(R.id.resident_banner);
TextView residentName = banner.findViewById(R.id.banner_name_game);
backButton = banner.findViewById(R.id.back_button);
backButton.setOnClickListener(v -> {
requireActivity().getSupportFragmentManager().popBackStack();
});
residentName = banner.findViewById(R.id.banner_name_game);
String fullName = resident.getName() + " " + resident.getSurnames();
residentName.setText(fullName);
@ -64,9 +91,21 @@ public class ResidentFragment extends Fragment {
recyclerViewLastGames.setHasFixedSize(true);
recyclerViewLastGames.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false));
if (filteredStats.isEmpty()){
pieCard.setVisibility(View.GONE);
recyclerViewLastGames.setVisibility(View.GONE);
tvLastGamesEmpty.setVisibility(View.VISIBLE);
tvStatsEmpty.setVisibility(View.VISIBLE);
} else {
pieCard.setVisibility(View.VISIBLE);
recyclerViewLastGames.setVisibility(View.VISIBLE);
tvLastGamesEmpty.setVisibility(View.GONE);
tvStatsEmpty.setVisibility(View.GONE);
pieChart(view);
generateBarCharts(view);
}
}
private void pieChart(View view){
CustomPieChartView pieChart = view.findViewById(R.id.pieChart);

View File

@ -17,10 +17,16 @@ import com.andresgmoran.apptrabajadores.interfaces.IOClickOnResidentListener;
import com.andresgmoran.apptrabajadores.models.Resident;
import com.andresgmoran.apptrabajadores.models.adapters.ResidentsAdapter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ResidentsListFragment extends Fragment {
private ResidentsAdapter residentsAdapter;
private RecyclerView recyclerViewResidents;
public interface IOOnAttachListener{
List<Resident> getResidents();
}
@ -35,11 +41,46 @@ public class ResidentsListFragment extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ResidentsAdapter adapter = new ResidentsAdapter(residents, (IOClickOnResidentListener) requireActivity());
RecyclerView recyclerView = view.findViewById(R.id.residents_recycleView);
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
residentsAdapter = new ResidentsAdapter(residents, (IOClickOnResidentListener) requireActivity());
recyclerViewResidents = view.findViewById(R.id.residents_recycleView);
recyclerViewResidents.setAdapter(residentsAdapter);
recyclerViewResidents.setHasFixedSize(true);
recyclerViewResidents.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
View filterResidentsButton = view.findViewById(R.id.filter_residents_list_button);
filterResidentsButton.setOnClickListener(v -> showResidentsFilterDialog());
}
private void showResidentsFilterDialog() {
String[] options = {"A-Z", "Z-A", "Fecha de nacimiento"};
new androidx.appcompat.app.AlertDialog.Builder(requireContext())
.setTitle("Filtrar residentes")
.setItems(options, (dialog, which) -> {
String selectedOption = options[which];
filterResidentsList(selectedOption);
})
.show();
}
private void filterResidentsList(String option) {
List<Resident> filteredList = new ArrayList<>(residents);
switch (option) {
case "A-Z":
Collections.sort(filteredList, Comparator.comparing(Resident::getName));
break;
case "Z-A":
Collections.sort(filteredList, (r1, r2) -> r2.getName().compareTo(r1.getName()));
break;
case "Fecha de nacimiento":
Collections.sort(filteredList, Comparator.comparing(Resident::getBirthDate));
break;
}
residentsAdapter.updateData(filteredList);
recyclerViewResidents.scrollToPosition(0);
}
@Override

View File

@ -0,0 +1,55 @@
package com.andresgmoran.apptrabajadores.utils;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.security.crypto.EncryptedSharedPreferences;
import androidx.security.crypto.MasterKey;
public class SecurePreferencesUtil {
private static final String PREF_NAME = "secure_auth";
private static SharedPreferences encryptedPrefs = null;
public static SharedPreferences getEncryptedPrefs(Context context) {
if (encryptedPrefs == null) {
try {
MasterKey masterKey = new MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build();
encryptedPrefs = EncryptedSharedPreferences.create(
context,
PREF_NAME,
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
} catch (Exception e) {
throw new RuntimeException("Error al inicializar SharedPreferences encriptadas", e);
}
}
return encryptedPrefs;
}
public static String getString(Context context, String key, String defaultValue) {
return getEncryptedPrefs(context).getString(key, defaultValue);
}
public static boolean getBoolean(Context context, String key, boolean defaultValue) {
return getEncryptedPrefs(context).getBoolean(key, defaultValue);
}
public static long getLong(Context context, String key, long defaultValue) {
return getEncryptedPrefs(context).getLong(key, defaultValue);
}
public static void edit(Context context, SharedPreferences.Editor editor) {
editor.apply();
}
public static void clear(Context context) {
SharedPreferences.Editor editor = getEncryptedPrefs(context).edit();
editor.clear();
edit(context, editor);
}
}

View File

@ -0,0 +1,4 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#59FF00" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 999 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -7,7 +7,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Incluye el contenido principal respetando el BottomNav -->
<include
android:id="@+id/content_main_include"
layout="@layout/content_main"
@ -18,7 +17,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- Círculo de carga centrado -->
<ProgressBar
android:id="@+id/progress_loader"
style="?android:attr/progressBarStyleLarge"
@ -31,14 +29,11 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<!-- Menú de navegación inferior anclado abajo -->
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
style="@style/RoundedBottomNav"
android:layout_width="407dp"
android:layout_height="56dp"
android:layout_marginHorizontal="30dp"
android:layout_marginBottom="40dp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"

View File

@ -31,7 +31,7 @@
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView2"
android:id="@+id/label_highlights"
android:layout_width="0dp"
android:layout_height="20dp"
android:layout_marginTop="20dp"
@ -44,47 +44,53 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edit_account_button" />
<TextView
android:id="@+id/textView3"
<Button
android:id="@+id/btn_favoritos"
android:layout_width="0dp"
android:layout_height="20dp"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@android:color/transparent"
android:fontFamily="@font/assistant_bold"
android:paddingStart="20dp"
android:text="Favoritos"
android:textAllCaps="false"
android:textColor="#324F5E"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView2" />
app:layout_constraintTop_toBottomOf="@+id/label_highlights" />
<TextView
android:id="@+id/textView4"
<Button
android:id="@+id/btn_residentes"
android:layout_width="0dp"
android:layout_height="20dp"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@android:color/transparent"
android:fontFamily="@font/assistant_bold"
android:paddingStart="20dp"
android:text="Residentes"
android:textAllCaps="false"
android:textColor="#324F5E"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView3" />
app:layout_constraintTop_toBottomOf="@+id/btn_favoritos" />
<TextView
android:id="@+id/textView5"
<Button
android:id="@+id/btn_juegos"
android:layout_width="0dp"
android:layout_height="20dp"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@android:color/transparent"
android:fontFamily="@font/assistant_bold"
android:paddingStart="20dp"
android:text="Juegos"
android:textAllCaps="false"
android:textColor="#324F5E"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView4" />
app:layout_constraintTop_toBottomOf="@+id/btn_residentes" />
<TextView
android:id="@+id/textView6"
android:id="@+id/label_preferences"
android:layout_width="0dp"
android:layout_height="20dp"
android:layout_marginTop="10dp"
@ -95,45 +101,51 @@
android:textColor="#324F5E"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView5" />
app:layout_constraintTop_toBottomOf="@+id/btn_juegos" />
<TextView
android:id="@+id/textView7"
<Button
android:id="@+id/btn_idioma"
android:layout_width="0dp"
android:layout_height="20dp"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@android:color/transparent"
android:fontFamily="@font/assistant_bold"
android:paddingStart="20dp"
android:text="Idioma"
android:textAllCaps="false"
android:textColor="#324F5E"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView6" />
app:layout_constraintTop_toBottomOf="@+id/label_preferences" />
<TextView
android:id="@+id/textView8"
<Button
android:id="@+id/btn_modo_oscuro"
android:layout_width="0dp"
android:layout_height="20dp"
android:layout_marginTop="5dp"
android:fontFamily="@font/assistant_bold"
android:paddingStart="20dp"
android:text="Modo oscuro"
android:textColor="#324F5E"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView7" />
<TextView
android:id="@+id/textView9"
android:layout_width="0dp"
android:layout_height="20dp"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@android:color/transparent"
android:fontFamily="@font/assistant_bold"
android:paddingStart="20dp"
android:text="Ajustes"
android:textAllCaps="false"
android:textColor="#324F5E"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView8" />
app:layout_constraintTop_toBottomOf="@+id/btn_idioma" />
<Button
android:id="@+id/btn_cerrar_sesion"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@android:color/transparent"
android:fontFamily="@font/assistant_bold"
android:paddingStart="20dp"
android:text="Cerrar Sesión"
android:textAllCaps="false"
android:textColor="#324F5E"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_modo_oscuro" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,18 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swipe_refresh_layout_activities_list"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#CCCCCC"
android:backgroundTint="#CCCCCC">
<LinearLayout
android:id="@+id/linearLayout3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/textView11"
android:id="@+id/textView18"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:fontFamily="@font/assistant_bold"
android:text="Actividades"
android:textColor="#324F5E"
android:textSize="20sp" />
<ImageButton
android:id="@+id/filter_activities_list_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="284dp"
android:text="Activities"
android:layout_gravity="center"
android:background="@android:color/transparent"
android:contentDescription="Filtro"
app:srcCompat="@drawable/filter" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/activities_recycleView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
app:layout_constraintEnd_toEndOf="@+id/linearLayout3"
app:layout_constraintStart_toStartOf="@+id/linearLayout3"
app:layout_constraintTop_toBottomOf="@+id/linearLayout3" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/add_activity_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="Añadir actividad"
app:backgroundTint="#324F5E"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
app:srcCompat="@android:drawable/ic_input_add"
app:tint="@android:color/white" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@ -1,6 +1,345 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/swipe_refresh_activity_detail"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:id="@+id/nested_scroll_game_detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#CCCCCC"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Banner azul -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/background_banner"
android:layout_width="0dp"
android:layout_height="174dp"
android:background="#0062FF"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageButton
android:id="@+id/back_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:background="@null"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/arrow_left" />
<TextView
android:id="@+id/activitie_detail_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/assistant_bold"
android:text="TextView"
android:textColor="#324F5E"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_start_end_activity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:text="Iniciar actividad"
android:textColor="@android:color/white"
app:backgroundTint="#28A745"
app:iconTint="@android:color/white"
app:iconPadding="8dp"
app:iconGravity="textStart"
app:layout_constraintTop_toBottomOf="@id/activitie_detail_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Nueva sección Descripción -->
<TextView
android:id="@+id/section_description_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#FFFFFFFF"
android:fontFamily="@font/assistant_semibold"
android:gravity="center"
android:text="Descripción"
android:textColor="#324F5E"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/background_banner" />
<TextView
android:id="@+id/tv_description_activity_detail"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:fontFamily="@font/assistant_semibold"
android:textColor="#324F5E"
android:textSize="16sp"
android:padding="16dp"
app:layout_constraintTop_toBottomOf="@id/section_description_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<!-- Sección Información -->
<TextView
android:id="@+id/textView2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#FFFFFF"
android:fontFamily="@font/assistant_semibold"
android:gravity="center"
android:text="Información"
android:textColor="#324F5E"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_description_activity_detail" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/info_container_activity_detail"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#CCCCCC"
android:padding="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView2">
<!-- Fecha -->
<TextView
android:id="@+id/label_date_activity_detail"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="@font/assistant_semibold"
android:text="Fecha"
android:textColor="#2C3E50"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@+id/tv_date_activity_detail"
app:layout_constraintHorizontal_bias="0" />
<TextView
android:id="@+id/tv_date_activity_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/assistant_semibold"
android:text="20/09/2025"
android:textColor="#2C3E50"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/label_date_activity_detail" />
<!-- Hora de salida -->
<TextView
android:id="@+id/label_exit_time_activity_detail"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:fontFamily="@font/assistant_semibold"
android:text="Hora de salida"
android:textColor="#2C3E50"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/label_date_activity_detail"
app:layout_constraintEnd_toStartOf="@+id/tv_exit_time_activity_detail" />
<TextView
android:id="@+id/tv_exit_time_activity_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/assistant_semibold"
android:text="10:00am"
android:textColor="#2C3E50"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/label_exit_time_activity_detail" />
<!-- Hora de vuelta estimada -->
<TextView
android:id="@+id/label_total_residents_activity_detail"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:fontFamily="@font/assistant_semibold"
android:text="Residentes totales"
android:textColor="#2C3E50"
android:textSize="16sp"
app:layout_constraintEnd_toStartOf="@+id/tv_total_participants_activity_detail"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/label_exit_time_activity_detail" />
<TextView
android:id="@+id/tv_total_participants_activity_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/assistant_semibold"
android:textColor="#2C3E50"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/label_total_residents_activity_detail" />
<!-- Residentes confirmados -->
<TextView
android:id="@+id/label_confirmed_residents"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:fontFamily="@font/assistant_semibold"
android:text="Residentes que si van"
android:textColor="#2C3E50"
android:textSize="16sp"
app:layout_constraintEnd_toStartOf="@+id/tv_confirmed_residents"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/label_total_residents_activity_detail" />
<TextView
android:id="@+id/tv_confirmed_residents"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/assistant_semibold"
android:text="20"
android:textColor="#2C3E50"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/label_confirmed_residents" />
<!-- Residentes sin confirmar -->
<TextView
android:id="@+id/label_unconfirmed_residents"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:fontFamily="@font/assistant_semibold"
android:text="Residentes que no van"
android:textColor="#2C3E50"
android:textSize="16sp"
app:layout_constraintEnd_toStartOf="@+id/tv_unconfirmed_residents"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/label_confirmed_residents" />
<TextView
android:id="@+id/tv_unconfirmed_residents"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/assistant_semibold"
android:text="11"
android:textColor="#2C3E50"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/label_unconfirmed_residents" />
<!-- Asistencia necesaria -->
<TextView
android:id="@+id/label_required_human_attendance"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:fontFamily="@font/assistant_semibold"
android:text="Asistencia humana necesaria"
android:textColor="#2C3E50"
android:textSize="16sp"
app:layout_constraintEnd_toStartOf="@+id/tv_required_human_attendance"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/label_unconfirmed_residents" />
<TextView
android:id="@+id/tv_required_human_attendance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/assistant_semibold"
android:text="9"
android:textColor="#2C3E50"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/label_required_human_attendance" />
<TextView
android:id="@+id/label_required_material_attendance"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:fontFamily="@font/assistant_semibold"
android:text="Asistencia material necesaria"
android:textColor="#2C3E50"
android:textSize="16sp"
app:layout_constraintEnd_toStartOf="@+id/tv_required_material_attendance"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/label_required_human_attendance" />
<TextView
android:id="@+id/tv_required_material_attendance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/assistant_semibold"
android:text="9"
android:textColor="#2C3E50"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/label_required_material_attendance" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Sección Participantes -->
<TextView
android:id="@+id/textView6"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="#FFFFFFFF"
android:fontFamily="@font/assistant_semibold"
android:gravity="center"
android:text="Participantes"
android:textColor="#324F5E"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/info_container_activity_detail" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_participants"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="@+id/textView6"
app:layout_constraintStart_toStartOf="@+id/textView6"
app:layout_constraintTop_toBottomOf="@+id/textView6" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.button.MaterialButton
android:id="@+id/add_participant_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:text="Añadir participante"
android:contentDescription="Añadir participante"
app:icon="@android:drawable/ic_input_add"
app:iconTint="@android:color/white"
app:iconPadding="8dp"
app:iconGravity="textStart"
app:backgroundTint="#324F5E"
android:textColor="@android:color/white"/>
</FrameLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:padding="20dp"
android:background="#CCCCCC">
<EditText
android:id="@+id/add_activity_name_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="Nombre"
android:inputType="textPersonName"
android:textColor="#324F5E"
android:textColorLink="#6CADFF"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/add_activity_description_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="top|start"
android:hint="Descripción"
android:inputType="textMultiLine"
android:minLines="3"
android:textColor="#324F5E"
android:textColorLink="#6CADFF"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/add_activity_name_input" />
<Button
android:id="@+id/buttonFecha"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:backgroundTint="#00AF4848"
android:text="Seleccionar fecha"
android:textAlignment="viewStart"
android:textColor="#324F5E"
android:textColorLink="#6CADFF"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/add_activity_description_input" />
<Button
android:id="@+id/save_new_activity_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:backgroundTint="#324F5E"
android:text="Guardar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/buttonFecha"
app:layout_constraintTop_toBottomOf="@id/buttonFecha" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/constraint_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<!-- Cuadro de texto para escribir -->
<EditText
android:id="@+id/opinion_edit_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="Escribe algo aquí"
android:padding="12dp"
android:textColor="#000000"
android:textColorHint="#888888"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<!-- Botón debajo del cuadro de texto -->
<Button
android:id="@+id/add_opinion_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Enviar"
android:textColor="#FFFFFF"
android:backgroundTint="#324F5E"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@id/opinion_edit_text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,8 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swipe_refresh_game"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
@ -24,7 +29,7 @@
<!-- Botón superior izquierdo -->
<ImageButton
android:id="@+id/imageButton2"
android:id="@+id/back_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
@ -43,7 +48,7 @@
android:scaleType="centerCrop"
android:src="@drawable/woman_avatar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/imageButton2"
app:layout_constraintTop_toBottomOf="@id/back_button"
app:shapeAppearanceOverlay="@style/CircularShapeAppearance" />
<TextView
@ -94,7 +99,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="@font/assistant_semibold"
android:text="Partidas úlrima semana"
android:text="Partidas última semana"
android:textColor="#2C3E50"
android:textSize="16sp"
app:layout_constraintEnd_toStartOf="@+id/tv_number_of_games_last_week"
@ -184,5 +189,19 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView6" />
<TextView
android:id="@+id/tv_lastgames_empty_game"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:fontFamily="@font/assistant_semibold"
android:text="No hay partidas disponibles"
android:textColor="#96A7AF"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="@+id/textView6"
app:layout_constraintStart_toStartOf="@+id/textView6"
app:layout_constraintTop_toBottomOf="@+id/textView6" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@ -1,11 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/swipe_refresh_game_detail"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:background="#CCCCCC">
android:background="#CCCCCC"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
@ -17,45 +21,45 @@
android:layout_width="0dp"
android:layout_height="174dp"
android:background="#0062FF"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
app:layout_constraintTop_toTopOf="parent">
<!-- Botón superior izquierdo -->
<ImageButton
android:id="@+id/imageButton2"
android:id="@+id/back_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:background="@null"
app:srcCompat="@drawable/arrow_left"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />
app:srcCompat="@drawable/arrow_left" />
<!-- Avatar + texto -->
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/circularImageView"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginStart="20dp"
android:layout_marginTop="16dp"
android:scaleType="centerCrop"
android:src="@drawable/woman_avatar"
app:shapeAppearanceOverlay="@style/CircularShapeAppearance"
app:layout_constraintTop_toBottomOf="@id/imageButton2"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="16dp"
android:layout_marginStart="20dp" />
app:layout_constraintTop_toBottomOf="@id/back_button"
app:shapeAppearanceOverlay="@style/CircularShapeAppearance" />
<LinearLayout
android:id="@+id/user_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="@id/circularImageView"
app:layout_constraintBottom_toBottomOf="@id/circularImageView"
app:layout_constraintStart_toEndOf="@id/circularImageView"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp">
android:layout_marginEnd="12dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="@id/circularImageView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/circularImageView"
app:layout_constraintTop_toTopOf="@id/circularImageView">
<TextView
android:id="@+id/banner_name_resident"
@ -146,7 +150,6 @@
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/label_fails" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Observaciones -->
@ -158,21 +161,22 @@
android:background="#FFFFFFFF"
android:fontFamily="@font/assistant_semibold"
android:gravity="center"
android:text="Observaciones"
android:text="Observacion"
android:textColor="#324F5E"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/stats_container" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/last_games_recycleView"
<include
android:id="@+id/observation"
layout="@layout/item_observation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:nestedScrollingEnabled="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView6" />
app:layout_constraintTop_toBottomOf="@+id/textView6" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@ -1,7 +1,13 @@
<androidx.core.widget.NestedScrollView
<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swipe_refresh_home"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
@ -51,7 +57,7 @@
</LinearLayout>
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/circularImageView3"
android:id="@+id/user_image_home"
android:layout_width="55dp"
android:layout_height="match_parent"
android:scaleType="centerCrop"
@ -103,6 +109,19 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/linearLayout2" />
<TextView
android:id="@+id/tv_lastgames_empty_home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:fontFamily="@font/assistant_semibold"
android:text="No hay partidas disponibles"
android:textColor="#96A7AF"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="@+id/linearLayout2"
app:layout_constraintStart_toStartOf="@+id/linearLayout2"
app:layout_constraintTop_toBottomOf="@+id/linearLayout2" />
<LinearLayout
android:id="@+id/linearLayout4"
android:layout_width="match_parent"
@ -132,7 +151,6 @@
android:background="@android:color/transparent"
android:contentDescription="Filtro"
app:srcCompat="@drawable/filter" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
@ -146,6 +164,19 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/linearLayout4" />
<TextView
android:id="@+id/tv_games_empty_home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:fontFamily="@font/assistant_semibold"
android:text="No hay juegos disponibles"
android:textColor="#96A7AF"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="@+id/linearLayout4"
app:layout_constraintStart_toStartOf="@+id/linearLayout4"
app:layout_constraintTop_toBottomOf="@+id/linearLayout4" />
<LinearLayout
android:id="@+id/linearLayout3"
android:layout_width="match_parent"
@ -175,7 +206,6 @@
android:background="@android:color/transparent"
android:contentDescription="Filtro"
app:srcCompat="@drawable/filter" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
@ -189,6 +219,21 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/linearLayout3" />
<TextView
android:id="@+id/tv_residents_empty_home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:fontFamily="@font/assistant_semibold"
android:text="No hay residentes disponibles"
android:textColor="#96A7AF"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="@+id/linearLayout3"
app:layout_constraintStart_toStartOf="@+id/linearLayout3"
app:layout_constraintTop_toBottomOf="@+id/linearLayout3" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="24dp">
@ -15,13 +16,13 @@
android:textColor="#324F5E"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/email_input"
app:layout_constraintBottom_toTopOf="@+id/email_input_login"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/email_input"
android:id="@+id/email_input_login"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
@ -33,7 +34,7 @@
app:layout_constraintTop_toBottomOf="@id/login_title" />
<EditText
android:id="@+id/password_input"
android:id="@+id/password_input_login"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
@ -42,17 +43,25 @@
android:textColorLink="#324F5E"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/email_input" />
app:layout_constraintTop_toBottomOf="@id/email_input_login" />
<CheckBox
android:id="@+id/remember_password_checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Recordar contraseña"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/password_input_login" />
<Button
android:id="@+id/login_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Iniciar sesión"
android:backgroundTint="#324F5E"
app:layout_constraintTop_toBottomOf="@id/password_input"
app:layout_constraintStart_toStartOf="parent"
android:text="Iniciar sesión"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="24dp" />
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/remember_password_checkBox" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,8 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swipe_refresh_resident"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#CCCCCC"
@ -66,6 +71,19 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/linearLayout2" />
<TextView
android:id="@+id/tv_lastgames_empty_resident"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:fontFamily="@font/assistant_semibold"
android:text="No hay partidas disponibles"
android:textColor="#96A7AF"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="@+id/linearLayout2"
app:layout_constraintStart_toStartOf="@+id/linearLayout2"
app:layout_constraintTop_toBottomOf="@+id/linearLayout2" />
<TextView
android:id="@+id/textView16"
android:layout_width="0dp"
@ -81,6 +99,19 @@
app:layout_constraintTop_toBottomOf="@id/latestGames_recycleView_resident" />
<!-- Card con gráfico de dona -->
<TextView
android:id="@+id/tv_stats_empty_resident"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:fontFamily="@font/assistant_semibold"
android:text="No hay estadisticas disponibles"
android:textColor="#96A7AF"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="@+id/textView16"
app:layout_constraintStart_toStartOf="@+id/textView16"
app:layout_constraintTop_toBottomOf="@+id/textView16" />
<androidx.cardview.widget.CardView
android:id="@+id/pieCard"
android:layout_width="0dp"
@ -147,7 +178,14 @@
android:background="#00FF00"
android:text="Laberinto - 10%"
android:textColor="#000000" />
<TextView android:id="@+id/pie_game_5_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#00FF00" android:text="Laberinto - 10%" android:textColor="#000000"/>
<TextView
android:id="@+id/pie_game_5_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00FF00"
android:text="Laberinto - 10%"
android:textColor="#000000"/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
@ -165,5 +203,5 @@
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@ -14,7 +14,7 @@
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/latestGames_recycleView_home">
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/textView18"

View File

@ -36,11 +36,14 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textview_salida" />
<ImageView
android:id="@+id/more_options_activityItem"
<ImageButton
android:id="@+id/more_options_activity_item"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/woman_avatar"
android:background="@null"
android:padding="0dp"
android:scaleType="centerInside"
android:src="@drawable/elipsis"
android:tint="#FFFFFF"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@ -67,5 +70,17 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/date_text_activityItem" />
<ImageButton
android:id="@+id/activity_status_button"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="@android:color/transparent"
android:src="@drawable/open_activity_status"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>

View File

@ -47,11 +47,14 @@
app:layout_constraintStart_toEndOf="@id/profile_image_latestGameItem"
app:layout_constraintTop_toBottomOf="@id/name_text_latestGameItem" />
<ImageView
<ImageButton
android:id="@+id/more_options_latestGameItem"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/woman_avatar"
android:background="@null"
android:padding="0dp"
android:scaleType="centerInside"
android:src="@drawable/elipsis"
android:tint="#FFFFFF"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/profile_image_latestGameItem" />

View File

@ -15,7 +15,7 @@
android:padding="10dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/circularImageView2"
android:id="@+id/item_list_image"
android:layout_width="41dp"
android:layout_height="41dp"
android:scaleType="centerCrop"
@ -45,11 +45,11 @@
</LinearLayout>
<ImageButton
android:id="@+id/imageButton3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/more_options_item_list"
android:layout_width="24dp"
android:layout_height="24dp"
android:background="@null"
app:srcCompat="@drawable/ic_dashboard_black_24dp" />
app:srcCompat="@drawable/elipsis" />
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@ -13,8 +13,8 @@
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/circularImageView3"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_width="52dp"
android:layout_height="51dp"
android:scaleType="centerCrop"
app:shapeAppearanceOverlay="@style/CircularShapeAppearance"
app:srcCompat="@drawable/woman_avatar" />
@ -28,7 +28,7 @@
android:layout_marginStart="10dp">
<TextView
android:id="@+id/home_user_name"
android:id="@+id/observation_user_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Person Name"
@ -42,17 +42,31 @@
</LinearLayout>
</LinearLayout>
<!-- Texto de la observación existente -->
<TextView
android:id="@+id/observation_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="Observation text" />
android:layout_marginTop="10dp"
android:text="Observation text"
android:visibility="gone" />
<!-- Línea de separación -->
<View
<!-- Campo de texto si no hay observación -->
<EditText
android:id="@+id/observation_input"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:hint="Escribe una observación..."
android:inputType="textMultiLine"
android:visibility="invisible" />
<Button
android:id="@+id/add_observation_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@android:color/darker_gray" />
android:backgroundTint="#324F5E"
android:text="Subir observación"
android:visibility="invisible" />
</LinearLayout>

View File

@ -30,7 +30,7 @@
android:orientation="horizontal">
<ImageButton
android:id="@+id/imageButton2"
android:id="@+id/back_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"

View File

@ -14,75 +14,92 @@
android:padding="12dp">
<!-- Imagen circular -->
<ImageView
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/profile_image"
android:layout_width="40dp"
android:layout_height="40dp"
android:scaleType="centerInside"
android:scaleType="centerCrop"
android:src="@drawable/woman_avatar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearanceOverlay="@style/CircularShapeAppearance" />
<!-- Nombre -->
<TextView
android:id="@+id/tv_name"
android:id="@+id/tv_name_participant_item"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="156dp"
android:text="Jose Manuel Carrasco"
android:textColor="#324F5E"
android:textStyle="bold"
android:textSize="16sp"
android:layout_marginStart="12dp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/profile_image"
app:layout_constraintTop_toTopOf="@id/profile_image"
app:layout_constraintEnd_toEndOf="parent"/>
app:layout_constraintTop_toTopOf="@id/profile_image" />
<!-- Primer botón -->
<ImageButton
android:id="@+id/btn_first"
android:id="@+id/participant_asistencia_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:backgroundTint="#6CADFF"
android:src="@drawable/logo_confirmation"
android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:background="@drawable/activity_button_unpressed_background"
android:scaleType="centerInside"
android:padding="8dp"
app:layout_constraintTop_toBottomOf="@id/tv_name"
android:scaleType="centerInside"
android:src="@drawable/logo_confirmation"
app:layout_constraintEnd_toStartOf="@id/participant_opinion_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/btn_second"
android:layout_marginTop="12dp"/>
app:layout_constraintTop_toBottomOf="@id/tv_name_participant_item" />
<!-- Segundo botón -->
<ImageButton
android:id="@+id/btn_second"
android:id="@+id/participant_opinion_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:backgroundTint="#6CADFF"
android:src="@drawable/logo_text"
android:background="@drawable/activity_button_unpressed_background"
android:scaleType="centerInside"
android:padding="8dp"
app:layout_constraintTop_toBottomOf="@id/tv_name"
app:layout_constraintStart_toEndOf="@id/btn_first"
app:layout_constraintEnd_toStartOf="@id/btn_third"
app:layout_constraintTop_toBottomOf="@id/tv_name_participant_item"
app:layout_constraintStart_toEndOf="@id/participant_asistencia_button"
app:layout_constraintEnd_toStartOf="@id/participant_material_help_button"
android:layout_marginStart="8dp"
android:layout_marginTop="12dp"/>
<!-- Nuevo botón -->
<ImageButton
android:id="@+id/participant_material_help_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="@drawable/activity_button_unpressed_background"
android:src="@drawable/logo_material_help"
android:scaleType="centerInside"
android:padding="8dp"
app:layout_constraintTop_toBottomOf="@id/tv_name_participant_item"
app:layout_constraintStart_toEndOf="@id/participant_opinion_button"
app:layout_constraintEnd_toStartOf="@id/participant_human_help_button"
android:layout_marginStart="8dp"
android:layout_marginTop="12dp"/>
<!-- Tercer botón -->
<ImageButton
android:id="@+id/btn_third"
android:id="@+id/participant_human_help_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="@drawable/activity_button_unpressed_background"
android:src="@drawable/logo_help"
android:src="@drawable/logo_human_help"
app:shapeAppearanceOverlay="@style/CircularShapeAppearance"
android:scaleType="centerInside"
android:padding="8dp"
app:layout_constraintTop_toBottomOf="@id/tv_name"
app:layout_constraintStart_toEndOf="@id/btn_second"
app:layout_constraintTop_toBottomOf="@id/tv_name_participant_item"
app:layout_constraintStart_toEndOf="@id/participant_material_help_button"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginStart="8dp"
android:layout_marginTop="12dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>

View File

@ -0,0 +1,5 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_delete"
android:title="Eliminar" />
</menu>

View File

@ -1,5 +0,0 @@
[folding]
node_unfolds=[NodePath("."), PackedStringArray("Layout"), NodePath("MarginContainer"), PackedStringArray("Layout", "Theme Overrides", "Theme Overrides/constants"), NodePath("MarginContainer/VBoxContainer"), PackedStringArray("Layout", "Theme Overrides", "Theme Overrides/constants"), NodePath("MarginContainer/VBoxContainer/Label"), PackedStringArray("Theme Overrides", "Theme Overrides/font_sizes", "Theme Overrides/colors"), NodePath("MarginContainer/VBoxContainer/Label2"), PackedStringArray("Theme Overrides", "Theme Overrides/font_sizes", "Theme Overrides/colors"), NodePath("MarginContainer/VBoxContainer/MenuButton"), PackedStringArray("Layout", "Layout/Container Sizing", "Theme Overrides", "theme_override_styles/normal", "Theme Overrides/colors"), NodePath("MarginContainer/VBoxContainer/Label3"), PackedStringArray("Theme Overrides", "Theme Overrides/font_sizes", "Layout", "Theme Overrides/colors"), NodePath("MarginContainer/VBoxContainer/PlayButton"), PackedStringArray("Theme Overrides", "Layout", "Layout/Container Sizing", "Theme Overrides/styles", "theme_override_styles/normal"), NodePath("Bloqueador"), PackedStringArray("Visibility", "Layout", "Mouse"), NodePath("Warning"), PackedStringArray("Flags"), NodePath("Warning/Panel"), PackedStringArray("Theme Overrides", "Layout", "Theme Overrides/styles", "theme_override_styles/panel"), NodePath("Window/ColorRect"), PackedStringArray("Layout"), NodePath("Window/VBoxContainer"), PackedStringArray("Layout", "Theme Overrides", "Theme Overrides/constants", "Layout/Transform"), NodePath("Window/VBoxContainer/Label"), PackedStringArray("Layout", "Layout/Container Sizing", "Theme Overrides", "Theme Overrides/colors"), NodePath("Window/VBoxContainer/EmailInput"), PackedStringArray("Layout", "Layout/Container Sizing", "Theme Overrides", "Theme Overrides/styles", "theme_override_styles/normal"), NodePath("Window/VBoxContainer/Label2"), PackedStringArray("Layout", "Layout/Container Sizing", "Theme Overrides", "Theme Overrides/colors"), NodePath("Window/VBoxContainer/PasswordInput"), PackedStringArray("Layout", "Layout/Container Sizing", "Theme Overrides", "Theme Overrides/styles", "theme_override_styles/normal"), NodePath("Window/VBoxContainer/LogInButton"), PackedStringArray("Layout", "Layout/Container Sizing", "Theme Overrides", "Theme Overrides/styles", "theme_override_styles/normal")]
resource_unfolds=["res://scenes/configuration.tscn::StyleBoxFlat_kporg", PackedStringArray(), "res://scenes/configuration.tscn::StyleBoxFlat_etp6l", PackedStringArray(), "res://scenes/configuration.tscn::StyleBoxFlat_sb302", PackedStringArray(), "res://scenes/configuration.tscn::StyleBoxFlat_hc4xr", PackedStringArray(), "res://scenes/configuration.tscn::StyleBoxFlat_7wcdq", PackedStringArray(), "res://scenes/configuration.tscn::StyleBoxFlat_lditi", PackedStringArray()]
nodes_folded=[NodePath("MarginContainer"), NodePath("MarginContainer/VBoxContainer"), NodePath("Warning"), NodePath("Window")]

View File

@ -1,63 +0,0 @@
[docks]
dock_3_selected_tab_idx=0
dock_4_selected_tab_idx=0
dock_5_selected_tab_idx=0
dock_floating={}
dock_filesystem_h_split_offset=240
dock_filesystem_v_split_offset=0
dock_filesystem_display_mode=0
dock_filesystem_file_sort=0
dock_filesystem_file_list_display_mode=1
dock_filesystem_selected_paths=PackedStringArray("res://audio/wolf.mp3")
dock_filesystem_uncollapsed_paths=PackedStringArray("Favorites", "res://", "res://audio/")
dock_node_current_tab=0
dock_history_include_scene=true
dock_history_include_global=true
dock_bottom=[]
dock_closed=[]
dock_split_2=0
dock_split_3=0
dock_hsplit_1=0
dock_hsplit_2=270
dock_hsplit_3=-270
dock_hsplit_4=0
dock_3="Scene,Import"
dock_4="FileSystem"
dock_5="Inspector,Node,History"
[EditorNode]
open_scenes=PackedStringArray("res://scenes/game.tscn", "res://scenes/configuration.tscn")
current_scene="res://scenes/game.tscn"
center_split_offset=0
selected_default_debugger_tab_idx=0
selected_main_editor_idx=2
selected_bottom_panel_item=0
[EditorWindow]
screen=0
mode="maximized"
position=Vector2i(0, 23)
[ScriptEditor]
open_scripts=["res://scripts/configuration.gd", "res://scripts/game.gd", "res://scripts/game_data.gd", "res://scripts/screen_manager.gd"]
selected_script="res://scripts/game.gd"
open_help=[]
script_split_offset=200
list_split_offset=0
zoom_factor=1.0
[GameView]
floating_window_rect=Rect2i(0, 0, 1932, 1127)
floating_window_screen=0
[ShaderEditor]
open_shaders=[]
split_offset=200
selected_shader=""
text_shader_zoom_factor=1.0

View File

@ -1,27 +0,0 @@
ea4bc82a6ad023ab7ee23ee620429895
::res://::1745432009
icon.svg::CompressedTexture2D/CompressedTexture2D::5044074093411398912::1744633584::1744633593::1::::<><><>0<>0<>f9adb246a70a7d9e0b44b9e0dce472bb<>res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex::
::res://audio/::1745432009
asno.mp3::AudioStreamMP3::5781012165743321088::1745431872::1745432009::1::::<><><>0<>0<>04849c7d6b682c88a72746e86174f73b<>res://.godot/imported/asno.mp3-c8f31127f4b178b8b2b8415bad169e07.mp3str::
caballo.mp3::AudioStreamMP3/AudioStreamMP3::4827901584278378597::1745431804::1745431804::1::::<><><>0<>0<>6e43501dc2941926b422a069a37c5b89<>res://.godot/imported/caballo.mp3-7b2055e87f29328701251f905f0ed53e.mp3str::
cuervo.mp3::AudioStreamMP3/AudioStreamMP3::4812865155172360579::1745431882::1745431965::1::::<><><>0<>0<>18f7a5517aeb2c4811e41ee28fbdbcbb<>res://.godot/imported/cuervo.mp3-699bfa229f8863609609060333d7eb09.mp3str::
Elefant.mp3::AudioStreamMP3/AudioStreamMP3::1108392689846586874::1744635741::1744635741::1::::<><><>0<>0<>009805eb2c7d9c7cd23bd1fcf3eb7bf8<>res://.godot/imported/Elefant.mp3-e3e5c8488a65256c22d6f79b59243fe7.mp3str::
gallo.mp3::AudioStreamMP3/AudioStreamMP3::2685061553279347517::1745431722::1745431729::1::::<><><>0<>0<>e12bc0d6db956a381fb428c74ffa81da<>res://.godot/imported/gallo.mp3-1271e286f267d5e31c477f20fe593d30.mp3str::
gato.mp3::AudioStreamMP3/AudioStreamMP3::5660098724051234660::1745431771::1745431930::1::::<><><>0<>0<>c8f2a66613b407ab6ee342c4cf2b03b7<>res://.godot/imported/gato.mp3-c61b66ed22aa208d5f0638a947cee007.mp3str::
gaviota.mp3::AudioStreamMP3/AudioStreamMP3::6630534147415936020::1745431879::1745431925::1::::<><><>0<>0<>1d8f8d40adc742a900f128a403114939<>res://.godot/imported/gaviota.mp3-b98dceded202a98d930f5d8b44e91302.mp3str::
oveja.mp3::AudioStreamMP3/AudioStreamMP3::6892221899961415453::1745431841::1745431936::1::::<><><>0<>0<>6b9875df10bf634bc5185ea4479c2ce1<>res://.godot/imported/oveja.mp3-548c0afa06640f39be929ba57d20c25d.mp3str::
perro.mp3::AudioStreamMP3/AudioStreamMP3::2363096142831056952::1745431668::1745431676::1::::<><><>0<>0<>6c8a300409787c83d6c5fda9997fc150<>res://.godot/imported/perro.mp3-70940168b9c50fc40928609c0024fb67.mp3str::
vaca.mp3::AudioStreamMP3/AudioStreamMP3::2596745121890943594::1745431616::1745431617::1::::<><><>0<>0<>dc233f99ee2d0d4acfba4fac41e69ab3<>res://.godot/imported/vaca.mp3-6fdbb0ce8242846d3ac977450b7ac193.mp3str::
wolf.mp3::AudioStreamMP3/AudioStreamMP3::4476753813126878356::1745431572::1745431573::1::::<><><>0<>0<>fe6fb338f4476d030d4e8e5517df5fa5<>res://.godot/imported/wolf.mp3-5b3e376d644832f42cc7647c484fe190.mp3str::
::res://images/::1745428753
background.png::CompressedTexture2D/CompressedTexture2D::6822232804109568982::1745428752::1745428753::1::::<><><>0<>0<>5a780c38dac7e0dc6cc39dd8f5632c97<>res://.godot/imported/background.png-23e4ff24ed3606e496e606d42ded004c.ctex::
Fondo.png::CompressedTexture2D/CompressedTexture2D::6448476263866600585::1745260713::1745260728::1::::<><><>0<>0<>a5e23edebe29509b5d3e01644f8185aa<>res://.godot/imported/Fondo.png-ba7036b5421ed7e1312c2cbc3c746cc2.ctex::
menu_logo.png::CompressedTexture2D/CompressedTexture2D::5689433748730304837::1745260946::1745260946::1::::<><><>0<>0<>aa8e65da18c85d772f423418a1d50520<>res://.godot/imported/menu_logo.png-326be22817043ae765a9aaa1fb96c9c5.ctex::
::res://scenes/::1745431061
configuration.tscn::PackedScene/PackedScene::1018116344755398623::1745431061::0::1::::<><><>0<>0<><>::uid://e41ws6j00o5::::res://scripts/configuration.gd
game.tscn::PackedScene/PackedScene::6874229073676243903::1745431061::0::1::::<><><>0<>0<><>::uid://dhqnf0xm2mwwm::::res://scripts/game.gd<>uid://c4g0gbifdm5fe::::res://images/background.png<>uid://cncae337c0ws8::::res://images/menu_logo.png
::res://scripts/::1745431061
configuration.gd::GDScript/GDScript::10065919189713686::1745414906::0::1::::<>Control<><>0<>0<><>::
game.gd::GDScript/GDScript::7684413599682033952::1745431061::0::1::::<>Control<><>0<>0<><>::
game_data.gd::GDScript/GDScript::3070763797095879381::1745431026::0::1::::<>Node<><>0<>0<><>::
screen_manager.gd::GDScript/GDScript::1421320781459715397::1744728053::0::1::::<>Node<><>0<>0<><>::

View File

@ -1,4 +0,0 @@
res://scenes/game.tscn
res://scenes/configuration.tscn
res://scripts/game_data.gd
res://scripts/game.gd

View File

@ -1,5 +0,0 @@
[folding]
node_unfolds=[]
resource_unfolds=[]
nodes_folded=[]

View File

@ -1,5 +0,0 @@
[folding]
node_unfolds=[NodePath("."), PackedStringArray("Layout"), NodePath("TextureRect"), PackedStringArray("Layout", "Layout/Transform", "Layout/Container Sizing"), NodePath("CenterContainer"), PackedStringArray("Layout"), NodePath("CenterContainer/VBoxContainer"), PackedStringArray("Layout", "Layout/Transform", "Layout/Container Sizing", "Layout/Grow Direction", "Layout/Anchor Points", "Layout/Anchor Offsets"), NodePath("CenterContainer/VBoxContainer/NextSoundButton"), PackedStringArray("Layout", "Theme Overrides/font_sizes", "Theme Overrides", "Theme Overrides/styles", "theme_override_styles/normal", "Layout/Container Sizing", "theme_override_styles/pressed", "Focus"), NodePath("CenterContainer/VBoxContainer/HBoxContainer"), PackedStringArray("Layout", "Layout/Container Sizing"), NodePath("CenterContainer/VBoxContainer/HBoxContainer/RepeatSoundButton"), PackedStringArray("Layout", "Layout/Container Sizing", "theme_override_styles/normal", "Theme Overrides/font_sizes", "Focus"), NodePath("CenterContainer/VBoxContainer/HBoxContainer/EndOfGameButton"), PackedStringArray("Layout", "Layout/Container Sizing", "Theme Overrides", "Theme Overrides/styles", "Theme Overrides/font_sizes", "theme_override_styles/normal", "Focus"), NodePath("WinnerSelector"), PackedStringArray("Theme Overrides", "theme_override_styles/embedded_unfocused_border", "theme_override_styles/embedded_border"), NodePath("WinnerSelector/ColorRect"), PackedStringArray("Layout"), NodePath("WinnerSelector/VBoxContainer"), PackedStringArray("Layout", "Layout/Container Sizing", "Theme Overrides", "Theme Overrides/constants", "Layout/Transform"), NodePath("WinnerSelector/VBoxContainer/Label"), PackedStringArray("Layout/Container Sizing", "Theme Overrides", "Theme Overrides/colors", "Layout"), NodePath("WinnerSelector/VBoxContainer/MenuPlayers"), PackedStringArray("Layout", "Layout/Container Sizing", "Theme Overrides", "Theme Overrides/styles", "theme_override_styles/normal", "Theme Overrides/colors"), NodePath("WinnerSelector/VBoxContainer/Button"), PackedStringArray("Layout", "Layout/Container Sizing", "Theme Overrides", "Theme Overrides/styles", "theme_override_styles/normal"), NodePath("Bloqueador"), PackedStringArray("Layout", "Layout/Transform"), NodePath("ExitButtonWindow/ColorRect"), PackedStringArray("Layout", "Layout/Container Sizing"), NodePath("ExitButtonWindow/VBoxContainer"), PackedStringArray("Layout", "Theme Overrides", "Theme Overrides/constants"), NodePath("ExitButtonWindow/VBoxContainer/Label"), PackedStringArray("Theme Overrides", "Theme Overrides/colors", "Theme Overrides/font_sizes"), NodePath("ExitButtonWindow/VBoxContainer/HBoxContainer/ConfirmExitButton"), PackedStringArray("Layout", "Layout/Container Sizing", "Theme Overrides", "Theme Overrides/styles", "theme_override_styles/normal"), NodePath("ExitButtonWindow/VBoxContainer/HBoxContainer/CancelExitButton"), PackedStringArray("Layout", "Layout/Container Sizing", "Theme Overrides", "Theme Overrides/styles", "theme_override_styles/normal")]
resource_unfolds=["res://scenes/game.tscn::StyleBoxFlat_0tnpc", PackedStringArray("Border", "Corner Radius"), "res://scenes/game.tscn::StyleBoxFlat_yqjtg", PackedStringArray("Corner Radius", "Border", "Border Width"), "res://scenes/game.tscn::StyleBoxFlat_lnu2h", PackedStringArray("Corner Radius", "Border", "Border Width"), "res://scenes/game.tscn::StyleBoxFlat_lbhrr", PackedStringArray("Corner Radius", "Border", "Border Width"), "res://scenes/game.tscn::StyleBoxFlat_iywne", PackedStringArray(), "res://scenes/game.tscn::StyleBoxFlat_p57ef", PackedStringArray(), "res://scenes/game.tscn::StyleBoxFlat_u5sy4", PackedStringArray(), "res://scenes/game.tscn::StyleBoxFlat_gee14", PackedStringArray()]
nodes_folded=[NodePath("WinnerSelector"), NodePath("WinnerSelector/VBoxContainer"), NodePath("ExitButtonWindow"), NodePath("ExitButtonWindow/VBoxContainer"), NodePath("ExitButtonWindow/VBoxContainer/HBoxContainer")]

View File

@ -1,27 +0,0 @@
[editor_metadata]
executable_path="C:/Users/moran/Downloads/Godot_v4.4.1-stable_win64.exe/Godot_v4.4.1-stable_win64.exe"
use_advanced_connections=false
[dialog_bounds]
project_settings=Rect2(360, 190, 1200, 700)
create_new_node=Rect2(510, 190, 900, 700)
[script_setup]
last_selected_language="GDScript"
[recent_files]
scripts=["res://scripts/game_data.gd", "res://scripts/screen_manager.gd", "res://scenes/configuration.gd", "res://game.gd"]
scenes=["res://scenes/configuration.tscn", "res://scenes/game.tscn", "res://game.tscn"]
[color_picker]
picker_shape=3
recent_presets=PackedColorArray(0.588235, 0.654902, 0.686275, 1, 0.588235, 0.654902, 0.686275, 1, 0.8, 0.8, 0.8, 1, 0.196078, 0.309804, 0.368627, 1, 0.0156863, 0.8, 0.8, 1, 0.0156863, 0.247059, 0.8, 1, 0.92549, 0.376471, 0.615686, 1, 0.92549, 0.376471, 0.615686, 0.788235, 0, 0, 0, 1)
[quick_open_dialog]
last_mode=1

View File

@ -1,2 +0,0 @@
res://scripts
res://

View File

@ -1,55 +0,0 @@
[res://scripts/game.gd]
state={
"bookmarks": PackedInt32Array(),
"breakpoints": PackedInt32Array(),
"column": 0,
"folded_lines": Array[int]([]),
"h_scroll_position": 0,
"row": 11,
"scroll_position": 0.0,
"selection": false,
"syntax_highlighter": "GDScript"
}
[res://scripts/configuration.gd]
state={
"bookmarks": PackedInt32Array(),
"breakpoints": PackedInt32Array(),
"column": 35,
"folded_lines": Array[int]([]),
"h_scroll_position": 0,
"row": 98,
"scroll_position": 0.0,
"selection": false,
"syntax_highlighter": "GDScript"
}
[res://scripts/screen_manager.gd]
state={
"bookmarks": PackedInt32Array(),
"breakpoints": PackedInt32Array(),
"column": 0,
"folded_lines": Array[int]([]),
"h_scroll_position": 0,
"row": 22,
"scroll_position": 0.0,
"selection": false,
"syntax_highlighter": "GDScript"
}
[res://scripts/game_data.gd]
state={
"bookmarks": PackedInt32Array(),
"breakpoints": PackedInt32Array(),
"column": 25,
"folded_lines": Array[int]([]),
"h_scroll_position": 0,
"row": 65,
"scroll_position": 49.0,
"selection": false,
"syntax_highlighter": "GDScript"
}

View File

@ -1 +0,0 @@
list=[]

View File

@ -1,3 +0,0 @@
source_md5="d0a2e8efb08934c125002ca2342b0b1b"
dest_md5="5eac8ba711953b444769459c636fa80b"

View File

@ -1,3 +0,0 @@
source_md5="78687f61f7636839a990dd7241418511"
dest_md5="31495e9ef1c8480db9407b663c9641c9"

View File

@ -1,3 +0,0 @@
source_md5="b7ed27b8733ac3938ea97b6f62f03fe2"
dest_md5="078c2aa3879e5d8fb05a4a95d08f28cb"

View File

@ -1,3 +0,0 @@
source_md5="075ad337ca02a6bc710d719cbd92152d"
dest_md5="b4db58192c0182707fd3e8d35c0876fc"

View File

@ -1,3 +0,0 @@
source_md5="075ad337ca02a6bc710d719cbd92152d"
dest_md5="b4db58192c0182707fd3e8d35c0876fc"

View File

@ -1,3 +0,0 @@
source_md5="8dbbd7f9330263827d347335fd9dad42"
dest_md5="5eb839a7b20831690790941de63c628e"

View File

@ -1,3 +0,0 @@
source_md5="74669865a41a88e37013718177f1f241"
dest_md5="0801e44c630f05fe51ab6cb331943b60"

View File

@ -1,3 +0,0 @@
source_md5="13fa9399ff066d872ef7b61ab16b2e73"
dest_md5="3bf30b72728e17e5b7b4f06796930ccd"

View File

@ -1,3 +0,0 @@
source_md5="d5bfa1139ddeff9aa03f46281442a4c0"
dest_md5="7cb96bbbcffc716ecb3f9ec84e6f9752"

Some files were not shown because too many files have changed in this diff Show More