Mejora de xml para que se vea mucho mas formal!
This commit is contained in:
parent
2566402280
commit
92fa136769
Binary file not shown.
|
|
@ -7,18 +7,34 @@ import retrofit2.converter.gson.GsonConverterFactory;
|
||||||
|
|
||||||
public class ApiClient {
|
public class ApiClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL base del servidor donde está alojada la API del backend.
|
||||||
|
* <p>Nota: "10.0.2.2" es una dirección especial utilizada para acceder al localhost
|
||||||
|
* del host desde el emulador de Android.</p>
|
||||||
|
*/
|
||||||
private static final String BASE_URL = "http://10.0.2.2:3000/";
|
private static final String BASE_URL = "http://10.0.2.2:3000/";
|
||||||
|
|
||||||
|
/** Instancia única de Retrofit. */
|
||||||
private static Retrofit retrofit = null;
|
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() {
|
public static Retrofit getClient() {
|
||||||
if (retrofit == null) {
|
if (retrofit == null) {
|
||||||
|
// Interceptor para mostrar logs del cuerpo de la petición y respuesta HTTP
|
||||||
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
|
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
|
||||||
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
|
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
|
||||||
|
|
||||||
|
// Cliente HTTP personalizado con el interceptor de logging
|
||||||
OkHttpClient client = new OkHttpClient.Builder()
|
OkHttpClient client = new OkHttpClient.Builder()
|
||||||
.addInterceptor(logging)
|
.addInterceptor(logging)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
// Construcción de la instancia de Retrofit
|
||||||
retrofit = new Retrofit.Builder()
|
retrofit = new Retrofit.Builder()
|
||||||
.baseUrl(BASE_URL)
|
.baseUrl(BASE_URL)
|
||||||
.client(client)
|
.client(client)
|
||||||
|
|
|
||||||
|
|
@ -14,36 +14,58 @@ import com.santiparra.yomitrack.model.RegisterResponse;
|
||||||
import com.santiparra.yomitrack.model.UserStatsResponse;
|
import com.santiparra.yomitrack.model.UserStatsResponse;
|
||||||
import com.santiparra.yomitrack.utils.ActivityLog;
|
import com.santiparra.yomitrack.utils.ActivityLog;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.http.Body;
|
import retrofit2.http.*;
|
||||||
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;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interfaz ApiService que define todos los endpoints disponibles
|
||||||
|
* para la comunicación entre la app YomiTrack y el backend.
|
||||||
|
*
|
||||||
|
* <p>Usa Retrofit para declarar métodos HTTP de forma declarativa.</p>
|
||||||
|
*/
|
||||||
public interface ApiService {
|
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")
|
@POST("users/register")
|
||||||
Call<RegisterResponse> registerUser(@Body UserEntity user);
|
Call<RegisterResponse> 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")
|
@POST("users/login")
|
||||||
Call<LoginResponse> loginUser(@Body UserEntity user);
|
Call<LoginResponse> 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
|
@FormUrlEncoded
|
||||||
@POST("users/forgot-password")
|
@POST("users/forgot-password")
|
||||||
Call<ApiResponse> forgotPassword(@Field("email") String email);
|
Call<ApiResponse> 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
|
@FormUrlEncoded
|
||||||
@POST("users/reset-password")
|
@POST("users/reset-password")
|
||||||
Call<ApiResponse> resetPassword(
|
Call<ApiResponse> resetPassword(
|
||||||
|
|
@ -52,11 +74,25 @@ public interface ApiService {
|
||||||
@Field("newPassword") String newPassword
|
@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")
|
@POST("anime/add")
|
||||||
Call<ApiResponse> insertAnime(@Body AnimeEntity anime);
|
Call<ApiResponse> 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}")
|
@GET("/anime/list/{userId}")
|
||||||
Call<AnimePageResponse> getAnimes(
|
Call<AnimePageResponse> getAnimes(
|
||||||
@Path("userId") int userId,
|
@Path("userId") int userId,
|
||||||
|
|
@ -64,16 +100,57 @@ public interface ApiService {
|
||||||
@Query("size") int size
|
@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}")
|
@PUT("anime/{id}")
|
||||||
Call<ApiResponse> updateAnime(@Path("id") int animeId, @Body AnimeEntity anime);
|
Call<ApiResponse> 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}")
|
@DELETE("anime/delete/{id}")
|
||||||
Call<ApiResponse> deleteAnime(@Path("id") int id);
|
Call<ApiResponse> 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<List<AnimeEntity>> 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")
|
@POST("manga/add")
|
||||||
Call<ApiResponse> insertManga(@Body MangaEntity manga);
|
Call<ApiResponse> 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}")
|
@GET("/manga/list/{userId}")
|
||||||
Call<MangaPageResponse> getMangas(
|
Call<MangaPageResponse> getMangas(
|
||||||
@Path("userId") int userId,
|
@Path("userId") int userId,
|
||||||
|
|
@ -81,57 +158,125 @@ public interface ApiService {
|
||||||
@Query("size") int size
|
@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}")
|
@GET("manga/user/{userId}/status/{status}")
|
||||||
Call<List<MangaEntity>> getMangaByUserAndStatus(
|
Call<List<MangaEntity>> getMangaByUserAndStatus(
|
||||||
@Path("userId") int userId,
|
@Path("userId") int userId,
|
||||||
@Path("status") String status
|
@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}")
|
@PUT("manga/{id}")
|
||||||
Call<ApiResponse> updateManga(@Path("id") int mangaId, @Body MangaEntity manga);
|
Call<ApiResponse> 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}")
|
@DELETE("manga/delete/{id}")
|
||||||
Call<ApiResponse> deleteManga(@Path("id") int id);
|
Call<ApiResponse> 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")
|
@GET("users/{id}/stats")
|
||||||
Call<UserStatsResponse> getUserStats(@Path("id") int userId);
|
Call<UserStatsResponse> 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}")
|
@GET("api/activity/list/{userId}")
|
||||||
Call<List<ActivityLog>> getActivityLog(@Path("userId") int userId);
|
Call<List<ActivityLog>> 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}")
|
@GET("api/activity/comments/{activityId}")
|
||||||
Call<List<CommentModel>> getCommentsByActivity(@Path("activityId") int activityId);
|
Call<List<CommentModel>> 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}")
|
@GET("/api/activity/like/{userId}/{activityId}")
|
||||||
Call<JsonObject> checkLike(
|
Call<JsonObject> checkLike(
|
||||||
@Path("userId") int userId,
|
@Path("userId") int userId,
|
||||||
@Path("activityId") int activityId
|
@Path("activityId") int activityId
|
||||||
);
|
);
|
||||||
|
|
||||||
@GET("anime/user/{userId}/status/{status}")
|
/**
|
||||||
Call<List<AnimeEntity>> getAnimeByUserAndStatus(
|
* Envía un like a una actividad.
|
||||||
@Path("userId") int userId,
|
*
|
||||||
@Path("status") String status
|
* @param body JSON con userId y activityId.
|
||||||
);
|
* @return respuesta del backend.
|
||||||
|
*/
|
||||||
@POST("api/activity/like")
|
@POST("api/activity/like")
|
||||||
Call<JsonObject> postLike(@Body JsonObject body);
|
Call<JsonObject> postLike(@Body JsonObject body);
|
||||||
|
|
||||||
@POST("api/activity/comment")
|
/**
|
||||||
Call<JsonObject> postComment(@Body JsonObject body);
|
* Elimina un like de una actividad.
|
||||||
|
*
|
||||||
@POST("api/activity/add")
|
* @param body JSON con userId y activityId.
|
||||||
Call<JsonObject> postActivity(@Body Map<String, Object> body);
|
* @return respuesta del backend.
|
||||||
|
*/
|
||||||
@HTTP(method = "DELETE", path = "api/activity/like/remove", hasBody = true)
|
@HTTP(method = "DELETE", path = "api/activity/like/remove", hasBody = true)
|
||||||
Call<JsonObject> deleteLike(@Body JsonObject body);
|
Call<JsonObject> 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<JsonObject> 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<JsonObject> postActivity(@Body Map<String, Object> 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")
|
@GET("anilist/search")
|
||||||
Call<List<AniListMedia>> searchAniList(@Query("query") String query, @Query("type") String type);
|
Call<List<AniListMedia>> searchAniList(@Query("query") String query, @Query("type") String type);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,22 +4,55 @@ import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entidad que representa un anime guardado por el usuario en la base de datos local.
|
* 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 {
|
public class AnimeEntity implements Serializable {
|
||||||
|
|
||||||
|
/** ID único del anime en la base de datos. */
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
|
/** ID del usuario al que pertenece este anime. */
|
||||||
private int userId;
|
private int userId;
|
||||||
|
|
||||||
|
/** Título del anime. */
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
|
/** Puntuación asignada por el usuario (por ejemplo, del 1 al 10). */
|
||||||
private int score;
|
private int score;
|
||||||
|
|
||||||
|
/** Progreso actual del usuario (número de episodios vistos). */
|
||||||
private int progress;
|
private int progress;
|
||||||
|
|
||||||
|
/** Estado del anime (Watching, Completed, Paused, etc.). */
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
|
/** Tipo del anime (TV, Movie, OVA, etc.). */
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
|
/** URL de la imagen de portada del anime. */
|
||||||
private String imageUrl;
|
private String imageUrl;
|
||||||
|
|
||||||
|
/** Número total de episodios del anime. */
|
||||||
private int totalEpisodes;
|
private int totalEpisodes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor vacío requerido por algunas librerías como Room o Retrofit.
|
||||||
|
*/
|
||||||
public AnimeEntity() {
|
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) {
|
public AnimeEntity(int id, String title, String status, int userId, String imageUrl, int progress, int score, int totalEpisodes) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
|
|
@ -31,75 +64,92 @@ public class AnimeEntity implements Serializable {
|
||||||
this.totalEpisodes = totalEpisodes;
|
this.totalEpisodes = totalEpisodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters y Setters
|
/** @return ID del anime. */
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param id ID del anime. */
|
||||||
public void setId(int id) {
|
public void setId(int id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return ID del usuario. */
|
||||||
public int getUserId() {
|
public int getUserId() {
|
||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param userId ID del usuario. */
|
||||||
public void setUserId(int userId) {
|
public void setUserId(int userId) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Título del anime. */
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param title Título del anime. */
|
||||||
public void setTitle(String title) {
|
public void setTitle(String title) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Puntuación del anime. */
|
||||||
public int getScore() {
|
public int getScore() {
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param score Puntuación del anime. */
|
||||||
public void setScore(int score) {
|
public void setScore(int score) {
|
||||||
this.score = score;
|
this.score = score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Progreso del usuario (episodios vistos). */
|
||||||
public int getProgress() {
|
public int getProgress() {
|
||||||
return progress;
|
return progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param progress Episodios vistos por el usuario. */
|
||||||
public void setProgress(int progress) {
|
public void setProgress(int progress) {
|
||||||
this.progress = progress;
|
this.progress = progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Estado del anime. */
|
||||||
public String getStatus() {
|
public String getStatus() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param status Estado del anime. */
|
||||||
public void setStatus(String status) {
|
public void setStatus(String status) {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Tipo de anime (TV, Movie, etc.). */
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param type Tipo de anime. */
|
||||||
public void setType(String type) {
|
public void setType(String type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return URL de la imagen del anime. */
|
||||||
public String getImageUrl() {
|
public String getImageUrl() {
|
||||||
return imageUrl;
|
return imageUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param imageUrl URL de la imagen del anime. */
|
||||||
public void setImageUrl(String imageUrl) {
|
public void setImageUrl(String imageUrl) {
|
||||||
this.imageUrl = imageUrl;
|
this.imageUrl = imageUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Total de episodios del anime. */
|
||||||
public int getTotalEpisodes() {
|
public int getTotalEpisodes() {
|
||||||
return totalEpisodes;
|
return totalEpisodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param totalEpisodes Número total de episodios. */
|
||||||
public void setTotalEpisodes(int totalEpisodes) {
|
public void setTotalEpisodes(int totalEpisodes) {
|
||||||
this.totalEpisodes = totalEpisodes;
|
this.totalEpisodes = totalEpisodes;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,22 +4,55 @@ import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entidad que representa un manga guardado por el usuario en la base de datos local.
|
* 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 {
|
public class MangaEntity implements Serializable {
|
||||||
|
|
||||||
|
/** ID único del manga en la base de datos. */
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
|
/** ID del usuario al que pertenece este manga. */
|
||||||
private int userId;
|
private int userId;
|
||||||
|
|
||||||
|
/** Título del manga. */
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
|
/** Puntuación asignada por el usuario (por ejemplo, del 1 al 10). */
|
||||||
private int score;
|
private int score;
|
||||||
|
|
||||||
|
/** Progreso actual del usuario (capítulos leídos). */
|
||||||
private int progress;
|
private int progress;
|
||||||
|
|
||||||
|
/** Estado del manga (Reading, Completed, On-Hold, etc.). */
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
|
/** Tipo del manga (Manga, Manhwa, Doujinshi, etc.). */
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
|
/** URL de la imagen de portada del manga. */
|
||||||
private String imageUrl;
|
private String imageUrl;
|
||||||
|
|
||||||
|
/** Número total de capítulos del manga. */
|
||||||
private int totalChapters;
|
private int totalChapters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor vacío necesario para serialización y frameworks como Room o Retrofit.
|
||||||
|
*/
|
||||||
public MangaEntity() {
|
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) {
|
public MangaEntity(int id, String title, String status, int userId, String imageUrl, int progress, int score, int totalChapters) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
|
|
@ -31,76 +64,92 @@ public class MangaEntity implements Serializable {
|
||||||
this.totalChapters = totalChapters;
|
this.totalChapters = totalChapters;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters y Setters
|
/** @return ID del manga. */
|
||||||
|
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param id ID del manga. */
|
||||||
public void setId(int id) {
|
public void setId(int id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return ID del usuario propietario del manga. */
|
||||||
public int getUserId() {
|
public int getUserId() {
|
||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param userId ID del usuario propietario. */
|
||||||
public void setUserId(int userId) {
|
public void setUserId(int userId) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Título del manga. */
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param title Título del manga. */
|
||||||
public void setTitle(String title) {
|
public void setTitle(String title) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Puntuación asignada al manga. */
|
||||||
public int getScore() {
|
public int getScore() {
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param score Puntuación del manga. */
|
||||||
public void setScore(int score) {
|
public void setScore(int score) {
|
||||||
this.score = score;
|
this.score = score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Capítulos leídos por el usuario. */
|
||||||
public int getProgress() {
|
public int getProgress() {
|
||||||
return progress;
|
return progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param progress Capítulos que el usuario ha leído. */
|
||||||
public void setProgress(int progress) {
|
public void setProgress(int progress) {
|
||||||
this.progress = progress;
|
this.progress = progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Estado del manga (Reading, Dropped, etc.). */
|
||||||
public String getStatus() {
|
public String getStatus() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param status Estado actual del manga. */
|
||||||
public void setStatus(String status) {
|
public void setStatus(String status) {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Tipo de manga (e.g., Manhwa, Doujinshi). */
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param type Tipo de manga. */
|
||||||
public void setType(String type) {
|
public void setType(String type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return URL de la imagen del manga. */
|
||||||
public String getImageUrl() {
|
public String getImageUrl() {
|
||||||
return imageUrl;
|
return imageUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param imageUrl URL de la imagen de portada. */
|
||||||
public void setImageUrl(String imageUrl) {
|
public void setImageUrl(String imageUrl) {
|
||||||
this.imageUrl = imageUrl;
|
this.imageUrl = imageUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return Total de capítulos del manga. */
|
||||||
public int getTotalChapters() {
|
public int getTotalChapters() {
|
||||||
return totalChapters;
|
return totalChapters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param totalChapters Cantidad total de capítulos. */
|
||||||
public void setTotalChapters(int totalChapters) {
|
public void setTotalChapters(int totalChapters) {
|
||||||
this.totalChapters = totalChapters;
|
this.totalChapters = totalChapters;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,60 +3,87 @@ package com.santiparra.yomitrack.db.entities;
|
||||||
import com.google.gson.annotations.SerializedName;
|
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 {
|
public class UserEntity {
|
||||||
|
|
||||||
|
/** Identificador único del usuario. */
|
||||||
@SerializedName("id")
|
@SerializedName("id")
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
|
/** Nombre de usuario utilizado para iniciar sesión y mostrar en el perfil. */
|
||||||
@SerializedName("username")
|
@SerializedName("username")
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
|
/** Contraseña del usuario (debe manejarse con cuidado y encriptación en producción). */
|
||||||
@SerializedName("password")
|
@SerializedName("password")
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
|
/** Dirección de correo electrónico del usuario. */
|
||||||
@SerializedName("email")
|
@SerializedName("email")
|
||||||
private String 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) {
|
public UserEntity(String username, String password) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
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) {
|
public UserEntity(String username, String email, String password) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.email = email;
|
this.email = email;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return ID del usuario. */
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param id ID del usuario. */
|
||||||
public void setId(int id) {
|
public void setId(int id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return nombre de usuario. */
|
||||||
public String getUsername() {
|
public String getUsername() {
|
||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param username nombre de usuario. */
|
||||||
public void setUsername(String username) {
|
public void setUsername(String username) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return contraseña del usuario. */
|
||||||
public String getPassword() {
|
public String getPassword() {
|
||||||
return password;
|
return password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param password contraseña del usuario. */
|
||||||
public void setPassword(String password) {
|
public void setPassword(String password) {
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return correo electrónico del usuario. */
|
||||||
public String getEmail() {
|
public String getEmail() {
|
||||||
return email;
|
return email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param email correo electrónico del usuario. */
|
||||||
public void setEmail(String email) {
|
public void setEmail(String email) {
|
||||||
this.email = email;
|
this.email = email;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,75 @@
|
||||||
package com.santiparra.yomitrack.model;
|
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 {
|
public class AniListMedia {
|
||||||
|
|
||||||
|
/** ID único del media (anime o manga) proporcionado por AniList. */
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
|
/** Título del anime o manga. */
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
|
/** URL de la imagen de portada del anime o manga. */
|
||||||
private String imageUrl;
|
private String imageUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor vacío necesario para serialización/deserialización automática.
|
||||||
|
*/
|
||||||
public AniListMedia() {}
|
public AniListMedia() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devuelve el ID del media.
|
||||||
|
*
|
||||||
|
* @return ID del anime o manga.
|
||||||
|
*/
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTitle() {
|
/**
|
||||||
return title;
|
* Establece el ID del media.
|
||||||
}
|
*
|
||||||
|
* @param id ID del anime o manga.
|
||||||
public String getImageUrl() {
|
*/
|
||||||
return imageUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(int id) {
|
public void setId(int id) {
|
||||||
this.id = 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) {
|
public void setTitle(String title) {
|
||||||
this.title = 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) {
|
public void setImageUrl(String imageUrl) {
|
||||||
this.imageUrl = imageUrl;
|
this.imageUrl = imageUrl;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
package com.santiparra.yomitrack.model;
|
|
||||||
|
|
||||||
public class ApiResponse {
|
|
||||||
private String message;
|
|
||||||
|
|
||||||
public String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -20,7 +20,6 @@ import com.santiparra.yomitrack.api.ApiService;
|
||||||
import com.santiparra.yomitrack.db.entities.AnimeEntity;
|
import com.santiparra.yomitrack.db.entities.AnimeEntity;
|
||||||
import com.santiparra.yomitrack.db.entities.MangaEntity;
|
import com.santiparra.yomitrack.db.entities.MangaEntity;
|
||||||
import com.santiparra.yomitrack.model.AniListMedia;
|
import com.santiparra.yomitrack.model.AniListMedia;
|
||||||
import com.santiparra.yomitrack.utils.ActivityLog;
|
|
||||||
import com.santiparra.yomitrack.utils.DateUtils;
|
import com.santiparra.yomitrack.utils.DateUtils;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
@ -31,18 +30,36 @@ import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
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<AniListSearchAdapter.ViewHolder> {
|
public class AniListSearchAdapter extends RecyclerView.Adapter<AniListSearchAdapter.ViewHolder> {
|
||||||
|
|
||||||
private final List<AniListMedia> mediaList;
|
private final List<AniListMedia> mediaList;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final String mediaType;
|
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<AniListMedia> mediaList, String mediaType) {
|
public AniListSearchAdapter(Context context, List<AniListMedia> mediaList, String mediaType) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.mediaList = mediaList;
|
this.mediaList = mediaList;
|
||||||
this.mediaType = mediaType;
|
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
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
|
@ -50,6 +67,12 @@ public class AniListSearchAdapter extends RecyclerView.Adapter<AniListSearchAdap
|
||||||
return new ViewHolder(view);
|
return new ViewHolder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asigna los datos de un ítem a su vista correspondiente.
|
||||||
|
*
|
||||||
|
* @param holder ViewHolder que contiene la vista.
|
||||||
|
* @param position posición del ítem en la lista.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||||
AniListMedia item = mediaList.get(position);
|
AniListMedia item = mediaList.get(position);
|
||||||
|
|
@ -69,6 +92,7 @@ public class AniListSearchAdapter extends RecyclerView.Adapter<AniListSearchAdap
|
||||||
ApiService apiService = ApiClient.getClient().create(ApiService.class);
|
ApiService apiService = ApiClient.getClient().create(ApiService.class);
|
||||||
|
|
||||||
if (mediaType.equals("ANIME")) {
|
if (mediaType.equals("ANIME")) {
|
||||||
|
// Crear objeto AnimeEntity
|
||||||
AnimeEntity anime = new AnimeEntity(
|
AnimeEntity anime = new AnimeEntity(
|
||||||
item.getId(),
|
item.getId(),
|
||||||
item.getTitle(),
|
item.getTitle(),
|
||||||
|
|
@ -81,12 +105,13 @@ public class AniListSearchAdapter extends RecyclerView.Adapter<AniListSearchAdap
|
||||||
);
|
);
|
||||||
anime.setType("TV");
|
anime.setType("TV");
|
||||||
|
|
||||||
|
// Llamada para insertar anime
|
||||||
apiService.insertAnime(anime).enqueue(new Callback<>() {
|
apiService.insertAnime(anime).enqueue(new Callback<>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call call, Response response) {
|
public void onResponse(Call call, Response response) {
|
||||||
Toast.makeText(context, "Anime añadido", Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, "Anime añadido", Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
// 🔁 Registrar actividad usando Map
|
// Registrar actividad
|
||||||
Map<String, Object> body = new HashMap<>();
|
Map<String, Object> body = new HashMap<>();
|
||||||
body.put("userId", userId);
|
body.put("userId", userId);
|
||||||
body.put("action", "añadió");
|
body.put("action", "añadió");
|
||||||
|
|
@ -96,7 +121,9 @@ public class AniListSearchAdapter extends RecyclerView.Adapter<AniListSearchAdap
|
||||||
|
|
||||||
apiService.postActivity(body).enqueue(new Callback<>() {
|
apiService.postActivity(body).enqueue(new Callback<>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call call, Response response) {}
|
public void onResponse(Call call, Response response) {
|
||||||
|
// Actividad registrada (sin acción adicional)
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call call, Throwable t) {
|
public void onFailure(Call call, Throwable t) {
|
||||||
|
|
@ -112,6 +139,7 @@ public class AniListSearchAdapter extends RecyclerView.Adapter<AniListSearchAdap
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
// Crear objeto MangaEntity
|
||||||
MangaEntity manga = new MangaEntity(
|
MangaEntity manga = new MangaEntity(
|
||||||
item.getId(),
|
item.getId(),
|
||||||
item.getTitle(),
|
item.getTitle(),
|
||||||
|
|
@ -124,6 +152,7 @@ public class AniListSearchAdapter extends RecyclerView.Adapter<AniListSearchAdap
|
||||||
);
|
);
|
||||||
manga.setType("Manga");
|
manga.setType("Manga");
|
||||||
|
|
||||||
|
// Llamada para insertar manga
|
||||||
apiService.insertManga(manga).enqueue(new Callback<>() {
|
apiService.insertManga(manga).enqueue(new Callback<>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call call, Response response) {
|
public void onResponse(Call call, Response response) {
|
||||||
|
|
@ -156,16 +185,35 @@ public class AniListSearchAdapter extends RecyclerView.Adapter<AniListSearchAdap
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devuelve la cantidad de elementos en la lista.
|
||||||
|
*
|
||||||
|
* @return número total de ítems en la búsqueda.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return mediaList.size();
|
return mediaList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clase interna que representa un ítem individual del RecyclerView.
|
||||||
|
*/
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
|
/** Título del anime/manga. */
|
||||||
TextView title;
|
TextView title;
|
||||||
|
|
||||||
|
/** Imagen de portada del anime/manga. */
|
||||||
ImageView cover;
|
ImageView cover;
|
||||||
|
|
||||||
|
/** Botón para añadir el ítem a la lista del usuario. */
|
||||||
Button btnAdd;
|
Button btnAdd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor del ViewHolder.
|
||||||
|
*
|
||||||
|
* @param itemView vista del ítem individual.
|
||||||
|
*/
|
||||||
public ViewHolder(View itemView) {
|
public ViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
title = itemView.findViewById(R.id.itemTitle);
|
title = itemView.findViewById(R.id.itemTitle);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package com.santiparra.yomitrack.model.adapters.anime_adapter;
|
package com.santiparra.yomitrack.model.adapters.anime_adapter;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
@ -18,17 +17,41 @@ import com.santiparra.yomitrack.db.entities.AnimeEntity;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adaptador de RecyclerView para mostrar una lista de animes con soporte para múltiples tipos de vista:
|
||||||
|
* normal, compacta y grande. Permite manejar clics normales y prolongados sobre los ítems.
|
||||||
|
*/
|
||||||
public class AnimeAdapter extends RecyclerView.Adapter<AnimeAdapter.AnimeViewHolder> {
|
public class AnimeAdapter extends RecyclerView.Adapter<AnimeAdapter.AnimeViewHolder> {
|
||||||
|
|
||||||
|
/** Vista normal por defecto. */
|
||||||
public static final int VIEW_NORMAL = 0;
|
public static final int VIEW_NORMAL = 0;
|
||||||
|
|
||||||
|
/** Vista compacta. */
|
||||||
public static final int VIEW_COMPACT = 1;
|
public static final int VIEW_COMPACT = 1;
|
||||||
|
|
||||||
|
/** Vista ampliada. */
|
||||||
public static final int VIEW_LARGE = 2;
|
public static final int VIEW_LARGE = 2;
|
||||||
|
|
||||||
|
/** Lista de animes a mostrar. */
|
||||||
private List<AnimeEntity> animeList;
|
private List<AnimeEntity> animeList;
|
||||||
|
|
||||||
|
/** Tipo de vista actual. */
|
||||||
private int viewType;
|
private int viewType;
|
||||||
|
|
||||||
|
/** Listener para clics normales (edición). */
|
||||||
private final OnAnimeClickListener onEditClick;
|
private final OnAnimeClickListener onEditClick;
|
||||||
|
|
||||||
|
/** Listener para clics prolongados (acciones extendidas). */
|
||||||
private final OnAnimeClickListener onLongClick;
|
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<AnimeEntity> animeList, int viewType,
|
public AnimeAdapter(List<AnimeEntity> animeList, int viewType,
|
||||||
OnAnimeClickListener onEditClick,
|
OnAnimeClickListener onEditClick,
|
||||||
OnAnimeClickListener onLongClick) {
|
OnAnimeClickListener onLongClick) {
|
||||||
|
|
@ -38,13 +61,23 @@ public class AnimeAdapter extends RecyclerView.Adapter<AnimeAdapter.AnimeViewHol
|
||||||
this.onLongClick = onLongClick;
|
this.onLongClick = onLongClick;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cambia el tipo de vista del adaptador.
|
||||||
|
*
|
||||||
|
* @param viewType nuevo tipo de vista.
|
||||||
|
*/
|
||||||
public void setViewType(int viewType) {
|
public void setViewType(int viewType) {
|
||||||
this.viewType = viewType;
|
this.viewType = viewType;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza la lista de animes mostrada.
|
||||||
|
*
|
||||||
|
* @param newList nueva lista de animes.
|
||||||
|
*/
|
||||||
public void updateList(List<AnimeEntity> newList) {
|
public void updateList(List<AnimeEntity> newList) {
|
||||||
this.animeList = newList != null ? newList : new ArrayList<>();
|
this.animeList = new ArrayList<>(newList); // o .clear() + .addAll()
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,11 +178,37 @@ public class AnimeAdapter extends RecyclerView.Adapter<AnimeAdapter.AnimeViewHol
|
||||||
return viewType;
|
return viewType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ViewHolder que representa un ítem individual del RecyclerView de animes.
|
||||||
|
*/
|
||||||
public static class AnimeViewHolder extends RecyclerView.ViewHolder {
|
public static class AnimeViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
|
/** Imagen de portada del anime. */
|
||||||
ImageView imageCover;
|
ImageView imageCover;
|
||||||
TextView textTitle, textStatus, textProgress, textScore, textType;
|
|
||||||
|
/** Título del anime. */
|
||||||
|
TextView textTitle;
|
||||||
|
|
||||||
|
/** Texto que muestra el estado y tipo del anime. */
|
||||||
|
TextView textStatus;
|
||||||
|
|
||||||
|
/** Texto que muestra el progreso (episodios vistos). */
|
||||||
|
TextView textProgress;
|
||||||
|
|
||||||
|
/** Texto que muestra la puntuación. */
|
||||||
|
TextView textScore;
|
||||||
|
|
||||||
|
/** Texto que muestra el tipo de anime. */
|
||||||
|
TextView textType;
|
||||||
|
|
||||||
|
/** Punto de color que indica el estado visualmente. */
|
||||||
View statusDot;
|
View statusDot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor del ViewHolder.
|
||||||
|
*
|
||||||
|
* @param itemView vista inflada del ítem.
|
||||||
|
*/
|
||||||
public AnimeViewHolder(@NonNull View itemView) {
|
public AnimeViewHolder(@NonNull View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
imageCover = itemView.findViewById(R.id.imageCover);
|
imageCover = itemView.findViewById(R.id.imageCover);
|
||||||
|
|
@ -162,7 +221,15 @@ public class AnimeAdapter extends RecyclerView.Adapter<AnimeAdapter.AnimeViewHol
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interfaz para manejar clics sobre un anime.
|
||||||
|
*/
|
||||||
public interface OnAnimeClickListener {
|
public interface OnAnimeClickListener {
|
||||||
|
/**
|
||||||
|
* Método invocado al hacer clic en un ítem de anime.
|
||||||
|
*
|
||||||
|
* @param anime objeto de anime clicado.
|
||||||
|
*/
|
||||||
void onClick(AnimeEntity anime);
|
void onClick(AnimeEntity anime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,65 +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.view.animation.Animation;
|
|
||||||
import android.view.animation.AnimationUtils;
|
|
||||||
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;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class BrowseGridAdapter extends RecyclerView.Adapter<BrowseGridAdapter.ViewHolder> {
|
|
||||||
|
|
||||||
private final List<ItemModel> items;
|
|
||||||
|
|
||||||
public BrowseGridAdapter(List<ItemModel> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -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<BrowseSectionAdapter.BrowseViewHolder> {
|
|
||||||
|
|
||||||
private final List<BrowseSection> sectionList;
|
|
||||||
|
|
||||||
public BrowseSectionAdapter(List<BrowseSection> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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<RecyclerView.ViewHolder> {
|
|
||||||
|
|
||||||
private List<ItemModel> itemList;
|
|
||||||
private String sectionTitle;
|
|
||||||
|
|
||||||
private static final int TYPE_AIRING = 0;
|
|
||||||
private static final int TYPE_ANIME_MANGA = 1;
|
|
||||||
|
|
||||||
public HomeAdapter(List<ItemModel> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -17,20 +17,48 @@ import com.santiparra.yomitrack.model.ItemModel;
|
||||||
|
|
||||||
import java.util.List;
|
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<HomeCardAdapter.ViewHolder> {
|
public class HomeCardAdapter extends RecyclerView.Adapter<HomeCardAdapter.ViewHolder> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interfaz para manejar clics en los ítems del RecyclerView.
|
||||||
|
*/
|
||||||
public interface OnItemClickListener {
|
public interface OnItemClickListener {
|
||||||
|
/**
|
||||||
|
* Se llama cuando el usuario hace clic sobre un ítem.
|
||||||
|
*
|
||||||
|
* @param item el ítem seleccionado.
|
||||||
|
*/
|
||||||
void onItemClick(ItemModel item);
|
void onItemClick(ItemModel item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Lista de ítems a mostrar (animes o mangas). */
|
||||||
private final List<ItemModel> itemList;
|
private final List<ItemModel> itemList;
|
||||||
|
|
||||||
|
/** Listener que maneja clics en los ítems. */
|
||||||
private final OnItemClickListener listener;
|
private final OnItemClickListener listener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor del adaptador.
|
||||||
|
*
|
||||||
|
* @param itemList lista de ítems a mostrar.
|
||||||
|
* @param listener manejador de eventos de clic.
|
||||||
|
*/
|
||||||
public HomeCardAdapter(List<ItemModel> itemList, OnItemClickListener listener) {
|
public HomeCardAdapter(List<ItemModel> itemList, OnItemClickListener listener) {
|
||||||
this.itemList = itemList;
|
this.itemList = itemList;
|
||||||
this.listener = listener;
|
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
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
|
@ -38,26 +66,58 @@ public class HomeCardAdapter extends RecyclerView.Adapter<HomeCardAdapter.ViewHo
|
||||||
return new ViewHolder(view);
|
return new ViewHolder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asocia los datos del ítem con su vista.
|
||||||
|
*
|
||||||
|
* @param holder ViewHolder con las vistas del ítem.
|
||||||
|
* @param position posición del ítem en la lista.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||||
ItemModel item = itemList.get(position);
|
ItemModel item = itemList.get(position);
|
||||||
holder.title.setText(item.getTitle());
|
holder.title.setText(item.getTitle());
|
||||||
holder.progress.setText(item.getProgress());
|
holder.progress.setText(item.getProgress());
|
||||||
Glide.with(holder.itemView.getContext()).load(item.getImageUrl()).into(holder.cover);
|
|
||||||
|
Glide.with(holder.itemView.getContext())
|
||||||
|
.load(item.getImageUrl())
|
||||||
|
.placeholder(R.drawable.rectangle_placeholder)
|
||||||
|
.into(holder.cover);
|
||||||
|
|
||||||
holder.card.setOnClickListener(v -> listener.onItemClick(item));
|
holder.card.setOnClickListener(v -> listener.onItemClick(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devuelve la cantidad de ítems en la lista.
|
||||||
|
*
|
||||||
|
* @return número total de ítems.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return itemList.size();
|
return itemList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ViewHolder que representa cada tarjeta (ítem) en el RecyclerView.
|
||||||
|
*/
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
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;
|
ImageView cover;
|
||||||
|
|
||||||
|
/** Tarjeta contenedora del ítem. */
|
||||||
CardView card;
|
CardView card;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor del ViewHolder.
|
||||||
|
*
|
||||||
|
* @param itemView vista del ítem inflada desde el layout.
|
||||||
|
*/
|
||||||
public ViewHolder(@NonNull View itemView) {
|
public ViewHolder(@NonNull View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
title = itemView.findViewById(R.id.itemTitle);
|
title = itemView.findViewById(R.id.itemTitle);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package com.santiparra.yomitrack.model.adapters.manga_adapter;
|
package com.santiparra.yomitrack.model.adapters.manga_adapter;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
@ -17,17 +16,41 @@ import com.santiparra.yomitrack.db.entities.MangaEntity;
|
||||||
|
|
||||||
import java.util.List;
|
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<MangaAdapter.MangaViewHolder> {
|
public class MangaAdapter extends RecyclerView.Adapter<MangaAdapter.MangaViewHolder> {
|
||||||
|
|
||||||
|
/** Vista estándar. */
|
||||||
public static final int VIEW_NORMAL = 0;
|
public static final int VIEW_NORMAL = 0;
|
||||||
|
|
||||||
|
/** Vista compacta. */
|
||||||
public static final int VIEW_COMPACT = 1;
|
public static final int VIEW_COMPACT = 1;
|
||||||
|
|
||||||
|
/** Vista grande. */
|
||||||
public static final int VIEW_LARGE = 2;
|
public static final int VIEW_LARGE = 2;
|
||||||
|
|
||||||
|
/** Lista de mangas a mostrar. */
|
||||||
private List<MangaEntity> mangaList;
|
private List<MangaEntity> mangaList;
|
||||||
|
|
||||||
|
/** Tipo de vista actual. */
|
||||||
private int viewType;
|
private int viewType;
|
||||||
|
|
||||||
|
/** Listener para clic corto (edición). */
|
||||||
private final OnMangaClickListener onEditClick;
|
private final OnMangaClickListener onEditClick;
|
||||||
|
|
||||||
|
/** Listener para clic prolongado (acciones extendidas). */
|
||||||
private final OnMangaClickListener onLongClick;
|
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<MangaEntity> mangaList, int viewType,
|
public MangaAdapter(List<MangaEntity> mangaList, int viewType,
|
||||||
OnMangaClickListener onEditClick,
|
OnMangaClickListener onEditClick,
|
||||||
OnMangaClickListener onLongClick) {
|
OnMangaClickListener onLongClick) {
|
||||||
|
|
@ -124,21 +147,51 @@ public class MangaAdapter extends RecyclerView.Adapter<MangaAdapter.MangaViewHol
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devuelve la cantidad de mangas en la lista.
|
||||||
|
*
|
||||||
|
* @return número total de ítems.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return mangaList != null ? mangaList.size() : 0;
|
return mangaList != null ? mangaList.size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devuelve el tipo de vista para el ítem en la posición dada.
|
||||||
|
*
|
||||||
|
* @param position posición del ítem.
|
||||||
|
* @return tipo de vista.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getItemViewType(int position) {
|
public int getItemViewType(int position) {
|
||||||
return viewType;
|
return viewType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reemplaza la lista actual por una nueva y actualiza el adaptador.
|
||||||
|
*
|
||||||
|
* @param newList nueva lista de mangas.
|
||||||
|
*/
|
||||||
|
public void updateList(List<MangaEntity> newList) {
|
||||||
|
mangaList.clear();
|
||||||
|
mangaList.addAll(newList);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ViewHolder para representar un ítem de manga en el RecyclerView.
|
||||||
|
*/
|
||||||
public static class MangaViewHolder extends RecyclerView.ViewHolder {
|
public static class MangaViewHolder extends RecyclerView.ViewHolder {
|
||||||
ImageView imageCover;
|
ImageView imageCover;
|
||||||
TextView textTitle, textStatus, textProgress, textScore, textType;
|
TextView textTitle, textStatus, textProgress, textScore, textType;
|
||||||
View statusDot;
|
View statusDot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor del ViewHolder.
|
||||||
|
*
|
||||||
|
* @param itemView vista inflada del ítem.
|
||||||
|
*/
|
||||||
public MangaViewHolder(@NonNull View itemView) {
|
public MangaViewHolder(@NonNull View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
imageCover = itemView.findViewById(R.id.imageCover);
|
imageCover = itemView.findViewById(R.id.imageCover);
|
||||||
|
|
@ -151,12 +204,15 @@ public class MangaAdapter extends RecyclerView.Adapter<MangaAdapter.MangaViewHol
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateList(List<MangaEntity> newList) {
|
/**
|
||||||
this.mangaList = newList;
|
* Interfaz para manejar clics sobre ítems de manga.
|
||||||
notifyDataSetChanged();
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnMangaClickListener {
|
public interface OnMangaClickListener {
|
||||||
|
/**
|
||||||
|
* Se ejecuta cuando se hace clic en un manga.
|
||||||
|
*
|
||||||
|
* @param manga el ítem clicado.
|
||||||
|
*/
|
||||||
void onClick(MangaEntity manga);
|
void onClick(MangaEntity manga);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,25 +15,58 @@ import com.santiparra.yomitrack.model.AniListMedia;
|
||||||
|
|
||||||
import java.util.List;
|
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<MangaSearchAdapter.SearchViewHolder> {
|
public class MangaSearchAdapter extends RecyclerView.Adapter<MangaSearchAdapter.SearchViewHolder> {
|
||||||
|
|
||||||
|
/** Lista de mangas obtenidos desde la API de AniList. */
|
||||||
private List<AniListMedia> mangaList;
|
private List<AniListMedia> mangaList;
|
||||||
|
|
||||||
|
/** Listener para manejar clics en los ítems del RecyclerView. */
|
||||||
private final OnMangaClickListener clickListener;
|
private final OnMangaClickListener clickListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interfaz que define el callback cuando se hace clic en un manga.
|
||||||
|
*/
|
||||||
public interface OnMangaClickListener {
|
public interface OnMangaClickListener {
|
||||||
|
/**
|
||||||
|
* Método invocado al hacer clic sobre un manga.
|
||||||
|
*
|
||||||
|
* @param manga objeto de AniList clicado.
|
||||||
|
*/
|
||||||
void onClick(AniListMedia manga);
|
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<AniListMedia> mangaList, OnMangaClickListener clickListener) {
|
public MangaSearchAdapter(List<AniListMedia> mangaList, OnMangaClickListener clickListener) {
|
||||||
this.mangaList = mangaList;
|
this.mangaList = mangaList;
|
||||||
this.clickListener = clickListener;
|
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<AniListMedia> mangaList) {
|
public void setMangaList(List<AniListMedia> mangaList) {
|
||||||
this.mangaList = mangaList;
|
this.mangaList = mangaList;
|
||||||
notifyDataSetChanged();
|
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
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public SearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public SearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
|
@ -41,6 +74,12 @@ public class MangaSearchAdapter extends RecyclerView.Adapter<MangaSearchAdapter.
|
||||||
return new SearchViewHolder(view);
|
return new SearchViewHolder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asocia los datos del manga con la vista.
|
||||||
|
*
|
||||||
|
* @param holder ViewHolder que contiene la vista.
|
||||||
|
* @param position posición del ítem en la lista.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull SearchViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull SearchViewHolder holder, int position) {
|
||||||
AniListMedia manga = mangaList.get(position);
|
AniListMedia manga = mangaList.get(position);
|
||||||
|
|
@ -54,15 +93,31 @@ public class MangaSearchAdapter extends RecyclerView.Adapter<MangaSearchAdapter.
|
||||||
holder.itemView.setOnClickListener(v -> clickListener.onClick(manga));
|
holder.itemView.setOnClickListener(v -> clickListener.onClick(manga));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devuelve la cantidad total de mangas en la lista.
|
||||||
|
*
|
||||||
|
* @return tamaño de la lista.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return mangaList != null ? mangaList.size() : 0;
|
return mangaList != null ? mangaList.size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ViewHolder que representa cada ítem del RecyclerView.
|
||||||
|
*/
|
||||||
static class SearchViewHolder extends RecyclerView.ViewHolder {
|
static class SearchViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
/** Imagen de portada del manga. */
|
||||||
ImageView imageCover;
|
ImageView imageCover;
|
||||||
|
|
||||||
|
/** Título del manga. */
|
||||||
TextView title;
|
TextView title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor del ViewHolder.
|
||||||
|
*
|
||||||
|
* @param itemView vista inflada del ítem.
|
||||||
|
*/
|
||||||
public SearchViewHolder(@NonNull View itemView) {
|
public SearchViewHolder(@NonNull View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
imageCover = itemView.findViewById(R.id.imageCover);
|
imageCover = itemView.findViewById(R.id.imageCover);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
|
@ -18,11 +19,24 @@ import com.santiparra.yomitrack.model.RecentActivityModel;
|
||||||
|
|
||||||
import java.util.List;
|
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<RecentActivityAdapter.ActivityViewHolder> {
|
public class RecentActivityAdapter extends RecyclerView.Adapter<RecentActivityAdapter.ActivityViewHolder> {
|
||||||
|
|
||||||
|
/** Lista de actividades recientes. */
|
||||||
private List<RecentActivityModel> activityList;
|
private List<RecentActivityModel> activityList;
|
||||||
|
|
||||||
|
/** ID del usuario actualmente logueado (para comentarios y likes). */
|
||||||
private final int currentUserId;
|
private final int currentUserId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor del adaptador.
|
||||||
|
*
|
||||||
|
* @param activityList lista de actividades a mostrar.
|
||||||
|
* @param currentUserId ID del usuario actual.
|
||||||
|
*/
|
||||||
public RecentActivityAdapter(List<RecentActivityModel> activityList, int currentUserId) {
|
public RecentActivityAdapter(List<RecentActivityModel> activityList, int currentUserId) {
|
||||||
this.activityList = activityList;
|
this.activityList = activityList;
|
||||||
this.currentUserId = currentUserId;
|
this.currentUserId = currentUserId;
|
||||||
|
|
@ -31,7 +45,8 @@ public class RecentActivityAdapter extends RecyclerView.Adapter<RecentActivityAd
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public ActivityViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public ActivityViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_activity_card, parent, false);
|
View view = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.item_activity_card, parent, false);
|
||||||
return new ActivityViewHolder(view);
|
return new ActivityViewHolder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,9 +64,11 @@ public class RecentActivityAdapter extends RecyclerView.Adapter<RecentActivityAd
|
||||||
.placeholder(R.drawable.placeholder_image)
|
.placeholder(R.drawable.placeholder_image)
|
||||||
.into(holder.image);
|
.into(holder.image);
|
||||||
|
|
||||||
|
// Limpiar contenedor de comentarios antes de agregar los nuevos
|
||||||
holder.commentContainer.removeAllViews();
|
holder.commentContainer.removeAllViews();
|
||||||
LayoutInflater inflater = LayoutInflater.from(holder.itemView.getContext());
|
LayoutInflater inflater = LayoutInflater.from(holder.itemView.getContext());
|
||||||
|
|
||||||
|
// Mostrar comentarios
|
||||||
for (CommentModel comment : activity.comments) {
|
for (CommentModel comment : activity.comments) {
|
||||||
View commentView = inflater.inflate(R.layout.item_comment, holder.commentContainer, false);
|
View commentView = inflater.inflate(R.layout.item_comment, holder.commentContainer, false);
|
||||||
|
|
||||||
|
|
@ -75,39 +92,16 @@ public class RecentActivityAdapter extends RecyclerView.Adapter<RecentActivityAd
|
||||||
likeButton.setImageResource(comment.isLiked() ? R.drawable.ic_heart_filled : R.drawable.ic_heart_outline);
|
likeButton.setImageResource(comment.isLiked() ? R.drawable.ic_heart_filled : R.drawable.ic_heart_outline);
|
||||||
likeButton.setColorFilter(commentView.getContext().getColor(comment.isLiked() ? R.color.pink : R.color.gray));
|
likeButton.setColorFilter(commentView.getContext().getColor(comment.isLiked() ? R.color.pink : R.color.gray));
|
||||||
|
|
||||||
likeButton.setOnClickListener(new View.OnClickListener() {
|
// Manejo de likes en comentarios
|
||||||
@Override
|
likeButton.setOnClickListener(v -> {
|
||||||
public void onClick(View v) {
|
boolean newLike = !comment.isLiked();
|
||||||
boolean newLike = !comment.isLiked();
|
comment.setLiked(newLike);
|
||||||
comment.setLiked(newLike);
|
likeButton.setImageResource(newLike ? R.drawable.ic_heart_filled : R.drawable.ic_heart_outline);
|
||||||
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));
|
||||||
likeButton.setColorFilter(commentView.getContext().getColor(newLike ? R.color.pink : R.color.gray));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
replyButton.setOnClickListener(new View.OnClickListener() {
|
// Manejo de respuesta a un comentario
|
||||||
@Override
|
replyButton.setOnClickListener(v -> {
|
||||||
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) {
|
|
||||||
int adapterPos = holder.getAdapterPosition();
|
int adapterPos = holder.getAdapterPosition();
|
||||||
if (adapterPos == RecyclerView.NO_POSITION) return;
|
if (adapterPos == RecyclerView.NO_POSITION) return;
|
||||||
RecentActivityModel activityItem = activityList.get(adapterPos);
|
RecentActivityModel activityItem = activityList.get(adapterPos);
|
||||||
|
|
@ -115,39 +109,72 @@ public class RecentActivityAdapter extends RecyclerView.Adapter<RecentActivityAd
|
||||||
holder.itemView.getContext(),
|
holder.itemView.getContext(),
|
||||||
currentUserId,
|
currentUserId,
|
||||||
activityItem.getId(),
|
activityItem.getId(),
|
||||||
() -> notifyItemChanged(adapterPos)
|
() -> notifyItemChanged(adapterPos),
|
||||||
|
comment.getUsername()
|
||||||
);
|
);
|
||||||
dialog.show();
|
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() {
|
// Botón de like para la actividad
|
||||||
@Override
|
holder.likeButton.setOnClickListener(v -> {
|
||||||
public void onClick(View v) {
|
activity.liked = !activity.liked;
|
||||||
activity.liked = !activity.liked;
|
holder.likeButton.setImageResource(activity.liked ? R.drawable.ic_heart_filled : R.drawable.ic_heart_outline);
|
||||||
holder.likeButton.setImageResource(activity.liked ? R.drawable.ic_heart_filled : R.drawable.ic_heart_outline);
|
holder.likeButton.setColorFilter(holder.itemView.getContext().getColor(
|
||||||
holder.likeButton.setColorFilter(holder.itemView.getContext().getColor(
|
activity.liked ? R.color.pink : R.color.textPrimary));
|
||||||
activity.liked ? R.color.pink : R.color.textPrimary));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Devuelve la cantidad de actividades en la lista.
|
||||||
|
*
|
||||||
|
* @return tamaño de la lista.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return activityList.size();
|
return activityList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reemplaza la lista actual por una nueva y actualiza la vista.
|
||||||
|
*
|
||||||
|
* @param newList nueva lista de actividades.
|
||||||
|
*/
|
||||||
public void updateData(List<RecentActivityModel> newList) {
|
public void updateData(List<RecentActivityModel> newList) {
|
||||||
this.activityList = newList;
|
this.activityList = newList;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ViewHolder que representa una tarjeta de actividad reciente.
|
||||||
|
*/
|
||||||
static class ActivityViewHolder extends RecyclerView.ViewHolder {
|
static class ActivityViewHolder extends RecyclerView.ViewHolder {
|
||||||
TextView user, action, title, time;
|
TextView user, action, title, time;
|
||||||
ImageView image;
|
ImageView image;
|
||||||
ImageButton likeButton, commentButton;
|
ImageButton likeButton, commentButton;
|
||||||
LinearLayout commentContainer;
|
LinearLayout commentContainer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor del ViewHolder.
|
||||||
|
*
|
||||||
|
* @param itemView vista inflada del ítem.
|
||||||
|
*/
|
||||||
public ActivityViewHolder(@NonNull View itemView) {
|
public ActivityViewHolder(@NonNull View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
user = itemView.findViewById(R.id.activityUser);
|
user = itemView.findViewById(R.id.activityUser);
|
||||||
|
|
|
||||||
|
|
@ -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<SectionAdapter.SectionViewHolder> {
|
|
||||||
|
|
||||||
private final List<String> sectionTitles;
|
|
||||||
private final Map<String, List<ItemModel>> sectionItems;
|
|
||||||
|
|
||||||
public SectionAdapter(List<String> sectionTitles, Map<String, List<ItemModel>> 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<ItemModel> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -75,18 +75,12 @@ public class AddAnimeFragment extends Fragment {
|
||||||
|
|
||||||
private void setupSpinners() {
|
private void setupSpinners() {
|
||||||
ArrayAdapter<CharSequence> statusAdapter = ArrayAdapter.createFromResource(
|
ArrayAdapter<CharSequence> statusAdapter = ArrayAdapter.createFromResource(
|
||||||
requireContext(),
|
requireContext(), R.array.anime_status_array, R.layout.item_spinner);
|
||||||
R.array.anime_status_array,
|
statusAdapter.setDropDownViewResource(R.layout.item_spinner);
|
||||||
R.layout.item_spinner
|
|
||||||
);
|
|
||||||
statusAdapter.setDropDownViewResource(R.layout.item_spinner); // ✅ blanco también al desplegar
|
|
||||||
statusSpinner.setAdapter(statusAdapter);
|
statusSpinner.setAdapter(statusAdapter);
|
||||||
|
|
||||||
ArrayAdapter<CharSequence> typeAdapter = ArrayAdapter.createFromResource(
|
ArrayAdapter<CharSequence> typeAdapter = ArrayAdapter.createFromResource(
|
||||||
requireContext(),
|
requireContext(), R.array.anime_type_array, R.layout.item_spinner);
|
||||||
R.array.anime_type_array,
|
|
||||||
R.layout.item_spinner
|
|
||||||
);
|
|
||||||
typeAdapter.setDropDownViewResource(R.layout.item_spinner);
|
typeAdapter.setDropDownViewResource(R.layout.item_spinner);
|
||||||
typeSpinner.setAdapter(typeAdapter);
|
typeSpinner.setAdapter(typeAdapter);
|
||||||
}
|
}
|
||||||
|
|
@ -128,23 +122,16 @@ public class AddAnimeFragment extends Fragment {
|
||||||
String status = statusSpinner.getSelectedItem().toString();
|
String status = statusSpinner.getSelectedItem().toString();
|
||||||
String type = typeSpinner.getSelectedItem().toString();
|
String type = typeSpinner.getSelectedItem().toString();
|
||||||
|
|
||||||
int score = 0;
|
int score = parseIntOrZero(scoreEditText.getText().toString());
|
||||||
int progress = 0;
|
int progress = parseIntOrZero(progressEditText.getText().toString());
|
||||||
try {
|
|
||||||
score = Integer.parseInt(scoreEditText.getText().toString());
|
|
||||||
progress = Integer.parseInt(progressEditText.getText().toString());
|
|
||||||
} catch (NumberFormatException ignored) {
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimeEntity anime = new AnimeEntity();
|
AnimeEntity anime = new AnimeEntity();
|
||||||
anime.setUserId(userId);
|
anime.setUserId(userId);
|
||||||
anime.setTitle(selected.getTitle());
|
anime.setTitle(selected.getTitle());
|
||||||
|
|
||||||
if (selected.getImageUrl() == null || selected.getImageUrl().isEmpty()) {
|
selectedImageUrl = (selected.getImageUrl() == null || selected.getImageUrl().isEmpty())
|
||||||
selectedImageUrl = "android.resource://" + requireContext().getPackageName() + "/" + R.drawable.sample_cover;
|
? "android.resource://" + requireContext().getPackageName() + "/" + R.drawable.sample_cover
|
||||||
} else {
|
: selected.getImageUrl();
|
||||||
selectedImageUrl = selected.getImageUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
anime.setImageUrl(selectedImageUrl);
|
anime.setImageUrl(selectedImageUrl);
|
||||||
anime.setStatus(status);
|
anime.setStatus(status);
|
||||||
|
|
@ -158,6 +145,7 @@ public class AddAnimeFragment extends Fragment {
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
Toast.makeText(getContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show();
|
Toast.makeText(getContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
registrarActividad(anime.getTitle());
|
registrarActividad(anime.getTitle());
|
||||||
|
notificarAñadido();
|
||||||
requireActivity().getSupportFragmentManager().popBackStack();
|
requireActivity().getSupportFragmentManager().popBackStack();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(getContext(), "Error al guardar anime", Toast.LENGTH_SHORT).show();
|
Toast.makeText(getContext(), "Error al guardar anime", Toast.LENGTH_SHORT).show();
|
||||||
|
|
@ -182,17 +170,29 @@ public class AddAnimeFragment extends Fragment {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
|
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
|
||||||
Log.d("ACTIVITY_POST", "Código de respuesta: " + response.code());
|
Log.d("ACTIVITY_POST", "Código de respuesta: " + response.code());
|
||||||
if (!response.isSuccessful()) {
|
|
||||||
Log.e("ACTIVITY_POST", "Error en response: " + response.errorBody());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<JsonObject> call, Throwable t) {
|
public void onFailure(Call<JsonObject> call, Throwable t) {
|
||||||
Log.e("ACTIVITY_POST", "Error al registrar actividad: " + t.getMessage(), t);
|
Log.e("ACTIVITY_POST", "Error al registrar actividad: " + t.getMessage(), t);
|
||||||
if (!isAdded()) return;
|
if (isAdded()) {
|
||||||
Toast.makeText(getContext(), "Error al registrar actividad", Toast.LENGTH_SHORT).show();
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,6 @@ public class AddMangaFragment extends Fragment {
|
||||||
typeSpinner.setAdapter(typeAdapter);
|
typeSpinner.setAdapter(typeAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void setupRecycler() {
|
private void setupRecycler() {
|
||||||
searchAdapter = new MangaSearchAdapter(new ArrayList<>(), this::onMangaSelected);
|
searchAdapter = new MangaSearchAdapter(new ArrayList<>(), this::onMangaSelected);
|
||||||
searchResults.setAdapter(searchAdapter);
|
searchResults.setAdapter(searchAdapter);
|
||||||
|
|
@ -98,8 +97,7 @@ public class AddMangaFragment extends Fragment {
|
||||||
|
|
||||||
private void setupSearch() {
|
private void setupSearch() {
|
||||||
searchEditText.setOnEditorActionListener((TextView v, int actionId, KeyEvent event) -> {
|
searchEditText.setOnEditorActionListener((TextView v, int actionId, KeyEvent event) -> {
|
||||||
if (actionId == EditorInfo.IME_ACTION_SEARCH ||
|
if (actionId == EditorInfo.IME_ACTION_SEARCH || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
|
||||||
(event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
|
|
||||||
String query = searchEditText.getText().toString().trim();
|
String query = searchEditText.getText().toString().trim();
|
||||||
if (!query.isEmpty()) {
|
if (!query.isEmpty()) {
|
||||||
api.searchAniList(query, "MANGA").enqueue(new Callback<List<AniListMedia>>() {
|
api.searchAniList(query, "MANGA").enqueue(new Callback<List<AniListMedia>>() {
|
||||||
|
|
@ -133,8 +131,7 @@ public class AddMangaFragment extends Fragment {
|
||||||
try {
|
try {
|
||||||
score = Integer.parseInt(scoreEditText.getText().toString());
|
score = Integer.parseInt(scoreEditText.getText().toString());
|
||||||
progress = Integer.parseInt(progressEditText.getText().toString());
|
progress = Integer.parseInt(progressEditText.getText().toString());
|
||||||
} catch (NumberFormatException ignored) {
|
} catch (NumberFormatException ignored) {}
|
||||||
}
|
|
||||||
|
|
||||||
MangaEntity manga = new MangaEntity();
|
MangaEntity manga = new MangaEntity();
|
||||||
manga.setUserId(userId);
|
manga.setUserId(userId);
|
||||||
|
|
@ -158,6 +155,9 @@ public class AddMangaFragment extends Fragment {
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
Toast.makeText(getContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show();
|
Toast.makeText(getContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
registrarActividad(manga.getTitle());
|
registrarActividad(manga.getTitle());
|
||||||
|
Bundle result = new Bundle();
|
||||||
|
result.putBoolean("manga_added", true);
|
||||||
|
getParentFragmentManager().setFragmentResult("manga_add_request", result);
|
||||||
requireActivity().getSupportFragmentManager().popBackStack();
|
requireActivity().getSupportFragmentManager().popBackStack();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(getContext(), "Error al guardar manga", Toast.LENGTH_SHORT).show();
|
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<JsonObject>() {
|
api.postActivity(actividad).enqueue(new Callback<JsonObject>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
|
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {}
|
||||||
if (!response.isSuccessful()) {
|
|
||||||
// Puedes logear el error si lo deseas
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<JsonObject> call, Throwable t) {
|
public void onFailure(Call<JsonObject> call, Throwable t) {
|
||||||
|
|
|
||||||
|
|
@ -59,15 +59,12 @@ public class FragmentAnime extends Fragment {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
@Nullable ViewGroup container,
|
|
||||||
@Nullable Bundle savedInstanceState) {
|
|
||||||
return inflater.inflate(R.layout.fragment_alist, container, false);
|
return inflater.inflate(R.layout.fragment_alist, container, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull View view,
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
@Nullable Bundle savedInstanceState) {
|
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
initViews(view);
|
initViews(view);
|
||||||
|
|
@ -76,6 +73,7 @@ public class FragmentAnime extends Fragment {
|
||||||
setupSearchListener();
|
setupSearchListener();
|
||||||
setupFab(view);
|
setupFab(view);
|
||||||
setupInsets(view);
|
setupInsets(view);
|
||||||
|
setupResultListener();
|
||||||
|
|
||||||
SharedPreferences prefs = requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE);
|
SharedPreferences prefs = requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE);
|
||||||
userId = prefs.getInt("user_id", -1);
|
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();
|
Toast.makeText(getContext(), "Error: sesión no iniciada", Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Mostrar el nombre del usuario
|
|
||||||
String username = prefs.getString("username", "Usuario");
|
String username = prefs.getString("username", "Usuario");
|
||||||
TextView textViewUsername = view.findViewById(R.id.textViewUsername);
|
TextView textViewUsername = view.findViewById(R.id.textViewUsername);
|
||||||
textViewUsername.setText(username);
|
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() {
|
private void setupViewButtons() {
|
||||||
btnViewCompact.setOnClickListener(v -> setViewType(AnimeAdapter.VIEW_COMPACT));
|
btnViewCompact.setOnClickListener(v -> setViewType(AnimeAdapter.VIEW_COMPACT));
|
||||||
btnViewNormal.setOnClickListener(v -> setViewType(AnimeAdapter.VIEW_NORMAL));
|
btnViewNormal.setOnClickListener(v -> setViewType(AnimeAdapter.VIEW_NORMAL));
|
||||||
|
|
@ -197,9 +219,8 @@ public class FragmentAnime extends Fragment {
|
||||||
|
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
Toast.makeText(requireContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show();
|
Toast.makeText(requireContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
currentPage = 1;
|
animeList.remove(anime);
|
||||||
animeList.clear();
|
adapter.updateList(animeList);
|
||||||
loadMoreAnimes(currentPage);
|
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(requireContext(), "Error al eliminar", Toast.LENGTH_SHORT).show();
|
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) {
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
List<AnimeEntity> nuevos = response.body().getData();
|
List<AnimeEntity> nuevos = response.body().getData();
|
||||||
animeList.addAll(nuevos);
|
if (page == 1) {
|
||||||
adapter.notifyItemRangeInserted(animeList.size() - nuevos.size(), nuevos.size());
|
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();
|
isLoading = response.body().isHasNextPage();
|
||||||
} else {
|
} else {
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ public class EditAnimeFragment extends Fragment {
|
||||||
String[] typeArray = getResources().getStringArray(R.array.anime_type_array);
|
String[] typeArray = getResources().getStringArray(R.array.anime_type_array);
|
||||||
|
|
||||||
ArrayAdapter<String> statusAdapter = new ArrayAdapter<>(requireContext(), R.layout.item_spinner, statusArray);
|
ArrayAdapter<String> 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);
|
spinnerStatus.setAdapter(statusAdapter);
|
||||||
|
|
||||||
ArrayAdapter<String> typeAdapter = new ArrayAdapter<>(requireContext(), R.layout.item_spinner, typeArray);
|
ArrayAdapter<String> 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<ApiResponse>() {
|
api.updateAnime(anime.getId(), anime).enqueue(new Callback<ApiResponse>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<ApiResponse> call, Response<ApiResponse> response) {
|
public void onResponse(Call<ApiResponse> call, Response<ApiResponse> response) {
|
||||||
Log.d("API_RESPONSE", "onResponse ejecutado: " + response.body());
|
|
||||||
|
|
||||||
if (!isAdded()) return;
|
if (!isAdded()) return;
|
||||||
|
|
||||||
if (response.isSuccessful()) {
|
if (response.isSuccessful()) {
|
||||||
|
|
@ -160,7 +158,6 @@ public class EditAnimeFragment extends Fragment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<ApiResponse> call, Throwable t) {
|
public void onFailure(Call<ApiResponse> call, Throwable t) {
|
||||||
Log.e("API_RESPONSE", "onFailure ejecutado: " + t.getMessage(), t);
|
|
||||||
if (!isAdded()) return;
|
if (!isAdded()) return;
|
||||||
Toast.makeText(requireContext(), "Fallo en la conexión", Toast.LENGTH_SHORT).show();
|
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();
|
Toast.makeText(requireContext(), "Anime eliminado", Toast.LENGTH_SHORT).show();
|
||||||
requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE)
|
requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE)
|
||||||
.edit().putBoolean("refresh_profile", true).apply();
|
.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();
|
requireActivity().getSupportFragmentManager().popBackStack();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(requireContext(), "Error al eliminar", Toast.LENGTH_SHORT).show();
|
Toast.makeText(requireContext(), "Error al eliminar", Toast.LENGTH_SHORT).show();
|
||||||
|
|
@ -231,7 +232,6 @@ public class EditAnimeFragment extends Fragment {
|
||||||
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
|
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
|
||||||
Log.d("ACTIVITY_DELETE", "Actividad de eliminación registrada");
|
Log.d("ACTIVITY_DELETE", "Actividad de eliminación registrada");
|
||||||
|
|
||||||
|
|
||||||
if (getParentFragment() instanceof FragmentProfile) {
|
if (getParentFragment() instanceof FragmentProfile) {
|
||||||
((FragmentProfile) getParentFragment()).loadActivity();
|
((FragmentProfile) getParentFragment()).loadActivity();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,30 +61,18 @@ public class EditMangaFragment extends Fragment {
|
||||||
|
|
||||||
fillFields();
|
fillFields();
|
||||||
|
|
||||||
String[] statusArray = getResources().getStringArray(R.array.manga_status_array);
|
ArrayAdapter<String> statusAdapter = new ArrayAdapter<>(requireContext(), R.layout.item_spinner,
|
||||||
String[] typeArray = getResources().getStringArray(R.array.manga_type_array);
|
getResources().getStringArray(R.array.manga_status_array));
|
||||||
|
|
||||||
ArrayAdapter<String> statusAdapter = new ArrayAdapter<>(requireContext(), R.layout.item_spinner, statusArray);
|
|
||||||
statusAdapter.setDropDownViewResource(R.layout.item_spinner);
|
statusAdapter.setDropDownViewResource(R.layout.item_spinner);
|
||||||
spinnerStatus.setAdapter(statusAdapter);
|
spinnerStatus.setAdapter(statusAdapter);
|
||||||
|
|
||||||
ArrayAdapter<String> typeAdapter = new ArrayAdapter<>(requireContext(), R.layout.item_spinner, typeArray);
|
ArrayAdapter<String> typeAdapter = new ArrayAdapter<>(requireContext(), R.layout.item_spinner,
|
||||||
|
getResources().getStringArray(R.array.manga_type_array));
|
||||||
typeAdapter.setDropDownViewResource(R.layout.item_spinner);
|
typeAdapter.setDropDownViewResource(R.layout.item_spinner);
|
||||||
spinnerType.setAdapter(typeAdapter);
|
spinnerType.setAdapter(typeAdapter);
|
||||||
|
|
||||||
for (int i = 0; i < statusArray.length; i++) {
|
setSpinnerSelection(spinnerStatus, manga.getStatus());
|
||||||
if (statusArray[i].equalsIgnoreCase(manga.getStatus())) {
|
setSpinnerSelection(spinnerType, manga.getType());
|
||||||
spinnerStatus.setSelection(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < typeArray.length; i++) {
|
|
||||||
if (typeArray[i].equalsIgnoreCase(manga.getType())) {
|
|
||||||
spinnerType.setSelection(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buttonSave.setOnClickListener(v -> saveChanges());
|
buttonSave.setOnClickListener(v -> saveChanges());
|
||||||
|
|
||||||
|
|
@ -104,6 +92,15 @@ public class EditMangaFragment extends Fragment {
|
||||||
editTextProgress.setText(String.valueOf(manga.getProgress()));
|
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() {
|
private void saveChanges() {
|
||||||
if (manga == null) {
|
if (manga == null) {
|
||||||
Toast.makeText(requireContext(), "Error: Manga no cargado", Toast.LENGTH_SHORT).show();
|
Toast.makeText(requireContext(), "Error: Manga no cargado", Toast.LENGTH_SHORT).show();
|
||||||
|
|
@ -128,14 +125,11 @@ public class EditMangaFragment extends Fragment {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String status = spinnerStatus.getSelectedItem().toString();
|
|
||||||
String type = spinnerType.getSelectedItem().toString();
|
|
||||||
|
|
||||||
manga.setTitle(title);
|
manga.setTitle(title);
|
||||||
manga.setScore(score);
|
manga.setScore(score);
|
||||||
manga.setProgress(progress);
|
manga.setProgress(progress);
|
||||||
manga.setStatus(status);
|
manga.setStatus(spinnerStatus.getSelectedItem().toString());
|
||||||
manga.setType(type);
|
manga.setType(spinnerType.getSelectedItem().toString());
|
||||||
|
|
||||||
api.updateManga(manga.getId(), manga).enqueue(new Callback<ApiResponse>() {
|
api.updateManga(manga.getId(), manga).enqueue(new Callback<ApiResponse>() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -144,7 +138,7 @@ public class EditMangaFragment extends Fragment {
|
||||||
|
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
Toast.makeText(requireContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show();
|
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)
|
requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE)
|
||||||
.edit().putBoolean("refresh_profile", true).apply();
|
.edit().putBoolean("refresh_profile", true).apply();
|
||||||
requireActivity().getSupportFragmentManager().popBackStack();
|
requireActivity().getSupportFragmentManager().popBackStack();
|
||||||
|
|
@ -162,7 +156,7 @@ public class EditMangaFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteManga() {
|
private void deleteManga() {
|
||||||
registrarActividadEliminacionManga(manga.getTitle(), manga.getImageUrl());
|
registrarActividad("eliminó un manga", manga.getTitle(), manga.getImageUrl());
|
||||||
|
|
||||||
api.deleteManga(manga.getId()).enqueue(new Callback<ApiResponse>() {
|
api.deleteManga(manga.getId()).enqueue(new Callback<ApiResponse>() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -173,6 +167,12 @@ public class EditMangaFragment extends Fragment {
|
||||||
Toast.makeText(requireContext(), "Manga eliminado", Toast.LENGTH_SHORT).show();
|
Toast.makeText(requireContext(), "Manga eliminado", Toast.LENGTH_SHORT).show();
|
||||||
requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE)
|
requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE)
|
||||||
.edit().putBoolean("refresh_profile", true).apply();
|
.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();
|
requireActivity().getSupportFragmentManager().popBackStack();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(requireContext(), "Error al eliminar", Toast.LENGTH_SHORT).show();
|
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);
|
int userId = requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE).getInt("user_id", -1);
|
||||||
if (userId == -1) return;
|
if (userId == -1) return;
|
||||||
|
|
||||||
Map<String, Object> actividad = new HashMap<>();
|
Map<String, Object> actividad = new HashMap<>();
|
||||||
actividad.put("userId", userId);
|
actividad.put("userId", userId);
|
||||||
actividad.put("action", "update de un manga");
|
actividad.put("action", action);
|
||||||
actividad.put("mediaTitle", titulo);
|
actividad.put("mediaTitle", titulo);
|
||||||
actividad.put("imageUrl", imagen);
|
actividad.put("imageUrl", imagen);
|
||||||
|
|
||||||
api.postActivity(actividad).enqueue(new Callback<JsonObject>() {
|
api.postActivity(actividad).enqueue(new Callback<JsonObject>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
|
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
|
||||||
Log.d("ACTIVITY_DELETE", "Actividad de edicion registrada");
|
Log.d("ACTIVITY", "Actividad registrada: " + action);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Call<JsonObject> 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<String, Object> 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<JsonObject>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
|
|
||||||
Log.d("ACTIVITY_DELETE", "Actividad de eliminación registrada");
|
|
||||||
|
|
||||||
if (getParentFragment() instanceof FragmentProfile) {
|
if (getParentFragment() instanceof FragmentProfile) {
|
||||||
((FragmentProfile) getParentFragment()).loadActivity();
|
((FragmentProfile) getParentFragment()).loadActivity();
|
||||||
}
|
}
|
||||||
|
|
@ -232,10 +208,8 @@ public class EditMangaFragment extends Fragment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<JsonObject> call, Throwable t) {
|
public void onFailure(Call<JsonObject> call, Throwable t) {
|
||||||
Log.e("ACTIVITY_DELETE", "Error al registrar actividad: " + t.getMessage(), t);
|
Log.e("ACTIVITY", "Error al registrar actividad: " + t.getMessage(), t);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
// FragmentHome.java
|
|
||||||
package com.santiparra.yomitrack.ui.fragments.home;
|
package com.santiparra.yomitrack.ui.fragments.home;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
@ -15,13 +13,11 @@ import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.santiparra.yomitrack.R;
|
import com.santiparra.yomitrack.R;
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ public class FragmentManga extends Fragment {
|
||||||
initViews(view);
|
initViews(view);
|
||||||
setupListeners();
|
setupListeners();
|
||||||
setupRecyclerView();
|
setupRecyclerView();
|
||||||
|
setupResultListeners();
|
||||||
|
|
||||||
api = ApiClient.getClient().create(ApiService.class);
|
api = ApiClient.getClient().create(ApiService.class);
|
||||||
SharedPreferences prefs = requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE);
|
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();
|
Toast.makeText(getContext(), "Error: sesión no iniciada", Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Mostrar el nombre del usuario
|
|
||||||
String username = prefs.getString("username", "Usuario");
|
String username = prefs.getString("username", "Usuario");
|
||||||
TextView textViewUsername = view.findViewById(R.id.textViewUsername);
|
((TextView) view.findViewById(R.id.textViewUsername)).setText(username);
|
||||||
textViewUsername.setText(username);
|
|
||||||
|
|
||||||
setViewType(currentViewType);
|
setViewType(currentViewType);
|
||||||
loadMoreMangas(currentPage);
|
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) {
|
private void setViewType(int viewType) {
|
||||||
currentViewType = viewType;
|
currentViewType = viewType;
|
||||||
|
|
||||||
if (viewType == MangaAdapter.VIEW_LARGE) {
|
if (viewType == MangaAdapter.VIEW_LARGE) {
|
||||||
recyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2));
|
recyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2));
|
||||||
} else {
|
} else {
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
|
recyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter = new MangaAdapter(mangaList, viewType, this::showEditDialog, this::deleteManga);
|
adapter = new MangaAdapter(mangaList, viewType, this::showEditDialog, this::deleteManga);
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
}
|
}
|
||||||
|
|
@ -187,12 +209,15 @@ public class FragmentManga extends Fragment {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<ApiResponse> call, Response<ApiResponse> response) {
|
public void onResponse(Call<ApiResponse> call, Response<ApiResponse> response) {
|
||||||
if (!isAdded()) return;
|
if (!isAdded()) return;
|
||||||
|
|
||||||
if (response.isSuccessful()) {
|
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();
|
Toast.makeText(requireContext(), response.body() != null ? response.body().getMessage() : "Manga eliminado", Toast.LENGTH_SHORT).show();
|
||||||
currentPage = 1;
|
|
||||||
mangaList.clear();
|
|
||||||
loadMoreMangas(currentPage);
|
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(requireContext(), "Error al eliminar", Toast.LENGTH_SHORT).show();
|
Toast.makeText(requireContext(), "Error al eliminar", Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|
@ -214,7 +239,6 @@ public class FragmentManga extends Fragment {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<MangaPageResponse> call, Response<MangaPageResponse> response) {
|
public void onResponse(Call<MangaPageResponse> call, Response<MangaPageResponse> response) {
|
||||||
if (!isAdded()) return;
|
if (!isAdded()) return;
|
||||||
|
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
List<MangaEntity> nuevos = response.body().getData();
|
List<MangaEntity> nuevos = response.body().getData();
|
||||||
mangaList.addAll(nuevos);
|
mangaList.addAll(nuevos);
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -7,11 +7,10 @@
|
||||||
</shape>
|
</shape>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
<!-- Progreso (color por defecto, se sobrescribe desde Java) -->
|
|
||||||
<item android:id="@android:id/progress">
|
<item android:id="@android:id/progress">
|
||||||
<clip>
|
<clip>
|
||||||
<shape android:shape="rectangle">
|
<shape android:shape="rectangle">
|
||||||
<solid android:color="#FFFFFF" /> <!-- No uses referencia aquí -->
|
<solid android:color="#FFFFFF" />
|
||||||
<corners android:radius="50dp" />
|
<corners android:radius="50dp" />
|
||||||
</shape>
|
</shape>
|
||||||
</clip>
|
</clip>
|
||||||
|
|
|
||||||
|
|
@ -59,13 +59,6 @@
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:layout_marginBottom="12dp" />
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/buttonGoToReset"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Ya tengo el código"
|
|
||||||
android:backgroundTint="#2C2F38"
|
|
||||||
android:textColor="@android:color/white" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingTop="12dp"
|
|
||||||
android:paddingBottom="12dp">
|
|
||||||
|
|
||||||
<!-- Título de la sección -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/sectionTitle"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Section Title"
|
|
||||||
android:textSize="18sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:textColor="@color/textPrimary"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:paddingStart="16dp"
|
|
||||||
android:paddingEnd="16dp" />
|
|
||||||
|
|
||||||
<!-- Lista horizontal de ítems -->
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/sectionRecyclerView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clipToPadding="false"
|
|
||||||
android:overScrollMode="never"
|
|
||||||
android:nestedScrollingEnabled="false" />
|
|
||||||
</LinearLayout>
|
|
||||||
Loading…
Reference in New Issue