diff --git a/app/src/main/java/com/santiparra/yomitrack/api/ApiService.java b/app/src/main/java/com/santiparra/yomitrack/api/ApiService.java index 782cf3f..5281b9a 100644 --- a/app/src/main/java/com/santiparra/yomitrack/api/ApiService.java +++ b/app/src/main/java/com/santiparra/yomitrack/api/ApiService.java @@ -1,5 +1,6 @@ package com.santiparra.yomitrack.api; +import com.google.gson.JsonObject; import com.santiparra.yomitrack.db.entities.AnimeEntity; import com.santiparra.yomitrack.db.entities.MangaEntity; import com.santiparra.yomitrack.db.entities.UserEntity; @@ -36,7 +37,7 @@ public interface ApiService { // ---------------- Anime ---------------- @POST("anime/add") - Call insertAnime(@Body AnimeEntity anime); + Call insertAnime(@Body AnimeEntity anime); @GET("anime/list/{userId}") Call> getAnimeByUser(@Path("userId") int userId); @@ -57,7 +58,7 @@ public interface ApiService { // ---------------- Manga ---------------- @POST("manga/add") - Call insertManga(@Body MangaEntity manga); + Call insertManga(@Body MangaEntity manga); @GET("manga/list/{userId}") Call> getMangaByUser(@Path("userId") int userId); @@ -82,8 +83,8 @@ public interface ApiService { @GET("api/activity/list/{userId}") Call> getActivityLog(@Path("userId") int userId); - @POST("activity/add") - Call postActivity(@Body Map body); + @POST("api/activity/add") + Call postActivity(@Body Map body); // ---------------- AniList API ---------------- diff --git a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addanime/AddAnimeFragment.java b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addanime/AddAnimeFragment.java index 86e9a5a..d15f4a1 100644 --- a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addanime/AddAnimeFragment.java +++ b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addanime/AddAnimeFragment.java @@ -1,10 +1,9 @@ -// AddAnimeFragment.java - package com.santiparra.yomitrack.ui.fragments.addanime; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; +import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -22,11 +21,13 @@ import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.google.gson.JsonObject; 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.AniListMedia; +import com.santiparra.yomitrack.model.ApiResponse; import com.santiparra.yomitrack.model.adapters.anime_adapter.AnimeSearchAdapter; import java.util.ArrayList; @@ -46,6 +47,7 @@ public class AddAnimeFragment extends Fragment { private AnimeSearchAdapter searchAdapter; private ApiService api; private int userId; + private String selectedImageUrl = ""; @Nullable @Override @@ -137,11 +139,13 @@ public class AddAnimeFragment extends Fragment { anime.setScore(score); anime.setProgress(progress); - api.insertAnime(anime).enqueue(new Callback() { + selectedImageUrl = selected.getImageUrl(); + + api.insertAnime(anime).enqueue(new Callback() { @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - Toast.makeText(getContext(), "Anime añadido", Toast.LENGTH_SHORT).show(); + public void onResponse(Call call, Response response) { + if (response.isSuccessful() && response.body() != null) { + Toast.makeText(getContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show(); registrarActividad(anime.getTitle()); requireActivity().getSupportFragmentManager().popBackStack(); } else { @@ -150,7 +154,7 @@ public class AddAnimeFragment extends Fragment { } @Override - public void onFailure(Call call, Throwable t) { + public void onFailure(Call call, Throwable t) { Toast.makeText(getContext(), "Fallo en la conexión", Toast.LENGTH_SHORT).show(); } }); @@ -159,16 +163,24 @@ public class AddAnimeFragment extends Fragment { private void registrarActividad(String titulo) { Map actividad = new HashMap<>(); actividad.put("userId", userId); - actividad.put("action", "Añadió"); + actividad.put("action", "añadió un anime"); actividad.put("mediaTitle", titulo); + actividad.put("imageUrl", selectedImageUrl); - api.postActivity(actividad).enqueue(new Callback<>() { + api.postActivity(actividad).enqueue(new Callback() { @Override - public void onResponse(Call call, Response response) { + public void onResponse(Call call, Response response) { + Log.d("ACTIVITY_POST", "Código de respuesta: " + response.code()); + if (!response.isSuccessful()) { + Log.e("ACTIVITY_POST", "Error en response: " + response.errorBody()); + } } @Override - public void onFailure(Call call, Throwable t) { + public void onFailure(Call call, Throwable t) { + Log.e("ACTIVITY_POST", "Error al registrar actividad: " + t.getMessage(), t); + if (!isAdded()) return; + Toast.makeText(getContext(), "Error al registrar actividad", Toast.LENGTH_SHORT).show(); } }); } diff --git a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addmanga/AddMangaFragment.java b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addmanga/AddMangaFragment.java index fc38cfb..a59a940 100644 --- a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addmanga/AddMangaFragment.java +++ b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/addmanga/AddMangaFragment.java @@ -20,11 +20,13 @@ import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.google.gson.JsonObject; 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.AniListMedia; +import com.santiparra.yomitrack.model.ApiResponse; import com.santiparra.yomitrack.model.adapters.manga_adapter.MangaSearchAdapter; import java.util.ArrayList; @@ -44,6 +46,7 @@ public class AddMangaFragment extends Fragment { private MangaSearchAdapter searchAdapter; private ApiService api; private int userId; + private String selectedImageUrl = ""; @Nullable @Override @@ -135,11 +138,13 @@ public class AddMangaFragment extends Fragment { manga.setScore(score); manga.setProgress(progress); - api.insertManga(manga).enqueue(new Callback() { + selectedImageUrl = selected.getImageUrl(); + + api.insertManga(manga).enqueue(new Callback() { @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - Toast.makeText(getContext(), "Manga añadido correctamente", Toast.LENGTH_SHORT).show(); + public void onResponse(Call call, Response response) { + if (response.isSuccessful() && response.body() != null) { + Toast.makeText(getContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show(); registrarActividad(manga.getTitle()); requireActivity().getSupportFragmentManager().popBackStack(); } else { @@ -148,7 +153,7 @@ public class AddMangaFragment extends Fragment { } @Override - public void onFailure(Call call, Throwable t) { + public void onFailure(Call call, Throwable t) { Toast.makeText(getContext(), "Fallo en la conexión", Toast.LENGTH_SHORT).show(); } }); @@ -157,16 +162,21 @@ public class AddMangaFragment extends Fragment { private void registrarActividad(String titulo) { Map actividad = new HashMap<>(); actividad.put("userId", userId); - actividad.put("action", "Añadió"); + actividad.put("action", "añadió un manga"); actividad.put("mediaTitle", titulo); + actividad.put("imageUrl", selectedImageUrl); - api.postActivity(actividad).enqueue(new Callback<>() { + api.postActivity(actividad).enqueue(new Callback() { @Override - public void onResponse(Call call, Response response) { + public void onResponse(Call call, Response response) { + if (!response.isSuccessful()) { + // Puedes logear el error si lo deseas + } } @Override - public void onFailure(Call call, Throwable t) { + public void onFailure(Call call, Throwable t) { + Toast.makeText(getContext(), "Error al registrar actividad", Toast.LENGTH_SHORT).show(); } }); } diff --git a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/anime_list/FragmentAnime.java b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/anime_list/FragmentAnime.java index 5ffd923..e48f5cf 100644 --- a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/anime_list/FragmentAnime.java +++ b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/anime_list/FragmentAnime.java @@ -46,7 +46,7 @@ public class FragmentAnime extends Fragment { private RecyclerView recyclerView; private AnimeAdapter adapter; private ApiService api; - private int userId = 1; + private int userId; private ImageButton btnViewCompact, btnViewNormal, btnViewLarge; private int currentViewType = AnimeAdapter.VIEW_NORMAL; @@ -69,22 +69,13 @@ public class FragmentAnime extends Fragment { @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - recyclerView = view.findViewById(R.id.recyclerViewAnime); - btnViewCompact = view.findViewById(R.id.btnViewCompact); - btnViewNormal = view.findViewById(R.id.btnViewNormal); - btnViewLarge = view.findViewById(R.id.btnViewLarge); - FloatingActionButton fabAdd = view.findViewById(R.id.fabAddAnime); - editSearch = view.findViewById(R.id.editSearch); + initViews(view); + setupRecyclerView(); + setupViewButtons(); + setupSearchListener(); + setupFab(view); + setupInsets(view); - editSearch.addTextChangedListener(new TextWatcher() { - @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} - @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - filterAnimeList(s.toString()); - } - @Override public void afterTextChanged(Editable s) {} - }); - - api = ApiClient.getClient().create(ApiService.class); SharedPreferences prefs = requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE); userId = prefs.getInt("user_id", -1); @@ -93,25 +84,26 @@ public class FragmentAnime extends Fragment { return; } + loadMoreAnimes(currentPage); + } + + private void initViews(View view) { + recyclerView = view.findViewById(R.id.recyclerViewAnime); + btnViewCompact = view.findViewById(R.id.btnViewCompact); + btnViewNormal = view.findViewById(R.id.btnViewNormal); + btnViewLarge = view.findViewById(R.id.btnViewLarge); + editSearch = view.findViewById(R.id.editSearch); + api = ApiClient.getClient().create(ApiService.class); + } + + private void setupRecyclerView() { adapter = new AnimeAdapter(animeList, currentViewType, this::showEditDialog, this::deleteAnime); recyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); recyclerView.setAdapter(adapter); - fabAdd.setOnClickListener(v -> requireActivity().getSupportFragmentManager() - .beginTransaction() - .replace(R.id.frame_layout, new AddAnimeFragment()) - .addToBackStack(null) - .commit()); - - btnViewCompact.setOnClickListener(v -> setViewType(AnimeAdapter.VIEW_COMPACT)); - btnViewNormal.setOnClickListener(v -> setViewType(AnimeAdapter.VIEW_NORMAL)); - btnViewLarge.setOnClickListener(v -> setViewType(AnimeAdapter.VIEW_LARGE)); - - setViewType(currentViewType); - loadMoreAnimes(currentPage); - recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { - @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); if (layoutManager == null) return; @@ -125,7 +117,34 @@ public class FragmentAnime extends Fragment { } } }); + } + private void setupViewButtons() { + btnViewCompact.setOnClickListener(v -> setViewType(AnimeAdapter.VIEW_COMPACT)); + btnViewNormal.setOnClickListener(v -> setViewType(AnimeAdapter.VIEW_NORMAL)); + btnViewLarge.setOnClickListener(v -> setViewType(AnimeAdapter.VIEW_LARGE)); + } + + private void setupSearchListener() { + editSearch.addTextChangedListener(new TextWatcher() { + @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + @Override public void onTextChanged(CharSequence s, int start, int before, int count) { + filterAnimeList(s.toString()); + } + @Override public void afterTextChanged(Editable s) {} + }); + } + + private void setupFab(View view) { + FloatingActionButton fabAdd = view.findViewById(R.id.fabAddAnime); + fabAdd.setOnClickListener(v -> requireActivity().getSupportFragmentManager() + .beginTransaction() + .replace(R.id.frame_layout, new AddAnimeFragment()) + .addToBackStack(null) + .commit()); + } + + private void setupInsets(View view) { ViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -> { int bottomInset = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom; recyclerView.setPadding( @@ -150,13 +169,9 @@ public class FragmentAnime extends Fragment { private void setViewType(int viewType) { currentViewType = viewType; - - if (viewType == AnimeAdapter.VIEW_LARGE) { - recyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2)); - } else { - recyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); - } - + recyclerView.setLayoutManager(viewType == AnimeAdapter.VIEW_LARGE ? + new GridLayoutManager(requireContext(), 2) : + new LinearLayoutManager(requireContext())); adapter = new AnimeAdapter(animeList, viewType, this::showEditDialog, this::deleteAnime); recyclerView.setAdapter(adapter); } @@ -175,9 +190,8 @@ public class FragmentAnime extends Fragment { public void onResponse(Call call, Response response) { if (!isAdded()) return; - if (response.isSuccessful()) { - String msg = response.body() != null ? response.body().getMessage() : "Anime eliminado"; - Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show(); + if (response.isSuccessful() && response.body() != null) { + Toast.makeText(requireContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show(); currentPage = 1; animeList.clear(); loadMoreAnimes(currentPage); @@ -208,7 +222,6 @@ public class FragmentAnime extends Fragment { List nuevos = response.body().getData(); animeList.addAll(nuevos); adapter.notifyItemRangeInserted(animeList.size() - nuevos.size(), nuevos.size()); - isLoading = response.body().isHasNextPage(); } else { isLoading = false; diff --git a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editanime/EditAnimeFragment.java b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editanime/EditAnimeFragment.java index 60b3f09..cceeaec 100644 --- a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editanime/EditAnimeFragment.java +++ b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editanime/EditAnimeFragment.java @@ -13,12 +13,16 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import com.google.gson.JsonObject; 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.ApiResponse; +import java.util.HashMap; +import java.util.Map; + import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; @@ -142,6 +146,7 @@ public class EditAnimeFragment extends Fragment { if (response.isSuccessful()) { String message = response.body() != null ? response.body().getMessage() : "Anime actualizado"; Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show(); + registrarActividad(anime.getTitle()); requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE) .edit().putBoolean("refresh_profile", true).apply(); requireActivity().getSupportFragmentManager().popBackStack(); @@ -184,4 +189,30 @@ public class EditAnimeFragment extends Fragment { } }); } + + private void registrarActividad(String titulo) { + int userId = requireContext() + .getSharedPreferences("user_session", Context.MODE_PRIVATE) + .getInt("user_id", -1); + + if (userId == -1) return; + + Map actividad = new HashMap<>(); + actividad.put("userId", userId); + actividad.put("action", "editó un anime"); + actividad.put("mediaTitle", titulo); + actividad.put("imageUrl", anime.getImageUrl()); + + api.postActivity(actividad).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + Log.d("ACTIVITY_EDIT", "Actividad registrada: " + response.code()); + } + + @Override + public void onFailure(Call call, Throwable t) { + Log.e("ACTIVITY_EDIT", "Error al registrar actividad: " + t.getMessage(), t); + } + }); + } } diff --git a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editmanga/EditMangaFragment.java b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editmanga/EditMangaFragment.java index 2ff8c45..e253e65 100644 --- a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editmanga/EditMangaFragment.java +++ b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/editmanga/EditMangaFragment.java @@ -13,12 +13,16 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import com.google.gson.JsonObject; 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.ApiResponse; +import java.util.HashMap; +import java.util.Map; + import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; @@ -36,8 +40,7 @@ public class EditMangaFragment extends Fragment { } @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_edit_manga, container, false); } @@ -134,13 +137,11 @@ public class EditMangaFragment extends Fragment { api.updateManga(manga.getId(), manga).enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { - Log.d("API_RESPONSE", "onResponse ejecutado: " + response.body()); - if (!isAdded()) return; - if (response.isSuccessful()) { - String message = response.body() != null ? response.body().getMessage() : "Manga actualizado"; - Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show(); + if (response.isSuccessful() && response.body() != null) { + Toast.makeText(requireContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show(); + registrarActividad(manga.getTitle()); requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE) .edit().putBoolean("refresh_profile", true).apply(); requireActivity().getSupportFragmentManager().popBackStack(); @@ -151,7 +152,6 @@ public class EditMangaFragment extends Fragment { @Override public void onFailure(Call call, Throwable t) { - Log.e("API_RESPONSE", "onFailure ejecutado: " + t.getMessage(), t); if (!isAdded()) return; Toast.makeText(requireContext(), "Fallo en la conexión", Toast.LENGTH_SHORT).show(); } @@ -164,9 +164,8 @@ public class EditMangaFragment extends Fragment { public void onResponse(Call call, Response response) { if (!isAdded()) return; - if (response.isSuccessful()) { - String message = response.body() != null ? response.body().getMessage() : "Manga eliminado"; - Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show(); + if (response.isSuccessful() && response.body() != null) { + Toast.makeText(requireContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show(); requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE) .edit().putBoolean("refresh_profile", true).apply(); requireActivity().getSupportFragmentManager().popBackStack(); @@ -177,10 +176,35 @@ public class EditMangaFragment extends Fragment { @Override public void onFailure(Call call, Throwable t) { - Log.e("API_RESPONSE", "onFailure eliminar: " + t.getMessage(), t); if (!isAdded()) return; Toast.makeText(requireContext(), "Fallo en la conexión", Toast.LENGTH_SHORT).show(); } }); } + + private void registrarActividad(String titulo) { + int userId = requireContext() + .getSharedPreferences("user_session", Context.MODE_PRIVATE) + .getInt("user_id", -1); + + if (userId == -1) return; + + Map actividad = new HashMap<>(); + actividad.put("userId", userId); + actividad.put("action", "editó un manga"); + actividad.put("mediaTitle", titulo); + actividad.put("imageUrl", manga.getImageUrl()); + + api.postActivity(actividad).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + Log.d("ACTIVITY_EDIT_MANGA", "Actividad registrada: " + response.code()); + } + + @Override + public void onFailure(Call call, Throwable t) { + Log.e("ACTIVITY_EDIT_MANGA", "Error al registrar actividad: " + t.getMessage(), t); + } + }); + } } diff --git a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/manga_list/FragmentManga.java b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/manga_list/FragmentManga.java index b9e74e3..37dd323 100644 --- a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/manga_list/FragmentManga.java +++ b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/manga_list/FragmentManga.java @@ -46,7 +46,7 @@ public class FragmentManga extends Fragment { private RecyclerView recyclerView; private MangaAdapter adapter; private ApiService api; - private int userId = 1; + private int userId; private ImageButton btnViewCompact, btnViewNormal, btnViewLarge; private int currentViewType = MangaAdapter.VIEW_NORMAL; @@ -58,31 +58,17 @@ public class FragmentManga extends Fragment { @Nullable @Override - public View onCreateView(@NonNull LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_mlist, container, false); } @Override - public void onViewCreated(@NonNull View view, - @Nullable Bundle savedInstanceState) { + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - recyclerView = view.findViewById(R.id.recyclerViewManga); - btnViewCompact = view.findViewById(R.id.btnViewCompact); - btnViewNormal = view.findViewById(R.id.btnViewNormal); - btnViewLarge = view.findViewById(R.id.btnViewLarge); - FloatingActionButton fabAdd = view.findViewById(R.id.fabAddManga); - editSearch = view.findViewById(R.id.editSearch); - - editSearch.addTextChangedListener(new TextWatcher() { - @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} - @Override public void afterTextChanged(Editable s) {} - @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - filterMangaList(s.toString()); - } - }); + initViews(view); + setupListeners(); + setupRecyclerView(); api = ApiClient.getClient().create(ApiService.class); SharedPreferences prefs = requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE); @@ -93,18 +79,54 @@ public class FragmentManga extends Fragment { return; } + setViewType(currentViewType); + loadMoreMangas(currentPage); + } + + private void initViews(View view) { + recyclerView = view.findViewById(R.id.recyclerViewManga); + btnViewCompact = view.findViewById(R.id.btnViewCompact); + btnViewNormal = view.findViewById(R.id.btnViewNormal); + btnViewLarge = view.findViewById(R.id.btnViewLarge); + FloatingActionButton fabAdd = view.findViewById(R.id.fabAddManga); + editSearch = view.findViewById(R.id.editSearch); + fabAdd.setOnClickListener(v -> requireActivity().getSupportFragmentManager() .beginTransaction() .replace(R.id.frame_layout, new AddMangaFragment()) .addToBackStack(null) .commit()); + ViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -> { + int bottomInset = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom; + recyclerView.setPadding( + recyclerView.getPaddingLeft(), + recyclerView.getPaddingTop(), + recyclerView.getPaddingRight(), + bottomInset + 95 + ); + return insets; + }); + } + + private void setupListeners() { + editSearch.addTextChangedListener(new TextWatcher() { + @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + @Override public void afterTextChanged(Editable s) {} + @Override public void onTextChanged(CharSequence s, int start, int before, int count) { + filterMangaList(s.toString()); + } + }); + btnViewCompact.setOnClickListener(v -> setViewType(MangaAdapter.VIEW_COMPACT)); btnViewNormal.setOnClickListener(v -> setViewType(MangaAdapter.VIEW_NORMAL)); btnViewLarge.setOnClickListener(v -> setViewType(MangaAdapter.VIEW_LARGE)); + } - setViewType(currentViewType); - loadMoreMangas(currentPage); + private void setupRecyclerView() { + adapter = new MangaAdapter(mangaList, currentViewType, this::showEditDialog, this::deleteManga); + recyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); + recyclerView.setAdapter(adapter); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override @@ -122,27 +144,6 @@ public class FragmentManga extends Fragment { } } }); - - ViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -> { - int bottomInset = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom; - recyclerView.setPadding( - recyclerView.getPaddingLeft(), - recyclerView.getPaddingTop(), - recyclerView.getPaddingRight(), - bottomInset + 95 - ); - return insets; - }); - } - - private void filterMangaList(String query) { - List filtered = new ArrayList<>(); - for (MangaEntity manga : mangaList) { - if (manga.getTitle().toLowerCase().contains(query.toLowerCase())) { - filtered.add(manga); - } - } - adapter.updateList(filtered); } private void setViewType(int viewType) { @@ -154,12 +155,20 @@ public class FragmentManga extends Fragment { 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); } + private void filterMangaList(String query) { + List filtered = new ArrayList<>(); + for (MangaEntity manga : mangaList) { + if (manga.getTitle().toLowerCase().contains(query.toLowerCase())) { + filtered.add(manga); + } + } + adapter.updateList(filtered); + } + private void showEditDialog(MangaEntity manga) { requireActivity().getSupportFragmentManager() .beginTransaction() @@ -175,8 +184,7 @@ public class FragmentManga extends Fragment { if (!isAdded()) return; if (response.isSuccessful()) { - String msg = response.body() != null ? response.body().getMessage() : "Manga eliminado"; - Toast.makeText(requireContext(), msg, 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); diff --git a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/profile/FragmentProfile.java b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/profile/FragmentProfile.java index 59f189f..a4a7179 100644 --- a/app/src/main/java/com/santiparra/yomitrack/ui/fragments/profile/FragmentProfile.java +++ b/app/src/main/java/com/santiparra/yomitrack/ui/fragments/profile/FragmentProfile.java @@ -10,17 +10,20 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.*; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import com.bumptech.glide.Glide; import com.santiparra.yomitrack.R; import com.santiparra.yomitrack.api.ApiClient; import com.santiparra.yomitrack.api.ApiService; import com.santiparra.yomitrack.model.UserStatsResponse; import com.santiparra.yomitrack.utils.ActivityLog; -import org.json.JSONObject; +import com.google.gson.JsonObject; + import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -42,11 +45,28 @@ public class FragmentProfile extends Fragment { private String username; private View view; + private SharedPreferences bioPrefs; + private static final String BIO_PREFS = "bio_prefs"; + private static final String BIO_KEY = "bio_text"; + @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { view = inflater.inflate(R.layout.fragment_profile, container, false); + initViews(); + setupUserInfo(); + setupListeners(); + return view; + } + @Override + public void onResume() { + super.onResume(); + loadStats(); + loadActivity(); + } + + private void initViews() { avatarImage = view.findViewById(R.id.avatarImage); coverImage = view.findViewById(R.id.coverImage); usernameText = view.findViewById(R.id.usernameText); @@ -57,28 +77,26 @@ public class FragmentProfile extends Fragment { animeStatsContainer = view.findViewById(R.id.animeStatsContainer); mangaStatsContainer = view.findViewById(R.id.mangaStatsContainer); activityContainer = view.findViewById(R.id.activityContainer); + } + private void setupUserInfo() { SharedPreferences prefs = requireContext().getSharedPreferences("user_session", Context.MODE_PRIVATE); userId = prefs.getInt("user_id", -1); username = prefs.getString("username", "Usuario"); - - api = ApiClient.getClient().create(ApiService.class); usernameText.setText(username); + bioPrefs = requireContext().getSharedPreferences(BIO_PREFS, Context.MODE_PRIVATE); + editBiography.setText(bioPrefs.getString(BIO_KEY, "")); + + api = ApiClient.getClient().create(ApiService.class); + loadStats(); loadActivity(); - - buttonPostStatus.setOnClickListener(v -> postStatus()); - buttonSaveBio.setOnClickListener(v -> saveBiography()); - - return view; } - @Override - public void onResume() { - super.onResume(); - loadStats(); - loadActivity(); + private void setupListeners() { + buttonPostStatus.setOnClickListener(v -> postStatus()); + buttonSaveBio.setOnClickListener(v -> saveBiography()); } private void loadStats() { @@ -104,48 +122,41 @@ public class FragmentProfile extends Fragment { container.removeAllViews(); if (stats == null || stats.isEmpty()) { - TextView noData = new TextView(getContext()); - noData.setText("No hay estadísticas disponibles"); - noData.setPadding(16, 8, 16, 8); - container.addView(noData); + addTextToContainer(container, "No hay estadísticas disponibles"); return; } - int total = 0; - for (int count : stats.values()) total += count; - + int total = stats.values().stream().mapToInt(Integer::intValue).sum(); LayoutInflater inflater = LayoutInflater.from(getContext()); + for (Map.Entry entry : stats.entrySet()) { View statView = inflater.inflate(R.layout.item_stat_bar, container, false); TextView label = statView.findViewById(R.id.statLabelFull); ProgressBar bar = statView.findViewById(R.id.statProgressBar); label.setText(String.format(Locale.getDefault(), "%s • %d", entry.getKey(), entry.getValue())); - int progress = total > 0 ? (entry.getValue() * 100 / total) : 0; - bar.setProgress(progress); - - // Usar método compatible para aplicar color de estado - int color = getColorForStatus(entry.getKey()); - bar.setProgressTintList(ColorStateList.valueOf(color)); + bar.setProgress(total > 0 ? (entry.getValue() * 100 / total) : 0); + bar.setProgressTintList(ColorStateList.valueOf(getColorForStatus(entry.getKey()))); container.addView(statView); } } + private void addTextToContainer(LinearLayout container, String message) { + TextView noData = new TextView(getContext()); + noData.setText(message); + noData.setPadding(16, 8, 16, 8); + container.addView(noData); + } + private int getColorForStatus(String status) { switch (status.toLowerCase(Locale.ROOT)) { - case "watching": - return requireContext().getColor(R.color.status_watching); - case "completed": - return requireContext().getColor(R.color.status_completed); - case "paused": - return requireContext().getColor(R.color.status_paused); - case "dropped": - return requireContext().getColor(R.color.status_dropped); - case "planning": - return requireContext().getColor(R.color.status_planning); - default: - return requireContext().getColor(R.color.gray); + case "watching": return requireContext().getColor(R.color.status_watching); + case "completed": return requireContext().getColor(R.color.status_completed); + case "paused": return requireContext().getColor(R.color.status_paused); + case "dropped": return requireContext().getColor(R.color.status_dropped); + case "planning": return requireContext().getColor(R.color.status_planning); + default: return requireContext().getColor(R.color.gray); } } @@ -163,6 +174,10 @@ public class FragmentProfile extends Fragment { ((TextView) card.findViewById(R.id.activityAction)).setText(log.getAction()); ((TextView) card.findViewById(R.id.activityTitle)).setText(log.getMediaTitle()); ((TextView) card.findViewById(R.id.activityTime)).setText(log.getTimestamp()); + + if (!TextUtils.isEmpty(log.getImageUrl())) { + Glide.with(requireContext()).load(log.getImageUrl()).into((ImageView) card.findViewById(R.id.activityCover)); + } activityContainer.addView(card); } } @@ -187,9 +202,9 @@ public class FragmentProfile extends Fragment { post.put("action", "publicó"); post.put("mediaTitle", status); - api.postActivity(post).enqueue(new Callback() { + api.postActivity(post).enqueue(new Callback() { @Override - public void onResponse(Call call, Response response) { + public void onResponse(Call call, Response response) { if (response.isSuccessful()) { editStatus.setText(""); loadActivity(); @@ -198,14 +213,14 @@ public class FragmentProfile extends Fragment { } @Override - public void onFailure(Call call, Throwable t) { + public void onFailure(Call call, Throwable t) { Toast.makeText(getContext(), "Error al publicar", Toast.LENGTH_SHORT).show(); } }); } private void saveBiography() { - String bio = editBiography.getText().toString().trim(); + bioPrefs.edit().putString(BIO_KEY, editBiography.getText().toString().trim()).apply(); Toast.makeText(getContext(), "Biografía guardada", Toast.LENGTH_SHORT).show(); } } diff --git a/app/src/main/java/com/santiparra/yomitrack/utils/ActivityLog.java b/app/src/main/java/com/santiparra/yomitrack/utils/ActivityLog.java index 149c208..b8437eb 100644 --- a/app/src/main/java/com/santiparra/yomitrack/utils/ActivityLog.java +++ b/app/src/main/java/com/santiparra/yomitrack/utils/ActivityLog.java @@ -13,6 +13,13 @@ public class ActivityLog { @SerializedName("timestamp") private String timestamp; + @SerializedName("imagenUrl") + private String imageUrl; + + public String getImageUrl() { + return imageUrl; + } + public String getAction() { return action; } public String getMediaTitle() { return mediaTitle; }