diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/interfaces/IOChangeFragmentListener.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/interfaces/IOChangeFragmentListener.java deleted file mode 100644 index 41ca876..0000000 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/interfaces/IOChangeFragmentListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.andresgmoran.apptrabajadores.interfaces; - -public interface IOChangeFragmentListener { - void changeFragment(String fragmentName); -} diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/interfaces/IOClickOnAddParticipantListener.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/interfaces/IOClickOnAddParticipantListener.java index f5a7ba6..03f9d47 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/interfaces/IOClickOnAddParticipantListener.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/interfaces/IOClickOnAddParticipantListener.java @@ -7,5 +7,5 @@ import com.andresgmoran.apptrabajadores.models.Resident; import java.util.List; public interface IOClickOnAddParticipantListener { - void onClickOnAddParticipant(Activity activity, List participants , List residents); + void onClickOnAddParticipant(Activity activity, List participants ); } diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/models/Residence.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/models/Residence.java new file mode 100644 index 0000000..ce84e46 --- /dev/null +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/models/Residence.java @@ -0,0 +1,52 @@ +package com.andresgmoran.apptrabajadores.models; + +import java.util.List; +import java.util.Objects; + +public class Residence { + private final Long id; + private final String name; + private final String email; + private final List users; + private final List residents; + + public Residence(Long id, String name, String email, List users, List residents) { + this.id = id; + this.name = name; + this.email = email; + this.users = users; + this.residents = residents; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getEmail() { + return email; + } + + public List getUsers() { + return users; + } + + public List getResidents() { + return residents; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + Residence residence = (Residence) o; + return Objects.equals(id, residence.id) && Objects.equals(name, residence.name) && Objects.equals(email, residence.email) && Objects.equals(users, residence.users) && Objects.equals(residents, residence.residents); + } + + @Override + public int hashCode() { + return Objects.hash(id, name, email, users, residents); + } +} diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/models/Resident.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/models/Resident.java index d594785..77e3bc9 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/models/Resident.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/models/Resident.java @@ -11,15 +11,21 @@ public class Resident implements Serializable { private final String surnames; private final LocalDate birthDate; private final String identityCard; + private final String family1; + private final String family2; private final Long residenceId; + private final boolean isTakenDown; - public Resident(Long id, String name, String surnames, LocalDate birthDate, String identityCard , Long residenceId) { + public Resident(Long id, String name, String surnames, LocalDate birthDate, String identityCard, String family1, String family2, Long residenceId, boolean isTakenDown) { this.id = id; this.name = name; this.surnames = surnames; this.birthDate = birthDate; this.identityCard = identityCard; + this.family1 = family1; + this.family2 = family2; this.residenceId = residenceId; + this.isTakenDown = isTakenDown; } public Long getId() { diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/models/adapters/ActivitiesAdapter.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/models/adapters/ActivitiesAdapter.java index 2859362..2da3c1c 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/models/adapters/ActivitiesAdapter.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/models/adapters/ActivitiesAdapter.java @@ -23,8 +23,10 @@ import com.andresgmoran.apptrabajadores.models.ActivityResident; import com.andresgmoran.apptrabajadores.models.ActivityState; import com.andresgmoran.apptrabajadores.models.Game; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; +import java.util.Locale; public class ActivitiesAdapter extends RecyclerView.Adapter { @@ -49,6 +51,12 @@ public class ActivitiesAdapter extends RecyclerView.Adapter newActivities, List newParticipants) { + this.activities = newActivities; + this.participants = newParticipants; + notifyDataSetChanged(); + } + @Override public void onBindViewHolder(@NonNull ActivitiesViewHolder holder, int position) { Activity activity = activities.get(position); @@ -63,12 +71,12 @@ public class ActivitiesAdapter extends RecyclerView.Adapter { 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) -> { + .setTitle(context.getString(R.string.close_activity_title)) + .setMessage(context.getString(R.string.close_activity_message)) + .setPositiveButton(context.getString(R.string.accept_text), (dialog, which) -> { changeStateListener.onChangeStateActivity(activity, ActivityState.CERRADO); }) - .setNegativeButton("Cancelar", (dialog, which) -> { + .setNegativeButton(context.getString(R.string.cancel_text), (dialog, which) -> { dialog.dismiss(); }) .show(); @@ -108,6 +116,7 @@ public class ActivitiesAdapter extends RecyclerView.Adapter{ +public class GamesAdapter extends RecyclerView.Adapter { private List games; private final IOClickOnGameListener listener; + private final Map weeklyPercentages; - public GamesAdapter(List games, IOClickOnGameListener listener) { + public GamesAdapter(List games, IOClickOnGameListener listener, Map weeklyPercentages) { this.games = games; this.listener = listener; + this.weeklyPercentages = weeklyPercentages; } public void updateData(List newGames) { @@ -31,22 +34,17 @@ public class GamesAdapter extends RecyclerView.Adapter listener.onClickOnGame(game)); } public int getItemCount() { @@ -54,15 +52,15 @@ public class GamesAdapter extends RecyclerView.Adapter newGameStats) { + this.gameStats.clear(); + this.gameStats.addAll(newGameStats); + notifyDataSetChanged(); + } + @NonNull @Override public LastGamesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -155,12 +161,13 @@ public class LastGamesAdapter extends RecyclerView.Adapter { @@ -26,7 +27,7 @@ public class ResidentsAdapter extends RecyclerView.Adapter newResidents) { - this.residents = newResidents; // O la lista que uses internamente + this.residents = newResidents; notifyDataSetChanged(); } @@ -73,17 +74,20 @@ public class ResidentsAdapter extends RecyclerView.Adapter usuarios = new ArrayList<>(); + if (obj.has("usuarios") && !obj.isNull("usuarios")) { + JSONArray usuariosArray = obj.getJSONArray("usuarios"); + for (int i = 0; i < usuariosArray.length(); i++) { + usuarios.add(usuariosArray.getLong(i)); + } + } + + List residentes = new ArrayList<>(); + if (obj.has("residentes") && !obj.isNull("residentes")) { + JSONArray residentesArray = obj.getJSONArray("residentes"); + for (int i = 0; i < residentesArray.length(); i++) { + residentes.add(residentesArray.getLong(i)); + } + } + + return new Residence(id, nombre, email, usuarios, residentes); + + } catch (JSONException e) { + throw new ParserException("Error al parsear residencia: " + e.getMessage(), e); + } + } +} diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/models/parsers/ResidentParser.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/models/parsers/ResidentParser.java index c6576bd..67bb5cc 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/models/parsers/ResidentParser.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/models/parsers/ResidentParser.java @@ -32,9 +32,14 @@ public class ResidentParser { String identityCard = obj.getString("documentoIdentidad"); + String family1 = obj.optString("familiar1", null); + String family2 = obj.optString("familiar2", null); + Long residenceId = obj.getLong("idResidencia"); - residents.add(new Resident(id, name, surnames, birthDate, identityCard, residenceId)); + boolean isTakenDown = obj.optBoolean("baja", false); + + residents.add(new Resident(id, name, surnames, birthDate, identityCard, family1, family2, residenceId, isTakenDown)); } } catch (JSONException | IllegalArgumentException e) { throw new ParserException("Error al parsear residentes", e); diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/network/ApiClient.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/network/ApiClient.java index 8e3d6d0..b81b5a9 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/network/ApiClient.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/network/ApiClient.java @@ -18,6 +18,7 @@ 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 { @@ -27,7 +28,10 @@ public class ApiClient { // Endpoints private static final String ENDPOINT_GET_USERS = "/resi/user/getAll"; private static final String ENDPOINT_GET_ME = "/resi/user/me"; + private static final String ENDPOINT_RESIDENCE = "/resi/get"; private static final String ENDPOINT_GET_RESIDENTS = "/resi/resident/getAll"; + private static final String ENDPOINT_GET_RESIDENTS_TAKEN_OUT = "/resi/resident/getAll/bajas"; + private static final String ENDPOINT_ADD_RESIDENT = "/resi/resident/add"; private static final String ENDPOINT_GET_GAMES = "/resi/juego/getAll"; private static final String ENDPOINT_GET_STATS = "/resi/registro/getAll"; private static final String ENDPOINT_GET_ACTIVITIES = "/resi/evento/getAll"; @@ -40,6 +44,8 @@ public class ApiClient { private static final String ENDPOINT_ACTIVITY_PARTICIPANTS = "/resi/evento/%d/participante/getAll"; private static final String ENDPOINT_ADD_PARTICIPANT = "/resi/evento/%d/participante/add"; private static final String ENDPOINT_UPDATE_PARTICIPANT = "/resi/evento/%d/participante/%d/update"; + private static final String ENDPOINT_ALLOW_PARTICIPANT = "/resi/evento/%d/participante/%d/allow"; + private static final String ENDPOINT_DENY_PARTICIPANT = "/resi/evento/%d/participante/%d/deny"; private static final String ENDPOINT_TAKE_OUT_RESIDENT = "/resi/resident/%d/baja"; public interface RawCallback { @@ -60,9 +66,16 @@ public class ApiClient { makeGetRequest(context, ENDPOINT_GET_ME, callback); } + public static void getResidence( Context context, RawCallback callback) { + makeGetRequest(context, ENDPOINT_RESIDENCE, callback); + } + public static void getResidents(Context context, RawCallback callback) { makeGetRequest(context, ENDPOINT_GET_RESIDENTS, callback); } + public static void getResidentsTakenOut(Context context, RawCallback callback) { + makeGetRequest(context, ENDPOINT_GET_RESIDENTS_TAKEN_OUT , callback); + } public static void getGames(Context context, RawCallback callback) { makeGetRequest(context, ENDPOINT_GET_GAMES, callback); @@ -85,6 +98,16 @@ public class ApiClient { makePostRequest(null, ENDPOINT_LOGIN, jsonBody, callback); } + public static void postResident(Context context, String nombre, String apellido, LocalDate fechaNacimiento, + String documentoIdentidad, String familiar1, String familiar2, int year, int month, + RawCallback callback) { + String jsonBody = String.format( + "{\"nombre\":\"%s\", \"apellido\":\"%s\", \"fechaNacimiento\":\"%s\", \"documentoIdentidad\":\"%s\", " + + "\"familiar1\":\"%s\", \"familiar2\":\"%s\", \"year\":%d, \"month\":%d}", + nombre, apellido, fechaNacimiento.toString(), documentoIdentidad, familiar1, familiar2, year, month); + makePostRequest(context, ENDPOINT_ADD_RESIDENT, jsonBody, 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); @@ -113,6 +136,12 @@ public class ApiClient { String jsonBody, RawCallback callback) { makePatchRequest(context, String.format(ENDPOINT_UPDATE_PARTICIPANT, idActivity, idParticipant), jsonBody, callback); } + public static void allowParticipant(Context context, long idActivity, long idParticipant, RawCallback callback) { + makePostRequest(context, String.format(ENDPOINT_ALLOW_PARTICIPANT, idActivity, idParticipant), "", callback); + } + public static void denyParticipant(Context context, long idActivity, long idParticipant, RawCallback callback) { + makePostRequest(context, String.format(ENDPOINT_DENY_PARTICIPANT, idActivity, idParticipant), "" ,callback); + } public static void patchTakeOutResident(Context context, long idResident, RawCallback callback) { makePatchRequest(context, String.format(ENDPOINT_TAKE_OUT_RESIDENT, idResident), "", callback); diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/repository/AppDataRepository.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/repository/AppDataRepository.java index f2e020d..0135a30 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/repository/AppDataRepository.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/repository/AppDataRepository.java @@ -1,13 +1,18 @@ package com.andresgmoran.apptrabajadores.repository; import android.content.Context; +import android.content.SharedPreferences; import android.graphics.Bitmap; import android.util.Log; +import android.widget.Toast; +import com.andresgmoran.apptrabajadores.R; +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 com.andresgmoran.apptrabajadores.models.Game; +import com.andresgmoran.apptrabajadores.models.Residence; import com.andresgmoran.apptrabajadores.models.Resident; import com.andresgmoran.apptrabajadores.models.User; import com.andresgmoran.apptrabajadores.models.gameStats.GameStat; @@ -15,10 +20,16 @@ import com.andresgmoran.apptrabajadores.models.parsers.ActivityParser; import com.andresgmoran.apptrabajadores.models.parsers.ActivityResidentParser; import com.andresgmoran.apptrabajadores.models.parsers.GameParser; import com.andresgmoran.apptrabajadores.models.parsers.GameStatParser; +import com.andresgmoran.apptrabajadores.models.parsers.ResidenceParser; import com.andresgmoran.apptrabajadores.models.parsers.ResidentParser; import com.andresgmoran.apptrabajadores.models.parsers.UserParser; import com.andresgmoran.apptrabajadores.network.ApiClient; +import com.andresgmoran.apptrabajadores.ui.MainActivity; +import com.andresgmoran.apptrabajadores.utils.SecurePreferencesUtil; +import org.json.JSONObject; + +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -30,7 +41,9 @@ public class AppDataRepository { private User actualUser; private Bitmap actualUserImage; private List users = new ArrayList<>(); + private Residence residence = null; private List residents = new ArrayList<>(); + private List residentsTakenOut = new ArrayList<>(); private List games = new ArrayList<>(); private List gameStats = new ArrayList<>(); private List activities = new ArrayList<>(); @@ -52,9 +65,15 @@ public class AppDataRepository { public List getUsers() { return users; } public void setUsers(List list) { this.users = new ArrayList<>(list); } + public Residence getResidence() { return residence; } + public void setResidence(Residence residence) { this.residence = residence; } + public List getResidents() { return residents; } public void setResidents(List list) { this.residents = new ArrayList<>(list); } + public List getResidentsTakenOut() { return residentsTakenOut; } + public void setResidentsTakenOut(List list) { this.residentsTakenOut = new ArrayList<>(list); } + public List getGames() { return games; } public void setGames(List list) { this.games = new ArrayList<>(list); } @@ -69,18 +88,23 @@ public class AppDataRepository { // -------------------- API Calls -------------------- - public void fetchActualUser(Context context, Runnable onFinish) { + public void fetchActualUser(Context context, Runnable onSuccess, Runnable onError) { ApiClient.getActualUser(context, new ApiClient.RawCallback() { @Override public void onSuccess(String jsonText) { - actualUser = UserParser.parseUser(jsonText); - fetchUserImage(context, actualUser.getAccountImage(), onFinish); + try { + actualUser = UserParser.parseUser(jsonText); + fetchUserImage(context, actualUser.getAccountImage(), onSuccess); + } catch (Exception e) { + Log.e("UserParser", "Error al parsear usuario: " + e.getMessage()); + onError.run(); + } } @Override public void onError(String error) { Log.e("API", "Error al obtener usuario: " + error); - onFinish.run(); + onError.run(); } }); } @@ -106,7 +130,7 @@ public class AppDataRepository { @Override public void onSuccess(String jsonText) { users = UserParser.parseUsers(jsonText); - fetchResidents(context, onFinish); + fetchResidence(context, onFinish); } @Override @@ -117,12 +141,28 @@ public class AppDataRepository { }); } + public void fetchResidence( Context context, Runnable onFinish) { + ApiClient.getResidence(context, new ApiClient.RawCallback() { + @Override + public void onSuccess(String jsonText) { + residence = ResidenceParser.parseResidence(jsonText); + fetchResidents(context, onFinish); + } + + @Override + public void onError(String error) { + Log.e("API", "Error al obtener residencia: " + error); + onFinish.run(); + } + }); + } + public void fetchResidents(Context context, Runnable onFinish) { ApiClient.getResidents(context, new ApiClient.RawCallback() { @Override public void onSuccess(String jsonText) { residents = ResidentParser.parseResidents(jsonText); - fetchGames(context, onFinish); + fetchResidentsTakenOut(context, onFinish); } @Override @@ -133,6 +173,22 @@ public class AppDataRepository { }); } + public void fetchResidentsTakenOut(Context context, Runnable onFinish) { + ApiClient.getResidentsTakenOut(context, new ApiClient.RawCallback() { + @Override + public void onSuccess(String jsonText) { + residentsTakenOut = ResidentParser.parseResidents(jsonText); + fetchGames(context, onFinish); + } + + @Override + public void onError(String error) { + Log.e("API", "Error al obtener residentes dados de baja: " + error); + onFinish.run(); + } + }); + } + public void fetchGames(Context context, Runnable onFinish) { ApiClient.getGames(context, new ApiClient.RawCallback() { @Override @@ -267,6 +323,22 @@ public class AppDataRepository { }); } + public void fetchResidenceOnly( Context context, Runnable onFinish) { + ApiClient.getResidence(context, new ApiClient.RawCallback() { + @Override + public void onSuccess(String jsonText) { + residence = ResidenceParser.parseResidence(jsonText); + onFinish.run(); + } + + @Override + public void onError(String error) { + Log.e("API", "Error al obtener residencia: " + error); + onFinish.run(); + } + }); + } + public void fetchResidentsOnly(Context context, Runnable onFinish) { ApiClient.getResidents(context, new ApiClient.RawCallback() { @Override @@ -283,6 +355,22 @@ public class AppDataRepository { }); } +public void fetchResidentsTakenOutOnly(Context context, Runnable onFinish) { + ApiClient.getResidentsTakenOut(context, new ApiClient.RawCallback() { + @Override + public void onSuccess(String jsonText) { + residentsTakenOut = ResidentParser.parseResidents(jsonText); + onFinish.run(); + } + + @Override + public void onError(String error) { + Log.e("API", "Error al obtener residentes dados de baja: " + error); + onFinish.run(); + } + }); + } + public void fetchGamesOnly(Context context, Runnable onFinish) { ApiClient.getGames(context, new ApiClient.RawCallback() { @Override @@ -331,17 +419,17 @@ public class AppDataRepository { }); } - public void fetchParticipantsOnly(Context context, List sourceActivities, Runnable onFinish) { + public void fetchParticipantsOnly(Context context, Runnable onSuccess) { activityResidents.clear(); - final int total = sourceActivities.size(); + final int total = activities.size(); final int[] completed = {0}; if (total == 0) { - onFinish.run(); + onSuccess.run(); return; } - for (Activity activity : sourceActivities) { + for (Activity activity : activities) { ApiClient.getAllParticipants(context, activity.getId(), new ApiClient.RawCallback() { @Override public void onSuccess(String jsonText) { @@ -362,7 +450,7 @@ public class AppDataRepository { synchronized (completed) { completed[0]++; if (completed[0] == total) { - onFinish.run(); + onSuccess.run(); } } } @@ -373,62 +461,236 @@ public class AppDataRepository { // -------------------- Otras acciones API -------------------- - public void addActivity(Context context, String nombre, String descripcion, LocalDateTime fecha, Runnable onSuccess, Runnable onError) { - ApiClient.postEvento(context, nombre, descripcion, fecha, new ApiClient.RawCallback() { + public void login(Context context, String email, String password, boolean rememberPassword, Runnable onSuccess, Runnable onError) { + ApiClient.postLogin(email, password, new ApiClient.RawCallback() { @Override public void onSuccess(String jsonText) { - fetchActivities(context, onSuccess); + try { + JSONObject json = new JSONObject(jsonText); + String token = json.getString("token"); + long expiresIn = json.getLong("expiresIn"); + long idResidence = json.getLong("idResidencia"); + long idUser = json.getLong("idUser"); + + long tokenExpiration = System.currentTimeMillis() + expiresIn; + + SharedPreferences.Editor editor = SecurePreferencesUtil.getEncryptedPrefs(context).edit(); + editor.putString("token", token); + editor.putLong("token_expiration", tokenExpiration); + editor.putBoolean("rememberPassword", rememberPassword); + editor.putLong("idResidence", idResidence); + editor.putLong("idUser", idUser); + + if (rememberPassword) { + editor.putString("email", email); + editor.putString("password", password); + } + + SecurePreferencesUtil.edit(context, editor); + + } catch (Exception e) { + throw new ParserException("Error al parsear respuesta de login: " + e.getMessage(), e); + } + Log.d("API", "Inicio de sesión exitoso"); + fetchActualUser(context, onSuccess, onError); } @Override public void onError(String error) { - Log.e("API", "Error al añadir actividad: " + error); + Log.e("API", "Error al iniciar sesión: " + error); onError.run(); } }); } - public void deleteGameStat(Context context, long id, Runnable onSuccess) { + public void addResident(Context context, String nombre, String apellido, LocalDate fechaNacimiento, String documentoIdentidad, String familiar1, String familiar2, int year, int month, Runnable onSuccess, Runnable onError) { + ApiClient.postResident(context, nombre, apellido, fechaNacimiento, documentoIdentidad, familiar1, familiar2, year, month, new ApiClient.RawCallback() { + @Override + public void onSuccess(String jsonText) { + fetchResidentsOnly(context, onSuccess); + } + + @Override + public void onError(String error) { + Log.e("API", "Error al añadir residente: " + error); + onError.run(); + } + }); + } + + + public void addActivity(Context context, String nombre, String descripcion, LocalDateTime fecha, Runnable onSuccess, Runnable onError) { + ApiClient.postEvento(context, nombre, descripcion, fecha, new ApiClient.RawCallback() { + @Override + public void onSuccess(String jsonText) { + fetchActivitiesOnly(context, onSuccess); + } + + @Override + public void onError(String error) { + onError.run(); + Log.e("API", "Error al añadir actividad: " + error); + } + }); + } + + public void deleteGameStat(Context context, long id, Runnable onSuccess, Runnable onError) { ApiClient.deleteGameStat(context, id, new ApiClient.RawCallback() { @Override public void onSuccess(String jsonText) { - fetchGameStats(context, onSuccess); + fetchGameStatsOnly(context, onSuccess); } @Override public void onError(String error) { + onError.run(); Log.e("API", "Error al borrar partida: " + error); - onSuccess.run(); // puede seguir aunque falle } }); } - public void updateObservation(Context context, String comment, long id, Runnable onSuccess) { + public void updateObservation(Context context, String comment, long id, Runnable onSuccess, Runnable onError) { ApiClient.patchObservation(context, comment, id, new ApiClient.RawCallback() { @Override public void onSuccess(String jsonText) { - fetchGameStats(context, onSuccess); + fetchGameStatsOnly(context, onSuccess); } @Override public void onError(String error) { + onError.run(); Log.e("API", "Error al actualizar observación: " + error); - onSuccess.run(); } }); } - public void changeActivityState(Context context, long id, ActivityState state, Runnable onSuccess) { + public void changeActivityState(Context context, long id, ActivityState state, Runnable onSuccess, Runnable onError) { ApiClient.patchActivityState(context, id, state, new ApiClient.RawCallback() { @Override public void onSuccess(String jsonText) { - fetchActivities(context, onSuccess); + fetchActivitiesOnly(context, onSuccess); } @Override public void onError(String error) { Log.e("API", "Error al cambiar estado: " + error); - onSuccess.run(); + onError.run(); + } + }); + } + + public void takeDownResident(Context context, long residentid, Runnable onSuccess, Runnable onError) { + ApiClient.patchTakeOutResident( context, residentid, new ApiClient.RawCallback() { + @Override + public void onSuccess(String jsonText) { + Log.d("API", "Residente dado de baja correctamente"); + fetchResidentsOnly(context, onSuccess); //TODO: Que llame a fetchResidentsTakenOutOnly también + } + + @Override + public void onError(String error) { + onError.run(); + Log.e("API", "Error al eliminar residente: " + error); + } + }); + } + + public void updateAssistance(Context context, long activityId, long participantId, boolean assistance, Runnable onSuccess, Runnable onError) { + if (assistance){ + ApiClient.allowParticipant( context, activityId, participantId , new ApiClient.RawCallback() { + @Override + public void onSuccess(String jsonText) { + fetchParticipantsOnly(context, onSuccess); + Log.d("API", "Asistencia actualizada correctamente"); + } + + @Override + public void onError(String error) { + onError.run(); + Log.e("API", "Error al actualizar asistencia: " + error); + } + }); + } else { + ApiClient.denyParticipant( context, activityId, participantId , new ApiClient.RawCallback() { + @Override + public void onSuccess(String jsonText) { + fetchParticipantsOnly(context, onSuccess); + Log.d("API", "Asistencia actualizada correctamente"); + } + + @Override + public void onError(String error) { + onError.run(); + Log.e("API", "Error al actualizar asistencia: " + error); + } + }); + } + } + public void updateOpinion(Context context, long activityId, long participantId, boolean isPreOpinion, String opinion, Runnable onSuccess, Runnable onError) { + String jsonBody = ""; + if (isPreOpinion) { + jsonBody = "{\"preOpinion\": \"" + opinion + "\"}"; + } else { + jsonBody = "{\"postOpinion\": \"" + opinion + "\"}"; + } + ApiClient.patchParticipant( context, activityId, participantId , jsonBody, new ApiClient.RawCallback() { + @Override + public void onSuccess(String jsonText) { + fetchParticipantsOnly(context, onSuccess); + Log.d("API", "Opinión actualizada correctamente"); + } + + @Override + public void onError(String error) { + onError.run(); + Log.e("API", "Error al actualizar opinión: " + error); + } + }); + } + public void updateMaterialHelp(Context context, long activityId, long participantId, boolean materialHelp, Runnable onSuccess, Runnable onError) { + String jsonBody = "{\"recursosMateriales\": " + materialHelp + "}"; + ApiClient.patchParticipant( context, activityId, participantId , jsonBody, new ApiClient.RawCallback() { + @Override + public void onSuccess(String jsonText) { + fetchParticipantsOnly(context, onSuccess); + Log.d("API", "Ayuda material actualizada correctamente"); + } + + @Override + public void onError(String error) { + onError.run(); + Log.e("API", "Error al actualizar ayuda material: " + error); + } + }); + } + public void updateHumanHelp(Context context, long activityId, long participantId, boolean humanHelp, Runnable onSuccess, Runnable onError) { + String jsonBody = "{\"recursosHumanos\": " + humanHelp + "}"; + ApiClient.patchParticipant( context, activityId, participantId , jsonBody, new ApiClient.RawCallback() { + @Override + public void onSuccess(String jsonText) { + fetchParticipantsOnly(context, onSuccess); + Log.d("API", "Ayuda humana actualizada correctamente"); + } + + @Override + public void onError(String error) { + onError.run(); + Log.e("API", "Error al actualizar ayuda humana: " + error); + } + }); + } + public void addParticipant(Context context, long activityId, long residentId, Runnable onSuccess, Runnable onError) { + ApiClient.postParticipant(context, residentId, false, false, "", "", activityId, new ApiClient.RawCallback() { + @Override + public void onSuccess(String jsonText) { + fetchParticipantsOnly(context, onSuccess); + Log.d("API", "Participante añadido correctamente"); + } + + @Override + public void onError(String error) { + onError.run(); + Log.e("API", "Error al añadir participante: " + error); } }); } diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/MainActivity.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/MainActivity.java index 1d33d2c..2a1eaa9 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/MainActivity.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/MainActivity.java @@ -1,22 +1,21 @@ package com.andresgmoran.apptrabajadores.ui; import android.content.SharedPreferences; -import android.graphics.Bitmap; import android.os.Bundle; import android.util.Log; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatDelegate; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; import androidx.fragment.app.Fragment; import com.andresgmoran.apptrabajadores.R; -import com.andresgmoran.apptrabajadores.exceptions.ParserException; -import com.andresgmoran.apptrabajadores.interfaces.IOChangeFragmentListener; import com.andresgmoran.apptrabajadores.interfaces.IOClickOnActivityListener; import com.andresgmoran.apptrabajadores.interfaces.IOClickOnAddParticipantListener; import com.andresgmoran.apptrabajadores.interfaces.IOClickOnGameListener; @@ -30,67 +29,79 @@ import com.andresgmoran.apptrabajadores.models.ActivityResident; import com.andresgmoran.apptrabajadores.models.ActivityState; import com.andresgmoran.apptrabajadores.models.Game; import com.andresgmoran.apptrabajadores.models.Resident; -import com.andresgmoran.apptrabajadores.models.User; import com.andresgmoran.apptrabajadores.models.gameStats.GameStat; -import com.andresgmoran.apptrabajadores.models.parsers.ActivityParser; -import com.andresgmoran.apptrabajadores.models.parsers.ActivityResidentParser; -import com.andresgmoran.apptrabajadores.models.parsers.GameParser; -import com.andresgmoran.apptrabajadores.models.parsers.GameStatParser; -import com.andresgmoran.apptrabajadores.models.parsers.ResidentParser; -import com.andresgmoran.apptrabajadores.models.parsers.UserParser; import com.andresgmoran.apptrabajadores.network.ApiClient; +import com.andresgmoran.apptrabajadores.repository.AppDataRepository; import com.andresgmoran.apptrabajadores.ui.fragments.account.AccountFragment; -import com.andresgmoran.apptrabajadores.ui.fragments.account.EditAccountFragment; import com.andresgmoran.apptrabajadores.ui.fragments.activities.ActivitiesFragment; import com.andresgmoran.apptrabajadores.ui.fragments.activities.ActivityDetailFragment; import com.andresgmoran.apptrabajadores.ui.fragments.activities.AddActivityFragment; import com.andresgmoran.apptrabajadores.ui.fragments.activities.OpinionFragment; +import com.andresgmoran.apptrabajadores.ui.fragments.activities.ParticipantDetailFragment; import com.andresgmoran.apptrabajadores.ui.fragments.activities.ParticipantSelectionDialogFragment; import com.andresgmoran.apptrabajadores.ui.fragments.authentication.LoginFragment; import com.andresgmoran.apptrabajadores.ui.fragments.game.GameFragment; import com.andresgmoran.apptrabajadores.ui.fragments.gameDetail.GameDetailFragment; import com.andresgmoran.apptrabajadores.ui.fragments.home.HomeFragment; +import com.andresgmoran.apptrabajadores.ui.fragments.residence.ResidenceDetailFragment; +import com.andresgmoran.apptrabajadores.ui.fragments.resident.AddResidentFragment; import com.andresgmoran.apptrabajadores.ui.fragments.resident.ResidentFragment; import com.andresgmoran.apptrabajadores.utils.SecurePreferencesUtil; import com.google.android.material.bottomnavigation.BottomNavigationView; import com.google.android.material.navigation.NavigationBarView; + +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; -import org.json.JSONObject; +import java.util.Locale; public class MainActivity extends AppCompatActivity implements - NavigationBarView.OnItemSelectedListener, IOChangeFragmentListener, IOnClickOnBackButtonListener, + NavigationBarView.OnItemSelectedListener, + IOnClickOnBackButtonListener, + HomeFragment.IOnRefreshHomeListener, HomeFragment.IOnClickOnAddParticipantListener, LoginFragment.OnLoginListener, - HomeFragment.IOnAttachListener, - IOClickOnResidentListener, - IOClickOnGameListener, IOClickOnGameStatsListener, GameDetailFragment.IOnAddObservationListener, - IOClickOnActivityListener, AddActivityFragment.IOnAddActivity, IOnChageStateActivityListener, ActivitiesFragment.IOOnAttachListener, ActivityDetailFragment.IOOnAttachListener, - IOClickOnParticipantListener, IOClickOnAddParticipantListener, ParticipantSelectionDialogFragment.OnParticipantSelectedListener, + IOClickOnResidentListener, AddResidentFragment.OnAddResidentListener, ResidentFragment.IOnRefreshResidentListener, + IOClickOnGameListener, GameFragment.IOnRefreshGameListener, + IOClickOnGameStatsListener, GameDetailFragment.IOnAddObservationListener, GameDetailFragment.IOnRefreshGameStatsListener, + IOClickOnActivityListener, AddActivityFragment.IOnAddActivity, IOnChageStateActivityListener, ActivityDetailFragment.OnRefreshActivityDetailListener, ActivitiesFragment.IOnActivities, + IOClickOnParticipantListener, IOClickOnAddParticipantListener, ParticipantSelectionDialogFragment.OnParticipantSelectedListener, ParticipantDetailFragment.IOnRefreshParticipantDetailListener, OpinionFragment.OnAddOpinionListener, - AccountFragment.IOAccountFragmentListener { + AccountFragment.IOAccountFragmentListener, + ResidenceDetailFragment.IOnRefreshResidenceDetailListener{ private Fragment lastFragment = null; - private User actualUser; - private Bitmap actualUserImage; - private List users = new ArrayList<>(); - private List residents = new ArrayList<>(); - private List games = new ArrayList<>(); - private List gameStats = new ArrayList<>(); - private List activities = new ArrayList<>(); - private List activityResidents = new ArrayList<>(); - @Override protected void onCreate(Bundle savedInstanceState) { + String language = SecurePreferencesUtil.getString(this, "language", "es"); + Locale locale = new Locale(language); + Locale.setDefault(locale); + android.content.res.Configuration config = new android.content.res.Configuration(); + config.setLocale(locale); + getBaseContext().getResources().updateConfiguration( + config, + getBaseContext().getResources().getDisplayMetrics() + ); + + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); + super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - // Adaptar diseño a la pantalla + // Adaptar diseño a la pantalla pudiendo cambiar el color del padding top desde los fragments que sean necesarios View rootView = findViewById(R.id.fcvMain); + View statusBarView = findViewById(R.id.status_bar_background); + ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); - v.setPadding(0, systemBars.top, 0,0); + + v.setPadding(0, systemBars.top, 0, 0); + + ViewGroup.LayoutParams params = statusBarView.getLayoutParams(); + params.height = systemBars.top; + statusBarView.setLayoutParams(params); + return insets; }); @@ -102,7 +113,22 @@ public class MainActivity extends AppCompatActivity implements if (rememberPassword) { if (token != null && System.currentTimeMillis() < expiration) { - getActualUserFromAPI(); + ProgressBar loader = findViewById(R.id.progress_loader); + loader.setVisibility(View.VISIBLE); + + AppDataRepository.getInstance().fetchActualUser(this, () -> { + runOnUiThread(() -> { + loadFragment(createHomeFragment()); + findViewById(R.id.nav_view).setVisibility(View.VISIBLE); + loader.setVisibility(View.GONE); + }); + }, () -> { + runOnUiThread(() -> { + Toast.makeText(MainActivity.this, "Error al cargar usuario", Toast.LENGTH_SHORT).show(); + findViewById(R.id.progress_loader).setVisibility(View.GONE); + loadFragment(new LoginFragment()); + }); + }); } else { Log.i( "AUTH", "Token no válido o expirado, intentando login automático"); // Token expirado: intentar login automático @@ -129,8 +155,6 @@ public class MainActivity extends AppCompatActivity implements } @Override - -// --------------------------------------------------------------------- NAVIGATION --------------------------------------------------------------------- public boolean onNavigationItemSelected(@NonNull MenuItem item) { Fragment f = null; int id = item.getItemId(); @@ -164,48 +188,17 @@ public class MainActivity extends AppCompatActivity implements * @param rememberPassword */ public void postLogin(String email, String password, boolean rememberPassword) { - ApiClient.postLogin(email, password, new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { - try { - JSONObject json = new JSONObject(jsonText); - String token = json.getString("token"); - long expiresIn = json.getLong("expiresIn"); - long idResidence = json.getLong("idResidencia"); - long idUser = json.getLong("idUser"); - - long tokenExpiration = System.currentTimeMillis() + expiresIn; - - SharedPreferences.Editor editor = SecurePreferencesUtil.getEncryptedPrefs(MainActivity.this).edit(); - editor.putString("token", token); - editor.putLong("token_expiration", tokenExpiration); - editor.putBoolean("rememberPassword", rememberPassword); - editor.putLong("idResidence", idResidence); - editor.putLong("idUser", idUser); - - if (rememberPassword) { - editor.putString("email", email); - editor.putString("password", password); - } - - SecurePreferencesUtil.edit(MainActivity.this, editor); - - } catch (Exception e) { - Log.e("API", "Error al parsear el JSON: " + e.getMessage()); - } - - ProgressBar loader = findViewById(R.id.progress_loader); - loader.setVisibility(View.VISIBLE); - - getActualUserFromAPI(); - } - - @Override - public void onError(String error) { - Toast.makeText(MainActivity.this, "Error al iniciar sesión.", Toast.LENGTH_SHORT).show(); - Log.e("API", "Error al iniciar sesión: " + error); - } - }); + AppDataRepository.getInstance().login(MainActivity.this, email, password, rememberPassword, () -> runOnUiThread(() -> { + loadFragment(createHomeFragment()); + findViewById(R.id.nav_view).setVisibility(View.VISIBLE); + findViewById(R.id.progress_loader).setVisibility(View.GONE); + ((BottomNavigationView) findViewById(R.id.nav_view)).setSelectedItemId(R.id.navigation_home); + }), + () -> runOnUiThread(() -> { + Toast.makeText(MainActivity.this, "Error al iniciar sesión", Toast.LENGTH_SHORT).show(); + findViewById(R.id.progress_loader).setVisibility(View.GONE); + }) + ); } @@ -213,20 +206,6 @@ public class MainActivity extends AppCompatActivity implements // --------------------------------------------------------------------- Fragment Creation --------------------------------------------------------------------- - /** - * Cambia el fragmento actual por otro - * @param fragmentName nombre del fragmento actual - */ - @Override - public void changeFragment(String fragmentName) { - if(fragmentName.equals("AccountFragment")){ - loadFragment(new EditAccountFragment()); - } - if(fragmentName.equals("ActivitiesFragment")){ - loadFragment(new AddActivityFragment()); - } - } - /** * Cambia el fragmento actual por otro * @param fragment fragmento a cargar @@ -236,7 +215,16 @@ public class MainActivity extends AppCompatActivity implements if (fragment != null) { Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fcvMain); if (currentFragment != null) { - lastFragment = currentFragment; // guarda el actual como "anterior" + lastFragment = currentFragment; + } + if (fragment instanceof GameFragment || fragment instanceof ResidentFragment){ + lastFragment = createHomeFragment(); + } + if (fragment instanceof ActivityDetailFragment) { + lastFragment = new ActivitiesFragment(); + } + if (fragment instanceof ResidenceDetailFragment) { + lastFragment = new AccountFragment(); } } if (fragment != null) { @@ -249,6 +237,18 @@ public class MainActivity extends AppCompatActivity implements return false; } + private boolean loadFragmentWithoutTracking(Fragment fragment) { + if (fragment != null) { + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.fcvMain, fragment) + .commit(); + return true; + } + return false; + } + + /** * Crea el fragmento de HOME * @return fragmento creado @@ -256,8 +256,6 @@ public class MainActivity extends AppCompatActivity implements public Fragment createHomeFragment(){ HomeFragment homeFragment = new HomeFragment(); Bundle bundle = new Bundle(); - bundle.putLong("idUser", SecurePreferencesUtil.getLong(this, "idUser", 0)); - bundle.putSerializable("users", (ArrayList) users); homeFragment.setArguments(bundle); return homeFragment; } @@ -271,8 +269,6 @@ public class MainActivity extends AppCompatActivity implements ResidentFragment residentFragment = new ResidentFragment(); Bundle bundle = new Bundle(); bundle.putSerializable("resident", resident); - bundle.putSerializable("gameStats", (ArrayList) gameStats); - bundle.putSerializable("games", (ArrayList) games); residentFragment.setArguments(bundle); return residentFragment; } @@ -286,8 +282,6 @@ public class MainActivity extends AppCompatActivity implements GameFragment gameFragment = new GameFragment(); Bundle bundle = new Bundle(); bundle.putSerializable("game", game); - bundle.putSerializable("gameStats", (ArrayList) gameStats); - bundle.putSerializable("residents", (ArrayList) residents); gameFragment.setArguments(bundle); return gameFragment; } @@ -305,7 +299,6 @@ public class MainActivity extends AppCompatActivity implements bundle.putSerializable("gameStat", gameStat); bundle.putSerializable("gameStatResident", gameStatResident); bundle.putSerializable("gameStatGame", gameStatGame); - bundle.putSerializable("user", actualUser); gameDetailFragment.setArguments(bundle); return gameDetailFragment; } @@ -355,7 +348,7 @@ public class MainActivity extends AppCompatActivity implements if (originalStat != null && resident != null && game != null) { GameStat updatedStat = null; - for (GameStat stat : gameStats) { + for (GameStat stat : AppDataRepository.getInstance().getGameStats()) { if (stat.getId() == originalStat.getId()) { updatedStat = stat; break; @@ -373,7 +366,7 @@ public class MainActivity extends AppCompatActivity implements Activity originalActivity = (Activity) args.getSerializable("activity"); if (originalActivity != null) { Activity updatedActivity = null; - for (Activity act : activities) { + for (Activity act : AppDataRepository.getInstance().getActivities()) { if (act.getId() == originalActivity.getId()) { updatedActivity = act; break; @@ -382,413 +375,22 @@ public class MainActivity extends AppCompatActivity implements if (updatedActivity != null) { List participants = new ArrayList<>(); - for (ActivityResident ar : activityResidents) { + for (ActivityResident ar : AppDataRepository.getInstance().getActivityResidents()) { if (ar.getActivityId() == updatedActivity.getId()) { participants.add(ar); + Log.e( "API", "Reloading ActivityDetailFragment for activity: " + ar.isHumanHelp()); } } + Log.e( "API", "Reloading ActivityDetailFragment for activity: " + updatedActivity.getId()); loadFragment(createActivityDetailFragment(updatedActivity, participants)); } } + } else if (fragment instanceof AccountFragment){ + loadFragment(new AccountFragment()); } } - // --------------------------------------------------------------------- GET DATOS FROM API --------------------------------------------------------------------- - - /** - * - * @return - */ - public User getActualUserFromAPI() { - ApiClient.getActualUser(MainActivity.this, new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { - try{ - actualUser = UserParser.parseUser(jsonText); - } catch (ParserException e){ - Log.e("UserParser", e.getMessage()); - } - getActualUserImageFromAPI(actualUser); - } - - @Override - public void onError(String error) { - Log.e("API", "Error al obtener usuario: " + error); - if (error.contains("405")) { - Toast.makeText( MainActivity.this, "Error al iniciar sesión automaticamente", Toast.LENGTH_SHORT).show(); - SecurePreferencesUtil.clear(MainActivity.this); - loadFragment(new LoginFragment()); - } else { - Toast.makeText(MainActivity.this, "Error inesperado al obtener usuario.", Toast.LENGTH_SHORT).show(); - } - } - }); - return actualUser; - } - @Override - public User getActualUser() { - return actualUser; - } - - /** - * - * @param user - * @return - */ - public Bitmap getActualUserImageFromAPI(User user) { - ApiClient.downloadImage(MainActivity.this, user.getAccountImage(), new ApiClient.ImageCallback() { - @Override - public void onSuccess(Bitmap bitmap) { - actualUserImage = bitmap; - - getUsersFromAPI(); - } - - @Override - public void onError(String error) { - Log.e("API", "Error al obtener la imagen del usuario: " + error); - } - }); - return actualUserImage; - } - @Override - public Bitmap getActualUserImage() { - return actualUserImage; - } - - /** - * Metodo para obtener los usuarios de la API - * Carga el fragmento de login - * @return usuarios obtenidos de la API - */ - public List getUsersFromAPI(){ - ApiClient.getUsers(MainActivity.this, new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { - try { - users = UserParser.parseUsers(jsonText); - } catch (ParserException e){ - Log.e("UserParser", e.getMessage()); - } - - getResidentsFromAPI(); - - - getSupportFragmentManager() - .beginTransaction() - .replace(R.id.fcvMain, new LoginFragment()) - .commit(); - } - - @Override - public void onError(String error) { - Log.e("API", "Error al obtener usuarios: " + error); - } - }); - return users; - } - @Override - public List getUsers() { - return users; - } - - /** - * Metodo para obtener los residentes de la API - * LLama a getGamesFromAPI() para obtener los juegos - * @return residentes obtenidos de la API - */ - public List getResidentsFromAPI(){ - ApiClient.getResidents(MainActivity.this, new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { - try{ - residents = ResidentParser.parseResidents(jsonText); - } catch (ParserException e){ - Log.e("ResidentParser", e.getMessage()); - } - - getGamesFromAPI(); - } - - @Override - public void onError(String error) { - Log.e("API", "Error al obtener residentes: " + error); - } - }); - return residents; - } - @Override - public List getResidents() { - return residents; - } - - public void refreshResidentsAndReload() { - ApiClient.getResidents(MainActivity.this, new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { - try{ - residents = ResidentParser.parseResidents(jsonText); - } catch (ParserException e){ - Log.e("ResidentParser", e.getMessage()); - } - - Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fcvMain); - reloadFragment(currentFragment); - } - - @Override - public void onError(String error) { - Log.e("API", "Error al refrescar residentes: " + error); - } - }); - } - - /** - * Metodo para obtener los juegos de la API - * Llama a getGameStatsFromAPI() para obtener las estadisticas de los juegos - * @return juegos obtenidos de la API - */ - public List getGamesFromAPI(){ - ApiClient.getGames(MainActivity.this, new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { - try { - games = GameParser.parseGames(jsonText); - } catch (ParserException e){ - Log.e("GameParser", e.getMessage()); - } - - getGameStatsFromAPI(); //Depende de games, residents y users - } - - @Override - public void onError(String error) { - Log.e("API", "Error al obtener juegos: " + error); - } - }); - - return games; - } - @Override - public List getGames() { - return games; - } - - - /** - * Metodo para obtener las partidas de la API - * Carga el fragmento de HOME - * @return partidas obtenidas de la API - */ - public void getGameStatsFromAPI() { - ApiClient.getGamesStats( MainActivity.this, new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { - try { - gameStats = GameStatParser.parseStats(jsonText); - } catch (ParserException e) { - Log.e("GameStatParser", e.getMessage()); - } - - getAllActivitiesFromAPI(); - } - - @Override - public void onError(String error) { - Log.e("API", "Error al obtener partidas: " + error); - } - }); - } - - @Override - public List getGameStats() { - return gameStats; - } - - public void refreshGameStatsAndReload() { - ApiClient.getGamesStats(MainActivity.this, new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { - try { - gameStats = GameStatParser.parseStats(jsonText); - } catch (ParserException e) { - Log.e("GameStatParser", e.getMessage()); - } - - Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fcvMain); - reloadFragment(currentFragment); - } - - @Override - public void onError(String error) { - Log.e("API", "Error al refrescar partidas: " + error); - } - }); - } - - public List getAllActivitiesFromAPI(){ - ApiClient.getAllActivities(MainActivity.this, new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { - try { - Log.i("API", "Actividades obtenidas: " + jsonText); - activities = ActivityParser.parseActivities(jsonText); - } catch (ParserException e){ - Log.e("ActivityParser", e.getMessage()); - } - if(!activities.isEmpty()) { - getAllParticipantsFromAPI(activities); - } else { - ProgressBar loader = findViewById(R.id.progress_loader); - BottomNavigationView navView = findViewById(R.id.nav_view); - - runOnUiThread(() -> { - loader.setVisibility(View.GONE); - - Log.i( "API", "Users obtenidas: " + users.size()); - Log.i( "API", "Residents obtenidas: " + residents.size()); - Log.i( "API", "Games obtenidas: " + games.size()); - Log.i( "API", "GameStats obtenidas: " + gameStats.size()); - Log.i( "API", "Activities obtenidas: " + activities.size()); - Log.i( "API", "ActivityResidents obtenidas: Sin datos porque no hay actividades"); - Log.i("INfo", "Cargar fragment home"); - loadFragment(createHomeFragment()); - - navView.setVisibility(View.VISIBLE); - }); - } - } - - @Override - public void onError(String error) { - Log.e("API", "Error al obtener actividades: " + error); - } - }); - return null; - } - @Override - public List getActivities() { - return activities; - } - - public void refreshActivitiesAndReload(){ - ApiClient.getAllActivities(MainActivity.this, new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { - try { - activities = ActivityParser.parseActivities(jsonText); - } catch (ParserException e){ - Log.e("ActivityParser", e.getMessage()); - } - - refreshParticipantsAndReload(activities); - } - - @Override - public void onError(String error) { - Log.e("API", "Error al refrescar actividades: " + error); - } - }); - } - - public List getAllParticipantsFromAPI(List activities){ - for (Activity activity : activities) { - ApiClient.getAllParticipants(MainActivity.this, activity.getId(), new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { - try { - List parsed = ActivityResidentParser.parseActivityResidents(jsonText); - - synchronized (activityResidents) { - activityResidents.addAll(parsed); - } - } catch (ParserException e){ - Log.e("ActivityResidentParser", e.getMessage()); - } - - ProgressBar loader = findViewById(R.id.progress_loader); - BottomNavigationView navView = findViewById(R.id.nav_view); - - runOnUiThread(() -> { - loader.setVisibility(View.GONE); - - Log.i( "API", "Users obtenidas: " + users.size()); - Log.i( "API", "Residents obtenidas: " + residents.size()); - Log.i( "API", "Games obtenidas: " + games.size()); - Log.i( "API", "GameStats obtenidas: " + gameStats.size()); - Log.i( "API", "Activities obtenidas: " + activities.size()); - Log.i( "API", "ActivityResidents obtenidas: " + activityResidents.size()); - Log.i("INfo", "Cargar fragment home"); - loadFragment(createHomeFragment()); - - navView.setVisibility(View.VISIBLE); - }); - } - - @Override - public void onError(String error) { - Log.e("API", "Error al obtener participantes: " + error); - } - }); - } - return activityResidents; - } - @Override - public List getParticipants() { - return activityResidents; - } - - /** - * - * @param activities - */ - public void refreshParticipantsAndReload(List activities) { - activityResidents.clear(); - int totalActivities = activities.size(); - final int[] completedRequests = {0}; - - if (totalActivities == 0) { - Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fcvMain); - reloadFragment(currentFragment); - return; - } - - for (Activity activity : activities) { - ApiClient.getAllParticipants(MainActivity.this, activity.getId(), new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { - try { - List parsed = ActivityResidentParser.parseActivityResidents(jsonText); - synchronized (activityResidents) { - activityResidents.addAll(parsed); - } - } catch (ParserException e) { - Log.e("ActivityResidentParser", e.getMessage()); - } - checkAndReload(); - } - - @Override - public void onError(String error) { - Log.e("API", "Error al refrescar participantes: " + error); - checkAndReload(); - } - - private void checkAndReload() { - Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fcvMain); - synchronized (completedRequests) { - completedRequests[0]++; - if (completedRequests[0] == totalActivities) { - runOnUiThread(() -> - reloadFragment(currentFragment)); - } - } - } - }); - } - } - // --------------------------------------------------------------------- OnClickListeners --------------------------------------------------------------------- @@ -811,19 +413,19 @@ public class MainActivity extends AppCompatActivity implements */ @Override public void onTakeOutResident(Resident resident) { - ApiClient.patchTakeOutResident( MainActivity.this, resident.getId(), new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { - Toast.makeText(MainActivity.this, "Residente dado de baja correctamente", Toast.LENGTH_SHORT).show(); - refreshResidentsAndReload(); - refreshGameStatsAndReload(); - } - - @Override - public void onError(String error) { - Toast.makeText(MainActivity.this, "Error al dar de baja a residente", Toast.LENGTH_SHORT).show(); - Log.e("API", "Error al eliminar residente: " + error); - } + AppDataRepository.getInstance().takeDownResident(MainActivity.this, resident.getId(), () -> { + runOnUiThread(() -> { + AppDataRepository.getInstance().fetchResidentsTakenOutOnly( MainActivity.this, () -> { + runOnUiThread(() -> { + Toast.makeText(MainActivity.this, "Residente dado de baja correctamente", Toast.LENGTH_SHORT).show(); + reloadFragment(getSupportFragmentManager().findFragmentById(R.id.fcvMain)); + }); + }); + }); + }, () -> { + runOnUiThread(() -> { + Toast.makeText(MainActivity.this, "Error al dar de baja al residente: ", Toast.LENGTH_SHORT).show(); + }); }); } @@ -859,18 +461,15 @@ public class MainActivity extends AppCompatActivity implements */ @Override public void onDeleteGameStat(GameStat gameStat, Game gamestatGame) { - ApiClient.deleteGameStat(MainActivity.this, gameStat.getId(), new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { + AppDataRepository.getInstance().deleteGameStat(MainActivity.this, gameStat.getId(), () -> { + runOnUiThread(() -> { Toast.makeText(MainActivity.this, "Partida eliminada correctamente", Toast.LENGTH_SHORT).show(); - refreshGameStatsAndReload(); - } - - @Override - public void onError(String error) { + reloadFragment(getSupportFragmentManager().findFragmentById(R.id.fcvMain)); + }); + }, () -> { + runOnUiThread(() -> { Toast.makeText(MainActivity.this, "Error al eliminar partida", Toast.LENGTH_SHORT).show(); - Log.e("API", "Error al eliminar partida: " + error); - } + }); }); } @@ -882,18 +481,15 @@ public class MainActivity extends AppCompatActivity implements */ @Override public void onAddObservation(String observation, long gameId, long gameStatId) { - ApiClient.patchObservation(MainActivity.this, observation, gameStatId, new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { - Toast.makeText(MainActivity.this, "Observación añadida correctamente", Toast.LENGTH_SHORT).show(); - refreshGameStatsAndReload(); - } - - @Override - public void onError(String error) { - Toast.makeText(MainActivity.this, "Error al añadir observación", Toast.LENGTH_SHORT).show(); - Log.e("API", "Error al añadir observación: " + error); - } + AppDataRepository.getInstance().updateObservation(MainActivity.this, observation, gameStatId, () -> { + runOnUiThread(() -> { + Toast.makeText(MainActivity.this, "Observación actualizada correctamente", Toast.LENGTH_SHORT).show(); + reloadFragment(getSupportFragmentManager().findFragmentById(R.id.fcvMain)); + }); + }, () -> { + runOnUiThread(() -> { + Toast.makeText(MainActivity.this, "Error al actualizar observación", Toast.LENGTH_SHORT).show(); + }); }); } @@ -917,20 +513,15 @@ public class MainActivity extends AppCompatActivity implements */ @Override public void onAddActivity(String activityName, String activityDescription, LocalDateTime date) { - ApiClient.postEvento(MainActivity.this, activityName, activityDescription, date, new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { + AppDataRepository.getInstance().addActivity(MainActivity.this, activityName, activityDescription, date, () -> { + runOnUiThread(() -> { Toast.makeText(MainActivity.this, "Actividad añadida correctamente", Toast.LENGTH_SHORT).show(); - refreshActivitiesAndReload(); loadFragment(new ActivitiesFragment()); - } - - @Override - public void onError(String error) { + }); + }, () -> { + runOnUiThread(() -> { Toast.makeText(MainActivity.this, "Error al añadir actividad", Toast.LENGTH_SHORT).show(); - Log.e("API", "Error al añadir actividad: " + error); - loadFragment( new ActivitiesFragment()); - } + }); }); } @@ -944,7 +535,11 @@ public class MainActivity extends AppCompatActivity implements @Override public void onSuccess(String jsonText) { Toast.makeText(MainActivity.this, "Actividad eliminada correctamente", Toast.LENGTH_SHORT).show(); - refreshActivitiesAndReload(); + AppDataRepository.getInstance().fetchActivitiesOnly(MainActivity.this, () -> { + runOnUiThread(() -> { + reloadFragment(getSupportFragmentManager().findFragmentById(R.id.fcvMain)); + }); + }); } @Override @@ -957,18 +552,16 @@ public class MainActivity extends AppCompatActivity implements @Override public void onChangeStateActivity(Activity activity, ActivityState state) { - ApiClient.patchActivityState(MainActivity.this, activity.getId(), state, new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { - Toast.makeText(MainActivity.this, "Actividad cerrada correctamente", Toast.LENGTH_SHORT).show(); - refreshActivitiesAndReload(); - } - - @Override - public void onError(String error) { - Toast.makeText(MainActivity.this, "Error al cerrar actividad", Toast.LENGTH_SHORT).show(); - Log.e("API", "Error al cerrar actividad: " + error); - } + Log.e( "API", "Cambiando estado de la actividad: " + activity.getId()); + AppDataRepository.getInstance().changeActivityState(MainActivity.this, activity.getId(), state, () -> { + runOnUiThread(() -> { + Toast.makeText(MainActivity.this, "Estado de la actividad actualizado correctamente", Toast.LENGTH_SHORT).show(); + reloadFragment(getSupportFragmentManager().findFragmentById(R.id.fcvMain)); + }); + }, () -> { + runOnUiThread(() -> { + Toast.makeText(MainActivity.this, "Error al actualizar el estado de la actividad", Toast.LENGTH_SHORT).show(); + }); }); } @@ -982,8 +575,8 @@ public class MainActivity extends AppCompatActivity implements * @param residents */ @Override - public void onClickOnAddParticipant(Activity activity, List participants ,List residents) { - ParticipantSelectionDialogFragment dialog = new ParticipantSelectionDialogFragment(activity, participants, residents); + public void onClickOnAddParticipant(Activity activity, List participants) { + ParticipantSelectionDialogFragment dialog = new ParticipantSelectionDialogFragment(activity, participants); dialog.show(getSupportFragmentManager(), "ParticipantDialog"); } @@ -993,7 +586,11 @@ public class MainActivity extends AppCompatActivity implements */ @Override public void onClickOnParticipant(ActivityResident participant) { - Toast.makeText( this, "Clicked on participant: " + participant.getIdResident() , Toast.LENGTH_SHORT).show(); + Fragment f = new ParticipantDetailFragment(); + Bundle bundle = new Bundle(); + bundle.putSerializable("participant", participant); + f.setArguments(bundle); + loadFragment(f); } /** @@ -1003,19 +600,15 @@ public class MainActivity extends AppCompatActivity implements */ @Override public void onClickOnAssistance(ActivityResident participant, boolean assistance ) { - String jsonBody = "{\"asistenciaPermitida\": " + assistance + "}"; - ApiClient.patchParticipant( MainActivity.this, participant.getActivityId(), participant.getId() , jsonBody, new ApiClient.RawCallback() { - @Override - public void onSuccess(String jsonText) { + AppDataRepository.getInstance().updateAssistance(MainActivity.this, participant.getActivityId(), participant.getId(), assistance, () -> { + runOnUiThread(() -> { Toast.makeText(MainActivity.this, "Asistencia actualizada correctamente", Toast.LENGTH_SHORT).show(); - refreshActivitiesAndReload(); - } - - @Override - public void onError(String error) { + reloadFragment(getSupportFragmentManager().findFragmentById(R.id.fcvMain)); + }); + }, () -> { + runOnUiThread(() -> { Toast.makeText(MainActivity.this, "Error al actualizar asistencia", Toast.LENGTH_SHORT).show(); - Log.e("API", "Error al actualizar asistencia: " + error); - } + }); }); } @@ -1042,24 +635,15 @@ public class MainActivity extends AppCompatActivity implements */ @Override public void onAddOpinion(ActivityResident participant ,boolean isPreOpinion, String opinion) { - String jsonBody = ""; - if (isPreOpinion) { - jsonBody = "{\"preOpinion\": \"" + opinion + "\"}"; - } else { - jsonBody = "{\"postOpinion\": \"" + opinion + "\"}"; - } - ApiClient.patchParticipant( MainActivity.this, participant.getActivityId(), participant.getId() , jsonBody, new ApiClient.RawCallback() {; - @Override - public void onSuccess(String jsonText) { - Toast.makeText(MainActivity.this, "Opinion actualizada correctamente", Toast.LENGTH_SHORT).show(); - refreshActivitiesAndReload(); - } - - @Override - public void onError(String error) { - Toast.makeText(MainActivity.this, "Error al actualizar opinion", Toast.LENGTH_SHORT).show(); - Log.e("API", "Error al actualizar opinion: " + error); - } + AppDataRepository.getInstance().updateOpinion( MainActivity.this, participant.getActivityId(), participant.getId(), isPreOpinion, opinion, () -> { + runOnUiThread(() -> { + Toast.makeText(MainActivity.this, "Opinión actualizada correctamente", Toast.LENGTH_SHORT).show(); + reloadFragment(lastFragment); + }); + }, () -> { + runOnUiThread(() -> { + Toast.makeText(MainActivity.this, "Error al actualizar opinión", Toast.LENGTH_SHORT).show(); + }); }); } @@ -1070,19 +654,15 @@ public class MainActivity extends AppCompatActivity implements */ @Override public void onClickOnMaterialHelp(ActivityResident participant, boolean materialHelp) { - String jsonBody = "{\"recursosMateriales\": " + materialHelp + "}"; - ApiClient.patchParticipant( MainActivity.this, participant.getActivityId(), participant.getId() , jsonBody, new ApiClient.RawCallback() {; - @Override - public void onSuccess(String jsonText) { + AppDataRepository.getInstance().updateMaterialHelp( MainActivity.this, participant.getActivityId(), participant.getId(), materialHelp, () -> { + runOnUiThread(() -> { Toast.makeText(MainActivity.this, "Ayuda material actualizada correctamente", Toast.LENGTH_SHORT).show(); - refreshActivitiesAndReload(); - } - - @Override - public void onError(String error) { + reloadFragment(getSupportFragmentManager().findFragmentById(R.id.fcvMain)); + }); + }, () -> { + runOnUiThread(() -> { Toast.makeText(MainActivity.this, "Error al actualizar ayuda material", Toast.LENGTH_SHORT).show(); - Log.e("API", "Error al actualizar ayuda material: " + error); - } + }); }); } @@ -1093,19 +673,15 @@ public class MainActivity extends AppCompatActivity implements */ @Override public void onClickOnHumanHelp(ActivityResident participant, boolean humanHelp) { - String jsonBody = "{\"recursosHumanos\": " + humanHelp + "}"; - ApiClient.patchParticipant( MainActivity.this, participant.getActivityId(), participant.getId() , jsonBody, new ApiClient.RawCallback() {; - @Override - public void onSuccess(String jsonText) { + AppDataRepository.getInstance().updateHumanHelp(MainActivity.this, participant.getActivityId(), participant.getId(), humanHelp, () -> { + runOnUiThread(() -> { Toast.makeText(MainActivity.this, "Ayuda humana actualizada correctamente", Toast.LENGTH_SHORT).show(); - refreshActivitiesAndReload(); - } - - @Override - public void onError(String error) { + reloadFragment(getSupportFragmentManager().findFragmentById(R.id.fcvMain)); + }); + }, () -> { + runOnUiThread(() -> { Toast.makeText(MainActivity.this, "Error al actualizar ayuda humana", Toast.LENGTH_SHORT).show(); - Log.e("API", "Error al actualizar ayuda humana: " + error); - } + }); }); } @@ -1117,32 +693,150 @@ public class MainActivity extends AppCompatActivity implements */ @Override public void onParticipantSelected(Activity activity, List participants ,Resident selectedResident) { - Toast.makeText( this, "Particiapnte added " , Toast.LENGTH_SHORT).show(); - ApiClient.postParticipant(MainActivity.this, selectedResident.getId(), false, false, "", "", activity.getId(), new ApiClient.RawCallback() {; - @Override - public void onSuccess(String jsonText) { + Log.e( "API", "Adding participant: " + selectedResident.getId() + " to activity: " + activity.getId()); + AppDataRepository.getInstance().addParticipant( MainActivity.this, activity.getId(), selectedResident.getId(), () -> { + runOnUiThread(() -> { Toast.makeText(MainActivity.this, "Participante añadido correctamente", Toast.LENGTH_SHORT).show(); - refreshActivitiesAndReload(); - } - - @Override - public void onError(String error) { + reloadFragment(getSupportFragmentManager().findFragmentById(R.id.fcvMain)); + }); + }, () -> { + runOnUiThread(() -> { Toast.makeText(MainActivity.this, "Error al añadir participante", Toast.LENGTH_SHORT).show(); - Log.e("API", "Error al añadir participante: " + error); - } + }); }); } // --------------------------------------------------------------------- LogOut listener --------------------------------------------------------------------- + @Override + public void OnResidenceButtonClicked() { + loadFragment( new ResidenceDetailFragment()); + } + + @Override + public void onLanguageSelected(String languageCode) { + SharedPreferences.Editor editor = SecurePreferencesUtil.getEncryptedPrefs(MainActivity.this).edit(); + editor.putString("language", languageCode); + editor.apply(); + + recreate(); + ((BottomNavigationView) findViewById(R.id.nav_view)).setSelectedItemId(R.id.navigation_home); + } + @Override public void onLogOutButtonClicked() { SecurePreferencesUtil.clear(MainActivity.this); loadFragment(new LoginFragment()); + findViewById(R.id.nav_view).setVisibility(View.GONE); } @Override public void onClickOnBackButton() { + Log.e( "API", "Back button clicked, reloading last fragment: " + (lastFragment != null ? lastFragment.getClass().getSimpleName() : "null")); reloadFragment(lastFragment); } + + @Override + public void onRefreshActivityDetail() { + AppDataRepository.getInstance().fetchActivitiesOnly( MainActivity.this, () -> { + runOnUiThread(() -> { + AppDataRepository.getInstance().fetchParticipantsOnly( MainActivity.this, () -> { + runOnUiThread(() -> { + reloadFragment(getSupportFragmentManager().findFragmentById(R.id.fcvMain)); + }); + }); + }); + }); + } + + @Override + public void onRefreshActivities() { + AppDataRepository.getInstance().fetchActivitiesOnly( MainActivity.this, () -> { + runOnUiThread(() -> { + reloadFragment(getSupportFragmentManager().findFragmentById(R.id.fcvMain)); + }); + }); + } + + @Override + public void onClickOnAddActivity() { + loadFragment(new AddActivityFragment()); + } + + @Override + public void onRefreshGameStats() { + AppDataRepository.getInstance().fetchGameStatsOnly( MainActivity.this, () -> { + runOnUiThread(() -> { + loadFragmentWithoutTracking(getSupportFragmentManager().findFragmentById(R.id.fcvMain)); + }); + }); + } + + @Override + public void onRefreshHome() { + AppDataRepository.getInstance().fetchActualUser( MainActivity.this, () -> { + runOnUiThread(() -> { + reloadFragment(getSupportFragmentManager().findFragmentById(R.id.fcvMain)); + }); + }, () -> { + runOnUiThread(() -> { + Toast.makeText(MainActivity.this, "Error al cargar datos", Toast.LENGTH_SHORT).show(); + }); + }); + } + + @Override + public void onRefreshParticipantDetail() { + AppDataRepository.getInstance().fetchParticipantsOnly( MainActivity.this, () -> { + runOnUiThread(() -> { + reloadFragment(getSupportFragmentManager().findFragmentById(R.id.fcvMain)); + }); + }); + } + + @Override + public void onRefreshResidenceDetail() { + AppDataRepository.getInstance().fetchResidenceOnly( MainActivity.this, () -> { + runOnUiThread(() -> { + AppDataRepository.getInstance().fetchResidentsOnly(MainActivity.this, () -> { + runOnUiThread(() -> { + AppDataRepository.getInstance().fetchResidentsTakenOutOnly( MainActivity.this, () -> { + runOnUiThread(() -> { + AppDataRepository.getInstance().fetchGamesOnly( MainActivity.this, () -> { + runOnUiThread(() -> { + AppDataRepository.getInstance().fetchGameStatsOnly( MainActivity.this, () -> { + runOnUiThread(() -> { + reloadFragment(getSupportFragmentManager().findFragmentById(R.id.fcvMain)); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + } + + @Override + public void onAddResidentFormSubmitted(String nombre, String apellido, LocalDate fechaNacimiento, String documentoIdentidad, String familiar1, String familiar2, int year, int month) { + AppDataRepository.getInstance().addResident( MainActivity.this, nombre, apellido, fechaNacimiento, documentoIdentidad, familiar1, familiar2, year, month, () -> { + runOnUiThread(() -> { + Toast.makeText(MainActivity.this, "Residente añadido correctamente", Toast.LENGTH_SHORT).show(); + reloadFragment(lastFragment); + }); + }, () -> { + runOnUiThread(() -> { + Toast.makeText(MainActivity.this, "Error al añadir residente", Toast.LENGTH_SHORT).show(); + }); + }); + } + + @Override + public void onClickOnAddParticipant() { + loadFragment(new AddResidentFragment()); + } + + } \ No newline at end of file diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/account/AccountFragment.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/account/AccountFragment.java index 9e96391..8c661cc 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/account/AccountFragment.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/account/AccountFragment.java @@ -1,26 +1,40 @@ package com.andresgmoran.apptrabajadores.ui.fragments.account; +import android.app.AlertDialog; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Color; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import com.andresgmoran.apptrabajadores.R; -import com.andresgmoran.apptrabajadores.interfaces.IOChangeFragmentListener; +import com.andresgmoran.apptrabajadores.models.User; +import com.andresgmoran.apptrabajadores.repository.AppDataRepository; public class AccountFragment extends Fragment { - private Button editAccountButton; + private User actualUser = AppDataRepository.getInstance().getActualUser(); + private Bitmap userImage = AppDataRepository.getInstance().getActualUserImage(); + + private View userCardView; + private TextView userNameTextView; + private ImageView userImageView; + private Button residenceButton; + private Button languageButton; private Button logOutButton; - private IOChangeFragmentListener listener; private IOAccountFragmentListener accountFragmentListener; public interface IOAccountFragmentListener { + void OnResidenceButtonClicked(); + void onLanguageSelected(String selectedLanguageCode); void onLogOutButtonClicked(); } @@ -33,18 +47,61 @@ public class AccountFragment extends Fragment { @Override 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() { + + View statusBar = requireActivity().findViewById(R.id.status_bar_background); + statusBar.setBackgroundColor(Color.parseColor("#0062FF")); + + userCardView = view.findViewById(R.id.account_card_view); + + userCardView.findViewById(R.id.back_button).setVisibility(View.GONE); + + userNameTextView = userCardView.findViewById(R.id.banner_name_game); + userNameTextView.setText(actualUser.getName() + " " + actualUser.getSurnames()); + + userImageView = userCardView.findViewById(R.id.image_item_person_banner); + userImageView.setImageBitmap(userImage); + + residenceButton = view.findViewById(R.id.residence_button_account); + residenceButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - listener.changeFragment("AccountFragment"); + accountFragmentListener.OnResidenceButtonClicked(); } }); + + languageButton = view.findViewById(R.id.btn_idioma); + languageButton.setOnClickListener(v -> { + final String[] idiomas = { + getString(R.string.es_language_text), + getString(R.string.en_language_text), + getString(R.string.va_language_text) + }; + final String[] codigos = {"es", "en", "va"}; + + new AlertDialog.Builder(requireContext()) + .setTitle(getString(R.string.select_language_tile)) + .setItems(idiomas, (dialog, which) -> { + String selectedLanguageCode = codigos[which]; + accountFragmentListener.onLanguageSelected(selectedLanguageCode); + }) + .show(); + }); + + + logOutButton = view.findViewById(R.id.btn_cerrar_sesion); logOutButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - accountFragmentListener.onLogOutButtonClicked(); + new AlertDialog.Builder(getContext()) + .setTitle(getString(R.string.logout_title)) + .setMessage(getString(R.string.confirm_logout_message)) + .setPositiveButton( getString(R.string.accept_text), (dialog, which) -> { + accountFragmentListener.onLogOutButtonClicked(); + }) + .setNegativeButton(getString(R.string.cancel_text), (dialog, which) -> { + dialog.dismiss(); + }) + .show(); } }); @@ -53,7 +110,6 @@ public class AccountFragment extends Fragment { @Override public void onAttach(@NonNull Context context) { super.onAttach(context); - listener = (IOChangeFragmentListener) context; accountFragmentListener = (IOAccountFragmentListener) context; } diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/account/EditAccountFragment.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/account/EditAccountFragment.java deleted file mode 100644 index 8913a7b..0000000 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/account/EditAccountFragment.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.andresgmoran.apptrabajadores.ui.fragments.account; - -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; - -import com.andresgmoran.apptrabajadores.R; - -public class EditAccountFragment extends Fragment { - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_edit_account, container, false); - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - } - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - } -} diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/ActivitiesFragment.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/ActivitiesFragment.java index fab4a86..cab9eb0 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/ActivitiesFragment.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/ActivitiesFragment.java @@ -1,42 +1,48 @@ 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 androidx.annotation.NonNull; import androidx.annotation.Nullable; +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.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.ActivityState; import com.andresgmoran.apptrabajadores.models.adapters.ActivitiesAdapter; -import com.andresgmoran.apptrabajadores.ui.MainActivity; -import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.andresgmoran.apptrabajadores.repository.AppDataRepository; +import com.google.android.material.button.MaterialButton; +import java.util.ArrayList; +import java.util.Comparator; import java.util.List; public class ActivitiesFragment extends Fragment { - public interface IOOnAttachListener{ - List getActivities(); - List getParticipants(); + private ActivitiesAdapter activitiesAdapter; + private RecyclerView activitiesRecyclerView; + + public interface IOnActivities { + void onRefreshActivities(); + void onClickOnAddActivity(); } + private IOnActivities listener; - private IOChangeFragmentListener changeFragmentListener; - - private List activities; - private List participants; + private List activities = AppDataRepository.getInstance().getActivities(); + private List participants = AppDataRepository.getInstance().getActivityResidents(); @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { @@ -47,33 +53,94 @@ public class ActivitiesFragment extends Fragment { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + View statusBar = requireActivity().findViewById(R.id.status_bar_background); + statusBar.setBackgroundColor(Color.parseColor("#CCCCCC")); + SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_layout_activities_list); swipeRefreshLayout.setOnRefreshListener(() -> { - ((MainActivity) requireActivity()).refreshActivitiesAndReload(); + listener.onRefreshActivities(); swipeRefreshLayout.setRefreshing(false); }); - ActivitiesAdapter activitiesAdapter = new ActivitiesAdapter(requireContext(), activities, participants, (IOClickOnActivityListener) requireActivity(), (IOnChageStateActivityListener) requireActivity()); - RecyclerView activitiesRecyclerView = view.findViewById(R.id.activities_recycleView); + activitiesAdapter = new ActivitiesAdapter(requireContext(), activities, participants, (IOClickOnActivityListener) requireActivity(), (IOnChageStateActivityListener) requireActivity()); + 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"); + setupFab(view); + filterButton(view); + } + + private void setupFab(View view) { + MaterialButton fab = view.findViewById(R.id.add_activity_button); + + fab.setOnClickListener(v -> + listener.onClickOnAddActivity() + ); + + + NestedScrollView scrollView = view.findViewById(R.id.nested_scroll_view_activities); + 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) { + fab.animate().translationY(fab.getHeight() + 50).alpha(0.0f).setDuration(200).withEndAction(() -> fab.setVisibility(View.GONE)); + isButtonVisible = false; + } else if (scrollY < lastScrollY - 10 && !isButtonVisible) { + 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; } }); } + private void filterButton(View view){ + ImageButton filterButton = view.findViewById(R.id.filter_activities_list_button); + filterButton.setOnClickListener( v -> { + String[] options = {getString(R.string.status_open_filter_text), + getString(R.string.status_closed_filter_text), + getString(R.string.status_on_going_filter_text), + getString(R.string.status_finished_filter_text), + getString(R.string.activity_date_filter_text)}; + + new androidx.appcompat.app.AlertDialog.Builder(requireContext()) + .setTitle(R.string.filter_activities_title) + .setItems(options, (dialog, which) -> filterActivities(options[which])) + .show(); + }); + } + + private void filterActivities(String option) { + List filteredList = new ArrayList<>(AppDataRepository.getInstance().getActivities()); + + if (option.equals(getString(R.string.status_open_filter_text))) { + filteredList.removeIf(activity -> activity.getState() != ActivityState.ABIERTO); + } else if (option.equals(getString(R.string.status_closed_filter_text))) { + filteredList.removeIf(activity -> activity.getState() != ActivityState.CERRADO); + } else if (option.equals(getString(R.string.status_on_going_filter_text))) { + filteredList.removeIf(activity -> activity.getState() != ActivityState.EN_CURSO); + } else if (option.equals(getString(R.string.status_finished_filter_text))) { + filteredList.removeIf(activity -> activity.getState() != ActivityState.FINALIZADA); + } else if (option.equals(getString(R.string.activity_date_filter_text))) { + filteredList.sort(Comparator.comparing(Activity::getDate)); + } + + activitiesAdapter.updateData(filteredList, participants); + activitiesRecyclerView.scrollToPosition(0); + } + @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(); + listener = (IOnActivities) context; } } diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/ActivityDetailFragment.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/ActivityDetailFragment.java index bd2b533..2a3a455 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/ActivityDetailFragment.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/ActivityDetailFragment.java @@ -1,6 +1,9 @@ package com.andresgmoran.apptrabajadores.ui.fragments.activities; +import android.app.AlertDialog; import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.Color; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -27,6 +30,7 @@ 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.repository.AppDataRepository; import com.andresgmoran.apptrabajadores.ui.MainActivity; import com.google.android.material.button.MaterialButton; @@ -37,15 +41,16 @@ public class ActivityDetailFragment extends Fragment { private Activity activity; private List participants; - private List residents; + private List residents = AppDataRepository.getInstance().getResidents(); private IOClickOnAddParticipantListener addParticipantListener; private IOnChageStateActivityListener changeStateActivityListener; private IOnClickOnBackButtonListener backButtonListener; - public interface IOOnAttachListener { - List getResidents(); + public interface OnRefreshActivityDetailListener { + void onRefreshActivityDetail(); } + private OnRefreshActivityDetailListener refreshActivityDetailListener; @Nullable @Override @@ -56,6 +61,10 @@ public class ActivityDetailFragment extends Fragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + + View statusBar = requireActivity().findViewById(R.id.status_bar_background); + statusBar.setBackgroundColor(Color.parseColor("#0062FF")); + setupSwipeRefresh(view); setupBackButton(view); setupActivityInfo(view); @@ -68,7 +77,7 @@ public class ActivityDetailFragment extends Fragment { private void setupSwipeRefresh(View view) { SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_activity_detail); swipeRefreshLayout.setOnRefreshListener(() -> { - ((MainActivity) requireActivity()).refreshActivitiesAndReload(); + refreshActivityDetailListener.onRefreshActivityDetail(); swipeRefreshLayout.setRefreshing(false); }); } @@ -92,31 +101,30 @@ public class ActivityDetailFragment extends Fragment { MaterialButton startEndButton = view.findViewById(R.id.btn_start_end_activity); ActivityState state = activity.getState(); - + if (state == ActivityState.ABIERTO){ + startEndButton.setVisibility(View.GONE); + }else { switch (state) { - case ABIERTO: - configureButton(startEndButton, "Cerrar actividad", R.color.purple_200, () -> - changeStateActivityListener.onChangeStateActivity(activity, ActivityState.CERRADO)); - break; case CERRADO: - configureButton(startEndButton, "Iniciar actividad", R.color.purple_200, () -> + configureButton(startEndButton, getContext().getString(R.string.start_activity_text), "#59FF00", () -> changeStateActivityListener.onChangeStateActivity(activity, ActivityState.EN_CURSO)); break; case EN_CURSO: - configureButton(startEndButton, "Finalizar actividad", R.color.teal_200, () -> + configureButton(startEndButton, getContext().getString(R.string.finish_activity_text), "#FF0000" , () -> changeStateActivityListener.onChangeStateActivity(activity, ActivityState.FINALIZADA)); break; case FINALIZADA: - startEndButton.setText("Actividad finalizada"); - startEndButton.setBackgroundTintList(ContextCompat.getColorStateList(requireContext(), R.color.teal_200)); + startEndButton.setText(getContext().getString(R.string.activity_finished_text)); + startEndButton.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#324F5E"))); startEndButton.setEnabled(false); break; } + } } - private void configureButton(MaterialButton button, String text, int colorRes, Runnable onClick) { + private void configureButton(MaterialButton button, String text, String hexColor, Runnable onClick) { button.setText(text); - button.setBackgroundTintList(ContextCompat.getColorStateList(requireContext(), colorRes)); + button.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor(hexColor))); button.setOnClickListener(v -> onClick.run()); } @@ -150,8 +158,10 @@ public class ActivityDetailFragment extends Fragment { int humanCount = 0, materialCount = 0; for (ActivityResident p : participants) { if (p.getActivityId() == activity.getId()) { - if (p.isHumanHelp()) humanCount++; - else if (p.isMaterialHelp()) materialCount++; + if (p.isHumanHelp()) + humanCount++; + if (p.isMaterialHelp()) + materialCount++; } } @@ -169,11 +179,11 @@ public class ActivityDetailFragment extends Fragment { private void setupFab(View view) { MaterialButton fab = view.findViewById(R.id.add_participant_button); - if (activity.getState() == ActivityState.CERRADO) { + if (activity.getState() != ActivityState.ABIERTO) { fab.setVisibility(View.GONE); } else { fab.setOnClickListener(v -> - addParticipantListener.onClickOnAddParticipant(activity, participants, residents) + addParticipantListener.onClickOnAddParticipant(activity, participants) ); NestedScrollView scrollView = view.findViewById(R.id.nested_scroll_game_detail); @@ -208,7 +218,8 @@ public class ActivityDetailFragment extends Fragment { participants = (List) getArguments().getSerializable("participants"); } - residents = ((IOOnAttachListener) context).getResidents(); + refreshActivityDetailListener = (OnRefreshActivityDetailListener) context; + addParticipantListener = (IOClickOnAddParticipantListener) context; changeStateActivityListener = (IOnChageStateActivityListener) context; backButtonListener = (IOnClickOnBackButtonListener) context; diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/AddActivityFragment.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/AddActivityFragment.java index 0286463..945b118 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/AddActivityFragment.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/AddActivityFragment.java @@ -1,14 +1,17 @@ package com.andresgmoran.apptrabajadores.ui.fragments.activities; import android.app.DatePickerDialog; +import android.app.TimePickerDialog; import android.content.Context; import android.os.Bundle; +import android.text.TextUtils; 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 android.widget.EditText; +import android.widget.TimePicker; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -16,20 +19,21 @@ 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); + void onAddActivity(String activityName, String activityDescription, LocalDateTime dateTime); } private IOnAddActivity listener; private Button buttonFecha; - private LocalDateTime selectedDate; + private EditText nameEditText; + private EditText descriptionEditText; + private LocalDateTime selectedDateTime; @Nullable @Override @@ -41,22 +45,19 @@ public class AddActivityFragment extends Fragment { 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); + nameEditText = view.findViewById(R.id.add_activity_name_input); + descriptionEditText = 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 (validarCampos()) { + String activityName = nameEditText.getText().toString().trim(); + String activityDescription = descriptionEditText.getText().toString().trim(); - if (activityName.isEmpty() || activityDescription.isEmpty() || selectedDate == null) { - return; - } - - if (listener != null) { - listener.onAddActivity(activityName, activityDescription, selectedDate); + listener.onAddActivity(activityName, activityDescription, selectedDateTime); } }); } @@ -67,16 +68,49 @@ public class AddActivityFragment extends Fragment { int month = calendar.get(Calendar.MONTH); int day = calendar.get(Calendar.DAY_OF_MONTH); - DatePickerDialog datePickerDialog = new 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()); + showTimePickerDialog(selectedYear, selectedMonth + 1, selectedDayOfMonth); }, year, month, day - ); + ).show(); + } - datePickerDialog.show(); + private void showTimePickerDialog(int year, int month, int dayOfMonth) { + final Calendar calendar = Calendar.getInstance(); + int hour = calendar.get(Calendar.HOUR_OF_DAY); + int minute = calendar.get(Calendar.MINUTE); + + new TimePickerDialog( + requireContext(), + (TimePicker view, int selectedHour, int selectedMinute) -> { + selectedDateTime = LocalDateTime.of(year, month, dayOfMonth, selectedHour, selectedMinute); + buttonFecha.setText(selectedDateTime.toString().replace('T', ' ')); + }, + hour, minute, true + ).show(); + } + + private boolean validarCampos() { + boolean valido = true; + + if (TextUtils.isEmpty(nameEditText.getText())) { + nameEditText.setError("Campo obligatorio"); + valido = false; + } + if (TextUtils.isEmpty(descriptionEditText.getText())) { + descriptionEditText.setError("Campo obligatorio"); + valido = false; + } + if (selectedDateTime == null) { + buttonFecha.setError("Selecciona fecha y hora"); + valido = false; + } else { + buttonFecha.setError(null); // limpia error si está bien + } + + return valido; } @Override diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/OpinionFragment.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/OpinionFragment.java index 7fe0d2a..a21b6e5 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/OpinionFragment.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/OpinionFragment.java @@ -1,8 +1,8 @@ package com.andresgmoran.apptrabajadores.ui.fragments.activities; -import android.app.Activity; import android.content.Context; import android.os.Bundle; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -17,26 +17,37 @@ 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); } + 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(); + String opinion = opinionEditText.getText().toString().trim(); + + if (TextUtils.isEmpty(opinion)) { + opinionEditText.setError("Campo obligatorio"); + return; + } + requireActivity().getSupportFragmentManager().popBackStack(); listener.onAddOpinion(participant, isPreOpinion, opinion); }); @@ -45,11 +56,16 @@ public class OpinionFragment extends Fragment { @Override public void onAttach(@NonNull Context context) { super.onAttach(context); - listener = (OnAddOpinionListener) context; + + if (context instanceof OnAddOpinionListener) { + listener = (OnAddOpinionListener) context; + } else { + throw new RuntimeException(context + " must implement OnAddOpinionListener"); + } + if (getArguments() != null) { participant = (ActivityResident) getArguments().getSerializable("participant"); isPreOpinion = getArguments().getBoolean("isPreOpinion"); } - } } diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/ParticipantDetailFragment.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/ParticipantDetailFragment.java new file mode 100644 index 0000000..bcf152d --- /dev/null +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/ParticipantDetailFragment.java @@ -0,0 +1,133 @@ +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.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.andresgmoran.apptrabajadores.R; +import com.andresgmoran.apptrabajadores.interfaces.IOnClickOnBackButtonListener; +import com.andresgmoran.apptrabajadores.models.Activity; +import com.andresgmoran.apptrabajadores.models.ActivityResident; +import com.andresgmoran.apptrabajadores.models.Resident; +import com.andresgmoran.apptrabajadores.repository.AppDataRepository; + +import java.util.List; + +public class ParticipantDetailFragment extends Fragment { + + private ImageButton backButton; + + private TextView participantNameTextView; + private ImageView participantImageView; + private TextView participantActivityTextView; + private TextView needMaterialHelpTextView; + private TextView needHumanHelpTextView; + private TextView preOpinionTextView; + private TextView postOpinionTextView; + + private ActivityResident participant; + private List residents; + private List activities; + + public interface IOnRefreshParticipantDetailListener { + void onRefreshParticipantDetail(); + } + + private IOnRefreshParticipantDetailListener refreshParticipantDetailListener; + private IOnClickOnBackButtonListener backButtonListener; + + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_participant_detail, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + View statusBar = requireActivity().findViewById(R.id.status_bar_background); + statusBar.setBackgroundColor(Color.parseColor("#0062FF")); + + View participantCardView = view.findViewById(R.id.participant_card_view); + + SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_participant_detail); + swipeRefreshLayout.setOnRefreshListener(() -> { + refreshParticipantDetailListener.onRefreshParticipantDetail(); + swipeRefreshLayout.setRefreshing(false); + }); + + backButton = participantCardView.findViewById(R.id.back_button); + backButton.setOnClickListener(v -> backButtonListener.onClickOnBackButton()); + + + participantNameTextView = participantCardView.findViewById( R.id.banner_name_game); + participantImageView = participantCardView.findViewById(R.id.image_item_person_banner); + participantActivityTextView = view.findViewById(R.id.tv_activity_participant); + needMaterialHelpTextView = view.findViewById(R.id.tv_need_material_help_participant_detail); + needHumanHelpTextView = view.findViewById(R.id.tv_need_human_help_participant_detail); + preOpinionTextView = view.findViewById(R.id.tv_pre_opinion_participant_detail); + postOpinionTextView = view.findViewById(R.id.tv_post_opinion_participant_detail); + + for (Resident resident : residents) { + if (resident.getId().equals(participant.getIdResident())) { + participantNameTextView.setText(resident.getName() + " " + resident.getSurnames()); + //participantImageView.setImageBitmap(resident.getImage()); + break; + } + } + + for (Activity activity : activities) { + if (activity.getId().equals(participant.getActivityId())) { + participantActivityTextView.setText(activity.getName()); + break; + } + } + + if (participant.isMaterialHelp()) + needMaterialHelpTextView.setText("Si"); + else + needMaterialHelpTextView.setText("No"); + + if (participant.isHumanHelp()) + needHumanHelpTextView.setText("Si"); + else + needHumanHelpTextView.setText("No"); + + if (participant.getPreOpinion().isEmpty()) + preOpinionTextView.setText("No hay opinión previa"); + else + preOpinionTextView.setText(participant.getPreOpinion()); + + if (participant.getPostOpinion().isEmpty()) + postOpinionTextView.setText("No hay opinión posterior"); + else + postOpinionTextView.setText(participant.getPostOpinion()); + + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + if (getArguments() != null) { + participant = (ActivityResident) getArguments().getSerializable("participant"); + } + residents = AppDataRepository.getInstance().getResidents(); + activities = AppDataRepository.getInstance().getActivities(); + + refreshParticipantDetailListener = (IOnRefreshParticipantDetailListener) context; + backButtonListener = (IOnClickOnBackButtonListener) context; + } +} diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/ParticipantSelectionDialogFragment.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/ParticipantSelectionDialogFragment.java index 1c86008..62c0a00 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/ParticipantSelectionDialogFragment.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/activities/ParticipantSelectionDialogFragment.java @@ -12,6 +12,7 @@ import androidx.fragment.app.DialogFragment; import com.andresgmoran.apptrabajadores.models.Activity; import com.andresgmoran.apptrabajadores.models.ActivityResident; import com.andresgmoran.apptrabajadores.models.Resident; +import com.andresgmoran.apptrabajadores.repository.AppDataRepository; import java.util.ArrayList; import java.util.List; @@ -26,8 +27,7 @@ public class ParticipantSelectionDialogFragment extends DialogFragment { private List participants; private List residentList; - public ParticipantSelectionDialogFragment(Activity activityId, List participants, List residents) { - this.residentList = residents; + public ParticipantSelectionDialogFragment(Activity activityId, List participants) { this.participants = participants; this.activityId = activityId; } @@ -68,6 +68,8 @@ public class ParticipantSelectionDialogFragment extends DialogFragment { @Override public void onAttach(@NonNull Context context) { super.onAttach(context); + + residentList = AppDataRepository.getInstance().getResidents(); if (context instanceof OnParticipantSelectedListener) { listener = (OnParticipantSelectedListener) context; } else { diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/game/GameFragment.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/game/GameFragment.java index 155698f..290d1ce 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/game/GameFragment.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/game/GameFragment.java @@ -2,6 +2,7 @@ package com.andresgmoran.apptrabajadores.ui.fragments.game; import android.content.Context; +import android.graphics.Color; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -23,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.repository.AppDataRepository; import com.andresgmoran.apptrabajadores.ui.MainActivity; import java.time.LocalDateTime; @@ -30,10 +32,15 @@ import java.util.ArrayList; import java.util.List; public class GameFragment extends Fragment { - private List gameStats; - private List residents; + private List gameStats = AppDataRepository.getInstance().getGameStats(); + private List residents = AppDataRepository.getInstance().getResidents(); private Game game; + public interface IOnRefreshGameListener { + void onRefreshGameStats(); + } + private IOnRefreshGameListener refreshGameListener; + private IOnClickOnBackButtonListener backButtonListener; private TextView gameNameTextView; @@ -50,6 +57,10 @@ public class GameFragment extends Fragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + + View statusBar = requireActivity().findViewById(R.id.status_bar_background); + statusBar.setBackgroundColor(Color.parseColor("#0062FF")); + gameNameTextView = view.findViewById(R.id.banner_name_game); numberOfGamesLastWeekTextView = view.findViewById(R.id.tv_number_of_games_last_week); totalGamesPlayedTextView = view.findViewById(R.id.tv_total_games_played); @@ -58,7 +69,7 @@ public class GameFragment extends Fragment { SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_game); swipeRefreshLayout.setOnRefreshListener(() -> { - ((MainActivity) requireActivity()).refreshGameStatsAndReload(); + refreshGameListener.onRefreshGameStats(); swipeRefreshLayout.setRefreshing(false); }); @@ -142,11 +153,10 @@ public class GameFragment extends Fragment { super.onAttach(context); if(getArguments() != null) { - gameStats = (List) getArguments().getSerializable("gameStats"); - residents = (List) getArguments().getSerializable("residents"); game = (Game) getArguments().getSerializable("game"); } + refreshGameListener = (IOnRefreshGameListener) context; backButtonListener = (IOnClickOnBackButtonListener) context; } } diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/gameDetail/GameDetailFragment.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/gameDetail/GameDetailFragment.java index a67de65..0d81d16 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/gameDetail/GameDetailFragment.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/gameDetail/GameDetailFragment.java @@ -1,6 +1,7 @@ package com.andresgmoran.apptrabajadores.ui.fragments.gameDetail; import android.content.Context; +import android.graphics.Color; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -21,6 +22,7 @@ import com.andresgmoran.apptrabajadores.models.Game; import com.andresgmoran.apptrabajadores.models.Resident; import com.andresgmoran.apptrabajadores.models.User; import com.andresgmoran.apptrabajadores.models.gameStats.GameStat; +import com.andresgmoran.apptrabajadores.repository.AppDataRepository; import com.andresgmoran.apptrabajadores.ui.MainActivity; import java.util.List; @@ -29,16 +31,19 @@ public class GameDetailFragment extends Fragment { public interface IOnAddObservationListener { void onAddObservation(String observation, long gameId, long gameStatId); - List getUsers(); } + public interface IOnRefreshGameStatsListener { + void onRefreshGameStats(); + } + private IOnRefreshGameStatsListener refreshGameStatsListener; private IOnAddObservationListener addObservationListener; private IOnClickOnBackButtonListener backButtonListener; private GameStat gameStat; private Resident gameStatResident; private Game gameStatGame; - private User actualUser; - private List users; + private User actualUser = AppDataRepository.getInstance().getActualUser(); + private List users = AppDataRepository.getInstance().getUsers(); private TextView residentNameTextView; private TextView gameNameTextView; @@ -57,10 +62,13 @@ public class GameDetailFragment extends Fragment { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + View statusBar = requireActivity().findViewById(R.id.status_bar_background); + statusBar.setBackgroundColor(Color.parseColor("#0062FF")); + SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_game_detail); swipeRefreshLayout.setOnRefreshListener(() -> { - ((MainActivity) requireActivity()).refreshGameStatsAndReload(); + refreshGameStatsListener.onRefreshGameStats(); swipeRefreshLayout.setRefreshing(false); }); @@ -131,16 +139,14 @@ public class GameDetailFragment extends Fragment { public void onAttach(@NonNull Context context) { super.onAttach(context); + refreshGameStatsListener = (IOnRefreshGameStatsListener) context; addObservationListener = (IOnAddObservationListener) context; backButtonListener = (IOnClickOnBackButtonListener) context; - 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"); } } } diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/home/HomeFragment.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/home/HomeFragment.java index ac2977f..562bf78 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/home/HomeFragment.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/home/HomeFragment.java @@ -2,6 +2,7 @@ package com.andresgmoran.apptrabajadores.ui.fragments.home; import android.content.Context; import android.graphics.Bitmap; +import android.graphics.Color; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -11,8 +12,8 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.widget.NestedScrollView; import androidx.fragment.app.Fragment; -import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -28,29 +29,23 @@ 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.ui.MainActivity; -import com.andresgmoran.apptrabajadores.viewmodel.HomeViewModel; +import com.andresgmoran.apptrabajadores.repository.AppDataRepository; +import com.google.android.material.button.MaterialButton; +import java.time.LocalDateTime; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class HomeFragment extends Fragment { - public interface IOnAttachListener { - List getResidents(); - List getGameStats(); - List getGames(); - User getActualUser(); - Bitmap getActualUserImage(); - } - - private List residents; - private List gameStats; - private List games; - private User user; - private Bitmap userImageBitmap; + private List residents = AppDataRepository.getInstance().getResidents(); + private List gameStats = AppDataRepository.getInstance().getGameStats(); + private List games = AppDataRepository.getInstance().getGames(); + private User user = AppDataRepository.getInstance().getActualUser(); + private Bitmap userImageBitmap = AppDataRepository.getInstance().getActualUserImage(); private TextView userNameTextView; private ImageView userImage; @@ -63,6 +58,17 @@ public class HomeFragment extends Fragment { private GamesAdapter gamesAdapter; private ResidentsAdapter residentsAdapter; + private LastGamesAdapter lastGamesAdapter; + + public interface IOnRefreshHomeListener { + void onRefreshHome(); + } + private IOnRefreshHomeListener refreshListener; + + public interface IOnClickOnAddParticipantListener { + void onClickOnAddParticipant(); + } + private IOnClickOnAddParticipantListener addParticipantListener; @Nullable @Override @@ -73,18 +79,23 @@ public class HomeFragment extends Fragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + + View statusBar = requireActivity().findViewById(R.id.status_bar_background); + statusBar.setBackgroundColor(Color.parseColor("#CCCCCC")); + setupSwipeRefresh(view); setupUserInfo(view); setupLastGamesList(view); setupGamesList(view); setupResidentsList(view); setupFilterButtons(view); + setupFab(view); } private void setupSwipeRefresh(View view) { SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_home); swipeRefreshLayout.setOnRefreshListener(() -> { - ((MainActivity) requireActivity()).refreshGameStatsAndReload(); + refreshListener.onRefreshHome(); swipeRefreshLayout.setRefreshing(false); }); } @@ -100,8 +111,8 @@ public class HomeFragment extends Fragment { emptyLatestGamesText = view.findViewById(R.id.tv_lastgames_empty_home); recyclerViewLastGames = view.findViewById(R.id.latestGames_recycleView_home); - LastGamesAdapter adapter = new LastGamesAdapter(gameStats, games, residents, (IOClickOnGameStatsListener) requireActivity()); - recyclerViewLastGames.setAdapter(adapter); + lastGamesAdapter = new LastGamesAdapter(gameStats, games, residents, (IOClickOnGameStatsListener) requireActivity()); + recyclerViewLastGames.setAdapter(lastGamesAdapter); recyclerViewLastGames.setHasFixedSize(true); recyclerViewLastGames.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false)); @@ -118,7 +129,9 @@ public class HomeFragment extends Fragment { emptyGamesText = view.findViewById(R.id.tv_games_empty_home); recyclerViewGames = view.findViewById(R.id.games_recycleView_home); - gamesAdapter = new GamesAdapter(games, (IOClickOnGameListener) requireActivity()); + Map weeklyPercentages = calculateWeeklyGamePercentages(); + + gamesAdapter = new GamesAdapter(games, (IOClickOnGameListener) requireActivity(), weeklyPercentages); recyclerViewGames.setAdapter(gamesAdapter); recyclerViewGames.setHasFixedSize(true); recyclerViewGames.setLayoutManager(new LinearLayoutManager(getActivity())); @@ -132,6 +145,29 @@ public class HomeFragment extends Fragment { } } + private Map calculateWeeklyGamePercentages() { + LocalDateTime oneWeekAgo = LocalDateTime.now().minusDays(7); + Map countMap = new HashMap<>(); + + for (Game game : games) { + long count = gameStats.stream() + .filter(stat -> stat.getGameId() == game.getId()) + .filter(stat -> stat.getDateTime().isAfter(oneWeekAgo)) + .count(); + countMap.put(game.getId(), count); + } + + long total = countMap.values().stream().mapToLong(Long::longValue).sum(); + Map percentageMap = new HashMap<>(); + + for (Map.Entry entry : countMap.entrySet()) { + double percentage = total > 0 ? (entry.getValue() * 100.0) / total : 0; + percentageMap.put(entry.getKey(), percentage); + } + + return percentageMap; + } + private void setupResidentsList(View view) { emptyResidentsText = view.findViewById(R.id.tv_residents_empty_home); recyclerViewResidents = view.findViewById(R.id.residents_recycleView_home); @@ -148,63 +184,104 @@ public class HomeFragment extends Fragment { recyclerViewResidents.setVisibility(View.VISIBLE); emptyResidentsText.setVisibility(View.GONE); } + + filterResidentsList("default"); } private void setupFilterButtons(View view) { View filterGamesButton = view.findViewById(R.id.filter_games_list_button); View filterResidentsButton = view.findViewById(R.id.filter_residents_list_button); + View filterLastGamesButton = view.findViewById(R.id.filter_lastgames_list_button); filterGamesButton.setOnClickListener(v -> showGamesFilterDialog()); filterResidentsButton.setOnClickListener(v -> showResidentsFilterDialog()); + filterLastGamesButton.setOnClickListener(v -> showLastGamesFilterDialog()); + } + + private void setupFab(View view) { + MaterialButton fab = view.findViewById(R.id.add_resident_button); + + fab.setOnClickListener(v -> + addParticipantListener.onClickOnAddParticipant() + ); + + NestedScrollView scrollView = view.findViewById(R.id.nested_scroll_view_home); + 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) { + fab.animate().translationY(fab.getHeight() + 50).alpha(0.0f).setDuration(200).withEndAction(() -> fab.setVisibility(View.GONE)); + isButtonVisible = false; + } else if (scrollY < lastScrollY - 10 && !isButtonVisible) { + 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) { super.onAttach(context); - IOnAttachListener attachListener = (IOnAttachListener) context; - user = attachListener.getActualUser(); - userImageBitmap = attachListener.getActualUserImage(); - residents = attachListener.getResidents(); - games = attachListener.getGames(); - gameStats = attachListener.getGameStats(); + refreshListener = (IOnRefreshHomeListener) context; + addParticipantListener = (IOnClickOnAddParticipantListener) context; } private void showGamesFilterDialog() { - String[] options = {"A-Z", "Z-A", "Más jugados"}; + String[] options = {getString(R.string.game_name_a_z_filter_text), getString(R.string.game_name_z_a_filter_text), getString(R.string.most_played_filter_text)}; new androidx.appcompat.app.AlertDialog.Builder(requireContext()) - .setTitle("Filtrar juegos") + .setTitle(R.string.filter_games_title) .setItems(options, (dialog, which) -> filterGamesList(options[which])) .show(); } private void showResidentsFilterDialog() { - String[] options = {"A-Z", "Z-A", "Fecha de nacimiento"}; + String[] options = {getString(R.string.resident_name_a_z_filter_text), getString(R.string.resident_name_z_a_filter_text), getString(R.string.date_of_birth_filter_text)}; new androidx.appcompat.app.AlertDialog.Builder(requireContext()) - .setTitle("Filtrar residentes") + .setTitle(R.string.filter_residents_title) .setItems(options, (dialog, which) -> filterResidentsList(options[which])) .show(); } + private void showLastGamesFilterDialog() { + String[] options = { + getString(R.string.resident_name_a_z_filter_text), + getString(R.string.resident_name_z_a_filter_text), + getString(R.string.game_name_a_z_filter_text), + getString(R.string.game_name_z_a_filter_text), + getString(R.string.first_to_last_filter_text), + getString(R.string.last_to_first_filter_text), + }; + + new androidx.appcompat.app.AlertDialog.Builder(requireContext()) + .setTitle(getString( R.string.filter_last_games_title)) + .setItems(options, (dialog, which) -> filterLastGamesList(options[which])) + .show(); + } + private void filterGamesList(String option) { List filteredList = new ArrayList<>(games); - switch (option) { - case "A-Z": - filteredList.sort(Comparator.comparing(Game::getName)); - break; - case "Z-A": - filteredList.sort((g1, g2) -> g2.getName().compareTo(g1.getName())); - break; - case "Más jugados": - filteredList.sort((g1, g2) -> { - long count1 = gameStats.stream().filter(stat -> stat.getGameId() == g1.getId()).count(); - long count2 = gameStats.stream().filter(stat -> stat.getGameId() == g2.getId()).count(); - return Long.compare(count2, count1); - }); - break; + if (option.equals(getString(R.string.game_name_a_z_filter_text))) { + filteredList.sort(Comparator.comparing(Game::getName)); + } else if (option.equals(getString(R.string.game_name_z_a_filter_text))) { + filteredList.sort((g1, g2) -> g2.getName().compareTo(g1.getName())); + } else if (option.equals(getString(R.string.most_played_filter_text))) { + filteredList.sort((g1, g2) -> { + long count1 = gameStats.stream().filter(stat -> stat.getGameId() == g1.getId()).count(); + long count2 = gameStats.stream().filter(stat -> stat.getGameId() == g2.getId()).count(); + return Long.compare(count2, count1); + }); } gamesAdapter.updateData(filteredList); @@ -214,19 +291,56 @@ public class HomeFragment extends Fragment { private void filterResidentsList(String option) { List filteredList = new ArrayList<>(residents); - switch (option) { - case "A-Z": - filteredList.sort(Comparator.comparing(Resident::getName)); - break; - case "Z-A": - filteredList.sort((r1, r2) -> r2.getName().compareTo(r1.getName())); - break; - case "Fecha de nacimiento": - filteredList.sort(Comparator.comparing(Resident::getBirthDate)); - break; + if (option.equals(getString(R.string.resident_name_a_z_filter_text))) { + filteredList.sort(Comparator.comparing(Resident::getName)); + } else if (option.equals(getString(R.string.resident_name_z_a_filter_text))) { + filteredList.sort((r1, r2) -> r2.getName().compareTo(r1.getName())); + } else if (option.equals(getString(R.string.date_of_birth_filter_text))) { + filteredList.sort(Comparator.comparing(Resident::getBirthDate)); + } else { + filteredList.sort((r1, r2) -> Long.compare(r2.getId(), r1.getId())); } residentsAdapter.updateData(filteredList); recyclerViewResidents.scrollToPosition(0); } -} + + private void filterLastGamesList(String option) { + List filteredList = new ArrayList<>(gameStats); + + if (option.equals(getString(R.string.resident_name_a_z_filter_text))) { + filteredList.sort(Comparator.comparing(stat -> getResidentNameById(stat.getResidentId()))); + } else if (option.equals(getString(R.string.resident_name_z_a_filter_text))) { + filteredList.sort((s1, s2) -> getResidentNameById(s2.getResidentId()).compareTo(getResidentNameById(s1.getResidentId()))); + } else if (option.equals(getString(R.string.game_name_a_z_filter_text))) { + filteredList.sort(Comparator.comparing(stat -> getGameNameById(stat.getGameId()))); + } else if (option.equals(getString(R.string.game_name_z_a_filter_text))) { + filteredList.sort((s1, s2) -> getGameNameById(s2.getGameId()).compareTo(getGameNameById(s1.getGameId()))); + } else if (option.equals(getString(R.string.first_to_last_filter_text))) { + filteredList.sort(Comparator.comparing(GameStat::getDateTime)); + } else if (option.equals(getString(R.string.last_to_first_filter_text))) { + filteredList.sort((s1, s2) -> s2.getDateTime().compareTo(s1.getDateTime())); + } else { + filteredList.sort((s1, s2) -> s2.getDateTime().compareTo(s1.getDateTime())); + } + + lastGamesAdapter.updateData(filteredList); + recyclerViewLastGames.scrollToPosition(0); + } + + private String getResidentNameById(Long id) { + return residents.stream() + .filter(r -> r.getId().equals(id)) + .map(Resident::getName) + .findFirst() + .orElse(""); + } + + private String getGameNameById(Long id) { + return games.stream() + .filter(g -> g.getId().equals(id)) + .map(Game::getName) + .findFirst() + .orElse(""); + } +} \ No newline at end of file diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/residence/ResidenceDetailFragment.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/residence/ResidenceDetailFragment.java new file mode 100644 index 0000000..0302e80 --- /dev/null +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/residence/ResidenceDetailFragment.java @@ -0,0 +1,311 @@ +package com.andresgmoran.apptrabajadores.ui.fragments.residence; + +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.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.cardview.widget.CardView; +import androidx.fragment.app.Fragment; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.andresgmoran.apptrabajadores.R; +import com.andresgmoran.apptrabajadores.interfaces.IOnClickOnBackButtonListener; +import com.andresgmoran.apptrabajadores.models.Game; +import com.andresgmoran.apptrabajadores.models.Residence; +import com.andresgmoran.apptrabajadores.models.Resident; +import com.andresgmoran.apptrabajadores.models.gameStats.GameStat; +import com.andresgmoran.apptrabajadores.repository.AppDataRepository; +import com.andresgmoran.apptrabajadores.ui.graphics.CustomBarChartView; +import com.andresgmoran.apptrabajadores.ui.graphics.CustomPieChartView; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class ResidenceDetailFragment extends Fragment { + + private TextView residenceNameTextView; + private TextView totalResidentsTextView; + private TextView residentsTakenOutTextView; + private TextView allGamesTextView; + private TextView gamesLastWeekTextView; + private TextView statsEmptyTextView; + + private CardView pieChartCardView; + private CustomPieChartView pieChart; + private LinearLayout barChartsContainer; + + private Residence residence; + private List residents; + private List residentsTakenOut; + private List gameStats; + private List games; + + public interface IOnRefreshResidenceDetailListener { + void onRefreshResidenceDetail(); + } + + private IOnRefreshResidenceDetailListener refreshListener; + private IOnClickOnBackButtonListener backButtonListener; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_residence_detail, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + View statusBar = requireActivity().findViewById(R.id.status_bar_background); + statusBar.setBackgroundColor(Color.parseColor("#0062FF")); + + setupSwipeRefresh(view); + setupBackButton(view); + + residenceNameTextView = view.findViewById(R.id.residence_detail_name); + totalResidentsTextView = view.findViewById(R.id.tv_residents_residence_detail); + residentsTakenOutTextView = view.findViewById(R.id.tv_residents_taken_down_residence_detail); + allGamesTextView = view.findViewById(R.id.tv_total_games_residence_detail); + gamesLastWeekTextView = view.findViewById(R.id.tv_games_last_week_residence_detail); + updateUI(); + + statsEmptyTextView = view.findViewById(R.id.tv_stats_empty_residence_detail); + pieChartCardView = view.findViewById(R.id.pieCard_residence_detail); + pieChart = view.findViewById(R.id.pieChart_residence_detail); + barChartsContainer = view.findViewById(R.id.barChartsContainer_residence_detail); + + if(gameStats.isEmpty()){ + pieChartCardView.setVisibility(View.GONE); + barChartsContainer.setVisibility(View.GONE); + statsEmptyTextView.setVisibility(View.VISIBLE); + } else { + statsEmptyTextView.setVisibility(View.GONE); + pieChartCardView.setVisibility(View.VISIBLE); + barChartsContainer.setVisibility(View.VISIBLE); + pieChart(view); + generateBarCharts(view); + } + } + + private void updateUI() { + if (residence != null) { + residenceNameTextView.setText(residence.getName()); + totalResidentsTextView.setText(String.valueOf(residence.getResidents().size())); + residentsTakenOutTextView.setText(String.valueOf(residentsTakenOut.size())); + allGamesTextView.setText(String.valueOf(gameStats.size())); + + int gamesLastWeekCount = 0; + for (GameStat gameStat : gameStats) { + if (gameStat.getDateTime() != null && + gameStat.getDateTime().toLocalDate().isAfter(java.time.LocalDate.now().minusDays(7))) { + gamesLastWeekCount++; + } + } + gamesLastWeekTextView.setText(String.valueOf(gamesLastWeekCount)); + } + } + + private void setupSwipeRefresh(View view) { + SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_residence_detail); + swipeRefreshLayout.setOnRefreshListener(() -> { + refreshListener.onRefreshResidenceDetail(); + swipeRefreshLayout.setRefreshing(false); + }); + } + + private void setupBackButton(View view) { + ImageButton backButton; + backButton = view.findViewById(R.id.back_button); + backButton.setOnClickListener(v -> + backButtonListener.onClickOnBackButton()); + } + + private void pieChart(View view){ + TextView[] gameNames = new TextView[]{ + view.findViewById(R.id.pie_game_1_name_residence_detail), + view.findViewById(R.id.pie_game_2_name_residence_detail), + view.findViewById(R.id.pie_game_3_name_residence_detail), + view.findViewById(R.id.pie_game_4_name_residence_detail), + view.findViewById(R.id.pie_game_5_name_residence_detail) + }; + + // Mapa juegoId → número de partidas jugadas + Map gameCountMap = new HashMap<>(); + List residentIds = residence.getResidents(); + + for (GameStat stat : gameStats) { + if (residentIds.contains(stat.getResidentId())) { + Long gameId = stat.getGameId(); + gameCountMap.put(gameId, gameCountMap.getOrDefault(gameId, 0) + 1); + } + } + + int totalPartidas = gameCountMap.values().stream().mapToInt(Integer::intValue).sum(); + if (totalPartidas == 0) { + pieChart.setVisibility(View.GONE); + view.findViewById(R.id.tv_stats_empty_residence_detail).setVisibility(View.VISIBLE); + for (TextView tv : gameNames) tv.setVisibility(View.GONE); + return; + } + + float[] pieValues = new float[gameCountMap.size()]; + int[] pieColors = new int[gameCountMap.size()]; + int[] colorPool = { Color.YELLOW, Color.RED, Color.GREEN, Color.MAGENTA, Color.CYAN }; + + int index = 0; + for (Map.Entry entry : gameCountMap.entrySet()) { + float porcentaje = (entry.getValue() * 100f) / totalPartidas; + pieValues[index] = porcentaje; + pieColors[index] = colorPool[index % colorPool.length]; + + String nombreJuego = ""; + for (Game g : games) { + if (g.getId().equals(entry.getKey())) { + nombreJuego = g.getName(); + break; + } + } + + if (index < gameNames.length) { + String texto = nombreJuego + " - " + String.format("%.1f", porcentaje) + "%"; + gameNames[index].setText(texto); + gameNames[index].setVisibility(View.VISIBLE); + gameNames[index].setBackgroundColor(colorPool[index % colorPool.length]); + } + + index++; + } + + // Ocultar los TextView sobrantes + for (int i = index; i < gameNames.length; i++) { + gameNames[i].setVisibility(View.GONE); + } + + pieChart.setVisibility(View.VISIBLE); + pieChart.setData(pieValues, pieColors); + } + + private void generateBarCharts(View view) { + barChartsContainer.removeAllViews(); + + // Mapa de juego → [día de la semana → cantidad de partidas] + Map> juegosPorDias = new HashMap<>(); + List residentIds = residence.getResidents(); + + for (GameStat stat : gameStats) { + if (residentIds.contains(stat.getResidentId())) { + Long gameId = stat.getGameId(); + int dia = stat.getDateTime().getDayOfWeek().getValue(); // 1 = lunes, ..., 7 = domingo + + juegosPorDias + .computeIfAbsent(gameId, k -> new HashMap<>()) + .put(dia, juegosPorDias.get(gameId).getOrDefault(dia, 0) + 1); + } + } + + int index = 0; + LinearLayout currentRow = null; + + for (Map.Entry> entry : juegosPorDias.entrySet()) { + if (index >= 5) break; + + if (index % 2 == 0) { + currentRow = new LinearLayout(requireContext()); + currentRow.setOrientation(LinearLayout.HORIZONTAL); + LinearLayout.LayoutParams rowParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ); + rowParams.setMargins(0, 0, 0, 32); + currentRow.setLayoutParams(rowParams); + barChartsContainer.addView(currentRow); + } + + String nombreJuego = ""; + for (Game g : games) { + if (g.getId().equals(entry.getKey())) { + nombreJuego = g.getName(); + break; + } + } + + float[] datos = new float[7]; + Map actividadDias = entry.getValue(); + for (int i = 1; i <= 7; i++) { + datos[i - 1] = actividadDias.getOrDefault(i, 0); + } + + // Layout vertical por gráfico + LinearLayout chartLayout = new LinearLayout(requireContext()); + chartLayout.setOrientation(LinearLayout.VERTICAL); + chartLayout.setPadding(16, 16, 16, 16); + + TextView title = new TextView(requireContext()); + title.setText(nombreJuego); + title.setTextColor(Color.BLACK); + title.setTextSize(14); + chartLayout.addView(title); + + TextView subtitle = new TextView(requireContext()); + subtitle.setText("Actividad semanal"); + subtitle.setTextColor(Color.GRAY); + subtitle.setTextSize(12); + chartLayout.addView(subtitle); + + CustomBarChartView chart = new CustomBarChartView(requireContext(), null); + chart.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + 500 + )); + chart.setData(datos); + chartLayout.addView(chart); + + CardView cardView = new CardView(requireContext()); + cardView.setCardElevation(6f); + cardView.setRadius(32f); + cardView.setUseCompatPadding(true); + cardView.setCardBackgroundColor(Color.WHITE); + cardView.addView(chartLayout); + + LinearLayout.LayoutParams colParams = new LinearLayout.LayoutParams( + 0, + ViewGroup.LayoutParams.WRAP_CONTENT, + 1f + ); + colParams.setMargins(8, 0, 8, 0); + cardView.setLayoutParams(colParams); + + if (currentRow != null) { + currentRow.addView(cardView); + } + + index++; + } + } + + + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + residence = AppDataRepository.getInstance().getResidence(); + residents = AppDataRepository.getInstance().getResidents(); + residentsTakenOut = AppDataRepository.getInstance().getResidentsTakenOut(); + gameStats = AppDataRepository.getInstance().getGameStats(); + games = AppDataRepository.getInstance().getGames(); + + refreshListener = (IOnRefreshResidenceDetailListener) context; + backButtonListener = (IOnClickOnBackButtonListener) context; + } +} diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/resident/AddResidentFragment.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/resident/AddResidentFragment.java new file mode 100644 index 0000000..01bfab0 --- /dev/null +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/resident/AddResidentFragment.java @@ -0,0 +1,153 @@ +package com.andresgmoran.apptrabajadores.ui.fragments.resident; + +import android.content.Context; +import android.os.Bundle; +import android.text.TextUtils; +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 java.time.LocalDate; +import java.time.format.DateTimeParseException; + +public class AddResidentFragment extends Fragment { + + public interface OnAddResidentListener { + void onAddResidentFormSubmitted( + String nombre, + String apellido, + LocalDate fechaNacimiento, + String documentoIdentidad, + String familiar1, + String familiar2, + int year, + int month + ); + } + + private OnAddResidentListener listener; + + private EditText nombreEditText; + private EditText apellidoEditText; + private EditText fechaNacimientoEditText; + private EditText documentoIdentidadEditText; + private EditText familiar1EditText; + private EditText familiar2EditText; + private EditText yearEditText; + private EditText monthEditText; + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + if (context instanceof OnAddResidentListener) { + listener = (OnAddResidentListener) context; + } else { + throw new RuntimeException(context + " debe implementar OnAddResidentListener"); + } + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_add_resident, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + nombreEditText = view.findViewById(R.id.et_add_resident_nombre); + apellidoEditText = view.findViewById(R.id.et_add_resident_apellido); + fechaNacimientoEditText = view.findViewById(R.id.et_add_resident_fecha_nacimiento); + documentoIdentidadEditText = view.findViewById(R.id.et_add_resident_documento_identidad); + familiar1EditText = view.findViewById(R.id.et_add_resident_familiar_1); + familiar2EditText = view.findViewById(R.id.et_add_resident_familiar_2); + yearEditText = view.findViewById(R.id.et_add_resident_year); + monthEditText = view.findViewById(R.id.et_add_resident_month); + + Button guardarButton = view.findViewById(R.id.btn_add_resident_guardar); + guardarButton.setOnClickListener(v -> { + if (validarCampos()) { + try { + String nombre = nombreEditText.getText().toString().trim(); + String apellido = apellidoEditText.getText().toString().trim(); + LocalDate fechaNacimiento = LocalDate.parse(fechaNacimientoEditText.getText().toString().trim()); + String documento = documentoIdentidadEditText.getText().toString().trim(); + String familiar1 = familiar1EditText.getText().toString().trim(); + String familiar2 = familiar2EditText.getText().toString().trim(); + int year = Integer.parseInt(yearEditText.getText().toString().trim()); + int month = Integer.parseInt(monthEditText.getText().toString().trim()); + + listener.onAddResidentFormSubmitted( + nombre, apellido, fechaNacimiento, documento, familiar1, familiar2, year, month + ); + } catch (DateTimeParseException e) { + fechaNacimientoEditText.setError("Formato inválido (usar YYYY-MM-DD)"); + } catch (NumberFormatException e) { + if (!isInteger(yearEditText.getText().toString().trim())) { + yearEditText.setError("Año inválido"); + } + if (!isInteger(monthEditText.getText().toString().trim())) { + monthEditText.setError("Mes inválido"); + } + } + } + }); + } + + private boolean validarCampos() { + boolean valido = true; + + if (TextUtils.isEmpty(nombreEditText.getText())) { + nombreEditText.setError("Campo obligatorio"); + valido = false; + } + if (TextUtils.isEmpty(apellidoEditText.getText())) { + apellidoEditText.setError("Campo obligatorio"); + valido = false; + } + if (TextUtils.isEmpty(fechaNacimientoEditText.getText())) { + fechaNacimientoEditText.setError("Campo obligatorio"); + valido = false; + } + if (TextUtils.isEmpty(documentoIdentidadEditText.getText())) { + documentoIdentidadEditText.setError("Campo obligatorio"); + valido = false; + } + if (TextUtils.isEmpty(familiar1EditText.getText())) { + familiar1EditText.setError("Campo obligatorio"); + valido = false; + } + if (TextUtils.isEmpty(familiar2EditText.getText())) { + familiar2EditText.setError("Campo obligatorio"); + valido = false; + } + if (TextUtils.isEmpty(yearEditText.getText())) { + yearEditText.setError("Campo obligatorio"); + valido = false; + } + if (TextUtils.isEmpty(monthEditText.getText())) { + monthEditText.setError("Campo obligatorio"); + valido = false; + } + + return valido; + } + + private boolean isInteger(String value) { + try { + Integer.parseInt(value); + return true; + } catch (NumberFormatException e) { + return false; + } + } +} diff --git a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/resident/ResidentFragment.java b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/resident/ResidentFragment.java index c28e9f5..e771d34 100644 --- a/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/resident/ResidentFragment.java +++ b/AppTrabajadores/app/src/main/java/com/andresgmoran/apptrabajadores/ui/fragments/resident/ResidentFragment.java @@ -12,7 +12,11 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; import androidx.cardview.widget.CardView; +import androidx.core.content.ContextCompat; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -25,10 +29,13 @@ 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.repository.AppDataRepository; import com.andresgmoran.apptrabajadores.ui.graphics.CustomBarChartView; import com.andresgmoran.apptrabajadores.ui.graphics.CustomPieChartView; + import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -36,16 +43,24 @@ import java.util.Objects; public class ResidentFragment extends Fragment { private Resident resident; - private List games; - private List gameStats; + private List games = AppDataRepository.getInstance().getGames(); + private List gameStats = AppDataRepository.getInstance().getGameStats(); private ImageButton backButton; private TextView residentName; - private CardView pieCard; private TextView tvLastGamesEmpty; private TextView tvStatsEmpty; + private RecyclerView recyclerViewLastGames; + private LastGamesAdapter lastGamesAdapter; + private List filteredStats; + + public interface IOnRefreshResidentListener { + void onRefreshGameStats(); + } + + private IOnRefreshResidentListener refreshListener; private IOnClickOnBackButtonListener backButtonListener; @Nullable @@ -58,43 +73,47 @@ public class ResidentFragment extends Fragment { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_resident); + View statusBar = requireActivity().findViewById(R.id.status_bar_background); + statusBar.setBackgroundColor(Color.parseColor("#0062FF")); + SwipeRefreshLayout swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_resident); swipeRefreshLayout.setOnRefreshListener(() -> { - ((MainActivity) requireActivity()).refreshGameStatsAndReload(); + refreshListener.onRefreshGameStats(); 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); + recyclerViewLastGames = view.findViewById(R.id.latestGames_recycleView_resident); View banner = view.findViewById(R.id.resident_banner); - backButton = banner.findViewById(R.id.back_button); - backButton.setOnClickListener(v -> { - backButtonListener.onClickOnBackButton(); - }); + backButton.setOnClickListener(v -> backButtonListener.onClickOnBackButton()); residentName = banner.findViewById(R.id.banner_name_game); - String fullName = resident.getName() + " " + resident.getSurnames(); - residentName.setText(fullName); - - List filteredStats = new ArrayList<>(); + residentName.setText(resident.getName() + " " + resident.getSurnames()); + filteredStats = new ArrayList<>(); for (GameStat stat : gameStats) { if (Objects.equals(stat.getResidentId(), resident.getId())) { filteredStats.add(stat); } } - LastGamesAdapter lastGamesAdapter = new LastGamesAdapter(filteredStats, games, resident, (IOClickOnGameStatsListener) requireActivity()); - RecyclerView recyclerViewLastGames = view.findViewById(R.id.latestGames_recycleView_resident); + lastGamesAdapter = new LastGamesAdapter(filteredStats, games, resident, (IOClickOnGameStatsListener) requireActivity()); recyclerViewLastGames.setAdapter(lastGamesAdapter); recyclerViewLastGames.setHasFixedSize(true); recyclerViewLastGames.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false)); - if (filteredStats.isEmpty()){ + ImageButton filterButton = view.findViewById(R.id.filter_lastgames_list_button); + filterButton.setOnClickListener(v -> showLastGamesFilterDialog()); + + updateVisibility(view); + } + + private void updateVisibility(View view) { + if (filteredStats.isEmpty()) { pieCard.setVisibility(View.GONE); recyclerViewLastGames.setVisibility(View.GONE); tvLastGamesEmpty.setVisibility(View.VISIBLE); @@ -104,12 +123,66 @@ public class ResidentFragment extends Fragment { recyclerViewLastGames.setVisibility(View.VISIBLE); tvLastGamesEmpty.setVisibility(View.GONE); tvStatsEmpty.setVisibility(View.GONE); - pieChart(view); generateBarCharts(view); } } + private void showLastGamesFilterDialog() { + String[] options = { + "Nombre juego [A-Z]", + "Nombre juego [Z-A]", + "De primera a última", + "default" + }; + + new AlertDialog.Builder(requireContext()) + .setTitle("Filtrar últimas partidas") + .setItems(options, (dialog, which) -> filterLastGamesList(options[which])) + .show(); + } + + private void filterLastGamesList(String option) { + List sortedList = new ArrayList<>(filteredStats); + + switch (option) { + case "Nombre juego [A-Z]": + sortedList.sort(Comparator.comparing(stat -> getGameNameById(stat.getGameId()))); + break; + case "Nombre juego [Z-A]": + sortedList.sort((s1, s2) -> getGameNameById(s2.getGameId()).compareTo(getGameNameById(s1.getGameId()))); + break; + case "De primera a última": + sortedList.sort(Comparator.comparing(GameStat::getDateTime)); + break; + default: + sortedList.sort((s1, s2) -> s2.getDateTime().compareTo(s1.getDateTime())); + break; + } + + lastGamesAdapter.updateData(sortedList); + recyclerViewLastGames.scrollToPosition(0); + } + + private String getGameNameById(Long id) { + return games.stream() + .filter(g -> g.getId().equals(id)) + .map(Game::getName) + .findFirst() + .orElse(""); + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + Bundle args = getArguments(); + if (args != null) { + resident = (Resident) args.getSerializable("resident"); + } + refreshListener = (IOnRefreshResidentListener) context; + backButtonListener = (IOnClickOnBackButtonListener) context; + } + private void pieChart(View view){ CustomPieChartView pieChart = view.findViewById(R.id.pieChart); @@ -262,17 +335,4 @@ public class ResidentFragment extends Fragment { } } - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - Bundle args = getArguments(); - if (args != null) { - resident = (Resident) args.getSerializable("resident"); - games = (ArrayList) args.getSerializable("games"); - gameStats = (ArrayList) args.getSerializable("gameStats"); - } - - backButtonListener = (IOnClickOnBackButtonListener) context; - } - } diff --git a/AppTrabajadores/app/src/main/res/layout/content_main.xml b/AppTrabajadores/app/src/main/res/layout/content_main.xml index 68f689c..0330ccb 100644 --- a/AppTrabajadores/app/src/main/res/layout/content_main.xml +++ b/AppTrabajadores/app/src/main/res/layout/content_main.xml @@ -5,6 +5,15 @@ android:layout_height="match_parent" android:background="#CCCCCC"> + + - -