Tesis 1.0.0
Loading...
Searching...
No Matches
PaymentFragment.java
Go to the documentation of this file.
1package com.example.food_front;
2
3import android.content.Intent;
4import android.graphics.Bitmap;
5import android.os.Bundle;
6import android.os.Handler;
7import android.util.Log;
8import android.view.LayoutInflater;
9import android.view.View;
10import android.view.ViewGroup;
11import android.webkit.WebResourceError;
12import android.webkit.WebResourceRequest;
13import android.webkit.WebSettings;
14import android.webkit.WebView;
15import android.webkit.WebViewClient;
16import android.widget.Button;
17import android.widget.ProgressBar;
18import android.widget.RadioButton;
19import android.widget.RadioGroup;
20import android.widget.TextView;
21import android.widget.Toast;
22import android.app.AlertDialog;
23import android.content.DialogInterface;
24import android.os.Handler;
25
26import androidx.fragment.app.Fragment;
27import androidx.fragment.app.FragmentManager;
28import androidx.fragment.app.FragmentTransaction;
29
30import com.example.food_front.models.MercadoPagoPreference;
31import com.example.food_front.utils.DiagnosticUtil;
32import com.example.food_front.utils.MercadoPagoService;
33import com.example.food_front.utils.NetworkUtils;
34import com.example.food_front.utils.SessionManager;
35import com.example.food_front.utils.ConnectionMonitor;
36
37public class PaymentFragment extends Fragment implements ConnectionMonitor.ConnectivityListener {
38
39 private RadioGroup radioGroupPaymentMethod;
40 private RadioButton radioButtonMercadoPago, radioButtonCreditCard, radioButtonPaypal;
41 private Button buttonPayNow, buttonRetry;
42 private ProgressBar progressBar;
43 private WebView webViewPayment;
44 private View paymentLayout, webViewLayout, errorLayout;
45 private TextView textViewError;
46 private static final String TAG = "PaymentFragment";
47 private MercadoPagoService mercadoPagoService;
48 private SessionManager sessionManager;
49 private String currentPaymentRequestId;
50
51 // Constantes para los errores de WebView
52 private static final int ERROR_TIMEOUT = -8;
53 private static final int ERROR_HOST_LOOKUP = -2;
54 private static final int ERROR_CONNECT = -6;
55 private static final int ERROR_IO = -7;
56
57 // Timeout en milisegundos para la carga de una página
58 private static final int PAGE_LOAD_TIMEOUT = 20000; // 20 segundos
59 private Runnable timeoutRunnable;
60 private Handler timeoutHandler = new Handler();
61
62 // Monitor de conexión
63 private ConnectionMonitor connectionMonitor;
64 private boolean isNetworkAvailable = true;
65
66 public PaymentFragment() {
67 // Constructor vacío requerido
68 }
69 @Override
70 public View onCreateView(LayoutInflater inflater, ViewGroup container,
71 Bundle savedInstanceState) {
72 // Inflar el layout para este fragmento
73 View view = inflater.inflate(R.layout.fragment_payment, container, false);
74
75 // Inicializar servicios
76 mercadoPagoService = new MercadoPagoService(requireContext());
77 sessionManager = new SessionManager(requireContext());
78
79 // Inicializar el monitor de conexión
80 connectionMonitor = new ConnectionMonitor(requireContext(), this);
81
82 // Inicializar vistas
83 radioGroupPaymentMethod = view.findViewById(R.id.radioGroupPaymentMethod);
84 radioButtonCreditCard = view.findViewById(R.id.radioButton4);
85 radioButtonMercadoPago = view.findViewById(R.id.radioButton6);
86 radioButtonPaypal = view.findViewById(R.id.radioButtonPaypal);
87 buttonPayNow = view.findViewById(R.id.button2);
88 buttonRetry = view.findViewById(R.id.buttonRetry);
89 progressBar = view.findViewById(R.id.progressBarPayment);
90 webViewPayment = view.findViewById(R.id.webViewPayment);
91 paymentLayout = view.findViewById(R.id.paymentLayout);
92 webViewLayout = view.findViewById(R.id.webViewLayout);
93 errorLayout = view.findViewById(R.id.errorLayout);
94 textViewError = view.findViewById(R.id.textViewError);
95 // Configurar texto para la opción de MercadoPago
96 radioButtonMercadoPago.setText("MercadoPago");
97 // Configurar texto para la opción de PayPal
98 radioButtonPaypal.setText("PayPal");
99
100 // Configurar WebView según las recomendaciones de MercadoPago
101 WebSettings webSettings = webViewPayment.getSettings();
102 webSettings.setJavaScriptEnabled(true); // MercadoPago requiere JavaScript
103 webSettings.setDomStorageEnabled(true); // Permitir almacenamiento DOM
104 webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE); // No usar caché
105 webSettings.setJavaScriptCanOpenWindowsAutomatically(true); // Permitir popups
106 webSettings.setSupportMultipleWindows(true); // Soportar múltiples ventanas
107 webSettings.setLoadWithOverviewMode(true); // Cargar la página ajustándola a la pantalla
108 webSettings.setUseWideViewPort(true); // Usar viewport ancho webSettings.setBuiltInZoomControls(false); // Desactivar controles de zoom
109 webSettings.setSupportZoom(false); // Desactivar zoom
110
111 webViewPayment.setWebViewClient(new WebViewClient() {
112 @Override
113 public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
114 String url = request.getUrl().toString();
115 Log.d(TAG, "URL cargada: " + url);
116
117 // Verificar si la URL es una de las URLs de retorno
118 // De acuerdo con la documentación de MercadoPago, debemos verificar las URLs de retorno
119 if (url.contains("/exito") || url.contains("/success") ||
120 url.contains("ispcfood.netlify.app/exito") ||
121 url.contains("success=true") ||
122 url.contains("status=approved")) {
123
124 Log.d(TAG, "Detectada URL de pago exitoso: " + url);
125 handlePaymentSuccess();
126 return true;
127 } else if (url.contains("/error") || url.contains("/failure") ||
128 url.contains("ispcfood.netlify.app/error") ||
129 url.contains("status=rejected")) {
130
131 Log.d(TAG, "Detectada URL de pago rechazado: " + url);
132 handlePaymentFailure();
133 return true;
134 } else if (url.contains("/pendiente") || url.contains("/pending") ||
135 url.contains("ispcfood.netlify.app/pendiente") ||
136 url.contains("status=pending") || url.contains("status=in_process")) {
137
138 Log.d(TAG, "Detectada URL de pago pendiente: " + url);
139 handlePaymentPending();
140 return true;
141 }
142
143 // Si no es una URL de retorno, permitir la carga normalmente
144 return false;
145 }
146
147 @Override
148 public void onPageStarted(WebView view, String url, Bitmap favicon) {
149 super.onPageStarted(view, url, favicon);
150 showWebViewProgress(true);
151
152 // Establecer un timeout para la carga de la página
153 startPageLoadingTimeout(view, url);
154 }
155
156 @Override
157 public void onPageFinished(WebView view, String url) {
158 super.onPageFinished(view, url);
159 showWebViewProgress(false);
160
161 // Cancelar el temporizador ya que la página se ha cargado
162 cancelPageLoadingTimeout();
163
164 // Log para depuración
165 Log.d(TAG, "Página cargada correctamente: " + url);
166 }
167
168 @Override
169 public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
170 super.onReceivedError(view, errorCode, description, failingUrl);
171 Log.e(TAG, "WebView error: " + description + " (código: " + errorCode + ") URL: " + failingUrl);
172
173 // Verificar si el error es en la URL principal de pago o en un recurso secundario
174 if (failingUrl != null && failingUrl.contains("mercadopago")) {
175 // Si es un error de tiempo de espera o de conectividad, mostrar un mensaje específico
176 if (errorCode == ERROR_TIMEOUT || errorCode == ERROR_HOST_LOOKUP ||
177 errorCode == ERROR_CONNECT || errorCode == ERROR_IO) {
178
179 // Error de conectividad
180 requireActivity().runOnUiThread(new Runnable() {
181 @Override
182 public void run() {
183 showWebViewProgress(false);
184 showErrorView(true, "Error de conexión con MercadoPago. Por favor verifica tu conexión a Internet e intenta nuevamente.");
185
186 // Agregar un botón para recargar directamente
187 if (buttonRetry != null) {
188 buttonRetry.setText("Reintentar conexión");
189 }
190 }
191 });
192 } else {
193 // Otros errores
194 requireActivity().runOnUiThread(new Runnable() {
195 @Override
196 public void run() {
197 showWebViewProgress(false);
198 showErrorView(true, "Error al cargar la página de pago de MercadoPago: " + description);
199 }
200 });
201 }
202 } else {
203 // Si es un recurso secundario, solo log pero no interrumpir
204 Log.w(TAG, "Error en recurso secundario, continuando carga: " + failingUrl);
205 }
206 }
207 });// Configurar el botón de pago
208 buttonPayNow.setOnClickListener(new View.OnClickListener() {
209 @Override
210 public void onClick(View v) {
211 if (radioButtonMercadoPago.isChecked()) {
212 procesarPagoConMercadoPago();
213 } else if (radioButtonCreditCard.isChecked() || radioButtonPaypal.isChecked()) {
214 // Confirmar pedido en backend para PayPal y tarjeta
215 confirmarPedidoBackend();
216 } else {
217 Toast.makeText(requireContext(), "Por favor selecciona un método de pago", Toast.LENGTH_SHORT).show();
218 }
219 }
220 });
221
222 // Configurar el botón de reintento
223 buttonRetry.setOnClickListener(new View.OnClickListener() {
224 @Override
225 public void onClick(View v) {
226 showErrorView(false, null);
227 procesarPagoConMercadoPago();
228 }
229 }); return view;
230 }
231
232 private void procesarPagoConMercadoPago() {
233 showLoading(true);
234 showErrorView(false, null);
235
236 // Verificar conectividad a Internet
237 if (!NetworkUtils.isNetworkAvailable(requireContext())) {
238 showErrorView(true, "No hay conexión a Internet. Por favor, verifica tu conexión e intenta nuevamente.");
239 return;
240 }
241
242 // Intentar verificar rápidamente conexión al servidor
243 new Thread(new Runnable() {
244 @Override
245 public void run() {
246 // Timeout más corto para mejorar la experiencia de usuario
247 final boolean serverReachable = NetworkUtils.checkUrlAvailability("https://backmp.onrender.com", 3000);
248
249 requireActivity().runOnUiThread(new Runnable() {
250 @Override
251 public void run() {
252 if (!serverReachable) {
253 Log.w(TAG, "Servidor aparentemente no alcanzable, pero intentaremos igualmente");
254 // Aunque el servidor no parezca alcanzable, intentamos de todas formas
255 // ya que la verificación no siempre es precisa
256 Toast.makeText(requireContext(), "Conectando con el servidor de pagos...", Toast.LENGTH_SHORT).show();
257 }
258
259 // Continuar con el proceso en cualquier caso
260 continuarProcesoPago();
261 }
262 });
263 } }).start();
264 }
265
266 private void continuarProcesoPago() {
267 // Obtener email del usuario desde SessionManager (si está disponible)
268 String userEmail = sessionManager.getUserEmail();
269
270 // Si no hay email disponible, mostrar error y no continuar
271 if (userEmail == null || userEmail.isEmpty() || userEmail.equals("usuario@example.com")) {
272 showLoading(false);
273 showErrorView(true, "Debes tener un email válido en tu perfil para realizar el pago. Inicia sesión nuevamente o completa tu perfil.");
274 Toast.makeText(requireContext(), "No se puede continuar sin email de usuario", Toast.LENGTH_LONG).show();
275 return;
276 }
277 // Mostrar mensaje de log para depuración
278 Log.d(TAG, "Iniciando proceso de pago con MercadoPago. Email: " + userEmail);
279 // Log extra: mostrar el token y el email que se enviarán
280 Log.d(TAG, "Token enviado: " + sessionManager.getToken());
281 // Log extra: mostrar el body que se enviará (en MercadoPagoService)
282 mercadoPagoService.createPreference(userEmail, new MercadoPagoService.MercadoPagoCallback() {
283 @Override
284 public void onSuccess(MercadoPagoPreference preference) {
285 Log.d(TAG, "Preferencia creada exitosamente: " + preference.getPreferenceId());
286 Log.d(TAG, "URL de pago: " + preference.getInitPoint());
287
288 if (preference.getInitPoint() == null || preference.getInitPoint().isEmpty()) {
289 requireActivity().runOnUiThread(new Runnable() {
290 @Override
291 public void run() {
292 showLoading(false);
293 showErrorView(true, "No se pudo obtener la URL de pago. Por favor, intenta nuevamente.");
294 }
295 });
296 return;
297 }
298
299 // Guardar el ID de la solicitud de pago
300 currentPaymentRequestId = preference.getPaymentRequestId();
301 // Guardar la URL de pago en SessionManager
302 sessionManager.saveLastInitPoint(preference.getInitPoint());
303 // Mostrar el WebView y cargar la URL de pago en la app
304 requireActivity().runOnUiThread(new Runnable() {
305 @Override
306 public void run() {
307 Toast.makeText(requireContext(), "Redirigiendo a MercadoPago...", Toast.LENGTH_SHORT).show();
308 Intent intent = new Intent(Intent.ACTION_VIEW, android.net.Uri.parse(preference.getInitPoint()));
309 startActivity(intent);
310 showWebView(false);
311 }
312 });
313 }
314
315 @Override
316 public void onError(String errorMessage) {
317 Log.e(TAG, "Error al crear preferencia: " + errorMessage);
318 requireActivity().runOnUiThread(new Runnable() {
319 @Override
320 public void run() {
321 showLoading(false);
322 // Mejorar feedback para errores de carrito vacío
323 if (errorMessage != null && (errorMessage.toLowerCase().contains("carrito") || errorMessage.toLowerCase().contains("empty") || errorMessage.toLowerCase().contains("vacío"))) {
324 showErrorView(true, "Tu carrito está vacío. Agrega productos antes de intentar pagar.");
325 } else if (errorMessage != null && (errorMessage.contains("500") || errorMessage.toLowerCase().contains("servidor"))) {
326 // Error 500 u otro error de servidor: ofrecer abrir en navegador
327 new AlertDialog.Builder(requireContext())
328 .setTitle("Error en el servidor de pagos")
329 .setMessage("Ocurrió un error al crear la preferencia de pago. ¿Quieres intentar abrir el pago en el navegador web?")
330 .setPositiveButton("Abrir en navegador", new DialogInterface.OnClickListener() {
331 @Override
332 public void onClick(DialogInterface dialog, int which) {
333 // Intentar abrir la URL de pago si está disponible
334 String lastInitPoint = (currentPaymentRequestId != null) ? sessionManager.getLastInitPoint() : null;
335 if (lastInitPoint != null && !lastInitPoint.isEmpty()) {
336 Intent browserIntent = new Intent(Intent.ACTION_VIEW, android.net.Uri.parse(lastInitPoint));
337 startActivity(browserIntent);
338 } else {
339 Toast.makeText(requireContext(), "No se pudo obtener la URL de pago.", Toast.LENGTH_LONG).show();
340 }
341 }
342 })
343 .setNegativeButton("Cancelar", null)
344 .show();
345 showErrorView(true, "Error al crear el pago: " + errorMessage);
346 } else {
347 showErrorView(true, "Error al crear el pago: " + errorMessage);
348 }
349 }
350 });
351 } });
352 }
353
354 private void handlePaymentSuccess() {
355 showWebView(false);
356 Log.d(TAG, "Pago exitoso! Redirigiendo a pantalla de confirmación");
357
358 // Confirmar el pedido en el backend usando el paymentRequestId
359 if (currentPaymentRequestId != null && !currentPaymentRequestId.isEmpty()) {
360 showLoading(true);
361 mercadoPagoService.confirmOrder(currentPaymentRequestId, new MercadoPagoService.OrderConfirmCallback() {
362 @Override
363 public void onSuccess(String orderId) {
364 showLoading(false);
365 // Mostrar un mensaje más informativo al usuario
366 AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
367 builder.setTitle("Pago Exitoso");
368 builder.setMessage("Tu pago ha sido procesado correctamente. ¡Gracias por tu compra!");
369 builder.setPositiveButton("Continuar", new DialogInterface.OnClickListener() {
370 @Override
371 public void onClick(DialogInterface dialog, int which) {
372 // Navegar al fragmento de éxito
373 navigateToSuccessFragment();
374 }
375 });
376 builder.setCancelable(false);
377 builder.show();
378 }
379
380 @Override
381 public void onError(String errorMessage) {
382 showLoading(false);
383 // Mostrar error de confirmación
384 AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
385 builder.setTitle("Error al confirmar pedido");
386 builder.setMessage("El pago fue exitoso, pero hubo un error al confirmar el pedido: " + errorMessage + "\nPor favor, contacta soporte si no recibes tu pedido.");
387 builder.setPositiveButton("Entendido", new DialogInterface.OnClickListener() {
388 @Override
389 public void onClick(DialogInterface dialog, int which) {
390 dialog.dismiss();
391 }
392 });
393 builder.setCancelable(true);
394 builder.show();
395 }
396 });
397 } else {
398 // Si no hay paymentRequestId, mostrar éxito pero advertir
399 AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
400 builder.setTitle("Pago Exitoso");
401 builder.setMessage("Tu pago ha sido procesado, pero no se pudo confirmar el pedido automáticamente. Si no recibes tu pedido, contacta soporte.");
402 builder.setPositiveButton("Continuar", new DialogInterface.OnClickListener() {
403 @Override
404 public void onClick(DialogInterface dialog, int which) {
405 navigateToSuccessFragment();
406 }
407 });
408 builder.setCancelable(false);
409 builder.show();
410 }
411 }
412
413 private void handlePaymentFailure() {
414 showWebView(false);
415
416 // Mostrar un diálogo con información clara sobre el fallo
417 AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
418 builder.setTitle("Pago no completado");
419 builder.setMessage("Lo sentimos, el pago no pudo ser procesado. Por favor, intenta con otro método de pago o contacta a tu entidad bancaria.");
420 builder.setPositiveButton("Entendido", new DialogInterface.OnClickListener() {
421 @Override
422 public void onClick(DialogInterface dialog, int which) {
423 dialog.dismiss();
424 }
425 });
426 builder.setNegativeButton("Reintentar", new DialogInterface.OnClickListener() {
427 @Override
428 public void onClick(DialogInterface dialog, int which) {
429 procesarPagoConMercadoPago();
430 }
431 });
432 builder.setCancelable(true);
433 builder.show();
434 }
435
436 private void handlePaymentPending() {
437 showWebView(false);
438
439 // Mostrar un diálogo con información clara sobre el estado pendiente
440 AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
441 builder.setTitle("Pago en Proceso");
442 builder.setMessage("Tu pago está siendo procesado. Puede tomar unos minutos. Recibirás una notificación cuando se complete.");
443 builder.setPositiveButton("Entendido", new DialogInterface.OnClickListener() {
444 @Override
445 public void onClick(DialogInterface dialog, int which) {
446 dialog.dismiss();
447 // Podríamos redirigir a una pantalla de estado pendiente aquí
448 }
449 });
450 builder.setCancelable(true); builder.show();
451 }
452
453 private void showLoading(boolean show) {
454 progressBar.setVisibility(show ? View.VISIBLE : View.GONE);
455 buttonPayNow.setEnabled(!show);
456 }
457
458 private void showWebViewProgress(boolean show) {
459 View progressBar = getView().findViewById(R.id.progressBarWebView);
460 if (progressBar != null) {
461 progressBar.setVisibility(show ? View.VISIBLE : View.GONE);
462 }
463 }
464
465 private void showWebView(boolean show) {
466 webViewLayout.setVisibility(show ? View.VISIBLE : View.GONE);
467 paymentLayout.setVisibility(show ? View.GONE : View.VISIBLE);
468 errorLayout.setVisibility(View.GONE);
469 showLoading(false);
470 }
471
472 private void showErrorView(boolean show, String errorMessage) {
473 if (show && errorMessage != null) {
474 textViewError.setText(errorMessage);
475 }
476 errorLayout.setVisibility(show ? View.VISIBLE : View.GONE);
477 webViewLayout.setVisibility(show ? View.GONE : webViewLayout.getVisibility());
478 paymentLayout.setVisibility(show ? View.GONE : paymentLayout.getVisibility());
479 }
480
481 private void verifyPaymentStatus(String paymentRequestId) {
482 Log.d(TAG, "URL de retorno de MercadoPago detectada");
483
484 // Como no estamos utilizando el endpoint de verificación de estado del backend,
485 // simplemente confiamos en la URL de retorno proporcionada por MercadoPago
486 // Si llegamos aquí desde una URL de éxito, asumimos que el pago se completó correctamente
487 handlePaymentSuccess();
488 }
489
490 private void navigateToSuccessFragment() {
491 // Determinar el método de pago seleccionado
492 String selectedPaymentMethod = "Efectivo"; // Valor por defecto
493
494 if (radioGroupPaymentMethod != null) {
495 int selectedId = radioGroupPaymentMethod.getCheckedRadioButtonId();
496 Log.d(TAG, "ID del radio button seleccionado: " + selectedId);
497
498 // Verificar si el RadioButton seleccionado es MercadoPago
499 if (selectedId == R.id.radioButton6) {
500 selectedPaymentMethod = "mercadopago";
501 Log.d(TAG, "Método de pago seleccionado: MercadoPago");
502 }
503 // Verificar si el RadioButton seleccionado es PayPal
504 else if (selectedId == R.id.radioButtonPaypal) {
505 selectedPaymentMethod = "paypal";
506 Log.d(TAG, "Método de pago seleccionado: PayPal");
507 }
508 // Verificar si el RadioButton seleccionado es Tarjeta de crédito
509 else if (selectedId == R.id.radioButton4) {
510 selectedPaymentMethod = "credit_card";
511 Log.d(TAG, "Método de pago seleccionado: Tarjeta de crédito");
512 } else {
513 Log.d(TAG, "No se detectó ningún método de pago específico, usando el valor por defecto: " + selectedPaymentMethod);
514 }
515 } else {
516 Log.e(TAG, "radioGroupPaymentMethod es nulo");
517 }
518
519 // Para confirmar el método de pago en otra parte del proceso
520 if (buttonPayNow != null && buttonPayNow.isEnabled()) {
521 if (radioButtonMercadoPago != null && radioButtonMercadoPago.isChecked()) {
522 selectedPaymentMethod = "mercadopago";
523 Log.d(TAG, "Método de pago confirmado por estado de RadioButton: MercadoPago");
524 } else if (radioButtonPaypal != null && radioButtonPaypal.isChecked()) {
525 selectedPaymentMethod = "paypal";
526 Log.d(TAG, "Método de pago confirmado por estado de RadioButton: PayPal");
527 } else if (radioButtonCreditCard != null && radioButtonCreditCard.isChecked()) {
528 selectedPaymentMethod = "credit_card";
529 Log.d(TAG, "Método de pago confirmado por estado de RadioButton: Tarjeta de crédito");
530 }
531 }
532
533 // Crear instancia del fragmento de éxito con el método de pago
534 SuccessFragment successFragment = SuccessFragment.newInstance(currentPaymentRequestId, selectedPaymentMethod);
535 Log.d(TAG, "Navegando al fragmento de éxito con método de pago: " + selectedPaymentMethod);
536
537 FragmentManager fragmentManager = getParentFragmentManager();
538 FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
539 // Añadir animación a la transición
540 fragmentTransaction.setCustomAnimations(
541 R.anim.slide_in_right,
542 R.anim.slide_out_left
543 );
544 fragmentTransaction.replace(R.id.fragment_container_view, successFragment);
545 fragmentTransaction.addToBackStack(null);
546 fragmentTransaction.commit();
547 }
548
553 private void startPageLoadingTimeout(final WebView webView, final String url) {
554 // Cancelar cualquier temporizador existente
555 cancelPageLoadingTimeout();
556
557 // Crear un nuevo temporizador
558 timeoutRunnable = new Runnable() {
559 @Override
560 public void run() {
561 // Si aún estamos mostrando el progreso, es que la página no ha terminado de cargar
562 if (webViewLayout.getVisibility() == View.VISIBLE &&
563 getView() != null &&
564 getView().findViewById(R.id.progressBarWebView).getVisibility() == View.VISIBLE) {
565
566 Log.e(TAG, "Timeout al cargar la página: " + url);
567
568 // Intentar detener la carga
569 webView.stopLoading();
570
571 // Mostrar un error al usuario
572 showErrorView(true, "La página de pago está tardando demasiado en cargar. " +
573 "Por favor, verifica tu conexión a Internet e intenta nuevamente.");
574 }
575 }
576 };
577
578 // Programar el temporizador
579 timeoutHandler.postDelayed(timeoutRunnable, PAGE_LOAD_TIMEOUT);
580 }
581
585 private void cancelPageLoadingTimeout() {
586 if (timeoutRunnable != null) {
587 timeoutHandler.removeCallbacks(timeoutRunnable);
588 timeoutRunnable = null;
589 }
590 } @Override
591 public void onStart() {
592 super.onStart();
593
594 // Iniciar el monitoreo de conexión
595 if (connectionMonitor != null) {
596 connectionMonitor.startMonitoring();
597 }
598 }
599
600 @Override
601 public void onStop() {
602 super.onStop();
603
604 // Limpiar recursos y cancelar temporizadores
605 cancelPageLoadingTimeout();
606
607 // Detener cualquier carga en progreso en el WebView
608 if (webViewPayment != null) {
609 webViewPayment.stopLoading();
610 }
611
612 // Detener el monitoreo de conexión
613 if (connectionMonitor != null) {
614 connectionMonitor.stopMonitoring();
615 }
616 }
617
618 @Override
619 public void onDestroyView() {
620 super.onDestroyView();
621
622 // Limpiar recursos del WebView
623 if (webViewPayment != null) {
624 webViewPayment.destroy();
625 }
626 }
627
628
629 @Override
630 public void onConnected() {
631 isNetworkAvailable = true;
632
633 // Solo actuamos si estamos en la vista de error y el error era de conexión
634 if (errorLayout != null && errorLayout.getVisibility() == View.VISIBLE &&
635 textViewError.getText().toString().contains("conexión")) {
636
637 requireActivity().runOnUiThread(new Runnable() {
638 @Override
639 public void run() {
640 Toast.makeText(requireContext(), "Conexión restablecida", Toast.LENGTH_SHORT).show();
641
642 // Si estábamos intentando cargar una página, reintentamos
643 if (currentPaymentRequestId != null) {
644 showErrorView(false, null);
645 procesarPagoConMercadoPago();
646 }
647 }
648 });
649 }
650 } @Override
651 public void onDisconnected() {
652 isNetworkAvailable = false;
653
654 // Si estamos cargando el WebView, mostramos el error
655 if (webViewLayout != null && webViewLayout.getVisibility() == View.VISIBLE) {
656 requireActivity().runOnUiThread(new Runnable() {
657 @Override
658 public void run() {
659 showWebViewProgress(false);
660 showErrorView(true, "Se ha perdido la conexión a Internet. Por favor, verifica tu conexión y reintenta.");
661 }
662 });
663 }
664 }
665
669 private void confirmarPedidoBackend() {
670 showLoading(true);
671 if (!NetworkUtils.isNetworkAvailable(requireContext())) {
672 showErrorView(true, "No hay conexión a Internet. Por favor, verifica tu conexión e intenta nuevamente.");
673 return;
674 }
675 String url = "https://backmobile1.onrender.com/appCART/confirmar/";
676 String token = sessionManager.getToken();
677 Log.d("PaymentFragment", "Token enviado en confirmarPedidoBackend: " + token);
678 if (token == null || token.isEmpty()) {
679 showLoading(false);
680 showErrorView(true, "Debes iniciar sesión para confirmar el pedido.");
681 return;
682 }
683 com.android.volley.RequestQueue queue = com.android.volley.toolbox.Volley.newRequestQueue(requireContext());
684 com.android.volley.toolbox.JsonObjectRequest request = new com.android.volley.toolbox.JsonObjectRequest(
685 com.android.volley.Request.Method.POST, url, null,
686 new com.android.volley.Response.Listener<org.json.JSONObject>() {
687 @Override
688 public void onResponse(org.json.JSONObject response) {
689 showLoading(false);
690 new android.app.AlertDialog.Builder(requireContext())
691 .setTitle("Pedido confirmado")
692 .setMessage("Tu pedido ha sido confirmado y el carrito se ha vaciado. ¡Gracias por tu compra!")
693 .setPositiveButton("Continuar", new android.content.DialogInterface.OnClickListener() {
694 @Override
695 public void onClick(android.content.DialogInterface dialog, int which) {
696 navigateToSuccessFragment();
697 }
698 })
699 .setCancelable(false)
700 .show();
701 }
702 },
703 new com.android.volley.Response.ErrorListener() {
704 @Override
705 public void onErrorResponse(com.android.volley.VolleyError error) {
706 showLoading(false);
707 String msg = "Error al confirmar el pedido";
708 if (error.networkResponse != null) {
709 msg += " (código: " + error.networkResponse.statusCode + ")";
710 }
711 showErrorView(true, msg);
712 }
713 }) {
714 @Override
715 public java.util.Map<String, String> getHeaders() {
716 java.util.Map<String, String> headers = new java.util.HashMap<>();
717 headers.put("Authorization", "Bearer " + token);
718 Log.d("PaymentFragment", "Header Authorization enviado: Bearer " + token);
719 return headers;
720 }
721 };
722 queue.add(request);
723 }
724}
View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
void confirmOrder(String paymentRequestId, OrderConfirmCallback callback)
static boolean isNetworkAvailable(Context context)