diff --git a/app/src/main/java.zip b/app/src/main/java.zip index 5d99493..ba60348 100644 Binary files a/app/src/main/java.zip and b/app/src/main/java.zip differ diff --git a/app/src/main/java/com/santiparra/yomitrack/api/ApiClient.java b/app/src/main/java/com/santiparra/yomitrack/api/ApiClient.java index 5017e9d..f659ffb 100644 --- a/app/src/main/java/com/santiparra/yomitrack/api/ApiClient.java +++ b/app/src/main/java/com/santiparra/yomitrack/api/ApiClient.java @@ -7,18 +7,34 @@ import retrofit2.converter.gson.GsonConverterFactory; public class ApiClient { + /** + * URL base del servidor donde está alojada la API del backend. + *

Nota: "10.0.2.2" es una dirección especial utilizada para acceder al localhost + * del host desde el emulador de Android.

+ */ private static final String BASE_URL = "http://10.0.2.2:3000/"; + + /** Instancia única de Retrofit. */ private static Retrofit retrofit = null; + /** + * Devuelve una instancia de Retrofit configurada con la URL base, un cliente HTTP + * con un interceptor para loguear las peticiones/respuestas, y un convertidor JSON. + * + * @return una instancia única de Retrofit lista para usar con las interfaces de servicio. + */ public static Retrofit getClient() { if (retrofit == null) { + // Interceptor para mostrar logs del cuerpo de la petición y respuesta HTTP HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); + // Cliente HTTP personalizado con el interceptor de logging OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(logging) .build(); + // Construcción de la instancia de Retrofit retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .client(client) diff --git a/app/src/main/java/com/santiparra/yomitrack/api/ApiService.java b/app/src/main/java/com/santiparra/yomitrack/api/ApiService.java index d67d525..a1a76e4 100644 --- a/app/src/main/java/com/santiparra/yomitrack/api/ApiService.java +++ b/app/src/main/java/com/santiparra/yomitrack/api/ApiService.java @@ -14,36 +14,58 @@ import com.santiparra.yomitrack.model.RegisterResponse; import com.santiparra.yomitrack.model.UserStatsResponse; import com.santiparra.yomitrack.utils.ActivityLog; - - import java.util.List; import java.util.Map; import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.DELETE; -import retrofit2.http.Field; -import retrofit2.http.FormUrlEncoded; -import retrofit2.http.GET; -import retrofit2.http.HTTP; -import retrofit2.http.POST; -import retrofit2.http.PUT; -import retrofit2.http.Path; -import retrofit2.http.Query; +import retrofit2.http.*; +/** + * Interfaz ApiService que define todos los endpoints disponibles + * para la comunicación entre la app YomiTrack y el backend. + * + *

Usa Retrofit para declarar métodos HTTP de forma declarativa.

+ */ public interface ApiService { - // ---------------- Usuario ---------------- + // -------------------- USUARIO -------------------- + + /** + * Registra un nuevo usuario en la aplicación. + * + * @param user Objeto con los datos del usuario. + * @return respuesta del backend con éxito o error. + */ @POST("users/register") Call registerUser(@Body UserEntity user); + /** + * Inicia sesión con un usuario existente. + * + * @param user Objeto con email y contraseña. + * @return respuesta con los datos del usuario autenticado. + */ @POST("users/login") Call loginUser(@Body UserEntity user); + /** + * Solicita un enlace de recuperación de contraseña al correo proporcionado. + * + * @param email correo electrónico del usuario. + * @return respuesta de estado de la operación. + */ @FormUrlEncoded @POST("users/forgot-password") Call forgotPassword(@Field("email") String email); + /** + * Restablece la contraseña del usuario con un token válido. + * + * @param email correo electrónico del usuario. + * @param token token enviado al correo. + * @param newPassword nueva contraseña. + * @return respuesta de la operación. + */ @FormUrlEncoded @POST("users/reset-password") Call resetPassword( @@ -52,11 +74,25 @@ public interface ApiService { @Field("newPassword") String newPassword ); - // ---------------- Anime ---------------- + // -------------------- ANIME -------------------- + + /** + * Inserta un nuevo anime en la lista del usuario. + * + * @param anime Objeto con los datos del anime. + * @return respuesta del backend. + */ @POST("anime/add") Call insertAnime(@Body AnimeEntity anime); - // Scroll infinito: obtener lista paginada + /** + * Obtiene la lista paginada de animes de un usuario. + * + * @param userId ID del usuario. + * @param page número de página. + * @param size cantidad de ítems por página. + * @return página con lista de animes. + */ @GET("/anime/list/{userId}") Call getAnimes( @Path("userId") int userId, @@ -64,16 +100,57 @@ public interface ApiService { @Query("size") int size ); + /** + * Actualiza un anime existente. + * + * @param animeId ID del anime. + * @param anime Objeto con datos actualizados. + * @return respuesta del backend. + */ @PUT("anime/{id}") Call updateAnime(@Path("id") int animeId, @Body AnimeEntity anime); + /** + * Elimina un anime por su ID. + * + * @param id ID del anime. + * @return respuesta del backend. + */ @DELETE("anime/delete/{id}") Call deleteAnime(@Path("id") int id); - // ---------------- Manga ---------------- + /** + * Obtiene animes por estado para un usuario específico. + * + * @param userId ID del usuario. + * @param status estado deseado (e.g., Watching, Completed). + * @return lista de animes con dicho estado. + */ + @GET("anime/user/{userId}/status/{status}") + Call> getAnimeByUserAndStatus( + @Path("userId") int userId, + @Path("status") String status + ); + + // -------------------- MANGA -------------------- + + /** + * Inserta un nuevo manga en la lista del usuario. + * + * @param manga Objeto con los datos del manga. + * @return respuesta del backend. + */ @POST("manga/add") Call insertManga(@Body MangaEntity manga); + /** + * Obtiene la lista paginada de mangas de un usuario. + * + * @param userId ID del usuario. + * @param page número de página. + * @param size cantidad de ítems por página. + * @return página con lista de mangas. + */ @GET("/manga/list/{userId}") Call getMangas( @Path("userId") int userId, @@ -81,57 +158,125 @@ public interface ApiService { @Query("size") int size ); + /** + * Obtiene mangas por estado para un usuario específico. + * + * @param userId ID del usuario. + * @param status estado deseado (e.g., Reading, Completed). + * @return lista de mangas con dicho estado. + */ @GET("manga/user/{userId}/status/{status}") Call> getMangaByUserAndStatus( @Path("userId") int userId, @Path("status") String status ); + /** + * Actualiza un manga existente. + * + * @param mangaId ID del manga. + * @param manga Objeto con datos actualizados. + * @return respuesta del backend. + */ @PUT("manga/{id}") Call updateManga(@Path("id") int mangaId, @Body MangaEntity manga); + /** + * Elimina un manga por su ID. + * + * @param id ID del manga. + * @return respuesta del backend. + */ @DELETE("manga/delete/{id}") Call deleteManga(@Path("id") int id); - // ---------------- Activity ------------------- + // -------------------- ACTIVIDAD -------------------- + /** + * Obtiene estadísticas de anime y manga del usuario. + * + * @param userId ID del usuario. + * @return objeto con estadísticas. + */ @GET("users/{id}/stats") Call getUserStats(@Path("id") int userId); + /** + * Obtiene el historial de actividad de un usuario. + * + * @param userId ID del usuario. + * @return lista de actividades. + */ @GET("api/activity/list/{userId}") Call> getActivityLog(@Path("userId") int userId); + /** + * Obtiene los comentarios de una actividad específica. + * + * @param activityId ID de la actividad. + * @return lista de comentarios. + */ @GET("api/activity/comments/{activityId}") Call> getCommentsByActivity(@Path("activityId") int activityId); + /** + * Verifica si un usuario dio like a una actividad. + * + * @param userId ID del usuario. + * @param activityId ID de la actividad. + * @return objeto JSON con resultado (true/false). + */ @GET("/api/activity/like/{userId}/{activityId}") Call checkLike( @Path("userId") int userId, @Path("activityId") int activityId ); - @GET("anime/user/{userId}/status/{status}") - Call> getAnimeByUserAndStatus( - @Path("userId") int userId, - @Path("status") String status - ); - + /** + * Envía un like a una actividad. + * + * @param body JSON con userId y activityId. + * @return respuesta del backend. + */ @POST("api/activity/like") Call postLike(@Body JsonObject body); - @POST("api/activity/comment") - Call postComment(@Body JsonObject body); - - @POST("api/activity/add") - Call postActivity(@Body Map body); - + /** + * Elimina un like de una actividad. + * + * @param body JSON con userId y activityId. + * @return respuesta del backend. + */ @HTTP(method = "DELETE", path = "api/activity/like/remove", hasBody = true) Call deleteLike(@Body JsonObject body); + /** + * Publica un comentario en una actividad. + * + * @param body JSON con userId, activityId, texto y otros datos. + * @return respuesta del backend. + */ + @POST("api/activity/comment") + Call postComment(@Body JsonObject body); - // ---------------- AniList API ---------------- + /** + * Publica una nueva actividad. + * + * @param body mapa con los datos de la actividad (userId, tipo, contenido...). + * @return respuesta del backend. + */ + @POST("api/activity/add") + Call postActivity(@Body Map body); + // -------------------- ANIList API -------------------- + + /** + * Busca animes o mangas en AniList. + * + * @param query término de búsqueda. + * @param type tipo de media: "ANIME" o "MANGA". + * @return lista de resultados obtenidos desde AniList. + */ @GET("anilist/search") Call> searchAniList(@Query("query") String query, @Query("type") String type); - } diff --git a/app/src/main/java/com/santiparra/yomitrack/db/entities/AnimeEntity.java b/app/src/main/java/com/santiparra/yomitrack/db/entities/AnimeEntity.java index e35a6cd..39ec8f4 100644 --- a/app/src/main/java/com/santiparra/yomitrack/db/entities/AnimeEntity.java +++ b/app/src/main/java/com/santiparra/yomitrack/db/entities/AnimeEntity.java @@ -4,22 +4,55 @@ import java.io.Serializable; /** * Entidad que representa un anime guardado por el usuario en la base de datos local. + * Implementa Serializable para facilitar el paso entre componentes. */ public class AnimeEntity implements Serializable { + /** ID único del anime en la base de datos. */ private int id; + + /** ID del usuario al que pertenece este anime. */ private int userId; + + /** Título del anime. */ private String title; + + /** Puntuación asignada por el usuario (por ejemplo, del 1 al 10). */ private int score; + + /** Progreso actual del usuario (número de episodios vistos). */ private int progress; + + /** Estado del anime (Watching, Completed, Paused, etc.). */ private String status; + + /** Tipo del anime (TV, Movie, OVA, etc.). */ private String type; + + /** URL de la imagen de portada del anime. */ private String imageUrl; + + /** Número total de episodios del anime. */ private int totalEpisodes; + /** + * Constructor vacío requerido por algunas librerías como Room o Retrofit. + */ public AnimeEntity() { } + /** + * Constructor completo de la entidad Anime. + * + * @param id ID único del anime. + * @param title Título del anime. + * @param status Estado del anime. + * @param userId ID del usuario propietario. + * @param imageUrl URL de la imagen del anime. + * @param progress Episodios vistos. + * @param score Puntuación asignada. + * @param totalEpisodes Total de episodios del anime. + */ public AnimeEntity(int id, String title, String status, int userId, String imageUrl, int progress, int score, int totalEpisodes) { this.id = id; this.title = title; @@ -31,75 +64,92 @@ public class AnimeEntity implements Serializable { this.totalEpisodes = totalEpisodes; } - // Getters y Setters + /** @return ID del anime. */ public int getId() { return id; } + /** @param id ID del anime. */ public void setId(int id) { this.id = id; } + /** @return ID del usuario. */ public int getUserId() { return userId; } + /** @param userId ID del usuario. */ public void setUserId(int userId) { this.userId = userId; } + /** @return Título del anime. */ public String getTitle() { return title; } + /** @param title Título del anime. */ public void setTitle(String title) { this.title = title; } + /** @return Puntuación del anime. */ public int getScore() { return score; } + /** @param score Puntuación del anime. */ public void setScore(int score) { this.score = score; } + /** @return Progreso del usuario (episodios vistos). */ public int getProgress() { return progress; } + /** @param progress Episodios vistos por el usuario. */ public void setProgress(int progress) { this.progress = progress; } + /** @return Estado del anime. */ public String getStatus() { return status; } + /** @param status Estado del anime. */ public void setStatus(String status) { this.status = status; } + /** @return Tipo de anime (TV, Movie, etc.). */ public String getType() { return type; } + /** @param type Tipo de anime. */ public void setType(String type) { this.type = type; } + /** @return URL de la imagen del anime. */ public String getImageUrl() { return imageUrl; } + /** @param imageUrl URL de la imagen del anime. */ public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; } + /** @return Total de episodios del anime. */ public int getTotalEpisodes() { return totalEpisodes; } + /** @param totalEpisodes Número total de episodios. */ public void setTotalEpisodes(int totalEpisodes) { this.totalEpisodes = totalEpisodes; } diff --git a/app/src/main/java/com/santiparra/yomitrack/db/entities/MangaEntity.java b/app/src/main/java/com/santiparra/yomitrack/db/entities/MangaEntity.java index 4af8fbf..91e5630 100644 --- a/app/src/main/java/com/santiparra/yomitrack/db/entities/MangaEntity.java +++ b/app/src/main/java/com/santiparra/yomitrack/db/entities/MangaEntity.java @@ -4,22 +4,55 @@ import java.io.Serializable; /** * Entidad que representa un manga guardado por el usuario en la base de datos local. + * Implementa Serializable para permitir su paso entre actividades y fragmentos. */ public class MangaEntity implements Serializable { + /** ID único del manga en la base de datos. */ private int id; + + /** ID del usuario al que pertenece este manga. */ private int userId; + + /** Título del manga. */ private String title; + + /** Puntuación asignada por el usuario (por ejemplo, del 1 al 10). */ private int score; + + /** Progreso actual del usuario (capítulos leídos). */ private int progress; + + /** Estado del manga (Reading, Completed, On-Hold, etc.). */ private String status; + + /** Tipo del manga (Manga, Manhwa, Doujinshi, etc.). */ private String type; + + /** URL de la imagen de portada del manga. */ private String imageUrl; + + /** Número total de capítulos del manga. */ private int totalChapters; + /** + * Constructor vacío necesario para serialización y frameworks como Room o Retrofit. + */ public MangaEntity() { } + /** + * Constructor completo para inicializar una instancia de manga. + * + * @param id ID único del manga. + * @param title Título del manga. + * @param status Estado actual del manga. + * @param userId ID del usuario que lo añadió. + * @param imageUrl URL de la portada del manga. + * @param progress Capítulos leídos. + * @param score Puntuación dada por el usuario. + * @param totalChapters Total de capítulos disponibles. + */ public MangaEntity(int id, String title, String status, int userId, String imageUrl, int progress, int score, int totalChapters) { this.id = id; this.title = title; @@ -31,76 +64,92 @@ public class MangaEntity implements Serializable { this.totalChapters = totalChapters; } - // Getters y Setters - + /** @return ID del manga. */ public int getId() { return id; } + /** @param id ID del manga. */ public void setId(int id) { this.id = id; } + /** @return ID del usuario propietario del manga. */ public int getUserId() { return userId; } + /** @param userId ID del usuario propietario. */ public void setUserId(int userId) { this.userId = userId; } + /** @return Título del manga. */ public String getTitle() { return title; } + /** @param title Título del manga. */ public void setTitle(String title) { this.title = title; } + /** @return Puntuación asignada al manga. */ public int getScore() { return score; } + /** @param score Puntuación del manga. */ public void setScore(int score) { this.score = score; } + /** @return Capítulos leídos por el usuario. */ public int getProgress() { return progress; } + /** @param progress Capítulos que el usuario ha leído. */ public void setProgress(int progress) { this.progress = progress; } + /** @return Estado del manga (Reading, Dropped, etc.). */ public String getStatus() { return status; } + /** @param status Estado actual del manga. */ public void setStatus(String status) { this.status = status; } + /** @return Tipo de manga (e.g., Manhwa, Doujinshi). */ public String getType() { return type; } + /** @param type Tipo de manga. */ public void setType(String type) { this.type = type; } + /** @return URL de la imagen del manga. */ public String getImageUrl() { return imageUrl; } + /** @param imageUrl URL de la imagen de portada. */ public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; } + /** @return Total de capítulos del manga. */ public int getTotalChapters() { return totalChapters; } + /** @param totalChapters Cantidad total de capítulos. */ public void setTotalChapters(int totalChapters) { this.totalChapters = totalChapters; } diff --git a/app/src/main/java/com/santiparra/yomitrack/db/entities/UserEntity.java b/app/src/main/java/com/santiparra/yomitrack/db/entities/UserEntity.java index df6dbff..89726b3 100644 --- a/app/src/main/java/com/santiparra/yomitrack/db/entities/UserEntity.java +++ b/app/src/main/java/com/santiparra/yomitrack/db/entities/UserEntity.java @@ -3,60 +3,87 @@ package com.santiparra.yomitrack.db.entities; import com.google.gson.annotations.SerializedName; /** - * Entidad que representa un usuario. + * Entidad que representa un usuario dentro del sistema. + * Utilizada tanto para autenticación como para registro y obtención de datos del backend. */ public class UserEntity { + /** Identificador único del usuario. */ @SerializedName("id") private int id; + /** Nombre de usuario utilizado para iniciar sesión y mostrar en el perfil. */ @SerializedName("username") private String username; + /** Contraseña del usuario (debe manejarse con cuidado y encriptación en producción). */ @SerializedName("password") private String password; + + /** Dirección de correo electrónico del usuario. */ @SerializedName("email") private String email; + /** + * Constructor utilizado para iniciar sesión con username y contraseña. + * + * @param username nombre de usuario. + * @param password contraseña del usuario. + */ public UserEntity(String username, String password) { this.username = username; this.password = password; } + /** + * Constructor utilizado para registrar un nuevo usuario. + * + * @param username nombre de usuario. + * @param email correo electrónico. + * @param password contraseña del usuario. + */ public UserEntity(String username, String email, String password) { this.username = username; this.email = email; this.password = password; } + /** @return ID del usuario. */ public int getId() { return id; } + /** @param id ID del usuario. */ public void setId(int id) { this.id = id; } + /** @return nombre de usuario. */ public String getUsername() { return username; } + /** @param username nombre de usuario. */ public void setUsername(String username) { this.username = username; } + /** @return contraseña del usuario. */ public String getPassword() { return password; } + /** @param password contraseña del usuario. */ public void setPassword(String password) { this.password = password; } + /** @return correo electrónico del usuario. */ public String getEmail() { return email; } + /** @param email correo electrónico del usuario. */ public void setEmail(String email) { this.email = email; } diff --git a/app/src/main/java/com/santiparra/yomitrack/model/AniListMedia.java b/app/src/main/java/com/santiparra/yomitrack/model/AniListMedia.java index e4ba69d..8789283 100644 --- a/app/src/main/java/com/santiparra/yomitrack/model/AniListMedia.java +++ b/app/src/main/java/com/santiparra/yomitrack/model/AniListMedia.java @@ -1,32 +1,75 @@ package com.santiparra.yomitrack.model; +/** + * Modelo de datos que representa un resultado de búsqueda desde la API de AniList. + * Utilizado tanto para anime como manga. + */ public class AniListMedia { + + /** ID único del media (anime o manga) proporcionado por AniList. */ private int id; + + /** Título del anime o manga. */ private String title; + + /** URL de la imagen de portada del anime o manga. */ private String imageUrl; + /** + * Constructor vacío necesario para serialización/deserialización automática. + */ public AniListMedia() {} + /** + * Devuelve el ID del media. + * + * @return ID del anime o manga. + */ public int getId() { return id; } - public String getTitle() { - return title; - } - - public String getImageUrl() { - return imageUrl; - } - + /** + * Establece el ID del media. + * + * @param id ID del anime o manga. + */ public void setId(int id) { this.id = id; } + /** + * Devuelve el título del media. + * + * @return título del anime o manga. + */ + public String getTitle() { + return title; + } + + /** + * Establece el título del media. + * + * @param title título del anime o manga. + */ public void setTitle(String title) { this.title = title; } + /** + * Devuelve la URL de la imagen de portada. + * + * @return URL de la imagen. + */ + public String getImageUrl() { + return imageUrl; + } + + /** + * Establece la URL de la imagen de portada. + * + * @param imageUrl URL de la imagen. + */ public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; } diff --git a/app/src/main/java/com/santiparra/yomitrack/model/ApiResponse.java b/app/src/main/java/com/santiparra/yomitrack/model/ApiResponse.java deleted file mode 100644 index a95b32e..0000000 --- a/app/src/main/java/com/santiparra/yomitrack/model/ApiResponse.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.santiparra.yomitrack.model; - -public class ApiResponse { - private String message; - - public String getMessage() { - return message; - } -} diff --git a/app/src/main/java/com/santiparra/yomitrack/model/adapters/airing/AiringViewHolder.java b/app/src/main/java/com/santiparra/yomitrack/model/adapters/airing/AiringViewHolder.java deleted file mode 100644 index 827e45e..0000000 --- a/app/src/main/java/com/santiparra/yomitrack/model/adapters/airing/AiringViewHolder.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.santiparra.yomitrack.model.adapters.airing; - -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import com.bumptech.glide.Glide; -import com.santiparra.yomitrack.R; -import com.santiparra.yomitrack.model.ItemModel; - -public class AiringViewHolder extends RecyclerView.ViewHolder { - - public ImageView imageView; - public TextView titleTextView; - public TextView progressTextView; - - public AiringViewHolder(@NonNull View itemView) { - super(itemView); - imageView = itemView.findViewById(R.id.mediaImage); - titleTextView = itemView.findViewById(R.id.titleTextView); - progressTextView = itemView.findViewById(R.id.progressTextView); - } - - public void bind(ItemModel item) { - titleTextView.setText(item.getTitle()); - progressTextView.setText("Progress: " + item.getProgress()); - - if (item.getImageUrl() != null && !item.getImageUrl().isEmpty()) { - Glide.with(itemView.getContext()) - .load(item.getImageUrl()) - .placeholder(R.drawable.placeholder_image) - .error(R.drawable.error_image) - .into(imageView); - } else { - imageView.setImageResource(R.drawable.placeholder_image); - } - } -} diff --git a/app/src/main/java/com/santiparra/yomitrack/model/adapters/airing/AnimeViewHolder.java b/app/src/main/java/com/santiparra/yomitrack/model/adapters/airing/AnimeViewHolder.java deleted file mode 100644 index e630cbc..0000000 --- a/app/src/main/java/com/santiparra/yomitrack/model/adapters/airing/AnimeViewHolder.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.santiparra.yomitrack.model.adapters.airing; - -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import com.bumptech.glide.Glide; -import com.santiparra.yomitrack.R; -import com.santiparra.yomitrack.model.ItemModel; - -public class AnimeViewHolder extends RecyclerView.ViewHolder { - - public ImageView imageView; - public TextView titleTextView; - public TextView progressTextView; - - public AnimeViewHolder(@NonNull View itemView) { - super(itemView); - imageView = itemView.findViewById(R.id.mediaImage); - titleTextView = itemView.findViewById(R.id.titleTextView); - progressTextView = itemView.findViewById(R.id.progressTextView); - } - - public void bind(ItemModel item) { - titleTextView.setText(item.getTitle()); - progressTextView.setText("Progress: " + item.getProgress()); - - if (item.getImageUrl() != null && !item.getImageUrl().isEmpty()) { - Glide.with(itemView.getContext()) - .load(item.getImageUrl()) - .placeholder(R.drawable.placeholder_image) - .error(R.drawable.error_image) - .into(imageView); - } else { - imageView.setImageResource(R.drawable.placeholder_image); - } - } -} diff --git a/app/src/main/java/com/santiparra/yomitrack/model/adapters/anilist_adapter/AniListSearchAdapter.java b/app/src/main/java/com/santiparra/yomitrack/model/adapters/anilist_adapter/AniListSearchAdapter.java index 6c28d19..e28055f 100644 --- a/app/src/main/java/com/santiparra/yomitrack/model/adapters/anilist_adapter/AniListSearchAdapter.java +++ b/app/src/main/java/com/santiparra/yomitrack/model/adapters/anilist_adapter/AniListSearchAdapter.java @@ -20,7 +20,6 @@ import com.santiparra.yomitrack.api.ApiService; import com.santiparra.yomitrack.db.entities.AnimeEntity; import com.santiparra.yomitrack.db.entities.MangaEntity; import com.santiparra.yomitrack.model.AniListMedia; -import com.santiparra.yomitrack.utils.ActivityLog; import com.santiparra.yomitrack.utils.DateUtils; import java.util.HashMap; @@ -31,18 +30,36 @@ import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; +/** + * Adaptador para mostrar resultados de búsqueda provenientes de AniList + * y permitir al usuario añadir animes o mangas a su lista local mediante la API. + */ public class AniListSearchAdapter extends RecyclerView.Adapter { private final List mediaList; private final Context context; private final String mediaType; + /** + * Constructor del adaptador. + * + * @param context contexto de la aplicación. + * @param mediaList lista de resultados de búsqueda de AniList. + * @param mediaType tipo de media ("ANIME" o "MANGA"). + */ public AniListSearchAdapter(Context context, List mediaList, String mediaType) { this.context = context; this.mediaList = mediaList; this.mediaType = mediaType; } + /** + * Infla el layout de cada ítem de la lista. + * + * @param parent el ViewGroup padre. + * @param viewType el tipo de vista. + * @return ViewHolder que contiene la vista del ítem. + */ @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -50,6 +67,12 @@ public class AniListSearchAdapter extends RecyclerView.Adapter() { @Override public void onResponse(Call call, Response response) { Toast.makeText(context, "Anime añadido", Toast.LENGTH_SHORT).show(); - // 🔁 Registrar actividad usando Map + // Registrar actividad Map body = new HashMap<>(); body.put("userId", userId); body.put("action", "añadió"); @@ -96,7 +121,9 @@ public class AniListSearchAdapter extends RecyclerView.Adapter() { @Override - public void onResponse(Call call, Response response) {} + public void onResponse(Call call, Response response) { + // Actividad registrada (sin acción adicional) + } @Override public void onFailure(Call call, Throwable t) { @@ -112,6 +139,7 @@ public class AniListSearchAdapter extends RecyclerView.Adapter() { @Override public void onResponse(Call call, Response response) { @@ -156,16 +185,35 @@ public class AniListSearchAdapter extends RecyclerView.Adapter { + /** Vista normal por defecto. */ public static final int VIEW_NORMAL = 0; + + /** Vista compacta. */ public static final int VIEW_COMPACT = 1; + + /** Vista ampliada. */ public static final int VIEW_LARGE = 2; + /** Lista de animes a mostrar. */ private List animeList; + + /** Tipo de vista actual. */ private int viewType; + + /** Listener para clics normales (edición). */ private final OnAnimeClickListener onEditClick; + + /** Listener para clics prolongados (acciones extendidas). */ private final OnAnimeClickListener onLongClick; + /** + * Constructor del adaptador. + * + * @param animeList lista de animes. + * @param viewType tipo de vista a usar (normal, compacta, grande). + * @param onEditClick callback para clics normales. + * @param onLongClick callback para clics prolongados. + */ public AnimeAdapter(List animeList, int viewType, OnAnimeClickListener onEditClick, OnAnimeClickListener onLongClick) { @@ -38,13 +61,23 @@ public class AnimeAdapter extends RecyclerView.Adapter newList) { - this.animeList = newList != null ? newList : new ArrayList<>(); + this.animeList = new ArrayList<>(newList); // o .clear() + .addAll() notifyDataSetChanged(); } @@ -145,11 +178,37 @@ public class AnimeAdapter extends RecyclerView.Adapter { - - private final List items; - - public BrowseGridAdapter(List items) { - this.items = items; - } - - @NonNull - @Override - public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_browse_card, parent, false); - return new ViewHolder(view); - } - - @Override - public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - ItemModel item = items.get(position); - holder.title.setText(item.getTitle()); - Glide.with(holder.itemView.getContext()) - .load(item.getImageUrl()) - .placeholder(R.drawable.placeholder_image) - .into(holder.cover); - - // 👉 Animación - Animation animation = AnimationUtils.loadAnimation(holder.itemView.getContext(), R.anim.item_animation_fade_scale); - holder.itemView.startAnimation(animation); - } - - @Override - public int getItemCount() { - return items.size(); - } - - static class ViewHolder extends RecyclerView.ViewHolder { - ImageView cover; - TextView title; - - ViewHolder(View itemView) { - super(itemView); - cover = itemView.findViewById(R.id.imageViewCover); - title = itemView.findViewById(R.id.textViewTitle); - } - } -} - diff --git a/app/src/main/java/com/santiparra/yomitrack/model/adapters/browser_section_adapter/BrowseSectionAdapter.java b/app/src/main/java/com/santiparra/yomitrack/model/adapters/browser_section_adapter/BrowseSectionAdapter.java deleted file mode 100644 index 33d1c83..0000000 --- a/app/src/main/java/com/santiparra/yomitrack/model/adapters/browser_section_adapter/BrowseSectionAdapter.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.santiparra.yomitrack.model.adapters.browser_section_adapter; - - - -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.santiparra.yomitrack.R; -import com.santiparra.yomitrack.model.BrowseSection; -import com.santiparra.yomitrack.model.adapters.homeadapter.HomeAdapter; - -import java.util.List; - -public class BrowseSectionAdapter extends RecyclerView.Adapter { - - private final List sectionList; - - public BrowseSectionAdapter(List sectionList) { - this.sectionList = sectionList; - } - - @NonNull - @Override - public BrowseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_section, parent, false); - return new BrowseViewHolder(view); - } - - @Override - public void onBindViewHolder(@NonNull BrowseViewHolder holder, int position) { - BrowseSection section = sectionList.get(position); - holder.sectionTitle.setText(section.getTitle()); - - HomeAdapter adapter = new HomeAdapter(section.getItems(), section.getTitle()); - holder.recyclerView.setLayoutManager(new LinearLayoutManager(holder.itemView.getContext(), LinearLayoutManager.HORIZONTAL, false)); - holder.recyclerView.setAdapter(adapter); - } - - @Override - public int getItemCount() { - return sectionList.size(); - } - - static class BrowseViewHolder extends RecyclerView.ViewHolder { - TextView sectionTitle; - RecyclerView recyclerView; - - public BrowseViewHolder(@NonNull View itemView) { - super(itemView); - sectionTitle = itemView.findViewById(R.id.sectionTitle); - recyclerView = itemView.findViewById(R.id.sectionRecyclerView); - } - } -} diff --git a/app/src/main/java/com/santiparra/yomitrack/model/adapters/homeadapter/HomeAdapter.java b/app/src/main/java/com/santiparra/yomitrack/model/adapters/homeadapter/HomeAdapter.java deleted file mode 100644 index 86d32fa..0000000 --- a/app/src/main/java/com/santiparra/yomitrack/model/adapters/homeadapter/HomeAdapter.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.santiparra.yomitrack.model.adapters.homeadapter; - -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import com.santiparra.yomitrack.R; -import com.santiparra.yomitrack.model.ItemModel; -import com.santiparra.yomitrack.model.adapters.airing.AiringViewHolder; -import com.santiparra.yomitrack.model.adapters.airing.AnimeViewHolder; - -import java.util.List; - -public class HomeAdapter extends RecyclerView.Adapter { - - private List itemList; - private String sectionTitle; - - private static final int TYPE_AIRING = 0; - private static final int TYPE_ANIME_MANGA = 1; - - public HomeAdapter(List itemList, String sectionTitle) { - this.itemList = itemList; - this.sectionTitle = sectionTitle; - } - - @Override - public int getItemViewType(int position) { - if (sectionTitle.equalsIgnoreCase("Airing")) { - return TYPE_AIRING; - } else { - return TYPE_ANIME_MANGA; - } - } - - @NonNull - @Override - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.item_media_card, parent, false); - - // Ajustamos manualmente el ancho - ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); - view.setLayoutParams(layoutParams); - - if (viewType == TYPE_AIRING) { - return new AiringViewHolder(view); - } else { - return new AnimeViewHolder(view); - } - } - - @Override - public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { - ItemModel item = itemList.get(position); - - if (holder instanceof AiringViewHolder) { - ((AiringViewHolder) holder).bind(item); - } else if (holder instanceof AnimeViewHolder) { - ((AnimeViewHolder) holder).bind(item); - } - } - - @Override - public int getItemCount() { - return itemList.size(); - } -} diff --git a/app/src/main/java/com/santiparra/yomitrack/model/adapters/homeadapter/HomeCardAdapter.java b/app/src/main/java/com/santiparra/yomitrack/model/adapters/homeadapter/HomeCardAdapter.java index 4f30552..2a079a5 100644 --- a/app/src/main/java/com/santiparra/yomitrack/model/adapters/homeadapter/HomeCardAdapter.java +++ b/app/src/main/java/com/santiparra/yomitrack/model/adapters/homeadapter/HomeCardAdapter.java @@ -17,20 +17,48 @@ import com.santiparra.yomitrack.model.ItemModel; import java.util.List; +/** + * Adaptador para el RecyclerView del fragmento de inicio (Home). + * Muestra tarjetas con imagen, título y progreso de animes o mangas recientes. + */ public class HomeCardAdapter extends RecyclerView.Adapter { + /** + * Interfaz para manejar clics en los ítems del RecyclerView. + */ public interface OnItemClickListener { + /** + * Se llama cuando el usuario hace clic sobre un ítem. + * + * @param item el ítem seleccionado. + */ void onItemClick(ItemModel item); } + /** Lista de ítems a mostrar (animes o mangas). */ private final List itemList; + + /** Listener que maneja clics en los ítems. */ private final OnItemClickListener listener; + /** + * Constructor del adaptador. + * + * @param itemList lista de ítems a mostrar. + * @param listener manejador de eventos de clic. + */ public HomeCardAdapter(List itemList, OnItemClickListener listener) { this.itemList = itemList; this.listener = listener; } + /** + * Infla la vista para un ítem del RecyclerView. + * + * @param parent vista contenedora. + * @param viewType tipo de vista (no usado aquí). + * @return instancia de ViewHolder. + */ @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -38,26 +66,58 @@ public class HomeCardAdapter extends RecyclerView.Adapter listener.onItemClick(item)); } + /** + * Devuelve la cantidad de ítems en la lista. + * + * @return número total de ítems. + */ @Override public int getItemCount() { return itemList.size(); } + /** + * ViewHolder que representa cada tarjeta (ítem) en el RecyclerView. + */ public static class ViewHolder extends RecyclerView.ViewHolder { - TextView title, progress; + + /** Texto que muestra el título del ítem. */ + TextView title; + + /** Texto que muestra el progreso del ítem. */ + TextView progress; + + /** Imagen de portada del ítem. */ ImageView cover; + + /** Tarjeta contenedora del ítem. */ CardView card; + /** + * Constructor del ViewHolder. + * + * @param itemView vista del ítem inflada desde el layout. + */ public ViewHolder(@NonNull View itemView) { super(itemView); title = itemView.findViewById(R.id.itemTitle); diff --git a/app/src/main/java/com/santiparra/yomitrack/model/adapters/manga_adapter/MangaAdapter.java b/app/src/main/java/com/santiparra/yomitrack/model/adapters/manga_adapter/MangaAdapter.java index f91ea4b..6954268 100644 --- a/app/src/main/java/com/santiparra/yomitrack/model/adapters/manga_adapter/MangaAdapter.java +++ b/app/src/main/java/com/santiparra/yomitrack/model/adapters/manga_adapter/MangaAdapter.java @@ -1,6 +1,5 @@ package com.santiparra.yomitrack.model.adapters.manga_adapter; -import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -17,17 +16,41 @@ import com.santiparra.yomitrack.db.entities.MangaEntity; import java.util.List; +/** + * Adaptador para mostrar una lista de mangas en un RecyclerView con distintos tipos de vista: + * normal, compacta y grande. Soporta clics normales y prolongados. + */ public class MangaAdapter extends RecyclerView.Adapter { + /** Vista estándar. */ public static final int VIEW_NORMAL = 0; + + /** Vista compacta. */ public static final int VIEW_COMPACT = 1; + + /** Vista grande. */ public static final int VIEW_LARGE = 2; + /** Lista de mangas a mostrar. */ private List mangaList; + + /** Tipo de vista actual. */ private int viewType; + + /** Listener para clic corto (edición). */ private final OnMangaClickListener onEditClick; + + /** Listener para clic prolongado (acciones extendidas). */ private final OnMangaClickListener onLongClick; + /** + * Constructor del adaptador. + * + * @param mangaList lista de mangas a mostrar. + * @param viewType tipo de vista deseado. + * @param onEditClick callback para clics normales. + * @param onLongClick callback para clics prolongados. + */ public MangaAdapter(List mangaList, int viewType, OnMangaClickListener onEditClick, OnMangaClickListener onLongClick) { @@ -124,21 +147,51 @@ public class MangaAdapter extends RecyclerView.Adapter newList) { + mangaList.clear(); + mangaList.addAll(newList); + notifyDataSetChanged(); + } + + /** + * ViewHolder para representar un ítem de manga en el RecyclerView. + */ public static class MangaViewHolder extends RecyclerView.ViewHolder { ImageView imageCover; TextView textTitle, textStatus, textProgress, textScore, textType; View statusDot; + /** + * Constructor del ViewHolder. + * + * @param itemView vista inflada del ítem. + */ public MangaViewHolder(@NonNull View itemView) { super(itemView); imageCover = itemView.findViewById(R.id.imageCover); @@ -151,12 +204,15 @@ public class MangaAdapter extends RecyclerView.Adapter newList) { - this.mangaList = newList; - notifyDataSetChanged(); - } - + /** + * Interfaz para manejar clics sobre ítems de manga. + */ public interface OnMangaClickListener { + /** + * Se ejecuta cuando se hace clic en un manga. + * + * @param manga el ítem clicado. + */ void onClick(MangaEntity manga); } } diff --git a/app/src/main/java/com/santiparra/yomitrack/model/adapters/manga_adapter/MangaSearchAdapter.java b/app/src/main/java/com/santiparra/yomitrack/model/adapters/manga_adapter/MangaSearchAdapter.java index 2d760fb..dcd74f4 100644 --- a/app/src/main/java/com/santiparra/yomitrack/model/adapters/manga_adapter/MangaSearchAdapter.java +++ b/app/src/main/java/com/santiparra/yomitrack/model/adapters/manga_adapter/MangaSearchAdapter.java @@ -15,25 +15,58 @@ import com.santiparra.yomitrack.model.AniListMedia; import java.util.List; +/** + * Adaptador para mostrar resultados de búsqueda de mangas desde AniList. + * Utilizado en el fragmento de búsqueda para permitir seleccionar un manga. + */ public class MangaSearchAdapter extends RecyclerView.Adapter { + /** Lista de mangas obtenidos desde la API de AniList. */ private List mangaList; + + /** Listener para manejar clics en los ítems del RecyclerView. */ private final OnMangaClickListener clickListener; + /** + * Interfaz que define el callback cuando se hace clic en un manga. + */ public interface OnMangaClickListener { + /** + * Método invocado al hacer clic sobre un manga. + * + * @param manga objeto de AniList clicado. + */ void onClick(AniListMedia manga); } + /** + * Constructor del adaptador. + * + * @param mangaList lista de resultados de búsqueda. + * @param clickListener listener para manejar el clic en cada ítem. + */ public MangaSearchAdapter(List mangaList, OnMangaClickListener clickListener) { this.mangaList = mangaList; this.clickListener = clickListener; } + /** + * Reemplaza la lista de mangas actual por una nueva y actualiza el RecyclerView. + * + * @param mangaList nueva lista de mangas. + */ public void setMangaList(List mangaList) { this.mangaList = mangaList; notifyDataSetChanged(); } + /** + * Infla el layout para un ítem individual del RecyclerView. + * + * @param parent el ViewGroup padre. + * @param viewType tipo de vista (no utilizado aquí). + * @return instancia del ViewHolder. + */ @NonNull @Override public SearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -41,6 +74,12 @@ public class MangaSearchAdapter extends RecyclerView.Adapter clickListener.onClick(manga)); } + /** + * Devuelve la cantidad total de mangas en la lista. + * + * @return tamaño de la lista. + */ @Override public int getItemCount() { return mangaList != null ? mangaList.size() : 0; } + /** + * ViewHolder que representa cada ítem del RecyclerView. + */ static class SearchViewHolder extends RecyclerView.ViewHolder { + /** Imagen de portada del manga. */ ImageView imageCover; + + /** Título del manga. */ TextView title; + /** + * Constructor del ViewHolder. + * + * @param itemView vista inflada del ítem. + */ public SearchViewHolder(@NonNull View itemView) { super(itemView); imageCover = itemView.findViewById(R.id.imageCover); diff --git a/app/src/main/java/com/santiparra/yomitrack/model/adapters/recentactivity_adapter/RecentActivityAdapter.java b/app/src/main/java/com/santiparra/yomitrack/model/adapters/recentactivity_adapter/RecentActivityAdapter.java index 06776e0..3e43e33 100644 --- a/app/src/main/java/com/santiparra/yomitrack/model/adapters/recentactivity_adapter/RecentActivityAdapter.java +++ b/app/src/main/java/com/santiparra/yomitrack/model/adapters/recentactivity_adapter/RecentActivityAdapter.java @@ -7,6 +7,7 @@ import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; @@ -18,11 +19,24 @@ import com.santiparra.yomitrack.model.RecentActivityModel; import java.util.List; +/** + * Adaptador para mostrar la actividad reciente del usuario en forma de tarjetas. + * Cada tarjeta puede incluir una acción, portada, comentarios, botón de like y comentar. + */ public class RecentActivityAdapter extends RecyclerView.Adapter { + /** Lista de actividades recientes. */ private List activityList; + + /** ID del usuario actualmente logueado (para comentarios y likes). */ private final int currentUserId; + /** + * Constructor del adaptador. + * + * @param activityList lista de actividades a mostrar. + * @param currentUserId ID del usuario actual. + */ public RecentActivityAdapter(List activityList, int currentUserId) { this.activityList = activityList; this.currentUserId = currentUserId; @@ -31,7 +45,8 @@ public class RecentActivityAdapter extends RecyclerView.Adapter { + boolean newLike = !comment.isLiked(); + comment.setLiked(newLike); + likeButton.setImageResource(newLike ? R.drawable.ic_heart_filled : R.drawable.ic_heart_outline); + likeButton.setColorFilter(commentView.getContext().getColor(newLike ? R.color.pink : R.color.gray)); }); - replyButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - int adapterPos = holder.getAdapterPosition(); - if (adapterPos == RecyclerView.NO_POSITION) return; - RecentActivityModel activityItem = activityList.get(adapterPos); - CommentDialog dialog = new CommentDialog( - holder.itemView.getContext(), - currentUserId, - activityItem.getId(), - () -> notifyItemChanged(adapterPos), - comment.getUsername() - ); - dialog.show(); - } - }); - - holder.commentContainer.addView(commentView); - } - - holder.commentButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { + // Manejo de respuesta a un comentario + replyButton.setOnClickListener(v -> { int adapterPos = holder.getAdapterPosition(); if (adapterPos == RecyclerView.NO_POSITION) return; RecentActivityModel activityItem = activityList.get(adapterPos); @@ -115,39 +109,72 @@ public class RecentActivityAdapter extends RecyclerView.Adapter notifyItemChanged(adapterPos) + () -> notifyItemChanged(adapterPos), + comment.getUsername() ); dialog.show(); - } + }); + + holder.commentContainer.addView(commentView); + } + + // Botón para añadir nuevo comentario a la actividad + holder.commentButton.setOnClickListener(v -> { + int adapterPos = holder.getAdapterPosition(); + if (adapterPos == RecyclerView.NO_POSITION) return; + RecentActivityModel activityItem = activityList.get(adapterPos); + CommentDialog dialog = new CommentDialog( + holder.itemView.getContext(), + currentUserId, + activityItem.getId(), + () -> notifyItemChanged(adapterPos) + ); + dialog.show(); }); - holder.likeButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - activity.liked = !activity.liked; - holder.likeButton.setImageResource(activity.liked ? R.drawable.ic_heart_filled : R.drawable.ic_heart_outline); - holder.likeButton.setColorFilter(holder.itemView.getContext().getColor( - activity.liked ? R.color.pink : R.color.textPrimary)); - } + // Botón de like para la actividad + holder.likeButton.setOnClickListener(v -> { + activity.liked = !activity.liked; + holder.likeButton.setImageResource(activity.liked ? R.drawable.ic_heart_filled : R.drawable.ic_heart_outline); + holder.likeButton.setColorFilter(holder.itemView.getContext().getColor( + activity.liked ? R.color.pink : R.color.textPrimary)); }); } + /** + * Devuelve la cantidad de actividades en la lista. + * + * @return tamaño de la lista. + */ @Override public int getItemCount() { return activityList.size(); } + /** + * Reemplaza la lista actual por una nueva y actualiza la vista. + * + * @param newList nueva lista de actividades. + */ public void updateData(List newList) { this.activityList = newList; notifyDataSetChanged(); } + /** + * ViewHolder que representa una tarjeta de actividad reciente. + */ static class ActivityViewHolder extends RecyclerView.ViewHolder { TextView user, action, title, time; ImageView image; ImageButton likeButton, commentButton; LinearLayout commentContainer; + /** + * Constructor del ViewHolder. + * + * @param itemView vista inflada del ítem. + */ public ActivityViewHolder(@NonNull View itemView) { super(itemView); user = itemView.findViewById(R.id.activityUser); diff --git a/app/src/main/java/com/santiparra/yomitrack/model/adapters/sectionadapter/SectionAdapter.java b/app/src/main/java/com/santiparra/yomitrack/model/adapters/sectionadapter/SectionAdapter.java deleted file mode 100644 index a759b59..0000000 --- a/app/src/main/java/com/santiparra/yomitrack/model/adapters/sectionadapter/SectionAdapter.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.santiparra.yomitrack.model.adapters.sectionadapter; - -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.santiparra.yomitrack.R; -import com.santiparra.yomitrack.model.ItemModel; -import com.santiparra.yomitrack.model.adapters.homeadapter.HomeAdapter; - -import java.util.List; -import java.util.Map; - -public class SectionAdapter extends RecyclerView.Adapter { - - private final List sectionTitles; - private final Map> sectionItems; - - public SectionAdapter(List sectionTitles, Map> sectionItems) { - this.sectionTitles = sectionTitles; - this.sectionItems = sectionItems; - } - - @NonNull - @Override - public SectionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_section, parent, false); - return new SectionViewHolder(view); - } - - @Override - public void onBindViewHolder(@NonNull SectionViewHolder holder, int position) { - String sectionTitle = sectionTitles.get(position); - holder.title.setText(sectionTitle); - - List fullList = sectionItems.get(sectionTitle); - - HomeAdapter adapter = new HomeAdapter(fullList, sectionTitle); - holder.recyclerView.setLayoutManager(new LinearLayoutManager(holder.itemView.getContext(), LinearLayoutManager.HORIZONTAL, false)); - holder.recyclerView.setAdapter(adapter); - } - - @Override - public int getItemCount() { - return sectionTitles.size(); - } - - static class SectionViewHolder extends RecyclerView.ViewHolder { - TextView title; - RecyclerView recyclerView; - - public SectionViewHolder(@NonNull View itemView) { - super(itemView); - title = itemView.findViewById(R.id.sectionTitle); - recyclerView = itemView.findViewById(R.id.sectionRecyclerView); - } - } -} diff --git a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addanime/AddAnimeFragment.java b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addanime/AddAnimeFragment.java index 3eb114e..188704f 100644 --- a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addanime/AddAnimeFragment.java +++ b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addanime/AddAnimeFragment.java @@ -75,18 +75,12 @@ public class AddAnimeFragment extends Fragment { private void setupSpinners() { ArrayAdapter statusAdapter = ArrayAdapter.createFromResource( - requireContext(), - R.array.anime_status_array, - R.layout.item_spinner - ); - statusAdapter.setDropDownViewResource(R.layout.item_spinner); // ✅ blanco también al desplegar + requireContext(), R.array.anime_status_array, R.layout.item_spinner); + statusAdapter.setDropDownViewResource(R.layout.item_spinner); statusSpinner.setAdapter(statusAdapter); ArrayAdapter typeAdapter = ArrayAdapter.createFromResource( - requireContext(), - R.array.anime_type_array, - R.layout.item_spinner - ); + requireContext(), R.array.anime_type_array, R.layout.item_spinner); typeAdapter.setDropDownViewResource(R.layout.item_spinner); typeSpinner.setAdapter(typeAdapter); } @@ -128,23 +122,16 @@ public class AddAnimeFragment extends Fragment { String status = statusSpinner.getSelectedItem().toString(); String type = typeSpinner.getSelectedItem().toString(); - int score = 0; - int progress = 0; - try { - score = Integer.parseInt(scoreEditText.getText().toString()); - progress = Integer.parseInt(progressEditText.getText().toString()); - } catch (NumberFormatException ignored) { - } + int score = parseIntOrZero(scoreEditText.getText().toString()); + int progress = parseIntOrZero(progressEditText.getText().toString()); AnimeEntity anime = new AnimeEntity(); anime.setUserId(userId); anime.setTitle(selected.getTitle()); - if (selected.getImageUrl() == null || selected.getImageUrl().isEmpty()) { - selectedImageUrl = "android.resource://" + requireContext().getPackageName() + "/" + R.drawable.sample_cover; - } else { - selectedImageUrl = selected.getImageUrl(); - } + selectedImageUrl = (selected.getImageUrl() == null || selected.getImageUrl().isEmpty()) + ? "android.resource://" + requireContext().getPackageName() + "/" + R.drawable.sample_cover + : selected.getImageUrl(); anime.setImageUrl(selectedImageUrl); anime.setStatus(status); @@ -158,6 +145,7 @@ public class AddAnimeFragment extends Fragment { if (response.isSuccessful() && response.body() != null) { Toast.makeText(getContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show(); registrarActividad(anime.getTitle()); + notificarAñadido(); requireActivity().getSupportFragmentManager().popBackStack(); } else { Toast.makeText(getContext(), "Error al guardar anime", Toast.LENGTH_SHORT).show(); @@ -182,17 +170,29 @@ public class AddAnimeFragment extends Fragment { @Override public void onResponse(Call call, Response response) { Log.d("ACTIVITY_POST", "Código de respuesta: " + response.code()); - if (!response.isSuccessful()) { - Log.e("ACTIVITY_POST", "Error en response: " + response.errorBody()); - } } @Override public void onFailure(Call call, Throwable t) { Log.e("ACTIVITY_POST", "Error al registrar actividad: " + t.getMessage(), t); - if (!isAdded()) return; - Toast.makeText(getContext(), "Error al registrar actividad", Toast.LENGTH_SHORT).show(); + if (isAdded()) { + Toast.makeText(getContext(), "Error al registrar actividad", Toast.LENGTH_SHORT).show(); + } } }); } + + private void notificarAñadido() { + Bundle result = new Bundle(); + result.putBoolean("anime_added", true); + getParentFragmentManager().setFragmentResult("anime_add_request", result); + } + + private int parseIntOrZero(String value) { + try { + return Integer.parseInt(value.trim()); + } catch (NumberFormatException e) { + return 0; + } + } } diff --git a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addmanga/AddMangaFragment.java b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addmanga/AddMangaFragment.java index 0ca99c4..17c7d38 100644 --- a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addmanga/AddMangaFragment.java +++ b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addmanga/AddMangaFragment.java @@ -90,7 +90,6 @@ public class AddMangaFragment extends Fragment { typeSpinner.setAdapter(typeAdapter); } - private void setupRecycler() { searchAdapter = new MangaSearchAdapter(new ArrayList<>(), this::onMangaSelected); searchResults.setAdapter(searchAdapter); @@ -98,8 +97,7 @@ public class AddMangaFragment extends Fragment { private void setupSearch() { searchEditText.setOnEditorActionListener((TextView v, int actionId, KeyEvent event) -> { - if (actionId == EditorInfo.IME_ACTION_SEARCH || - (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) { + if (actionId == EditorInfo.IME_ACTION_SEARCH || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) { String query = searchEditText.getText().toString().trim(); if (!query.isEmpty()) { api.searchAniList(query, "MANGA").enqueue(new Callback>() { @@ -133,8 +131,7 @@ public class AddMangaFragment extends Fragment { try { score = Integer.parseInt(scoreEditText.getText().toString()); progress = Integer.parseInt(progressEditText.getText().toString()); - } catch (NumberFormatException ignored) { - } + } catch (NumberFormatException ignored) {} MangaEntity manga = new MangaEntity(); manga.setUserId(userId); @@ -158,6 +155,9 @@ public class AddMangaFragment extends Fragment { if (response.isSuccessful() && response.body() != null) { Toast.makeText(getContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show(); registrarActividad(manga.getTitle()); + Bundle result = new Bundle(); + result.putBoolean("manga_added", true); + getParentFragmentManager().setFragmentResult("manga_add_request", result); requireActivity().getSupportFragmentManager().popBackStack(); } else { Toast.makeText(getContext(), "Error al guardar manga", Toast.LENGTH_SHORT).show(); @@ -180,11 +180,7 @@ public class AddMangaFragment extends Fragment { api.postActivity(actividad).enqueue(new Callback() { @Override - public void onResponse(Call call, Response response) { - if (!response.isSuccessful()) { - // Puedes logear el error si lo deseas - } - } + public void onResponse(Call call, Response response) {} @Override public void onFailure(Call call, Throwable t) { diff --git a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/anime_list/FragmentAnime.java b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/anime_list/FragmentAnime.java index c51f223..48d9580 100644 --- a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/anime_list/FragmentAnime.java +++ b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/anime_list/FragmentAnime.java @@ -59,15 +59,12 @@ public class FragmentAnime extends Fragment { @Nullable @Override - public View onCreateView(@NonNull LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_alist, container, false); } @Override - public void onViewCreated(@NonNull View view, - @Nullable Bundle savedInstanceState) { + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); initViews(view); @@ -76,6 +73,7 @@ public class FragmentAnime extends Fragment { setupSearchListener(); setupFab(view); setupInsets(view); + setupResultListener(); SharedPreferences prefs = requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE); userId = prefs.getInt("user_id", -1); @@ -84,7 +82,7 @@ public class FragmentAnime extends Fragment { Toast.makeText(getContext(), "Error: sesión no iniciada", Toast.LENGTH_SHORT).show(); return; } - // Mostrar el nombre del usuario + String username = prefs.getString("username", "Usuario"); TextView textViewUsername = view.findViewById(R.id.textViewUsername); textViewUsername.setText(username); @@ -124,6 +122,30 @@ public class FragmentAnime extends Fragment { }); } + private void setupResultListener() { + getParentFragmentManager().setFragmentResultListener("anime_add_request", this, (requestKey, bundle) -> { + if (bundle.getBoolean("anime_added", false)) { + currentPage = 1; + animeList.clear(); + adapter.updateList(new ArrayList<>()); + loadMoreAnimes(currentPage); + } + }); + + getParentFragmentManager().setFragmentResultListener("anime_delete_request", this, (requestKey, bundle) -> { + int deletedId = bundle.getInt("anime_id", -1); + if (deletedId != -1) { + for (int i = 0; i < animeList.size(); i++) { + if (animeList.get(i).getId() == deletedId) { + animeList.remove(i); + adapter.updateList(animeList); + break; + } + } + } + }); + } + private void setupViewButtons() { btnViewCompact.setOnClickListener(v -> setViewType(AnimeAdapter.VIEW_COMPACT)); btnViewNormal.setOnClickListener(v -> setViewType(AnimeAdapter.VIEW_NORMAL)); @@ -197,9 +219,8 @@ public class FragmentAnime extends Fragment { if (response.isSuccessful() && response.body() != null) { Toast.makeText(requireContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show(); - currentPage = 1; - animeList.clear(); - loadMoreAnimes(currentPage); + animeList.remove(anime); + adapter.updateList(animeList); } else { Toast.makeText(requireContext(), "Error al eliminar", Toast.LENGTH_SHORT).show(); } @@ -225,8 +246,15 @@ public class FragmentAnime extends Fragment { if (response.isSuccessful() && response.body() != null) { List nuevos = response.body().getData(); - animeList.addAll(nuevos); - adapter.notifyItemRangeInserted(animeList.size() - nuevos.size(), nuevos.size()); + if (page == 1) { + animeList.clear(); + animeList.addAll(nuevos); + adapter.updateList(animeList); + } else { + int start = animeList.size(); + animeList.addAll(nuevos); + adapter.notifyItemRangeInserted(start, nuevos.size()); + } isLoading = response.body().isHasNextPage(); } else { isLoading = false; diff --git a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editanime/EditAnimeFragment.java b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editanime/EditAnimeFragment.java index b58feb2..192943b 100644 --- a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editanime/EditAnimeFragment.java +++ b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editanime/EditAnimeFragment.java @@ -67,7 +67,7 @@ public class EditAnimeFragment extends Fragment { String[] typeArray = getResources().getStringArray(R.array.anime_type_array); ArrayAdapter statusAdapter = new ArrayAdapter<>(requireContext(), R.layout.item_spinner, statusArray); - statusAdapter.setDropDownViewResource(R.layout.item_spinner); // Aplica color blanco en lista desplegable también + statusAdapter.setDropDownViewResource(R.layout.item_spinner); spinnerStatus.setAdapter(statusAdapter); ArrayAdapter typeAdapter = new ArrayAdapter<>(requireContext(), R.layout.item_spinner, typeArray); @@ -142,8 +142,6 @@ public class EditAnimeFragment extends Fragment { api.updateAnime(anime.getId(), anime).enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { - Log.d("API_RESPONSE", "onResponse ejecutado: " + response.body()); - if (!isAdded()) return; if (response.isSuccessful()) { @@ -160,7 +158,6 @@ public class EditAnimeFragment extends Fragment { @Override public void onFailure(Call call, Throwable t) { - Log.e("API_RESPONSE", "onFailure ejecutado: " + t.getMessage(), t); if (!isAdded()) return; Toast.makeText(requireContext(), "Fallo en la conexión", Toast.LENGTH_SHORT).show(); } @@ -179,6 +176,10 @@ public class EditAnimeFragment extends Fragment { Toast.makeText(requireContext(), "Anime eliminado", Toast.LENGTH_SHORT).show(); requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE) .edit().putBoolean("refresh_profile", true).apply(); + Bundle result = new Bundle(); + result.putBoolean("anime_deleted", true); + result.putInt("anime_id", anime.getId()); + getParentFragmentManager().setFragmentResult("anime_delete_request", result); requireActivity().getSupportFragmentManager().popBackStack(); } else { Toast.makeText(requireContext(), "Error al eliminar", Toast.LENGTH_SHORT).show(); @@ -231,7 +232,6 @@ public class EditAnimeFragment extends Fragment { public void onResponse(Call call, Response response) { Log.d("ACTIVITY_DELETE", "Actividad de eliminación registrada"); - if (getParentFragment() instanceof FragmentProfile) { ((FragmentProfile) getParentFragment()).loadActivity(); } diff --git a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editmanga/EditMangaFragment.java b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editmanga/EditMangaFragment.java index 9fb0c63..8b0b472 100644 --- a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editmanga/EditMangaFragment.java +++ b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editmanga/EditMangaFragment.java @@ -61,30 +61,18 @@ public class EditMangaFragment extends Fragment { fillFields(); - String[] statusArray = getResources().getStringArray(R.array.manga_status_array); - String[] typeArray = getResources().getStringArray(R.array.manga_type_array); - - ArrayAdapter statusAdapter = new ArrayAdapter<>(requireContext(), R.layout.item_spinner, statusArray); + ArrayAdapter statusAdapter = new ArrayAdapter<>(requireContext(), R.layout.item_spinner, + getResources().getStringArray(R.array.manga_status_array)); statusAdapter.setDropDownViewResource(R.layout.item_spinner); spinnerStatus.setAdapter(statusAdapter); - ArrayAdapter typeAdapter = new ArrayAdapter<>(requireContext(), R.layout.item_spinner, typeArray); + ArrayAdapter typeAdapter = new ArrayAdapter<>(requireContext(), R.layout.item_spinner, + getResources().getStringArray(R.array.manga_type_array)); typeAdapter.setDropDownViewResource(R.layout.item_spinner); spinnerType.setAdapter(typeAdapter); - for (int i = 0; i < statusArray.length; i++) { - if (statusArray[i].equalsIgnoreCase(manga.getStatus())) { - spinnerStatus.setSelection(i); - break; - } - } - - for (int i = 0; i < typeArray.length; i++) { - if (typeArray[i].equalsIgnoreCase(manga.getType())) { - spinnerType.setSelection(i); - break; - } - } + setSpinnerSelection(spinnerStatus, manga.getStatus()); + setSpinnerSelection(spinnerType, manga.getType()); buttonSave.setOnClickListener(v -> saveChanges()); @@ -104,6 +92,15 @@ public class EditMangaFragment extends Fragment { editTextProgress.setText(String.valueOf(manga.getProgress())); } + private void setSpinnerSelection(Spinner spinner, String value) { + for (int i = 0; i < spinner.getCount(); i++) { + if (spinner.getItemAtPosition(i).toString().equalsIgnoreCase(value)) { + spinner.setSelection(i); + break; + } + } + } + private void saveChanges() { if (manga == null) { Toast.makeText(requireContext(), "Error: Manga no cargado", Toast.LENGTH_SHORT).show(); @@ -128,14 +125,11 @@ public class EditMangaFragment extends Fragment { return; } - String status = spinnerStatus.getSelectedItem().toString(); - String type = spinnerType.getSelectedItem().toString(); - manga.setTitle(title); manga.setScore(score); manga.setProgress(progress); - manga.setStatus(status); - manga.setType(type); + manga.setStatus(spinnerStatus.getSelectedItem().toString()); + manga.setType(spinnerType.getSelectedItem().toString()); api.updateManga(manga.getId(), manga).enqueue(new Callback() { @Override @@ -144,7 +138,7 @@ public class EditMangaFragment extends Fragment { if (response.isSuccessful() && response.body() != null) { Toast.makeText(requireContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show(); - registrarActividad(manga.getTitle(), manga.getImageUrl()); + registrarActividad("update de un manga", manga.getTitle(), manga.getImageUrl()); requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE) .edit().putBoolean("refresh_profile", true).apply(); requireActivity().getSupportFragmentManager().popBackStack(); @@ -162,7 +156,7 @@ public class EditMangaFragment extends Fragment { } private void deleteManga() { - registrarActividadEliminacionManga(manga.getTitle(), manga.getImageUrl()); + registrarActividad("eliminó un manga", manga.getTitle(), manga.getImageUrl()); api.deleteManga(manga.getId()).enqueue(new Callback() { @Override @@ -173,6 +167,12 @@ public class EditMangaFragment extends Fragment { Toast.makeText(requireContext(), "Manga eliminado", Toast.LENGTH_SHORT).show(); requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE) .edit().putBoolean("refresh_profile", true).apply(); + + Bundle result = new Bundle(); + result.putBoolean("manga_deleted", true); + result.putInt("manga_id", manga.getId()); + getParentFragmentManager().setFragmentResult("manga_delete_request", result); + requireActivity().getSupportFragmentManager().popBackStack(); } else { Toast.makeText(requireContext(), "Error al eliminar", Toast.LENGTH_SHORT).show(); @@ -187,44 +187,20 @@ public class EditMangaFragment extends Fragment { }); } - private void registrarActividad(String titulo, String imagen) { + private void registrarActividad(String action, String titulo, String imagen) { int userId = requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE).getInt("user_id", -1); if (userId == -1) return; Map actividad = new HashMap<>(); actividad.put("userId", userId); - actividad.put("action", "update de un manga"); + actividad.put("action", action); actividad.put("mediaTitle", titulo); actividad.put("imageUrl", imagen); api.postActivity(actividad).enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { - Log.d("ACTIVITY_DELETE", "Actividad de edicion registrada"); - } - - @Override - public void onFailure(Call call, Throwable t) { - Log.e("ACTIVITY_DELETE", "Error al registrar actividad: " + t.getMessage(), t); - } - }); - } - - private void registrarActividadEliminacionManga(String titulo, String imagen) { - int userId = requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE).getInt("user_id", -1); - if (userId == -1) return; - - Map actividad = new HashMap<>(); - actividad.put("userId", userId); - actividad.put("action", "eliminó un manga"); - actividad.put("mediaTitle", titulo); - actividad.put("imageUrl", imagen); - - api.postActivity(actividad).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - Log.d("ACTIVITY_DELETE", "Actividad de eliminación registrada"); - + Log.d("ACTIVITY", "Actividad registrada: " + action); if (getParentFragment() instanceof FragmentProfile) { ((FragmentProfile) getParentFragment()).loadActivity(); } @@ -232,10 +208,8 @@ public class EditMangaFragment extends Fragment { @Override public void onFailure(Call call, Throwable t) { - Log.e("ACTIVITY_DELETE", "Error al registrar actividad: " + t.getMessage(), t); + Log.e("ACTIVITY", "Error al registrar actividad: " + t.getMessage(), t); } }); } - - } diff --git a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/home/FragmentHome.java b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/home/FragmentHome.java index 69edc41..9216b48 100644 --- a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/home/FragmentHome.java +++ b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/home/FragmentHome.java @@ -1,6 +1,4 @@ -// FragmentHome.java package com.santiparra.yomitrack.ui.fragments.home; - import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; @@ -15,13 +13,11 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; - import com.bumptech.glide.Glide; import com.google.gson.JsonObject; import com.santiparra.yomitrack.R; diff --git a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/manga_list/FragmentManga.java b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/manga_list/FragmentManga.java index ec213df..73234f0 100644 --- a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/manga_list/FragmentManga.java +++ b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/manga_list/FragmentManga.java @@ -70,6 +70,7 @@ public class FragmentManga extends Fragment { initViews(view); setupListeners(); setupRecyclerView(); + setupResultListeners(); api = ApiClient.getClient().create(ApiService.class); SharedPreferences prefs = requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE); @@ -79,10 +80,9 @@ public class FragmentManga extends Fragment { Toast.makeText(getContext(), "Error: sesión no iniciada", Toast.LENGTH_SHORT).show(); return; } - // Mostrar el nombre del usuario + String username = prefs.getString("username", "Usuario"); - TextView textViewUsername = view.findViewById(R.id.textViewUsername); - textViewUsername.setText(username); + ((TextView) view.findViewById(R.id.textViewUsername)).setText(username); setViewType(currentViewType); loadMoreMangas(currentPage); @@ -151,15 +151,37 @@ public class FragmentManga extends Fragment { }); } + private void setupResultListeners() { + getParentFragmentManager().setFragmentResultListener("manga_add_request", this, (key, bundle) -> { + if (bundle.getBoolean("manga_added", false)) { + currentPage = 1; + mangaList.clear(); + adapter.updateList(new ArrayList<>()); + loadMoreMangas(currentPage); + } + }); + + getParentFragmentManager().setFragmentResultListener("manga_delete_request", this, (key, bundle) -> { + int deletedId = bundle.getInt("manga_id", -1); + if (deletedId != -1) { + for (int i = 0; i < mangaList.size(); i++) { + if (mangaList.get(i).getId() == deletedId) { + mangaList.remove(i); + adapter.notifyItemRemoved(i); + break; + } + } + } + }); + } + private void setViewType(int viewType) { currentViewType = viewType; - if (viewType == MangaAdapter.VIEW_LARGE) { recyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2)); } else { recyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); } - adapter = new MangaAdapter(mangaList, viewType, this::showEditDialog, this::deleteManga); recyclerView.setAdapter(adapter); } @@ -187,12 +209,15 @@ public class FragmentManga extends Fragment { @Override public void onResponse(Call call, Response response) { if (!isAdded()) return; - if (response.isSuccessful()) { + for (int i = 0; i < mangaList.size(); i++) { + if (mangaList.get(i).getId() == manga.getId()) { + mangaList.remove(i); + adapter.notifyItemRemoved(i); + break; + } + } Toast.makeText(requireContext(), response.body() != null ? response.body().getMessage() : "Manga eliminado", Toast.LENGTH_SHORT).show(); - currentPage = 1; - mangaList.clear(); - loadMoreMangas(currentPage); } else { Toast.makeText(requireContext(), "Error al eliminar", Toast.LENGTH_SHORT).show(); } @@ -214,7 +239,6 @@ public class FragmentManga extends Fragment { @Override public void onResponse(Call call, Response response) { if (!isAdded()) return; - if (response.isSuccessful() && response.body() != null) { List nuevos = response.body().getData(); mangaList.addAll(nuevos); diff --git a/app/src/main/res.zip b/app/src/main/res.zip index b332b7f..3106aff 100644 Binary files a/app/src/main/res.zip and b/app/src/main/res.zip differ diff --git a/app/src/main/res/drawable/progress_bar.xml b/app/src/main/res/drawable/progress_bar.xml index 3cc0b0b..9fdd773 100644 --- a/app/src/main/res/drawable/progress_bar.xml +++ b/app/src/main/res/drawable/progress_bar.xml @@ -7,11 +7,10 @@ - - + diff --git a/app/src/main/res/layout/fragment_forgot_password.xml b/app/src/main/res/layout/fragment_forgot_password.xml index b504833..9467c79 100644 --- a/app/src/main/res/layout/fragment_forgot_password.xml +++ b/app/src/main/res/layout/fragment_forgot_password.xml @@ -59,13 +59,6 @@ android:textColor="@android:color/white" android:layout_marginBottom="12dp" /> -