70% of features done!

This commit is contained in:
OnlyPapy98
2025-12-12 17:55:12 +01:00
parent dc93d1320f
commit b3d94ad038
31 changed files with 3334 additions and 285 deletions

View File

@@ -4,22 +4,34 @@ import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.example.quiz.data.model.Pari;
import com.example.quiz.databinding.FragmentAnnulationTicketBinding;
import com.example.quiz.utils.Result;
import com.example.quiz.viewModel.PariViewModel;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link AnnulationTicket#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class AnnulationTicket extends Fragment {
FragmentAnnulationTicketBinding binding;
PariViewModel viewModel;
public AnnulationTicket() {
// Required empty public constructor
}
@@ -47,10 +59,45 @@ public class AnnulationTicket extends Fragment {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
viewModel = new ViewModelProvider(this).get(PariViewModel.class);
binding.annuleTicketBtnBack.setOnClickListener(v->{
getActivity().onBackPressed();
});
binding.scanTicketBtn.setOnClickListener(v -> {
ScannerDialog scannerDialog = new ScannerDialog();
scannerDialog.setOnBarcodeScannedListener(code -> {
binding.referenceTicket.setText(code);
});
scannerDialog.show(getParentFragmentManager(), "scanner");
});
binding.annuleTicketBtn.setOnClickListener(v->{
String reference = binding.referenceTicket.getText().toString();
if(reference.isEmpty()){
Toast.makeText(getContext(),"Entrez la référence du ticket", Toast.LENGTH_SHORT).show();
return;
}
viewModel.annulerPari(reference).observe(getViewLifecycleOwner(), new Observer<Result<Pari>>() {
@Override
public void onChanged(Result<Pari> pariResult) {
switch (pariResult.status){
case LOADING:{
Toast.makeText(getContext(), "Chargement...", Toast.LENGTH_SHORT).show();
break;
}
case ERROR:{
Toast.makeText(getContext(), pariResult.message, Toast.LENGTH_SHORT).show();
break;
}
case SUCCESS:{
Toast.makeText(getContext(), "Ticket annulé avec succès", Toast.LENGTH_SHORT).show();
binding.referenceTicket.setText("");
}
}
}
});
});
}
@Override

View File

@@ -45,6 +45,7 @@ import com.example.quiz.data.model.enums.PariStatut;
import com.example.quiz.databinding.FragmentBetValidationBinding;
import com.example.quiz.utils.BluetoothUtils;
import com.example.quiz.utils.Result;
import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.PariViewModel;
import com.example.quiz.viewModel.SharedViewModel;
import com.google.android.material.appbar.MaterialToolbar;
@@ -77,20 +78,24 @@ public class BetValidation extends Fragment {
private AlertDialog dialog;
private int nombreX;
private boolean order;
private long mise;
private TypeOfBet typeOfBet;
SharedPrefsHelper prefsHelper;
private Reunion reunion;
private Course course;
private int coeff;
private int mise;
private ActivityResultLauncher<Intent> enableBluetoothLauncher;
@@ -114,6 +119,7 @@ public class BetValidation extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prefsHelper = SharedPrefsHelper.getInstance(getContext());
}
@Override
@@ -139,8 +145,8 @@ public class BetValidation extends Fragment {
return;
}
coeff = Integer.parseInt(charSequence.toString());
calculateMise(selectedHorses.getValue().size());
binding.mise.setText(String.valueOf(mise+" CFA"));
calculateMise(selectedHorses.getValue());
}
@Override
@@ -180,7 +186,15 @@ public class BetValidation extends Fragment {
textView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
textView.setOnClickListener(v -> {
final List<String> horses = new ArrayList<>(selectedHorses.getValue());
if (horses.contains(horse)) {
if(horses.size() >= shared.typeOfBet.getValue().getNumberOfHorse() && horse.equals("X")){
Toast.makeText(getContext(), "Vous ne pouvez plus sélectionner X", Toast.LENGTH_SHORT).show();
return;
}
if(_notClickable(horses) && horse.equals("X")){
Toast.makeText(getContext(), "Vous ne pouvez plus sélectionner X", Toast.LENGTH_SHORT).show();
return;
}
if (horses.contains(horse) && !horse.equals("X")) {
horses.remove(horse);
selectedHorses.setValue(horses);
v.setSelected(false);
@@ -196,15 +210,27 @@ public class BetValidation extends Fragment {
.collect(Collectors.joining("-"));
binding.combination.setText( combinationText);
});
return textView;
}
boolean _notClickable(List<String> selectedHorses){
int numberOfElement = 0;
if(shared.typeOfBet.getValue().getNumberOfHorse() < 2){
return true;
}
for(String horse: selectedHorses){
numberOfElement = horse.equals("X")?numberOfElement+1:numberOfElement;
}
nombreX = numberOfElement;
return numberOfElement == shared.typeOfBet.getValue().getNumberOfHorse() - 1;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
shared = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
setSelectedTypeOfBetImage();
pariViewModel = new ViewModelProvider(this).get(PariViewModel.class);
typeOfBet = shared.typeOfBet.getValue();
reunion = shared.selectedReunion.getValue();
@@ -241,8 +267,12 @@ public class BetValidation extends Fragment {
selectedHorses.observe(getViewLifecycleOwner(), new Observer<List<String>>() {
@Override
public void onChanged(List<String> horses) {
calculateMise(horses.size());
binding.mise.setText(String.valueOf(mise+" CFA"));
calculateMise(horses);
if(horses.size() > shared.typeOfBet.getValue().getNumberOfHorse()){
binding.elargie.setVisibility(View.VISIBLE);
}else{
binding.elargie.setVisibility(View.GONE);
}
if(shared.typeOfBet.getValue().getNumberOfHorse() > 2 && horses.size() >= shared.typeOfBet.getValue().getNumberOfHorse()){
binding.order.setVisibility(View.VISIBLE);
}else{
@@ -252,8 +282,7 @@ public class BetValidation extends Fragment {
});
binding.order.setOnCheckedChangeListener((buttonView, isChecked) -> {
order = isChecked;
calculateMise(selectedHorses.getValue().size());
binding.mise.setText(String.valueOf(mise+" CFA"));
calculateMise(selectedHorses.getValue());
});
binding.betValidateBtn.setOnClickListener(v->{
@@ -274,10 +303,10 @@ public class BetValidation extends Fragment {
}
Pari pari = new Pari(
generate12Digits(),
shared.typeOfBet.getValue().getName(),
"GAGNANT",
mise,
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss").format(LocalDateTime.now()),
true,
@@ -285,25 +314,11 @@ public class BetValidation extends Fragment {
new PariCourseDto(shared.selectedCourse.getValue().getId()),
selectedHorses.getValue(),
order?new ArrayList<String>(): selectedHorses.getValue(),
order,
"MULTI_4"
!order,
"MULTI_4",
prefsHelper.get("code")
);
pariViewModel.createPari(pari).observe(getViewLifecycleOwner(),new Observer<Result<Pari>>() {
@Override
public void onChanged(Result<Pari> pariResult) {
switch (pariResult.status){
case ERROR:
Toast.makeText(getContext(), pariResult.message, Toast.LENGTH_SHORT).show();
break;
case LOADING:
Toast.makeText(getContext(), "En cours", Toast.LENGTH_SHORT).show();
break;
case SUCCESS:
_showPariDialog(pariResult.data);
break;
}
}
});
_showPariDialog(pari);
});
binding.backBtn.setOnClickListener(v->{
@@ -315,6 +330,26 @@ public class BetValidation extends Fragment {
});
}
private void setSelectedTypeOfBetImage(){
switch (shared.typeOfBet.getValue().getName()){
case "COUPLE_PLACE":
binding.icTypeOfBet.setImageResource(R.drawable.ic_couple_place);
break;
case "COUPLE_GAGNANT":
binding.icTypeOfBet.setImageResource(R.drawable.ic_couple_gagnant);
break;
case "TIERCE":
binding.icTypeOfBet.setImageResource(R.drawable.ic_tierce);
break;
case "QUARTE":
binding.icTypeOfBet.setImageResource(R.drawable.ic_quarte);
break;
case "QUINTE":
binding.icTypeOfBet.setImageResource(R.drawable.ic_quinte_plus);
break;
}
}
public void printPari(Pari pari) throws WriterException {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pmu_logo);
Bitmap barcode = generateBarcodeBitmap(pari.getNumeroTicket(), 384, 100);
@@ -332,15 +367,16 @@ public class BetValidation extends Fragment {
tspl.append("--------------------------------\n");
boolean isElargie = selectedHorses.getValue().size()>shared.typeOfBet.getValue().getNumberOfHorse();
tspl.append(isElargie?pari.getTypePari()+"/Elargie":pari.getTypePari()).append("\n");
tspl.append(order?"COMBINAISON COMPLETE"+"\n":"");
String combinationText = selectedHorses.getValue().stream()
.map(String::valueOf)
.collect(Collectors.joining("-"));
tspl.append(combinationText).append("\n");
tspl.append("COEF: "+String.valueOf(coeff)).append(".0").append("\n");
tspl.append("--------------------------------\n");
tspl.append("MONTANT: ").append(mise).append(" XOF\n");
tspl.append("MONTANT: ").append(pari.getMise()).append(" XOF\n");
tspl.append("-------------------------------\n");
tspl.append("AGENT: ").append(" 3332\n");
tspl.append("AGENT: ").append(prefsHelper.get("code")).append("\n");
tspl.append("DATE: ").append(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss").format(LocalDateTime.now())).append("\n");
if (BluetoothUtils.needsBluetoothPermissions()) {
if (!BluetoothUtils.hasBluetoothPermission(requireContext())) {
@@ -378,7 +414,7 @@ public class BetValidation extends Fragment {
TextView aler_coeff = (TextView) view.findViewById(R.id.alert_coeff);
aler_coeff.setText("Coef:"+String.valueOf(coeff));
TextView alert_montant = (TextView) view.findViewById(R.id.alert_montant);
alert_montant.setText("Montant: "+String.valueOf(mise)+" CFA");
alert_montant.setText("Montant: "+String.valueOf(pari.getMise())+" CFA");
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setView(view);
builder.setCancelable(false);
@@ -387,22 +423,35 @@ public class BetValidation extends Fragment {
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);
}
pariViewModel.createPari(pari).observe(getViewLifecycleOwner(),new Observer<Result<Pari>>() {
@Override
public void onChanged(Result<Pari> pariResult) {
switch (pariResult.status){
case ERROR:
Toast.makeText(getContext(), pariResult.message, Toast.LENGTH_SHORT).show();
break;
case LOADING:
Toast.makeText(getContext(), "En cours", Toast.LENGTH_SHORT).show();
break;
case SUCCESS:
try {
printPari(pari);
dialog.dismiss();
} catch (WriterException e) {
throw new RuntimeException(e);
}
break;
}
}
});
});
view.findViewById(R.id.alert_cancel).setOnClickListener(v -> {
dialog.dismiss();
});
dialog.show();
}
void _initializeToZero(){
mise = 0;
binding.mise.setText(String.valueOf(mise+" CFA"));
selectedHorses.setValue(List.of());
binding.combination.setText("");
binding.order.setChecked(false);
@@ -413,56 +462,67 @@ public class BetValidation extends Fragment {
setupNumberGrid(binding.gridNumbers);
}
public void calculateMise(int nombreChevauxSelectionnes){
if(typeOfBet.getNumberOfHorse() == 1){
if(nombreChevauxSelectionnes==1){
public void calculateMise(List<String> selectedHorses){
_notClickable(selectedHorses);
int nombreChevauxSelectionnes = selectedHorses.size();
long mise = 0;
if(shared.typeOfBet.getValue() == null || shared.selectedCourse.getValue() == null){
return;
}
int typeOfBetHorses = shared.typeOfBet.getValue().getNumberOfHorse();
int partants = shared.selectedCourse.getValue().getPartants();
if(shared.typeOfBet.getValue().getNumberOfHorse() > nombreChevauxSelectionnes){
binding.mise.setText(mise+" CFA");
return;
}
if(typeOfBetHorses == 2){
mise = 500;
}else{
if(typeOfBetHorses == 5){
mise = 300;
}else{
mise = 200;
}
}
if(typeOfBet.getNumberOfHorse() == 2){
if(nombreChevauxSelectionnes == 2){
mise = 400;
mise = mise * coeff;
if(nombreX>0){
if(nombreChevauxSelectionnes == typeOfBetHorses){
mise = mise * _calculateArrangement((partants - (typeOfBetHorses-nombreX)), nombreX);
}else{
mise = mise * _calculateArrangement(nombreChevauxSelectionnes - typeOfBetHorses , nombreX);
}
if(nombreChevauxSelectionnes > 2){
mise = 400 + (nombreChevauxSelectionnes - 2)*300;
if(order){
mise = mise * _calculateArrangement(typeOfBetHorses, (typeOfBetHorses-nombreX));
}
this.mise = mise;
binding.mise.setText(mise+" CFA");
return;
}
if(typeOfBet.getNumberOfHorse() == 3){
if(nombreChevauxSelectionnes == 3){
mise = 500;
}
if(nombreChevauxSelectionnes > 3){
mise = 500 + (nombreChevauxSelectionnes - 3)*500;
}
mise = mise * _calculateCombinaison(nombreChevauxSelectionnes, typeOfBetHorses);
if(order){
mise = mise * _calculateArrangement(nombreChevauxSelectionnes, typeOfBetHorses);
}
if(typeOfBet.getNumberOfHorse() == 4){
if(nombreChevauxSelectionnes == 4){
mise = 600;
}
if(nombreChevauxSelectionnes > 4){
mise = 600 + (nombreChevauxSelectionnes - 4)*600;
}
}
if(typeOfBet.getNumberOfHorse() == 5){
if(nombreChevauxSelectionnes == 5){
mise = 1200;
}
if(nombreChevauxSelectionnes > 5){
mise = 1200 + (nombreChevauxSelectionnes - 5)*1200;
}
}
mise = order?mise * coeff * _calculateFactorial(shared.typeOfBet.getValue().getNumberOfHorse()):mise * coeff;
this.mise = mise;
binding.mise.setText(mise+" CFA");
}
Integer _calculateFactorial(int n){
int f = 1;
Long _calculateArrangement(int n, int k){
return _calculateFactorial(n) / _calculateFactorial(n-k);
}
Long _calculateCombinaison(int n, int k){
return _calculateFactorial(n) / (_calculateFactorial(k) * _calculateFactorial(n - k));
}
Long _calculateFactorial(int n){
long f = 1;
if(n == 0){
return f;
return f;
}
for(int i = 1; i <=n; i++){
f *= i;
}
return f;
return f;
}

View File

@@ -78,6 +78,14 @@ public class Caisse extends Fragment {
.addToBackStack(null)
.commit();
});
binding.lastBetsBtn.setOnClickListener(v -> {
getActivity().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.nav_host_fragment_content_main, DerniersParis.newInstance())
.addToBackStack(null)
.commit();
});
}
@Override

View File

@@ -0,0 +1,105 @@
package com.example.quiz;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.example.quiz.data.adapter.LastBetsAdapter;
import com.example.quiz.data.model.Pari;
import com.example.quiz.databinding.FragmentDerniersParisBinding;
import com.example.quiz.utils.Result;
import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.PariViewModel;
import com.google.android.material.appbar.MaterialToolbar;
import java.util.List;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link DerniersParis#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class DerniersParis extends Fragment {
FragmentDerniersParisBinding binding;
SharedPrefsHelper prefsHelper;
PariViewModel viewModel;
LastBetsAdapter adapter;
public DerniersParis() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static DerniersParis newInstance() {
DerniersParis fragment = new DerniersParis();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prefsHelper = SharedPrefsHelper.getInstance(getContext());
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentDerniersParisBinding.inflate(inflater, container, false);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding.lastBetsRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
viewModel = new ViewModelProvider(this).get(PariViewModel.class);
viewModel.getDerniersParis(prefsHelper.get("code")).observe(getViewLifecycleOwner(), new Observer<Result<List<Pari>>>() {
@Override
public void onChanged(Result<List<Pari>> listResult) {
switch (listResult.status){
case LOADING:
Toast.makeText(getContext(), "En cours", Toast.LENGTH_SHORT).show();
break;
case ERROR:
Toast.makeText(getContext(), listResult.message, Toast.LENGTH_SHORT).show();
break;
case SUCCESS:
adapter = new LastBetsAdapter(listResult.data, pari -> {
});
binding.lastBetsRecyclerView.setAdapter(adapter);
}
}
});
}
@Override
public void onResume() {
super.onResume();
AppCompatActivity activity = (AppCompatActivity) getActivity();
if(activity!=null){
MaterialToolbar toolbar = activity.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
toolbar.setTitle("Derniers Paris");
}
}
}

View File

@@ -92,17 +92,17 @@ public class ListOfTypeOfBets extends Fragment {
),
new TypeOfBet(
"Tierce",
"TRIPLET",
"TIERCE",
3
),
new TypeOfBet(
"Quarte +",
"QUARTE_PLUS",
"QUARTE",
4
),
new TypeOfBet(
"Quinte +",
"QUINTE_PLUS",
"QUINTE",
5
)
);
@@ -129,7 +129,7 @@ public class ListOfTypeOfBets extends Fragment {
});
Button btnValidate = binding.btnValidate;
btnValidate.setOnClickListener(v->{
if(shared.typeOfBet == null){
if(shared.typeOfBet.getValue() == null){
Toast.makeText(getContext(),"Aucun Type de jeu choisi", Toast.LENGTH_SHORT).show();
return;
}

View File

@@ -135,10 +135,12 @@ public class PageQuiz extends AppCompatActivity {
private void loginSuccess(LoginResponse loginResponse){
prefsHelper.save("id", String.valueOf(loginResponse.getId()));
prefsHelper.save("firstName", loginResponse.getPrenom());
prefsHelper.save("lastName", loginResponse.getNom());
prefsHelper.save("profile", loginResponse.getProfile());
prefsHelper.save("limit", String.valueOf(loginResponse.getLimiteSuperieure()));
prefsHelper.save("code", loginResponse.getCode());
}
@Override

View File

@@ -0,0 +1,137 @@
package com.example.quiz;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.media.Image;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.Manifest;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.DialogFragment;
import com.example.quiz.databinding.FragmentScanBinding;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.mlkit.vision.barcode.BarcodeScanner;
import com.google.mlkit.vision.barcode.BarcodeScanning;
import com.google.mlkit.vision.barcode.common.Barcode;
import com.google.mlkit.vision.common.InputImage;
public class ScannerDialog extends DialogFragment {
private PreviewView previewView;
private ProcessCameraProvider cameraProvider;
public interface OnBarcodeScannedListener {
void onBarcodeScanned(String code);
}
private OnBarcodeScannedListener listener;
private FragmentScanBinding binding;
public void setOnBarcodeScannedListener(OnBarcodeScannedListener listener){
this.listener = listener;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
binding = FragmentScanBinding.inflate(inflater, container, false);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
previewView = view.findViewById(R.id.cameraPreview);
if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.CAMERA}, 1001);
} else {
startCamera();
}
view.findViewById(R.id.closeScanDialog).setOnClickListener(v -> dismiss());
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1001 && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startCamera();
} else {
Toast.makeText(getContext(), "Permission caméra refusée", Toast.LENGTH_SHORT).show();
dismiss();
}
}
private void startCamera() {
final ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
ProcessCameraProvider.getInstance(getContext());
cameraProviderFuture.addListener(() -> {
try {
cameraProvider = cameraProviderFuture.get();
bindPreviewAndScanner();
} catch (Exception e) {
e.printStackTrace();
}
}, ContextCompat.getMainExecutor(getContext()));
}
private void bindPreviewAndScanner() {
cameraProvider.unbindAll();
Preview preview = new Preview.Builder().build();
CameraSelector selector = CameraSelector.DEFAULT_BACK_CAMERA;
preview.setSurfaceProvider(previewView.getSurfaceProvider());
ImageAnalysis analysis = new ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build();
analysis.setAnalyzer(ContextCompat.getMainExecutor(getContext()), imageProxy -> {
@SuppressLint("UnsafeOptInUsageError")
Image mediaImage = imageProxy.getImage();
if (mediaImage != null) {
InputImage inputImage = InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees());
BarcodeScanner scanner = BarcodeScanning.getClient();
scanner.process(inputImage)
.addOnSuccessListener(barcodes -> {
for (Barcode b : barcodes) {
String value = b.getRawValue();
if (value != null && listener != null) {
listener.onBarcodeScanned(value);
dismiss(); // Fermer le dialog après scan
scanner.close();
imageProxy.close();
cameraProvider.unbindAll();
return;
}
}
})
.addOnFailureListener(Throwable::printStackTrace)
.addOnCompleteListener(task -> imageProxy.close());
}
});
cameraProvider.bindToLifecycle(this, selector, preview, analysis);
}
}

View File

@@ -9,26 +9,39 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.example.quiz.databinding.FragmentSoldBinding;
import com.example.quiz.utils.Result;
import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.PariViewModel;
import com.google.android.material.appbar.MaterialToolbar;
import java.util.Calendar;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link Sold#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class Sold extends Fragment {
FragmentSoldBinding binding;
PariViewModel pariViewModel;
SharedPrefsHelper prefsHelper;
public Sold() {
// Required empty public constructor
}
@@ -44,6 +57,7 @@ public class Sold extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prefsHelper = SharedPrefsHelper.getInstance(getContext());
AppCompatActivity activity = (AppCompatActivity) getActivity();
if(activity != null){
MaterialToolbar toolbar = activity.findViewById(R.id.toolbar);
@@ -66,6 +80,7 @@ public class Sold extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
pariViewModel = new ViewModelProvider(this).get(PariViewModel.class);
binding.btnByCourse.setOnClickListener(v -> {
FragmentManager fragmentManager = getParentFragmentManager();
SoldByCourse soldByCourse = SoldByCourse.newInstance();
@@ -86,14 +101,26 @@ public class Sold extends Fragment {
DatePickerDialog datePickerDialog = new DatePickerDialog(
getContext(),
(view, year, month, dayOfMonth) -> {
String date = dayOfMonth + "/" + (month + 1) + "/" + year;
//Toast.makeText(getContext(), date, Toast.LENGTH_SHORT).show();
new AlertDialog.Builder(getContext())
.setTitle("Solde")
.setMessage("Solde la course 3000CFA")
.setPositiveButton("Ok", (dialog, which)->{
dialog.dismiss();
}).show();
String date = year + "-" + (month + 1) + "-" + dayOfMonth;
pariViewModel.getSoldeByDay(prefsHelper.get("code"), date).observe(getViewLifecycleOwner(), new Observer<Result<Double>>() {
@Override
public void onChanged(Result<Double> doubleResult) {
switch (doubleResult.status){
case LOADING:{
Toast.makeText(getContext(), "En cours", Toast.LENGTH_SHORT).show();
break;
}
case ERROR:{
Log.d("Response", doubleResult.message);
break;
}
case SUCCESS:{
_showSold(doubleResult.data);
break;
}
}
}
});
},
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
@@ -102,4 +129,13 @@ public class Sold extends Fragment {
datePickerDialog.show();
}
void _showSold(double solde){
new AlertDialog.Builder(getContext())
.setTitle("Solde")
.setMessage("Solde la course "+solde)
.setPositiveButton("Ok", (dialog, which)->{
dialog.dismiss();
}).show();
}
}

View File

@@ -6,26 +6,35 @@ import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.example.quiz.databinding.FragmentSoldByCourseBinding;
import com.example.quiz.utils.Result;
import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.PariViewModel;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link SoldByCourse#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class SoldByCourse extends Fragment {
FragmentSoldByCourseBinding binding;
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
PariViewModel pariViewModel;
SharedPrefsHelper prefsHelper;
public static SoldByCourse newInstance() {
@@ -39,6 +48,7 @@ public class SoldByCourse extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prefsHelper = SharedPrefsHelper.getInstance(getContext());
}
@Override
@@ -52,19 +62,43 @@ public class SoldByCourse extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
pariViewModel = new ViewModelProvider(this).get(PariViewModel.class);
binding.btnCheckBalance.setOnClickListener(v -> {
if(binding.etRaceNumber.getText().toString().isEmpty()){
binding.etRaceNumber.setError("Veuillez entrer un numéro de course");
return;
}
new AlertDialog.Builder(getContext())
.setTitle("Solde")
.setMessage("Solde la course 3000CFA")
.setPositiveButton("Ok", (dialog, which) -> {
binding.etRaceNumber.setText("");
dialog.dismiss();
})
.show();
pariViewModel.getSoldeByCourse(prefsHelper.get("code"), binding.etRaceNumber.getText().toString()).observe(getViewLifecycleOwner(), new Observer<Result<Double>>() {
@Override
public void onChanged(Result<Double> doubleResult) {
switch (doubleResult.status){
case LOADING:{
Toast.makeText(getContext(), "Chargement..", Toast.LENGTH_SHORT).show();
break;
}
case ERROR:{
Toast.makeText(getContext(), doubleResult.message, Toast.LENGTH_SHORT).show();
break;
}
case SUCCESS:{
_showPariDialog(doubleResult.data);
break;
}
}
}
});
});
}
void _showPariDialog(double solde){
new AlertDialog.Builder(getContext())
.setTitle("Solde")
.setMessage("Solde la course "+solde)
.setPositiveButton("Ok", (dialog, which) -> {
binding.etRaceNumber.setText("");
dialog.dismiss();
})
.show();
}
}

View File

@@ -51,6 +51,13 @@ public class WinTicket extends Fragment {
binding.winTicketBtnBack.setOnClickListener(v -> {
getActivity().onBackPressed();
});
binding.scanTicketBtn.setOnClickListener(v ->{
ScannerDialog scannerDialog = new ScannerDialog();
scannerDialog.setOnBarcodeScannedListener(code -> {
binding.referenceTicket.setText(code);
});
scannerDialog.show(getParentFragmentManager(), "scanner");
});
}
@Override

View File

@@ -14,6 +14,8 @@ import com.example.quiz.data.model.Course;
import com.example.quiz.viewModel.SharedViewModel;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
public class BetsAdapter extends RecyclerView.Adapter<BetsAdapter.BetViewHolder> {
@@ -51,7 +53,12 @@ public class BetsAdapter extends RecyclerView.Adapter<BetsAdapter.BetViewHolder>
public void onBindViewHolder(@NonNull BetViewHolder holder, int position) {
Course bet = bets.get(position);
holder.tvDate.setText(String.valueOf(bet.getDateDepartCourse()));
holder.tvDate.setText(LocalDateTime.parse(
bet.getDateDepartCourse(),
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")
).format(
DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")
));
holder.tvName.setText(bet.getNom());
if (shared != null && shared.selectedReunion.getValue() != null) {

View File

@@ -0,0 +1,120 @@
package com.example.quiz.data.adapter;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.quiz.R;
import com.example.quiz.data.model.Pari;
import java.util.ArrayList;
import java.util.List;
public class LastBetsAdapter extends RecyclerView.Adapter<LastBetsAdapter.LastBetsViewHolder> {
private List<Pari> listeParis = new ArrayList<>(); // évite les NPE
private OnBetClick onBetClick; // peut être null si tu veux
public interface OnBetClick {
void onItemClick(Pari pari);
}
public LastBetsAdapter(List<Pari> listeParis, OnBetClick onBetClick) {
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<Pari> newList) {
if (newList == null) {
this.listeParis = new ArrayList<>();
} else {
this.listeParis = newList;
}
notifyDataSetChanged();
}
public void addItem(Pari pari) {
if (pari == null) return;
this.listeParis.add(pari);
notifyItemInserted(listeParis.size() - 1);
}
public void clear() {
this.listeParis.clear();
notifyDataSetChanged();
}
@NonNull
@Override
public LastBetsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.last_bets_item, parent, false);
return new LastBetsViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull LastBetsViewHolder holder, int position) {
Pari pari = listeParis.get(position);
if (pari == null) return;
holder.typeOfCourse.setText(pari.getCourse().getType());
holder.refenceTicket.setText(pari.getNumeroTicket());
// Type (défensif : vérifie null)
holder.betType.setText(pari.getTypePari() != null ? pari.getTypePari() : "-");
// Course (défensif : course peut être null)
if (pari.getCourse() != null) {
holder.course.setText("Course: " + pari.getCourse().getId());
} else {
holder.course.setText("Course: -");
}
// Chevaux : join en toute sécurité (gère Integer list ou String list)
List<?> chevaux = pari.getChevauxSelectionnes();
if (chevaux != null && !chevaux.isEmpty()) {
// convertir en strings
List<String> str = new ArrayList<>(chevaux.size());
for (Object o : chevaux) {
str.add(String.valueOf(o));
}
// TextUtils.join est compatible avec tous les niveaux API
holder.horses.setText("Chevaux : " + TextUtils.join("-", str));
} else {
holder.horses.setText("Chevaux : -");
}
// Mise (défensif)
holder.mise.setText("Mise: " + pari.getMise() + " CFA");
// click listener défensif
holder.itemView.setOnClickListener(v -> {
if (onBetClick != null) onBetClick.onItemClick(pari);
});
}
@Override
public int getItemCount() {
return (listeParis != null) ? listeParis.size() : 0;
}
public static class LastBetsViewHolder extends RecyclerView.ViewHolder {
TextView betType, horses, course, mise, refenceTicket, typeOfCourse;
public LastBetsViewHolder(@NonNull View itemView) {
super(itemView);
betType = itemView.findViewById(R.id.last_bet_type);
course = itemView.findViewById(R.id.last_bet_course);
horses = itemView.findViewById(R.id.last_bet_horses);
mise = itemView.findViewById(R.id.last_bet_mise);
refenceTicket = itemView.findViewById(R.id.reference_ticket);
typeOfCourse = itemView.findViewById(R.id.type_of_course);
}
}
}

View File

@@ -7,7 +7,6 @@ import java.util.Map;
public class Pari {
private String numeroTicket;
private String typePari;
private String typeFormule;
private double mise;
private String datePari;
private boolean estPaye;
@@ -18,10 +17,11 @@ public class Pari {
private boolean validationOrdreExact;
private String typeMulti;
public Pari(String numeroTicket, String typePari, String typeFormule, double mise, String datePari, boolean estPaye, boolean estRembourse, PariCourseDto course, List<String> chevauxSelectionnes, List<String> ordrePredit, boolean validationOrdreExact, String typeMulti) {
private String createdBy;
public Pari(String numeroTicket, String typePari, double mise, String datePari, boolean estPaye, boolean estRembourse, PariCourseDto course, List<String> chevauxSelectionnes, List<String> ordrePredit, boolean validationOrdreExact, String typeMulti, String createdBy) {
this.numeroTicket = numeroTicket;
this.typePari = typePari;
this.typeFormule = typeFormule;
this.mise = mise;
this.datePari = datePari;
this.estPaye = estPaye;
@@ -31,6 +31,7 @@ public class Pari {
this.ordrePredit = ordrePredit;
this.validationOrdreExact = validationOrdreExact;
this.typeMulti = typeMulti;
this.createdBy = createdBy;
}
public String getNumeroTicket() {
@@ -49,14 +50,6 @@ public class Pari {
this.typePari = typePari;
}
public String getTypeFormule() {
return typeFormule;
}
public void setTypeFormule(String typeFormule) {
this.typeFormule = typeFormule;
}
public double getMise() {
return mise;
}
@@ -128,4 +121,12 @@ public class Pari {
public void setTypeMulti(String typeMulti) {
this.typeMulti = typeMulti;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
}

View File

@@ -3,10 +3,43 @@ package com.example.quiz.data.model.dtos;
public class PariCourseDto {
private int id;
private String nom;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
private String type;
public PariCourseDto(int id) {
this.id = id;
}
public PariCourseDto(String nom) {
this.nom = nom;
}
public PariCourseDto(int id, String nom, String type) {
this.id = id;
this.nom = nom;
this.type = type;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public int getId() {
return id;
}

View File

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

View File

@@ -12,7 +12,9 @@ import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Path;
import retrofit2.http.Query;
public interface ApiService {
@GET("reunions")
@@ -26,4 +28,17 @@ public interface ApiService {
@POST("auth/agent/login")
Call<LoginResponse> login(@Body LoginPayload loginPayload);
@GET("pari/created-by/{created-by}/today")
Call<List<Pari>> derniersParis(@Path("created-by") String createdBy);
@PUT("pari/annuler/{numeroTicket}")
Call<Pari> annulerPari(@Path("numeroTicket") String numeroTicket);
@GET("pari/solde/{createdBy}/course/{courseId}")
Call<Double> getSoldeByCourse(@Path("createdBy") String createdBy, @Path("courseId") String courseId);
@GET("pari/solde/{createdBy}")
Call<Double> getSoldeByDay(@Path("createdBy") String createdBy, @Query("date") String day);
}

View File

@@ -10,6 +10,8 @@ import com.example.quiz.data.model.Pari;
import com.example.quiz.data.remote.ApiService;
import com.example.quiz.utils.Result;
import java.util.List;
import javax.inject.Inject;
import retrofit2.Call;
@@ -57,5 +59,111 @@ public class PariRepository {
return pariResponse;
}
public LiveData<Result<List<Pari>>> derniersParis(String createdBy){
MutableLiveData<Result<List<Pari>>> derniersParis = new MutableLiveData<>();
derniersParis.setValue(Result.loading());
apiService.derniersParis(createdBy).enqueue(new Callback<List<Pari>>() {
@Override
public void onResponse(Call<List<Pari>> call, Response<List<Pari>> response) {
if(response.isSuccessful() && response.body() != null){
derniersParis.postValue(Result.success(response.body()));
}else{
try{
String errorBody = response.errorBody() != null ?
response.errorBody().string() : "Erreur inconnue";
derniersParis.postValue(Result.error(errorBody));
}catch (Exception e){
derniersParis.postValue(Result.error(e.getMessage()));
}
}
}
@Override
public void onFailure(Call<List<Pari>> call, Throwable throwable) {
derniersParis.postValue(Result.error(throwable.getMessage()));
}
});
return derniersParis;
}
public LiveData<Result<Pari>> annulerPari(String numeroTicket){
MutableLiveData<Result<Pari>> pariResponse = new MutableLiveData<>();
pariResponse.setValue(Result.loading());
apiService.annulerPari(numeroTicket).enqueue(new Callback<Pari>(){
@Override
public void onResponse(Call<Pari> call, Response<Pari> response) {
if(response.isSuccessful()){
pariResponse.postValue(Result.success(response.body()));
}else{
try{
String errorBody = response.errorBody() != null ?
response.errorBody().string() : "Erreur inconnue";
pariResponse.postValue(Result.error(errorBody));
}catch (Exception e){
pariResponse.postValue(Result.error(e.getMessage()));
}
}
}
@Override
public void onFailure(Call<Pari> call, Throwable throwable) {
pariResponse.postValue(Result.error(throwable.getMessage()));
}
});
return pariResponse;
}
public LiveData<Result<Double>> getSoldeByCourse(String createdBy, String courseId){
MutableLiveData<Result<Double>> solde = new MutableLiveData<>();
solde.setValue(Result.loading());
apiService.getSoldeByCourse(createdBy, courseId).enqueue(new Callback<Double>() {
@Override
public void onResponse(Call<Double> call, Response<Double> response) {
if(response.isSuccessful()){
solde.postValue(Result.success(response.body()));
}else{
try{
solde.postValue(Result.error(response.errorBody().string()));
}catch (Exception e){
solde.postValue(Result.error(e.getMessage()));
}
}
}
@Override
public void onFailure(Call<Double> call, Throwable throwable) {
solde.postValue(Result.error(throwable.getMessage()));
}
});
return solde;
}
public LiveData<Result<Double>> getSoldeByDay(String createdBy, String day){
MutableLiveData<Result<Double>> solde = new MutableLiveData<>();
solde.setValue(Result.loading());
apiService.getSoldeByDay(createdBy, day).enqueue(new Callback<Double>() {
@Override
public void onResponse(Call<Double> call, Response<Double> response) {
if(response.isSuccessful()){
solde.postValue(Result.success(response.body()));
}else{
try {
solde.postValue(Result.error(response.errorBody().string()));
}catch (Exception e){
solde.postValue(Result.error(e.getMessage()));
}
}
}
@Override
public void onFailure(Call<Double> call, Throwable throwable) {
solde.postValue(Result.error(throwable.getMessage()));
}
});
return solde;
}
}

View File

@@ -7,6 +7,8 @@ import com.example.quiz.data.model.Pari;
import com.example.quiz.data.repository.PariRepository;
import com.example.quiz.utils.Result;
import java.util.List;
import javax.inject.Inject;
import dagger.hilt.android.lifecycle.HiltViewModel;
@@ -16,6 +18,14 @@ public class PariViewModel extends ViewModel {
private final PariRepository pariRepository;
private LiveData<Result<Pari>> pari;
private LiveData<Result<List<Pari>>> derniersParis;
private LiveData<Result<Pari>> pariAnnule;
private LiveData<Result<Double>> solde;
private LiveData<Result<Double>> soldeByDay;
@Inject
public PariViewModel(PariRepository repository){
this.pariRepository = repository;
@@ -27,4 +37,32 @@ public class PariViewModel extends ViewModel {
}
return this.pari;
}
public LiveData<Result<List<Pari>>> getDerniersParis(String createdBy){
if(derniersParis == null){
derniersParis = pariRepository.derniersParis(createdBy);
}
return pariRepository.derniersParis(createdBy);
}
public LiveData<Result<Pari>> annulerPari(String numeroTicket){
if(pariAnnule == null){
pariAnnule = pariRepository.annulerPari(numeroTicket);
}
return pariAnnule;
}
public LiveData<Result<Double>> getSoldeByCourse(String createdBy, String courseId){
if(solde == null){
solde = pariRepository.getSoldeByCourse(createdBy, courseId);
}
return solde;
}
public LiveData<Result<Double>> getSoldeByDay(String createdBy, String day){
if(soldeByDay == null){
soldeByDay = pariRepository.getSoldeByDay(createdBy, day);
}
return soldeByDay;
}
}