Creacion de nuevas clases y de nuevos xml, funcionamiento de la api de animelist , tambien ya se consume los datos del anime list y ya puedo adaptar el anime, es decir puedo añadir y editar flata por implementar eliminar!
This commit is contained in:
parent
1f526aa91e
commit
a040e9c755
Binary file not shown.
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.santiparra.yomitrack.api;
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor;
|
||||||
|
import retrofit2.Retrofit;
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory;
|
||||||
|
|
||||||
|
public class ApiClient {
|
||||||
|
|
||||||
|
private static final String BASE_URL = "http://10.0.2.2:3000/";
|
||||||
|
private static Retrofit retrofit = null;
|
||||||
|
|
||||||
|
public static Retrofit getClient() {
|
||||||
|
if (retrofit == null) {
|
||||||
|
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
|
||||||
|
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
|
||||||
|
|
||||||
|
OkHttpClient client = new OkHttpClient.Builder()
|
||||||
|
.addInterceptor(logging)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
retrofit = new Retrofit.Builder()
|
||||||
|
.baseUrl(BASE_URL)
|
||||||
|
.client(client)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
return retrofit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
package com.santiparra.yomitrack.api;
|
||||||
|
|
||||||
|
import com.santiparra.yomitrack.db.entities.AnimeEntity;
|
||||||
|
import com.santiparra.yomitrack.db.entities.MangaEntity;
|
||||||
|
import com.santiparra.yomitrack.db.entities.UserEntity;
|
||||||
|
import com.santiparra.yomitrack.model.AniListAnime;
|
||||||
|
import com.santiparra.yomitrack.model.LoginResponse;
|
||||||
|
import com.santiparra.yomitrack.model.RegisterResponse;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.http.Body;
|
||||||
|
import retrofit2.http.DELETE;
|
||||||
|
import retrofit2.http.GET;
|
||||||
|
import retrofit2.http.POST;
|
||||||
|
import retrofit2.http.PUT;
|
||||||
|
import retrofit2.http.Path;
|
||||||
|
import retrofit2.http.Query;
|
||||||
|
|
||||||
|
public interface ApiService {
|
||||||
|
|
||||||
|
// ---------------- Usuario ----------------
|
||||||
|
@POST("users/register")
|
||||||
|
Call<RegisterResponse> registerUser(@Body Map<String, String> request);
|
||||||
|
@POST("users/login")
|
||||||
|
Call<LoginResponse> loginUser(@Body UserEntity user);
|
||||||
|
|
||||||
|
// ---------------- Anime ----------------
|
||||||
|
@POST("anime/add")
|
||||||
|
Call<String> insertAnime(@Body AnimeEntity anime);
|
||||||
|
|
||||||
|
@GET("anime/list/{userId}")
|
||||||
|
Call<List<AnimeEntity>> getAnimeByUser(@Path("userId") int userId);
|
||||||
|
|
||||||
|
@PUT("anime/{id}")
|
||||||
|
Call<String> updateAnime(@Path("id") int animeId, @Body AnimeEntity anime);
|
||||||
|
|
||||||
|
@DELETE("anime/delete/{id}")
|
||||||
|
Call<String> deleteAnime(@Path("id") int id);
|
||||||
|
|
||||||
|
// ---------------- Manga ----------------
|
||||||
|
@POST("manga/add")
|
||||||
|
Call<String> insertManga(@Body MangaEntity manga);
|
||||||
|
|
||||||
|
@GET("manga/list/{userId}")
|
||||||
|
Call<List<MangaEntity>> getMangaByUser(@Path("userId") int userId);
|
||||||
|
|
||||||
|
@PUT("manga/{id}")
|
||||||
|
Call<String> updateManga(@Path("id") int mangaId, @Body MangaEntity manga);
|
||||||
|
|
||||||
|
@DELETE("manga/delete/{id}")
|
||||||
|
Call<String> deleteManga(@Path("id") int id);
|
||||||
|
|
||||||
|
// ---------------- AniList API ----------------
|
||||||
|
@GET("/anilist/search")
|
||||||
|
Call<List<AniListAnime>> searchAnimeAniList(@Query("query") String query);
|
||||||
|
|
||||||
|
@GET("anilist/search/manga")
|
||||||
|
Call<List<AniListAnime>> searchMangaAniList(@Query("query") String query);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.santiparra.yomitrack.db.entities;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entidad que representa un anime guardado por el usuario en la base de datos local.
|
||||||
|
*/
|
||||||
|
public class AnimeEntity implements Serializable {
|
||||||
|
|
||||||
|
private int id;
|
||||||
|
private int userId;
|
||||||
|
private String title;
|
||||||
|
private int score;
|
||||||
|
private int progress;
|
||||||
|
private String status;
|
||||||
|
private String type;
|
||||||
|
private String imageUrl;
|
||||||
|
|
||||||
|
// Getters y Setters
|
||||||
|
public int getId() { return id; }
|
||||||
|
|
||||||
|
public void setId(int id) { this.id = id; }
|
||||||
|
|
||||||
|
public int getUserId() { return userId; }
|
||||||
|
|
||||||
|
public void setUserId(int userId) { this.userId = userId; }
|
||||||
|
|
||||||
|
public String getTitle() { return title; }
|
||||||
|
|
||||||
|
public void setTitle(String title) { this.title = title; }
|
||||||
|
|
||||||
|
public int getScore() { return score; }
|
||||||
|
|
||||||
|
public void setScore(int score) { this.score = score; }
|
||||||
|
|
||||||
|
public int getProgress() { return progress; }
|
||||||
|
|
||||||
|
public void setProgress(int progress) { this.progress = progress; }
|
||||||
|
|
||||||
|
public String getStatus() { return status; }
|
||||||
|
|
||||||
|
public void setStatus(String status) { this.status = status; }
|
||||||
|
|
||||||
|
public String getType() { return type; }
|
||||||
|
|
||||||
|
public void setType(String type) { this.type = type; }
|
||||||
|
|
||||||
|
public String getImageUrl() { return imageUrl; }
|
||||||
|
|
||||||
|
public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.santiparra.yomitrack.db.entities;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entidad que representa un manga guardado por el usuario en la base de datos local.
|
||||||
|
*/
|
||||||
|
public class MangaEntity implements Serializable {
|
||||||
|
|
||||||
|
private int id;
|
||||||
|
private int userId;
|
||||||
|
private String title;
|
||||||
|
private int score;
|
||||||
|
private int progress;
|
||||||
|
private String status;
|
||||||
|
private String type;
|
||||||
|
private String imageUrl;
|
||||||
|
|
||||||
|
// Getters y Setters
|
||||||
|
public int getId() { return id; }
|
||||||
|
|
||||||
|
public void setId(int id) { this.id = id; }
|
||||||
|
|
||||||
|
public int getUserId() { return userId; }
|
||||||
|
|
||||||
|
public void setUserId(int userId) { this.userId = userId; }
|
||||||
|
|
||||||
|
public String getTitle() { return title; }
|
||||||
|
|
||||||
|
public void setTitle(String title) { this.title = title; }
|
||||||
|
|
||||||
|
public int getScore() { return score; }
|
||||||
|
|
||||||
|
public void setScore(int score) { this.score = score; }
|
||||||
|
|
||||||
|
public int getProgress() { return progress; }
|
||||||
|
|
||||||
|
public void setProgress(int progress) { this.progress = progress; }
|
||||||
|
|
||||||
|
public String getStatus() { return status; }
|
||||||
|
|
||||||
|
public void setStatus(String status) { this.status = status; }
|
||||||
|
|
||||||
|
public String getType() { return type; }
|
||||||
|
|
||||||
|
public void setType(String type) { this.type = type; }
|
||||||
|
|
||||||
|
public String getImageUrl() { return imageUrl; }
|
||||||
|
|
||||||
|
public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.santiparra.yomitrack.db.entities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entidad que representa un usuario en la base de datos
|
||||||
|
*/
|
||||||
|
public class UserEntity {
|
||||||
|
public int id;
|
||||||
|
public String username;
|
||||||
|
public String password;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.santiparra.yomitrack.model;
|
||||||
|
|
||||||
|
public class AniListAnime {
|
||||||
|
private int id;
|
||||||
|
private String title;
|
||||||
|
private String imageUrl;
|
||||||
|
|
||||||
|
// Constructor vacío
|
||||||
|
public AniListAnime() {}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getImageUrl() {
|
||||||
|
return imageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImageUrl(String imageUrl) {
|
||||||
|
this.imageUrl = imageUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.santiparra.yomitrack.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modelo que representa una sección de la pantalla de exploración con su título y lista de ítems.
|
||||||
|
*/
|
||||||
|
public class BrowseSection {
|
||||||
|
private final String title;
|
||||||
|
private final List<ItemModel> items;
|
||||||
|
|
||||||
|
public BrowseSection(String title, List<ItemModel> items) {
|
||||||
|
this.title = title;
|
||||||
|
this.items = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ItemModel> getItems() {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.santiparra.yomitrack.model;
|
||||||
|
|
||||||
|
import com.santiparra.yomitrack.db.entities.UserEntity;
|
||||||
|
|
||||||
|
public class LoginResponse {
|
||||||
|
public boolean success;
|
||||||
|
public String message;
|
||||||
|
public UserEntity user;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.santiparra.yomitrack.model;
|
||||||
|
|
||||||
|
public class RegisterResponse {
|
||||||
|
private int userId;
|
||||||
|
|
||||||
|
public int getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(int userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
package com.santiparra.yomitrack.model.adapters.anime_adapter;
|
||||||
|
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
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.AniListAnime;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AnimeSearchAdapter extends RecyclerView.Adapter<AnimeSearchAdapter.SearchViewHolder> {
|
||||||
|
|
||||||
|
private List<AniListAnime> animeList;
|
||||||
|
private final OnAnimeClickListener clickListener;
|
||||||
|
|
||||||
|
public interface OnAnimeClickListener {
|
||||||
|
void onClick(AniListAnime anime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnimeSearchAdapter(List<AniListAnime> animeList, OnAnimeClickListener clickListener) {
|
||||||
|
this.animeList = animeList;
|
||||||
|
this.clickListener = clickListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAnimeList(List<AniListAnime> animeList) {
|
||||||
|
this.animeList = animeList;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public SearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_anime, parent, false);
|
||||||
|
return new SearchViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull SearchViewHolder holder, int position) {
|
||||||
|
AniListAnime anime = animeList.get(position);
|
||||||
|
holder.title.setText(anime.getTitle());
|
||||||
|
|
||||||
|
Glide.with(holder.itemView.getContext())
|
||||||
|
.load(anime.getImageUrl())
|
||||||
|
.placeholder(R.drawable.rectangle_placeholder)
|
||||||
|
.into(holder.imageCover);
|
||||||
|
|
||||||
|
holder.itemView.setOnClickListener(v -> clickListener.onClick(anime));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return animeList != null ? animeList.size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SearchViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
ImageView imageCover;
|
||||||
|
TextView title;
|
||||||
|
|
||||||
|
public SearchViewHolder(@NonNull View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
imageCover = itemView.findViewById(R.id.imageCover);
|
||||||
|
title = itemView.findViewById(R.id.textTitle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
package com.santiparra.yomitrack.model.adapters.manga_adapter;
|
||||||
|
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
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.AniListAnime;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MangaSearchAdapter extends RecyclerView.Adapter<MangaSearchAdapter.SearchViewHolder> {
|
||||||
|
|
||||||
|
private List<AniListAnime> mangaList;
|
||||||
|
private final OnMangaClickListener clickListener;
|
||||||
|
|
||||||
|
public interface OnMangaClickListener {
|
||||||
|
void onClick(AniListAnime manga);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MangaSearchAdapter(List<AniListAnime> mangaList, OnMangaClickListener clickListener) {
|
||||||
|
this.mangaList = mangaList;
|
||||||
|
this.clickListener = clickListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMangaList(List<AniListAnime> mangaList) {
|
||||||
|
this.mangaList = mangaList;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public SearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_manga, parent, false);
|
||||||
|
return new SearchViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull SearchViewHolder holder, int position) {
|
||||||
|
AniListAnime manga = mangaList.get(position);
|
||||||
|
holder.title.setText(manga.getTitle());
|
||||||
|
|
||||||
|
Glide.with(holder.itemView.getContext())
|
||||||
|
.load(manga.getImageUrl())
|
||||||
|
.placeholder(R.drawable.rectangle_placeholder)
|
||||||
|
.into(holder.imageCover);
|
||||||
|
|
||||||
|
holder.itemView.setOnClickListener(v -> clickListener.onClick(manga));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return mangaList != null ? mangaList.size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SearchViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
ImageView imageCover;
|
||||||
|
TextView title;
|
||||||
|
|
||||||
|
public SearchViewHolder(@NonNull View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
imageCover = itemView.findViewById(R.id.imageCover);
|
||||||
|
title = itemView.findViewById(R.id.textTitle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,154 @@
|
||||||
|
// AddAnimeFragment.java actualizado con LinearLayoutManager asignado al RecyclerView
|
||||||
|
|
||||||
|
package com.santiparra.yomitrack.ui.fragments.addanime;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.inputmethod.EditorInfo;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.santiparra.yomitrack.R;
|
||||||
|
import com.santiparra.yomitrack.api.ApiClient;
|
||||||
|
import com.santiparra.yomitrack.api.ApiService;
|
||||||
|
import com.santiparra.yomitrack.db.entities.AnimeEntity;
|
||||||
|
import com.santiparra.yomitrack.model.AniListAnime;
|
||||||
|
import com.santiparra.yomitrack.model.adapters.anime_adapter.AnimeSearchAdapter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
public class AddAnimeFragment extends Fragment {
|
||||||
|
|
||||||
|
private EditText searchEditText, scoreEditText, progressEditText;
|
||||||
|
private Spinner statusSpinner, typeSpinner;
|
||||||
|
private RecyclerView searchResults;
|
||||||
|
private AnimeSearchAdapter searchAdapter;
|
||||||
|
private ApiService api;
|
||||||
|
private int userId;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_add_anime, container, false);
|
||||||
|
|
||||||
|
searchEditText = view.findViewById(R.id.editTextSearch);
|
||||||
|
scoreEditText = view.findViewById(R.id.editTextScore);
|
||||||
|
progressEditText = view.findViewById(R.id.editTextProgress);
|
||||||
|
statusSpinner = view.findViewById(R.id.spinnerStatus);
|
||||||
|
typeSpinner = view.findViewById(R.id.spinnerType);
|
||||||
|
searchResults = view.findViewById(R.id.recyclerSearchResults);
|
||||||
|
searchResults.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
|
|
||||||
|
api = ApiClient.getClient().create(ApiService.class);
|
||||||
|
SharedPreferences prefs = requireContext().getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
|
||||||
|
userId = prefs.getInt("current_user_id", -1);
|
||||||
|
|
||||||
|
setupSpinners();
|
||||||
|
setupRecycler();
|
||||||
|
setupSearch();
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupSpinners() {
|
||||||
|
ArrayAdapter<CharSequence> statusAdapter = ArrayAdapter.createFromResource(
|
||||||
|
requireContext(), R.array.anime_status_array, android.R.layout.simple_spinner_item);
|
||||||
|
statusAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
statusSpinner.setAdapter(statusAdapter);
|
||||||
|
|
||||||
|
ArrayAdapter<CharSequence> typeAdapter = ArrayAdapter.createFromResource(
|
||||||
|
requireContext(), R.array.anime_type_array, android.R.layout.simple_spinner_item);
|
||||||
|
typeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
typeSpinner.setAdapter(typeAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupRecycler() {
|
||||||
|
searchAdapter = new AnimeSearchAdapter(new ArrayList<>(), this::onAnimeSelected);
|
||||||
|
searchResults.setAdapter(searchAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupSearch() {
|
||||||
|
searchEditText.setOnEditorActionListener((TextView v, int actionId, KeyEvent event) -> {
|
||||||
|
if (actionId == EditorInfo.IME_ACTION_SEARCH ||
|
||||||
|
(event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
|
||||||
|
String query = searchEditText.getText().toString().trim();
|
||||||
|
if (!query.isEmpty()) {
|
||||||
|
api.searchAnimeAniList(query).enqueue(new Callback<List<AniListAnime>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<List<AniListAnime>> call, Response<List<AniListAnime>> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
searchAdapter.setAnimeList(response.body());
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getContext(), "Sin resultados", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<List<AniListAnime>> call, Throwable t) {
|
||||||
|
Toast.makeText(getContext(), "Error de red", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onAnimeSelected(AniListAnime selected) {
|
||||||
|
String status = statusSpinner.getSelectedItem().toString();
|
||||||
|
String type = typeSpinner.getSelectedItem().toString();
|
||||||
|
|
||||||
|
int score = 0;
|
||||||
|
int progress = 0;
|
||||||
|
try {
|
||||||
|
score = Integer.parseInt(scoreEditText.getText().toString());
|
||||||
|
progress = Integer.parseInt(progressEditText.getText().toString());
|
||||||
|
} catch (NumberFormatException ignored) {}
|
||||||
|
|
||||||
|
AnimeEntity anime = new AnimeEntity();
|
||||||
|
anime.setUserId(userId);
|
||||||
|
anime.setTitle(selected.getTitle());
|
||||||
|
anime.setImageUrl(selected.getImageUrl());
|
||||||
|
anime.setStatus(status);
|
||||||
|
anime.setType(type);
|
||||||
|
anime.setScore(score);
|
||||||
|
anime.setProgress(progress);
|
||||||
|
|
||||||
|
api.insertAnime(anime).enqueue(new Callback<String>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<String> call, Response<String> response) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
Toast.makeText(getContext(), "Anime añadido", Toast.LENGTH_SHORT).show();
|
||||||
|
requireActivity().getSupportFragmentManager().popBackStack();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getContext(), "Error al guardar anime", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<String> call, Throwable t) {
|
||||||
|
Toast.makeText(getContext(), "Fallo en la conexión", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,152 @@
|
||||||
|
package com.santiparra.yomitrack.ui.fragments.addmanga;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.inputmethod.EditorInfo;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.santiparra.yomitrack.R;
|
||||||
|
import com.santiparra.yomitrack.api.ApiClient;
|
||||||
|
import com.santiparra.yomitrack.api.ApiService;
|
||||||
|
import com.santiparra.yomitrack.db.entities.MangaEntity;
|
||||||
|
import com.santiparra.yomitrack.model.AniListAnime;
|
||||||
|
import com.santiparra.yomitrack.model.adapters.manga_adapter.MangaSearchAdapter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
public class AddMangaFragment extends Fragment {
|
||||||
|
|
||||||
|
private EditText searchEditText, scoreEditText, progressEditText;
|
||||||
|
private Spinner statusSpinner, typeSpinner;
|
||||||
|
private RecyclerView searchResults;
|
||||||
|
private MangaSearchAdapter searchAdapter;
|
||||||
|
private ApiService api;
|
||||||
|
private int userId;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_add_anime, container, false);
|
||||||
|
|
||||||
|
searchEditText = view.findViewById(R.id.editTextSearch);
|
||||||
|
scoreEditText = view.findViewById(R.id.editTextScore);
|
||||||
|
progressEditText = view.findViewById(R.id.editTextProgress);
|
||||||
|
statusSpinner = view.findViewById(R.id.spinnerStatus);
|
||||||
|
typeSpinner = view.findViewById(R.id.spinnerType);
|
||||||
|
searchResults = view.findViewById(R.id.recyclerSearchResults);
|
||||||
|
searchResults.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
|
|
||||||
|
api = ApiClient.getClient().create(ApiService.class);
|
||||||
|
SharedPreferences prefs = requireContext().getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
|
||||||
|
userId = prefs.getInt("current_user_id", -1);
|
||||||
|
|
||||||
|
setupSpinners();
|
||||||
|
setupRecycler();
|
||||||
|
setupSearch();
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupSpinners() {
|
||||||
|
ArrayAdapter<CharSequence> statusAdapter = ArrayAdapter.createFromResource(
|
||||||
|
requireContext(), R.array.anime_status_array, android.R.layout.simple_spinner_item);
|
||||||
|
statusAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
statusSpinner.setAdapter(statusAdapter);
|
||||||
|
|
||||||
|
ArrayAdapter<CharSequence> typeAdapter = ArrayAdapter.createFromResource(
|
||||||
|
requireContext(), R.array.anime_type_array, android.R.layout.simple_spinner_item);
|
||||||
|
typeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
typeSpinner.setAdapter(typeAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupRecycler() {
|
||||||
|
searchAdapter = new MangaSearchAdapter(new ArrayList<>(), this::onMangaSelected);
|
||||||
|
searchResults.setAdapter(searchAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupSearch() {
|
||||||
|
searchEditText.setOnEditorActionListener((TextView v, int actionId, KeyEvent event) -> {
|
||||||
|
if (actionId == EditorInfo.IME_ACTION_SEARCH ||
|
||||||
|
(event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
|
||||||
|
String query = searchEditText.getText().toString().trim();
|
||||||
|
if (!query.isEmpty()) {
|
||||||
|
api.searchMangaAniList(query).enqueue(new Callback<List<AniListAnime>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<List<AniListAnime>> call, Response<List<AniListAnime>> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
searchAdapter.setMangaList(response.body());
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getContext(), "Sin resultados", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<List<AniListAnime>> call, Throwable t) {
|
||||||
|
Toast.makeText(getContext(), "Error de red", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onMangaSelected(AniListAnime selected) {
|
||||||
|
String status = statusSpinner.getSelectedItem().toString();
|
||||||
|
String type = typeSpinner.getSelectedItem().toString();
|
||||||
|
|
||||||
|
int score = 0;
|
||||||
|
int progress = 0;
|
||||||
|
try {
|
||||||
|
score = Integer.parseInt(scoreEditText.getText().toString());
|
||||||
|
progress = Integer.parseInt(progressEditText.getText().toString());
|
||||||
|
} catch (NumberFormatException ignored) {}
|
||||||
|
|
||||||
|
MangaEntity manga = new MangaEntity();
|
||||||
|
manga.setUserId(userId);
|
||||||
|
manga.setTitle(selected.getTitle());
|
||||||
|
manga.setImageUrl(selected.getImageUrl());
|
||||||
|
manga.setStatus(status);
|
||||||
|
manga.setType(type);
|
||||||
|
manga.setScore(score);
|
||||||
|
manga.setProgress(progress);
|
||||||
|
|
||||||
|
api.insertManga(manga).enqueue(new Callback<String>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<String> call, Response<String> response) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
Toast.makeText(getContext(), "Manga añadido", Toast.LENGTH_SHORT).show();
|
||||||
|
requireActivity().getSupportFragmentManager().popBackStack();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getContext(), "Error al guardar manga", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<String> call, Throwable t) {
|
||||||
|
Toast.makeText(getContext(), "Fallo en la conexión", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,162 @@
|
||||||
|
// EditAnimeFragment.java optimizado con setupSpinners y safe saveChanges
|
||||||
|
|
||||||
|
package com.santiparra.yomitrack.ui.fragments.editanime;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import com.santiparra.yomitrack.R;
|
||||||
|
import com.santiparra.yomitrack.api.ApiClient;
|
||||||
|
import com.santiparra.yomitrack.api.ApiService;
|
||||||
|
import com.santiparra.yomitrack.db.entities.AnimeEntity;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
public class EditAnimeFragment extends Fragment {
|
||||||
|
|
||||||
|
private EditText editTextTitle, editTextScore, editTextProgress;
|
||||||
|
private Spinner spinnerStatus, spinnerType;
|
||||||
|
private Button buttonSave;
|
||||||
|
private AnimeEntity anime;
|
||||||
|
private ApiService api;
|
||||||
|
private int userId;
|
||||||
|
|
||||||
|
public EditAnimeFragment(AnimeEntity anime) {
|
||||||
|
this.anime = anime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_edit_anime, container, false);
|
||||||
|
|
||||||
|
editTextTitle = view.findViewById(R.id.editTextAnimeTitle);
|
||||||
|
editTextScore = view.findViewById(R.id.editTextScore);
|
||||||
|
editTextProgress = view.findViewById(R.id.editTextProgress);
|
||||||
|
spinnerStatus = view.findViewById(R.id.spinnerStatus);
|
||||||
|
spinnerType = view.findViewById(R.id.spinnerType);
|
||||||
|
buttonSave = view.findViewById(R.id.buttonSaveAnime);
|
||||||
|
|
||||||
|
api = ApiClient.getClient().create(ApiService.class);
|
||||||
|
SharedPreferences prefs = requireContext().getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
|
||||||
|
userId = prefs.getInt("current_user_id", -1);
|
||||||
|
|
||||||
|
if (getArguments() != null && getArguments().containsKey("anime")) {
|
||||||
|
anime = (AnimeEntity) getArguments().getSerializable("anime");
|
||||||
|
fillFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
setupSpinners();
|
||||||
|
|
||||||
|
buttonSave.setOnClickListener(v -> saveChanges());
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupSpinners() {
|
||||||
|
ArrayAdapter<CharSequence> statusAdapter = ArrayAdapter.createFromResource(
|
||||||
|
requireContext(), R.array.anime_status_array, android.R.layout.simple_spinner_item);
|
||||||
|
statusAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
spinnerStatus.setAdapter(statusAdapter);
|
||||||
|
|
||||||
|
ArrayAdapter<CharSequence> typeAdapter = ArrayAdapter.createFromResource(
|
||||||
|
requireContext(), R.array.anime_type_array, android.R.layout.simple_spinner_item);
|
||||||
|
typeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
spinnerType.setAdapter(typeAdapter);
|
||||||
|
|
||||||
|
if (anime != null) {
|
||||||
|
String[] statusArray = getResources().getStringArray(R.array.anime_status_array);
|
||||||
|
String[] typeArray = getResources().getStringArray(R.array.anime_type_array);
|
||||||
|
|
||||||
|
for (int i = 0; i < statusArray.length; i++) {
|
||||||
|
if (statusArray[i].equalsIgnoreCase(anime.getStatus())) {
|
||||||
|
spinnerStatus.setSelection(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < typeArray.length; i++) {
|
||||||
|
if (typeArray[i].equalsIgnoreCase(anime.getType())) {
|
||||||
|
spinnerType.setSelection(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillFields() {
|
||||||
|
editTextTitle.setText(anime.getTitle());
|
||||||
|
editTextScore.setText(String.valueOf(anime.getScore()));
|
||||||
|
editTextProgress.setText(String.valueOf(anime.getProgress()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveChanges() {
|
||||||
|
if (anime == null) {
|
||||||
|
Toast.makeText(requireContext(), "Error: Anime no cargado", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String title = editTextTitle.getText().toString().trim();
|
||||||
|
String scoreStr = editTextScore.getText().toString().trim();
|
||||||
|
String progressStr = editTextProgress.getText().toString().trim();
|
||||||
|
|
||||||
|
if (title.isEmpty()) {
|
||||||
|
Toast.makeText(requireContext(), "El título no puede estar vacío", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int score = 0, progress = 0;
|
||||||
|
try {
|
||||||
|
score = Integer.parseInt(scoreStr);
|
||||||
|
progress = Integer.parseInt(progressStr);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Toast.makeText(requireContext(), "Score y Progreso deben ser números", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String status = spinnerStatus.getSelectedItem() != null ? spinnerStatus.getSelectedItem().toString() : "";
|
||||||
|
String type = spinnerType.getSelectedItem() != null ? spinnerType.getSelectedItem().toString() : "";
|
||||||
|
|
||||||
|
if (status.isEmpty() || type.isEmpty()) {
|
||||||
|
Toast.makeText(requireContext(), "Debe seleccionar estado y tipo", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
anime.setTitle(title);
|
||||||
|
anime.setScore(score);
|
||||||
|
anime.setProgress(progress);
|
||||||
|
anime.setStatus(status);
|
||||||
|
anime.setType(type);
|
||||||
|
|
||||||
|
api.updateAnime(anime.getId(),anime).enqueue(new Callback<String>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<String> call, Response<String> response) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
Toast.makeText(requireContext(), "Anime actualizado", Toast.LENGTH_SHORT).show();
|
||||||
|
requireActivity().getSupportFragmentManager().popBackStack();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(requireContext(), "Error al actualizar", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<String> call, Throwable t) {
|
||||||
|
Toast.makeText(requireContext(), "Fallo en la conexión", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
// EditMangaFragment.java conectado a fragment_edit_manga.xml y funcional
|
||||||
|
|
||||||
|
package com.santiparra.yomitrack.ui.fragments.editmanga;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import com.santiparra.yomitrack.R;
|
||||||
|
import com.santiparra.yomitrack.api.ApiClient;
|
||||||
|
import com.santiparra.yomitrack.api.ApiService;
|
||||||
|
import com.santiparra.yomitrack.db.entities.MangaEntity;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
public class EditMangaFragment extends Fragment {
|
||||||
|
|
||||||
|
private EditText editTextTitle, editTextScore, editTextProgress;
|
||||||
|
private Spinner spinnerStatus, spinnerType;
|
||||||
|
private Button buttonSave;
|
||||||
|
private MangaEntity manga;
|
||||||
|
private ApiService api;
|
||||||
|
private int userId;
|
||||||
|
|
||||||
|
public EditMangaFragment(MangaEntity manga) {
|
||||||
|
this.manga = manga;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_edit_manga, container, false);
|
||||||
|
|
||||||
|
editTextTitle = view.findViewById(R.id.editTextMangaTitle);
|
||||||
|
editTextScore = view.findViewById(R.id.editTextScore);
|
||||||
|
editTextProgress = view.findViewById(R.id.editTextProgress);
|
||||||
|
spinnerStatus = view.findViewById(R.id.spinnerStatus);
|
||||||
|
spinnerType = view.findViewById(R.id.spinnerType);
|
||||||
|
buttonSave = view.findViewById(R.id.buttonSaveManga);
|
||||||
|
|
||||||
|
api = ApiClient.getClient().create(ApiService.class);
|
||||||
|
SharedPreferences prefs = requireContext().getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
|
||||||
|
userId = prefs.getInt("current_user_id", -1);
|
||||||
|
|
||||||
|
setupSpinners();
|
||||||
|
|
||||||
|
if (getArguments() != null && getArguments().containsKey("manga")) {
|
||||||
|
manga = (MangaEntity) getArguments().getSerializable("manga");
|
||||||
|
fillFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonSave.setOnClickListener(v -> updateManga());
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupSpinners() {
|
||||||
|
ArrayAdapter<CharSequence> statusAdapter = ArrayAdapter.createFromResource(
|
||||||
|
requireContext(), R.array.anime_status_array, android.R.layout.simple_spinner_item);
|
||||||
|
statusAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
spinnerStatus.setAdapter(statusAdapter);
|
||||||
|
|
||||||
|
ArrayAdapter<CharSequence> typeAdapter = ArrayAdapter.createFromResource(
|
||||||
|
requireContext(), R.array.anime_type_array, android.R.layout.simple_spinner_item);
|
||||||
|
typeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
spinnerType.setAdapter(typeAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillFields() {
|
||||||
|
editTextTitle.setText(manga.getTitle());
|
||||||
|
editTextScore.setText(String.valueOf(manga.getScore()));
|
||||||
|
editTextProgress.setText(String.valueOf(manga.getProgress()));
|
||||||
|
|
||||||
|
String[] statusArray = getResources().getStringArray(R.array.anime_status_array);
|
||||||
|
for (int i = 0; i < statusArray.length; i++) {
|
||||||
|
if (statusArray[i].equalsIgnoreCase(manga.getStatus())) {
|
||||||
|
spinnerStatus.setSelection(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] typeArray = getResources().getStringArray(R.array.anime_type_array);
|
||||||
|
for (int i = 0; i < typeArray.length; i++) {
|
||||||
|
if (typeArray[i].equalsIgnoreCase(manga.getType())) {
|
||||||
|
spinnerType.setSelection(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateManga() {
|
||||||
|
String title = editTextTitle.getText().toString().trim();
|
||||||
|
int score = Integer.parseInt(editTextScore.getText().toString());
|
||||||
|
int progress = Integer.parseInt(editTextProgress.getText().toString());
|
||||||
|
String status = spinnerStatus.getSelectedItem().toString();
|
||||||
|
String type = spinnerType.getSelectedItem().toString();
|
||||||
|
|
||||||
|
manga.setTitle(title);
|
||||||
|
manga.setScore(score);
|
||||||
|
manga.setProgress(progress);
|
||||||
|
manga.setStatus(status);
|
||||||
|
manga.setType(type);
|
||||||
|
|
||||||
|
api.updateManga(manga.getId(),manga).enqueue(new Callback<String>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<String> call, Response<String> response) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
Toast.makeText(getContext(), "Manga actualizado", Toast.LENGTH_SHORT).show();
|
||||||
|
requireActivity().getSupportFragmentManager().popBackStack();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getContext(), "Error al actualizar", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<String> call, Throwable t) {
|
||||||
|
Toast.makeText(getContext(), "Fallo de conexión", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.santiparra.yomitrack.ui.fragments.login;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import com.santiparra.yomitrack.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actividad contenedora del sistema de login y registro.
|
||||||
|
* Esta actividad aloja el NavHostFragment definido en el layout activity_login.xml
|
||||||
|
*/
|
||||||
|
public class LoginActivity extends AppCompatActivity {
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_login); // contiene el NavHostFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
package com.santiparra.yomitrack.ui.fragments.login;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.navigation.NavController;
|
||||||
|
import androidx.navigation.fragment.NavHostFragment;
|
||||||
|
|
||||||
|
import com.santiparra.yomitrack.R;
|
||||||
|
import com.santiparra.yomitrack.api.ApiClient;
|
||||||
|
import com.santiparra.yomitrack.api.ApiService;
|
||||||
|
import com.santiparra.yomitrack.db.entities.UserEntity;
|
||||||
|
import com.santiparra.yomitrack.model.LoginResponse;
|
||||||
|
import com.santiparra.yomitrack.ui.MainActivity;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fragmento que gestiona el inicio de sesión y entrada como invitado.
|
||||||
|
*/
|
||||||
|
public class LoginFragment extends Fragment {
|
||||||
|
|
||||||
|
private EditText usernameEditText, passwordEditText;
|
||||||
|
private Button loginButton, guestButton, registerButton;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_login, container, false);
|
||||||
|
|
||||||
|
usernameEditText = view.findViewById(R.id.editTextUsername);
|
||||||
|
passwordEditText = view.findViewById(R.id.editTextPassword);
|
||||||
|
loginButton = view.findViewById(R.id.buttonLogin);
|
||||||
|
guestButton = view.findViewById(R.id.buttonGuest);
|
||||||
|
registerButton = view.findViewById(R.id.buttonGoRegister);
|
||||||
|
|
||||||
|
loginButton.setOnClickListener(v -> {
|
||||||
|
String username = usernameEditText.getText().toString().trim();
|
||||||
|
String password = passwordEditText.getText().toString().trim();
|
||||||
|
|
||||||
|
if (username.isEmpty() || password.isEmpty()) {
|
||||||
|
Toast.makeText(getContext(), "Rellena todos los campos", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiService api = ApiClient.getClient().create(ApiService.class);
|
||||||
|
UserEntity user = new UserEntity();
|
||||||
|
user.username = username;
|
||||||
|
user.password = password;
|
||||||
|
|
||||||
|
Call<LoginResponse> call = api.loginUser(user);
|
||||||
|
call.enqueue(new Callback<LoginResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
LoginResponse result = response.body();
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
UserEntity user = result.user;
|
||||||
|
Toast.makeText(getContext(), "Bienvenido " + user.username, Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
|
saveSession(user.id); // ✅ Guardamos el ID del usuario
|
||||||
|
navigateToHome(); // ✅ Entramos a MainActivity
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getContext(), result.message, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getContext(), "Error inesperado", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<LoginResponse> call, Throwable t) {
|
||||||
|
Toast.makeText(getContext(), "Error de red: " + t.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
guestButton.setOnClickListener(v -> {
|
||||||
|
saveSession(-1); // usuario invitado
|
||||||
|
navigateToHome();
|
||||||
|
});
|
||||||
|
|
||||||
|
registerButton.setOnClickListener(v -> {
|
||||||
|
NavController navController = NavHostFragment.findNavController(LoginFragment.this);
|
||||||
|
navController.navigate(R.id.action_login_to_register);
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveSession(int userId) {
|
||||||
|
SharedPreferences prefs = requireContext().getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
|
||||||
|
prefs.edit().putInt("current_user_id", userId).apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void navigateToHome() {
|
||||||
|
startActivity(new Intent(getActivity(), MainActivity.class));
|
||||||
|
requireActivity().finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.santiparra.yomitrack.ui.fragments.login;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import com.santiparra.yomitrack.ui.MainActivity;
|
||||||
|
import com.santiparra.yomitrack.ui.fragments.login.LoginActivity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actividad inicial que decide si ir a LoginActivity o directamente a MainActivity.
|
||||||
|
*/
|
||||||
|
public class SplashActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
SharedPreferences prefs = getSharedPreferences("app_prefs", MODE_PRIVATE);
|
||||||
|
int userId = prefs.getInt("current_user_id", -999);
|
||||||
|
|
||||||
|
if (userId != -999) {
|
||||||
|
// Ya hay una sesión guardada: entrar a la app
|
||||||
|
startActivity(new Intent(this, MainActivity.class));
|
||||||
|
} else {
|
||||||
|
// No hay sesión: ir a login
|
||||||
|
startActivity(new Intent(this, LoginActivity.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
finish(); // Cierra el Splash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
// RegisterFragment.java solucionado para evitar NPE en onFailure()
|
||||||
|
|
||||||
|
package com.santiparra.yomitrack.ui.fragments.register;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import com.santiparra.yomitrack.R;
|
||||||
|
import com.santiparra.yomitrack.api.ApiClient;
|
||||||
|
import com.santiparra.yomitrack.api.ApiService;
|
||||||
|
import com.santiparra.yomitrack.model.RegisterResponse;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
public class RegisterFragment extends Fragment {
|
||||||
|
|
||||||
|
private EditText usernameEditText;
|
||||||
|
private EditText passwordEditText;
|
||||||
|
private Button registerButton;
|
||||||
|
private ApiService api;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_register, container, false);
|
||||||
|
|
||||||
|
usernameEditText = view.findViewById(R.id.editTextUsernameRegister);
|
||||||
|
passwordEditText = view.findViewById(R.id.editTextPasswordRegister);
|
||||||
|
registerButton = view.findViewById(R.id.buttonRegister);
|
||||||
|
api = ApiClient.getClient().create(ApiService.class);
|
||||||
|
|
||||||
|
registerButton.setOnClickListener(v -> attemptRegister());
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void attemptRegister() {
|
||||||
|
String username = usernameEditText.getText().toString().trim();
|
||||||
|
String password = passwordEditText.getText().toString().trim();
|
||||||
|
|
||||||
|
if (username.isEmpty() || password.isEmpty()) {
|
||||||
|
safeToast("Todos los campos son obligatorios");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap<String, String> request = new HashMap<>();
|
||||||
|
request.put("username", username);
|
||||||
|
request.put("password", password);
|
||||||
|
|
||||||
|
api.registerUser(request).enqueue(new Callback<RegisterResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<RegisterResponse> call, Response<RegisterResponse> response) {
|
||||||
|
if (isAdded() && response.isSuccessful() && response.body() != null && response.body().getUserId() > 0) {
|
||||||
|
int userId = response.body().getUserId();
|
||||||
|
SharedPreferences prefs = requireContext().getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
|
||||||
|
prefs.edit().putInt("current_user_id", userId).apply();
|
||||||
|
safeToast("Registro exitoso");
|
||||||
|
requireActivity().finish();
|
||||||
|
} else {
|
||||||
|
safeToast("Error al registrar usuario");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<RegisterResponse> call, Throwable t) {
|
||||||
|
safeToast("Fallo de conexión: " + t.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void safeToast(String message) {
|
||||||
|
if (isAdded() && getContext() != null) {
|
||||||
|
Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:interpolator="@android:interpolator/decelerate_quad"
|
||||||
|
android:fillAfter="true">
|
||||||
|
|
||||||
|
<alpha
|
||||||
|
android:fromAlpha="0"
|
||||||
|
android:toAlpha="1"
|
||||||
|
android:duration="300"/>
|
||||||
|
|
||||||
|
<scale
|
||||||
|
android:fromXScale="0.9"
|
||||||
|
android:fromYScale="0.9"
|
||||||
|
android:toXScale="1.0"
|
||||||
|
android:toYScale="1.0"
|
||||||
|
android:pivotX="50%"
|
||||||
|
android:pivotY="50%"
|
||||||
|
android:duration="300"/>
|
||||||
|
</set>
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid android:color="#4CAF50" /> <!-- verde -->
|
||||||
|
</shape>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 911 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 179 B |
Binary file not shown.
|
After Width: | Height: | Size: 196 B |
Binary file not shown.
|
After Width: | Height: | Size: 236 B |
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
</selector>
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
</selector>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners android:radius="8dp" />
|
||||||
|
<solid android:color="#CCCCCC" />
|
||||||
|
</shape>
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/nav_host_fragment"
|
||||||
|
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:navGraph="@navigation/nav_graph"
|
||||||
|
app:defaultNavHost="true" />
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?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="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingTop="100dp"
|
||||||
|
android:paddingBottom="80dp"
|
||||||
|
android:paddingHorizontal="16dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextSearch"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Buscar anime..."
|
||||||
|
android:inputType="text"
|
||||||
|
android:imeOptions="actionSearch" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextScore"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Puntuación (0-100)"
|
||||||
|
android:inputType="number"
|
||||||
|
android:layout_marginTop="12dp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextProgress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Progreso (episodios vistos)"
|
||||||
|
android:inputType="number"
|
||||||
|
android:layout_marginTop="12dp" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinnerStatus"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinnerType"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recyclerSearchResults"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:scrollbars="vertical" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingTop="100dp"
|
||||||
|
android:paddingBottom="80dp"
|
||||||
|
android:paddingHorizontal="16dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextSearch"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Buscar manga..."
|
||||||
|
android:inputType="text"
|
||||||
|
android:imeOptions="actionSearch" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextScore"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Puntuación (0-100)"
|
||||||
|
android:inputType="number"
|
||||||
|
android:layout_marginTop="12dp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextProgress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Progreso (capítulos leídos)"
|
||||||
|
android:inputType="number"
|
||||||
|
android:layout_marginTop="12dp" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinnerStatus"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinnerType"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recyclerSearchResults"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:scrollbars="vertical" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingTop="100dp"
|
||||||
|
android:paddingBottom="80dp"
|
||||||
|
android:fillViewport="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextAnimeTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Título del anime"
|
||||||
|
android:inputType="text"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:background="@drawable/edit_text_background" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextScore"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Puntuación (0-100)"
|
||||||
|
android:inputType="number"
|
||||||
|
android:layout_marginTop="12dp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextProgress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Progreso (episodios vistos)"
|
||||||
|
android:inputType="number"
|
||||||
|
android:layout_marginTop="12dp" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinnerStatus"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:padding="8dp" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinnerType"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:padding="8dp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/buttonSaveAnime"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Guardar cambios"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:backgroundTint="@color/primary"
|
||||||
|
android:textColor="@android:color/white" />
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingTop="100dp"
|
||||||
|
android:paddingBottom="80dp"
|
||||||
|
android:fillViewport="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextMangaTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Título del manga"
|
||||||
|
android:inputType="text"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:background="@drawable/edit_text_background" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextScore"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Puntuación (0-100)"
|
||||||
|
android:inputType="number"
|
||||||
|
android:layout_marginTop="12dp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextProgress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Progreso (capítulos leídos)"
|
||||||
|
android:inputType="number"
|
||||||
|
android:layout_marginTop="12dp" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinnerStatus"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:padding="8dp" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinnerType"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:padding="8dp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/buttonSaveManga"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Guardar cambios"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:backgroundTint="@color/primary"
|
||||||
|
android:textColor="@android:color/white" />
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="24dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextUsername"
|
||||||
|
android:hint="Usuario"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextPassword"
|
||||||
|
android:hint="Contraseña"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/buttonLogin"
|
||||||
|
android:text="Iniciar Sesión"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/buttonGuest"
|
||||||
|
android:text="Entrar como Invitado"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/buttonGoRegister"
|
||||||
|
android:text="Registrarse"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="24dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextUsernameRegister"
|
||||||
|
android:hint="Nuevo usuario"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextPasswordRegister"
|
||||||
|
android:hint="Contraseña"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/buttonRegister"
|
||||||
|
android:text="Registrarse"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageCover"
|
||||||
|
android:layout_width="60dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:contentDescription="Imagen" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textTitle"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="Título"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:gravity="center_horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageViewCover"
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:layout_height="170dp"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:clipToOutline="true"
|
||||||
|
android:background="@drawable/sample_cover" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textViewTitle"
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Anime Title"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textColor="@color/textPrimary"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:layout_marginTop="4dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/spinnerItemText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/textPrimary"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_view_type"
|
||||||
|
android:icon="@drawable/ic_view_normal"
|
||||||
|
android:title="Cambiar vista"
|
||||||
|
app:showAsAction="always" />
|
||||||
|
</menu>
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/nav_graph"
|
||||||
|
app:startDestination="@id/loginFragment">
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/loginFragment"
|
||||||
|
android:name="com.santiparra.yomitrack.ui.fragments.login.LoginFragment"
|
||||||
|
android:label="Login" >
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_login_to_register"
|
||||||
|
app:destination="@id/registerFragment" />
|
||||||
|
</fragment>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/registerFragment"
|
||||||
|
android:name="com.santiparra.yomitrack.ui.fragments.register.RegisterFragment"
|
||||||
|
android:label="Register" />
|
||||||
|
</navigation>
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<network-security-config>
|
||||||
|
<domain-config cleartextTrafficPermitted="true">
|
||||||
|
<domain includeSubdomains="true">10.0.2.2</domain>
|
||||||
|
</domain-config>
|
||||||
|
</network-security-config>
|
||||||
Loading…
Reference in New Issue