Version avec integration slave master

This commit is contained in:
OnlyPapy98
2026-04-01 19:51:19 +02:00
parent acc5ec1b70
commit 4eaca7e1d8
66 changed files with 3229 additions and 218 deletions

View File

@@ -0,0 +1,331 @@
package com.example.quiz;
import android.app.AlertDialog;
import android.content.DialogInterface;
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 androidx.recyclerview.widget.LinearLayoutManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.example.quiz.data.adapter.MultiTypeOfBetsAdapter;
import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.Restriction;
import com.example.quiz.data.model.TypeOfBet;
import com.example.quiz.data.model.dtos.auth.User;
import com.example.quiz.databinding.FragmentAgentDetailsBinding;
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.AgentViewModel;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link AgentDetails#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class AgentDetails extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private String agentId;
private FragmentAgentDetailsBinding binding;
MultiTypeOfBetsAdapter multiTypeOfBetsAdapter;
private AgentViewModel agentViewModel;
private boolean userInteraction = false;
private User agent;
private Restriction allowedBetTypes;
private SharedPrefsHelper prefsHelper;
private LoaderDialog loaderDialog;
public AgentDetails() {
// Required empty public constructor
}
private static final String AGENT_ID = "agentId";
// TODO: Rename and change types and number of parameters
public static AgentDetails newInstance(User agent) {
AgentDetails fragment = new AgentDetails();
Bundle args = new Bundle();
args.putString(AGENT_ID, String.valueOf(agent.getId()));
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
agentId = getArguments().getString(AGENT_ID);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
binding = FragmentAgentDetailsBinding.inflate(inflater, container, false);
agentViewModel = new ViewModelProvider(this).get(AgentViewModel.class);
allowedBetTypes = new Restriction();
prefsHelper = SharedPrefsHelper.getInstance(getContext());
loaderDialog = new LoaderDialog(getContext());
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
loadAgentDetails(agentId);
binding.switchAccess.setOnCheckedChangeListener((compoundButton, b) -> {
if(!userInteraction){
return;
}
String message = b ? "Voulez-vous activer l'accès à l'agent ?" : "Voulez-vous désactiver l'accès à l'agent ?";
new AlertDialog.Builder(getContext())
.setTitle("Activation de l'accès")
.setMessage(message)
.setPositiveButton("Oui", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
if(prefsHelper.get("id")== null){
MessageDialog.showError(getContext(), "Veuillez vous connecter");
return;
}
String masterId = prefsHelper.get("id");
agentViewModel.setAccess(masterId, agentId, !b).observe(getViewLifecycleOwner(), new Observer<Result<Void>>() {
@Override
public void onChanged(Result<Void> voidResult) {
switch (voidResult.status){
case LOADING:{
loaderDialog.show("Chargement des agents");
break;
}
case ERROR:{
loaderDialog.dismiss();
MessageDialog.showError(getContext(), voidResult.message);
break;
}
case SUCCESS:{
loaderDialog.dismiss();
MessageDialog.showSuccess(getContext(), "L'accès a été mis à jour");
loadAgentDetails(agentId);
break;
}
}
}
});
}
}).setNegativeButton("Non", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
}).show();
});
binding.btnValidate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(prefsHelper.get("id")== null){
MessageDialog.showError(getContext(), "Veuillez vous connecter");
return;
}
if(allowedBetTypes.getAllowedBetTypes() == null || allowedBetTypes.getAllowedBetTypes().isEmpty()){
MessageDialog.showError(getContext(), "Veuillez sélectionner au moins un type de paris");
return;
}
if(agent == null){
MessageDialog.showError(getContext(), "Veuillez charger les détails de l'agent");
return;
}
String masterId = prefsHelper.get("id");
new AlertDialog.Builder(getContext())
.setTitle("Valider la sélection")
.setMessage("Êtes-vous sûr de vouloir valider la sélection ?")
.setPositiveButton("Oui", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
agentViewModel.setRestrictions(masterId, agentId, allowedBetTypes).observe(getViewLifecycleOwner(), new Observer<Result<Void>>() {
@Override
public void onChanged(Result<Void> voidResult) {
switch (voidResult.status){
case LOADING:{
loaderDialog.show("Chargement des agents");
break;
}
case ERROR:{
loaderDialog.dismiss();
MessageDialog.showError(getContext(), voidResult.message);
break;
}
case SUCCESS:{
loaderDialog.dismiss();
MessageDialog.showSuccess(getContext(), "Les types de paris ont été mises à jour");
loadAgentDetails(agentId);
break;
}
default:{
}
}
}
});
}
})
.setNegativeButton("Non", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
})
.show();
}
});
}
private void loadAgentDetails(String slaveId){
agentViewModel.getAgentById(slaveId).observe(getViewLifecycleOwner(), new Observer<Result<User>>() {
@Override
public void onChanged(Result<User> userResult) {
switch (userResult.status){
case LOADING:{
loaderDialog.show("Chargement des agents");
break;
}
case ERROR:{
loaderDialog.dismiss();
MessageDialog.showError(getContext(), userResult.message);
break;
}
case SUCCESS:{
loaderDialog.dismiss();
agent = userResult.data;
binding.txtCode.setText(agent.getCode());
String adresse;
if(agent.getVille() != null && agent.getAdresse() != null){
adresse = agent.getVille()+"; "+agent.getAdresse();
}else{
adresse = "Pas d'adresse";
}
binding.txtAdresse.setText(adresse);
userInteraction = false;
binding.switchAccess.setChecked(agent.getStatut().equals("ACTIF"));
userInteraction = true;
loadAvailableBets(String.valueOf(agent.getId()));
break;
}
default:{
break;
}
}
}
});
}
private void loadAvailableBets(String id){
agentViewModel.getAvailableBets(id).observe(getViewLifecycleOwner(), new Observer<Result<List<Course.TypeParis>>>() {
@Override
public void onChanged(Result<List<Course.TypeParis>> listResult) {
switch (listResult.status){
case LOADING:{
loaderDialog.show("Chargement des paris disponibles");
break;
}
case ERROR:{
loaderDialog.dismiss();
MessageDialog.showError(getContext(), listResult.message);
}
case SUCCESS:{
loaderDialog.dismiss();
List<TypeOfBet> types = createTypeOfBetList();
multiTypeOfBetsAdapter = new MultiTypeOfBetsAdapter(types);
multiTypeOfBetsAdapter.preSelectAvailableBets(listResult.data);
binding.betsRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
binding.betsRecyclerView.setAdapter(multiTypeOfBetsAdapter);
List<Course.TypeParis> selectedTypes = multiTypeOfBetsAdapter.getSelectedItems().stream().map(TypeOfBet::getName).collect(Collectors.toList());
allowedBetTypes.setAllowedBetTypes(selectedTypes);
multiTypeOfBetsAdapter.setOnItemClickListener(new MultiTypeOfBetsAdapter.onItemClickListener() {
@Override
public void onItemClick(TypeOfBet type, boolean isChecked) {
List<Course.TypeParis> selectedTypes = multiTypeOfBetsAdapter.getSelectedItems().stream().map(TypeOfBet::getName).collect(Collectors.toList());
allowedBetTypes.setAllowedBetTypes(selectedTypes);
}
@Override
public void onItemsSelected(List<TypeOfBet> selectedItems) {
}
});
}
default:{
break;
}
}
}
});
}
private List<TypeOfBet> createTypeOfBetList() {
List<TypeOfBet> types = new ArrayList<>();
// 1. COUPLE GAGNANT
TypeOfBet coupleGagnant = new TypeOfBet(
"Couple Gagnant", // label
Course.TypeParis.COUPLE_GAGNANT, // name
2 // numberOfHorse (2 chevaux)
);
types.add(coupleGagnant);
// 2. COUPLE PLACE
TypeOfBet couplePlace = new TypeOfBet(
"Couple Place", // label
Course.TypeParis.COUPLE_PLACE, // name
2 // numberOfHorse (2 chevaux)
);
types.add(couplePlace);
// 3. TIERCE
TypeOfBet tierce = new TypeOfBet(
"Tiercé", // label
Course.TypeParis.TIERCE, // name
3 // numberOfHorse (3 chevaux)
);
types.add(tierce);
// 4. QUARTE
TypeOfBet quarte = new TypeOfBet(
"Quarté", // label
Course.TypeParis.QUARTE, // name
4 // numberOfHorse (4 chevaux)
);
types.add(quarte);
// 5. QUINTE (optionnel)
TypeOfBet quinte = new TypeOfBet(
"Quinté", // label
Course.TypeParis.QUINTE, // name
5 // numberOfHorse (5 chevaux)
);
types.add(quinte);
return types;
}
}

View File

@@ -0,0 +1,135 @@
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 android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.example.quiz.data.adapter.AgentItemAdapter;
import com.example.quiz.data.model.dtos.auth.User;
import com.example.quiz.databinding.FragmentAgentManagementBinding;
import com.example.quiz.utils.AuthNavigator;
import com.example.quiz.utils.LoaderDialog;
import com.example.quiz.utils.MessageDialog;
import com.example.quiz.utils.Result;
import com.example.quiz.utils.SessionManager;
import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.AgentViewModel;
import com.example.quiz.viewModel.LoginViewModel;
import com.example.quiz.viewModel.LogsViewModel;
import com.google.android.material.appbar.MaterialToolbar;
import java.util.List;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link AgentManagement#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class AgentManagement extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private FragmentAgentManagementBinding binding;
private LoaderDialog loaderDialog;
private AgentViewModel agentViewModel;
SharedPrefsHelper prefsHelper;
AgentItemAdapter agentItemAdapter;
AuthNavigator authNavigator;
public AgentManagement() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static AgentManagement newInstance() {
AgentManagement fragment = new AgentManagement();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
authNavigator = new AuthNavigator(getContext(), getParentFragmentManager(), SessionManager.newInstance(getContext()),new ViewModelProvider(this).get(LoginViewModel.class),new ViewModelProvider(this).get(LogsViewModel.class), this);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
binding = FragmentAgentManagementBinding.inflate(inflater, container, false);
agentViewModel = new ViewModelProvider(this).get(AgentViewModel.class);
loaderDialog = new LoaderDialog(getContext());
prefsHelper = SharedPrefsHelper.getInstance(getContext());
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
AppCompatActivity activity = (AppCompatActivity) getActivity();
if(activity != null){
MaterialToolbar toolbar = activity.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
if (activity.getSupportActionBar() != null) {
activity.getSupportActionBar().show();
activity.getSupportActionBar().setTitle("Gestion aides");
}
toolbar.setBackgroundColor(getResources().getColor(R.color.primary_green, null));
toolbar.setTitleTextColor(getResources().getColor(R.color.white, null));
}
String agentId = prefsHelper.get("id");
if(agentId == null){
return;
}
agentViewModel.getAgents(agentId).observe(getViewLifecycleOwner(), new Observer<Result<List<User>>>() {
@Override
public void onChanged(Result<List<User>> listResult) {
switch (listResult.status){
case LOADING:{
loaderDialog.show("Chargement des agents");
break;
}
case ERROR:{
loaderDialog.dismiss();
MessageDialog.showError(getContext(), listResult.message);
}
case SUCCESS:{
loaderDialog.dismiss();
agentItemAdapter = new AgentItemAdapter(listResult.data);
binding.agentList.setLayoutManager(new LinearLayoutManager(getContext()));
binding.agentList.setAdapter(agentItemAdapter);
agentItemAdapter.setOnItemClickListener(new AgentItemAdapter.onItemClickListener() {
@Override
public void onItemClick(User agent) {
AgentDetails agentDetails = AgentDetails.newInstance(agent);
authNavigator.navigate(agentDetails);
}});
}
}
}
});
}
}

View File

@@ -37,13 +37,16 @@ import android.widget.Toast;
import com.anggastudio.printama.Printama;
import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.MiseInitiale;
import com.example.quiz.data.model.Pari;
import com.example.quiz.data.model.PariMise;
import com.example.quiz.data.model.ParisResponse;
import com.example.quiz.data.model.Reunion;
import com.example.quiz.data.model.TypeOfBet;
import com.example.quiz.data.model.dtos.NotifPayload;
import com.example.quiz.data.model.dtos.PariCourseDto;
import com.example.quiz.data.model.enums.PariStatut;
import com.example.quiz.data.remote.StompManager;
import com.example.quiz.databinding.FragmentBetValidationBinding;
import com.example.quiz.utils.BluetoothUtils;
import com.example.quiz.utils.LoaderDialog;
@@ -51,14 +54,18 @@ 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.PariMiseViewModel;
import com.example.quiz.viewModel.PariViewModel;
import com.example.quiz.viewModel.SharedViewModel;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
@@ -69,6 +76,9 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
/**
@@ -84,8 +94,15 @@ public class BetValidation extends Fragment {
SharedViewModel shared;
PariMiseViewModel pariMiseViewModel;
List<MiseInitiale> misesInitiales;
private AlertDialog dialog;
@Inject
StompManager stompManager;
private int nombreX;
LogsViewModel logsViewModel;
@@ -253,6 +270,40 @@ public class BetValidation extends Fragment {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
shared = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
pariMiseViewModel = new ViewModelProvider(this).get(PariMiseViewModel.class);
pariMiseViewModel.getBetInitMise().observe(
getViewLifecycleOwner(),
result->{
switch (result.status){
case LOADING: {
loader.show("Chargement des mise");
break;
}
case SUCCESS: {
misesInitiales = result.data;
loader.dismiss();
break;
}
case ERROR: {
loader.dismiss();
MessageDialog.showError(getContext(), result.message);
}
default:
break;
}
}
);
if(shared.selectedCourse.getValue() != null){
stompManager.subscribe("courses/"+shared.selectedCourse.getValue().getId(), json->{
Type type = new TypeToken<NotifPayload<Course>>(){}.getType();
NotifPayload<Course> notif = new Gson().fromJson(json, type);
Course updatedCourse = notif.getPayload();
if(shared.selectedCourse.getValue().getId() == updatedCourse.getId()){
shared.setSelectedCourse(updatedCourse);
setupNumberGrid(binding.gridNumbers);
}
});
}
setSelectedTypeOfBetImage();
pariViewModel = new ViewModelProvider(this).get(PariViewModel.class);
typeOfBet = shared.typeOfBet.getValue();
@@ -266,7 +317,6 @@ public class BetValidation extends Fragment {
activity.getSupportActionBar().setTitle("Pari "+shared.selectedCourse.getValue().getNom());
}
}
setupNumberGrid(binding.gridNumbers);
binding.paymentType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
@@ -323,8 +373,32 @@ public class BetValidation extends Fragment {
});
binding.betValidateBtn.setOnClickListener(v->{
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();
Log.d("PAPER_STATUS", String.valueOf(paperStatus));
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;
}
default:
break;
}
if(binding.paymentType.getSelectedItem().toString().equals("Orange Money") && binding.phoneNumber.getText().toString().isEmpty()){
Toast.makeText(getContext(), "Veuillez entrer un numéro de téléphone", Toast.LENGTH_SHORT).show();
MessageDialog.showError(getContext(), "Veuillez saisir le numéro de téléphone");
return;
}
@@ -444,7 +518,6 @@ public class BetValidation extends Fragment {
String formattedDate = dateTime.format(formatter);
tspl.append(formattedDate).append("\n");
tspl.append("Course ").append(String.valueOf(shared.selectedCourse.getValue().getId())).append("\n");
tspl.append(shared.selectedCourse.getValue().getTypesParisOuverts().get(0)).append("\n");
tspl.append(printama.lineSeparator()+"\n");
boolean isElargie = selectedHorses.getValue().size()>shared.typeOfBet.getValue().getNumberOfHorse();
String typePari = pari.getTypesParisMises().get(0).getTypePari();
@@ -564,19 +637,44 @@ public class BetValidation extends Fragment {
}
int typeOfBetHorses = shared.typeOfBet.getValue().getNumberOfHorse();
int partants = shared.selectedCourse.getValue().getNombrePartants();
Course.TypeParis courseName = shared.typeOfBet.getValue().getName();
if(shared.typeOfBet.getValue().getNumberOfHorse() > nombreChevauxSelectionnes){
binding.mise.setText(mise+" CFA");
return;
}
if(typeOfBetHorses == 2){
mise = 500;
}else{
if(typeOfBetHorses == 5){
mise = 300;
}else{
mise = 200;
MiseInitiale miseModel = misesInitiales.stream()
.filter(miseInitiale-> miseInitiale.getTypePari().equals(courseName))
.findFirst()
.orElse(null);
if(miseModel == null){
MessageDialog.showError(getContext(), "Erreur lors de l'initialisation de la mise");
_initializeToZero();
return;
}
mise = miseModel.getMiseInitialeMin();
Course.TypeParis typePari = shared.typeOfBet.getValue().getName();
boolean estCoupleGagnantOuPlace = typePari.equals(Course.TypeParis.COUPLE_GAGNANT) || typePari.equals(Course.TypeParis.COUPLE_PLACE);
Log.d("TYPE_PARI", typePari.toString());
if (estCoupleGagnantOuPlace) {
// Pour COUPLE_GAGNANT ou COUPLE_PLACE: coefficient < 200
if (coeff > 200) {
// Erreur: coefficient trop élevé
MessageDialog.showError(getContext(),"Le coefficient doit être au plus 200 pour "+typePari.toString());
_initializeToZero();
return;
}
} else {
// Pour les autres types: coefficient <= 20
if (coeff > 20) {
// Erreur: coefficient trop élevé
MessageDialog.showError(getContext(), "Le coefficient doit être inférieur ou égal à 20 pour "+typePari.toString());
_initializeToZero();
return;
}
}
mise = mise * coeff;
if(nombreX>0){
if(nombreChevauxSelectionnes == typeOfBetHorses){
@@ -651,4 +749,10 @@ public class BetValidation extends Fragment {
super.onDestroyView();
binding = null;
}
@Override
public void onDestroy() {
super.onDestroy();
stompManager.disconnect();
}
}

View File

@@ -18,11 +18,17 @@ import com.example.quiz.viewModel.LoginViewModel;
import com.example.quiz.viewModel.LogsViewModel;
import com.google.android.material.appbar.MaterialToolbar;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link Caisse#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class Caisse extends Fragment {
FragmentCaisseBinding binding;
@@ -47,14 +53,13 @@ public class Caisse extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sessionManager = SessionManager.newInstance(getContext());
FragmentManager fragmentManager = getParentFragmentManager();
authNavigator = new AuthNavigator(getContext(),fragmentManager, sessionManager,new ViewModelProvider(requireActivity()).get(LoginViewModel.class), new ViewModelProvider(requireActivity()).get(LogsViewModel.class));
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentCaisseBinding.inflate(inflater, container, false);
authNavigator = new AuthNavigator(getContext(), getParentFragmentManager(), sessionManager,new ViewModelProvider(this).get(LoginViewModel.class),new ViewModelProvider(this).get(LogsViewModel.class), this);
return binding.getRoot();
}

View File

@@ -29,6 +29,7 @@ import com.anggastudio.printama.Printama;
import com.example.quiz.data.adapter.BetsAdapter;
import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.PagedModel;
import com.example.quiz.data.remote.StompManager;
import com.example.quiz.databinding.FragmentListOFBettingBinding;
import com.example.quiz.utils.AuthNavigator;
import com.example.quiz.utils.BluetoothUtils;
@@ -46,6 +47,8 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
/**
@@ -56,15 +59,15 @@ import dagger.hilt.android.AndroidEntryPoint;
@AndroidEntryPoint
public class ListOFBets extends Fragment {
FragmentListOFBettingBinding binding;
LoaderDialog loader;
private SharedViewModel shared;
private CourseViewModel viewModel;
@Inject
StompManager stompManager;
AuthNavigator authNavigator;
private BetsAdapter adapter;
@@ -85,31 +88,8 @@ public class ListOFBets extends Fragment {
super.onCreate(savedInstanceState);
SessionManager sessionManager = SessionManager.newInstance(getContext());
FragmentManager fragmentManager = getParentFragmentManager();
authNavigator = new AuthNavigator(getContext(), fragmentManager, sessionManager, new ViewModelProvider(requireActivity()).get(LoginViewModel.class), new ViewModelProvider(requireActivity()).get(LogsViewModel.class));
requestPermission();
}
private void requestPermission(){
Pref.init(getContext());
if (BluetoothUtils.needsBluetoothPermissions()) {
if (!BluetoothUtils.hasBluetoothPermission(getContext())) {
// 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
try {
Printama printama = Printama.with(getContext());
if(!printama.isConnected()){
BluetoothUtils.showPrinterList(getContext(), requireActivity());
}
} catch (SecurityException e) {
Toast.makeText(getContext(),
"Permission Bluetooth non accordée", Toast.LENGTH_SHORT).show();
}
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
@@ -121,7 +101,7 @@ public class ListOFBets extends Fragment {
binding.recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2));
binding.recyclerView.setAdapter(adapter);
viewModel = new ViewModelProvider(this).get(CourseViewModel.class);
authNavigator = new AuthNavigator(getContext(), getParentFragmentManager(), SessionManager.newInstance(getContext()),new ViewModelProvider(this).get(LoginViewModel.class),new ViewModelProvider(this).get(LogsViewModel.class), this);
/*viewModel.bets.observe(getViewLifecycleOwner(), bets -> {
@@ -173,8 +153,12 @@ public class ListOFBets extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
MenuHost menuHost = requireActivity();
stompManager.subscribe("courses", json->{
requireActivity().runOnUiThread(this::observe);
});
MenuHost menuHost = requireActivity();
// 🔹 On enlève d'abord les anciens menu providers si ce fragment est recréé
menuHost.invalidateMenu();
@@ -222,4 +206,10 @@ public class ListOFBets extends Fragment {
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
stompManager.disconnect();
}
}

View File

@@ -7,9 +7,11 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -18,18 +20,33 @@ import android.widget.Toast;
import com.example.quiz.data.adapter.TypeOfBetAdapter;
import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.PariMise;
import com.example.quiz.data.model.TypeOfBet;
import com.example.quiz.data.model.dtos.NotifPayload;
import com.example.quiz.data.remote.StompManager;
import com.example.quiz.databinding.FragmentListOfTypeOfBetsBinding;
import com.example.quiz.utils.AuthNavigator;
import com.example.quiz.utils.LoaderDialog;
import com.example.quiz.utils.MessageDialog;
import com.example.quiz.utils.Result;
import com.example.quiz.utils.SessionManager;
import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.AgentViewModel;
import com.example.quiz.viewModel.LoginViewModel;
import com.example.quiz.viewModel.LogsViewModel;
import com.example.quiz.viewModel.PariMiseViewModel;
import com.example.quiz.viewModel.SharedViewModel;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
@@ -44,13 +61,25 @@ public class ListOfTypeOfBets extends Fragment {
private FragmentListOfTypeOfBetsBinding binding;
SessionManager sessionManager;
AuthNavigator authNavigator;
@Inject
StompManager stompManager;
private SharedViewModel shared;
private TypeOfBetAdapter adapter;
private SharedPrefsHelper prefsHelper;
private AgentViewModel agentViewModel;
private LoaderDialog loaderDialog;
public ListOfTypeOfBets() {
// Required empty public constructor
}
@@ -65,28 +94,74 @@ public class ListOfTypeOfBets extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sessionManager = SessionManager.newInstance(getContext());
authNavigator = new AuthNavigator(getContext(), getParentFragmentManager(), sessionManager, new ViewModelProvider(this).get(LoginViewModel.class), new ViewModelProvider(this).get(LogsViewModel.class));
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentListOfTypeOfBetsBinding.inflate(inflater, container, false);
authNavigator = new AuthNavigator(getContext(), getParentFragmentManager(), SessionManager.newInstance(getContext()),new ViewModelProvider(this).get(LoginViewModel.class),new ViewModelProvider(this).get(LogsViewModel.class), this);
prefsHelper = SharedPrefsHelper.getInstance(getContext());
loaderDialog = new LoaderDialog(getContext());
agentViewModel = new ViewModelProvider(this).get(AgentViewModel.class);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if(prefsHelper.get("id") == null){
MessageDialog.showError(getContext(), "Veuillez vous connecter");
return;
}
agentViewModel.getAvailableBets(prefsHelper.get("id")).observe(getViewLifecycleOwner(), new Observer<Result<List<Course.TypeParis>>>() {
@Override
public void onChanged(Result<List<Course.TypeParis>> listResult) {
switch (listResult.status){
case LOADING:{
loaderDialog.show("Chargement des types de paris");
break;
}
case ERROR:{
loaderDialog.dismiss();
MessageDialog.showError(getContext(), listResult.message);
break;
}
case SUCCESS:{
loaderDialog.dismiss();
syncAuthorizedBets(listResult.data);
break;
}
}
}
});
}
public void syncAuthorizedBets(List<Course.TypeParis> authorizedBets){
binding.typeOfBetRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
// ViewModels
//viewModel = new ViewModelProvider(this).get(BetViewModel.class);
shared = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
// Observers
if(shared.selectedCourse.getValue() == null){
return;
}
Course sCourse = shared.selectedCourse.getValue();
if(sCourse != null){
stompManager.subscribe("courses/"+sCourse.getId(), json->{
requireActivity().runOnUiThread(()->{
Type type = new TypeToken<NotifPayload<Course>>(){}.getType();
NotifPayload<Course> notif = new Gson().fromJson(json, type);
Course updatedCourse = notif.getPayload();
if(sCourse.getId() == updatedCourse.getId()){
shared.setSelectedCourse(updatedCourse);
}
});
});
}
// ⚡ Initialiser ladapter UNE SEULE FOIS
adapter = new TypeOfBetAdapter(new ArrayList<>());
binding.typeOfBetRecyclerView.setAdapter(adapter);
List<Course.TypeParis> betType = shared.selectedCourse.getValue().getTypesParisOuverts();
List<Course.TypeParis> betType = sCourse.getTypesParisOuverts();
List<TypeOfBet> useList = new ArrayList<>();
if(betType.contains(Course.TypeParis.QUINTE)){
useList.add(new TypeOfBet("Quinte", Course.TypeParis.QUINTE, 5));
@@ -97,14 +172,15 @@ public class ListOfTypeOfBets extends Fragment {
if(betType.contains(Course.TypeParis.TIERCE)){
useList.add(new TypeOfBet("Tierce", Course.TypeParis.TIERCE, 3));
}
if(betType.contains(Course.TypeParis.COUPLE_PLACE)){
useList.add(new TypeOfBet("Couple Place", Course.TypeParis.COUPLE_PLACE, 2));
}
if(betType.contains(Course.TypeParis.COUPLE_PLACE)){
useList.add(new TypeOfBet("Couple Gagnant", Course.TypeParis.COUPLE_GAGNANT, 2));
}
AtomicReference<TypeOfBet> typeOfBet = new AtomicReference<>();
adapter.setTypes(useList);
if(betType.contains(Course.TypeParis.COUPLE_PLACE)){
useList.add(new TypeOfBet("Couple Place", Course.TypeParis.COUPLE_PLACE, 2));
}
if(betType.contains(Course.TypeParis.COUPLE_PLACE)){
useList.add(new TypeOfBet("Couple Gagnant", Course.TypeParis.COUPLE_GAGNANT, 2));
}
AtomicReference<TypeOfBet> typeOfBet = new AtomicReference<>();
List<TypeOfBet> availableTypeOfBets = useList.stream().filter(type -> authorizedBets.contains(type.getName())).collect(Collectors.toList());
adapter.setTypes(availableTypeOfBets);
adapter.setOnItemClickListener(type -> {
typeOfBet.set(type);
});
@@ -133,4 +209,10 @@ public class ListOfTypeOfBets extends Fragment {
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
stompManager.disconnect();
}
}

View File

@@ -19,11 +19,14 @@ import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.LoginViewModel;
import com.example.quiz.viewModel.LogsViewModel;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link Login#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class Login extends Fragment {
@@ -52,6 +55,7 @@ public class Login extends Fragment {
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentLoginBinding.inflate(inflater, container, false);
authNavigator = new AuthNavigator(getContext(), getParentFragmentManager(), SessionManager.newInstance(getContext()),new ViewModelProvider(this).get(LoginViewModel.class),new ViewModelProvider(this).get(LogsViewModel.class), this);
return binding.getRoot();
}
@@ -60,7 +64,6 @@ public class Login extends Fragment {
super.onViewCreated(view, savedInstanceState);
SessionManager sessionManager = SessionManager.newInstance(getContext());
FragmentManager fragmentManager = getParentFragmentManager();
authNavigator = new AuthNavigator(getContext(), fragmentManager, sessionManager, new ViewModelProvider(requireActivity()).get(LoginViewModel.class), new ViewModelProvider(requireActivity()).get(LogsViewModel.class));
AppCompatActivity activity = (AppCompatActivity) getActivity();
if(activity != null){
activity.getSupportActionBar().hide();

View File

@@ -2,12 +2,14 @@ package com.example.quiz;
import android.graphics.Color;
import android.os.Bundle;
import com.anggastudio.printama.Pref;
import com.anggastudio.printama.Printama;
import com.example.quiz.utils.AuthNavigator;
import com.example.quiz.utils.BluetoothUtils;
import com.example.quiz.utils.MessageDialog;
import com.example.quiz.utils.SessionManager;
import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.LoginViewModel;
import com.example.quiz.viewModel.LogsViewModel;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Handler;
import android.os.Looper;
@@ -20,6 +22,8 @@ import androidx.navigation.ui.NavigationUI;
import com.example.quiz.databinding.ActivityPageQuizBinding;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
@AndroidEntryPoint
@@ -46,7 +50,7 @@ public class PageQuiz extends AppCompatActivity {
setContentView(binding.getRoot());
logsViewModel = new ViewModelProvider(this).get(LogsViewModel.class);
viewModel = new ViewModelProvider(this).get(LoginViewModel.class);
authNavigator = new AuthNavigator(this, getSupportFragmentManager(), sessionManager, viewModel, logsViewModel);
authNavigator = new AuthNavigator(this, getSupportFragmentManager(), sessionManager, viewModel, logsViewModel, this);
setSupportActionBar(binding.toolbar);
binding.toolbar.setBackgroundColor(Color.parseColor("#501C5A29"));
}
@@ -117,12 +121,32 @@ public class PageQuiz extends AppCompatActivity {
// }
private void checkPermission(){
Pref.init(this);
if (BluetoothUtils.needsBluetoothPermissions()) {
if (!BluetoothUtils.hasBluetoothPermission(this)) {
// Demande la permission si non accordée
BluetoothUtils.requestBluetoothPermission(this);
return; // arrête ici, la popup va apparaître
}
}
// 2⃣ Permission OK, on peut afficher la liste
try {
Printama printama = Printama.with(this);
if(printama.getConnectedPrinter() == null){
BluetoothUtils.showPrinterList(this, this);
}
} catch (SecurityException e) {
MessageDialog.showError(this, "Permission refusée");
}
}
@Override
protected void onResume() {
checkPermission();
super.onResume();
handler = new Handler(Looper.getMainLooper());
checkRunnable = new Runnable() {
@Override
public void run() {

View File

@@ -6,19 +6,30 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.example.quiz.databinding.FragmentSettingsBinding;
import com.example.quiz.utils.AuthNavigator;
import com.example.quiz.utils.SessionManager;
import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.LoginViewModel;
import com.example.quiz.viewModel.LogsViewModel;
import com.google.android.material.appbar.MaterialToolbar;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link Settings#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class Settings extends Fragment {
// TODO: Rename parameter arguments, choose names that match
@@ -28,6 +39,10 @@ public class Settings extends Fragment {
FragmentSettingsBinding binding;
AuthNavigator authNavigator;
SharedPrefsHelper prefsHelper;
public Settings() {
// Required empty public constructor
}
@@ -42,14 +57,16 @@ public class Settings extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
prefsHelper = SharedPrefsHelper.getInstance(getContext());
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentSettingsBinding.inflate(inflater, container, false);
// Inflate the layout for this fragment
authNavigator = new AuthNavigator(getContext(), getParentFragmentManager(), SessionManager.newInstance(getContext()),new ViewModelProvider(this).get(LoginViewModel.class),new ViewModelProvider(this).get(LogsViewModel.class), this);
return binding.getRoot();
}
@@ -57,6 +74,16 @@ public class Settings extends Fragment {
public void onViewCreated(@NonNull View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
AppCompatActivity activity = (AppCompatActivity) getActivity();
if(prefsHelper.get("isSupAgent") == null){
binding.agentManagement.setVisibility(View.GONE);
}else{
String isSubAgent = prefsHelper.get("isSupAgent");
if(isSubAgent.equals("true")){
binding.agentManagement.setVisibility(View.GONE);
}else{
binding.agentManagement.setVisibility(View.VISIBLE);
}
}
if(activity != null){
MaterialToolbar toolbar = activity.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
@@ -92,6 +119,21 @@ public class Settings extends Fragment {
.commit();
}
});
binding.changePin.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
UpdatePin updatePin = UpdatePin.newInstance();
authNavigator.navigate(updatePin);
}
});
binding.agentManagement.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AgentManagement agentManagement = AgentManagement.newInstance();
authNavigator.navigate(agentManagement);
}
});
}

View File

@@ -2,11 +2,15 @@ package com.example.quiz;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.LifecycleOwner;
@@ -19,6 +23,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.anggastudio.printama.Printama;
import com.example.quiz.data.model.dtos.paris.SoldeResponse;
import com.example.quiz.databinding.FragmentSoldBinding;
import com.example.quiz.utils.LoaderDialog;
import com.example.quiz.utils.MessageDialog;
@@ -28,6 +34,8 @@ import com.example.quiz.viewModel.LogsViewModel;
import com.example.quiz.viewModel.PariViewModel;
import com.google.android.material.appbar.MaterialToolbar;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import dagger.hilt.android.AndroidEntryPoint;
@@ -116,9 +124,9 @@ public class Sold extends Fragment {
getContext(),
(view, year, month, dayOfMonth) -> {
String date = year + "-" + _reformatDateForDate(month + 1) + "-" + _reformatDateForDate(dayOfMonth);
pariViewModel.getSoldeByDay(prefsHelper.get("id"), date).observe(getViewLifecycleOwner(), new Observer<Result<Double>>() {
pariViewModel.getSoldeByDay(prefsHelper.get("id"), date).observe(getViewLifecycleOwner(), new Observer<Result<SoldeResponse>>() {
@Override
public void onChanged(Result<Double> doubleResult) {
public void onChanged(Result<SoldeResponse> doubleResult) {
switch (doubleResult.status){
case LOADING:{
dialog.show("Solde du jour");
@@ -131,7 +139,8 @@ public class Sold extends Fragment {
}
case SUCCESS:{
dialog.dismiss();
_showSold(doubleResult.data);
_showSold(doubleResult.data, date);
logsViewModel.insertLog(prefsHelper.get("id"), "SOLDE JOUR", "Solde du "+date, System.currentTimeMillis());
break;
}
@@ -147,12 +156,44 @@ public class Sold extends Fragment {
datePickerDialog.show();
}
void _showSold(double solde){
void _showSold(SoldeResponse soldeResponse, String date){
int solde = soldeResponse.getMontantParis() - soldeResponse.getMontantAnnulations() - soldeResponse.getMontantPaiements();
new AlertDialog.Builder(getContext())
.setTitle("Solde")
.setMessage("Solde la course "+solde)
.setPositiveButton("Ok", (dialog, which)->{
.setNeutralButton("Ok", (dialog, which)->{
dialog.dismiss();
}).show();
})
.setPositiveButton("Imprimer", (dialog, which)->{
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;
}
Printama printama = Printama.with(getContext());
Bitmap logo = BitmapFactory.decodeResource(getResources(), R.drawable.pmu_logo);
String title = "SOLDE AU "+date;
StringBuilder text = new StringBuilder();
text.append("VENTES HIPPIQUES: ").append(String.valueOf(soldeResponse.getMontantParis())).append(" XOF").append("\n");
text.append("NBR. PAIEMENTS: ").append(soldeResponse.getNombrePaiements()).append("\n");
text.append("PAIEMENTS: ").append(String.valueOf(soldeResponse.getMontantPaiements())).append(" XOF").append("\n");
text.append("NBR. ANNULATIONS: ").append(soldeResponse.getNombreAnnulations()).append("\n");
text.append("ANNULATIONS: ").append(String.valueOf(soldeResponse.getMontantAnnulations())).append(" XOF").append("\n");
text.append(printama.lineSeparator()).append("\n");
text.append("SOLDE: ").append(String.valueOf(solde)).append(" XOF").append("\n");
text.append(printama.lineSeparator()).append("\n");
text.append("AGENT : ").append(prefsHelper.get("code")).append("\n");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
String now = formatter.format(LocalDateTime.now());
text.append("DATE : ").append(now).append("\n");
printama.printSold(logo, title, text);
})
.show();
}
}

View File

@@ -1,10 +1,14 @@
package com.example.quiz;
import android.app.AlertDialog;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
@@ -14,6 +18,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.anggastudio.printama.Printama;
import com.example.quiz.data.model.dtos.paris.SoldeResponse;
import com.example.quiz.databinding.FragmentSoldByCourseBinding;
import com.example.quiz.utils.LoaderDialog;
import com.example.quiz.utils.MessageDialog;
@@ -22,6 +28,9 @@ import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.LogsViewModel;
import com.example.quiz.viewModel.PariViewModel;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import dagger.hilt.android.AndroidEntryPoint;
/**
@@ -78,9 +87,9 @@ public class SoldByCourse extends Fragment {
binding.etRaceNumber.setError("Veuillez entrer un numéro de course");
return;
}
pariViewModel.getSoldeByCourse(prefsHelper.get("id"), binding.etRaceNumber.getText().toString()).observe(getViewLifecycleOwner(), new Observer<Result<Double>>() {
pariViewModel.getSoldeByCourse(prefsHelper.get("id"), binding.etRaceNumber.getText().toString()).observe(getViewLifecycleOwner(), new Observer<Result<SoldeResponse>>() {
@Override
public void onChanged(Result<Double> doubleResult) {
public void onChanged(Result<SoldeResponse> doubleResult) {
switch (doubleResult.status){
case LOADING:{
loader.show("Chargement du solde");
@@ -93,7 +102,7 @@ public class SoldByCourse extends Fragment {
}
case SUCCESS:{
loader.dismiss();
_showPariDialog(doubleResult.data);
_showPariDialog(doubleResult.data, binding.etRaceNumber.getText().toString());
logsViewModel.insertLog(prefsHelper.get("id"), "SOLDE COURSE", "Solde de la course "+binding.etRaceNumber.getText(), System.currentTimeMillis());
break;
}
@@ -103,14 +112,44 @@ public class SoldByCourse extends Fragment {
});
}
void _showPariDialog(double solde){
void _showPariDialog(SoldeResponse soldeResponse, String numero){
int solde = soldeResponse.getMontantParis() - soldeResponse.getMontantAnnulations() - soldeResponse.getMontantPaiements();
new AlertDialog.Builder(getContext())
.setTitle("Solde")
.setMessage("Solde la course "+solde)
.setPositiveButton("Ok", (dialog, which) -> {
.setNeutralButton("Ok", (dialog, which) -> {
binding.etRaceNumber.setText("");
dialog.dismiss();
})
.setPositiveButton("Imprimer", (dialog, which)->{
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;
}
Printama printama = Printama.with(getContext());
Bitmap logo = BitmapFactory.decodeResource(getResources(), R.drawable.pmu_logo);
String title = "SOLDE DE LA COURSE "+numero;
StringBuilder text = new StringBuilder();
text.append("VENTES HIPPIQUES: ").append(String.valueOf(soldeResponse.getMontantParis())).append(" XOF").append("\n");
text.append("NBR. PAIEMENTS: ").append(soldeResponse.getNombrePaiements()).append("\n");
text.append("PAIEMENTS: ").append(String.valueOf(soldeResponse.getMontantPaiements())).append(" XOF").append("\n");
text.append("NBR. ANNULATIONS: ").append(soldeResponse.getNombreAnnulations()).append("\n");
text.append("ANNULATIONS: ").append(String.valueOf(soldeResponse.getMontantAnnulations())).append(" XOF").append("\n");
text.append(printama.lineSeparator()).append("\n");
text.append("SOLDE: ").append(String.valueOf(solde)).append(" XOF").append("\n");
text.append(printama.lineSeparator()).append("\n");
text.append("AGENT : ").append(prefsHelper.get("code")).append("\n");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
String now = formatter.format(LocalDateTime.now());
text.append("DATE : ").append(now).append("\n");
printama.printSold(logo, title, text);
})
.show();
}
}

View File

@@ -0,0 +1,24 @@
package com.example.quiz;
import com.example.quiz.data.remote.NotificationHelper;
import com.example.quiz.data.remote.StompManager;
import com.example.quiz.data.remote.TokenManager;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import dagger.hilt.InstallIn;
import dagger.hilt.components.SingletonComponent;
@Module
@InstallIn(SingletonComponent.class)
public class StompModule {
@Provides
@Singleton
public StompManager provideStompManager(TokenManager tokenManager,
NotificationHelper notificationHelper) {
return new StompManager(tokenManager, notificationHelper);
}
}

View File

@@ -0,0 +1,132 @@
package com.example.quiz;
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 com.example.quiz.data.model.dtos.auth.User;
import com.example.quiz.databinding.FragmentUpdatePinBinding;
import com.example.quiz.utils.AuthNavigator;
import com.example.quiz.utils.LoaderDialog;
import com.example.quiz.utils.MessageDialog;
import com.example.quiz.utils.Result;
import com.example.quiz.utils.SessionManager;
import com.example.quiz.viewModel.LoginViewModel;
import com.example.quiz.viewModel.LogsViewModel;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link UpdatePin#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class UpdatePin extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
// TODO: Rename and change types of parameters
FragmentUpdatePinBinding binding;
String oldPin;
String newPin;
String confirmation;
AuthNavigator authNavigator;
LoginViewModel viewModel;
LoaderDialog loaderDialog;
public UpdatePin() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static UpdatePin newInstance() {
UpdatePin fragment = new UpdatePin();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
viewModel = new ViewModelProvider(this).get(LoginViewModel.class);
loaderDialog = new LoaderDialog(getContext());
authNavigator = new AuthNavigator(getContext(), getParentFragmentManager(), new SessionManager(getContext()), new ViewModelProvider(this).get(LoginViewModel.class),new ViewModelProvider(this).get(LogsViewModel.class),this);
// Inflate the layout for this fragment
binding = FragmentUpdatePinBinding.inflate(inflater, container, false);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding.validate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
oldPin = binding.oldPin.getText().toString();
newPin = binding.newPin.getText().toString();
confirmation = binding.pinConfirmation.getText().toString();
if(oldPin.length()<4 || newPin.length()<4 || confirmation.length()<4){
MessageDialog.showError(getContext(), "Le pin doit au mois avoir 4 Caractères!");
return;
}
if(!newPin.equals(confirmation)){
MessageDialog.showError(getContext(), "Les pins ne sont pas identiques!");
return;
}
viewModel.changePin(oldPin, newPin).observe(getViewLifecycleOwner(), new Observer<Result<User>>(){
@Override
public void onChanged(Result<User> userResult) {
switch (userResult.status){
case LOADING:{
loaderDialog.show("Mis à jour du pin");
break;
}
case ERROR:{
loaderDialog.dismiss();
MessageDialog.showError(getContext(), userResult.message);
break;
}
case SUCCESS:{
loaderDialog.dismiss();
MessageDialog.showSuccess(getContext(), "Pin mis à jour avec succès");
SessionManager sessionManager = new SessionManager(getContext());
authNavigator.showPinDialog(()->{
sessionManager.updateLastExpiredDate();
getParentFragmentManager().popBackStack();
});
}
}
}
});
}
});
binding.cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getParentFragmentManager().popBackStack();
}
});
}
}

View File

@@ -0,0 +1,94 @@
package com.example.quiz.data.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.quiz.R;
import com.example.quiz.data.model.dtos.auth.User;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class AgentItemAdapter extends RecyclerView.Adapter<AgentItemAdapter.AgentItemViewHolder> {
private List<User> agents = new ArrayList<>();
public AgentItemAdapter(){
}
public AgentItemAdapter(List<User> agents) {
this.agents = agents;
}
public interface onItemClickListener{
void onItemClick(User agent);
}
private onItemClickListener listener;
public void setOnItemClickListener(onItemClickListener listener){
this.listener = listener;
}
static class AgentItemViewHolder extends RecyclerView.ViewHolder{
TextView txtCode, txtDate, txtAdresse;
ImageButton details;
public AgentItemViewHolder(@NonNull View itemView) {
super(itemView);
txtCode = itemView.findViewById(R.id.txtCode);
txtDate = itemView.findViewById(R.id.txtDate);
txtAdresse = itemView.findViewById(R.id.txtAdresse);
details = itemView.findViewById(R.id.details);
}
}
@Override
public int getItemCount() {
return agents.size();
}
@NonNull
@Override
public AgentItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.agent_item, parent, false);
return new AgentItemViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull AgentItemViewHolder holder, int position) {
User agent = agents.get(position);
holder.txtCode.setText(agent.getCode());
if(agent.getDateEmbauche() == null){
holder.txtDate.setText("Pas de date");
}else{
LocalDate date = LocalDate.parse(agent.getDateEmbauche());
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
holder.txtDate.setText(dateTimeFormatter.format(date));
}
if(agent.getVille() == null || agent.getAdresse() == null){
holder.txtAdresse.setText("Pas d'adresse");
}else{
String address = agent.getVille()+"; "+agent.getAdresse();
holder.txtAdresse.setText(address);
}
holder.details.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener != null){
listener.onItemClick(agent);
}
}
});
}
}

View File

@@ -0,0 +1,149 @@
package com.example.quiz.data.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.quiz.R;
import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.TypeOfBet;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class MultiTypeOfBetsAdapter extends RecyclerView.Adapter<MultiTypeOfBetsAdapter.TypeOfBetViewHolder> {
private List<TypeOfBet> types;
private Set<Integer> selectedPositions = new HashSet<>();
private onItemClickListener listener;
public interface onItemClickListener {
void onItemClick(TypeOfBet type, boolean isChecked);
void onItemsSelected(List<TypeOfBet> selectedItems);
}
public void setOnItemClickListener(onItemClickListener listener) {
this.listener = listener;
}
public MultiTypeOfBetsAdapter(List<TypeOfBet> types) {
this.types = types;
}
// Méthode pour pré-sélectionner les paris (rendue publique)
public void preSelectAvailableBets(List<Course.TypeParis> preselectedTypes) {
selectedPositions.clear();
for (int i = 0; i < types.size(); i++) {
if (preselectedTypes.contains(types.get(i).getName())) {
selectedPositions.add(i);
}
}
notifyDataSetChanged();
}
public void setTypes(List<TypeOfBet> types) {
this.types = types;
selectedPositions.clear();
notifyDataSetChanged();
}
@NonNull
@Override
public TypeOfBetViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.multi_type_of_bet_item, parent, false);
return new TypeOfBetViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull TypeOfBetViewHolder holder, int position) {
TypeOfBet type = types.get(position);
holder.type_of_bet_name.setText(type.getLabel());
boolean isSelected = selectedPositions.contains(position);
holder.checkBox.setChecked(isSelected);
if (isSelected) {
holder.itemView.setBackgroundResource(R.drawable.item_gradient_bg_selected);
} else {
holder.itemView.setBackgroundResource(R.drawable.item_gradient_bg);
}
holder.itemView.setOnClickListener(v -> {
toggleSelection(position, type);
});
holder.checkBox.setOnClickListener(v -> {
toggleSelection(position, type);
});
}
private void toggleSelection(int position, TypeOfBet type) {
boolean isCurrentlySelected = selectedPositions.contains(position);
if (isCurrentlySelected) {
selectedPositions.remove(position);
} else {
selectedPositions.add(position);
}
if (listener != null) {
listener.onItemClick(type, !isCurrentlySelected);
}
notifyItemChanged(position);
}
@Override
public int getItemCount() {
return types.size();
}
public List<TypeOfBet> getSelectedItems() {
List<TypeOfBet> selectedItems = new ArrayList<>();
for (Integer position : selectedPositions) {
if (position >= 0 && position < types.size()) {
selectedItems.add(types.get(position));
}
}
return selectedItems;
}
public boolean isSelected(int position) {
return selectedPositions.contains(position);
}
public void selectAll() {
selectedPositions.clear();
for (int i = 0; i < types.size(); i++) {
selectedPositions.add(i);
}
notifyDataSetChanged();
}
public void deselectAll() {
selectedPositions.clear();
notifyDataSetChanged();
}
public int getSelectedCount() {
return selectedPositions.size();
}
public class TypeOfBetViewHolder extends RecyclerView.ViewHolder {
TextView type_of_bet_name;
CheckBox checkBox;
public TypeOfBetViewHolder(@NonNull View itemView) {
super(itemView);
type_of_bet_name = itemView.findViewById(R.id.tv_bet_name);
checkBox = itemView.findViewById(R.id.checkbox_bet);
}
}
}

View File

@@ -1,6 +1,5 @@
package com.example.quiz.data.model;
import com.example.quiz.data.model.enums.CourseType;
import java.time.LocalDate;
import java.time.LocalDateTime;

View File

@@ -0,0 +1,49 @@
package com.example.quiz.data.model;
public class MiseInitiale {
private Long id;
private Course.TypeParis typePari;
private Long miseInitialeMin;
private Long miseInitialeMax;
private boolean actif;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Course.TypeParis getTypePari() {
return typePari;
}
public void setTypePari(Course.TypeParis typePari) {
this.typePari = typePari;
}
public Long getMiseInitialeMin() {
return miseInitialeMin;
}
public void setMiseInitialeMin(Long miseInitialeMin) {
this.miseInitialeMin = miseInitialeMin;
}
public Long getMiseInitialeMax() {
return miseInitialeMax;
}
public void setMiseInitialeMax(Long miseInitialeMax) {
this.miseInitialeMax = miseInitialeMax;
}
public boolean isActif() {
return actif;
}
public void setActif(boolean actif) {
this.actif = actif;
}
}

View File

@@ -0,0 +1,17 @@
package com.example.quiz.data.model;
import java.util.List;
public class Restriction {
private List<Course.TypeParis> allowedBetTypes;
public Restriction(){}
public List<Course.TypeParis> getAllowedBetTypes() {
return allowedBetTypes;
}
public void setAllowedBetTypes(List<Course.TypeParis> allowedBetTypes) {
this.allowedBetTypes = allowedBetTypes;
}
}

View File

@@ -0,0 +1,52 @@
package com.example.quiz.data.model.dtos;
public class NotifPayload<T> {
private NotifType type;
private String entity;
private Long entityId;
private T payload;
public NotifPayload() {
}
public NotifType getType() {
return type;
}
public void setType(NotifType type) {
this.type = type;
}
public String getEntity() {
return entity;
}
public void setEntity(String entity) {
this.entity = entity;
}
public Long getEntityId() {
return entityId;
}
public void setEntityId(Long entityId) {
this.entityId = entityId;
}
public T getPayload() {
return payload;
}
public void setPayload(T payload) {
this.payload = payload;
}
public enum NotifType {
COURSE_CREATED,
COURSE_UPDATED,
COURSE_CANCELLED,
COURSE_REPORTED,
COURSE_CLOSED_FOR_BETTING,
RUNNER_DECLARED_NON_PARTANT
}
}

View File

@@ -8,6 +8,8 @@ public class Agent {
private String phone;
private String zone;
private String fonction;
private boolean subAgent;
public Agent(){}
public Long getId() {
@@ -65,4 +67,12 @@ public class Agent {
public void setFonction(String fonction) {
this.fonction = fonction;
}
public boolean isSubAgent() {
return subAgent;
}
public void setSubAgent(boolean subAgent) {
this.subAgent = subAgent;
}
}

View File

@@ -0,0 +1,25 @@
package com.example.quiz.data.model.dtos.auth;
public class ChangePin {
private String oldPin;
private String newPin;
public ChangePin() {
}
public String getOldPin() {
return oldPin;
}
public void setOldPin(String oldPin) {
this.oldPin = oldPin;
}
public String getNewPin() {
return newPin;
}
public void setNewPin(String newPin) {
this.newPin = newPin;
}
}

View File

@@ -0,0 +1,17 @@
package com.example.quiz.data.model.dtos.paris;
public class CancelParisPaylaod {
private String statutPari;
public CancelParisPaylaod(String statutPari) {
this.statutPari = statutPari;
}
public String getStatutPari() {
return statutPari;
}
public void setStatutPari(String statutPari) {
this.statutPari = statutPari;
}
}

View File

@@ -0,0 +1,51 @@
package com.example.quiz.data.model.dtos.paris;
public class SoldeResponse {
private int montantParis;
private int nombrePaiements;
private int montantPaiements;
private int nombreAnnulations;
private int montantAnnulations;
// Getters et setters
public int getMontantParis() {
return montantParis;
}
public void setMontantParis(int montantParis) {
this.montantParis = montantParis;
}
public int getNombrePaiements() {
return nombrePaiements;
}
public void setNombrePaiements(int nombrePaiements) {
this.nombrePaiements = nombrePaiements;
}
public int getMontantPaiements() {
return montantPaiements;
}
public void setMontantPaiements(int montantPaiements) {
this.montantPaiements = montantPaiements;
}
public int getNombreAnnulations() {
return nombreAnnulations;
}
public void setNombreAnnulations(int nombreAnnulations) {
this.nombreAnnulations = nombreAnnulations;
}
public int getMontantAnnulations() {
return montantAnnulations;
}
public void setMontantAnnulations(int montantAnnulations) {
this.montantAnnulations = montantAnnulations;
}
}

View File

@@ -1,7 +0,0 @@
package com.example.quiz.data.model.enums;
public enum CourseType {
TIERCE,
QUARTE,
QUINTE
}

View File

@@ -1,21 +1,29 @@
package com.example.quiz.data.remote;
import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.MiseInitiale;
import com.example.quiz.data.model.PagedModel;
import com.example.quiz.data.model.Pari;
import com.example.quiz.data.model.PariMise;
import com.example.quiz.data.model.ParisResponse;
import com.example.quiz.data.model.PointDeVente;
import com.example.quiz.data.model.Restriction;
import com.example.quiz.data.model.Reunion;
import com.example.quiz.data.model.Tpe;
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.LoginResponse;
import com.example.quiz.data.model.TpeResponse;
import com.example.quiz.data.model.dtos.auth.User;
import com.example.quiz.data.model.dtos.paris.CancelParisPaylaod;
import com.example.quiz.data.model.dtos.paris.SoldeResponse;
import java.util.List;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.PATCH;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Path;
@@ -26,7 +34,7 @@ public interface ApiService {
Call<List<Reunion>> getReunions(@Path("date") String date);
@GET("courses")
Call<PagedModel<Course>> getCourses(@Query("reunionDate") String reunionDate);
Call<PagedModel<Course>> getCourses(@Query("reunionDate") String reunionDate, @Query("statut") String statut);
@POST("paris")
Call<ParisResponse> createPari(@Body Pari pari);
@@ -37,18 +45,39 @@ public interface ApiService {
@GET("paris/agent/{agentId}/today")
Call<List<ParisResponse>> derniersParis(@Path("agentId") String agentId);
@PUT("pari/annuler/{numeroTicket}")
Call<ParisResponse> annulerPari(@Path("numeroTicket") String numeroTicket);
@PATCH("paris/numero/{numeroTicket}/statut")
Call<ParisResponse> annulerPari(@Path("numeroTicket") String numeroTicket,
@Body() CancelParisPaylaod cancelParisPaylaod);
@GET("paris/agent/{agentId}/solde/course/{courseId}")
Call<Double> getSoldeByCourse(@Path("agentId") String createdBy, @Path("courseId") String courseId);
Call<SoldeResponse> getSoldeByCourse(@Path("agentId") String createdBy, @Path("courseId") String courseId);
@GET("paris/agent/{agentId}/solde")
Call<Double> getSoldeByDay(@Path("agentId") String agentId, @Query("date") String day);
Call<SoldeResponse> getSoldeByDay(@Path("agentId") String agentId, @Query("date") String day);
@POST("terminaux")
Call<TpeResponse> createTpe(@Body Tpe tpe);
@GET("points-de-vente")
Call<PagedModel<PointDeVente>> getPointsDeVente(@Query("nom") String nom);
@PATCH("agents/me/pin")
Call<User> changePin(@Body ChangePin pin);
@GET("config/mise-initiale")
Call<List<MiseInitiale>> getBetInitMise();
@GET("agents/byMaster/{masterId}")
Call<List<User>> getAgentsByMaster(@Path("masterId") String masterId);
@GET("agents/{agentId}")
Call<User> getAgent(@Path("agentId") String agentId);
@GET("agents/{agentId}/available-bets")
Call<List<Course.TypeParis>> getAvailableBets(@Path("agentId") String agentId);
@PATCH("agents/{masterId}/slaves/{slaveId}/access")
Call<Void> setAccess(@Path("masterId") String masterId, @Path("slaveId") String slaveId, @Query("block") boolean access);
@POST("agents/{masterId}/slaves/{slaveId}/available-bets")
Call<Void> setRestrictions(@Path("masterId") String masterId, @Path("slaveId") String slaveId, @Body Restriction restrictions);
}

View File

@@ -0,0 +1,57 @@
package com.example.quiz.data.remote;
import android.annotation.SuppressLint;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import com.example.quiz.R;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.hilt.android.qualifiers.ApplicationContext;
@Singleton
public class NotificationHelper {
private final Context context;
private static final String CHANNEL_ID = "socket_channel";
@Inject
public NotificationHelper(@ApplicationContext Context context) {
this.context = context;
createChannel();
}
private void createChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
"Socket Notifications",
NotificationManager.IMPORTANCE_HIGH
);
channel.setDescription("Notifications des messages du socket");
NotificationManager manager =
context.getSystemService(NotificationManager.class);
if (manager != null) manager.createNotificationChannel(channel);
}
}
@SuppressLint("MissingPermission")
public void showNotification(String title, String message) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(title)
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true);
NotificationManagerCompat manager = NotificationManagerCompat.from(context);
manager.notify((int) System.currentTimeMillis(), builder.build());
}
}

View File

@@ -1,85 +0,0 @@
package com.example.quiz.data.remote;
import android.util.Log;
import javax.inject.Inject;
import javax.inject.Singleton;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
@Singleton
public class SocketManager {
private final OkHttpClient client;
private final TokenManager tokenManager;
private WebSocket webSocket;
private boolean isConnected = false;
@Inject
public SocketManager(OkHttpClient client, TokenManager tokenManager) {
this.client = client;
this.tokenManager = tokenManager;
}
public synchronized void connect() {
String token = tokenManager.getToken();
if (token == null) {
Log.d("SOCKET", "Token null → no connection");
return;
}
if (isConnected) return;
Request request = new Request.Builder()
.url("ws://boxer-adapting-bluegill.ngrok-free.app/ws")
.addHeader("Authorization", "Bearer " + token)
.build();
webSocket = client.newWebSocket(request, new WebSocketListener() {
@Override
public void onOpen(WebSocket webSocket, Response response) {
isConnected = true;
Log.d("SOCKET", "Connected");
}
@Override
public void onMessage(WebSocket webSocket, String text) {
Log.d("SOCKET", "Message: " + text);
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
isConnected = false;
Log.e("SOCKET", "Error: " + t.getMessage());
// tentative de reconnexion
reconnect();
}
@Override
public void onClosed(WebSocket webSocket, int code, String reason) {
isConnected = false;
}
});
}
public synchronized void reconnect() {
disconnect();
connect();
}
public synchronized void disconnect() {
if (webSocket != null) {
webSocket.close(1000, "Closing");
webSocket = null;
}
isConnected = false;
}
}

View File

@@ -0,0 +1,285 @@
package com.example.quiz.data.remote;
import android.util.Log;
import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.dtos.NotifPayload;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Singleton;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import ua.naiksoftware.stomp.Stomp;
import ua.naiksoftware.stomp.StompClient;
import ua.naiksoftware.stomp.dto.StompHeader;
@Singleton
public class StompManager {
private final TokenManager tokenManager;
private final NotificationHelper notificationHelper;
private StompClient stompClient;
private boolean isConnected = false;
// Map topic -> liste de listeners
private final Map<String, List<Consumer<String>>> topicListeners = new HashMap<>();
// Gestion des Disposables RxJava
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
// Map pour stocker les subscriptions par topic
private final Map<String, Disposable> topicSubscriptions = new HashMap<>();
@Inject
public StompManager(TokenManager tokenManager,
NotificationHelper notificationHelper) {
this.tokenManager = tokenManager;
this.notificationHelper = notificationHelper;
}
// -------------------- Connexion --------------------
public synchronized void connect() {
if (isConnected) return;
String token = tokenManager.getToken();
if (token == null) {
Log.e("STOMP", "No token available");
return;
}
// URL de connexion WebSocket
String url = "wss://boxer-adapting-bluegill.ngrok-free.app/ws";
try {
// Créer le client STOMP
stompClient = Stomp.over(Stomp.ConnectionProvider.OKHTTP, url);
// Ajouter les headers d'authentification
List<StompHeader> headers = new ArrayList<>();
headers.add(new StompHeader("Authorization", "Bearer " + token));
// Observer la connexion et stocker le Disposable
Disposable lifecycleDisposable = stompClient.lifecycle()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(lifecycleEvent -> {
switch (lifecycleEvent.getType()) {
case OPENED:
isConnected = true;
Log.d("STOMP", "Connected to WebSocket");
resubscribeAll();
break;
case CLOSED:
isConnected = false;
Log.d("STOMP", "Disconnected from WebSocket");
break;
case ERROR:
isConnected = false;
Log.e("STOMP", "Error: " + lifecycleEvent.getException());
reconnect();
break;
}
}, throwable -> {
Log.e("STOMP", "Lifecycle error", throwable);
isConnected = false;
reconnect();
});
compositeDisposable.add(lifecycleDisposable);
// Se connecter
stompClient.connect(headers);
} catch (Exception e) {
Log.e("STOMP", "Connection error", e);
reconnect();
}
}
// -------------------- Souscription aux topics --------------------
public synchronized void subscribe(String topic, Consumer<String> listener) {
// Ajouter le listener
topicListeners.computeIfAbsent(topic, k -> new ArrayList<>()).add(listener);
// Si déjà connecté, souscrire immédiatement
if (isConnected && stompClient != null) {
subscribeToTopic(topic);
} else {
connect();
}
}
private void subscribeToTopic(String topic) {
if (stompClient == null) return;
// Si déjà abonné à ce topic, ne pas souscrire à nouveau
if (topicSubscriptions.containsKey(topic)) {
Log.d("STOMP", "Already subscribed to " + topic);
return;
}
// Formater le topic correctement
String destination = topic.startsWith("/topic/") ? topic : "/topic/" + topic;
Log.d("STOMP", "Subscribing to " + destination);
Disposable subscription = stompClient.topic(destination)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
stompMessage -> {
String payload = stompMessage.getPayload();
Log.d("STOMP", "Message on " + destination + ": " + payload);
// Notifier les listeners
List<Consumer<String>> listeners = topicListeners.get(topic);
if (listeners != null) {
for (Consumer<String> listener : listeners) {
try {
listener.accept(payload);
} catch (Exception e) {
Log.e("STOMP", "Listener error", e);
}
}
}
String notif = "";
Type type = new TypeToken<NotifPayload<Course>>(){}.getType();
NotifPayload<Course> notifCourse = new Gson().fromJson(payload, type);
Course updatedCourse = notifCourse.getPayload();
switch (notifCourse.getType()){
case COURSE_CREATED:
notif = "Nouvelle course "+updatedCourse.getNom()+" créée";
break;
case COURSE_UPDATED:
notif = "Course "+updatedCourse.getNom()+" modifiée";
break;
case COURSE_CANCELLED:
notif = "Course "+updatedCourse.getNom()+" annulée";
break;
case COURSE_REPORTED:
notif = "Course "+updatedCourse.getNom()+" reportée";
break;
case COURSE_CLOSED_FOR_BETTING:
notif = "Course "+updatedCourse.getNom()+" fermée aux paris!";
break;
case RUNNER_DECLARED_NON_PARTANT:
notif = "Non partants déclarés pour la course "+updatedCourse.getNom();
break;
}
// Notification
notificationHelper.showNotification(topic, notif);
},
throwable -> {
Log.e("STOMP", "Error on " + destination, throwable);
// Nettoyer en cas d'erreur
topicSubscriptions.remove(topic);
}
);
topicSubscriptions.put(topic, subscription);
compositeDisposable.add(subscription);
}
private void resubscribeAll() {
if (stompClient == null) return;
// Nettoyer les anciennes subscriptions
for (Disposable disposable : topicSubscriptions.values()) {
if (disposable != null && !disposable.isDisposed()) {
disposable.dispose();
}
}
topicSubscriptions.clear();
// Resouscrire à tous les topics
for (String topic : topicListeners.keySet()) {
subscribeToTopic(topic);
}
}
// -------------------- Envoi de messages --------------------
public void sendMessage(String destination, Object payload) {
if (!isConnected || stompClient == null) {
Log.e("STOMP", "Not connected");
return;
}
String dest = destination.startsWith("/app/") ? destination : "/app/" + destination;
Disposable sendDisposable = stompClient.send(dest, payload.toString())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
() -> Log.d("STOMP", "Message sent to " + dest),
throwable -> Log.e("STOMP", "Error sending to " + dest, throwable)
);
compositeDisposable.add(sendDisposable);
}
public void sendToCourses(Object payload) {
sendMessage("/app/courses", payload);
}
// -------------------- Désabonnement --------------------
public synchronized void unsubscribe(String topic, Consumer<String> listener) {
if (topicListeners.containsKey(topic)) {
topicListeners.get(topic).remove(listener);
if (topicListeners.get(topic).isEmpty()) {
topicListeners.remove(topic);
// Si plus de listeners, annuler la souscription STOMP
Disposable subscription = topicSubscriptions.remove(topic);
if (subscription != null && !subscription.isDisposed()) {
subscription.dispose();
compositeDisposable.remove(subscription);
}
}
}
}
// -------------------- Déconnexion --------------------
public synchronized void disconnect() {
// Nettoyer toutes les subscriptions RxJava
compositeDisposable.clear();
topicSubscriptions.clear();
if (stompClient != null) {
stompClient.disconnect();
stompClient = null;
}
isConnected = false;
topicListeners.clear();
}
private void reconnect() {
disconnect();
// Réessayer après délai
new android.os.Handler().postDelayed(() -> {
Log.d("STOMP", "Attempting to reconnect...");
connect();
}, 5000);
}
// À appeler dans le cycle de vie du fragment/activity
public void onCleanup() {
disconnect();
compositeDisposable.dispose();
}
}

View File

@@ -11,16 +11,13 @@ public class TokenManager {
private static final String PREF_NAME = "auth_pref";
private static final String KEY_TOKEN = "auth_token";
SocketManager socketManager;
private SharedPreferences sharedPreferences;
@Inject
public TokenManager(@ApplicationContext Context context, SocketManager socketManager) {
public TokenManager(@ApplicationContext Context context) {
this.sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
this.socketManager = socketManager;
}
public void saveToken(String token){
sharedPreferences.edit().putString(KEY_TOKEN, token).apply();
socketManager.reconnect();
}
public String getToken(){

View File

@@ -0,0 +1,128 @@
package com.example.quiz.data.repository;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.Restriction;
import com.example.quiz.data.model.dtos.auth.User;
import com.example.quiz.data.remote.ApiService;
import com.example.quiz.utils.Result;
import java.util.List;
import javax.inject.Inject;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class AgentRepository {
private ApiService apiService;
@Inject
public AgentRepository(ApiService apiService) {
this.apiService = apiService;
}
public LiveData<Result<List<User>>> getAgents(String agentId) {
MutableLiveData<Result<List<User>>> liveAgents = new MutableLiveData<>();
liveAgents.setValue(Result.loading());
apiService.getAgentsByMaster(agentId).enqueue(new Callback<List<User>>() {
@Override
public void onResponse(@NonNull Call<List<User>> call, @NonNull Response<List<User>> response) {
if (response.isSuccessful()) {
liveAgents.postValue(Result.success(response.body()));
} else {
liveAgents.postValue(Result.error(response.message()));
}
}
@Override
public void onFailure(@NonNull Call<List<User>> call, @NonNull Throwable throwable) {
liveAgents.postValue(Result.error(throwable.getMessage()));
}
});
return liveAgents;
}
public LiveData<Result<User>> getAgentById(String agentId) {
MutableLiveData<Result<User>> liveAgent = new MutableLiveData<>();
liveAgent.setValue(Result.loading());
apiService.getAgent(agentId).enqueue(new Callback<User>() {
@Override
public void onResponse(@NonNull Call<User> call, @NonNull Response<User> response) {
if (response.isSuccessful()) {
liveAgent.postValue(Result.success(response.body()));
} else {
liveAgent.postValue(Result.error(response.message()));
}
}
@Override
public void onFailure(@NonNull Call<User> call, @NonNull Throwable throwable) {
liveAgent.postValue(Result.error(throwable.getMessage()));
}
});
return liveAgent;
}
public LiveData<Result<List<Course.TypeParis>>> getAvailableBets(String agentId) {
MutableLiveData<Result<List<Course.TypeParis>>> liveAvailableBets = new MutableLiveData<>();
liveAvailableBets.setValue(Result.loading());
apiService.getAvailableBets(agentId).enqueue(new Callback<List<Course.TypeParis>>() {
@Override
public void onResponse(@NonNull Call<List<Course.TypeParis>> call, @NonNull Response<List<Course.TypeParis>> response) {
if (response.isSuccessful()) {
liveAvailableBets.postValue(Result.success(response.body()));
} else {
liveAvailableBets.postValue(Result.error(response.message()));
}
}
@Override
public void onFailure(@NonNull Call<List<Course.TypeParis>> call, @NonNull Throwable throwable) {
liveAvailableBets.postValue(Result.error(throwable.getMessage()));
}
});
return liveAvailableBets;
}
public LiveData<Result<Void>> setAccess(String masterId, String slaveId, boolean access) {
MutableLiveData<Result<Void>> liveSetAccess = new MutableLiveData<>();
liveSetAccess.setValue(Result.loading());
apiService.setAccess(masterId, slaveId, access).enqueue(new Callback<Void>() {
@Override
public void onResponse(@NonNull Call<Void> call, @NonNull Response<Void> response) {
if (response.isSuccessful()) {
liveSetAccess.postValue(Result.success(null));
} else {
liveSetAccess.postValue(Result.error(response.message()));
}
}
@Override
public void onFailure(@NonNull Call<Void> call, @NonNull Throwable throwable) {
liveSetAccess.postValue(Result.error(throwable.getMessage()));
}
});
return liveSetAccess;
};
public LiveData<Result<Void>> setRestrictions(String masterId, String slaveId, Restriction restrictions) {
MutableLiveData<Result<Void>> liveSetRestrictions = new MutableLiveData<>();
liveSetRestrictions.setValue(Result.loading());
apiService.setRestrictions(masterId, slaveId, restrictions).enqueue(new Callback<Void>() {
@Override
public void onResponse(@NonNull Call<Void> call, @NonNull Response<Void> response) {
if (response.isSuccessful()) {
liveSetRestrictions.postValue(Result.success(null));
} else {
liveSetRestrictions.postValue(Result.error(response.message()));
}
}
@Override
public void onFailure(@NonNull Call<Void> call, @NonNull Throwable throwable) {
liveSetRestrictions.postValue(Result.error(throwable.getMessage()));
}
});
return liveSetRestrictions;
}
}

View File

@@ -10,8 +10,6 @@ import com.example.quiz.data.model.PagedModel;
import com.example.quiz.data.remote.ApiService;
import com.example.quiz.utils.Result;
import java.util.List;
import javax.inject.Inject;
import retrofit2.Call;
@@ -20,6 +18,7 @@ import retrofit2.Response;
public class CourseRepository {
private ApiService apiService;
private final Course.Statut OPENED_STATUT = Course.Statut.OUVERT;
@Inject
public CourseRepository(ApiService apiService) {
@@ -29,11 +28,25 @@ public class CourseRepository {
public LiveData<Result<PagedModel<Course>>> getCourses(String reunionDate) {
MutableLiveData<Result<PagedModel<Course>>> liveCourses = new MutableLiveData<Result<PagedModel<Course>>>();
liveCourses.setValue(Result.loading());
apiService.getCourses(reunionDate).enqueue(new Callback<PagedModel<Course>>() {
apiService.getCourses(reunionDate,String.valueOf(OPENED_STATUT)).enqueue(new Callback<PagedModel<Course>>() {
@Override
public void onResponse(Call<PagedModel<Course>> call, Response<PagedModel<Course>> response) {
if(response.isSuccessful()){
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{
liveCourses.postValue(Result.error(response.message()));
}

View File

@@ -5,8 +5,10 @@ import android.util.Log;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
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.LoginResponse;
import com.example.quiz.data.model.dtos.auth.User;
import com.example.quiz.data.remote.ApiService;
import com.example.quiz.data.remote.TokenManager;
import com.example.quiz.utils.Result;
@@ -20,6 +22,7 @@ import retrofit2.Response;
public class LoginRepository {
private ApiService apiService;
private TokenManager tokenManager;
@Inject
public LoginRepository(ApiService apiService, TokenManager tokenManager) {
this.tokenManager = tokenManager;
@@ -37,15 +40,38 @@ public class LoginRepository {
Log.d("TOKEN", response.body().getToken());
tokenManager.saveToken(response.body().getToken());
}else{
liveLogin.postValue(Result.error(response.message()));
liveLogin.postValue(Result.error(response.toString()));
}
}
@Override
public void onFailure(Call<LoginResponse> call, Throwable throwable) {
liveLogin.postValue(Result.error(throwable.getMessage()));
liveLogin.postValue(Result.error(throwable.toString()));
}
});
return liveLogin;
}
public LiveData<Result<User>> changePin(String oldPin, String newPin){
MutableLiveData<Result<User>> liveUser = new MutableLiveData<Result<User>>();
liveUser.setValue(Result.loading());
ChangePin changePin = new ChangePin();
changePin.setOldPin(oldPin);
changePin.setNewPin(newPin);
apiService.changePin(changePin).enqueue(new Callback<User>(){
@Override
public void onResponse(Call<User> call, Response<User> response) {
if(response.isSuccessful()) {
liveUser.postValue(Result.success(response.body()));
}else {
liveUser.postValue(Result.error(response.message()));
}
}
@Override
public void onFailure(Call<User> call, Throwable throwable) {
liveUser.postValue(Result.error(throwable.getMessage()));
}
});
return liveUser;
}
}

View File

@@ -0,0 +1,47 @@
package com.example.quiz.data.repository;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.example.quiz.data.model.MiseInitiale;
import com.example.quiz.data.model.PariMise;
import com.example.quiz.data.remote.ApiService;
import com.example.quiz.data.remote.TokenManager;
import com.example.quiz.utils.Result;
import java.util.List;
import javax.inject.Inject;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class PariMiseRepository {
private ApiService apiService;
@Inject
public PariMiseRepository(ApiService apiService, TokenManager tokenManager) {
this.apiService = apiService;
}
public LiveData<Result<List<MiseInitiale>>> getBetInitMise() {
MutableLiveData<Result<List<MiseInitiale>>> livePariMise = new MutableLiveData<Result<List<MiseInitiale>>>();
livePariMise.setValue(Result.loading());
apiService.getBetInitMise().enqueue(new Callback<List<MiseInitiale>>() {
@Override
public void onResponse(Call<List<MiseInitiale>> call, Response<List<MiseInitiale>> response) {
if (response.isSuccessful()) {
livePariMise.postValue(Result.success(response.body()));
}else{
livePariMise.postValue(Result.error(response.message()));
}
}
@Override
public void onFailure(Call<List<MiseInitiale>> call, Throwable throwable) {
livePariMise.postValue(Result.error(throwable.getMessage()));
}
});
return livePariMise;
}
}

View File

@@ -8,6 +8,8 @@ import androidx.lifecycle.MutableLiveData;
import com.example.quiz.data.model.Pari;
import com.example.quiz.data.model.ParisResponse;
import com.example.quiz.data.model.dtos.paris.CancelParisPaylaod;
import com.example.quiz.data.model.dtos.paris.SoldeResponse;
import com.example.quiz.data.remote.ApiService;
import com.example.quiz.utils.Result;
@@ -96,7 +98,8 @@ public class PariRepository {
public LiveData<Result<ParisResponse>> annulerPari(String numeroTicket){
MutableLiveData<Result<ParisResponse>> pariResponse = new MutableLiveData<>();
pariResponse.setValue(Result.loading());
apiService.annulerPari(numeroTicket).enqueue(new Callback<ParisResponse>(){
CancelParisPaylaod cancelParisPaylaod = new CancelParisPaylaod("ANNULE");
apiService.annulerPari(numeroTicket, cancelParisPaylaod).enqueue(new Callback<ParisResponse>(){
@Override
public void onResponse(Call<ParisResponse> call, Response<ParisResponse> response) {
if(response.isSuccessful()){
@@ -121,12 +124,12 @@ public class PariRepository {
return pariResponse;
}
public LiveData<Result<Double>> getSoldeByCourse(String agentId, String courseId){
MutableLiveData<Result<Double>> solde = new MutableLiveData<>();
public LiveData<Result<SoldeResponse>> getSoldeByCourse(String agentId, String courseId){
MutableLiveData<Result<SoldeResponse>> solde = new MutableLiveData<>();
solde.setValue(Result.loading());
apiService.getSoldeByCourse(agentId, courseId).enqueue(new Callback<Double>() {
apiService.getSoldeByCourse(agentId, courseId).enqueue(new Callback<SoldeResponse>() {
@Override
public void onResponse(Call<Double> call, Response<Double> response) {
public void onResponse(Call<SoldeResponse> call, Response<SoldeResponse> response) {
if(response.isSuccessful()){
solde.postValue(Result.success(response.body()));
}else{
@@ -139,19 +142,19 @@ public class PariRepository {
}
@Override
public void onFailure(Call<Double> call, Throwable throwable) {
public void onFailure(Call<SoldeResponse> call, Throwable throwable) {
solde.postValue(Result.error(throwable.getMessage()));
}
});
return solde;
}
public LiveData<Result<Double>> getSoldeByDay(String agentId, String day){
MutableLiveData<Result<Double>> solde = new MutableLiveData<>();
public LiveData<Result<SoldeResponse>> getSoldeByDay(String agentId, String day){
MutableLiveData<Result<SoldeResponse>> solde = new MutableLiveData<>();
solde.setValue(Result.loading());
apiService.getSoldeByDay(agentId, day).enqueue(new Callback<Double>() {
apiService.getSoldeByDay(agentId, day).enqueue(new Callback<SoldeResponse>() {
@Override
public void onResponse(Call<Double> call, Response<Double> response) {
public void onResponse(Call<SoldeResponse> call, Response<SoldeResponse> response) {
if(response.isSuccessful()){
solde.postValue(Result.success(response.body()));
}else{
@@ -164,7 +167,7 @@ public class PariRepository {
}
@Override
public void onFailure(Call<Double> call, Throwable throwable) {
public void onFailure(Call<SoldeResponse> call, Throwable throwable) {
solde.postValue(Result.error(throwable.getMessage()));
}
});

View File

@@ -28,21 +28,24 @@ public class AuthNavigator {
private FragmentManager fragmentManager;
private TokenManager tokenManager;
private final SessionManager sessionManager;
LoginViewModel viewModel;
LogsViewModel logsViewModel;
private LoginViewModel viewModel;
private LogsViewModel logsViewModel;
private LifecycleOwner lifecycleOwner;
private Dialog dialog;
SharedPrefsHelper prefsHelper;
public AuthNavigator(Context context,
FragmentManager fragmentManager,
SessionManager sessionManager,
LoginViewModel viewModel,
LogsViewModel logsViewModel) {
LogsViewModel logsViewModel,
LifecycleOwner lifecycleOwner) {
this.viewModel = viewModel;
this.logsViewModel = logsViewModel;
this.prefsHelper = SharedPrefsHelper.getInstance(context);
@@ -50,6 +53,7 @@ public class AuthNavigator {
this.context = context;
dialog = new Dialog(context);
this.sessionManager = sessionManager;
this.lifecycleOwner = lifecycleOwner;
}
public void navigate(Fragment destinationFragment) {
@@ -98,12 +102,15 @@ public class AuthNavigator {
pin.setError("Le pin doit contenir minimum quatre chiffres!");
return;
}
if(prefsHelper.get("terminalId") == null){
MessageDialog.showError(context, "Terminal non trouvé");
}
LoginPayload loginPayload = new LoginPayload(
code.getText().toString(),
pin.getText().toString(),
Long.valueOf(prefsHelper.get("terminalId"))
);
viewModel.login(loginPayload).observe((LifecycleOwner) context, new Observer<Result<LoginResponse>>() {
viewModel.login(loginPayload).observe(lifecycleOwner, new Observer<Result<LoginResponse>>() {
@Override
public void onChanged(Result<LoginResponse> loginResponseResult) {
switch (loginResponseResult.status){
@@ -137,11 +144,18 @@ public class AuthNavigator {
}
private void loginSuccess(LoginResponse loginResponse){
String terminalId = prefsHelper.get("terminalId");
if(terminalId == null){
MessageDialog.showError(context, "Terminal non trouvé");
return;
}
prefsHelper.save("id", String.valueOf(loginResponse.getUser().getId()));
prefsHelper.save("firstName", loginResponse.getUser().getPrenom());
prefsHelper.save("lastName", loginResponse.getUser().getNom());
prefsHelper.save("profile", loginResponse.getUser().getFonction());
prefsHelper.save("code", loginResponse.getUser().getCode());
String isSupAgent = loginResponse.getUser().isSubAgent() ? "true" : "false";
prefsHelper.save("isSupAgent", isSupAgent);
}
}

View File

@@ -0,0 +1,56 @@
package com.example.quiz.viewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.Restriction;
import com.example.quiz.data.model.dtos.auth.User;
import com.example.quiz.data.repository.AgentRepository;
import com.example.quiz.utils.Result;
import java.util.List;
import javax.inject.Inject;
import dagger.hilt.android.lifecycle.HiltViewModel;
@HiltViewModel
public class AgentViewModel extends ViewModel {
private final AgentRepository agentRepository;
private LiveData<Result<List<User>>> agents;
private LiveData<Result<User>> agentDetails;
private LiveData<Result<List<Course.TypeParis>>> availableBets;
@Inject
public AgentViewModel(AgentRepository agentRepository) {
this.agentRepository = agentRepository;
}
public LiveData<Result<List<User>>> getAgents(String agentId) {
agents = agentRepository.getAgents(agentId);
return agents;
}
public LiveData<Result<User>> getAgentById(String agentId) {
agentDetails = agentRepository.getAgentById(agentId);
return agentDetails;
}
public LiveData<Result<List<Course.TypeParis>>> getAvailableBets(String agentId) {
availableBets = agentRepository.getAvailableBets(agentId);
return availableBets;
}
public LiveData<Result<Void>> setAccess(String masterId, String slaveId, boolean access) {
return agentRepository.setAccess(masterId, slaveId, access);
};
public LiveData<Result<Void>> setRestrictions(String masterId, String slaveId, Restriction restrictions) {
return agentRepository.setRestrictions(masterId, slaveId, restrictions);
}
}

View File

@@ -1,10 +1,13 @@
package com.example.quiz.viewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
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.LoginResponse;
import com.example.quiz.data.model.dtos.auth.User;
import com.example.quiz.data.repository.LoginRepository;
import com.example.quiz.utils.Result;
@@ -16,6 +19,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel;
public class LoginViewModel extends ViewModel {
LoginRepository loginRepository;
LiveData<Result<User>> user = new MutableLiveData<>();
@Inject
public LoginViewModel(LoginRepository loginRepository) {
this.loginRepository = loginRepository;
@@ -24,4 +28,9 @@ public class LoginViewModel extends ViewModel {
public LiveData<Result<LoginResponse>> login(LoginPayload loginPayload){
return loginRepository.login(loginPayload);
}
public LiveData<Result<User>> changePin(String oldPin, String newPin){
user = loginRepository.changePin(oldPin, newPin);
return user;
}
}

View File

@@ -0,0 +1,4 @@
package com.example.quiz.viewModel;
public class NotificationViewModel {
}

View File

@@ -0,0 +1,33 @@
package com.example.quiz.viewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import com.example.quiz.data.model.MiseInitiale;
import com.example.quiz.data.model.PariMise;
import com.example.quiz.data.repository.PariMiseRepository;
import com.example.quiz.utils.Result;
import java.util.List;
import javax.inject.Inject;
import dagger.hilt.android.lifecycle.HiltViewModel;
@HiltViewModel
public class PariMiseViewModel extends ViewModel {
private final PariMiseRepository pariMiseRepository;
private LiveData<Result<List<MiseInitiale>>> pariMise;
@Inject
public PariMiseViewModel(PariMiseRepository pariMiseRepository) {
this.pariMiseRepository = pariMiseRepository;
}
public LiveData<Result<List<MiseInitiale>>> getBetInitMise() {
this.pariMise = pariMiseRepository.getBetInitMise();
return this.pariMise;
}
}

View File

@@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModel;
import com.example.quiz.data.model.Pari;
import com.example.quiz.data.model.ParisResponse;
import com.example.quiz.data.model.dtos.paris.SoldeResponse;
import com.example.quiz.data.repository.PariRepository;
import com.example.quiz.utils.Result;
@@ -23,9 +24,9 @@ public class PariViewModel extends ViewModel {
private LiveData<Result<ParisResponse>> pariAnnule;
private LiveData<Result<Double>> solde;
private LiveData<Result<SoldeResponse>> solde;
private LiveData<Result<Double>> soldeByDay;
private LiveData<Result<SoldeResponse>> soldeByDay;
@Inject
public PariViewModel(PariRepository repository){
@@ -47,12 +48,12 @@ public class PariViewModel extends ViewModel {
return pariAnnule;
}
public LiveData<Result<Double>> getSoldeByCourse(String agentId, String courseId){
public LiveData<Result<SoldeResponse>> getSoldeByCourse(String agentId, String courseId){
solde = pariRepository.getSoldeByCourse(agentId, courseId);
return solde;
}
public LiveData<Result<Double>> getSoldeByDay(String agentId, String day){
public LiveData<Result<SoldeResponse>> getSoldeByDay(String agentId, String day){
soldeByDay = pariRepository.getSoldeByDay(agentId, day);
return soldeByDay;
}