ticket fomattage

This commit is contained in:
OnlyPapy98
2026-04-30 13:08:05 +02:00
parent c0e5072523
commit 4ef19bd4e8
45 changed files with 2492 additions and 449 deletions

View File

@@ -1,14 +1,19 @@
package com.example.quiz;
import android.Manifest;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.app.Dialog;
import android.content.Intent;
import android.content.pm.PackageManager;
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;
@@ -16,10 +21,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
@@ -42,11 +44,9 @@ 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.Reunion;
import com.example.quiz.data.model.TypeOfBet;
import com.example.quiz.data.model.dtos.NotifPayload;
import com.example.quiz.data.model.dtos.PariCourseDto;
import com.example.quiz.data.model.enums.PariStatut;
import com.example.quiz.data.remote.StompManager;
import com.example.quiz.databinding.FragmentBetValidationBinding;
import com.example.quiz.utils.BluetoothUtils;
@@ -54,6 +54,7 @@ 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;
@@ -67,15 +68,17 @@ import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import java.lang.reflect.Type;
import java.time.LocalDate;
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.Map;
import java.util.Objects;
import java.util.Observable;
import java.util.stream.Collectors;
import javax.inject.Inject;
@@ -93,8 +96,10 @@ public class BetValidation extends Fragment {
FragmentBetValidationBinding binding;
SharedViewModel shared;
PariMiseViewModel pariMiseViewModel;
List<MiseInitiale> misesInitiales;
@@ -104,6 +109,8 @@ public class BetValidation extends Fragment {
@Inject
StompManager stompManager;
SunmiPrinterManager sunmiPrinterManager;
private int nombreX;
LogsViewModel logsViewModel;
@@ -113,16 +120,20 @@ public class BetValidation extends Fragment {
private long mise;
String mobileName;
private TypeOfBet typeOfBet;
MutableLiveData<Boolean> isPrinterReady = new MutableLiveData<>(false);
SharedPrefsHelper prefsHelper;
private Course course;
LoaderDialog loader;
LoaderDialog loader;
private int coeff;
@@ -135,12 +146,11 @@ public class BetValidation extends Fragment {
PariViewModel pariViewModel;
public BetValidation() {
// Required empty public constructor
}
public static BetValidation newInstance() {
public static BetValidation newInstance() {
BetValidation fragment = new BetValidation();
Bundle args = new Bundle();
fragment.setArguments(args);
@@ -151,8 +161,16 @@ public class BetValidation extends Fragment {
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) {
@@ -161,7 +179,7 @@ public class BetValidation extends Fragment {
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(){
binding.coeff.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
@@ -169,11 +187,11 @@ public class BetValidation extends Fragment {
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if(charSequence.toString().isEmpty()){
if (charSequence.toString().isEmpty()) {
binding.coeff.setError("Le coefficient est obligatoire");
return;
}
if(Integer.parseInt(charSequence.toString())<1){
if (Integer.parseInt(charSequence.toString()) < 1) {
binding.coeff.setError("Le coefficient doit être supérieur ou égal à 1 ");
return;
}
@@ -194,7 +212,7 @@ public class BetValidation extends Fragment {
binding.gridNumbers.removeAllViews();
int columns = 8;
grid.setColumnCount(columns);
if(shared.selectedCourse.getValue() != null){
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)));
@@ -203,7 +221,6 @@ public class BetValidation extends Fragment {
createNumberItem("X");
grid.addView(createNumberItem("X"));
}
private TextView createNumberItem(String horse) {
TextView textView = new TextView(requireContext());
textView.setText(horse);
@@ -215,53 +232,53 @@ public class BetValidation extends Fragment {
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.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))){
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);
});
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){
boolean _notClickable(List<String> selectedHorses) {
int numberOfElement = 0;
if(shared.typeOfBet.getValue().getNumberOfHorse() < 2){
if (shared.typeOfBet.getValue().getNumberOfHorse() < 2) {
return true;
}
for(String horse: selectedHorses){
numberOfElement = horse.equals("X")?numberOfElement+1:numberOfElement;
for (String horse : selectedHorses) {
numberOfElement = horse.equals("X") ? numberOfElement + 1 : numberOfElement;
}
nombreX = numberOfElement;
return numberOfElement == shared.typeOfBet.getValue().getNumberOfHorse() - 1;
@@ -274,8 +291,8 @@ public class BetValidation extends Fragment {
pariMiseViewModel = new ViewModelProvider(this).get(PariMiseViewModel.class);
pariMiseViewModel.getBetInitMise().observe(
getViewLifecycleOwner(),
result->{
switch (result.status){
result -> {
switch (result.status) {
case LOADING: {
loader.show("Chargement des mise");
break;
@@ -294,12 +311,13 @@ public class BetValidation extends Fragment {
}
}
);
if(shared.selectedCourse.getValue() != null){
stompManager.subscribe("courses/"+shared.selectedCourse.getValue().getId(), json->{
Type type = new TypeToken<NotifPayload<Course>>(){}.getType();
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()){
if (shared.selectedCourse.getValue().getId() == updatedCourse.getId()) {
shared.setSelectedCourse(updatedCourse);
setupNumberGrid(binding.gridNumbers);
}
@@ -310,12 +328,12 @@ public class BetValidation extends Fragment {
typeOfBet = shared.typeOfBet.getValue();
course = shared.selectedCourse.getValue();
AppCompatActivity activity = (AppCompatActivity) getActivity();
if(activity != null){
if (activity != null) {
MaterialToolbar toolbar = activity.findViewById(R.id.toolbar);
toolbar.setBackgroundColor( getResources().getColor(R.color.primary_green));
toolbar.setBackgroundColor(getResources().getColor(R.color.primary_green));
activity.setSupportActionBar(toolbar);
if(activity.getSupportActionBar() != null){
activity.getSupportActionBar().setTitle("Pari "+shared.selectedCourse.getValue().getNom());
if (activity.getSupportActionBar() != null) {
activity.getSupportActionBar().setTitle("Pari " + shared.selectedCourse.getValue().getNom());
}
}
setupNumberGrid(binding.gridNumbers);
@@ -342,28 +360,28 @@ public class BetValidation extends Fragment {
@Override
public void onChanged(List<String> horses) {
calculateMise(horses);
if(shared.typeOfBet.getValue().getNumberOfHorse() > 2 && horses.size() >= shared.typeOfBet.getValue().getNumberOfHorse()){
if (shared.typeOfBet.getValue().getNumberOfHorse() > 2 && horses.size() >= shared.typeOfBet.getValue().getNumberOfHorse()) {
binding.order.setVisibility(View.VISIBLE);
}else{
} else {
binding.order.setVisibility(View.GONE);
}
if(horses.contains("X")){
if(selectedHorses.getValue().size() == shared.typeOfBet.getValue().getNumberOfHorse()){
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()){
} 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()){
if (horses.size() > shared.typeOfBet.getValue().getNumberOfHorse()) {
binding.elargie.setVisibility(View.VISIBLE);
binding.elargie.setText("Elargi");
}else{
} else {
binding.elargie.setVisibility(View.GONE);
}
}
@@ -373,48 +391,24 @@ public class BetValidation extends Fragment {
calculateMise(selectedHorses.getValue());
});
binding.betValidateBtn.setOnClickListener(v->{
// Log.d("PAPER_STATUS", String.valueOf(ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.BLUETOOTH_CONNECT))+" "+String.valueOf(PackageManager.PERMISSION_GRANTED));
// if (ActivityCompat.checkSelfPermission(getContext(), android.Manifest.permission.BLUETOOTH_CONNECT)
// != PackageManager.PERMISSION_GRANTED) {
// // TODO: Consider calling
// // ActivityCompat#requestPermissions
// // here to request the missing permissions, and then overriding
// // public void onRequestPermissionsResult(int requestCode, String[] permissions,
// // int[] grantResults)
// // to handle the case where the user grants the permission. See the documentation
// // for ActivityCompat#requestPermissions for more details.
// return;
// }
// int paperStatus = Printama.with(getContext()).checkPaperStatus();
// switch (paperStatus){
// case 2 :{
// MessageDialog.showError(getContext(), "Le papier d'impression est vide");
// return;
// }
// case 1:{
// MessageDialog.showError(getContext(), "Le papier d'impression est presque vide");
// break;
// }
// }
if(binding.paymentType.getSelectedItem().toString().equals("Orange Money") && binding.phoneNumber.getText().toString().isEmpty()){
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){
if (shared.typeOfBet == null || shared.selectedCourse == null) {
return;
}
int required = typeOfBet.getNumberOfHorse();
if(selectedHorses.getValue().size() < required){
Toast.makeText(getContext(), "Veuillez sélectionner au moins"+required+" chevaux", Toast.LENGTH_SHORT).show();
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){
if (this.mise == 0) {
Toast.makeText(getContext(), "Pari non valide", Toast.LENGTH_SHORT).show();
return;
}
@@ -432,61 +426,63 @@ public class BetValidation extends Fragment {
"XOF",
"Pari"
);
if (dialog != null && dialog.isShowing()) {
return;
}
_showPariDialog(pari);
});
binding.backBtn.setOnClickListener(v->{
binding.backBtn.setOnClickListener(v -> {
getActivity().onBackPressed();
});
binding.deleteBtn.setOnClickListener(v->{
binding.deleteBtn.setOnClickListener(v -> {
_initializeToZero();
});
}
String _getCombinaison(){
if(selectedHorses.getValue().contains("X") && shared.typeOfBet.getValue().getNumberOfHorse() < selectedHorses.getValue().size()){
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 first + ",R," + last;
} else {
return selectedHorses.getValue().stream().map(String::valueOf).collect(Collectors.joining(","));
}
}
List<String> _getFormule(){
List<String> _getFormule() {
List<String> combinaison = selectedHorses.getValue();
if(!combinaison.contains("X")){
if(!order){
return List.of("UNITAIRE");
}else{
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){
} else {
if (shared.typeOfBet.getValue().getNumberOfHorse() < selectedHorses.getValue().size()) {
if (order) {
return List.of("CHAMP_X", "FORMULE_COMPLETE");
}else{
} else {
return List.of("CHAMP_X");
}
}else{
if(order){
} else {
if (order) {
return List.of("CHAMP_TOTAL", "FORMULE_COMPLETE");
}else{
} else {
return List.of("CHAMP_TOTAL");
}
}
}
}
private void setSelectedTypeOfBetImage(){
switch (shared.typeOfBet.getValue().getName()){
private void setSelectedTypeOfBetImage() {
switch (shared.typeOfBet.getValue().getName()) {
case COUPLE_PLACE:
binding.icTypeOfBet.setImageResource(R.drawable.ic_couple_place);
break;
@@ -506,34 +502,41 @@ public class BetValidation extends Fragment {
}
public void printPari(ParisResponse pari) throws WriterException {
try {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pmu_logo);
Bitmap barcode = generateBarcodeBitmap(pari.getNumeroTicket(), 384, 100);
StringBuilder tspl = new StringBuilder();
Printama printama = Printama.with(getContext());
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;
}
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(printama.lineSeparator()+"\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 = selectedHorses.getValue().stream()
.map(String::valueOf)
.collect(Collectors.joining("-"));
tspl.append(combinationText).append("\n");
tspl.append("COEF: ").append(String.valueOf(coeff)).append(".0");
tspl.append("\n").append(printama.lineSeparator()).append("\n");
tspl.append("MONTANT: ").append(pari.getTypesParisMises().get(0).getMiseTotale()).append(" XOF");
tspl.append("\n").append(printama.lineSeparator()).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");
try {
if (BluetoothUtils.needsBluetoothPermissions()) {
if (!BluetoothUtils.hasBluetoothPermission(requireContext())) {
// Demande la permission si non accordée
@@ -544,8 +547,28 @@ public class BetValidation extends Fragment {
// 2⃣ Permission OK, on peut afficher la liste
Printama.with(getContext()).printTextBuilder(tspl, bitmap, pari.getNumeroTicket(), barcode);
_initializeToZero();
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();
@@ -553,36 +576,103 @@ public class BetValidation extends Fragment {
}
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){
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()));
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");
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));
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");
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->{
pariViewModel.createPari(pari).observe(getViewLifecycleOwner(),new Observer<Result<ParisResponse>>() {
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){
switch (pariResult.status) {
case ERROR:
loader.dismiss();
dialog.dismiss();
@@ -594,7 +684,7 @@ public class BetValidation extends Fragment {
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());
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");
@@ -614,7 +704,7 @@ public class BetValidation extends Fragment {
dialog.show();
}
void _initializeToZero(){
void _initializeToZero() {
selectedHorses.setValue(List.of());
binding.combination.setText("");
binding.order.setChecked(false);
@@ -625,29 +715,29 @@ public class BetValidation extends Fragment {
setupNumberGrid(binding.gridNumbers);
}
public void calculateMise(List<String> selectedHorses){
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){
if (shared.typeOfBet.getValue() == null || shared.selectedCourse.getValue() == null) {
return;
}
if(shared.selectedCourse.getValue().getNonPartants() != null){
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");
if (shared.typeOfBet.getValue().getNumberOfHorse() > nombreChevauxSelectionnes) {
binding.mise.setText(mise + " CFA");
return;
}
MiseInitiale miseModel = misesInitiales.stream()
.filter(miseInitiale-> miseInitiale.getTypePari().equals(courseName))
.filter(miseInitiale -> miseInitiale.getTypePari().equals(courseName))
.findFirst()
.orElse(null);
if(miseModel == null){
if (miseModel == null) {
MessageDialog.showError(getContext(), "Erreur lors de l'initialisation de la mise");
_initializeToZero();
return;
@@ -662,7 +752,7 @@ public class BetValidation extends Fragment {
// 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());
MessageDialog.showError(getContext(), "Le coefficient doit être au plus 200 pour " + typePari.toString());
_initializeToZero();
return;
}
@@ -670,58 +760,103 @@ public class BetValidation extends Fragment {
// 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());
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){
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");
binding.mise.setText(mise + " CFA");
return;
}
mise = mise * _calculateArrangement(nombreChevauxSelectionnes - typeOfBetHorses , nombreX);
mise = mise * _calculateArrangement(nombreChevauxSelectionnes - typeOfBetHorses, nombreX);
}
if(order){
mise = mise * _calculateArrangement(typeOfBetHorses, (typeOfBetHorses-nombreX));
if (order) {
mise = mise * _calculateArrangement(typeOfBetHorses, (typeOfBetHorses - nombreX));
}
this.mise = mise;
binding.mise.setText(mise+" CFA");
binding.mise.setText(mise + " CFA");
return;
}
if(!order){
if (!order) {
mise = mise * _calculateCombinaison(nombreChevauxSelectionnes, typeOfBetHorses);
}else{
} else {
mise = mise * _calculateArrangement(nombreChevauxSelectionnes, typeOfBetHorses);
}
this.mise = mise;
binding.mise.setText(mise+" CFA");
binding.mise.setText(mise + " CFA");
}
Long _calculateArrangement(int n, int k){
return _calculateFactorial(n) / _calculateFactorial(n-k);
Long _calculateArrangement(int n, int k) {
return _calculateFactorial(n) / _calculateFactorial(n - k);
}
Long _calculateCombinaison(int n, int k){
Long _calculateCombinaison(int n, int k) {
return _calculateFactorial(n) / (_calculateFactorial(k) * _calculateFactorial(n - k));
}
Long _calculateFactorial(int n){
Long _calculateFactorial(int n) {
long f = 1;
if(n == 0){
return f;
if (n == 0) {
return f;
}
for(int i = 1; i <=n; i++){
for (int i = 1; i <= n; i++) {
f *= i;
}
return f;
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;
}
@@ -735,6 +870,7 @@ public class BetValidation extends Fragment {
}
return bmp;
}
public static String generate12Digits() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 8; i++) {