Files
pmu_android/app/src/main/java/com/example/quiz/BetValidation.java
2026-04-30 13:08:05 +02:00

895 lines
37 KiB
Java
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.example.quiz;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Bundle;
import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.GridLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.anggastudio.printama.Printama;
import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.MiseInitiale;
import com.example.quiz.data.model.Pari;
import com.example.quiz.data.model.PariMise;
import com.example.quiz.data.model.ParisResponse;
import com.example.quiz.data.model.TypeOfBet;
import com.example.quiz.data.model.dtos.NotifPayload;
import com.example.quiz.data.remote.StompManager;
import com.example.quiz.databinding.FragmentBetValidationBinding;
import com.example.quiz.utils.BluetoothUtils;
import com.example.quiz.utils.LoaderDialog;
import com.example.quiz.utils.MessageDialog;
import com.example.quiz.utils.Result;
import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.utils.SunmiPrinterManager;
import com.example.quiz.viewModel.LogsViewModel;
import com.example.quiz.viewModel.PariMiseViewModel;
import com.example.quiz.viewModel.PariViewModel;
import com.example.quiz.viewModel.SharedViewModel;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Observable;
import java.util.stream.Collectors;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link BetValidation#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class BetValidation extends Fragment {
FragmentBetValidationBinding binding;
SharedViewModel shared;
PariMiseViewModel pariMiseViewModel;
List<MiseInitiale> misesInitiales;
private AlertDialog dialog;
@Inject
StompManager stompManager;
SunmiPrinterManager sunmiPrinterManager;
private int nombreX;
LogsViewModel logsViewModel;
private boolean order;
private long mise;
String mobileName;
private TypeOfBet typeOfBet;
MutableLiveData<Boolean> isPrinterReady = new MutableLiveData<>(false);
SharedPrefsHelper prefsHelper;
private Course course;
LoaderDialog loader;
private int coeff;
private ActivityResultLauncher<Intent> enableBluetoothLauncher;
private final MutableLiveData<List<String>> selectedHorses = new MutableLiveData<>(List.of());
PariViewModel pariViewModel;
public BetValidation() {
// Required empty public constructor
}
public static BetValidation newInstance() {
BetValidation fragment = new BetValidation();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prefsHelper = SharedPrefsHelper.getInstance(getContext());
mobileName = Build.MANUFACTURER;
sunmiPrinterManager = SunmiPrinterManager.getInstance(requireContext());
if(mobileName.toLowerCase().contains("sunmi")){
sunmiPrinterManager.connectPrinter(status ->{
isPrinterReady.setValue(status);
});
}
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentBetValidationBinding.inflate(inflater, container, false);
loader = new LoaderDialog(getContext());
logsViewModel = new ViewModelProvider(this).get(LogsViewModel.class);
binding.coeff.setText(String.valueOf(1));
coeff = Integer.parseInt(binding.coeff.getText().toString());
binding.coeff.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (charSequence.toString().isEmpty()) {
binding.coeff.setError("Le coefficient est obligatoire");
return;
}
if (Integer.parseInt(charSequence.toString()) < 1) {
binding.coeff.setError("Le coefficient doit être supérieur ou égal à 1 ");
return;
}
coeff = Integer.parseInt(charSequence.toString());
calculateMise(selectedHorses.getValue());
}
@Override
public void afterTextChanged(Editable editable) {
}
});
return binding.getRoot();
}
private void setupNumberGrid(GridLayout grid) {
binding.gridNumbers.removeAllViews();
int columns = 8;
grid.setColumnCount(columns);
if (shared.selectedCourse.getValue() != null) {
for (int i = 1; i <= shared.selectedCourse.getValue().getNombrePartants(); i++) {
createNumberItem(String.valueOf(i));
grid.addView(createNumberItem(String.valueOf(i)));
}
}
createNumberItem("X");
grid.addView(createNumberItem("X"));
}
private TextView createNumberItem(String horse) {
TextView textView = new TextView(requireContext());
textView.setText(horse);
textView.setTextColor(getResources().getColor(R.color.white));
GridLayout.LayoutParams params = new GridLayout.LayoutParams();
params.setMargins(1, 1, 1, 1);
textView.setLayoutParams(params);
textView.setTextSize(10);
textView.setWidth(80);
textView.setHeight(100);
textView.setGravity(Gravity.CENTER);
textView.setBackgroundResource(Objects.equals(horse, "X") ? R.drawable.x_background : R.drawable.number_background);
if (!Objects.equals(horse, "X") && shared.selectedCourse.getValue().getNonPartants() != null && shared.selectedCourse.getValue().getNonPartants().contains(Integer.valueOf(horse))) {
textView.setTextColor(getResources().getColor(R.color.white));
textView.setBackgroundResource(R.drawable.number_background_grey);
}
textView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
textView.setOnClickListener(v -> {
if (!Objects.equals(horse, "X") && shared.selectedCourse.getValue().getNonPartants() != null && shared.selectedCourse.getValue().getNonPartants().contains(Integer.valueOf(horse))) {
Toast.makeText(getContext(), "Ce cheval n'est pas partant", Toast.LENGTH_SHORT).show();
return;
}
final List<String> horses = new ArrayList<>(selectedHorses.getValue());
if (horses.size() >= shared.typeOfBet.getValue().getNumberOfHorse() && horse.equals("X")) {
Toast.makeText(getContext(), "Vous ne pouvez plus sélectionner X", Toast.LENGTH_SHORT).show();
return;
}
if (_notClickable(horses) && horse.equals("X")) {
Toast.makeText(getContext(), "Vous ne pouvez plus sélectionner X", Toast.LENGTH_SHORT).show();
return;
}
if (horses.contains(horse) && !horse.equals("X")) {
horses.remove(horse);
selectedHorses.setValue(horses);
v.setSelected(false);
v.setBackgroundResource(R.drawable.number_background);
} else {
horses.add(horse);
selectedHorses.setValue(horses);
v.setSelected(true);
v.setBackgroundResource(R.drawable.number_selected_background);
}
String combinationText = selectedHorses.getValue().stream()
.map(h -> h)
.collect(Collectors.joining("-"));
binding.combination.setText(combinationText);
});
return textView;
}
boolean _notClickable(List<String> selectedHorses) {
int numberOfElement = 0;
if (shared.typeOfBet.getValue().getNumberOfHorse() < 2) {
return true;
}
for (String horse : selectedHorses) {
numberOfElement = horse.equals("X") ? numberOfElement + 1 : numberOfElement;
}
nombreX = numberOfElement;
return numberOfElement == shared.typeOfBet.getValue().getNumberOfHorse() - 1;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
shared = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
pariMiseViewModel = new ViewModelProvider(this).get(PariMiseViewModel.class);
pariMiseViewModel.getBetInitMise().observe(
getViewLifecycleOwner(),
result -> {
switch (result.status) {
case LOADING: {
loader.show("Chargement des mise");
break;
}
case SUCCESS: {
misesInitiales = result.data;
loader.dismiss();
break;
}
case ERROR: {
loader.dismiss();
MessageDialog.showError(getContext(), result.message);
}
default:
break;
}
}
);
if (shared.selectedCourse.getValue() != null) {
stompManager.subscribe("courses/" + shared.selectedCourse.getValue().getId(), json -> {
Type type = new TypeToken<NotifPayload<Course>>() {
}.getType();
NotifPayload<Course> notif = new Gson().fromJson(json, type);
Course updatedCourse = notif.getPayload();
if (shared.selectedCourse.getValue().getId() == updatedCourse.getId()) {
shared.setSelectedCourse(updatedCourse);
setupNumberGrid(binding.gridNumbers);
}
});
}
setSelectedTypeOfBetImage();
pariViewModel = new ViewModelProvider(this).get(PariViewModel.class);
typeOfBet = shared.typeOfBet.getValue();
course = shared.selectedCourse.getValue();
AppCompatActivity activity = (AppCompatActivity) getActivity();
if (activity != null) {
MaterialToolbar toolbar = activity.findViewById(R.id.toolbar);
toolbar.setBackgroundColor(getResources().getColor(R.color.primary_green));
activity.setSupportActionBar(toolbar);
if (activity.getSupportActionBar() != null) {
activity.getSupportActionBar().setTitle("Pari " + shared.selectedCourse.getValue().getNom());
}
}
setupNumberGrid(binding.gridNumbers);
binding.paymentType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String selected = binding.paymentType.getSelectedItem().toString();
if (selected.equals("Orange Money")) {
binding.phoneNumber.setVisibility(View.VISIBLE);
} else {
binding.phoneNumber.setVisibility(View.GONE); // ou GONE
binding.phoneNumber.setText(""); // vider le champ si non utilisé
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
binding.phoneNumber.setVisibility(View.INVISIBLE);
}
});
selectedHorses.observe(getViewLifecycleOwner(), new Observer<List<String>>() {
@Override
public void onChanged(List<String> horses) {
calculateMise(horses);
if (shared.typeOfBet.getValue().getNumberOfHorse() > 2 && horses.size() >= shared.typeOfBet.getValue().getNumberOfHorse()) {
binding.order.setVisibility(View.VISIBLE);
} else {
binding.order.setVisibility(View.GONE);
}
if (horses.contains("X")) {
if (selectedHorses.getValue().size() == shared.typeOfBet.getValue().getNumberOfHorse()) {
binding.elargie.setVisibility(View.VISIBLE);
binding.elargie.setText("Champ total");
return;
} else {
if (selectedHorses.getValue().size() > shared.typeOfBet.getValue().getNumberOfHorse()) {
binding.elargie.setVisibility(View.VISIBLE);
binding.elargie.setText("Champ partiel");
return;
}
}
}
if (horses.size() > shared.typeOfBet.getValue().getNumberOfHorse()) {
binding.elargie.setVisibility(View.VISIBLE);
binding.elargie.setText("Elargi");
} else {
binding.elargie.setVisibility(View.GONE);
}
}
});
binding.order.setOnCheckedChangeListener((buttonView, isChecked) -> {
order = isChecked;
calculateMise(selectedHorses.getValue());
});
binding.betValidateBtn.setOnClickListener(v -> {
if (binding.paymentType.getSelectedItem().toString().equals("Orange Money") && binding.phoneNumber.getText().toString().isEmpty()) {
MessageDialog.showError(getContext(), "Veuillez saisir le numéro de téléphone");
return;
}
if (shared.typeOfBet == null || shared.selectedCourse == null) {
return;
}
int required = typeOfBet.getNumberOfHorse();
if (Objects.requireNonNull(selectedHorses.getValue()).size() < required) {
Toast.makeText(getContext(), "Veuillez sélectionner au moins" + required + " chevaux", Toast.LENGTH_SHORT).show();
return;
}
if (this.mise == 0) {
Toast.makeText(getContext(), "Pari non valide", Toast.LENGTH_SHORT).show();
return;
}
Pari pari = new Pari(
OffsetDateTime.now(ZoneOffset.UTC).toString(),
Long.valueOf(course.getId()),
Long.valueOf(prefsHelper.get("id")),
Long.valueOf(prefsHelper.get("terminalId")),
Long.valueOf(prefsHelper.get("pointDeVenteId")),
List.of(new PariMise(String.valueOf(shared.typeOfBet.getValue().getName()), mise)),
_getFormule(),
_getCombinaison(),
coeff,
"XOF",
"Pari"
);
if (dialog != null && dialog.isShowing()) {
return;
}
_showPariDialog(pari);
});
binding.backBtn.setOnClickListener(v -> {
getActivity().onBackPressed();
});
binding.deleteBtn.setOnClickListener(v -> {
_initializeToZero();
});
}
String _getCombinaison() {
if (selectedHorses.getValue().contains("X") && shared.typeOfBet.getValue().getNumberOfHorse() < selectedHorses.getValue().size()) {
String first = selectedHorses.getValue().subList(0, shared.typeOfBet.getValue().getNumberOfHorse()).stream()
.map(String::valueOf)
.collect(Collectors.joining(","));
String last = selectedHorses.getValue().subList(shared.typeOfBet.getValue().getNumberOfHorse(), selectedHorses.getValue().size()).stream()
.map(String::valueOf)
.collect(Collectors.joining(","));
return first + ",R," + last;
} else {
return selectedHorses.getValue().stream().map(String::valueOf).collect(Collectors.joining(","));
}
}
List<String> _getFormule() {
List<String> combinaison = selectedHorses.getValue();
if (!combinaison.contains("X")) {
if (!order) {
return List.of("UNITAIRE");
} else {
return List.of("FORMULE_COMPLETE");
}
} else {
if (shared.typeOfBet.getValue().getNumberOfHorse() < selectedHorses.getValue().size()) {
if (order) {
return List.of("CHAMP_X", "FORMULE_COMPLETE");
} else {
return List.of("CHAMP_X");
}
} else {
if (order) {
return List.of("CHAMP_TOTAL", "FORMULE_COMPLETE");
} else {
return List.of("CHAMP_TOTAL");
}
}
}
}
private void setSelectedTypeOfBetImage() {
switch (shared.typeOfBet.getValue().getName()) {
case COUPLE_PLACE:
binding.icTypeOfBet.setImageResource(R.drawable.ic_couple_place);
break;
case COUPLE_GAGNANT:
binding.icTypeOfBet.setImageResource(R.drawable.ic_couple_gagnant);
break;
case TIERCE:
binding.icTypeOfBet.setImageResource(R.drawable.ic_tierce);
break;
case QUARTE:
binding.icTypeOfBet.setImageResource(R.drawable.ic_quarte);
break;
case QUINTE:
binding.icTypeOfBet.setImageResource(R.drawable.ic_quinte_plus);
break;
}
}
public void printPari(ParisResponse pari) throws WriterException {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pmu_logo);
Bitmap barcode = generateBarcodeBitmap(pari.getNumeroTicket(), 384, 100);
StringBuilder tspl = new StringBuilder();
tspl.append("Bamako").append("\n");
tspl.append(shared.selectedCourse.getValue().getNom()).append("\n");
OffsetDateTime dateTime = OffsetDateTime.parse(shared.selectedCourse.getValue().getHeureDepartPrevue());
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
String formattedDate = dateTime.format(formatter);
tspl.append(formattedDate).append("\n");
tspl.append("Course ").append(String.valueOf(shared.selectedCourse.getValue().getId())).append("\n");
tspl.append(sunmiPrinterManager.separationText()+ "\n");
boolean isElargie = selectedHorses.getValue().size() > shared.typeOfBet.getValue().getNumberOfHorse();
String typePari = pari.getTypesParisMises().get(0).getTypePari();
tspl.append(isElargie ? typePari + "/Elargie" : typePari).append("\n");
tspl.append(order ? "COMBINAISON COMPLETE" + "\n" : "");
String combinationText = formatLineWithNumbers(selectedHorses.getValue().stream().map(String::valueOf).toArray(String[]::new), "-") ;
tspl.append(combinationText).append("\n");
tspl.append("COEF: ").append(String.valueOf(coeff)).append(".0");
tspl.append("\n").append(sunmiPrinterManager.separationText()).append("\n");
tspl.append("MONTANT: ").append(pari.getTypesParisMises().get(0).getMiseTotale()).append(" XOF");
tspl.append("\n").append(sunmiPrinterManager.separationText()).append("\n");
tspl.append("AGENT: ").append(prefsHelper.get("code")).append("\n");
tspl.append("DATE: ").append(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss").format(LocalDateTime.now())).append("\n");
if(mobileName.toLowerCase().contains("sunmi")){
String pariText = tspl.toString();
if(!sunmiPrinterManager.printPari(resizeToPrinterWidth(bitmap, 384), barcode, pari.getNumeroTicket(), pariText)){
MessageDialog.showError(getContext(), "Erreur d'impression");
prefsHelper.save("noPrintId", String.valueOf(pari.getId()));
return;
};
_initializeToZero();
return;
}
try {
if (BluetoothUtils.needsBluetoothPermissions()) {
if (!BluetoothUtils.hasBluetoothPermission(requireContext())) {
// Demande la permission si non accordée
BluetoothUtils.requestBluetoothPermission(requireActivity());
return; // arrête ici, la popup va apparaître
}
}
// 2⃣ Permission OK, on peut afficher la liste
Printama.with(getContext()).printTextBuilder(tspl, bitmap, pari.getNumeroTicket(), barcode, new Printama.PrintCallback() {
@Override
public void onResult(boolean success, String errorMessage) {
if (!success) {
new android.app.AlertDialog.Builder(getContext())
.setTitle("Impréssion pari")
.setMessage("Voulez-vous rééimprimer ce ticket?")
.setPositiveButton("Oui", (dialog, which) -> {
try {
printPari(pari);
} catch (WriterException e) {
throw new RuntimeException(e);
}
})
.setNegativeButton("Non", (dialog, which) -> {
dialog.dismiss();
});
} else {
_initializeToZero();
}
}
});
} catch (SecurityException e) {
Toast.makeText(requireContext(),
"Permission Bluetooth non accordée", Toast.LENGTH_SHORT).show();
}
}
public String formatLineWithNumbers(String[] numbers, String separator) {
StringBuilder currentLine = new StringBuilder();
StringBuilder finalOutput = new StringBuilder();
List<String> formatted = new ArrayList<>();
int requiredHorse = shared.typeOfBet.getValue().getNumberOfHorse();
if(Arrays.stream(numbers).map(String::valueOf).collect(Collectors.toList()).contains("X")){
if(numbers.length <= requiredHorse){
return Arrays.stream(numbers).map(String::valueOf).collect(Collectors.joining("-")).toString();
}
List<String> firstPart = Arrays.stream(numbers).limit(requiredHorse).map(String::valueOf).collect(Collectors.toList());
List<String> secondPart = Arrays.stream(numbers).skip(requiredHorse).map(String::valueOf).collect(Collectors.toList());
formatted.addAll(firstPart);
formatted.add("R");
formatted.addAll(secondPart);
}else{
formatted = Arrays.stream(numbers).map(String::valueOf).collect(Collectors.toList());
}
for (String number : formatted) {
String element = (currentLine.length() == 0 ? "":separator) + number;
// Si l'ajout dépasse la largeur max, on termine la ligne et on recommence
if (currentLine.length() + element.length() > sunmiPrinterManager.getMaxChar()) {
finalOutput.append(currentLine.toString()).append("\n");
currentLine = new StringBuilder(number);
} else {
currentLine.append(element);
}
}
if (currentLine.length() > 0) {
finalOutput.append(currentLine.toString());
}
return finalOutput.toString();
}
@SuppressLint({"MissingInflatedId", "SetTextI18n"})
void _showPariDialog(Pari pari) {
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.pari_confirmation, null);
TextView numero_course = (TextView) view.findViewById(R.id.alert_course_numero);
numero_course.setText("Numero Course: " + String.valueOf(shared.selectedCourse.getValue().getId()));
TextView alert_pari_type = (TextView) view.findViewById(R.id.alert_pari_type);
alert_pari_type.setText(String.valueOf(shared.typeOfBet.getValue().getName()));
TextView is_elargie = (TextView) view.findViewById(R.id.alert_is_elargie);
is_elargie.setText(selectedHorses.getValue().size() > shared.typeOfBet.getValue().getNumberOfHorse() ? "CE" : "SI");
TextView alert_combinaison = (TextView) view.findViewById(R.id.alert_combinaison);
alert_combinaison.setText(selectedHorses.getValue().stream()
.map(String::valueOf)
.collect(Collectors.joining("-")));
TextView aler_coeff = (TextView) view.findViewById(R.id.alert_coeff);
aler_coeff.setText("Coef:" + String.valueOf(coeff));
TextView alert_montant = (TextView) view.findViewById(R.id.alert_montant);
alert_montant.setText("Montant: " + String.valueOf(pari.getTypesParisMises().get(0).getMiseTotale()) + " CFA");
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setView(view);
builder.setCancelable(false);
dialog = builder.create();
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
view.findViewById(R.id.alert_validate).setOnClickListener(v -> {
if(mobileName.toLowerCase().contains("sunmi")){
if(isPrinterReady.getValue() != null && !isPrinterReady.getValue()){
sunmiPrinterManager.connectPrinter(status ->{
isPrinterReady.setValue(status);
});
}
switch (sunmiPrinterManager.printerStatus()){
case 2:{
MessageDialog.showError(getContext(), "L'imprimante n'est pas connectée!");
return;
}
case 3:{
MessageDialog.showError(getContext(), "L'imprimante n'est pas disponible!");
return;
}
case 4:{
MessageDialog.showError(getContext(), "Veuillez insérer du papier dans l'imprimante, SVP!");
return;
}
case 5: {
MessageDialog.showError(getContext(), "Suchauffe iminante de l'imprimante, Veuillez laisser reposer!");
return;
}
case 6: {
MessageDialog.showError(getContext(), "Le capot est ouvert, veuillez fermer SVP!");
return;
}
}
}
pariViewModel.createPari(pari).observe(getViewLifecycleOwner(), new Observer<Result<ParisResponse>>() {
@Override
public void onChanged(Result<ParisResponse> pariResult) {
switch (pariResult.status) {
case ERROR:
loader.dismiss();
dialog.dismiss();
MessageDialog.showError(getContext(), pariResult.message);
break;
case LOADING:
loader.show("Prise de pari");
break;
case SUCCESS:
try {
loader.dismiss();
logsViewModel.insertLog(prefsHelper.get("id"), "BET", "Création du pari " + pariResult.data.getNumeroTicket() + ", type de paris: " + pariResult.data.getTypesParisMises().get(0).getTypePari() + ", combinaison:" + selectedHorses.getValue().stream().map(String::valueOf).collect(Collectors.joining("-")), System.currentTimeMillis());
printPari(pariResult.data);
dialog.dismiss();
MessageDialog.showSuccess(getContext(), "Pari créé avec succès");
} catch (WriterException e) {
loader.dismiss();
MessageDialog.showError(getContext(), e.getMessage());
throw new RuntimeException(e);
}
break;
}
}
});
});
view.findViewById(R.id.alert_cancel).setOnClickListener(v -> {
dialog.dismiss();
});
dialog.show();
}
void _initializeToZero() {
selectedHorses.setValue(List.of());
binding.combination.setText("");
binding.order.setChecked(false);
order = false;
binding.order.setVisibility(View.GONE);
binding.coeff.setText("1");
coeff = Integer.parseInt(binding.coeff.getText().toString());
setupNumberGrid(binding.gridNumbers);
}
public void calculateMise(List<String> selectedHorses) {
_notClickable(selectedHorses);
int nombreChevauxSelectionnes = selectedHorses.size();
long mise = 0;
int nonPartants = 0;
if (shared.typeOfBet.getValue() == null || shared.selectedCourse.getValue() == null) {
return;
}
if (shared.selectedCourse.getValue().getNonPartants() != null) {
nonPartants = shared.selectedCourse.getValue().getNonPartants().size();
}
int typeOfBetHorses = shared.typeOfBet.getValue().getNumberOfHorse();
int partants = shared.selectedCourse.getValue().getNombrePartants();
Course.TypeParis courseName = shared.typeOfBet.getValue().getName();
if (shared.typeOfBet.getValue().getNumberOfHorse() > nombreChevauxSelectionnes) {
binding.mise.setText(mise + " CFA");
return;
}
MiseInitiale miseModel = misesInitiales.stream()
.filter(miseInitiale -> miseInitiale.getTypePari().equals(courseName))
.findFirst()
.orElse(null);
if (miseModel == null) {
MessageDialog.showError(getContext(), "Erreur lors de l'initialisation de la mise");
_initializeToZero();
return;
}
mise = miseModel.getMiseInitialeMin();
Course.TypeParis typePari = shared.typeOfBet.getValue().getName();
boolean estCoupleGagnantOuPlace = typePari.equals(Course.TypeParis.COUPLE_GAGNANT) || typePari.equals(Course.TypeParis.COUPLE_PLACE);
Log.d("TYPE_PARI", typePari.toString());
if (estCoupleGagnantOuPlace) {
// Pour COUPLE_GAGNANT ou COUPLE_PLACE: coefficient < 200
if (coeff > 200) {
// Erreur: coefficient trop élevé
MessageDialog.showError(getContext(), "Le coefficient doit être au plus 200 pour " + typePari.toString());
_initializeToZero();
return;
}
} else {
// Pour les autres types: coefficient <= 20
if (coeff > 20) {
// Erreur: coefficient trop élevé
MessageDialog.showError(getContext(), "Le coefficient doit être inférieur ou égal à 20 pour " + typePari.toString());
_initializeToZero();
return;
}
}
mise = mise * coeff;
if (nombreX > 0) {
if (nombreChevauxSelectionnes == typeOfBetHorses) {
mise = mise * _calculateArrangement((partants - (typeOfBetHorses - nombreX) - nonPartants), nombreX);
} else {
if (nombreChevauxSelectionnes - typeOfBetHorses < nombreX || nombreChevauxSelectionnes - typeOfBetHorses == 1) {
mise = 0;
this.mise = mise;
binding.mise.setText(mise + " CFA");
return;
}
mise = mise * _calculateArrangement(nombreChevauxSelectionnes - typeOfBetHorses, nombreX);
}
if (order) {
mise = mise * _calculateArrangement(typeOfBetHorses, (typeOfBetHorses - nombreX));
}
this.mise = mise;
binding.mise.setText(mise + " CFA");
return;
}
if (!order) {
mise = mise * _calculateCombinaison(nombreChevauxSelectionnes, typeOfBetHorses);
} else {
mise = mise * _calculateArrangement(nombreChevauxSelectionnes, typeOfBetHorses);
}
this.mise = mise;
binding.mise.setText(mise + " CFA");
}
Long _calculateArrangement(int n, int k) {
return _calculateFactorial(n) / _calculateFactorial(n - k);
}
Long _calculateCombinaison(int n, int k) {
return _calculateFactorial(n) / (_calculateFactorial(k) * _calculateFactorial(n - k));
}
Long _calculateFactorial(int n) {
long f = 1;
if (n == 0) {
return f;
}
for (int i = 1; i <= n; i++) {
f *= i;
}
return f;
}
private Bitmap resizeToPrinterWidth(Bitmap originalBitmap, int printerWidthPx) {
int originalWidth = originalBitmap.getWidth();
int originalHeight = originalBitmap.getHeight();
int newHeight = (originalHeight * printerWidthPx) / originalWidth;
// 1. Redimensionner sans filtre (conserve les contours nets)
Bitmap scaledBitmap = Bitmap.createScaledBitmap(originalBitmap,
printerWidthPx,
newHeight,
false);
// 2. Créer un bitmap ARGB_8888 (meilleure qualité que RGB_565)
Bitmap result = Bitmap.createBitmap(printerWidthPx, newHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
canvas.drawColor(Color.WHITE);
// 3. Dessiner avec un Paint qui préserve les couleurs
Paint paint = new Paint();
paint.setAntiAlias(false); // Pas d'anti-aliasing (évite le flou)
canvas.drawBitmap(scaledBitmap, 0, 0, paint);
// 4. Seuillage intelligent pour garder les détails
for (int x = 0; x < result.getWidth(); x++) {
for (int y = 0; y < result.getHeight(); y++) {
int pixel = result.getPixel(x, y);
int r = Color.red(pixel);
int g = Color.green(pixel);
int b = Color.blue(pixel);
// Calculer la luminosité
int gray = (r + g + b) / 3;
// Seuil adaptatif : si c'est sombre, deviens noir
if (gray < 130) { // Seuil à 200 pour garder les gris clairs
result.setPixel(x, y, Color.BLACK);
} else {
result.setPixel(x, y, Color.WHITE);
}
}
}
return result;
}
public Bitmap generateBarcodeBitmap(String contents, int width, int height) throws WriterException {
BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.CODE_128, width, height);
Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
bmp.setPixel(x, y, bitMatrix.get(x, y) ? android.graphics.Color.BLACK : android.graphics.Color.WHITE);
}
}
return bmp;
}
public static String generate12Digits() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 8; i++) {
int digit = (int) (Math.random() * 10); // 0 à 9
sb.append(digit);
}
return sb.toString();
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
@Override
public void onDestroy() {
super.onDestroy();
stompManager.disconnect();
}
}