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

@@ -90,6 +90,8 @@ dependencies {
implementation(libs.material) implementation(libs.material)
implementation(libs.constraintlayout) implementation(libs.constraintlayout)
implementation(libs.printerlibrary)
implementation(libs.navigation.fragment) implementation(libs.navigation.fragment)
implementation(libs.navigation.ui) implementation(libs.navigation.ui)

View File

@@ -16,6 +16,11 @@
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="com.sunmi.peripheral.printer.permission.PRINTER" />
<!-- Pour certains modèles -->
<uses-permission android:name="android.permission.BIND_PRINTER_SERVICE" />
<!-- ✅ Location Permissions --> <!-- ✅ Location Permissions -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
@@ -40,6 +45,10 @@
<uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" /> <uses-feature android:name="android.hardware.camera.autofocus" />
<queries>
<package android:name="woyou.aidlservice.jiuiv5" />
</queries>
<application <application
android:name=".PmuHorseBetting" android:name=".PmuHorseBetting"
android:allowBackup="true" android:allowBackup="true"

View File

@@ -1,5 +1,6 @@
package com.example.quiz; package com.example.quiz;
import android.app.AlertDialog;
import android.os.Bundle; import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
@@ -88,10 +89,49 @@ public class AnnulationTicket extends Fragment {
binding.annuleTicketBtn.setOnClickListener(v->{ binding.annuleTicketBtn.setOnClickListener(v->{
String reference = binding.referenceTicket.getText().toString(); String reference = binding.referenceTicket.getText().toString();
if(reference.isEmpty()){ if(reference.isEmpty()){
Toast.makeText(getContext(),"Entrez la référence du ticket", Toast.LENGTH_SHORT).show(); MessageDialog.showError(getContext(), "Veuillez donner la reference du ticket");
return; return;
} }
viewModel.annulerPari(reference).observe(getViewLifecycleOwner(), new Observer<Result<ParisResponse>>() { viewModel.getPariByNumero(reference).observe(getViewLifecycleOwner(), new Observer<Result<ParisResponse>>() {
@Override
public void onChanged(Result<ParisResponse> parisResponseResult) {
switch (parisResponseResult.status){
case LOADING:{
dialog.show("Recherche du ticket");
break;
}
case ERROR:{
MessageDialog.showError(getContext(), parisResponseResult.message);
break;
}
case SUCCESS:{
if(parisResponseResult.data.getNumeroTicket().equals(reference)){
dialog.dismiss();
if(parisResponseResult.data.getStatutPari() == ParisResponse.StatutPari.ANNULE){
MessageDialog.showError(getContext(), "Le ticket est déjà annulé");
return;
}
_showPariDialog(reference);
}else{
MessageDialog.showError(getContext(), "Le ticket n'existe pas");
}
}
}
}
});
});
}
void _showPariDialog(String ticketReference){
new AlertDialog.Builder(getContext())
.setTitle("Annulation du ticket")
.setMessage("Etes-vous sûr de vouloir annuler le ticket "+ticketReference+" ?")
.setCancelable(true)
.setNegativeButton("Annuler", (dialog, which) -> {
dialog.dismiss();
})
.setPositiveButton("Confirmer", (annulationDialog, which) -> {
viewModel.annulerPari(ticketReference).observe(getViewLifecycleOwner(), new Observer<Result<ParisResponse>>() {
@Override @Override
public void onChanged(Result<ParisResponse> pariResult) { public void onChanged(Result<ParisResponse> pariResult) {
switch (pariResult.status){ switch (pariResult.status){
@@ -113,7 +153,7 @@ public class AnnulationTicket extends Fragment {
} }
} }
}); });
}); }).show();
} }
@Override @Override

View File

@@ -1,14 +1,19 @@
package com.example.quiz; package com.example.quiz;
import android.Manifest;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter; import android.app.Dialog;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.ActivityResultLauncher;
@@ -16,10 +21,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider; 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.Pari;
import com.example.quiz.data.model.PariMise; import com.example.quiz.data.model.PariMise;
import com.example.quiz.data.model.ParisResponse; 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.TypeOfBet;
import com.example.quiz.data.model.dtos.NotifPayload; 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.data.remote.StompManager;
import com.example.quiz.databinding.FragmentBetValidationBinding; import com.example.quiz.databinding.FragmentBetValidationBinding;
import com.example.quiz.utils.BluetoothUtils; 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.MessageDialog;
import com.example.quiz.utils.Result; import com.example.quiz.utils.Result;
import com.example.quiz.utils.SharedPrefsHelper; import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.utils.SunmiPrinterManager;
import com.example.quiz.viewModel.LogsViewModel; import com.example.quiz.viewModel.LogsViewModel;
import com.example.quiz.viewModel.PariMiseViewModel; import com.example.quiz.viewModel.PariMiseViewModel;
import com.example.quiz.viewModel.PariViewModel; import com.example.quiz.viewModel.PariViewModel;
@@ -67,15 +68,17 @@ import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix; import com.google.zxing.common.BitMatrix;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Observable;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.inject.Inject; import javax.inject.Inject;
@@ -93,8 +96,10 @@ public class BetValidation extends Fragment {
FragmentBetValidationBinding binding; FragmentBetValidationBinding binding;
SharedViewModel shared; SharedViewModel shared;
PariMiseViewModel pariMiseViewModel; PariMiseViewModel pariMiseViewModel;
List<MiseInitiale> misesInitiales; List<MiseInitiale> misesInitiales;
@@ -104,6 +109,8 @@ public class BetValidation extends Fragment {
@Inject @Inject
StompManager stompManager; StompManager stompManager;
SunmiPrinterManager sunmiPrinterManager;
private int nombreX; private int nombreX;
LogsViewModel logsViewModel; LogsViewModel logsViewModel;
@@ -113,16 +120,20 @@ public class BetValidation extends Fragment {
private long mise; private long mise;
String mobileName;
private TypeOfBet typeOfBet; private TypeOfBet typeOfBet;
MutableLiveData<Boolean> isPrinterReady = new MutableLiveData<>(false);
SharedPrefsHelper prefsHelper; SharedPrefsHelper prefsHelper;
private Course course; private Course course;
LoaderDialog loader;
LoaderDialog loader;
private int coeff; private int coeff;
@@ -135,7 +146,6 @@ public class BetValidation extends Fragment {
PariViewModel pariViewModel; PariViewModel pariViewModel;
public BetValidation() { public BetValidation() {
// Required empty public constructor // Required empty public constructor
} }
@@ -151,7 +161,15 @@ public class BetValidation extends Fragment {
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
prefsHelper = SharedPrefsHelper.getInstance(getContext()); prefsHelper = SharedPrefsHelper.getInstance(getContext());
mobileName = Build.MANUFACTURER;
sunmiPrinterManager = SunmiPrinterManager.getInstance(requireContext());
if(mobileName.toLowerCase().contains("sunmi")){
sunmiPrinterManager.connectPrinter(status ->{
isPrinterReady.setValue(status);
});
} }
}
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
@@ -161,7 +179,7 @@ public class BetValidation extends Fragment {
logsViewModel = new ViewModelProvider(this).get(LogsViewModel.class); logsViewModel = new ViewModelProvider(this).get(LogsViewModel.class);
binding.coeff.setText(String.valueOf(1)); binding.coeff.setText(String.valueOf(1));
coeff = Integer.parseInt(binding.coeff.getText().toString()); coeff = Integer.parseInt(binding.coeff.getText().toString());
binding.coeff.addTextChangedListener(new TextWatcher(){ binding.coeff.addTextChangedListener(new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
@@ -169,11 +187,11 @@ public class BetValidation extends Fragment {
@Override @Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { 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"); binding.coeff.setError("Le coefficient est obligatoire");
return; 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 "); binding.coeff.setError("Le coefficient doit être supérieur ou égal à 1 ");
return; return;
} }
@@ -194,7 +212,7 @@ public class BetValidation extends Fragment {
binding.gridNumbers.removeAllViews(); binding.gridNumbers.removeAllViews();
int columns = 8; int columns = 8;
grid.setColumnCount(columns); grid.setColumnCount(columns);
if(shared.selectedCourse.getValue() != null){ if (shared.selectedCourse.getValue() != null) {
for (int i = 1; i <= shared.selectedCourse.getValue().getNombrePartants(); i++) { for (int i = 1; i <= shared.selectedCourse.getValue().getNombrePartants(); i++) {
createNumberItem(String.valueOf(i)); createNumberItem(String.valueOf(i));
grid.addView(createNumberItem(String.valueOf(i))); grid.addView(createNumberItem(String.valueOf(i)));
@@ -203,7 +221,6 @@ public class BetValidation extends Fragment {
createNumberItem("X"); createNumberItem("X");
grid.addView(createNumberItem("X")); grid.addView(createNumberItem("X"));
} }
private TextView createNumberItem(String horse) { private TextView createNumberItem(String horse) {
TextView textView = new TextView(requireContext()); TextView textView = new TextView(requireContext());
textView.setText(horse); textView.setText(horse);
@@ -215,23 +232,23 @@ public class BetValidation extends Fragment {
textView.setWidth(80); textView.setWidth(80);
textView.setHeight(100); textView.setHeight(100);
textView.setGravity(Gravity.CENTER); textView.setGravity(Gravity.CENTER);
textView.setBackgroundResource(Objects.equals(horse, "X") ?R.drawable.x_background: R.drawable.number_background); 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))){ 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.setTextColor(getResources().getColor(R.color.white));
textView.setBackgroundResource(R.drawable.number_background_grey); textView.setBackgroundResource(R.drawable.number_background_grey);
} }
textView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); textView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
textView.setOnClickListener(v -> { 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(); Toast.makeText(getContext(), "Ce cheval n'est pas partant", Toast.LENGTH_SHORT).show();
return; return;
} }
final List<String> horses = new ArrayList<>(selectedHorses.getValue()); final List<String> horses = new ArrayList<>(selectedHorses.getValue());
if(horses.size() >= shared.typeOfBet.getValue().getNumberOfHorse() && horse.equals("X")){ if (horses.size() >= shared.typeOfBet.getValue().getNumberOfHorse() && horse.equals("X")) {
Toast.makeText(getContext(), "Vous ne pouvez plus sélectionner X", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Vous ne pouvez plus sélectionner X", Toast.LENGTH_SHORT).show();
return; return;
} }
if(_notClickable(horses) && horse.equals("X")){ if (_notClickable(horses) && horse.equals("X")) {
Toast.makeText(getContext(), "Vous ne pouvez plus sélectionner X", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Vous ne pouvez plus sélectionner X", Toast.LENGTH_SHORT).show();
return; return;
} }
@@ -249,19 +266,19 @@ public class BetValidation extends Fragment {
String combinationText = selectedHorses.getValue().stream() String combinationText = selectedHorses.getValue().stream()
.map(h -> h) .map(h -> h)
.collect(Collectors.joining("-")); .collect(Collectors.joining("-"));
binding.combination.setText( combinationText); binding.combination.setText(combinationText);
}); });
return textView; return textView;
} }
boolean _notClickable(List<String> selectedHorses){ boolean _notClickable(List<String> selectedHorses) {
int numberOfElement = 0; int numberOfElement = 0;
if(shared.typeOfBet.getValue().getNumberOfHorse() < 2){ if (shared.typeOfBet.getValue().getNumberOfHorse() < 2) {
return true; return true;
} }
for(String horse: selectedHorses){ for (String horse : selectedHorses) {
numberOfElement = horse.equals("X")?numberOfElement+1:numberOfElement; numberOfElement = horse.equals("X") ? numberOfElement + 1 : numberOfElement;
} }
nombreX = numberOfElement; nombreX = numberOfElement;
return numberOfElement == shared.typeOfBet.getValue().getNumberOfHorse() - 1; return numberOfElement == shared.typeOfBet.getValue().getNumberOfHorse() - 1;
@@ -274,8 +291,8 @@ public class BetValidation extends Fragment {
pariMiseViewModel = new ViewModelProvider(this).get(PariMiseViewModel.class); pariMiseViewModel = new ViewModelProvider(this).get(PariMiseViewModel.class);
pariMiseViewModel.getBetInitMise().observe( pariMiseViewModel.getBetInitMise().observe(
getViewLifecycleOwner(), getViewLifecycleOwner(),
result->{ result -> {
switch (result.status){ switch (result.status) {
case LOADING: { case LOADING: {
loader.show("Chargement des mise"); loader.show("Chargement des mise");
break; break;
@@ -294,12 +311,13 @@ public class BetValidation extends Fragment {
} }
} }
); );
if(shared.selectedCourse.getValue() != null){ if (shared.selectedCourse.getValue() != null) {
stompManager.subscribe("courses/"+shared.selectedCourse.getValue().getId(), json->{ stompManager.subscribe("courses/" + shared.selectedCourse.getValue().getId(), json -> {
Type type = new TypeToken<NotifPayload<Course>>(){}.getType(); Type type = new TypeToken<NotifPayload<Course>>() {
}.getType();
NotifPayload<Course> notif = new Gson().fromJson(json, type); NotifPayload<Course> notif = new Gson().fromJson(json, type);
Course updatedCourse = notif.getPayload(); Course updatedCourse = notif.getPayload();
if(shared.selectedCourse.getValue().getId() == updatedCourse.getId()){ if (shared.selectedCourse.getValue().getId() == updatedCourse.getId()) {
shared.setSelectedCourse(updatedCourse); shared.setSelectedCourse(updatedCourse);
setupNumberGrid(binding.gridNumbers); setupNumberGrid(binding.gridNumbers);
} }
@@ -310,12 +328,12 @@ public class BetValidation extends Fragment {
typeOfBet = shared.typeOfBet.getValue(); typeOfBet = shared.typeOfBet.getValue();
course = shared.selectedCourse.getValue(); course = shared.selectedCourse.getValue();
AppCompatActivity activity = (AppCompatActivity) getActivity(); AppCompatActivity activity = (AppCompatActivity) getActivity();
if(activity != null){ if (activity != null) {
MaterialToolbar toolbar = activity.findViewById(R.id.toolbar); 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); activity.setSupportActionBar(toolbar);
if(activity.getSupportActionBar() != null){ if (activity.getSupportActionBar() != null) {
activity.getSupportActionBar().setTitle("Pari "+shared.selectedCourse.getValue().getNom()); activity.getSupportActionBar().setTitle("Pari " + shared.selectedCourse.getValue().getNom());
} }
} }
setupNumberGrid(binding.gridNumbers); setupNumberGrid(binding.gridNumbers);
@@ -342,28 +360,28 @@ public class BetValidation extends Fragment {
@Override @Override
public void onChanged(List<String> horses) { public void onChanged(List<String> horses) {
calculateMise(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); binding.order.setVisibility(View.VISIBLE);
}else{ } else {
binding.order.setVisibility(View.GONE); binding.order.setVisibility(View.GONE);
} }
if(horses.contains("X")){ if (horses.contains("X")) {
if(selectedHorses.getValue().size() == shared.typeOfBet.getValue().getNumberOfHorse()){ if (selectedHorses.getValue().size() == shared.typeOfBet.getValue().getNumberOfHorse()) {
binding.elargie.setVisibility(View.VISIBLE); binding.elargie.setVisibility(View.VISIBLE);
binding.elargie.setText("Champ total"); binding.elargie.setText("Champ total");
return; return;
}else{ } else {
if(selectedHorses.getValue().size() > shared.typeOfBet.getValue().getNumberOfHorse()){ if (selectedHorses.getValue().size() > shared.typeOfBet.getValue().getNumberOfHorse()) {
binding.elargie.setVisibility(View.VISIBLE); binding.elargie.setVisibility(View.VISIBLE);
binding.elargie.setText("Champ partiel"); binding.elargie.setText("Champ partiel");
return; return;
} }
} }
} }
if(horses.size() > shared.typeOfBet.getValue().getNumberOfHorse()){ if (horses.size() > shared.typeOfBet.getValue().getNumberOfHorse()) {
binding.elargie.setVisibility(View.VISIBLE); binding.elargie.setVisibility(View.VISIBLE);
binding.elargie.setText("Elargi"); binding.elargie.setText("Elargi");
}else{ } else {
binding.elargie.setVisibility(View.GONE); binding.elargie.setVisibility(View.GONE);
} }
} }
@@ -373,48 +391,24 @@ public class BetValidation extends Fragment {
calculateMise(selectedHorses.getValue()); calculateMise(selectedHorses.getValue());
}); });
binding.betValidateBtn.setOnClickListener(v->{ binding.betValidateBtn.setOnClickListener(v -> {
// Log.d("PAPER_STATUS", String.valueOf(ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.BLUETOOTH_CONNECT))+" "+String.valueOf(PackageManager.PERMISSION_GRANTED)); if (binding.paymentType.getSelectedItem().toString().equals("Orange Money") && binding.phoneNumber.getText().toString().isEmpty()) {
// 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()){
MessageDialog.showError(getContext(), "Veuillez saisir le numéro de téléphone"); MessageDialog.showError(getContext(), "Veuillez saisir le numéro de téléphone");
return; return;
} }
if(shared.typeOfBet == null || shared.selectedCourse == null){ if (shared.typeOfBet == null || shared.selectedCourse == null) {
return; return;
} }
int required = typeOfBet.getNumberOfHorse(); int required = typeOfBet.getNumberOfHorse();
if(selectedHorses.getValue().size() < required){ if (Objects.requireNonNull(selectedHorses.getValue()).size() < required) {
Toast.makeText(getContext(), "Veuillez sélectionner au moins"+required+" chevaux", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Veuillez sélectionner au moins" + required + " chevaux", Toast.LENGTH_SHORT).show();
return; return;
} }
if(this.mise == 0){ if (this.mise == 0) {
Toast.makeText(getContext(), "Pari non valide", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Pari non valide", Toast.LENGTH_SHORT).show();
return; return;
} }
@@ -432,61 +426,63 @@ public class BetValidation extends Fragment {
"XOF", "XOF",
"Pari" "Pari"
); );
if (dialog != null && dialog.isShowing()) {
return;
}
_showPariDialog(pari); _showPariDialog(pari);
}); });
binding.backBtn.setOnClickListener(v->{ binding.backBtn.setOnClickListener(v -> {
getActivity().onBackPressed(); getActivity().onBackPressed();
}); });
binding.deleteBtn.setOnClickListener(v->{ binding.deleteBtn.setOnClickListener(v -> {
_initializeToZero(); _initializeToZero();
}); });
} }
String _getCombinaison() {
String _getCombinaison(){ if (selectedHorses.getValue().contains("X") && shared.typeOfBet.getValue().getNumberOfHorse() < selectedHorses.getValue().size()) {
if(selectedHorses.getValue().contains("X") && shared.typeOfBet.getValue().getNumberOfHorse() < selectedHorses.getValue().size()){
String first = selectedHorses.getValue().subList(0, shared.typeOfBet.getValue().getNumberOfHorse()).stream() String first = selectedHorses.getValue().subList(0, shared.typeOfBet.getValue().getNumberOfHorse()).stream()
.map(String::valueOf) .map(String::valueOf)
.collect(Collectors.joining(",")); .collect(Collectors.joining(","));
String last = selectedHorses.getValue().subList(shared.typeOfBet.getValue().getNumberOfHorse(), selectedHorses.getValue().size()).stream() String last = selectedHorses.getValue().subList(shared.typeOfBet.getValue().getNumberOfHorse(), selectedHorses.getValue().size()).stream()
.map(String::valueOf) .map(String::valueOf)
.collect(Collectors.joining(",")); .collect(Collectors.joining(","));
return first+",R,"+last; return first + ",R," + last;
}else{ } else {
return selectedHorses.getValue().stream().map(String::valueOf).collect(Collectors.joining(",")); return selectedHorses.getValue().stream().map(String::valueOf).collect(Collectors.joining(","));
} }
} }
List<String> _getFormule(){ List<String> _getFormule() {
List<String> combinaison = selectedHorses.getValue(); List<String> combinaison = selectedHorses.getValue();
if(!combinaison.contains("X")){ if (!combinaison.contains("X")) {
if(!order){ if (!order) {
return List.of("UNITAIRE"); return List.of("UNITAIRE");
}else{ } else {
return List.of("FORMULE_COMPLETE"); return List.of("FORMULE_COMPLETE");
} }
}else{ } else {
if(shared.typeOfBet.getValue().getNumberOfHorse() < selectedHorses.getValue().size()){ if (shared.typeOfBet.getValue().getNumberOfHorse() < selectedHorses.getValue().size()) {
if(order){ if (order) {
return List.of("CHAMP_X", "FORMULE_COMPLETE"); return List.of("CHAMP_X", "FORMULE_COMPLETE");
}else{ } else {
return List.of("CHAMP_X"); return List.of("CHAMP_X");
} }
}else{ } else {
if(order){ if (order) {
return List.of("CHAMP_TOTAL", "FORMULE_COMPLETE"); return List.of("CHAMP_TOTAL", "FORMULE_COMPLETE");
}else{ } else {
return List.of("CHAMP_TOTAL"); return List.of("CHAMP_TOTAL");
} }
} }
} }
} }
private void setSelectedTypeOfBetImage(){ private void setSelectedTypeOfBetImage() {
switch (shared.typeOfBet.getValue().getName()){ switch (shared.typeOfBet.getValue().getName()) {
case COUPLE_PLACE: case COUPLE_PLACE:
binding.icTypeOfBet.setImageResource(R.drawable.ic_couple_place); binding.icTypeOfBet.setImageResource(R.drawable.ic_couple_place);
break; break;
@@ -506,12 +502,9 @@ public class BetValidation extends Fragment {
} }
public void printPari(ParisResponse pari) throws WriterException { public void printPari(ParisResponse pari) throws WriterException {
try {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pmu_logo); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pmu_logo);
Bitmap barcode = generateBarcodeBitmap(pari.getNumeroTicket(), 384, 100); Bitmap barcode = generateBarcodeBitmap(pari.getNumeroTicket(), 384, 100);
StringBuilder tspl = new StringBuilder(); StringBuilder tspl = new StringBuilder();
Printama printama = Printama.with(getContext());
tspl.append("Bamako").append("\n"); tspl.append("Bamako").append("\n");
tspl.append(shared.selectedCourse.getValue().getNom()).append("\n"); tspl.append(shared.selectedCourse.getValue().getNom()).append("\n");
OffsetDateTime dateTime = OffsetDateTime.parse(shared.selectedCourse.getValue().getHeureDepartPrevue()); OffsetDateTime dateTime = OffsetDateTime.parse(shared.selectedCourse.getValue().getHeureDepartPrevue());
@@ -519,21 +512,31 @@ public class BetValidation extends Fragment {
String formattedDate = dateTime.format(formatter); String formattedDate = dateTime.format(formatter);
tspl.append(formattedDate).append("\n"); tspl.append(formattedDate).append("\n");
tspl.append("Course ").append(String.valueOf(shared.selectedCourse.getValue().getId())).append("\n"); tspl.append("Course ").append(String.valueOf(shared.selectedCourse.getValue().getId())).append("\n");
tspl.append(printama.lineSeparator()+"\n"); tspl.append(sunmiPrinterManager.separationText()+ "\n");
boolean isElargie = selectedHorses.getValue().size()>shared.typeOfBet.getValue().getNumberOfHorse(); boolean isElargie = selectedHorses.getValue().size() > shared.typeOfBet.getValue().getNumberOfHorse();
String typePari = pari.getTypesParisMises().get(0).getTypePari(); String typePari = pari.getTypesParisMises().get(0).getTypePari();
tspl.append(isElargie?typePari+"/Elargie":typePari).append("\n"); tspl.append(isElargie ? typePari + "/Elargie" : typePari).append("\n");
tspl.append(order?"COMBINAISON COMPLETE"+"\n":""); tspl.append(order ? "COMBINAISON COMPLETE" + "\n" : "");
String combinationText = selectedHorses.getValue().stream() String combinationText = formatLineWithNumbers(selectedHorses.getValue().stream().map(String::valueOf).toArray(String[]::new), "-") ;
.map(String::valueOf)
.collect(Collectors.joining("-"));
tspl.append(combinationText).append("\n"); tspl.append(combinationText).append("\n");
tspl.append("COEF: ").append(String.valueOf(coeff)).append(".0"); tspl.append("COEF: ").append(String.valueOf(coeff)).append(".0");
tspl.append("\n").append(printama.lineSeparator()).append("\n"); tspl.append("\n").append(sunmiPrinterManager.separationText()).append("\n");
tspl.append("MONTANT: ").append(pari.getTypesParisMises().get(0).getMiseTotale()).append(" XOF"); tspl.append("MONTANT: ").append(pari.getTypesParisMises().get(0).getMiseTotale()).append(" XOF");
tspl.append("\n").append(printama.lineSeparator()).append("\n"); tspl.append("\n").append(sunmiPrinterManager.separationText()).append("\n");
tspl.append("AGENT: ").append(prefsHelper.get("code")).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"); 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.needsBluetoothPermissions()) {
if (!BluetoothUtils.hasBluetoothPermission(requireContext())) { if (!BluetoothUtils.hasBluetoothPermission(requireContext())) {
// Demande la permission si non accordée // Demande la permission si non accordée
@@ -544,8 +547,28 @@ public class BetValidation extends Fragment {
// 2⃣ Permission OK, on peut afficher la liste // 2⃣ Permission OK, on peut afficher la liste
Printama.with(getContext()).printTextBuilder(tspl, bitmap, pari.getNumeroTicket(), barcode); 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(); _initializeToZero();
}
}
});
} catch (SecurityException e) { } catch (SecurityException e) {
Toast.makeText(requireContext(), Toast.makeText(requireContext(),
"Permission Bluetooth non accordée", Toast.LENGTH_SHORT).show(); "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"}) @SuppressLint({"MissingInflatedId", "SetTextI18n"})
void _showPariDialog(Pari pari){ void _showPariDialog(Pari pari) {
LayoutInflater inflater = getLayoutInflater(); LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.pari_confirmation, null); View view = inflater.inflate(R.layout.pari_confirmation, null);
TextView numero_course = (TextView) view.findViewById(R.id.alert_course_numero); 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); TextView alert_pari_type = (TextView) view.findViewById(R.id.alert_pari_type);
alert_pari_type.setText(String.valueOf(shared.typeOfBet.getValue().getName())); alert_pari_type.setText(String.valueOf(shared.typeOfBet.getValue().getName()));
TextView is_elargie = (TextView) view.findViewById(R.id.alert_is_elargie); 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); TextView alert_combinaison = (TextView) view.findViewById(R.id.alert_combinaison);
alert_combinaison.setText(selectedHorses.getValue().stream() alert_combinaison.setText(selectedHorses.getValue().stream()
.map(String::valueOf) .map(String::valueOf)
.collect(Collectors.joining("-"))); .collect(Collectors.joining("-")));
TextView aler_coeff = (TextView) view.findViewById(R.id.alert_coeff); 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); 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()); AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setView(view); builder.setView(view);
builder.setCancelable(false); builder.setCancelable(false);
dialog = builder.create(); dialog = builder.create();
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
view.findViewById(R.id.alert_validate).setOnClickListener(v->{ view.findViewById(R.id.alert_validate).setOnClickListener(v -> {
pariViewModel.createPari(pari).observe(getViewLifecycleOwner(),new Observer<Result<ParisResponse>>() { 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 @Override
public void onChanged(Result<ParisResponse> pariResult) { public void onChanged(Result<ParisResponse> pariResult) {
switch (pariResult.status){ switch (pariResult.status) {
case ERROR: case ERROR:
loader.dismiss(); loader.dismiss();
dialog.dismiss(); dialog.dismiss();
@@ -594,7 +684,7 @@ public class BetValidation extends Fragment {
case SUCCESS: case SUCCESS:
try { try {
loader.dismiss(); 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); printPari(pariResult.data);
dialog.dismiss(); dialog.dismiss();
MessageDialog.showSuccess(getContext(), "Pari créé avec succès"); MessageDialog.showSuccess(getContext(), "Pari créé avec succès");
@@ -614,7 +704,7 @@ public class BetValidation extends Fragment {
dialog.show(); dialog.show();
} }
void _initializeToZero(){ void _initializeToZero() {
selectedHorses.setValue(List.of()); selectedHorses.setValue(List.of());
binding.combination.setText(""); binding.combination.setText("");
binding.order.setChecked(false); binding.order.setChecked(false);
@@ -625,29 +715,29 @@ public class BetValidation extends Fragment {
setupNumberGrid(binding.gridNumbers); setupNumberGrid(binding.gridNumbers);
} }
public void calculateMise(List<String> selectedHorses){ public void calculateMise(List<String> selectedHorses) {
_notClickable(selectedHorses); _notClickable(selectedHorses);
int nombreChevauxSelectionnes = selectedHorses.size(); int nombreChevauxSelectionnes = selectedHorses.size();
long mise = 0; long mise = 0;
int nonPartants = 0; int nonPartants = 0;
if(shared.typeOfBet.getValue() == null || shared.selectedCourse.getValue() == null){ if (shared.typeOfBet.getValue() == null || shared.selectedCourse.getValue() == null) {
return; return;
} }
if(shared.selectedCourse.getValue().getNonPartants() != null){ if (shared.selectedCourse.getValue().getNonPartants() != null) {
nonPartants = shared.selectedCourse.getValue().getNonPartants().size(); nonPartants = shared.selectedCourse.getValue().getNonPartants().size();
} }
int typeOfBetHorses = shared.typeOfBet.getValue().getNumberOfHorse(); int typeOfBetHorses = shared.typeOfBet.getValue().getNumberOfHorse();
int partants = shared.selectedCourse.getValue().getNombrePartants(); int partants = shared.selectedCourse.getValue().getNombrePartants();
Course.TypeParis courseName = shared.typeOfBet.getValue().getName(); Course.TypeParis courseName = shared.typeOfBet.getValue().getName();
if(shared.typeOfBet.getValue().getNumberOfHorse() > nombreChevauxSelectionnes){ if (shared.typeOfBet.getValue().getNumberOfHorse() > nombreChevauxSelectionnes) {
binding.mise.setText(mise+" CFA"); binding.mise.setText(mise + " CFA");
return; return;
} }
MiseInitiale miseModel = misesInitiales.stream() MiseInitiale miseModel = misesInitiales.stream()
.filter(miseInitiale-> miseInitiale.getTypePari().equals(courseName)) .filter(miseInitiale -> miseInitiale.getTypePari().equals(courseName))
.findFirst() .findFirst()
.orElse(null); .orElse(null);
if(miseModel == null){ if (miseModel == null) {
MessageDialog.showError(getContext(), "Erreur lors de l'initialisation de la mise"); MessageDialog.showError(getContext(), "Erreur lors de l'initialisation de la mise");
_initializeToZero(); _initializeToZero();
return; return;
@@ -662,7 +752,7 @@ public class BetValidation extends Fragment {
// Pour COUPLE_GAGNANT ou COUPLE_PLACE: coefficient < 200 // Pour COUPLE_GAGNANT ou COUPLE_PLACE: coefficient < 200
if (coeff > 200) { if (coeff > 200) {
// Erreur: coefficient trop élevé // 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(); _initializeToZero();
return; return;
} }
@@ -670,61 +760,106 @@ public class BetValidation extends Fragment {
// Pour les autres types: coefficient <= 20 // Pour les autres types: coefficient <= 20
if (coeff > 20) { if (coeff > 20) {
// Erreur: coefficient trop élevé // 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(); _initializeToZero();
return; return;
} }
} }
mise = mise * coeff; mise = mise * coeff;
if(nombreX>0){ if (nombreX > 0) {
if(nombreChevauxSelectionnes == typeOfBetHorses){ if (nombreChevauxSelectionnes == typeOfBetHorses) {
mise = mise * _calculateArrangement((partants - (typeOfBetHorses-nombreX) - nonPartants), nombreX); mise = mise * _calculateArrangement((partants - (typeOfBetHorses - nombreX) - nonPartants), nombreX);
}else{ } else {
if(nombreChevauxSelectionnes - typeOfBetHorses < nombreX || nombreChevauxSelectionnes - typeOfBetHorses==1){ if (nombreChevauxSelectionnes - typeOfBetHorses < nombreX || nombreChevauxSelectionnes - typeOfBetHorses == 1) {
mise = 0; mise = 0;
this.mise = mise; this.mise = mise;
binding.mise.setText(mise+" CFA"); binding.mise.setText(mise + " CFA");
return; return;
} }
mise = mise * _calculateArrangement(nombreChevauxSelectionnes - typeOfBetHorses , nombreX); mise = mise * _calculateArrangement(nombreChevauxSelectionnes - typeOfBetHorses, nombreX);
} }
if(order){ if (order) {
mise = mise * _calculateArrangement(typeOfBetHorses, (typeOfBetHorses-nombreX)); mise = mise * _calculateArrangement(typeOfBetHorses, (typeOfBetHorses - nombreX));
} }
this.mise = mise; this.mise = mise;
binding.mise.setText(mise+" CFA"); binding.mise.setText(mise + " CFA");
return; return;
} }
if(!order){ if (!order) {
mise = mise * _calculateCombinaison(nombreChevauxSelectionnes, typeOfBetHorses); mise = mise * _calculateCombinaison(nombreChevauxSelectionnes, typeOfBetHorses);
}else{ } else {
mise = mise * _calculateArrangement(nombreChevauxSelectionnes, typeOfBetHorses); mise = mise * _calculateArrangement(nombreChevauxSelectionnes, typeOfBetHorses);
} }
this.mise = mise; this.mise = mise;
binding.mise.setText(mise+" CFA"); binding.mise.setText(mise + " CFA");
} }
Long _calculateArrangement(int n, int k){ Long _calculateArrangement(int n, int k) {
return _calculateFactorial(n) / _calculateFactorial(n-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)); return _calculateFactorial(n) / (_calculateFactorial(k) * _calculateFactorial(n - k));
} }
Long _calculateFactorial(int n){ Long _calculateFactorial(int n) {
long f = 1; long f = 1;
if(n == 0){ if (n == 0) {
return f; return f;
} }
for(int i = 1; i <=n; i++){ for (int i = 1; i <= n; i++) {
f *= 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;
}
public Bitmap generateBarcodeBitmap(String contents, int width, int height) throws WriterException { public Bitmap generateBarcodeBitmap(String contents, int width, int height) throws WriterException {
BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.CODE_128, width, height); BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.CODE_128, width, height);
Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
@@ -735,6 +870,7 @@ public class BetValidation extends Fragment {
} }
return bmp; return bmp;
} }
public static String generate12Digits() { public static String generate12Digits() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {

View File

@@ -1,9 +1,15 @@
package com.example.quiz; package com.example.quiz;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
@@ -11,15 +17,20 @@ import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.anggastudio.printama.Printama;
import com.example.quiz.data.adapter.LastBetsAdapter; import com.example.quiz.data.adapter.LastBetsAdapter;
import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.Pari; import com.example.quiz.data.model.Pari;
import com.example.quiz.data.model.ParisResponse; import com.example.quiz.data.model.ParisResponse;
import com.example.quiz.databinding.FragmentDerniersParisBinding; import com.example.quiz.databinding.FragmentDerniersParisBinding;
import com.example.quiz.utils.BluetoothUtils;
import com.example.quiz.utils.LoaderDialog; import com.example.quiz.utils.LoaderDialog;
import com.example.quiz.utils.MessageDialog; import com.example.quiz.utils.MessageDialog;
import com.example.quiz.utils.Result; import com.example.quiz.utils.Result;
@@ -27,8 +38,18 @@ import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.LogsViewModel; import com.example.quiz.viewModel.LogsViewModel;
import com.example.quiz.viewModel.PariViewModel; import com.example.quiz.viewModel.PariViewModel;
import com.google.android.material.appbar.MaterialToolbar; import com.google.android.material.appbar.MaterialToolbar;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import dagger.hilt.android.AndroidEntryPoint; import dagger.hilt.android.AndroidEntryPoint;
@@ -45,13 +66,18 @@ public class DerniersParis extends Fragment {
LogsViewModel logsViewModel; LogsViewModel logsViewModel;
LoaderDialog loader; LoaderDialog loader;
SharedPrefsHelper prefsHelper; SharedPrefsHelper prefsHelper;
PariViewModel viewModel; PariViewModel viewModel;
AlertDialog dialog;
LastBetsAdapter adapter; LastBetsAdapter adapter;
Map<String, Integer> listProduits = Map.of("QUINTE", 5, "QUARTE", 4, "TIERCE", 3, "COUPLE_GAGNANT", 2, "COUPLE_PLACE", 2);
public DerniersParis() { public DerniersParis() {
// Required empty public constructor // Required empty public constructor
} }
@@ -70,6 +96,7 @@ public class DerniersParis extends Fragment {
prefsHelper = SharedPrefsHelper.getInstance(getContext()); prefsHelper = SharedPrefsHelper.getInstance(getContext());
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
@@ -84,6 +111,10 @@ public class DerniersParis extends Fragment {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
binding.lastBetsRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); binding.lastBetsRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
viewModel = new ViewModelProvider(this).get(PariViewModel.class); viewModel = new ViewModelProvider(this).get(PariViewModel.class);
_getLastBets();
}
void _getLastBets(){
viewModel.getDerniersParis(prefsHelper.get("id")).observe(getViewLifecycleOwner(), new Observer<Result<List<ParisResponse>>>() { viewModel.getDerniersParis(prefsHelper.get("id")).observe(getViewLifecycleOwner(), new Observer<Result<List<ParisResponse>>>() {
@Override @Override
public void onChanged(Result<List<ParisResponse>> listResult) { public void onChanged(Result<List<ParisResponse>> listResult) {
@@ -97,9 +128,31 @@ public class DerniersParis extends Fragment {
break; break;
case SUCCESS: case SUCCESS:
loader.dismiss(); loader.dismiss();
adapter = new LastBetsAdapter(listResult.data, pari -> { if(adapter == null){
}); adapter = new LastBetsAdapter(listResult.data);
}else{
adapter.setData(listResult.data);
}
logsViewModel.insertLog(prefsHelper.get("id"), "LAST BETS", "Affichage derniers paris", System.currentTimeMillis()); logsViewModel.insertLog(prefsHelper.get("id"), "LAST BETS", "Affichage derniers paris", System.currentTimeMillis());
adapter.setPariClickListener(new LastBetsAdapter.onPariClickListener() {
@Override
public void onItemClick(ParisResponse pari) {
if(pari.getStatutPari() != null && pari.getStatutPari() != ParisResponse.StatutPari.ENREGISTRE){
MessageDialog.showError(getContext(), "Ce pari ne peut pas être réimprimé!");
return;
}
_showPariDialog(pari);
}
@Override
public void onItemCancel(ParisResponse pari) {
if(pari.getStatutPari() != null && pari.getStatutPari() != ParisResponse.StatutPari.ENREGISTRE){
MessageDialog.showError(getContext(), "Ce pari ne peut pas être annulé");
return;
}
_cancelConfirmationDialog(pari);
}
});
binding.lastBetsRecyclerView.setAdapter(adapter); binding.lastBetsRecyclerView.setAdapter(adapter);
break; break;
} }
@@ -107,6 +160,154 @@ public class DerniersParis extends Fragment {
}); });
} }
void _cancelConfirmationDialog(ParisResponse pari){
new AlertDialog.Builder(getContext())
.setTitle("Annulation du pari")
.setMessage("Êtes-vous sûr de vouloir annuler le pari "+pari.getNumeroTicket()+" ?")
.setPositiveButton("Oui", (cancelDialog, which) -> {
_cancelPari(pari);
cancelDialog.dismiss();
})
.setNegativeButton("Non", (cancelDialog, which) -> {
cancelDialog.dismiss();
}).show();
}
void _cancelPari(ParisResponse pari){
viewModel.annulerPari(pari.getNumeroTicket()).observe(getViewLifecycleOwner(), new Observer<Result<ParisResponse>>() {
@Override
public void onChanged(Result<ParisResponse> result) {
switch (result.status){
case LOADING:
loader.show("Annulation du pari");
break;
case ERROR:
loader.dismiss();
MessageDialog.showError(getContext(), result.message);
break;
case SUCCESS:
loader.dismiss();
MessageDialog.showSuccess(getContext(), "Pari annulé avec succès");
_getLastBets();
break;
}
}
});
}
@SuppressLint({"MissingInflatedId", "SetTextI18n"})
void _showPariDialog(ParisResponse 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(pari.getCourseId()));
TextView alert_pari_type = (TextView) view.findViewById(R.id.alert_pari_type);
alert_pari_type.setText(String.valueOf(pari.getTypesParisMises().get(0).getTypePari()));
TextView is_elargie = (TextView) view.findViewById(R.id.alert_is_elargie);
List<String> selectedHorses = Arrays.stream(pari.getCombinaison().split(","))
.map(String::trim)
.collect(Collectors.toList());
is_elargie.setText(selectedHorses.size() > listProduits.get(pari.getTypesParisMises().get(0).getTypePari())?"CE":"SI");
TextView alert_combinaison = (TextView) view.findViewById(R.id.alert_combinaison);
alert_combinaison.setText(selectedHorses.stream()
.map(String::valueOf)
.collect(Collectors.joining("-")));
TextView aler_coeff = (TextView) view.findViewById(R.id.alert_coeff);
aler_coeff.setText("Coef:"+String.valueOf(pari.getCoefficient()));
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->{
try {
_printPari(pari);
dialog.dismiss();
} catch (WriterException e) {
throw new RuntimeException(e);
}
});
view.findViewById(R.id.alert_cancel).setOnClickListener(v -> {
dialog.dismiss();
});
dialog.show();
}
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());
tspl.append("Bamako").append("\n");
tspl.append(pari.getCourseNom()).append("\n");
OffsetDateTime dateTime = OffsetDateTime.parse(pari.getHeureDepartPrevue() != null ? pari.getHeureDepartPrevue() : OffsetDateTime.now().toString());
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(pari.getCourseId())).append("\n");
tspl.append(printama.lineSeparator()+"\n");
List<String> selectedHorses = Arrays.stream(pari.getCombinaison().split(",")).collect(Collectors.toList());
boolean isElargie = selectedHorses.size()> listProduits.get(pari.getTypesParisMises().get(0).getTypePari());
String typePari = pari.getTypesParisMises().get(0).getTypePari();
tspl.append(isElargie?typePari+"/Elargie":typePari).append("\n");
tspl.append(pari.getFormules().contains("FORMULE_COMPLETE") ?"COMBINAISON COMPLETE"+"\n":"");
String combinationText = selectedHorses.stream()
.map(String::valueOf)
.collect(Collectors.joining("-"));
tspl.append(combinationText).append("\n");
tspl.append("COEF: ").append(String.valueOf(pari.getCoefficient()));
tspl.append("\n").append(printama.lineSeparator()).append("\n");
tspl.append("MONTANT: ").append(pari.getMiseTotale()).append(" XOF");
tspl.append("\n").append(printama.lineSeparator()).append("\n");
tspl.append("AGENT: ").append(pari.getAgentCode()).append("\n");
tspl.append("DATE: ").append(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss").format(OffsetDateTime.parse(pari.getDateHeurePrise()))).append("\n");
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){
MessageDialog.showError(getContext(), errorMessage);
}else{
MessageDialog.showSuccess(getContext(), "Pari imprimé avec succès");
}
}
});
} catch (SecurityException e) {
Toast.makeText(requireContext(),
"Permission Bluetooth non accordée", Toast.LENGTH_SHORT).show();
}
}
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;
}
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();

View File

@@ -16,6 +16,7 @@ import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.GridLayoutManager;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@@ -156,6 +157,7 @@ public class ListOFBets extends Fragment {
stompManager.subscribe("courses", json->{ stompManager.subscribe("courses", json->{
requireActivity().runOnUiThread(this::observe); requireActivity().runOnUiThread(this::observe);
Log.d("STOMP", json);
}); });
MenuHost menuHost = requireActivity(); MenuHost menuHost = requireActivity();

View File

@@ -1,5 +1,6 @@
package com.example.quiz; package com.example.quiz;
import android.graphics.Color; import android.graphics.Color;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import com.anggastudio.printama.Pref; import com.anggastudio.printama.Pref;
@@ -8,12 +9,18 @@ import com.example.quiz.utils.AuthNavigator;
import com.example.quiz.utils.BluetoothUtils; import com.example.quiz.utils.BluetoothUtils;
import com.example.quiz.utils.MessageDialog; import com.example.quiz.utils.MessageDialog;
import com.example.quiz.utils.SessionManager; import com.example.quiz.utils.SessionManager;
import com.example.quiz.utils.SunmiPrinterManager;
import com.example.quiz.viewModel.LoginViewModel; import com.example.quiz.viewModel.LoginViewModel;
import com.example.quiz.viewModel.LogsViewModel; import com.example.quiz.viewModel.LogsViewModel;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavController; import androidx.navigation.NavController;
import androidx.navigation.Navigation; import androidx.navigation.Navigation;
@@ -22,6 +29,9 @@ import androidx.navigation.ui.NavigationUI;
import com.example.quiz.databinding.ActivityPageQuizBinding; import com.example.quiz.databinding.ActivityPageQuizBinding;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint; import dagger.hilt.android.AndroidEntryPoint;
@@ -36,6 +46,11 @@ public class PageQuiz extends AppCompatActivity {
AuthNavigator authNavigator; AuthNavigator authNavigator;
private SessionManager sessionManager; private SessionManager sessionManager;
String mobileName;
private Set<Class<?>> exemptedFragment = new HashSet<>();
private Handler handler = new Handler(); private Handler handler = new Handler();
private Runnable checkRunnable; private Runnable checkRunnable;
@@ -45,7 +60,10 @@ public class PageQuiz extends AppCompatActivity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
exemptedFragment.add(ServerConfig.class);
exemptedFragment.add(Logs.class);
sessionManager = SessionManager.newInstance(this); sessionManager = SessionManager.newInstance(this);
mobileName = Build.MANUFACTURER;
binding = ActivityPageQuizBinding.inflate(getLayoutInflater()); binding = ActivityPageQuizBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot()); setContentView(binding.getRoot());
logsViewModel = new ViewModelProvider(this).get(LogsViewModel.class); logsViewModel = new ViewModelProvider(this).get(LogsViewModel.class);
@@ -121,6 +139,72 @@ public class PageQuiz extends AppCompatActivity {
// } // }
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
View touchedView = findTouchedView(ev);
Fragment currentFragment = getCurrentFragment();
if(currentFragment != null && exemptedFragment.contains(currentFragment.getClass())){
return super.dispatchTouchEvent(ev);
}
if(touchedView!=null && "tag_pin_exempt".equals(touchedView.getTag())){
return super.dispatchTouchEvent(ev);
}
if (authNavigator.isSessionExpired()) {
authNavigator.showPinDialog(() -> {
authNavigator.updatedLastExpiredDate();
});
return false; // Consomme l'événement pour ne pas le propager
}
authNavigator.updatedLastExpiredDate();
return super.dispatchTouchEvent(ev);
}
private Fragment getCurrentFragment() {
FragmentManager fm = getSupportFragmentManager();
// Méthode 1: Par conteneur
Fragment fragment = fm.findFragmentById(R.id.nav_host_fragment_content_main);
// Méthode 2: Par tag si vous utilisez des tags
if (fragment == null) {
fragment = fm.findFragmentByTag("current_fragment");
}
return fragment;
}
private View findTouchedView(MotionEvent ev) {
float x = ev.getRawX();
float y = ev.getRawY();
View rootView = getWindow().getDecorView().getRootView();
return findViewAtPosition(rootView, (int) x, (int) y);
}
private View findViewAtPosition(View view, int x, int y) {
if (view == null) return null;
int[] location = new int[2];
view.getLocationOnScreen(location);
int left = location[0];
int top = location[1];
int right = left + view.getWidth();
int bottom = top + view.getHeight();
if (x >= left && x <= right && y >= top && y <= bottom) {
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
for (int i = group.getChildCount() - 1; i >= 0; i--) {
View child = group.getChildAt(i);
View found = findViewAtPosition(child, x, y);
if (found != null) return found;
}
}
return view;
}
return null;
}
private void checkPermission(){ private void checkPermission(){
Pref.init(this); Pref.init(this);
if (BluetoothUtils.needsBluetoothPermissions()) { if (BluetoothUtils.needsBluetoothPermissions()) {
@@ -144,7 +228,9 @@ public class PageQuiz extends AppCompatActivity {
@Override @Override
protected void onResume() { protected void onResume() {
if(!mobileName.toLowerCase().contains("sunmi")){
checkPermission(); checkPermission();
}
super.onResume(); super.onResume();
handler = new Handler(Looper.getMainLooper()); handler = new Handler(Looper.getMainLooper());
checkRunnable = new Runnable() { checkRunnable = new Runnable() {
@@ -153,7 +239,7 @@ public class PageQuiz extends AppCompatActivity {
if (sessionManager.isExpired()) { if (sessionManager.isExpired()) {
if (!authNavigator.dialogIsShowing()) { if (!authNavigator.dialogIsShowing()) {
authNavigator.showPinDialog(() -> { authNavigator.showPinDialog(() -> {
sessionManager.updateLastExpiredDate(); authNavigator.updatedLastExpiredDate();
handler.postDelayed(checkRunnable, 1); handler.postDelayed(checkRunnable, 1);
}); });
} }

View File

@@ -1,7 +1,9 @@
package com.example.quiz; package com.example.quiz;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
@@ -17,7 +19,9 @@ import androidx.recyclerview.widget.RecyclerView;
import android.provider.Settings; import android.provider.Settings;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -41,6 +45,7 @@ import java.net.NetworkInterface;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.Objects;
import dagger.hilt.android.AndroidEntryPoint; import dagger.hilt.android.AndroidEntryPoint;
@@ -61,6 +66,8 @@ public class ServerConfig extends Fragment {
PointDeVenteAdapter pointDeVenteAdapter; PointDeVenteAdapter pointDeVenteAdapter;
TpeResponse existingTpe;
PointDeVente pdv = null; PointDeVente pdv = null;
private PointDeVenteViewModel pointDeVenteViewModel; private PointDeVenteViewModel pointDeVenteViewModel;
@@ -100,9 +107,66 @@ public class ServerConfig extends Fragment {
toolbar.setTitle("Configuration du terminal"); toolbar.setTitle("Configuration du terminal");
toolbar.setBackgroundColor( getResources().getColor(R.color.primary_green)); toolbar.setBackgroundColor( getResources().getColor(R.color.primary_green));
} }
if(sharedPrefsHelper.get("terminalId") != null){
viewModel.getTpeById(sharedPrefsHelper.get("terminalId")).observe(getViewLifecycleOwner(), new Observer<Result<TpeResponse>>() {
@Override
public void onChanged(Result<TpeResponse> tpeResult) {
switch (tpeResult.status){
case LOADING:
loader.show("Chargement du TPE");
break;
case SUCCESS:
loader.dismiss();
existingTpe = tpeResult.data;
if( existingTpe != null && Objects.equals(sharedPrefsHelper.get("terminalId"), String.valueOf(existingTpe.getId()))){
_checkPdv(existingTpe);
return;
}else{
MessageDialog.showError(getContext(), "Ce TPE n'est pas encore configuré");
_startAutocomplete();
break;
}
case ERROR:
loader.dismiss();
MessageDialog.showError(getContext(), "Erreur lors du chargement du TPE");
break;
}
}
});
}
_startAutocomplete();
super.onViewCreated(view, savedInstanceState);
}
@SuppressLint("ClickableViewAccessibility")
void _startAutocomplete(){
pointDeVenteAdapter = new PointDeVenteAdapter(); pointDeVenteAdapter = new PointDeVenteAdapter();
RecyclerView recyclerView = binding.pointRecyclerView; RecyclerView recyclerView = binding.pointRecyclerView;
recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
binding.getRoot().setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// Vérifier si le clic est en dehors de l'autocomplete
if (binding.autocompleteContainer.getVisibility() == View.VISIBLE && !binding.pointDeVente.isEnabled()) {
int[] location = new int[2];
binding.autocompleteContainer.getLocationOnScreen(location);
Rect rect = new Rect(
location[0],
location[1],
location[0] + binding.autocompleteContainer.getWidth(),
location[1] + binding.autocompleteContainer.getHeight()
);
int x = (int) event.getRawX();
int y = (int) event.getRawY();
if (!rect.contains(x, y)) {
binding.autocompleteContainer.setVisibility(View.GONE);
}
}
}
return false;
});
binding.pointDeVente.addTextChangedListener(new TextWatcher() { binding.pointDeVente.addTextChangedListener(new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
@@ -112,7 +176,7 @@ public class ServerConfig extends Fragment {
@Override @Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if(!isUserTap) return; if(!isUserTap) return;
if(charSequence.toString().isEmpty() || charSequence.toString().length()==0){ if(charSequence.toString().isEmpty() || !binding.pointDeVente.isEnabled()){
recyclerView.setVisibility(View.GONE); recyclerView.setVisibility(View.GONE);
binding.autocompleteContainer.setVisibility(View.GONE); binding.autocompleteContainer.setVisibility(View.GONE);
return; return;
@@ -157,7 +221,34 @@ public class ServerConfig extends Fragment {
} }
}); });
super.onViewCreated(view, savedInstanceState); }
void _checkPdv(Tpe eTpe){
binding.numeroSerie.setText(eTpe.getNumeroSerie());
binding.brand.setText(eTpe.getTypeTerminal());
binding.model.setText(eTpe.getModeleAppareil());
binding.type.setText(eTpe.getTypeTerminal());
pointDeVenteViewModel.getPointDeVenteById(String.valueOf(eTpe.getPointDeVenteId())).observe(getViewLifecycleOwner(), new Observer<Result<PointDeVente>>() {
@Override
public void onChanged(Result<PointDeVente> pointDeVenteResult) {
switch (pointDeVenteResult.status){
case LOADING:
loader.show("Chargement du point de vente");
break;
case SUCCESS:
loader.dismiss();
binding.pointDeVente.setEnabled(false);
binding.pointDeVente.setText(pointDeVenteResult.data.getNom());
binding.validate.setClickable(false);
MessageDialog.showSuccess(getContext(), "Ce tpe est déjà configuré");
break;
case ERROR:
loader.dismiss();
MessageDialog.showError(getContext(), "Erreur lors du chargement du point de vente");
break;
}
}
});
} }
@Override @Override

View File

@@ -134,6 +134,10 @@ public class Settings extends Fragment {
authNavigator.navigate(agentManagement); authNavigator.navigate(agentManagement);
} }
}); });
binding.logout.setOnClickListener(v -> {
authNavigator.logOut();
});
} }

View File

@@ -1,26 +1,59 @@
package com.example.quiz; package com.example.quiz;
import android.annotation.SuppressLint;
import android.graphics.Color;
import android.os.Bundle; import android.os.Bundle;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.example.quiz.data.model.ParisResponse;
import com.example.quiz.data.model.enums.PariStatut;
import com.example.quiz.databinding.FragmentWinTicketBinding; import com.example.quiz.databinding.FragmentWinTicketBinding;
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.viewModel.LogsViewModel;
import com.example.quiz.viewModel.PariViewModel;
import com.google.android.material.appbar.MaterialToolbar; import com.google.android.material.appbar.MaterialToolbar;
import org.w3c.dom.Text;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import dagger.hilt.android.AndroidEntryPoint;
/** /**
* A simple {@link Fragment} subclass. * A simple {@link Fragment} subclass.
* Use the {@link WinTicket#newInstance} factory method to * Use the {@link WinTicket#newInstance} factory method to
* create an instance of this fragment. * create an instance of this fragment.
*/ */
@AndroidEntryPoint
public class WinTicket extends Fragment { public class WinTicket extends Fragment {
FragmentWinTicketBinding binding; FragmentWinTicketBinding binding;
PariViewModel pariViewModel;
LogsViewModel logsViewModel;
SharedPrefsHelper sharedPrefsHelper;
LoaderDialog loader;
public WinTicket() { public WinTicket() {
// Required empty public constructor // Required empty public constructor
@@ -48,6 +81,10 @@ public class WinTicket extends Fragment {
@Override @Override
public void onViewCreated(View view, Bundle savedInstanceState) { public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
pariViewModel = new ViewModelProvider(this).get(PariViewModel.class);
logsViewModel = new ViewModelProvider(this).get(LogsViewModel.class);
sharedPrefsHelper = SharedPrefsHelper.getInstance(getContext());
loader = new LoaderDialog(getContext());
binding.winTicketBtnBack.setOnClickListener(v -> { binding.winTicketBtnBack.setOnClickListener(v -> {
getActivity().onBackPressed(); getActivity().onBackPressed();
}); });
@@ -58,6 +95,173 @@ public class WinTicket extends Fragment {
}); });
scannerDialog.show(getParentFragmentManager(), "scanner"); scannerDialog.show(getParentFragmentManager(), "scanner");
}); });
binding.winTicketVerificationBtn.setOnClickListener(v -> {
String reference = binding.referenceTicket.getText().toString();
if(reference.isEmpty()){
MessageDialog.showError(getContext(), "Veuillez donner la reference du ticket");
return;
}
pariViewModel.getPariByNumero(reference).observe(getViewLifecycleOwner(), new Observer<Result<ParisResponse>>() {
@Override
public void onChanged(Result<ParisResponse> parisResponseResult) {
switch (parisResponseResult.status){
case LOADING:{
loader.show("Recherche du ticket");
break;
}
case ERROR:{
MessageDialog.showError(getContext(), parisResponseResult.message);
break;
}
case SUCCESS:{
if(parisResponseResult.data.getNumeroTicket().equals(reference)){
loader.dismiss();
_showDialog(parisResponseResult.data);
}else{
MessageDialog.showError(getContext(), "Le ticket n'existe pas");
}
break;
}
}
}
});
});
}
@SuppressLint("SetTextI18n")
void _showDialog(ParisResponse pari){
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.pay_confirmation_layout, null);
TextView statut = (TextView) view.findViewById(R.id.tv_statut);
statut.setText("Statut: "+String.valueOf(pari.getStatutPari()));
TextView dateHeure = (TextView) view.findViewById(R.id.tv_date_heure);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
dateHeure.setText(formatter.format(LocalDateTime.now()));
TextView numeroCourse = (TextView) view.findViewById(R.id.tv_numero_course);
numeroCourse.setText(String.valueOf(pari.getCourseNumero()));
TextView nomCourse = (TextView) view.findViewById(R.id.tv_nom_course);
nomCourse.setText(pari.getCourseNom());
TextView numeroTicket = (TextView) view.findViewById(R.id.tv_numero_ticket);
numeroTicket.setText(pari.getNumeroTicket());
TextView datePrise = (TextView) view.findViewById(R.id.tv_date_prise);
datePrise.setText(formatter.format(OffsetDateTime.parse(pari.getDateHeurePrise())));
TextView combinaison = (TextView) view.findViewById(R.id.tv_combinaison);
combinaison.setText(pari.getCombinaison());
TextView montant = (TextView) view.findViewById(R.id.tv_montant);
LinearLayout montantLayout = (LinearLayout) view.findViewById(R.id.tv_montant_layout);
Button confirmer = (Button) view.findViewById(R.id.btn_confirmer);
LinearLayout notesLayout = (LinearLayout) view.findViewById(R.id.notes_layout);
TextView notes = (TextView) view.findViewById(R.id.notes);
TextView messageStatut = (TextView) view.findViewById(R.id.tv_message_statut);
switch (pari.getStatutPari()){
case GAGNANT:{
messageStatut.setText("Veuillez confirmer le paiement de ce pari");
montant.setText(pari.getGainCalcule()+" CFA");
break;
}
case A_REMBOURSER:{
messageStatut.setText("Veuillez confirmer le remboursement de ce pari");
montant.setText(pari.getMiseTotale()+" CFA");
break;
}
case PAYE:{
messageStatut.setText("Ce pari a déjà été payé");
montant.setText(pari.getGainCalcule()+" CFA");
notesLayout.setVisibility(View.VISIBLE);
notes.setText(pari.getNotes());
confirmer.setVisibility(View.GONE);
break;
}
default:{
montantLayout.setVisibility(View.GONE);
statut.setTextColor(Color.parseColor("#cf1c08"));
messageStatut.setVisibility(View.GONE);
confirmer.setVisibility(View.GONE);
break;
}
}
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setView(view);
AlertDialog dialog = builder.create();
Button annuler = (Button) view.findViewById(R.id.btn_annuler);
annuler.setOnClickListener(v -> {
dialog.dismiss();
});
confirmer.setOnClickListener(v -> {
switch (pari.getStatutPari()){
case A_REMBOURSER:{
pariViewModel.rembourserPari(pari.getNumeroTicket()).observe(getViewLifecycleOwner(), new Observer<Result<ParisResponse>>() {
@Override
public void onChanged(Result<ParisResponse> pariResponseResult) {
switch (pariResponseResult.status){
case LOADING: {
loader.show("Remboursement en cours");
break;
}
case ERROR: {
loader.dismiss();
MessageDialog.showError(getContext(), pariResponseResult.message);
break;
}
case SUCCESS: {
loader.dismiss();
if(sharedPrefsHelper.get("id") == null){
MessageDialog.showError(getContext(), "Erreur de connexion");
return;
}
logsViewModel.insertLog(sharedPrefsHelper.get("id"), "REMBOURSEMENT TICKET", "Remboursement du ticket numéro "+ pari.getNumeroTicket()+" montant "+pari.getMiseTotale(), System.currentTimeMillis());
MessageDialog.showSuccess(getContext(), "Remboursement effectué avec succès");
binding.referenceTicket.setText("");
dialog.dismiss();
break;
}
}
}
});
break;
}
case GAGNANT:{
pariViewModel.payerPari(pari.getNumeroTicket()).observe(getViewLifecycleOwner(), new Observer<Result<ParisResponse>>() {
@Override
public void onChanged(Result<ParisResponse> pariResponseResult) {
switch (pariResponseResult.status){
case LOADING: {
loader.show("Paiement en cours");
break;
}
case ERROR: {
loader.dismiss();
MessageDialog.showError(getContext(), pariResponseResult.message);
break;
}
case SUCCESS: {
loader.dismiss();
if(sharedPrefsHelper.get("id") == null){
MessageDialog.showError(getContext(), "Erreur de connexion");
return;
}
logsViewModel.insertLog(sharedPrefsHelper.get("id"), "PAIEMENT TICKET", "Paiement du ticket numéro "+ pari.getNumeroTicket()+" montant "+pari.getGainCalcule(), System.currentTimeMillis());
binding.referenceTicket.setText("");
MessageDialog.showSuccess(getContext(), "Paiement effectué avec succès");
dialog.dismiss();
break;
}
}
}
});
break;
}
default:{
dialog.dismiss();
MessageDialog.showError(getContext(), "Action non comprise pour ce ticket");
binding.referenceTicket.setText("");
break;
}
}
});
dialog.show();
} }
@Override @Override

View File

@@ -1,9 +1,16 @@
package com.example.quiz.data.adapter; package com.example.quiz.data.adapter;
import static java.security.AccessController.getContext;
import android.graphics.Color;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@@ -17,21 +24,23 @@ import java.util.List;
public class LastBetsAdapter extends RecyclerView.Adapter<LastBetsAdapter.LastBetsViewHolder> { public class LastBetsAdapter extends RecyclerView.Adapter<LastBetsAdapter.LastBetsViewHolder> {
private List<ParisResponse> listeParis = new ArrayList<>(); // évite les NPE private List<ParisResponse> listeParis = new ArrayList<>(); // évite les NPE
private OnBetClick onBetClick; // peut être null si tu veux
public interface OnBetClick { private onPariClickListener listener;
public interface onPariClickListener {
void onItemClick(ParisResponse pari); void onItemClick(ParisResponse pari);
void onItemCancel(ParisResponse pari);
} }
public LastBetsAdapter(List<ParisResponse> listeParis, OnBetClick onBetClick) { public void setPariClickListener(onPariClickListener listener) {
this.listener = listener;
}
public LastBetsAdapter(List<ParisResponse> listeParis) {
if (listeParis != null) this.listeParis = listeParis; if (listeParis != null) this.listeParis = listeParis;
this.onBetClick = onBetClick;
} }
// Constructeur vide utile si tu veux créer puis setData ensuite
public LastBetsAdapter(OnBetClick onBetClick) {
this.onBetClick = onBetClick;
}
public void setData(List<ParisResponse> newList) { public void setData(List<ParisResponse> newList) {
if (newList == null) { if (newList == null) {
@@ -77,10 +86,44 @@ public class LastBetsAdapter extends RecyclerView.Adapter<LastBetsAdapter.LastBe
// Mise (défensif) // Mise (défensif)
holder.mise.setText("Mise: " + pari.getMiseTotale() + " CFA"); holder.mise.setText("Mise: " + pari.getMiseTotale() + " CFA");
holder.tvStatut.setText(pari.getStatutPari() != null ? String.valueOf(pari.getStatutPari()) : "Pas de statut");
switch (pari.getStatutPari()){
case ANNULE:{
holder.tvStatut.setTextColor(Color.RED);
holder.btnAnnuler.setVisibility(View.GONE);
holder.btnImprimer.setVisibility(View.GONE);
break;
}
case PAYE:{
holder.tvStatut.setTextColor(Color.GREEN);
holder.btnAnnuler.setVisibility(View.GONE);
holder.btnImprimer.setVisibility(View.GONE);
break;
}
case ENREGISTRE:{
holder.tvStatut.setTextColor(Color.YELLOW);
holder.btnAnnuler.setVisibility(View.VISIBLE);
holder.btnImprimer.setVisibility(View.VISIBLE);
break;
}
default:{
holder.tvStatut.setTextColor(Color.BLACK);
holder.btnAnnuler.setVisibility(View.GONE);
holder.btnImprimer.setVisibility(View.GONE);
break;
}
}
// click listener défensif holder.btnAnnuler.setOnClickListener(v -> {
holder.itemView.setOnClickListener(v -> { if (listener != null) {
if (onBetClick != null) onBetClick.onItemClick(pari); listener.onItemCancel(pari);
}
});
holder.btnImprimer.setOnClickListener(v -> {
if (listener != null) {
listener.onItemClick(pari);
}
}); });
} }
@@ -90,7 +133,8 @@ public class LastBetsAdapter extends RecyclerView.Adapter<LastBetsAdapter.LastBe
} }
public static class LastBetsViewHolder extends RecyclerView.ViewHolder { public static class LastBetsViewHolder extends RecyclerView.ViewHolder {
TextView betType, horses, course, mise, refenceTicket, typeOfCourse; TextView betType, horses, course, mise, refenceTicket, typeOfCourse, tvStatut;
Button btnAnnuler, btnImprimer;;
public LastBetsViewHolder(@NonNull View itemView) { public LastBetsViewHolder(@NonNull View itemView) {
super(itemView); super(itemView);
@@ -100,6 +144,9 @@ public class LastBetsAdapter extends RecyclerView.Adapter<LastBetsAdapter.LastBe
mise = itemView.findViewById(R.id.last_bet_mise); mise = itemView.findViewById(R.id.last_bet_mise);
refenceTicket = itemView.findViewById(R.id.reference_ticket); refenceTicket = itemView.findViewById(R.id.reference_ticket);
typeOfCourse = itemView.findViewById(R.id.type_of_course); typeOfCourse = itemView.findViewById(R.id.type_of_course);
btnAnnuler = itemView.findViewById(R.id.btn_annuler);
btnImprimer = itemView.findViewById(R.id.btn_imprimer);
tvStatut = itemView.findViewById(R.id.tv_statut);
} }
} }
} }

View File

@@ -1,6 +1,7 @@
package com.example.quiz.data.model; package com.example.quiz.data.model;
import java.io.Serializable; import java.io.Serializable;
import java.time.temporal.TemporalAccessor;
import java.util.List; import java.util.List;
public class ParisResponse implements Serializable { public class ParisResponse implements Serializable {
@@ -58,7 +59,10 @@ public class ParisResponse implements Serializable {
PAYE, PAYE,
ANNULE, ANNULE,
PERDANT, PERDANT,
GAGNANT GAGNANT,
A_REMBOURSER,
REMBOURSE,
ECHEC_CACUL
} }
// ================= INNER CLASS ================= // ================= INNER CLASS =================

View File

@@ -0,0 +1,36 @@
package com.example.quiz.data.model;
public class ResponseError {
private String message;
private int status;
private String timestamp;
public ResponseError(){
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
}

View File

@@ -20,7 +20,7 @@ import retrofit2.converter.gson.GsonConverterFactory;
@Module @Module
@InstallIn(SingletonComponent.class) @InstallIn(SingletonComponent.class)
public class ApiClient { public class ApiClient {
private static final String BASE_URL = "https://boxer-adapting-bluegill.ngrok-free.app/api/"; private static final String BASE_URL = "https://alr.pmu.ml/api/";
@Provides @Provides

View File

@@ -45,9 +45,17 @@ public interface ApiService {
@GET("paris/agent/{agentId}/today") @GET("paris/agent/{agentId}/today")
Call<List<ParisResponse>> derniersParis(@Path("agentId") String agentId); Call<List<ParisResponse>> derniersParis(@Path("agentId") String agentId);
@PATCH("paris/numero/{numeroTicket}/statut") @PATCH("paris/numero/{numeroTicket}/cancel")
Call<ParisResponse> annulerPari(@Path("numeroTicket") String numeroTicket, Call<ParisResponse> annulerPari(@Path("numeroTicket") String numeroTicket);
@Body() CancelParisPaylaod cancelParisPaylaod); @PATCH("paris/numero/{numeroTicket}/rembourser")
Call<ParisResponse> rembourserPari(@Path("numeroTicket") String numeroTicket);
@PATCH("paris/numero/{numeroTicket}/pay")
Call<ParisResponse> payerPari(@Path("numeroTicket") String numeroTicket);
@GET("paris/numero/{numeroTicket}")
Call<ParisResponse> getPariByNumero(@Path("numeroTicket") String numeroTicket);
@GET("paris/agent/{agentId}/solde/course/{courseId}") @GET("paris/agent/{agentId}/solde/course/{courseId}")
Call<SoldeResponse> getSoldeByCourse(@Path("agentId") String createdBy, @Path("courseId") String courseId); Call<SoldeResponse> getSoldeByCourse(@Path("agentId") String createdBy, @Path("courseId") String courseId);
@@ -58,9 +66,15 @@ public interface ApiService {
@POST("terminaux") @POST("terminaux")
Call<TpeResponse> createTpe(@Body Tpe tpe); Call<TpeResponse> createTpe(@Body Tpe tpe);
@GET("terminaux/{id}")
Call<TpeResponse> getTpeById(@Path("id") String id);
@GET("points-de-vente") @GET("points-de-vente")
Call<PagedModel<PointDeVente>> getPointsDeVente(@Query("nom") String nom); Call<PagedModel<PointDeVente>> getPointsDeVente(@Query("nom") String nom);
@GET("points-de-vente/{id}")
Call<PointDeVente> getPointDeVenteById(@Path("id") String id);
@PATCH("agents/me/pin") @PATCH("agents/me/pin")
Call<User> changePin(@Body ChangePin pin); Call<User> changePin(@Body ChangePin pin);

View File

@@ -61,7 +61,7 @@ public class StompManager {
} }
// URL de connexion WebSocket // URL de connexion WebSocket
String url = "wss://boxer-adapting-bluegill.ngrok-free.app/ws"; String url = "wss://alr.pmu.ml/ws";
try { try {
// Créer le client STOMP // Créer le client STOMP

View File

@@ -5,11 +5,14 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import com.example.quiz.data.model.Course; import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.ResponseError;
import com.example.quiz.data.model.Restriction; import com.example.quiz.data.model.Restriction;
import com.example.quiz.data.model.dtos.auth.User; import com.example.quiz.data.model.dtos.auth.User;
import com.example.quiz.data.remote.ApiService; import com.example.quiz.data.remote.ApiService;
import com.example.quiz.utils.Result; import com.example.quiz.utils.Result;
import com.google.gson.Gson;
import java.io.IOException;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@@ -34,7 +37,14 @@ public class AgentRepository {
if (response.isSuccessful()) { if (response.isSuccessful()) {
liveAgents.postValue(Result.success(response.body())); liveAgents.postValue(Result.success(response.body()));
} else { } else {
liveAgents.postValue(Result.error(response.message())); try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveAgents.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
} }
@Override @Override
@@ -54,7 +64,14 @@ public class AgentRepository {
if (response.isSuccessful()) { if (response.isSuccessful()) {
liveAgent.postValue(Result.success(response.body())); liveAgent.postValue(Result.success(response.body()));
} else { } else {
liveAgent.postValue(Result.error(response.message())); try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveAgent.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
} }
@Override @Override
@@ -74,7 +91,14 @@ public class AgentRepository {
if (response.isSuccessful()) { if (response.isSuccessful()) {
liveAvailableBets.postValue(Result.success(response.body())); liveAvailableBets.postValue(Result.success(response.body()));
} else { } else {
liveAvailableBets.postValue(Result.error(response.message())); try{
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveAvailableBets.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){
liveAvailableBets.postValue(Result.error(e.getMessage()));
}
} }
} }
@Override @Override
@@ -94,7 +118,14 @@ public class AgentRepository {
if (response.isSuccessful()) { if (response.isSuccessful()) {
liveSetAccess.postValue(Result.success(null)); liveSetAccess.postValue(Result.success(null));
} else { } else {
liveSetAccess.postValue(Result.error(response.message())); try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveSetAccess.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
} }
@Override @Override
@@ -114,7 +145,14 @@ public class AgentRepository {
if (response.isSuccessful()) { if (response.isSuccessful()) {
liveSetRestrictions.postValue(Result.success(null)); liveSetRestrictions.postValue(Result.success(null));
} else { } else {
liveSetRestrictions.postValue(Result.error(response.message())); try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveSetRestrictions.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
} }
@Override @Override

View File

@@ -7,8 +7,10 @@ import androidx.lifecycle.MutableLiveData;
import com.example.quiz.data.model.Course; import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.PagedModel; import com.example.quiz.data.model.PagedModel;
import com.example.quiz.data.model.ResponseError;
import com.example.quiz.data.remote.ApiService; import com.example.quiz.data.remote.ApiService;
import com.example.quiz.utils.Result; import com.example.quiz.utils.Result;
import com.google.gson.Gson;
import javax.inject.Inject; import javax.inject.Inject;
@@ -33,22 +35,15 @@ public class CourseRepository {
public void onResponse(Call<PagedModel<Course>> call, Response<PagedModel<Course>> response) { public void onResponse(Call<PagedModel<Course>> call, Response<PagedModel<Course>> response) {
if(response.isSuccessful()){ if(response.isSuccessful()){
liveCourses.postValue(Result.success(response.body())); liveCourses.postValue(Result.success(response.body()));
// PagedModel<Course> openedPagesCourses = new PagedModel<>();
// List<Course> listOfCourses = new ArrayList<>();
// for(Course course: response.body().getContent()){
// if(course.getStatut().equals(OPENED_STATUT)){
// listOfCourses.add(course);
// }
// }
//// openedPagesCourses.setTotalPages(response.body().getTotalPages());
//// openedPagesCourses.setTotalElements(response.body().getTotalElements());
//// openedPagesCourses.setPageable(response.body().getPageable());
//// openedPagesCourses.setNumberOfElements(response.body().getNumberOfElements());
//// openedPagesCourses.setSize(response.body().getSize());
//// openedPagesCourses.setContent(listOfCourses);
// liveCourses.postValue(Result.success(response.body()));
}else{ }else{
liveCourses.postValue(Result.error(response.message())); try{
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveCourses.postValue(Result.error(errorResponse.getMessage()));
} catch (Exception e) {
throw new RuntimeException(e);
}
} }
} }

View File

@@ -5,6 +5,7 @@ import android.util.Log;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import com.example.quiz.data.model.ResponseError;
import com.example.quiz.data.model.dtos.auth.ChangePin; import com.example.quiz.data.model.dtos.auth.ChangePin;
import com.example.quiz.data.model.dtos.auth.LoginPayload; import com.example.quiz.data.model.dtos.auth.LoginPayload;
import com.example.quiz.data.model.dtos.auth.LoginResponse; import com.example.quiz.data.model.dtos.auth.LoginResponse;
@@ -12,6 +13,9 @@ import com.example.quiz.data.model.dtos.auth.User;
import com.example.quiz.data.remote.ApiService; import com.example.quiz.data.remote.ApiService;
import com.example.quiz.data.remote.TokenManager; import com.example.quiz.data.remote.TokenManager;
import com.example.quiz.utils.Result; import com.example.quiz.utils.Result;
import com.google.gson.Gson;
import java.io.IOException;
import javax.inject.Inject; import javax.inject.Inject;
@@ -37,10 +41,16 @@ public class LoginRepository {
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) { public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
if(response.isSuccessful()){ if(response.isSuccessful()){
liveLogin.postValue(Result.success(response.body())); liveLogin.postValue(Result.success(response.body()));
Log.d("TOKEN", response.body().getToken());
tokenManager.saveToken(response.body().getToken()); tokenManager.saveToken(response.body().getToken());
}else{ }else{
liveLogin.postValue(Result.error(response.toString())); try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveLogin.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
} }
@@ -64,7 +74,14 @@ public class LoginRepository {
if(response.isSuccessful()) { if(response.isSuccessful()) {
liveUser.postValue(Result.success(response.body())); liveUser.postValue(Result.success(response.body()));
}else { }else {
liveUser.postValue(Result.error(response.message())); try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveUser.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
} }
@Override @Override

View File

@@ -1,13 +1,17 @@
package com.example.quiz.data.repository; package com.example.quiz.data.repository;
import android.util.Log;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import com.example.quiz.data.model.MiseInitiale; import com.example.quiz.data.model.MiseInitiale;
import com.example.quiz.data.model.PariMise; import com.example.quiz.data.model.PariMise;
import com.example.quiz.data.model.ResponseError;
import com.example.quiz.data.remote.ApiService; import com.example.quiz.data.remote.ApiService;
import com.example.quiz.data.remote.TokenManager; import com.example.quiz.data.remote.TokenManager;
import com.example.quiz.utils.Result; import com.example.quiz.utils.Result;
import com.google.gson.Gson;
import java.util.List; import java.util.List;
@@ -34,7 +38,14 @@ public class PariMiseRepository {
if (response.isSuccessful()) { if (response.isSuccessful()) {
livePariMise.postValue(Result.success(response.body())); livePariMise.postValue(Result.success(response.body()));
}else{ }else{
livePariMise.postValue(Result.error(response.message())); try{
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
livePariMise.postValue(Result.error(errorResponse.getMessage()));
} catch (Exception e) {
throw new RuntimeException(e);
}
} }
} }
@Override @Override

View File

@@ -8,10 +8,12 @@ import androidx.lifecycle.MutableLiveData;
import com.example.quiz.data.model.Pari; import com.example.quiz.data.model.Pari;
import com.example.quiz.data.model.ParisResponse; import com.example.quiz.data.model.ParisResponse;
import com.example.quiz.data.model.ResponseError;
import com.example.quiz.data.model.dtos.paris.CancelParisPaylaod; import com.example.quiz.data.model.dtos.paris.CancelParisPaylaod;
import com.example.quiz.data.model.dtos.paris.SoldeResponse; import com.example.quiz.data.model.dtos.paris.SoldeResponse;
import com.example.quiz.data.remote.ApiService; import com.example.quiz.data.remote.ApiService;
import com.example.quiz.utils.Result; import com.example.quiz.utils.Result;
import com.google.gson.Gson;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -44,13 +46,10 @@ public class PariRepository {
} else { } else {
// On récupère l'erreur exacte envoyée par le backend // On récupère l'erreur exacte envoyée par le backend
try { try {
Map<String, String> errorBody = Collections.emptyMap(); String error = response.errorBody().string();
if(response.errorBody() != null){ Gson gson = new Gson();
errorBody = (Map<String, String>) response.errorBody(); ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
} pariResponse.postValue(Result.error(errorResponse.getMessage()));
Log.d("PariRepository", response.errorBody().toString());
pariResponse.postValue(Result.error(errorBody.get("message")));
} catch (Exception e) { } catch (Exception e) {
pariResponse.postValue(Result.error("Erreur serveur")); pariResponse.postValue(Result.error("Erreur serveur"));
} }
@@ -76,10 +75,10 @@ public class PariRepository {
derniersParis.postValue(Result.success(response.body())); derniersParis.postValue(Result.success(response.body()));
}else{ }else{
try{ try{
String errorBody = response.errorBody() != null ? String error = response.errorBody().string();
response.errorBody().string() : "Erreur inconnue"; Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
derniersParis.postValue(Result.error(errorBody)); derniersParis.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){ }catch (Exception e){
derniersParis.postValue(Result.error(e.getMessage())); derniersParis.postValue(Result.error(e.getMessage()));
} }
@@ -95,21 +94,74 @@ public class PariRepository {
return derniersParis; return derniersParis;
} }
public LiveData<Result<ParisResponse>> annulerPari(String numeroTicket){ public LiveData<Result<ParisResponse>> payTicket(String numeroTicket){
MutableLiveData<Result<ParisResponse>> pariResponse = new MutableLiveData<>(); MutableLiveData<Result<ParisResponse>> pariResponse = new MutableLiveData<>();
pariResponse.setValue(Result.loading()); pariResponse.setValue(Result.loading());
CancelParisPaylaod cancelParisPaylaod = new CancelParisPaylaod("ANNULE"); apiService.payerPari(numeroTicket).enqueue(new Callback<ParisResponse>(){
apiService.annulerPari(numeroTicket, cancelParisPaylaod).enqueue(new Callback<ParisResponse>(){
@Override @Override
public void onResponse(Call<ParisResponse> call, Response<ParisResponse> response) { public void onResponse(Call<ParisResponse> call, Response<ParisResponse> response) {
if(response.isSuccessful()){ if(response.isSuccessful()){
pariResponse.postValue(Result.success(response.body())); pariResponse.postValue(Result.success(response.body()));
}else{ }else{
try{ try{
String errorBody = response.errorBody() != null ? String error = response.errorBody().string();
response.errorBody().string() : "Erreur inconnue"; Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
pariResponse.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){
pariResponse.postValue(Result.error(e.getMessage()));
}
}
};
@Override
public void onFailure(Call<ParisResponse> call, Throwable throwable) {
pariResponse.postValue(Result.error(throwable.getMessage()));
}
});
return pariResponse;
}
pariResponse.postValue(Result.error(errorBody)); public LiveData<Result<ParisResponse>> rembourserTicket(String numeroTicket){
MutableLiveData<Result<ParisResponse>> pariResponse = new MutableLiveData<>();
pariResponse.setValue(Result.loading());
apiService.rembourserPari(numeroTicket).enqueue(new Callback<ParisResponse>(){
@Override
public void onResponse(Call<ParisResponse> call, Response<ParisResponse> response) {
if(response.isSuccessful()){
pariResponse.postValue(Result.success(response.body()));
}else{
try{
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
pariResponse.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){
pariResponse.postValue(Result.error(e.getMessage()));
}
}
}
@Override
public void onFailure(Call<ParisResponse> call, Throwable throwable) {
pariResponse.postValue(Result.error(throwable.getMessage()));
}
});
return pariResponse;
}
public LiveData<Result<ParisResponse>> annulerPari(String numeroTicket){
MutableLiveData<Result<ParisResponse>> pariResponse = new MutableLiveData<>();
pariResponse.setValue(Result.loading());
apiService.annulerPari(numeroTicket).enqueue(new Callback<ParisResponse>(){
@Override
public void onResponse(Call<ParisResponse> call, Response<ParisResponse> response) {
if(response.isSuccessful()){
pariResponse.postValue(Result.success(response.body()));
}else{
try{
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
pariResponse.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){ }catch (Exception e){
pariResponse.postValue(Result.error(e.getMessage())); pariResponse.postValue(Result.error(e.getMessage()));
} }
@@ -134,7 +186,10 @@ public class PariRepository {
solde.postValue(Result.success(response.body())); solde.postValue(Result.success(response.body()));
}else{ }else{
try{ try{
solde.postValue(Result.error(response.errorBody().string())); String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
solde.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){ }catch (Exception e){
solde.postValue(Result.error(e.getMessage())); solde.postValue(Result.error(e.getMessage()));
} }
@@ -159,7 +214,10 @@ public class PariRepository {
solde.postValue(Result.success(response.body())); solde.postValue(Result.success(response.body()));
}else{ }else{
try { try {
solde.postValue(Result.error(response.errorBody().string())); String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
solde.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){ }catch (Exception e){
solde.postValue(Result.error(e.getMessage())); solde.postValue(Result.error(e.getMessage()));
} }
@@ -174,4 +232,32 @@ public class PariRepository {
return solde; return solde;
} }
public LiveData<Result<ParisResponse>> getPariByNumero(String numeroTicket) {
MutableLiveData<Result<ParisResponse>> pari = new MutableLiveData<>();
pari.setValue(Result.loading());
apiService.getPariByNumero(numeroTicket).enqueue(new Callback<ParisResponse>() {
@Override
public void onResponse(Call<ParisResponse> call, Response<ParisResponse> response) {
if (response.isSuccessful()) {
pari.postValue(Result.success(response.body()));
}else{
try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
pari.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){
pari.postValue(Result.error(e.getMessage()));
}
}
}
@Override
public void onFailure(Call<ParisResponse> call, Throwable throwable) {
pari.postValue(Result.error(throwable.getMessage()));
}
});
return pari;
}
} }

View File

@@ -5,10 +5,14 @@ import androidx.lifecycle.MutableLiveData;
import com.example.quiz.data.model.PagedModel; import com.example.quiz.data.model.PagedModel;
import com.example.quiz.data.model.PointDeVente; import com.example.quiz.data.model.PointDeVente;
import com.example.quiz.data.model.ResponseError;
import com.example.quiz.data.remote.ApiService; import com.example.quiz.data.remote.ApiService;
import com.example.quiz.utils.Result; import com.example.quiz.utils.Result;
import com.google.gson.Gson;
import java.io.IOException;
import javax.inject.Inject; import javax.inject.Inject;
import retrofit2.*; import retrofit2.*;
@@ -36,18 +40,14 @@ public class PointDeVenteRepository {
if (response.isSuccessful() && response.body() != null) { if (response.isSuccessful() && response.body() != null) {
result.postValue(Result.success(response.body())); result.postValue(Result.success(response.body()));
} else { } else {
String errorMessage = "Erreur inconnue";
try { try {
if (response.errorBody() != null) { String error = response.errorBody().string();
errorMessage = response.errorBody().string(); Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
result.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
} }
} catch (Exception e) {
errorMessage = e.getMessage();
}
result.postValue(Result.error(errorMessage));
} }
} }
@@ -62,4 +62,33 @@ public class PointDeVenteRepository {
return result; return result;
} }
public LiveData<Result<PointDeVente>> getPointDeVenteById(String id) {
MutableLiveData<Result<PointDeVente>> result = new MutableLiveData<>();
result.setValue(Result.loading());
apiService.getPointDeVenteById(id).enqueue(new Callback<PointDeVente>() {
@Override
public void onResponse(Call<PointDeVente> call, Response<PointDeVente> response) {
if(response.isSuccessful()){
result.postValue(Result.success(response.body()));
}else{
try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
result.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void onFailure(Call<PointDeVente> call, Throwable throwable) {
result.postValue(Result.error(throwable.getMessage()));
}
});
return result;
}
} }

View File

@@ -3,10 +3,12 @@ package com.example.quiz.data.repository;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import com.example.quiz.data.model.ResponseError;
import com.example.quiz.data.model.Tpe; import com.example.quiz.data.model.Tpe;
import com.example.quiz.data.model.TpeResponse; import com.example.quiz.data.model.TpeResponse;
import com.example.quiz.data.remote.ApiService; import com.example.quiz.data.remote.ApiService;
import com.example.quiz.utils.Result; import com.example.quiz.utils.Result;
import com.google.gson.Gson;
import javax.inject.Inject; import javax.inject.Inject;
@@ -33,7 +35,43 @@ public class TpeRepository {
if (response.isSuccessful()) { if (response.isSuccessful()) {
tpeLiveData.postValue(Result.success(response.body())); tpeLiveData.postValue(Result.success(response.body()));
} else { } else {
tpeLiveData.postValue(Result.error(response.message())); try{
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
tpeLiveData.postValue(Result.error(errorResponse.getMessage()));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@Override
public void onFailure(Call<TpeResponse> call, Throwable throwable) {
tpeLiveData.postValue(Result.error(throwable.getMessage()));
}
});
return tpeLiveData;
}
public LiveData<Result<TpeResponse>> getTpeById(String id) {
MutableLiveData<Result<TpeResponse>> tpeLiveData = new MutableLiveData<>();
tpeLiveData.setValue(Result.loading());
apiService.getTpeById(id).enqueue(new Callback<TpeResponse>() {
@Override
public void onResponse(Call<TpeResponse> call, Response<TpeResponse> response) {
if (response.isSuccessful()) {
tpeLiveData.postValue(Result.success(response.body()));
} else {
try{
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
tpeLiveData.postValue(Result.error(errorResponse.getMessage()));
} catch (Exception e) {
throw new RuntimeException(e);
}
} }
} }

View File

@@ -61,6 +61,7 @@ public class AuthNavigator {
return; return;
} }
if (sessionManager.isExpired()) { if (sessionManager.isExpired()) {
if(!dialogIsShowing()){
showPinDialog(() -> { showPinDialog(() -> {
sessionManager.updateLastExpiredDate(); sessionManager.updateLastExpiredDate();
fragmentManager.beginTransaction() fragmentManager.beginTransaction()
@@ -68,7 +69,7 @@ public class AuthNavigator {
.addToBackStack(null) .addToBackStack(null)
.commit(); .commit();
}); });
}
} else { } else {
fragmentManager.beginTransaction() fragmentManager.beginTransaction()
.replace(R.id.nav_host_fragment_content_main, destinationFragment) .replace(R.id.nav_host_fragment_content_main, destinationFragment)
@@ -143,6 +144,15 @@ public class AuthNavigator {
return dialog.isShowing(); return dialog.isShowing();
} }
public boolean isSessionExpired(){
return sessionManager.isExpired();
}
public void updatedLastExpiredDate(){
sessionManager.updateLastExpiredDate();
}
private void loginSuccess(LoginResponse loginResponse){ private void loginSuccess(LoginResponse loginResponse){
String terminalId = prefsHelper.get("terminalId"); String terminalId = prefsHelper.get("terminalId");
if(terminalId == null){ if(terminalId == null){
@@ -158,4 +168,14 @@ public class AuthNavigator {
prefsHelper.save("isSupAgent", isSupAgent); prefsHelper.save("isSupAgent", isSupAgent);
} }
public void logOut (){
prefsHelper.save("id", null);
prefsHelper.save("firstName", null);
prefsHelper.save("lastName", null);
prefsHelper.save("profile", null);
prefsHelper.save("code", null);
prefsHelper.save("isSupAgent", null);
sessionManager.setToExpire();
}
} }

View File

@@ -31,6 +31,10 @@ public class SessionManager {
lastExpiredDate = LocalDateTime.now(); lastExpiredDate = LocalDateTime.now();
} }
public void setToExpire(){
lastExpiredDate = null;
}
public boolean isExpired() { public boolean isExpired() {
if (lastExpiredDate == null) { if (lastExpiredDate == null) {
return true; return true;

View File

@@ -0,0 +1,275 @@
package com.example.quiz.utils;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.RemoteException;
import android.util.Log;
import com.sunmi.peripheral.printer.InnerPrinterCallback;
import com.sunmi.peripheral.printer.InnerPrinterManager;
import com.sunmi.peripheral.printer.InnerResultCallback;
import com.sunmi.peripheral.printer.SunmiPrinterService;
import java.util.List;
import java.util.function.Consumer;
public class SunmiPrinterManager {
private static final String TAG = "SunmiPrinterManager";
private static SunmiPrinterManager instance;
private static final int MAX_CHAR_2_INCH = 32;
private static Context context;
private SunmiPrinterService sunmiPrinter;
private SunmiPrinterManager() {}
public static SunmiPrinterManager getInstance(Context ctx) {
if (instance == null) {
instance = new SunmiPrinterManager();
context = ctx.getApplicationContext();
}
return instance;
}
// 🔌 Bind UNE SEULE FOIS
public void connectPrinter(Consumer<Boolean> status) {
Log.d("######", "Point d'entrée printer");
try {
InnerPrinterManager.getInstance().bindService(context, new InnerPrinterCallback() {
@Override
protected void onConnected(SunmiPrinterService service) {
Log.d("######", "Connecté printer");
sunmiPrinter = service;
status.accept(true);
}
@Override
protected void onDisconnected() {
Log.d("######", "Déconnecté printer");
sunmiPrinter = null;
status.accept(false);
}
});
} catch (Exception e) {
Log.e(TAG, "#################Erreur bindService"+String.valueOf(e));
}
}
// ✅ simple check
// 🖨️ Impression robuste
public void printText(String text, PrinterListener listener) {
try {
sunmiPrinter.printText(text + "\n", new InnerResultCallback() {
@Override
public void onRunResult(boolean isSuccess) {
if(!isSuccess){
try {
throw new Exception("Impression", new Throwable("Erreur lors d'impression!"));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@Override
public void onReturnString(String result) {
// rarement utile
}
@Override
public void onRaiseException(int code, String msg) {
listener.onError(msg);
listener.onResult(code);
}
@Override
public void onPrintResult(int code, String msg) {
listener.onResult(code);
listener.onError(msg);
}
});
} catch (Exception e) {
if (listener != null) {
listener.onError(e.getMessage());
}
}
}
public int getMaxChar(){
return MAX_CHAR_2_INCH;
}
public boolean printPari(Bitmap logo, Bitmap barcode, String numeroTicket, String text){
try{
printSimpleImage(logo);
printTextSimple("\n"+separationText()+"\n");
printSimpleImage(barcode);
setAlignment(1, new PrinterListener() {
@Override
public void onResult(int code) {
}
@Override
public void onError(String errorMessage) {
}
});
printTextSimple(numeroTicket);
printTextSimple("\n"+separationText()+"\n");
setAlignment(0, new PrinterListener() {
@Override
public void onResult(int code) {}
@Override
public void onError(String errorMessage) {}
});
printTextSimple(text);
printTextSimple("\n"+separationText()+"\n");
setAlignment(1, new PrinterListener() {
@Override
public void onResult(int code) {}
@Override
public void onError(String errorMessage) {}
});
printTextSimple("Powered by PMU-MALI");
printTextSimple("\n"+separationText()+"\n");
printTextSimple(" ");
printTextSimple(" ");
return true;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String separationText(){
return "-".repeat(MAX_CHAR_2_INCH);
}
public void printSimpleImage(Bitmap bitmap){
printImage(bitmap, new PrinterListener() {
@Override
public void onResult(int code) {
Log.d(TAG, "Print OK");
}
@Override
public void onError(String errorMessage) {
Log.e(TAG, errorMessage);
}
});
}
// version simple
public void printTextSimple(String text) {
printText(text, new PrinterListener() {
@Override
public void onResult(int code) {
Log.d(TAG, "Print OK");
}
@Override
public void onError(String errorMessage) {
Log.e(TAG, errorMessage);
}
});
}
// Dans SunmiPrinterManager.java
public void setAlignment(int alignment, PrinterListener listener) {
try {
// Appel au SDK Sunmi : 0=gauche, 1=centre, 2=droite
sunmiPrinter.setAlignment(alignment, new InnerResultCallback() {
@Override
public void onRunResult(boolean isSuccess) throws RemoteException {
if(!isSuccess){
try {
throw new Exception("Alignement", new Throwable("L'alignement n'a pas pu être défini"));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@Override
public void onReturnString(String result) throws RemoteException {
}
@Override
public void onRaiseException(int code, String msg) throws RemoteException {
listener.onError(msg);
listener.onResult(code);
}
@Override
public void onPrintResult(int code, String msg) throws RemoteException {
}
});
} catch (Exception e) {
if (listener != null) listener.onError(e.getMessage());
}
}
public void printImage(Bitmap bitmap, PrinterListener listener){
try {
// La plupart des imprimantes Sunmi utilisent cette méthode
// Le paramètre '0' correspond généralement à l'alignement (0 = gauche)
sunmiPrinter.printBitmap(bitmap, new InnerResultCallback() {
@Override
public void onRunResult(boolean isSuccess) {
if(!isSuccess){
try {
throw new Exception("Impression", new Throwable("Erreur lors d'impression d'une image!"));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@Override
public void onReturnString(String result) {
// Pas utile
}
@Override
public void onRaiseException(int code, String msg) {
Log.e(TAG, "onRaiseException: "+String.valueOf(code));
listener.onResult(code);
listener.onError(msg);
}
@Override
public void onPrintResult(int code, String msg) {
Log.e(TAG, "onPrintResult: "+String.valueOf(code));
listener.onResult(code);
listener.onError(msg);
}
// N'oublie pas les autres callbacks vides (onRunResult, etc.)
});
} catch (Exception e) {
listener.onError(e.getMessage());
}
}
public int printerStatus(){
try {
return sunmiPrinter.updatePrinterState();
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
public interface PrinterListener {
void onResult(int code);
void onError(String errorMessage);
}
}

View File

@@ -24,10 +24,17 @@ public class PariViewModel extends ViewModel {
private LiveData<Result<ParisResponse>> pariAnnule; private LiveData<Result<ParisResponse>> pariAnnule;
private LiveData<Result<ParisResponse>> pariPaye;
private LiveData<Result<ParisResponse>> pariByNumero;
private LiveData<Result<SoldeResponse>> solde; private LiveData<Result<SoldeResponse>> solde;
private LiveData<Result<SoldeResponse>> soldeByDay; private LiveData<Result<SoldeResponse>> soldeByDay;
private LiveData<Result<ParisResponse>> pariRembourse;
@Inject @Inject
public PariViewModel(PariRepository repository){ public PariViewModel(PariRepository repository){
this.pariRepository = repository; this.pariRepository = repository;
@@ -57,4 +64,19 @@ public class PariViewModel extends ViewModel {
soldeByDay = pariRepository.getSoldeByDay(agentId, day); soldeByDay = pariRepository.getSoldeByDay(agentId, day);
return soldeByDay; return soldeByDay;
} }
public LiveData<Result<ParisResponse>> getPariByNumero(String numeroTicket){
pariByNumero = pariRepository.getPariByNumero(numeroTicket);
return pariByNumero;
}
public LiveData<Result<ParisResponse>> payerPari(String numeroTicket){
pariPaye = pariRepository.payTicket(numeroTicket);
return pariPaye;
}
public LiveData<Result<ParisResponse>> rembourserPari(String numeroTicket){
pariRembourse = pariRepository.rembourserTicket(numeroTicket);
return pariRembourse;
}
} }

View File

@@ -17,6 +17,8 @@ public class PointDeVenteViewModel extends ViewModel {
private final PointDeVenteRepository pointDeVenteRepository; private final PointDeVenteRepository pointDeVenteRepository;
private LiveData<Result<PagedModel<PointDeVente>>> pointsDeVente; private LiveData<Result<PagedModel<PointDeVente>>> pointsDeVente;
private LiveData<Result<PointDeVente>> pointDeVenteById;
@Inject @Inject
public PointDeVenteViewModel(PointDeVenteRepository pointDeVenteRepository){ public PointDeVenteViewModel(PointDeVenteRepository pointDeVenteRepository){
this.pointDeVenteRepository = pointDeVenteRepository; this.pointDeVenteRepository = pointDeVenteRepository;
@@ -26,4 +28,9 @@ public class PointDeVenteViewModel extends ViewModel {
this.pointsDeVente = pointDeVenteRepository.getPointsDeVente(search); this.pointsDeVente = pointDeVenteRepository.getPointsDeVente(search);
return this.pointsDeVente; return this.pointsDeVente;
} }
public LiveData<Result<PointDeVente>> getPointDeVenteById(String id) {
pointDeVenteById = pointDeVenteRepository.getPointDeVenteById(id);
return pointDeVenteById;
}
} }

View File

@@ -18,6 +18,8 @@ public class TpeViewModel extends ViewModel {
private LiveData<Result<TpeResponse>> tpeLiveData; private LiveData<Result<TpeResponse>> tpeLiveData;
private LiveData<Result<TpeResponse>> tpeByIdLiveData;
@Inject @Inject
public TpeViewModel(TpeRepository repository){ public TpeViewModel(TpeRepository repository){
this.tpeRepository = repository; this.tpeRepository = repository;
@@ -27,4 +29,9 @@ public class TpeViewModel extends ViewModel {
tpeLiveData = tpeRepository.createTpe(tpe); tpeLiveData = tpeRepository.createTpe(tpe);
return tpeLiveData; return tpeLiveData;
} }
public LiveData<Result<TpeResponse>> getTpeById(String id){
tpeByIdLiveData = tpeRepository.getTpeById(id);
return tpeByIdLiveData;
}
} }

View File

@@ -1,4 +1,5 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
@@ -10,7 +11,7 @@
android:layout_width="64dp" android:layout_width="64dp"
android:layout_height="64dp" android:layout_height="64dp"
android:src="@android:drawable/ic_delete" android:src="@android:drawable/ic_delete"
android:tint="#F44336"/> app:tint="#F44336" />
<TextView <TextView
android:id="@+id/txtMessage" android:id="@+id/txtMessage"

View File

@@ -1,4 +1,5 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
@@ -10,7 +11,8 @@
android:layout_width="64dp" android:layout_width="64dp"
android:layout_height="64dp" android:layout_height="64dp"
android:src="@android:drawable/checkbox_on_background" android:src="@android:drawable/checkbox_on_background"
android:tint="#4CAF50"/> android:outlineSpotShadowColor="#4CAF50"
/>
<TextView <TextView
android:id="@+id/txtMessage" android:id="@+id/txtMessage"

View File

@@ -29,7 +29,7 @@
android:textSize="14sp" android:textSize="14sp"
android:drawableStart="@drawable/hashtag" android:drawableStart="@drawable/hashtag"
android:background="@drawable/edittext_outline_white" android:background="@drawable/edittext_outline_white"
android:inputType="number" android:inputType="text"
/> />
<ImageButton <ImageButton
android:id="@+id/scan_ticket_btn" android:id="@+id/scan_ticket_btn"

View File

@@ -54,20 +54,20 @@
android:text="ANNULER TICKET" android:text="ANNULER TICKET"
android:textAllCaps="false" android:textAllCaps="false"
android:textColor="#FFFFFF"/> android:textColor="#FFFFFF"/>
<Button <!-- <Button-->
android:id="@+id/report_btn" <!-- android:id="@+id/report_btn"-->
android:layout_width="match_parent" <!-- android:layout_width="match_parent"-->
android:layout_height="57dp" <!-- android:layout_height="57dp"-->
android:textSize="21sp" <!-- android:textSize="21sp"-->
android:textAlignment="textStart" <!-- android:textAlignment="textStart"-->
android:layout_marginVertical="4sp" <!-- android:layout_marginVertical="4sp"-->
android:background="@drawable/rounded_button_green" <!-- android:background="@drawable/rounded_button_green"-->
android:fontFamily="sans-serif-medium" <!-- android:fontFamily="sans-serif-medium"-->
android:backgroundTint="@color/primary_green" <!-- android:backgroundTint="@color/primary_green"-->
android:drawableLeft="@drawable/tpe" <!-- android:drawableLeft="@drawable/tpe"-->
android:text="RAPPORTS" <!-- android:text="RAPPORTS"-->
android:textAllCaps="false" <!-- android:textAllCaps="false"-->
android:textColor="#FFFFFF"/> <!-- android:textColor="#FFFFFF"/>-->
<Button <Button
android:id="@+id/last_bets_btn" android:id="@+id/last_bets_btn"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -68,7 +68,7 @@
android:textColor="#FFFFFF"/> android:textColor="#FFFFFF"/>
<Button <Button
android:id="@+id/settings" android:id="@+id/settings"
android:tag="@id/tag_pin_exempt" android:tag="tag_pin_exempt"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="57dp" android:layout_height="57dp"
android:textSize="23sp" android:textSize="23sp"

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -212,23 +213,28 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="30sp" android:layout_marginTop="30sp"
android:gravity="center"> android:gravity="center"
android:orientation="horizontal">
<Button <Button
android:id="@+id/cancel" android:id="@+id/cancel"
android:layout_width="200dp" android:layout_width="0dp"
android:layout_marginRight="3sp"
android:layout_height="40dp" android:layout_height="40dp"
android:layout_weight="1"
android:layout_marginEnd="8dp"
android:background="@color/primary_red" android:background="@color/primary_red"
android:text="@string/cancel"/> android:text="@string/cancel"/>
<Button <Button
android:id="@+id/validate" android:id="@+id/validate"
android:layout_marginLeft="3sp" android:layout_width="0dp"
android:layout_width="200dp"
android:layout_height="40dp" android:layout_height="40dp"
android:layout_weight="1"
android:layout_marginStart="8dp"
android:background="@color/primary_green" android:background="@color/primary_green"
android:text="@string/validate"/> android:text="@string/validate"/>
</LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout>
</ScrollView> </ScrollView>
</FrameLayout> </FrameLayout>

View File

@@ -12,19 +12,19 @@
android:gravity="start" android:gravity="start"
android:orientation="vertical" android:orientation="vertical"
android:visibility="visible"> android:visibility="visible">
<Button <!-- <Button-->
android:id="@+id/agent" <!-- android:id="@+id/agent"-->
android:layout_width="match_parent" <!-- android:layout_width="match_parent"-->
android:layout_height="60dp" <!-- android:layout_height="60dp"-->
android:textSize="21sp" <!-- android:textSize="21sp"-->
android:textAlignment="center" <!-- android:textAlignment="center"-->
android:layout_marginVertical="4sp" <!-- android:layout_marginVertical="4sp"-->
android:background="@drawable/rounded_button_green" <!-- android:background="@drawable/rounded_button_green"-->
android:fontFamily="sans-serif-medium" <!-- android:fontFamily="sans-serif-medium"-->
android:backgroundTint="@color/primary_green" <!-- android:backgroundTint="@color/primary_green"-->
android:text="@string/agents_setting" <!-- android:text="@string/agents_setting"-->
android:textAllCaps="false" <!-- android:textAllCaps="false"-->
android:textColor="#FFFFFF"/> <!-- android:textColor="#FFFFFF"/>-->
<Button <Button
android:id="@+id/change_pin" android:id="@+id/change_pin"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -40,6 +40,7 @@
android:textColor="#FFFFFF"/> android:textColor="#FFFFFF"/>
<Button <Button
android:id="@+id/server_config" android:id="@+id/server_config"
android:tag="tag_pin_exempt"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="60dp"
android:textSize="21sp" android:textSize="21sp"
@@ -66,6 +67,7 @@
android:textColor="#FFFFFF"/> android:textColor="#FFFFFF"/>
<Button <Button
android:id="@+id/logs" android:id="@+id/logs"
android:tag="tag_pin_exempt"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="60dp"
android:textSize="21sp" android:textSize="21sp"

View File

@@ -29,7 +29,7 @@
android:textSize="14sp" android:textSize="14sp"
android:drawableStart="@drawable/hashtag" android:drawableStart="@drawable/hashtag"
android:background="@drawable/edittext_outline_white" android:background="@drawable/edittext_outline_white"
android:inputType="number" android:inputType="text"
/> />
<ImageButton <ImageButton
android:id="@+id/scan_ticket_btn" android:id="@+id/scan_ticket_btn"

View File

@@ -13,10 +13,10 @@
android:padding="18dp" android:padding="18dp"
android:background="@drawable/course_item_border"> android:background="@drawable/course_item_border">
<LinearLayout <LinearLayout
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="horizontal"
android:layout_gravity="center_vertical"> android:layout_gravity="start">
<ImageView <ImageView
android:layout_width="50dp" android:layout_width="50dp"
android:layout_height="50dp" android:layout_height="50dp"
@@ -24,14 +24,15 @@
</ImageView> </ImageView>
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<TextView <TextView
android:id="@+id/tvName" android:id="@+id/tvName"
android:text="GP SANGARE"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="18sp" android:textSize="16sp"
android:textColor="@color/white" android:textColor="@color/white"
android:textFontWeight="500" android:textFontWeight="500"
android:fontFamily="sans-serif-medium"> android:fontFamily="sans-serif-medium">

View File

@@ -2,18 +2,30 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:orientation="vertical"
android:padding="12dp" android:padding="8dp"
android:layout_marginVertical="10dp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@color/white"> android:background="@color/white">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
android:gravity="center_vertical" android:gravity="end">
android:layout_marginBottom="8dp"> <TextView
android:id="@+id/tv_statut"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Statut"
android:textSize="20sp">
</TextView>
</LinearLayout>
<!-- Première ligne : Course et Type -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView <TextView
android:id="@+id/last_bet_course" android:id="@+id/last_bet_course"
@@ -21,14 +33,13 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:text="Course: 5" android:text="Course: 5"
android:textSize="16sp" android:textSize="14sp"
android:gravity="start" android:padding="2dp" />
android:padding="4dp" />
<com.google.android.material.divider.MaterialDivider <com.google.android.material.divider.MaterialDivider
android:layout_width="1dp" android:layout_width="1dp"
android:layout_height="24dp" android:layout_height="16dp"
android:layout_marginHorizontal="8dp" android:layout_marginHorizontal="4dp"
app:dividerColor="@color/black" /> app:dividerColor="@color/black" />
<TextView <TextView
@@ -37,24 +48,18 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:text="QUARTE + TIERCE" android:text="QUARTE + TIERCE"
android:textSize="16sp" android:textSize="12sp"
android:gravity="end" android:gravity="end"
android:padding="4dp" /> android:padding="2dp" />
</LinearLayout> </LinearLayout>
<com.google.android.material.divider.MaterialDivider <!-- Deuxième ligne : Référence et Type de pari -->
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginBottom="5dp"
app:dividerColor="@color/black"/>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
android:gravity="center_vertical" android:gravity="center_vertical"
android:layout_marginBottom="3dp"> android:layout_marginTop="2dp">
<TextView <TextView
android:id="@+id/reference_ticket" android:id="@+id/reference_ticket"
@@ -62,14 +67,13 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:text="12573829288" android:text="12573829288"
android:textSize="16sp" android:textSize="12sp"
android:gravity="start" android:padding="2dp" />
android:padding="4dp" />
<com.google.android.material.divider.MaterialDivider <com.google.android.material.divider.MaterialDivider
android:layout_width="1dp" android:layout_width="1dp"
android:layout_height="24dp" android:layout_height="16dp"
android:layout_marginHorizontal="8dp" android:layout_marginHorizontal="4dp"
app:dividerColor="@color/black" /> app:dividerColor="@color/black" />
<TextView <TextView
@@ -78,25 +82,70 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:text="TIERCE" android:text="TIERCE"
android:textSize="16sp" android:textSize="13sp"
android:textFontWeight="900" android:textStyle="bold"
android:gravity="end" android:gravity="end"
android:padding="4dp" /> android:padding="2dp" />
</LinearLayout> </LinearLayout>
<!-- Troisième ligne : Chevaux et Mise -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginTop="2dp">
<TextView <TextView
android:id="@+id/last_bet_horses" android:id="@+id/last_bet_horses"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Horses: 3-7-9" android:text="Horses: 3-7-9"
android:textSize="16sp" android:textSize="13sp"
android:layout_marginTop="4dp"/> android:padding="2dp" />
<TextView <TextView
android:id="@+id/last_bet_mise" android:id="@+id/last_bet_mise"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Mise: 500 CFA" android:text="Mise: 500 CFA"
android:textSize="16sp" android:textSize="13sp"
android:layout_marginTop="4dp"/> android:padding="2dp" />
</LinearLayout>
<!-- Séparateur avant le dropdown -->
<com.google.android.material.divider.MaterialDivider
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginVertical="6dp"
app:dividerColor="@color/black" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<Button
android:id="@+id/btn_annuler"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginEnd="8dp"
android:background="@drawable/rounded_button_red"
android:text="Annuler" />
<Button
android:id="@+id/btn_imprimer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="8dp"
android:background="@drawable/rounded_button_green"
android:text="Imprimer" />
</LinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -0,0 +1,283 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:cardElevation="8dp"
app:cardBackgroundColor="@android:color/white">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<!-- En-tête avec statut -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="16dp">
<TextView
android:id="@+id/tv_statut"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Statut: ENREGISTRÉ"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="@color/primary_green" />
<TextView
android:id="@+id/tv_date_heure"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Date et heure"
android:textSize="12sp"
android:textColor="@color/colorAccent" />
</LinearLayout>
<!-- Séparateur -->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/login_background"
android:layout_marginBottom="16dp" />
<!-- Numéro de la course -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="12dp">
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="Numéro course :"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="@color/primary_green" />
<TextView
android:id="@+id/tv_numero_course"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="5"
android:textSize="14sp"
android:textColor="@color/primary_green" />
</LinearLayout>
<!-- Nom de la course -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="12dp">
<TextView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="Nom course :"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="@color/primary_green" />
<TextView
android:id="@+id/tv_nom_course"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Prix de l'Arc de Triomphe"
android:textSize="14sp"
android:textColor="@color/primary_green" />
</LinearLayout>
<!-- Numéro Ticket -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="12dp">
<TextView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="N° Ticket :"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="@color/primary_green" />
<TextView
android:id="@+id/tv_numero_ticket"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="T-2024-001234"
android:textSize="14sp"
android:textColor="@color/primary_green"
android:textStyle="bold" />
</LinearLayout>
<!-- Date de prise -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="12dp">
<TextView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="Date prise :"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="@color/primary_green" />
<TextView
android:id="@+id/tv_date_prise"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="15/03/2024 14:30"
android:textSize="14sp"
android:textColor="@color/primary_green" />
</LinearLayout>
<!-- Combinaison -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="12dp">
<TextView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="Combinaison :"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="@color/primary_green" />
<TextView
android:id="@+id/tv_combinaison"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="5 - 8 - 12 - 15"
android:textSize="14sp"
android:textColor="@color/primary_green"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:id="@+id/notes_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone"
android:layout_marginBottom="12sp"
android:layout_gravity="start">
<TextView
android:id="@+id/notes"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="2 ordres, 6 desordres"
android:textSize="14sp"
android:textColor="@color/primary_green"
android:textStyle="bold" />
</LinearLayout>
<!-- Montant -->
<LinearLayout
android:id="@+id/tv_montant_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="20dp">
<TextView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="Montant :"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="@color/primary_green" />
<TextView
android:id="@+id/tv_montant"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="1 000 FCFA"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@color/primary_green" />
</LinearLayout>
<!-- Séparateur -->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/background_gray"
android:layout_marginBottom="16dp" />
<!-- Message dynamique selon statut -->
<TextView
android:id="@+id/tv_message_statut"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Veuillez confirmer l'enregistrement de ce pari"
android:textSize="14sp"
android:textColor="@color/primary_green"
android:gravity="center"
android:layout_marginBottom="20dp"
android:padding="5dp"
android:background="@color/green_opacity_30"
android:visibility="visible" />
<!-- Boutons Confirmer et Annuler -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_annuler"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:layout_marginEnd="8dp"
android:text="Annuler"
android:textSize="14sp"
app:cornerRadius="8dp"
style="@style/Widget.Material3.Button.OutlinedButton" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_confirmer"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:layout_marginStart="8dp"
android:text="Confirmer"
android:textSize="14sp"
app:cornerRadius="8dp"
style="@style/Widget.Material3.Button" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

View File

@@ -4,4 +4,9 @@
<item>Espèce</item> <item>Espèce</item>
<item>Orange Money</item> <item>Orange Money</item>
</string-array> </string-array>
<string-array name="action_options">
<item>Imprimer</item>
<item>Annuler</item>
</string-array>
</resources> </resources>

View File

@@ -14,6 +14,7 @@ navigationUi = "2.6.0"
googleAndroidLibrariesMapsplatformSecretsGradlePlugin = "2.0.1" googleAndroidLibrariesMapsplatformSecretsGradlePlugin = "2.0.1"
okhttp = "4.12.0" okhttp = "4.12.0"
playServicesMaps = "18.1.0" playServicesMaps = "18.1.0"
printerlibrary = "1.0.23"
recyclerviewV7 = "28.0.0" recyclerviewV7 = "28.0.0"
retrofit = "2.11.0" retrofit = "2.11.0"
rxandroid = "1.2.1" rxandroid = "1.2.1"
@@ -55,6 +56,7 @@ navigation-fragment = { group = "androidx.navigation", name = "navigation-fragme
navigation-ui = { group = "androidx.navigation", name = "navigation-ui", version.ref = "navigationUi" } navigation-ui = { group = "androidx.navigation", name = "navigation-ui", version.ref = "navigationUi" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
play-services-maps = { group = "com.google.android.gms", name = "play-services-maps", version.ref = "playServicesMaps" } play-services-maps = { group = "com.google.android.gms", name = "play-services-maps", version.ref = "playServicesMaps" }
printerlibrary = { module = "com.sunmi:printerlibrary", version.ref = "printerlibrary" }
recyclerview-v7 = { module = "com.android.support:recyclerview-v7", version.ref = "recyclerviewV7" } recyclerview-v7 = { module = "com.android.support:recyclerview-v7", version.ref = "recyclerviewV7" }
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
room-compiler = { module = "androidx.room:room-compiler", version.ref = "roomCommonJvm" } room-compiler = { module = "androidx.room:room-compiler", version.ref = "roomCommonJvm" }

View File

@@ -25,6 +25,7 @@ import com.anggastudio.printama.constants.PW;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
/** /**
* Printama is a lightweight Android library for printing text and bitmaps to ESC/POS Bluetooth * Printama is a lightweight Android library for printing text and bitmaps to ESC/POS Bluetooth
@@ -280,6 +281,8 @@ public class Printama {
Pref.setBoolean(Pref.IS_PRINTER_3INCH, is3inches); Pref.setBoolean(Pref.IS_PRINTER_3INCH, is3inches);
} }
public static boolean is3inchesPrinter() { public static boolean is3inchesPrinter() {
return Pref.getBoolean(Pref.IS_PRINTER_3INCH); return Pref.getBoolean(Pref.IS_PRINTER_3INCH);
} }
@@ -311,11 +314,27 @@ public class Printama {
}); });
} }
public void testAllPaperStatusCommands(){
public int checkPaperStatus(){ _printama.connect(printama -> {
return _util.checkPaperStatus(); _util.testAllPaperStatusCommands();
});
} }
public void checkPaperStatus(Consumer<String> status){
_printama.connect(printama -> {
String paperStatus = _util.checkPaperStatus();
status.accept(paperStatus);
});
}
public void isQueued(Consumer<Integer> status){
_printama.connect(printama -> {
int isQueued = _util.isQueued();
status.accept(isQueued);
});
}
public boolean isConnected() { public boolean isConnected() {
return _util.isConnected(); return _util.isConnected();
} }
@@ -361,34 +380,48 @@ public class Printama {
} }
public void printTextBuilder(StringBuilder text, Bitmap bitmap, String numeroTicket,Bitmap barCode){
public void printTextBuilder(StringBuilder text, Bitmap bitmap, String numeroTicket, Bitmap barCode, PrintCallback callback) {
_printama.connect(printama -> { _printama.connect(printama -> {
try {
_util.resetPrinter(); _util.resetPrinter();
_util.setBold(); _util.setBold();
_util.printImage(bitmap); _util.printImage(bitmap);
_util.printText(printama.lineSeparator()+"\n"); _util.printText(printama.lineSeparator() + "\n");
_util.setBold(); _util.setBold();
_util.printImage(barCode); _util.printImage(barCode);
_util.setBold(); _util.setBold();
_util.setNormalText(); _util.setNormalText();
_util.setAlign(PA.CENTER); _util.setAlign(PA.CENTER);
_util.printText(numeroTicket); _util.printText(numeroTicket);
_util.printText("\n"+printama.lineSeparator()+"\n"); _util.printText("\n" + printama.lineSeparator() + "\n");
_util.setBold(); _util.setBold();
_util.setNormalText(); _util.setNormalText();
_util.setAlign(0); _util.setAlign(0);
_util.setAlign(PA.LEFT); _util.setAlign(PA.LEFT);
_util.printText(text.toString()); _util.printText(text.toString());
_util.printText(printama.lineSeparator()+"\n"); _util.printText(printama.lineSeparator() + "\n");
_util.setBold(); _util.setBold();
_util.setNormalText(); _util.setNormalText();
_util.setAlign(PA.CENTER); _util.setAlign(PA.CENTER);
_util.printText("Powered by PMU-MALI"); _util.printText("Powered by PMU-MALI");
_util.printText("\n"+printama.lineSeparator()+"\n"); _util.printText("\n" + printama.lineSeparator() + "\n");
_util.printText("\n\n\n"); _util.printText("\n\n\n");
printama.feedPaper(); printama.feedPaper();
printama.close(); printama.close();
}); if (callback != null) callback.onResult(true, null);
} catch (Exception e) {
if (callback != null) callback.onResult(false, e.getMessage());
e.printStackTrace();
}
}, error -> {
if (callback != null) callback.onResult(false, error);
}
);
}
public interface PrintCallback{
void onResult(boolean success, String errorMessage);
} }
public void printSold(Bitmap bitmap, String title, StringBuilder text){ public void printSold(Bitmap bitmap, String title, StringBuilder text){
@@ -554,7 +587,19 @@ public class Printama {
//---------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------
public void printText(String text) { public void printText(String text) {
printText(text, PA.LEFT); _printama.connect((printama)->{
_util.printText(text);
});
}
public void myPrintText(String text, Consumer<String> callback) {
_printama.connect(printama -> {
if(_util.printText(text)){
callback.accept("L'impression a été effectuée avec succès");
}else{
callback.accept("L'impression a échoué");
}
});
} }
/** /**
@@ -708,6 +753,8 @@ public class Printama {
return spaces.toString(); return spaces.toString();
} }
//---------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------
// COLUMN FORMATTERS // COLUMN FORMATTERS
//---------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------

View File

@@ -144,12 +144,25 @@ class PrinterUtil {
String s = StrUtil.encodeNonAscii(text); String s = StrUtil.encodeNonAscii(text);
btOutputStream.write(s.getBytes()); btOutputStream.write(s.getBytes());
return true; return true;
} catch (IOException e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return false; return false;
} }
} }
String textTest(String text){
try{
String s = StrUtil.encodeNonAscii(text);
btOutputStream.write(s.getBytes());
btOutputStream.flush();
int available = btInputStream.available();
return String.valueOf(available);
}catch (Exception e){
e.printStackTrace();
return "Erreur: "+e.getMessage();
}
}
boolean printTextBuilder(StringBuilder text){ boolean printTextBuilder(StringBuilder text){
try { try {
String tspl = ""+ text + "\r\n"; String tspl = ""+ text + "\r\n";
@@ -162,6 +175,61 @@ class PrinterUtil {
} }
} }
/**
* Vérifie si l'imprimante a une opération en attente ou en cours
*
* @return
* 0 = Aucune opération (imprimante prête)
* 1 = Opération en cours d'impression
* 2 = Opération en attente (buffer plein)
* -1 = Erreur / impossible de déterminer
*/
public int isQueued() {
try {
// Vider le buffer d'entrée avant d'envoyer la commande
while (btInputStream != null && btInputStream.available() > 0) {
btInputStream.read();
}
// Commande DLE EOT 1 - Statut en temps réel
byte[] command = new byte[]{0x10, 0x04, 0x01};
btOutputStream.write(command);
btOutputStream.flush();
// Attendre 100ms pour la réponse
Thread.sleep(100);
// Lire la réponse (1 octet)
if (btInputStream != null && btInputStream.available() > 0) {
byte[] response = new byte[1];
int bytesRead = btInputStream.read(response);
if (bytesRead > 0) {
byte status = response[0];
// Bit 1 (0x02) = Imprimante en cours d'impression
if ((status & 0x02) != 0) {
return 1; // Opération en cours
}
// Bit 3 (0x08) = Buffer plein / attente
if ((status & 0x08) != 0) {
return 2; // Opération en attente
}
return 0; // Aucune opération
}
}
// Pas de réponse
return -1;
} catch (Exception e) {
Log.e(TAG, "Erreur isQueued: " + e.getMessage());
return -1;
}
}
void setNormalizedForAll(){ void setNormalizedForAll(){
printUnicode(NORMALIZED_FOR_ALL); printUnicode(NORMALIZED_FOR_ALL);
} }
@@ -265,39 +333,190 @@ class PrinterUtil {
} }
} }
public int checkPaperStatus() { public void testAllPaperStatusCommands() {
// Liste des commandes à tester
int[][] commands = {
{0x1D, 0x72, 0x01}, // GS r 1 - Standard paper status
{0x10, 0x04, 0x01}, // DLE EOT 1 - Real-time status
{0x10, 0x04, 0x04}, // DLE EOT 4 - Paper sensor status
{0x1B, 0x76, 0x00}, // ESC v 0 - Paper sensor
{0x1D, 0x61, 0x01}, // GS a 1 - Enable real-time mode
{0x1D, 0x49, 0x01}, // GS I 1 - Printer ID
{0x1B, 0x69, 0x00} // ESC i 0 - Printer status
};
for (int i = 0; i < commands.length; i++) {
try { try {
// Certaines imprimantes doivent être en mode "real-time" Log.e("TEST", "========================================");
// Commande GS a 1 pour activer le mode "real-time" Log.e("TEST", "Test commande " + i + ": " + bytesToHex(commands[i]));
byte[] realtimeMode = new byte[]{0x1D, 0x61, 0x01};
btOutputStream.write(realtimeMode);
btOutputStream.flush();
Thread.sleep(50); // Nettoyer buffer
while (btInputStream.available() > 0) {
// Ensuite la commande de statut btInputStream.read();
byte[] statusCommand = new byte[]{0x1D, 0x72, 0x01};
btOutputStream.write(statusCommand);
btOutputStream.flush();
Thread.sleep(200);
// Lire la réponse
byte[] response = new byte[4];
int bytesRead = btInputStream.read(response);
if (bytesRead > 0) {
// Traiter la réponse...
return 0;
} }
return -1; // Envoyer commande
byte[] cmd = new byte[commands[i].length];
for (int j = 0; j < commands[i].length; j++) {
cmd[j] = (byte) commands[i][j];
}
btOutputStream.write(cmd);
btOutputStream.flush();
// Attendre réponse
Thread.sleep(300);
// Lire réponse
byte[] response = new byte[16];
int totalRead = 0;
long startTime = System.currentTimeMillis();
while (totalRead < response.length && System.currentTimeMillis() - startTime < 1000) {
if (btInputStream.available() > 0) {
int read = btInputStream.read(response, totalRead, response.length - totalRead);
if (read > 0) {
totalRead += read;
}
}
Thread.sleep(20);
}
if (totalRead > 0) {
Log.e("TEST", "✓ RÉPONSE REÇUE ! " + totalRead + " octets");
StringBuilder hex = new StringBuilder();
for (int j = 0; j < totalRead; j++) {
hex.append(String.format("%02X ", response[j]));
}
Log.e("TEST", " Hex: " + hex.toString());
// Interpréter la réponse selon la commande
if (i == 0 && totalRead >= 1) { // GS r 1
interpretGS_r1(response[0]);
} else if (i == 1 && totalRead >= 1) { // DLE EOT 1
interpretDLE_EOT_1(response[0]);
} else if (i == 2 && totalRead >= 1) { // DLE EOT 4
interpretDLE_EOT_4(response[0]);
} else if (i == 5 && totalRead >= 1) { // GS I 1
Log.e("TEST", " ID Imprimante: " + new String(response, 0, totalRead));
}
} else {
Log.e("TEST", "✗ AUCUNE RÉPONSE");
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); Log.e("TEST", "Erreur commande " + i, e);
}
}
}
private void interpretGS_r1(byte status) {
Log.e("TEST", "Interprétation GS r 1:");
Log.e("TEST", " Bit 0 (couvercle): " + ((status & 0x01) != 0 ? "OUVERT" : "FERMÉ"));
Log.e("TEST", " Bit 2 (papier): " + ((status & 0x04) != 0 ? "FAIBLE" : "OK"));
Log.e("TEST", " Bit 5 (papier): " + ((status & 0x20) != 0 ? "VIDE" : "OK"));
}
private void interpretDLE_EOT_1(byte status) {
Log.e("TEST", "Interprétation DLE EOT 1:");
Log.e("TEST", " Bit 2 (papier): " + ((status & 0x04) != 0 ? "VIDE" : "OK"));
}
private void interpretDLE_EOT_4(byte status) {
Log.e("TEST", "Interprétation DLE EOT 4:");
Log.e("TEST", " Bit 0 (couvercle): " + ((status & 0x01) != 0 ? "OUVERT" : "FERMÉ"));
Log.e("TEST", " Bit 2 (papier): " + ((status & 0x04) != 0 ? "FAIBLE" : "OK"));
Log.e("TEST", " Bit 5 (papier): " + ((status & 0x20) != 0 ? "VIDE" : "OK"));
}
private String bytesToHex(int[] bytes) {
StringBuilder sb = new StringBuilder();
for (int b : bytes) {
sb.append(String.format("%02X ", b));
}
return sb.toString();
}
public String getPrinterPaperStatus() {
try{
byte[] command = new byte[]{0x10, 0x04, 0x04};
btOutputStream.write(command);
btOutputStream.flush();
Thread.sleep(300);
int status = btInputStream.read();
return String.valueOf(status);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String checkPaperStatus() {
try {
// 1. Envoyer la commande d'activation ASB
byte[] cmd = {0x1D, 0x61, (byte) 0xFF};
btOutputStream.write(cmd);
btOutputStream.flush();
// 2. Attendre un peu plus longtemps pour la réponse
Thread.sleep(500);
// 3. Lire tout ce qui est disponible dans le buffer
int available = btInputStream.available();
if (available > 0) {
byte[] buffer = new byte[available];
btInputStream.read(buffer);
// On convertit le buffer en une chaîne lisible (Hex)
StringBuilder sb = new StringBuilder();
for (byte b : buffer) {
sb.append(String.format("%02X ", b));
}
return "Status: " + sb.toString();
} else {
return "0 (Aucune réponse)";
}
} catch (Exception e) {
return "Erreur: " + e.getMessage();
}
}
private int readStatusByte(int timeoutMs) throws IOException, InterruptedException {
long start = System.currentTimeMillis();
// petite attente initiale (important en Bluetooth)
Thread.sleep(50);
while (System.currentTimeMillis() - start < timeoutMs) {
int available = btInputStream.available();
Log.e("AVAILABLE", "STATUS: "+String.valueOf(available) );
if (available > 0) {
byte[] buffer = new byte[available];
int read = btInputStream.read(buffer);
if (read > 0) {
int value = buffer[0] & 0xFF;
Log.d("Printama", "Raw bytes: " + bytesToHex(buffer, read));
return value; // on prend le premier byte
}
}
Thread.sleep(20);
}
return -1; return -1;
} }
private String bytesToHex(byte[] bytes, int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(String.format("%02X ", bytes[i]));
} }
return sb.toString();
}
boolean printImage(Bitmap bitmap, int width) { boolean printImage(Bitmap bitmap, int width) {
return printImage(PA.CENTER, bitmap, width); return printImage(PA.CENTER, bitmap, width);