Compare commits

...

13 Commits

Author SHA1 Message Date
OnlyPapy98
4ef19bd4e8 ticket fomattage 2026-04-30 13:08:05 +02:00
OnlyPapy98
c0e5072523 total review 2026-04-03 19:30:06 +02:00
OnlyPapy98
4eaca7e1d8 Version avec integration slave master 2026-04-01 19:51:19 +02:00
OnlyPapy98
acc5ec1b70 gestion des formats de tickets! 2026-02-16 10:16:49 +01:00
OnlyPapy98
2fc21fd433 correction on mise calculation 2025-12-16 16:22:43 +01:00
OnlyPapy98
b3d94ad038 70% of features done! 2025-12-12 17:55:12 +01:00
OnlyPapy98
dc93d1320f in progress! 2025-12-05 18:08:01 +01:00
OnlyPapy98
ed92a63015 print successfully integrated! 2025-12-03 09:41:46 +01:00
OnlyPapy98
87a3e952aa new printer integration! 2025-11-28 16:35:53 +01:00
OnlyPapy98
1031307b3a break for printer! 2025-11-27 11:54:52 +01:00
OnlyPapy98
8f80492287 create pari 2025-11-18 18:03:02 +01:00
OnlyPapy98
b1ce91ef20 http request call done 2025-11-12 16:52:48 +01:00
OnlyPapy98
159837bd6f type of game step done! 2025-10-31 16:17:15 +01:00
257 changed files with 22403 additions and 1286 deletions

2
.idea/compiler.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="CompilerConfiguration"> <component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" /> <bytecodeTargetLevel target="17" />
</component> </component>
</project> </project>

View File

@@ -4,10 +4,10 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-09-29T14:58:34.998303700Z"> <DropdownSelection timestamp="2026-04-03T13:27:33.582048600Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\T480\.android\avd\Pixel_7_API_34.avd" /> <DeviceId pluginId="PhysicalDevice" identifier="serial=5051917024" />
</handle> </handle>
</Target> </Target>
</DropdownSelection> </DropdownSelection>

3
.idea/gradle.xml generated
View File

@@ -6,11 +6,12 @@
<GradleProjectSettings> <GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" /> <option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" /> <option name="gradleJvm" value="17" />
<option name="modules"> <option name="modules">
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" /> <option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/printama" />
</set> </set>
</option> </option>
<option name="resolveExternalAnnotations" value="false" /> <option name="resolveExternalAnnotations" value="false" />

View File

@@ -0,0 +1,8 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="AutoCloseableResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="METHOD_MATCHER_CONFIG" value="java.util.Formatter,format,java.io.Writer,append,com.google.common.base.Preconditions,checkNotNull,org.hibernate.Session,close,java.io.PrintWriter,printf,java.io.PrintStream,printf,java.lang.foreign.Arena,ofAuto,java.lang.foreign.Arena,global,retrofit2.Response,errorBody" />
</inspection_tool>
</profile>
</component>

6
.idea/kotlinc.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.24" />
</component>
</project>

2
.idea/misc.xml generated
View File

@@ -1,6 +1,6 @@
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@@ -1,7 +1,17 @@
import java.util.Properties
plugins { plugins {
alias(libs.plugins.android.application) alias(libs.plugins.android.application)
alias(libs.plugins.google.android.libraries.mapsplatform.secrets.gradle.plugin) alias(libs.plugins.google.android.libraries.mapsplatform.secrets.gradle.plugin)
id("com.google.dagger.hilt.android") id("com.google.dagger.hilt.android")
alias(libs.plugins.kotlin.android)
}
val keystoreProperties = Properties()
val keystorePropertiesFile = rootProject.file("local.properties")
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(keystorePropertiesFile.inputStream())
} }
android { android {
@@ -18,39 +28,90 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
signingConfigs {
create("release") {
storeFile = file(keystoreProperties["STORE_FILE"] as String)
storePassword = keystoreProperties["STORE_PASSWORD"] as String
keyAlias = keystoreProperties["KEY_ALIAS"] as String
keyPassword = keystoreProperties["KEY_PASSWORD"] as String
}
}
buildTypes { buildTypes {
release { release {
isMinifyEnabled = false isMinifyEnabled = false
signingConfig = signingConfigs.getByName("release")
proguardFiles( proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"), getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro" "proguard-rules.pro"
) )
} }
} }
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_11 sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11
} }
buildFeatures { buildFeatures {
viewBinding = true viewBinding = true
} }
kotlinOptions {
jvmTarget = "17"
}
} }
dependencies { dependencies {
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar", "*.aar")))) implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar", "*.aar"))))
implementation(libs.room.runtime)
annotationProcessor(libs.room.compiler)
implementation("com.github.NaikSoftware:StompProtocolAndroid:1.6.6")
implementation("io.reactivex.rxjava2:rxjava:2.2.21")
implementation("io.reactivex.rxjava2:rxandroid:2.1.1")
implementation(libs.retrofit)
implementation(libs.okhttp)
implementation(libs.logging.interceptor)
implementation(libs.converter.gson)
implementation(libs.kotlinx.coroutines.android)
implementation(libs.hilt.android) implementation(libs.hilt.android)
annotationProcessor(libs.hilt.compiler) annotationProcessor(libs.hilt.compiler)
implementation(libs.rxjava)
implementation(libs.rxandroid)
implementation(libs.recyclerview.v7) implementation(libs.recyclerview.v7)
implementation(libs.appcompat) implementation(libs.appcompat)
implementation(libs.material) implementation(libs.material)
implementation(libs.constraintlayout) implementation(libs.constraintlayout)
implementation(libs.printerlibrary)
implementation(libs.navigation.fragment) implementation(libs.navigation.fragment)
implementation(libs.navigation.ui) implementation(libs.navigation.ui)
implementation(libs.play.services.maps) implementation(libs.play.services.maps)
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.camera:camera-camera2:1.2.3")
implementation("androidx.camera:camera-lifecycle:1.2.3")
implementation("androidx.camera:camera-view:1.2.3")
implementation("androidx.camera:camera-core:1.2.3")
implementation("com.google.mlkit:barcode-scanning:17.2.0")
implementation(libs.zxing.android.embedded)
implementation(project(":printama"))
testImplementation(libs.junit) testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit) androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core) androidTestImplementation(libs.espresso.core)
implementation("androidx.annotation:annotation:1.7.1")
} }

Binary file not shown.

View File

@@ -2,10 +2,52 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.BLUETOOTH"/> <!-- ✅ Bluetooth Permissions (Handle Both Legacy and Modern) -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.CAMERA" />
<!-- ✅ Required for Android 12+ -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="com.sunmi.peripheral.printer.permission.PRINTER" />
<!-- Pour certains modèles -->
<uses-permission android:name="android.permission.BIND_PRINTER_SERVICE" />
<!-- ✅ Location Permissions -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- ✅ Storage and Network -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
<!-- ✅ USB and Hardware -->
<uses-feature android:name="android.hardware.usb.host" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<queries>
<package android:name="woyou.aidlservice.jiuiv5" />
</queries>
<application <application
android:name=".PmuHorseBetting" android:name=".PmuHorseBetting"
@@ -17,11 +59,8 @@
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.Quiz" android:theme="@style/Theme.Quiz"
tools:targetApi="31"> tools:targetApi="31"
<activity android:usesCleartextTraffic="true">
android:name=".PageQuiz"
android:exported="true"
android:theme="@style/Theme.Quiz" />
<!-- <!--
TODO: Before you run your application, you need a Google Maps API key. TODO: Before you run your application, you need a Google Maps API key.
@@ -37,8 +76,9 @@
android:name="com.google.android.geo.API_KEY" android:name="com.google.android.geo.API_KEY"
android:value="YOUR_API_KEY" /> android:value="YOUR_API_KEY" />
<activity <activity
android:name=".MainActivity" android:name=".PageQuiz"
android:exported="true" android:exported="true"
android:theme="@style/Theme.Quiz"> android:theme="@style/Theme.Quiz">
<intent-filter> <intent-filter>

Binary file not shown.

After

Width:  |  Height:  |  Size: 974 KiB

View File

@@ -0,0 +1,337 @@
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 com.example.quiz.viewModel.LogsViewModel;
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;
LogsViewModel logsViewModel;
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());
logsViewModel = new ViewModelProvider(this).get(LogsViewModel.class);
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");
String logsMessage = !b? "Activation de l'accès du sous agent":"Désactivation de l'accès du sous agent";
logsViewModel.insertLog(prefsHelper.get("id"), !b?"ACTIVATION":"DESACTIVATION",message+" "+agent.getCode(), System.currentTimeMillis());
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();
logsViewModel.insertLog(prefsHelper.get("id"), "MIS A JOUR PRODUIT", "Mise à jour des types de paris"+" "+agent.getCode()+": "+allowedBetTypes.getAllowedBetTypes().stream().map(Enum::toString).collect(Collectors.joining(",")), System.currentTimeMillis());
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

@@ -0,0 +1,168 @@
package com.example.quiz;
import android.app.AlertDialog;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.example.quiz.data.model.ParisResponse;
import com.example.quiz.databinding.FragmentAnnulationTicketBinding;
import com.example.quiz.utils.LoaderDialog;
import com.example.quiz.utils.MessageDialog;
import com.example.quiz.utils.Result;
import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.LogsViewModel;
import com.example.quiz.viewModel.PariViewModel;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link AnnulationTicket#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class AnnulationTicket extends Fragment {
FragmentAnnulationTicketBinding binding;
SharedPrefsHelper prefsHelper;
LogsViewModel logsViewModel;
PariViewModel viewModel;
LoaderDialog dialog;
public AnnulationTicket() {
// Required empty public constructor
}
public static AnnulationTicket newInstance() {
AnnulationTicket fragment = new AnnulationTicket();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentAnnulationTicketBinding.inflate(inflater, container, false);
prefsHelper = SharedPrefsHelper.getInstance(getContext());
logsViewModel = new ViewModelProvider(this).get(LogsViewModel.class);
dialog = new LoaderDialog(getContext());
return binding.getRoot();
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
viewModel = new ViewModelProvider(this).get(PariViewModel.class);
binding.annuleTicketBtnBack.setOnClickListener(v->{
getActivity().onBackPressed();
});
binding.scanTicketBtn.setOnClickListener(v -> {
ScannerDialog scannerDialog = new ScannerDialog();
scannerDialog.setOnBarcodeScannedListener(code -> {
binding.referenceTicket.setText(code);
});
scannerDialog.show(getParentFragmentManager(), "scanner");
});
binding.annuleTicketBtn.setOnClickListener(v->{
String reference = binding.referenceTicket.getText().toString();
if(reference.isEmpty()){
MessageDialog.showError(getContext(), "Veuillez donner la reference du ticket");
return;
}
viewModel.getPariByNumero(reference).observe(getViewLifecycleOwner(), new Observer<Result<ParisResponse>>() {
@Override
public void onChanged(Result<ParisResponse> parisResponseResult) {
switch (parisResponseResult.status){
case LOADING:{
dialog.show("Recherche du ticket");
break;
}
case ERROR:{
MessageDialog.showError(getContext(), parisResponseResult.message);
break;
}
case SUCCESS:{
if(parisResponseResult.data.getNumeroTicket().equals(reference)){
dialog.dismiss();
if(parisResponseResult.data.getStatutPari() == ParisResponse.StatutPari.ANNULE){
MessageDialog.showError(getContext(), "Le ticket est déjà annulé");
return;
}
_showPariDialog(reference);
}else{
MessageDialog.showError(getContext(), "Le ticket n'existe pas");
}
}
}
}
});
});
}
void _showPariDialog(String ticketReference){
new AlertDialog.Builder(getContext())
.setTitle("Annulation du ticket")
.setMessage("Etes-vous sûr de vouloir annuler le ticket "+ticketReference+" ?")
.setCancelable(true)
.setNegativeButton("Annuler", (dialog, which) -> {
dialog.dismiss();
})
.setPositiveButton("Confirmer", (annulationDialog, which) -> {
viewModel.annulerPari(ticketReference).observe(getViewLifecycleOwner(), new Observer<Result<ParisResponse>>() {
@Override
public void onChanged(Result<ParisResponse> pariResult) {
switch (pariResult.status){
case LOADING:{
dialog.show("Annulation du ticket");
break;
}
case ERROR:{
dialog.dismiss();
MessageDialog.showError(getContext(), pariResult.message);
break;
}
case SUCCESS:{
dialog.dismiss();
MessageDialog.showSuccess(getContext(), "Ticket annulé avec succès");
logsViewModel.insertLog(prefsHelper.get("id"), "ANNULATION TICKET", "Annulation du ticket "+pariResult.data.getNumeroTicket(), System.currentTimeMillis());
binding.referenceTicket.setText("");
}
}
}
});
}).show();
}
@Override
public void onResume() {
super.onResume();
AppCompatActivity activity = (AppCompatActivity) getActivity();
if(activity != null){
activity.getSupportActionBar().setTitle("Annulation Ticket");
}
}
}

View File

@@ -1,27 +1,9 @@
package com.example.quiz; package com.example.quiz;
import com.example.quiz.data.BetsBank; import android.app.Application;
import com.example.quiz.data.repository.BetRepository;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import dagger.hilt.InstallIn;
import dagger.hilt.components.SingletonComponent;
@Module public class AppModule extends Application{
@InstallIn(SingletonComponent.class)
public class AppModule {
@Provides
@Singleton
public BetsBank provideApiService(){
return BetsBank.getInstance();
}
@Provides
@Singleton
public BetRepository provideBetRepository() {
return new BetRepository();
}
} }

View File

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

View File

@@ -0,0 +1,110 @@
package com.example.quiz;
import android.os.Bundle;
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.FragmentCaisseBinding;
import com.example.quiz.utils.AuthNavigator;
import com.example.quiz.utils.SessionManager;
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;
AuthNavigator authNavigator;
SessionManager sessionManager;
public Caisse() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static Caisse newInstance() {
Caisse fragment = new Caisse();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sessionManager = SessionManager.newInstance(getContext());
}
@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();
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
binding.soldeBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Sold sold = Sold.newInstance();
authNavigator.navigate(sold);
}
});
binding.winTicketBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
WinTicket winTicket = WinTicket.newInstance();
authNavigator.navigate(winTicket);
}
});
binding.cancelTicketBtn.setOnClickListener(v -> {
AnnulationTicket annulationTicket = AnnulationTicket.newInstance();
authNavigator.navigate(annulationTicket);
});
binding.lastBetsBtn.setOnClickListener(v -> {
authNavigator.navigate(DerniersParis.newInstance());
});
}
@Override
public void onResume() {
super.onResume();
AppCompatActivity activity = (AppCompatActivity) getActivity();
if (activity != null){
MaterialToolbar toolbar = activity.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
if(toolbar != null){
if(activity.getSupportActionBar() != null){
activity.getSupportActionBar().setTitle("Caisse");
toolbar.setBackgroundColor(getResources().getColor(R.color.primary_green));
toolbar.setTitleTextColor(getResources().getColor(R.color.white));
toolbar.setVisibility(View.VISIBLE);
}
}
}
}
}

View File

@@ -0,0 +1,321 @@
package com.example.quiz;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import com.anggastudio.printama.Printama;
import com.example.quiz.data.adapter.LastBetsAdapter;
import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.Pari;
import com.example.quiz.data.model.ParisResponse;
import com.example.quiz.databinding.FragmentDerniersParisBinding;
import com.example.quiz.utils.BluetoothUtils;
import com.example.quiz.utils.LoaderDialog;
import com.example.quiz.utils.MessageDialog;
import com.example.quiz.utils.Result;
import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.LogsViewModel;
import com.example.quiz.viewModel.PariViewModel;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link DerniersParis#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class DerniersParis extends Fragment {
FragmentDerniersParisBinding binding;
LogsViewModel logsViewModel;
LoaderDialog loader;
SharedPrefsHelper prefsHelper;
PariViewModel viewModel;
AlertDialog dialog;
LastBetsAdapter adapter;
Map<String, Integer> listProduits = Map.of("QUINTE", 5, "QUARTE", 4, "TIERCE", 3, "COUPLE_GAGNANT", 2, "COUPLE_PLACE", 2);
public DerniersParis() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static DerniersParis newInstance() {
DerniersParis fragment = new DerniersParis();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prefsHelper = SharedPrefsHelper.getInstance(getContext());
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentDerniersParisBinding.inflate(inflater, container, false);
loader = new LoaderDialog(getContext());
logsViewModel = new ViewModelProvider(this).get(LogsViewModel.class);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding.lastBetsRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
viewModel = new ViewModelProvider(this).get(PariViewModel.class);
_getLastBets();
}
void _getLastBets(){
viewModel.getDerniersParis(prefsHelper.get("id")).observe(getViewLifecycleOwner(), new Observer<Result<List<ParisResponse>>>() {
@Override
public void onChanged(Result<List<ParisResponse>> listResult) {
switch (listResult.status){
case LOADING:
loader.show("Chargement des derniers paris");
break;
case ERROR:
loader.dismiss();
MessageDialog.showError(getContext(), listResult.message);
break;
case SUCCESS:
loader.dismiss();
if(adapter == null){
adapter = new LastBetsAdapter(listResult.data);
}else{
adapter.setData(listResult.data);
}
logsViewModel.insertLog(prefsHelper.get("id"), "LAST BETS", "Affichage derniers paris", System.currentTimeMillis());
adapter.setPariClickListener(new LastBetsAdapter.onPariClickListener() {
@Override
public void onItemClick(ParisResponse pari) {
if(pari.getStatutPari() != null && pari.getStatutPari() != ParisResponse.StatutPari.ENREGISTRE){
MessageDialog.showError(getContext(), "Ce pari ne peut pas être réimprimé!");
return;
}
_showPariDialog(pari);
}
@Override
public void onItemCancel(ParisResponse pari) {
if(pari.getStatutPari() != null && pari.getStatutPari() != ParisResponse.StatutPari.ENREGISTRE){
MessageDialog.showError(getContext(), "Ce pari ne peut pas être annulé");
return;
}
_cancelConfirmationDialog(pari);
}
});
binding.lastBetsRecyclerView.setAdapter(adapter);
break;
}
}
});
}
void _cancelConfirmationDialog(ParisResponse pari){
new AlertDialog.Builder(getContext())
.setTitle("Annulation du pari")
.setMessage("Êtes-vous sûr de vouloir annuler le pari "+pari.getNumeroTicket()+" ?")
.setPositiveButton("Oui", (cancelDialog, which) -> {
_cancelPari(pari);
cancelDialog.dismiss();
})
.setNegativeButton("Non", (cancelDialog, which) -> {
cancelDialog.dismiss();
}).show();
}
void _cancelPari(ParisResponse pari){
viewModel.annulerPari(pari.getNumeroTicket()).observe(getViewLifecycleOwner(), new Observer<Result<ParisResponse>>() {
@Override
public void onChanged(Result<ParisResponse> result) {
switch (result.status){
case LOADING:
loader.show("Annulation du pari");
break;
case ERROR:
loader.dismiss();
MessageDialog.showError(getContext(), result.message);
break;
case SUCCESS:
loader.dismiss();
MessageDialog.showSuccess(getContext(), "Pari annulé avec succès");
_getLastBets();
break;
}
}
});
}
@SuppressLint({"MissingInflatedId", "SetTextI18n"})
void _showPariDialog(ParisResponse pari){
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.pari_confirmation, null);
TextView numero_course = (TextView) view.findViewById(R.id.alert_course_numero);
numero_course.setText("Numero Course: "+String.valueOf(pari.getCourseId()));
TextView alert_pari_type = (TextView) view.findViewById(R.id.alert_pari_type);
alert_pari_type.setText(String.valueOf(pari.getTypesParisMises().get(0).getTypePari()));
TextView is_elargie = (TextView) view.findViewById(R.id.alert_is_elargie);
List<String> selectedHorses = Arrays.stream(pari.getCombinaison().split(","))
.map(String::trim)
.collect(Collectors.toList());
is_elargie.setText(selectedHorses.size() > listProduits.get(pari.getTypesParisMises().get(0).getTypePari())?"CE":"SI");
TextView alert_combinaison = (TextView) view.findViewById(R.id.alert_combinaison);
alert_combinaison.setText(selectedHorses.stream()
.map(String::valueOf)
.collect(Collectors.joining("-")));
TextView aler_coeff = (TextView) view.findViewById(R.id.alert_coeff);
aler_coeff.setText("Coef:"+String.valueOf(pari.getCoefficient()));
TextView alert_montant = (TextView) view.findViewById(R.id.alert_montant);
alert_montant.setText("Montant: "+String.valueOf(pari.getTypesParisMises().get(0).getMiseTotale())+" CFA");
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setView(view);
builder.setCancelable(false);
dialog = builder.create();
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
view.findViewById(R.id.alert_validate).setOnClickListener(v->{
try {
_printPari(pari);
dialog.dismiss();
} catch (WriterException e) {
throw new RuntimeException(e);
}
});
view.findViewById(R.id.alert_cancel).setOnClickListener(v -> {
dialog.dismiss();
});
dialog.show();
}
void _printPari(ParisResponse pari) throws WriterException {
try {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pmu_logo);
Bitmap barcode = generateBarcodeBitmap(pari.getNumeroTicket(), 384, 100);
StringBuilder tspl = new StringBuilder();
Printama printama = Printama.with(getContext());
tspl.append("Bamako").append("\n");
tspl.append(pari.getCourseNom()).append("\n");
OffsetDateTime dateTime = OffsetDateTime.parse(pari.getHeureDepartPrevue() != null ? pari.getHeureDepartPrevue() : OffsetDateTime.now().toString());
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
String formattedDate = dateTime.format(formatter);
tspl.append(formattedDate).append("\n");
tspl.append("Course ").append(String.valueOf(pari.getCourseId())).append("\n");
tspl.append(printama.lineSeparator()+"\n");
List<String> selectedHorses = Arrays.stream(pari.getCombinaison().split(",")).collect(Collectors.toList());
boolean isElargie = selectedHorses.size()> listProduits.get(pari.getTypesParisMises().get(0).getTypePari());
String typePari = pari.getTypesParisMises().get(0).getTypePari();
tspl.append(isElargie?typePari+"/Elargie":typePari).append("\n");
tspl.append(pari.getFormules().contains("FORMULE_COMPLETE") ?"COMBINAISON COMPLETE"+"\n":"");
String combinationText = selectedHorses.stream()
.map(String::valueOf)
.collect(Collectors.joining("-"));
tspl.append(combinationText).append("\n");
tspl.append("COEF: ").append(String.valueOf(pari.getCoefficient()));
tspl.append("\n").append(printama.lineSeparator()).append("\n");
tspl.append("MONTANT: ").append(pari.getMiseTotale()).append(" XOF");
tspl.append("\n").append(printama.lineSeparator()).append("\n");
tspl.append("AGENT: ").append(pari.getAgentCode()).append("\n");
tspl.append("DATE: ").append(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss").format(OffsetDateTime.parse(pari.getDateHeurePrise()))).append("\n");
if (BluetoothUtils.needsBluetoothPermissions()) {
if (!BluetoothUtils.hasBluetoothPermission(requireContext())) {
// Demande la permission si non accordée
BluetoothUtils.requestBluetoothPermission(requireActivity());
return; // arrête ici, la popup va apparaître
}
}
// 2⃣ Permission OK, on peut afficher la liste
Printama.with(getContext()).printTextBuilder(tspl, bitmap, pari.getNumeroTicket(), barcode, new Printama.PrintCallback() {
@Override
public void onResult(boolean success, String errorMessage) {
if(!success){
MessageDialog.showError(getContext(), errorMessage);
}else{
MessageDialog.showSuccess(getContext(), "Pari imprimé avec succès");
}
}
});
} catch (SecurityException e) {
Toast.makeText(requireContext(),
"Permission Bluetooth non accordée", Toast.LENGTH_SHORT).show();
}
}
public Bitmap generateBarcodeBitmap(String contents, int width, int height) throws WriterException {
BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.CODE_128, width, height);
Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
bmp.setPixel(x, y, bitMatrix.get(x, y) ? android.graphics.Color.BLACK : android.graphics.Color.WHITE);
}
}
return bmp;
}
@Override
public void onResume() {
super.onResume();
AppCompatActivity activity = (AppCompatActivity) getActivity();
if(activity!=null){
MaterialToolbar toolbar = activity.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
toolbar.setTitle("Derniers Paris");
}
}
}

View File

@@ -6,31 +6,51 @@ import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.core.view.MenuHost;
import androidx.core.app.ActivityCompat; import androidx.core.view.MenuProvider;
import androidx.core.app.ComponentActivity;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.service.controls.Control; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
import android.widget.Toast; import android.widget.Toast;
import com.anggastudio.printama.Pref;
import com.anggastudio.printama.Printama;
import com.example.quiz.data.adapter.BetsAdapter; 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.databinding.FragmentListOFBettingBinding;
import com.example.quiz.viewModel.BetViewModel; import com.example.quiz.utils.AuthNavigator;
import com.example.quiz.utils.BluetoothUtils;
import com.example.quiz.utils.LoaderDialog;
import com.example.quiz.utils.MessageDialog;
import com.example.quiz.utils.Result;
import com.example.quiz.utils.SessionManager;
import com.example.quiz.viewModel.CourseViewModel;
import com.example.quiz.viewModel.LoginViewModel;
import com.example.quiz.viewModel.LogsViewModel;
import com.example.quiz.viewModel.SharedViewModel; import com.example.quiz.viewModel.SharedViewModel;
import com.google.android.material.appbar.MaterialToolbar;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint; import dagger.hilt.android.AndroidEntryPoint;
import dagger.hilt.android.internal.lifecycle.HiltViewModelFactory;
/** /**
* A simple {@link Fragment} subclass. * A simple {@link Fragment} subclass.
@@ -40,25 +60,26 @@ import dagger.hilt.android.internal.lifecycle.HiltViewModelFactory;
@AndroidEntryPoint @AndroidEntryPoint
public class ListOFBets extends Fragment { public class ListOFBets extends Fragment {
private String username;
private View view;
FragmentListOFBettingBinding binding; FragmentListOFBettingBinding binding;
LoaderDialog loader;
private BetViewModel viewModel;
private SharedViewModel shared; private SharedViewModel shared;
private CourseViewModel viewModel;
@Inject
StompManager stompManager;
AuthNavigator authNavigator;
private BetsAdapter adapter; private BetsAdapter adapter;
private AppCompatActivity activity; private AppCompatActivity activity;
public static ListOFBets newInstance(String username) { public static ListOFBets newInstance() {
ListOFBets fragment = new ListOFBets(); ListOFBets fragment = new ListOFBets();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString("ARG_USERNAME", username);
fragment.setArguments(args); fragment.setArguments(args);
return fragment; return fragment;
} }
@@ -66,33 +87,25 @@ public class ListOFBets extends Fragment {
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if(getArguments() != null){ SessionManager sessionManager = SessionManager.newInstance(getContext());
username = getArguments().getString("ARG_USERNAME"); FragmentManager fragmentManager = getParentFragmentManager();
}
} }
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
binding = FragmentListOFBettingBinding.inflate(inflater, container, false); binding = FragmentListOFBettingBinding.inflate(inflater, container, false);
activity = (AppCompatActivity) getActivity(); loader = new LoaderDialog(getContext());
if(activity != null){ shared = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
if(activity.getSupportActionBar() != null){
activity.getSupportActionBar().show();
activity.getSupportActionBar().setTitle("Liste des paris");
}
}
adapter = new BetsAdapter(); adapter = new BetsAdapter();
binding.recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2)); binding.recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2));
binding.recyclerView.setAdapter(adapter); binding.recyclerView.setAdapter(adapter);
LayoutAnimationController controller = AnimationUtils.loadLayoutAnimation(getContext(), R.anim.layout_fad_in); viewModel = new ViewModelProvider(this).get(CourseViewModel.class);
binding.recyclerView.setLayoutAnimation(controller); authNavigator = new AuthNavigator(getContext(), getParentFragmentManager(), SessionManager.newInstance(getContext()),new ViewModelProvider(this).get(LoginViewModel.class),new ViewModelProvider(this).get(LogsViewModel.class), this);
viewModel = new ViewModelProvider(this).get(BetViewModel.class);
shared = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
/*viewModel.bets.observe(getViewLifecycleOwner(), bets -> {
viewModel.bets.observe(getViewLifecycleOwner(), bets -> {
adapter.setBets(bets); adapter.setBets(bets);
adapter.setOnItemClickListener(position -> { adapter.setOnItemClickListener(position -> {
shared.setBetId(position); shared.setBetId(position);
@@ -103,25 +116,102 @@ public class ListOFBets extends Fragment {
.addToBackStack(null) .addToBackStack(null)
.commit(); .commit();
}); });
}); });*/
viewModel.loadBets(); //viewModel.loadBets();
observe();
return binding.getRoot(); return binding.getRoot();
} }
public void observe(){
String day = DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDateTime.now());
viewModel.getCourses(day).observe(getViewLifecycleOwner(), new Observer<Result<PagedModel<Course>>>() {
@Override
public void onChanged(Result<PagedModel<Course>> result) {
switch (result.status){
case LOADING:
loader.show("Chargement des courses");
break;
case SUCCESS:
loader.dismiss();
adapter.setBets(result.data.getContent());
adapter.setOnItemClickListener(course ->{
shared.setSelectedCourse(course);
ListOfTypeOfBets typeOfBets = ListOfTypeOfBets.newInstance();
authNavigator.navigate(typeOfBets);
});
break;
case ERROR:
loader.dismiss();
MessageDialog.showError(getContext(), result.message);
break;
}
}
});
}
@SuppressLint("UseSupportActionBar") @SuppressLint("UseSupportActionBar")
@Override @Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
stompManager.subscribe("courses", json->{
requireActivity().runOnUiThread(this::observe);
Log.d("STOMP", json);
});
MenuHost menuHost = requireActivity();
// 🔹 On enlève d'abord les anciens menu providers si ce fragment est recréé
menuHost.invalidateMenu();
// 🔹 Ajout du menu spécifique à ce fragment
menuHost.addMenuProvider(new MenuProvider() {
@Override
public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) {
// Nettoyer avant d'inflater
menu.clear();
menuInflater.inflate(R.menu.menu_main, menu);
}
@Override
public boolean onMenuItemSelected(@NonNull MenuItem menuItem) {
int id = menuItem.getItemId();
if (id == R.id.action_sold) {
FragmentManager fragmentManager = getParentFragmentManager();
Sold sold = Sold.newInstance();
fragmentManager.beginTransaction()
.replace(R.id.nav_host_fragment_content_main, sold)
.addToBackStack(null)
.commit();
return true;
}
return false;
}
}, getViewLifecycleOwner(), Lifecycle.State.RESUMED);
}
@Override
public void onResume() {
super.onResume();
AppCompatActivity activity = (AppCompatActivity) getActivity(); AppCompatActivity activity = (AppCompatActivity) getActivity();
if(activity != null){ if(activity != null){
Toolbar toolbar = activity.findViewById(R.id.toolbar); MaterialToolbar toolbar = activity.findViewById(R.id.toolbar);
activity.getSupportActionBar().show();
toolbar.setBackgroundColor( getResources().getColor(R.color.primary_green)); toolbar.setBackgroundColor( getResources().getColor(R.color.primary_green));
toolbar.setTitleTextColor(getResources().getColor(R.color.text_light_grey)); toolbar.setTitleTextColor(getResources().getColor(R.color.white, null));
activity.setSupportActionBar(toolbar); activity.setSupportActionBar(toolbar);
if(activity.getSupportActionBar() != null){ if(activity.getSupportActionBar() != null){
activity.getSupportActionBar().setTitle(username); activity.getSupportActionBar().setTitle("Liste des courses");
} }
} }
} }
@Override
public void onDestroy() {
super.onDestroy();
stompManager.disconnect();
}
} }

View File

@@ -0,0 +1,177 @@
package com.example.quiz;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.MenuHost;
import androidx.core.view.MenuProvider;
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.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import android.widget.Toolbar;
import com.anggastudio.printama.Pref;
import com.anggastudio.printama.Printama;
import com.example.quiz.data.adapter.ReunionAdapter;
import com.example.quiz.data.model.Reunion;
import com.example.quiz.databinding.FragmentListOfReunionsBinding;
import com.example.quiz.utils.BluetoothUtils;
import com.example.quiz.utils.LoaderDialog;
import com.example.quiz.utils.MessageDialog;
import com.example.quiz.utils.Result;
import com.example.quiz.viewModel.ReunionViewModel;
import com.example.quiz.viewModel.SharedViewModel;
import com.google.android.material.appbar.MaterialToolbar;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link ListOfReunions#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class ListOfReunions extends Fragment {
FragmentListOfReunionsBinding binding;
SharedViewModel shared;
ReunionAdapter adapter;
LoaderDialog loader;
ReunionViewModel reunionViewModel;
public ListOfReunions() {
// Required empty public constructor
}
public static ListOfReunions newInstance(String username) {
ListOfReunions fragment = new ListOfReunions();
Bundle args = new Bundle();
args.putString("USER_NAME", username);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestPermission();
}
private void requestPermission(){
Pref.init(getContext());
if (BluetoothUtils.needsBluetoothPermissions()) {
if (!BluetoothUtils.hasBluetoothPermission(getContext())) {
// Demande la permission si non accordée
BluetoothUtils.requestBluetoothPermission(getActivity());
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(), getActivity());
}
} catch (SecurityException e) {
Toast.makeText(getContext(),
"Permission Bluetooth non accordée", Toast.LENGTH_SHORT).show();
}
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentListOfReunionsBinding.inflate(inflater, container, false);
loader = new LoaderDialog(getContext());
adapter = new ReunionAdapter();
binding.reunionsList.setLayoutManager(new LinearLayoutManager(getContext()));
binding.reunionsList.setAdapter(adapter);
reunionViewModel = new ViewModelProvider(this).get(ReunionViewModel.class);
shared = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
binding.reunionsLayout.setOnRefreshListener(()->{
observeReunions();
binding.reunionsLayout.setRefreshing(false);
});
observeReunions();
return binding.getRoot();
}
public void observeReunions(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
String formattedDate = sdf.format(new Date());
reunionViewModel.getReunions(formattedDate).observe(getViewLifecycleOwner(), new Observer<Result<List<Reunion>>>() {
@Override
public void onChanged(Result<List<Reunion>> result) {
switch (result.status) {
case LOADING:
loader.show("Chargement des réunions");
break;
case SUCCESS:
loader.dismiss();
adapter.setReunions(result.data);
adapter.setOnItemClickListener(reunion->{
shared.setSelectedReunion(reunion);
FragmentManager fragmentManager = getParentFragmentManager();
ListOFBets bets = ListOFBets.newInstance();
fragmentManager.beginTransaction()
.replace(R.id.nav_host_fragment_content_main, bets)
.addToBackStack(null)
.commit();
});
break;
case ERROR:
loader.dismiss();
MessageDialog.showError(getContext(), result.message);
break;
}
}
});
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
@Override
public void onResume() {
super.onResume();
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("Liste des réunions");
}
toolbar.setBackgroundColor(getResources().getColor(R.color.primary_green, null));
toolbar.setTitleTextColor(getResources().getColor(R.color.white, null));
}
}
}

View File

@@ -4,20 +4,49 @@ import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast; 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.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.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; import dagger.hilt.android.AndroidEntryPoint;
@@ -32,8 +61,25 @@ public class ListOfTypeOfBets extends Fragment {
private FragmentListOfTypeOfBetsBinding binding; private FragmentListOfTypeOfBetsBinding binding;
SessionManager sessionManager;
AuthNavigator authNavigator;
@Inject
StompManager stompManager;
private SharedViewModel shared; private SharedViewModel shared;
private TypeOfBetAdapter adapter;
private SharedPrefsHelper prefsHelper;
private AgentViewModel agentViewModel;
private LoaderDialog loaderDialog;
public ListOfTypeOfBets() { public ListOfTypeOfBets() {
// Required empty public constructor // Required empty public constructor
} }
@@ -47,38 +93,126 @@ public class ListOfTypeOfBets extends Fragment {
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
sessionManager = SessionManager.newInstance(getContext());
} }
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
binding = FragmentListOfTypeOfBetsBinding.inflate(inflater, container, false); 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(); return binding.getRoot();
} }
@Override @Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
if(prefsHelper.get("id") == null){
RadioGroup types = binding.optionsGroup; MessageDialog.showError(getContext(), "Veuillez vous connecter");
Button btnValidate = binding.btnValidate;
btnValidate.setOnClickListener(v->{
int selectedId = types.getCheckedRadioButtonId();
if (selectedId == -1) {
Toast.makeText(requireContext(), "Veuillez sélectionner une option", Toast.LENGTH_SHORT).show();
return; return;
} }
RadioButton selectedButton = view.findViewById(selectedId); agentViewModel.getAvailableBets(prefsHelper.get("id")).observe(getViewLifecycleOwner(), new Observer<Result<List<Course.TypeParis>>>() {
String selectedType = selectedButton.getText().toString(); @Override
shared = new ViewModelProvider(requireActivity()).get(SharedViewModel.class); public void onChanged(Result<List<Course.TypeParis>> listResult) {
shared.setTypeOfBet(selectedType); switch (listResult.status){
FragmentManager fragmentManager = getParentFragmentManager(); case LOADING:{
BetValidation betValidation = BetValidation.newInstance(); loaderDialog.show("Chargement des types de paris");
fragmentManager.beginTransaction() break;
.replace(R.id.nav_host_fragment_content_main, betValidation) }
.addToBackStack(null) case ERROR:{
.commit(); 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()));
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 = sCourse.getTypesParisOuverts();
List<TypeOfBet> useList = new ArrayList<>();
if(betType.contains(Course.TypeParis.QUINTE)){
useList.add(new TypeOfBet("Quinte", Course.TypeParis.QUINTE, 5));
}
if(betType.contains(Course.TypeParis.QUARTE)){
useList.add(new TypeOfBet("Quarte", Course.TypeParis.QUARTE, 4));
}
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<>();
List<TypeOfBet> availableTypeOfBets = useList.stream().filter(type -> authorizedBets.contains(type.getName())).collect(Collectors.toList());
adapter.setTypes(availableTypeOfBets);
adapter.setOnItemClickListener(type -> {
typeOfBet.set(type);
});
Button btnValidate = binding.btnValidate;
btnValidate.setOnClickListener(v->{
if(typeOfBet.get() == null){
Toast.makeText(getContext(),"Aucun Type de jeu choisi", Toast.LENGTH_SHORT).show();
return;
}
shared.setTypeOfBet(typeOfBet.get());
BetValidation betValidation = BetValidation.newInstance();
authNavigator.navigate(betValidation);
});
}
@Override
public void onResume() {
super.onResume();
AppCompatActivity activity = (AppCompatActivity) getActivity();
if(activity != null){
MaterialToolbar toolbar = activity.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
if(activity.getSupportActionBar() != null){
activity.getSupportActionBar().setTitle("Liste des jeux");
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
stompManager.disconnect();
} }
} }

View File

@@ -1,34 +1,36 @@
package com.example.quiz; package com.example.quiz;
import android.app.Activity;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction; import androidx.lifecycle.ViewModelProvider;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Toast;
import android.widget.Toolbar;
import com.example.quiz.databinding.FragmentLoginBinding; import com.example.quiz.databinding.FragmentLoginBinding;
import com.example.quiz.utils.AuthNavigator;
import com.example.quiz.utils.SessionManager;
import com.example.quiz.utils.SharedPrefsHelper; 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. * A simple {@link Fragment} subclass.
* Use the {@link Login#newInstance} factory method to * Use the {@link Login#newInstance} factory method to
* create an instance of this fragment. * create an instance of this fragment.
*/ */
@AndroidEntryPoint
public class Login extends Fragment { public class Login extends Fragment {
private AuthNavigator authNavigator;
private SharedPrefsHelper prefsHelper; private SharedPrefsHelper prefsHelper;
public Login() { public Login() {
// Required empty public constructor // Required empty public constructor
@@ -53,12 +55,15 @@ public class Login extends Fragment {
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
binding = FragmentLoginBinding.inflate(inflater, container, false); 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(); return binding.getRoot();
} }
@Override @Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
SessionManager sessionManager = SessionManager.newInstance(getContext());
FragmentManager fragmentManager = getParentFragmentManager();
AppCompatActivity activity = (AppCompatActivity) getActivity(); AppCompatActivity activity = (AppCompatActivity) getActivity();
if(activity != null){ if(activity != null){
activity.getSupportActionBar().hide(); activity.getSupportActionBar().hide();
@@ -71,27 +76,28 @@ public class Login extends Fragment {
binding.loginButton.setOnClickListener(new View.OnClickListener() { binding.loginButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if(binding.userNameInput.getText().toString().isEmpty()){
binding.userNameInput.setError("Le nom d'utilisateur est obligatoire");
binding.userNameInput.requestFocus();
return;
}
if(binding.passwordInput.getText().toString().isEmpty()){
binding.passwordInput.setError("Le mot de passe est obligatoire");
binding.passwordInput.requestFocus();
return;
}
if(binding.passwordInput.getText().toString().length() < 6){
binding.passwordInput.setError("Le mot de passe doit contenir au moins 6 caractères ");
binding.passwordInput.requestFocus();
return;
}
prefsHelper = SharedPrefsHelper.getInstance(getContext()); prefsHelper = SharedPrefsHelper.getInstance(getContext());
prefsHelper.save("username", binding.userNameInput.getText().toString()); ListOFBets bets = ListOFBets.newInstance();
authNavigator.navigate(bets);
}
});
binding.caisse.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Caisse caisse = Caisse.newInstance();
authNavigator.navigate(caisse);
}
});
binding.settings.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Settings settings = Settings.newInstance();
FragmentManager fragmentManager = getParentFragmentManager(); FragmentManager fragmentManager = getParentFragmentManager();
ListOFBets bets = ListOFBets.newInstance(binding.userNameInput.getText().toString());
fragmentManager.beginTransaction() fragmentManager.beginTransaction()
.replace(R.id.nav_host_fragment_content_main, bets) .replace(R.id.nav_host_fragment_content_main, settings)
.addToBackStack(null)
.commit(); .commit();
} }
}); });

View File

@@ -0,0 +1,118 @@
package com.example.quiz;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.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 android.widget.Toast;
import com.example.quiz.data.adapter.LogsAdapter;
import com.example.quiz.data.dao.UserActivityLogDao;
import com.example.quiz.data.database.DatabaseClient;
import com.example.quiz.databinding.FragmentLogsBinding;
import com.example.quiz.utils.LoaderDialog;
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 Logs#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class Logs extends Fragment {
FragmentLogsBinding binding;
LogsViewModel viewModel;
private LogsAdapter adapter;
LoaderDialog loader;
public Logs() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static Logs newInstance() {
Logs fragment = new Logs();
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) {
binding = FragmentLogsBinding.inflate(inflater, container, false);
loader = new LoaderDialog(getContext());
adapter = new LogsAdapter();
binding.recyclerLogs.setLayoutManager(new LinearLayoutManager(getContext()));
binding.recyclerLogs.setAdapter(adapter);
// Inflate the layout for this fragment
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
AppCompatActivity activity = (AppCompatActivity) getActivity();
if (activity != null) {
if(activity.getSupportActionBar() != null){
activity.getSupportActionBar().setTitle("Historique");
MaterialToolbar toolbar = activity.findViewById(R.id.toolbar);
toolbar.setBackgroundColor(getResources().getColor(R.color.primary_green));
toolbar.setTitleTextColor(getResources().getColor(R.color.white));
}
}
viewModel = new ViewModelProvider(this).get(LogsViewModel.class);
// Observer les logs
viewModel.getTodayLogs().observe(getViewLifecycleOwner(), new Observer<List<com.example.quiz.data.entity.Logs>>() {
@Override
public void onChanged(List<com.example.quiz.data.entity.Logs> logs) {
loader.show("Chargement des logs");
if(logs != null){
loader.dismiss();
adapter.setLogs(logs);
}else{
loader.dismiss();
showErrorAlert("Erreur", "Impossible de charger les logs");
}
}
});
}
private void showErrorAlert(String title, String message) {
new AlertDialog.Builder(requireContext())
.setTitle(title)
.setMessage(message)
.setCancelable(true)
.setPositiveButton("OK", (dialog, which) -> dialog.dismiss())
.show();
}
}

View File

@@ -1,16 +1,27 @@
package com.example.quiz; package com.example.quiz;
import android.graphics.Color; import android.graphics.Color;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import com.example.quiz.utils.SharedPrefsHelper; import com.anggastudio.printama.Pref;
import com.google.android.material.snackbar.Snackbar; 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.SunmiPrinterManager;
import com.example.quiz.viewModel.LoginViewModel;
import com.example.quiz.viewModel.LogsViewModel;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.os.Handler;
import android.os.Looper;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavController; import androidx.navigation.NavController;
import androidx.navigation.Navigation; import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration; import androidx.navigation.ui.AppBarConfiguration;
@@ -18,48 +29,228 @@ import androidx.navigation.ui.NavigationUI;
import com.example.quiz.databinding.ActivityPageQuizBinding; import com.example.quiz.databinding.ActivityPageQuizBinding;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint; import dagger.hilt.android.AndroidEntryPoint;
@AndroidEntryPoint @AndroidEntryPoint
public class PageQuiz extends AppCompatActivity { public class PageQuiz extends AppCompatActivity {
LoginViewModel viewModel;
LogsViewModel logsViewModel;
AuthNavigator authNavigator;
private SessionManager sessionManager;
String mobileName;
private Set<Class<?>> exemptedFragment = new HashSet<>();
private Handler handler = new Handler();
private Runnable checkRunnable;
private AppBarConfiguration appBarConfiguration; private AppBarConfiguration appBarConfiguration;
private ActivityPageQuizBinding binding; private ActivityPageQuizBinding binding;
private SharedPrefsHelper prefsHelper;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
exemptedFragment.add(ServerConfig.class);
exemptedFragment.add(Logs.class);
sessionManager = SessionManager.newInstance(this);
mobileName = Build.MANUFACTURER;
binding = ActivityPageQuizBinding.inflate(getLayoutInflater()); binding = ActivityPageQuizBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot()); 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, this);
setSupportActionBar(binding.toolbar); setSupportActionBar(binding.toolbar);
binding.toolbar.setBackgroundColor(Color.parseColor("#501C5A29")); binding.toolbar.setBackgroundColor(Color.parseColor("#501C5A29"));
binding.fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAnchorView(R.id.fab)
.setAction("Action", null).show();
} }
});
prefsHelper = SharedPrefsHelper.getInstance(getApplicationContext());
FragmentManager fragmentManager = getSupportFragmentManager();
if(prefsHelper.get("username") != null){ // void _showPinDialog(){
ListOFBets bets = ListOFBets.newInstance(prefsHelper.get("username")); // LayoutInflater inflater = getLayoutInflater();
fragmentManager // View view = inflater.inflate(R.layout.pin_view, null);
.beginTransaction() //
.replace(R.id.nav_host_fragment_content_main, bets) // AlertDialog.Builder builder = new AlertDialog.Builder(this);
.commit(); // builder.setView(view);
}else{ // builder.setCancelable(true);
Login login = Login.newInstance(); //
fragmentManager // dialog = builder.create();
.beginTransaction() // dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
.replace(R.id.nav_host_fragment_content_main, login) //
.commit(); // view.findViewById(R.id.cancel).setOnClickListener(v -> dialog.dismiss());
//// Bouton OK
// view.findViewById(R.id.pin_validate).setOnClickListener(v -> {
// TextView pin = view.findViewById(R.id.pin);
// if(pin.getText().toString().isEmpty()){
// pin.setError("Entrez le pin!");
// return;
// }
// if(pin.getText().toString().length() < 4){
// pin.setError("Le pin doit contenir minimum quatre chiffres!");
// return;
// }
// LoginPayload loginPayload = new LoginPayload(
// pin.getText().toString()
// );
// viewModel.login(loginPayload).observe(this, new Observer<Result<LoginResponse>>() {
// @Override
// public void onChanged(Result<LoginResponse> loginResponseResult) {
// switch (loginResponseResult.status){
// case LOADING:
// view.findViewById(R.id.pin_validate).setEnabled(false);
// view.findViewById(R.id.pin_validate).setAlpha(0.5f);
// break;
// case ERROR:
// Toast.makeText(getApplicationContext(), loginResponseResult.message, Toast.LENGTH_SHORT).show();
// view.findViewById(R.id.pin_validate).setEnabled(true);
// view.findViewById(R.id.pin_validate).setAlpha(1f);
// break;
// case SUCCESS:
// loginSuccess(loginResponseResult.data);
// logsViewModel.insertLog(prefsHelper.get("id"), "LOGIN","Authentification sur l'appareil", System.currentTimeMillis());
// sessionManager.updateLastExpiredDate();
// dialog.dismiss();
// view.findViewById(R.id.pin_validate).setEnabled(true);
// view.findViewById(R.id.pin_validate).setAlpha(1f);
// break;
// }
// }
// });
// });
//
// dialog.show();
// }
//
//
// private void loginSuccess(LoginResponse loginResponse){
// prefsHelper.save("id", String.valueOf(loginResponse.getId()));
// prefsHelper.save("firstName", loginResponse.getPrenom());
// prefsHelper.save("lastName", loginResponse.getNom());
// prefsHelper.save("profile", loginResponse.getProfile());
// prefsHelper.save("limit", String.valueOf(loginResponse.getLimiteSuperieure()));
// prefsHelper.save("code", loginResponse.getCode());
// }
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
View touchedView = findTouchedView(ev);
Fragment currentFragment = getCurrentFragment();
if(currentFragment != null && exemptedFragment.contains(currentFragment.getClass())){
return super.dispatchTouchEvent(ev);
} }
if(touchedView!=null && "tag_pin_exempt".equals(touchedView.getTag())){
return super.dispatchTouchEvent(ev);
}
if (authNavigator.isSessionExpired()) {
authNavigator.showPinDialog(() -> {
authNavigator.updatedLastExpiredDate();
});
return false; // Consomme l'événement pour ne pas le propager
}
authNavigator.updatedLastExpiredDate();
return super.dispatchTouchEvent(ev);
}
private Fragment getCurrentFragment() {
FragmentManager fm = getSupportFragmentManager();
// Méthode 1: Par conteneur
Fragment fragment = fm.findFragmentById(R.id.nav_host_fragment_content_main);
// Méthode 2: Par tag si vous utilisez des tags
if (fragment == null) {
fragment = fm.findFragmentByTag("current_fragment");
}
return fragment;
}
private View findTouchedView(MotionEvent ev) {
float x = ev.getRawX();
float y = ev.getRawY();
View rootView = getWindow().getDecorView().getRootView();
return findViewAtPosition(rootView, (int) x, (int) y);
}
private View findViewAtPosition(View view, int x, int y) {
if (view == null) return null;
int[] location = new int[2];
view.getLocationOnScreen(location);
int left = location[0];
int top = location[1];
int right = left + view.getWidth();
int bottom = top + view.getHeight();
if (x >= left && x <= right && y >= top && y <= bottom) {
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
for (int i = group.getChildCount() - 1; i >= 0; i--) {
View child = group.getChildAt(i);
View found = findViewAtPosition(child, x, y);
if (found != null) return found;
}
}
return view;
}
return null;
}
private void checkPermission(){
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() {
if(!mobileName.toLowerCase().contains("sunmi")){
checkPermission();
}
super.onResume();
handler = new Handler(Looper.getMainLooper());
checkRunnable = new Runnable() {
@Override
public void run() {
if (sessionManager.isExpired()) {
if (!authNavigator.dialogIsShowing()) {
authNavigator.showPinDialog(() -> {
authNavigator.updatedLastExpiredDate();
handler.postDelayed(checkRunnable, 1);
});
}
} else {
// Replanifie le check toutes les secondes
handler.postDelayed(this, 1);
}
}
};
handler.postDelayed(checkRunnable, 1);
} }
@Override @Override

View File

@@ -1,80 +0,0 @@
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.Question;
import com.example.quiz.databinding.FragmentQuestionsBinding;
import com.example.quiz.injection.QuestionViewModelFactory;
import com.example.quiz.viewModel.QuestionViewModel;
public class Questions extends Fragment {
private FragmentQuestionsBinding binding;
private QuestionViewModel viewModel;
public Questions() {
// Required empty public constructor
}
public static Questions newInstance(String username) {
Questions fragment = new Questions();
Bundle args = new Bundle();
args.putString("ARG_USERNAME", username);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel = new ViewModelProvider(this, QuestionViewModelFactory.getInstance()).get(QuestionViewModel.class);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentQuestionsBinding.inflate(inflater, container, false);
// Inflate the layout for this fragment
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
viewModel.startQuiz();
viewModel.currentQuestion.observe(getViewLifecycleOwner(), new Observer<Question>() {
@Override
public void onChanged(Question question) {
binding.questionText.setText(question.getQuestion());
binding.answer1.setText(question.getAnswers().get(0));
binding.answer2.setText(question.getAnswers().get(1));
binding.answer3.setText(question.getAnswers().get(2));
binding.answer4.setText(question.getAnswers().get(3));
}
});
}
@Override
public void onStart() {
super.onStart();
binding.nextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
viewModel.nextQuestion();
}
});
}
}

View File

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

View File

@@ -1,44 +0,0 @@
package com.example.quiz;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.navigation.fragment.NavHostFragment;
import com.example.quiz.databinding.FragmentSecond2Binding;
public class Second2Fragment extends Fragment {
private FragmentSecond2Binding binding;
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState
) {
binding = FragmentSecond2Binding.inflate(inflater, container, false);
return binding.getRoot();
}
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding.buttonSecond.setOnClickListener(v ->
NavHostFragment.findNavController(Second2Fragment.this)
.navigate(R.id.action_Second2Fragment_to_First2Fragment)
);
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}

View File

@@ -1,44 +0,0 @@
package com.example.quiz;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.navigation.fragment.NavHostFragment;
import com.example.quiz.databinding.FragmentSecondBinding;
public class SecondFragment extends Fragment {
private FragmentSecondBinding binding;
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState
) {
binding = FragmentSecondBinding.inflate(inflater, container, false);
return binding.getRoot();
}
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding.buttonSecond.setOnClickListener(v ->
NavHostFragment.findNavController(SecondFragment.this)
.navigate(R.id.action_SecondFragment_to_FirstFragment)
);
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}

View File

@@ -0,0 +1,366 @@
package com.example.quiz;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.provider.Settings;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import com.example.quiz.data.adapter.PointDeVenteAdapter;
import com.example.quiz.data.model.PagedModel;
import com.example.quiz.data.model.PointDeVente;
import com.example.quiz.data.model.Tpe;
import com.example.quiz.data.model.TpeResponse;
import com.example.quiz.databinding.FragmentServerConfigBinding;
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.PointDeVenteViewModel;
import com.example.quiz.viewModel.TpeViewModel;
import com.google.android.material.appbar.MaterialToolbar;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link ServerConfig#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class ServerConfig extends Fragment {
FragmentServerConfigBinding binding;
private TpeViewModel viewModel;
private SharedPrefsHelper sharedPrefsHelper;
private boolean isUserTap = true;
PointDeVenteAdapter pointDeVenteAdapter;
TpeResponse existingTpe;
PointDeVente pdv = null;
private PointDeVenteViewModel pointDeVenteViewModel;
LoaderDialog loader;
public ServerConfig() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static ServerConfig newInstance() {
ServerConfig fragment = new ServerConfig();
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sharedPrefsHelper = SharedPrefsHelper.getInstance(getContext());
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentServerConfigBinding.inflate(inflater, container, false);
viewModel = new ViewModelProvider(this).get(TpeViewModel.class);
pointDeVenteViewModel = new ViewModelProvider(this).get(PointDeVenteViewModel.class);
loader = new LoaderDialog(getContext());
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
AppCompatActivity activity = (AppCompatActivity) getActivity();
if(activity != null){
MaterialToolbar toolbar = activity.findViewById(R.id.toolbar);
toolbar.setTitle("Configuration du terminal");
toolbar.setBackgroundColor( getResources().getColor(R.color.primary_green));
}
if(sharedPrefsHelper.get("terminalId") != null){
viewModel.getTpeById(sharedPrefsHelper.get("terminalId")).observe(getViewLifecycleOwner(), new Observer<Result<TpeResponse>>() {
@Override
public void onChanged(Result<TpeResponse> tpeResult) {
switch (tpeResult.status){
case LOADING:
loader.show("Chargement du TPE");
break;
case SUCCESS:
loader.dismiss();
existingTpe = tpeResult.data;
if( existingTpe != null && Objects.equals(sharedPrefsHelper.get("terminalId"), String.valueOf(existingTpe.getId()))){
_checkPdv(existingTpe);
return;
}else{
MessageDialog.showError(getContext(), "Ce TPE n'est pas encore configuré");
_startAutocomplete();
break;
}
case ERROR:
loader.dismiss();
MessageDialog.showError(getContext(), "Erreur lors du chargement du TPE");
break;
}
}
});
}
_startAutocomplete();
super.onViewCreated(view, savedInstanceState);
}
@SuppressLint("ClickableViewAccessibility")
void _startAutocomplete(){
pointDeVenteAdapter = new PointDeVenteAdapter();
RecyclerView recyclerView = binding.pointRecyclerView;
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
binding.getRoot().setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// Vérifier si le clic est en dehors de l'autocomplete
if (binding.autocompleteContainer.getVisibility() == View.VISIBLE && !binding.pointDeVente.isEnabled()) {
int[] location = new int[2];
binding.autocompleteContainer.getLocationOnScreen(location);
Rect rect = new Rect(
location[0],
location[1],
location[0] + binding.autocompleteContainer.getWidth(),
location[1] + binding.autocompleteContainer.getHeight()
);
int x = (int) event.getRawX();
int y = (int) event.getRawY();
if (!rect.contains(x, y)) {
binding.autocompleteContainer.setVisibility(View.GONE);
}
}
}
return false;
});
binding.pointDeVente.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if(!isUserTap) return;
if(charSequence.toString().isEmpty() || !binding.pointDeVente.isEnabled()){
recyclerView.setVisibility(View.GONE);
binding.autocompleteContainer.setVisibility(View.GONE);
return;
}
pointDeVenteViewModel.setPointsDeVente(charSequence.toString()).observe(getViewLifecycleOwner(), new Observer<Result<PagedModel<PointDeVente>>>() {
@Override
public void onChanged(Result<PagedModel<PointDeVente>> pagedModelResult) {
switch (pagedModelResult.status){
case LOADING:
binding.autocompleteContainer.setVisibility(View.VISIBLE);
binding.loader.setVisibility(View.VISIBLE);
break;
case SUCCESS:
binding.autocompleteContainer.setVisibility(View.VISIBLE);
binding.loader.setVisibility(View.GONE);
List<PointDeVente> pointsDeVente = pagedModelResult.data.getContent();
recyclerView.setVisibility(View.VISIBLE);
pointDeVenteAdapter.setPoints(pointsDeVente);
recyclerView.setAdapter(pointDeVenteAdapter);
pointDeVenteAdapter.setOnItemClickListener((PointDeVente pointDeVente)->{
pdv = pointDeVente;
isUserTap = false;
binding.pointDeVente.setText(pointDeVente.getNom());
isUserTap = true;
binding.autocompleteContainer.setVisibility(View.GONE);
binding.loader.setVisibility(View.GONE);
});
break;
case ERROR:
binding.autocompleteContainer.setVisibility(View.GONE);
binding.loader.setVisibility(View.GONE);
MessageDialog.showError(getContext(), "Erreur lors du chargement des points de vente");
break;
}
}
});
}
@Override
public void afterTextChanged(Editable editable) {
}
});
}
void _checkPdv(Tpe eTpe){
binding.numeroSerie.setText(eTpe.getNumeroSerie());
binding.brand.setText(eTpe.getTypeTerminal());
binding.model.setText(eTpe.getModeleAppareil());
binding.type.setText(eTpe.getTypeTerminal());
pointDeVenteViewModel.getPointDeVenteById(String.valueOf(eTpe.getPointDeVenteId())).observe(getViewLifecycleOwner(), new Observer<Result<PointDeVente>>() {
@Override
public void onChanged(Result<PointDeVente> pointDeVenteResult) {
switch (pointDeVenteResult.status){
case LOADING:
loader.show("Chargement du point de vente");
break;
case SUCCESS:
loader.dismiss();
binding.pointDeVente.setEnabled(false);
binding.pointDeVente.setText(pointDeVenteResult.data.getNom());
binding.validate.setClickable(false);
MessageDialog.showSuccess(getContext(), "Ce tpe est déjà configuré");
break;
case ERROR:
loader.dismiss();
MessageDialog.showError(getContext(), "Erreur lors du chargement du point de vente");
break;
}
}
});
}
@Override
public void onResume() {
String serialNumber = Settings.Secure.getString(getContext().getContentResolver(), Settings.Secure.ANDROID_ID);
binding.numeroSerie.setText(serialNumber);
binding.brand.setText(Build.BRAND);
binding.model.setText(Build.MODEL);
binding.type.setText("POS");
binding.validate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(pdv == null){
MessageDialog.showError(getContext(), "Veuillez sélectionner un point de vente");
return;
}
Tpe tpe = new Tpe();
tpe.setNumeroSerie(serialNumber);
tpe.setVersionOs(Build.VERSION.RELEASE);
tpe.setVersionLogicielle(getAppVersion(getContext()));
tpe.setPlateforme("PMU_BET");
tpe.setSystemeExploitation("Android");
tpe.setPointDeVenteId(pdv.getId());
tpe.setAdresseIp(getLocalIpAddress());
tpe.setModeleAppareil(Build.MODEL);
tpe.setTypeTerminal("POS/"+Build.BRAND);
tpe.setStatut("ACTIF");
viewModel.createTpe(tpe).observe(getViewLifecycleOwner(), new Observer<Result<TpeResponse>>() {
@Override
public void onChanged(Result<TpeResponse> tpeResult) {
switch (tpeResult.status){
case LOADING:
loader.show("Création du TPE");
break;
case SUCCESS:
loader.dismiss();
MessageDialog.showSuccess(getContext(), "TPE configuré avec succès!");
sharedPrefsHelper.save("terminalId", String.valueOf(tpeResult.data.getId()));
sharedPrefsHelper.save("pointDeVenteId", String.valueOf(tpeResult.data.getPointDeVenteId()));
break;
case ERROR:
loader.dismiss();
MessageDialog.showError(getContext(), "Erreur lors de la configuration du TPE");
break;
}
}
});
}
});
binding.cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getActivity() != null) {
getActivity().getSupportFragmentManager().popBackStack();
}
}
});
super.onResume();
}
public String getLocalIpAddress() {
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
return inetAddress.getHostAddress();
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return "0.0.0.0";
}
public static String getAppVersion(Context context) {
try {
return context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0)
.versionName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return "Version inconnue";
}
}
public static String getMacAddress() {
try {
List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface nif : interfaces) {
if (!nif.getName().equalsIgnoreCase("wlan0")) continue;
byte[] macBytes = nif.getHardwareAddress();
if (macBytes == null) return "N/A";
StringBuilder res1 = new StringBuilder();
for (byte b : macBytes) {
res1.append(String.format("%02X:", b));
}
if (res1.length() > 0) res1.deleteCharAt(res1.length() - 1);
return res1.toString();
}
} catch (Exception ex) {
ex.printStackTrace();
}
return "N/A";
}
}

View File

@@ -0,0 +1,144 @@
package com.example.quiz;
import android.os.Bundle;
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
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
// TODO: Rename and change types of parameters
FragmentSettingsBinding binding;
AuthNavigator authNavigator;
SharedPrefsHelper prefsHelper;
public Settings() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static Settings newInstance() {
Settings fragment = new Settings();
Bundle args = new Bundle();
fragment.setArguments(args);
return 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);
authNavigator = new AuthNavigator(getContext(), getParentFragmentManager(), SessionManager.newInstance(getContext()),new ViewModelProvider(this).get(LoginViewModel.class),new ViewModelProvider(this).get(LogsViewModel.class), this);
return binding.getRoot();
}
@Override
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);
if (activity.getSupportActionBar() != null) {
activity.getSupportActionBar().show();
activity.getSupportActionBar().setTitle("Choisissez une action à effectuer");
}
toolbar.setBackgroundColor(getResources().getColor(R.color.primary_green, null));
toolbar.setTitleTextColor(getResources().getColor(R.color.white, null));
}
binding.logs.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Logs logs = Logs.newInstance();
FragmentManager fragmentManager = getParentFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.nav_host_fragment_content_main, logs)
.addToBackStack(null)
.commit();
}
});
binding.serverConfig.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ServerConfig serverConfig = ServerConfig.newInstance();
FragmentManager fragmentManager = getParentFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.nav_host_fragment_content_main, serverConfig)
.addToBackStack(null)
.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);
}
});
binding.logout.setOnClickListener(v -> {
authNavigator.logOut();
});
}
}

View File

@@ -0,0 +1,198 @@
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;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.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;
import com.example.quiz.utils.Result;
import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.LogsViewModel;
import com.example.quiz.viewModel.PariViewModel;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.zxing.WriterException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link Sold#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class Sold extends Fragment {
FragmentSoldBinding binding;
LoaderDialog dialog;
PariViewModel pariViewModel;
SharedPrefsHelper prefsHelper;
LogsViewModel logsViewModel;
public Sold() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static Sold newInstance() {
Sold fragment = new Sold();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prefsHelper = SharedPrefsHelper.getInstance(getContext());
AppCompatActivity activity = (AppCompatActivity) getActivity();
if(activity != null){
MaterialToolbar toolbar = activity.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
if(activity.getSupportActionBar() != null){
activity.getSupportActionBar().setTitle("Soldes");
}
}
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
binding = FragmentSoldBinding.inflate(inflater, container, false);
dialog = new LoaderDialog(getContext());
logsViewModel = new ViewModelProvider(this).get(LogsViewModel.class);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
pariViewModel = new ViewModelProvider(this).get(PariViewModel.class);
binding.btnByCourse.setOnClickListener(v -> {
FragmentManager fragmentManager = getParentFragmentManager();
SoldByCourse soldByCourse = SoldByCourse.newInstance();
fragmentManager.beginTransaction()
.replace(R.id.nav_host_fragment_content_main, soldByCourse)
.addToBackStack(null)
.commit();
});
binding.btnByDay.setOnClickListener(v->{
_showCalendar();
});
}
String _reformatDateForDate(int num){
if(num<10){
return "0"+num;
}
return String.valueOf(num);
}
void _showCalendar(){
Calendar calendar = Calendar.getInstance();
DatePickerDialog datePickerDialog = new DatePickerDialog(
getContext(),
(view, year, month, dayOfMonth) -> {
String date = year + "-" + _reformatDateForDate(month + 1) + "-" + _reformatDateForDate(dayOfMonth);
pariViewModel.getSoldeByDay(prefsHelper.get("id"), date).observe(getViewLifecycleOwner(), new Observer<Result<SoldeResponse>>() {
@Override
public void onChanged(Result<SoldeResponse> doubleResult) {
switch (doubleResult.status){
case LOADING:{
dialog.show("Solde du jour");
break;
}
case ERROR:{
dialog.dismiss();
MessageDialog.showError(getContext(), doubleResult.message);
break;
}
case SUCCESS:{
dialog.dismiss();
try {
_showSold(doubleResult.data, date);
} catch (WriterException e) {
throw new RuntimeException(e);
}
logsViewModel.insertLog(prefsHelper.get("id"), "SOLDE JOUR", "Solde du "+date, System.currentTimeMillis());
break;
}
}
}
});
},
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)
);
datePickerDialog.show();
}
void _showSold(SoldeResponse soldeResponse, String date) throws WriterException {
try {
int solde = soldeResponse.getMontantParis() - soldeResponse.getMontantAnnulations() - soldeResponse.getMontantPaiements();
new AlertDialog.Builder(getContext())
.setTitle("Solde")
.setMessage("Solde la course "+solde)
.setNeutralButton("Ok", (dialog, which)->{
dialog.dismiss();
})
.setPositiveButton("Imprimer", (dialog, which)->{
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();
}catch (SecurityException e){
MessageDialog.showError(getContext(), "Erreur lors de l'affichage du solde");
}
}
}

View File

@@ -0,0 +1,154 @@
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;
import android.view.LayoutInflater;
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;
import com.example.quiz.utils.Result;
import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.LogsViewModel;
import com.example.quiz.viewModel.PariViewModel;
import com.google.zxing.WriterException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A simple {@link Fragment} subclass.
* Use the {@link SoldByCourse#newInstance} factory method to
* create an instance of this fragment.
*/
@AndroidEntryPoint
public class SoldByCourse extends Fragment {
FragmentSoldByCourseBinding binding;
LoaderDialog loader;
LogsViewModel logsViewModel;
PariViewModel pariViewModel;
SharedPrefsHelper prefsHelper;
public static SoldByCourse newInstance() {
SoldByCourse fragment = new SoldByCourse();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prefsHelper = SharedPrefsHelper.getInstance(getContext());
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
binding = FragmentSoldByCourseBinding.inflate(inflater, container, false);
logsViewModel = new ViewModelProvider(this).get(LogsViewModel.class);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
loader = new LoaderDialog(getContext());
pariViewModel = new ViewModelProvider(this).get(PariViewModel.class);
binding.btnCheckBalance.setOnClickListener(v -> {
if(binding.etRaceNumber.getText().toString().isEmpty()){
binding.etRaceNumber.setError("Veuillez entrer un numéro de course");
return;
}
pariViewModel.getSoldeByCourse(prefsHelper.get("id"), binding.etRaceNumber.getText().toString()).observe(getViewLifecycleOwner(), new Observer<Result<SoldeResponse>>() {
@Override
public void onChanged(Result<SoldeResponse> doubleResult) {
switch (doubleResult.status){
case LOADING:{
loader.show("Chargement du solde");
break;
}
case ERROR:{
loader.dismiss();
MessageDialog.showError(getContext(), doubleResult.message);
break;
}
case SUCCESS:{
loader.dismiss();
try {
_showPariDialog(doubleResult.data, binding.etRaceNumber.getText().toString());
} catch (WriterException e) {
throw new RuntimeException(e);
}
logsViewModel.insertLog(prefsHelper.get("id"), "SOLDE COURSE", "Solde de la course "+binding.etRaceNumber.getText(), System.currentTimeMillis());
break;
}
}
}
});
});
}
void _showPariDialog(SoldeResponse soldeResponse, String numero) throws WriterException {
try {
int solde = soldeResponse.getMontantParis() - soldeResponse.getMontantAnnulations() - soldeResponse.getMontantPaiements();
new AlertDialog.Builder(getContext())
.setTitle("Solde")
.setMessage("Solde la course "+solde)
.setNeutralButton("Ok", (dialog, which) -> {
binding.etRaceNumber.setText("");
dialog.dismiss();
})
.setPositiveButton("Imprimer", (dialog, which)->{
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();
}catch (SecurityException e){
MessageDialog.showError(getContext(), "Erreur lors de l'affichage du solde");
}
}
}

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

View File

@@ -0,0 +1,28 @@
package com.example.quiz.data;
import android.os.AsyncTask;
import com.example.quiz.data.dao.UserActivityLogDao;
import com.example.quiz.data.entity.Logs;
import java.util.concurrent.Executors;
public class ActivityLogger {
public static UserActivityLogDao dao;
public static void init(UserActivityLogDao iDao){
dao = iDao;
}
public static void log(String userId, String activity, String description, Long timestamp){
Executors.newSingleThreadExecutor().execute(()->{
Logs userLog = new Logs();
userLog.setUserId(userId);
userLog.setAction(activity);
userLog.setDescription(description);
userLog.setTimestamp(timestamp);
dao.insertLog(userLog);
});
}
}

View File

@@ -1,72 +0,0 @@
package com.example.quiz.data;
import com.example.quiz.data.model.Bet;
import com.example.quiz.data.model.Horse;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
public class BetsBank {
public List<Bet> getBet() {
return Arrays.asList(
new Bet(
1,
"Course de chevaux",
LocalDate.of(2025,10,1),
Arrays.asList(
new Horse(1),
new Horse(2),
new Horse(3),
new Horse(4)
)
),
new Bet(
2,
"Course de chevaux 2",
LocalDate.of(2025,10,1),
Arrays.asList(
new Horse(4),
new Horse(5),
new Horse(7),
new Horse(6)
)
),
new Bet(
3,
"Course de chevaux 3",
LocalDate.of(2025,10,1),
Arrays.asList(
new Horse(10),
new Horse(90),
new Horse(45),
new Horse(9)
)
),
new Bet(
4,
"Course de chevaux 4",
LocalDate.of(2025,10,1),
Arrays.asList(
new Horse(5),
new Horse(33),
new Horse(26),
new Horse(99),
new Horse(100),
new Horse(101),
new Horse(102),
new Horse(103),
new Horse(104),
new Horse(105)
)
)
);
}
public static BetsBank instance;
public static BetsBank getInstance(){
if(instance == null){
instance = new BetsBank();
}
return instance;
}
}

View File

@@ -1,69 +0,0 @@
package com.example.quiz.data;
import com.example.quiz.data.model.Question;
import java.util.Arrays;
import java.util.List;
public class QuestionsBank {
public List<Question> getQuestions() {
return Arrays.asList(
new Question(
"Who is the creator of Android?",
Arrays.asList(
"Andy Rubin",
"Steve Wozniak",
"Jake Wharton",
"Paul Smith"
),
0
),
new Question(
"When did the first man land on the moon?",
Arrays.asList(
"1958",
"1962",
"1967",
"1969"
),
3
),
new Question(
"What is the house number of The Simpsons?",
Arrays.asList(
"42",
"101",
"666",
"742"
),
3
),
new Question(
"Who painteddid the Mona Lisa paint?",
Arrays.asList(
"Michelangelo",
"Leonardo Da Vinci",
"Raphael",
"Caravaggio"
),
1
),
new Question(
"What is the country top-level domain of Belgium?",
Arrays.asList(
".bg",
".bm",
".bl",
".be"
),
3
)
);
}
private static QuestionsBank instance;
public static QuestionsBank getInstance() {
if (instance == null) {
instance = new QuestionsBank();
}
return instance;
}
}

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

@@ -10,27 +10,33 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.example.quiz.R; import com.example.quiz.R;
import com.example.quiz.data.model.Bet; import com.example.quiz.data.model.Course;
import com.example.quiz.viewModel.SharedViewModel;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class BetsAdapter extends RecyclerView.Adapter<BetsAdapter.BetViewHolder> { public class BetsAdapter extends RecyclerView.Adapter<BetsAdapter.BetViewHolder> {
private List<Bet> bets = new ArrayList<>();
private List<Course> bets = new ArrayList<>();
private onItemClickListener listener; private onItemClickListener listener;
public BetsAdapter() {
}
public interface onItemClickListener { public interface onItemClickListener {
void onItemClick(int position); void onItemClick(Course bet);
} }
public void setOnItemClickListener(onItemClickListener listener){ public void setOnItemClickListener(onItemClickListener listener){
this.listener = listener; this.listener = listener;
} }
public void setBets(List<Course> bets){
public void setBets(List<Bet> bets){
this.bets = bets; this.bets = bets;
notifyDataSetChanged(); notifyDataSetChanged();
} }
@@ -38,38 +44,41 @@ public class BetsAdapter extends RecyclerView.Adapter<BetsAdapter.BetViewHolder>
@NonNull @NonNull
@Override @Override
public BetViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public BetViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_bet, parent, false); View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_bet, parent, false);
return new BetViewHolder(view); return new BetViewHolder(view);
} }
@Override @Override
public void onBindViewHolder(@NonNull BetViewHolder holder, int position) { public void onBindViewHolder(@NonNull BetViewHolder holder, int position) {
Bet bet = bets.get(position); Course bet = bets.get(position);
holder.tvDate.setText(String.valueOf(bet.getDate())); OffsetDateTime dateTime = OffsetDateTime.parse(bet.getHeureDepartPrevue());
holder.tvName.setText(String.valueOf(bet.getName())); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
String formattedDate = dateTime.format(formatter);
holder.tvDate.setText(formattedDate);
holder.tvName.setText(bet.getNom());
String reunion = "Reunion "+bet.getReunionNumero();
holder.tvReunion.setText(reunion);
holder.itemView.setOnClickListener(v -> { holder.itemView.setOnClickListener(v -> {
if(listener != null){ if (listener != null) listener.onItemClick(bet);
listener.onItemClick(bet.getId());
}
}); });
} }
@Override @Override
public int getItemCount(){ public int getItemCount(){
return bets.size(); return bets.size();
} }
static class BetViewHolder extends RecyclerView.ViewHolder{ static class BetViewHolder extends RecyclerView.ViewHolder{
TextView tvName, tvDate; TextView tvName, tvDate, tvReunion;
public BetViewHolder(@NonNull View itemView) { public BetViewHolder(@NonNull View itemView) {
super(itemView); super(itemView);
tvName = itemView.findViewById(R.id.tvName); tvName = itemView.findViewById(R.id.tvName);
tvDate = itemView.findViewById(R.id.tvDate); tvDate = itemView.findViewById(R.id.tvDate);
tvReunion = itemView.findViewById(R.id.tvReunion);
} }
} }
} }

View File

@@ -0,0 +1,152 @@
package com.example.quiz.data.adapter;
import static java.security.AccessController.getContext;
import android.graphics.Color;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.quiz.R;
import com.example.quiz.data.model.Pari;
import com.example.quiz.data.model.ParisResponse;
import java.util.ArrayList;
import java.util.List;
public class LastBetsAdapter extends RecyclerView.Adapter<LastBetsAdapter.LastBetsViewHolder> {
private List<ParisResponse> listeParis = new ArrayList<>(); // évite les NPE
private onPariClickListener listener;
public interface onPariClickListener {
void onItemClick(ParisResponse pari);
void onItemCancel(ParisResponse pari);
}
public void setPariClickListener(onPariClickListener listener) {
this.listener = listener;
}
public LastBetsAdapter(List<ParisResponse> listeParis) {
if (listeParis != null) this.listeParis = listeParis;
}
public void setData(List<ParisResponse> newList) {
if (newList == null) {
this.listeParis = new ArrayList<>();
} else {
this.listeParis = newList;
}
notifyDataSetChanged();
}
public void addItem(ParisResponse pari) {
if (pari == null) return;
this.listeParis.add(pari);
notifyItemInserted(listeParis.size() - 1);
}
public void clear() {
this.listeParis.clear();
notifyDataSetChanged();
}
@NonNull
@Override
public LastBetsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.last_bets_item, parent, false);
return new LastBetsViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull LastBetsViewHolder holder, int position) {
ParisResponse pari = listeParis.get(position);
if (pari == null) return;
holder.typeOfCourse.setText(pari.getCourseNom());
holder.refenceTicket.setText(pari.getNumeroTicket());
holder.betType.setText(pari.getFormules().size()>0 ? pari.getFormules().get(0):"Pas de formule");
holder.course.setText("Course: " + pari.getCourseId());
// Chevaux : join en toute sécurité (gère Integer list ou String list)
holder.horses.setText(pari.getCombinaison());
// Mise (défensif)
holder.mise.setText("Mise: " + pari.getMiseTotale() + " CFA");
holder.tvStatut.setText(pari.getStatutPari() != null ? String.valueOf(pari.getStatutPari()) : "Pas de statut");
switch (pari.getStatutPari()){
case ANNULE:{
holder.tvStatut.setTextColor(Color.RED);
holder.btnAnnuler.setVisibility(View.GONE);
holder.btnImprimer.setVisibility(View.GONE);
break;
}
case PAYE:{
holder.tvStatut.setTextColor(Color.GREEN);
holder.btnAnnuler.setVisibility(View.GONE);
holder.btnImprimer.setVisibility(View.GONE);
break;
}
case ENREGISTRE:{
holder.tvStatut.setTextColor(Color.YELLOW);
holder.btnAnnuler.setVisibility(View.VISIBLE);
holder.btnImprimer.setVisibility(View.VISIBLE);
break;
}
default:{
holder.tvStatut.setTextColor(Color.BLACK);
holder.btnAnnuler.setVisibility(View.GONE);
holder.btnImprimer.setVisibility(View.GONE);
break;
}
}
holder.btnAnnuler.setOnClickListener(v -> {
if (listener != null) {
listener.onItemCancel(pari);
}
});
holder.btnImprimer.setOnClickListener(v -> {
if (listener != null) {
listener.onItemClick(pari);
}
});
}
@Override
public int getItemCount() {
return (listeParis != null) ? listeParis.size() : 0;
}
public static class LastBetsViewHolder extends RecyclerView.ViewHolder {
TextView betType, horses, course, mise, refenceTicket, typeOfCourse, tvStatut;
Button btnAnnuler, btnImprimer;;
public LastBetsViewHolder(@NonNull View itemView) {
super(itemView);
betType = itemView.findViewById(R.id.last_bet_type);
course = itemView.findViewById(R.id.last_bet_course);
horses = itemView.findViewById(R.id.last_bet_horses);
mise = itemView.findViewById(R.id.last_bet_mise);
refenceTicket = itemView.findViewById(R.id.reference_ticket);
typeOfCourse = itemView.findViewById(R.id.type_of_course);
btnAnnuler = itemView.findViewById(R.id.btn_annuler);
btnImprimer = itemView.findViewById(R.id.btn_imprimer);
tvStatut = itemView.findViewById(R.id.tv_statut);
}
}
}

View File

@@ -0,0 +1,63 @@
package com.example.quiz.data.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.example.quiz.R;
import com.example.quiz.data.entity.Logs;
import org.jspecify.annotations.NonNull;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class LogsAdapter extends RecyclerView.Adapter<LogsAdapter.LogViewHolder> {
private List<Logs> logs = new ArrayList<>();
public void setLogs(List<Logs> logs) {
this.logs = logs;
notifyDataSetChanged();
}
@NonNull
@Override
public LogViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_log, parent, false);
return new LogViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull LogViewHolder holder, int position) {
Logs log = logs.get(position);
holder.textAction.setText(log.getAction());
holder.textDescription.setText(log.getDescription());
SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy • HH:mm", Locale.getDefault());
holder.textDate.setText(sdf.format(new Date(log.getTimestamp())));
}
@Override
public int getItemCount() {
return logs.size();
}
static class LogViewHolder extends RecyclerView.ViewHolder {
TextView textAction, textDescription, textDate;
public LogViewHolder(@NonNull View itemView) {
super(itemView);
textAction = itemView.findViewById(R.id.textAction);
textDescription = itemView.findViewById(R.id.textDescription);
textDate = itemView.findViewById(R.id.textDate);
}
}
}

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

@@ -0,0 +1,78 @@
package com.example.quiz.data.adapter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.quiz.R;
import com.example.quiz.data.model.PointDeVente;
import java.util.ArrayList;
import java.util.List;
public class PointDeVenteAdapter extends RecyclerView.Adapter<PointDeVenteAdapter.ViewHolder> {
private List<PointDeVente> points = new ArrayList<>();
private OnItemClickListener listener;
public PointDeVenteAdapter(){
}
// Interface pour gérer le clic sur un item
public interface OnItemClickListener {
void onItemClick(PointDeVente point);
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.listener = listener;
}
public void setPoints(List<PointDeVente> points) {
this.points = points;
notifyDataSetChanged();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_point_de_vente, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
PointDeVente point = points.get(position);
holder.txtNom.setText(point.getNom());
String adresse = point.getVille()+", "+point.getAdresse();
holder.txtAdresse.setText(adresse);
holder.itemView.setOnClickListener(v -> {
if (listener != null) listener.onItemClick(point);
});
}
@Override
public int getItemCount() {
return points.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView txtNom;
TextView txtAdresse;
public ViewHolder(@NonNull View itemView) {
super(itemView);
txtNom = itemView.findViewById(R.id.txtNom);
txtAdresse = itemView.findViewById(R.id.txtAdresse);
}
}
}

View File

@@ -0,0 +1,72 @@
package com.example.quiz.data.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.quiz.R;
import com.example.quiz.data.model.Reunion;
import java.util.ArrayList;
import java.util.List;
public class ReunionAdapter extends RecyclerView.Adapter<ReunionAdapter.ReunionViewHolder> {
private List<Reunion> reunions = List.of();
private onItemClickListener listener;
public interface onItemClickListener {
void onItemClick(Reunion reunion);
}
public void setOnItemClickListener(onItemClickListener listener){
this.listener = listener;
}
public void setReunions(List<Reunion> reunions){
this.reunions = reunions;
notifyDataSetChanged();
}
@NonNull
@Override
public ReunionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_reunion, parent, false);
return new ReunionViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ReunionViewHolder holder, int position){
Reunion reunion = reunions.get(position);
holder.reunionName.setText(String.valueOf(reunion.getNom()));
holder.reunionDate.setText(String.valueOf(reunion.getDate()));
holder.itemView.setOnClickListener(v -> {
if(listener != null){
listener.onItemClick(reunion);
}
});
}
@Override
public int getItemCount() {
return reunions.size();
}
static class ReunionViewHolder extends RecyclerView.ViewHolder {
TextView reunionName, reunionDate;
public ReunionViewHolder(View itemView){
super(itemView);
reunionName = itemView.findViewById(R.id.reunionName);
reunionDate = itemView.findViewById(R.id.reunionDate);
}
}
}

View File

@@ -0,0 +1,80 @@
package com.example.quiz.data.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.quiz.R;
import com.example.quiz.data.model.TypeOfBet;
import java.util.List;
public class TypeOfBetAdapter extends RecyclerView.Adapter<TypeOfBetAdapter.TypeOfBetViewHolder> {
private List<TypeOfBet> types;
private onItemClickListener listener;
private int selectedPosition = -1;
public interface onItemClickListener{
void onItemClick(TypeOfBet type);
}
public void setOnItemClickListener(TypeOfBetAdapter.onItemClickListener listener){
this.listener = listener;
}
public TypeOfBetAdapter(List<TypeOfBet> types){
this.types = types;
}
public void setTypes(List<TypeOfBet> types){
this.types = types;
notifyDataSetChanged();
}
@NonNull
@Override
public TypeOfBetViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.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());
if(selectedPosition != position){
holder.itemView.setBackgroundResource(R.drawable.item_gradient_bg);
}else{
holder.itemView.setBackgroundResource(R.drawable.item_gradient_bg_selected);
}
holder.itemView.setOnClickListener(v->{
if(listener != null){
listener.onItemClick(type);
}
int previousPosition = selectedPosition;
selectedPosition = holder.getAdapterPosition();
notifyItemChanged(previousPosition);
notifyItemChanged(selectedPosition);
});
}
@Override
public int getItemCount() {
return types.size();
}
public class TypeOfBetViewHolder extends RecyclerView.ViewHolder {
TextView type_of_bet_name;
public TypeOfBetViewHolder(@NonNull View itemView) {
super(itemView);
type_of_bet_name = itemView.findViewById(R.id.type_of_bet_name);
}
}
}

View File

@@ -0,0 +1,20 @@
package com.example.quiz.data.dao;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.Query;
import com.example.quiz.data.entity.Logs;
import java.util.List;
@Dao
public interface UserActivityLogDao {
@Insert
void insertLog(Logs log);
@Query(" SELECT * FROM user_activity_logs WHERE date(timestamp / 1000, 'unixepoch', 'localtime') = date('now', 'localtime') ORDER BY timestamp DESC ")
LiveData<List<Logs>> getTodayLogs();
}

View File

@@ -0,0 +1,30 @@
package com.example.quiz.data.database;
import android.content.Context;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import com.example.quiz.data.dao.UserActivityLogDao;
import com.example.quiz.data.entity.Logs;
@Database(entities = {Logs.class}, version = 3, exportSchema = false)
public abstract class AppDataBase extends RoomDatabase {
private static AppDataBase instance;
public abstract UserActivityLogDao logsDao();
public static synchronized AppDataBase getInstance(Context context) {
if (instance == null) {
instance = Room.databaseBuilder(
context.getApplicationContext(),
AppDataBase.class,
"app-db"
).fallbackToDestructiveMigration() // optionnel
.build();
}
return instance;
}
}

View File

@@ -0,0 +1,34 @@
package com.example.quiz.data.database;
import android.content.Context;
import androidx.room.Room;
public class DatabaseClient {
private static DatabaseClient instance;
private AppDataBase appDatabase;
private Context context;
private DatabaseClient(Context context) {
this.context = context;
appDatabase = Room.databaseBuilder(context,
AppDataBase.class, "QuizDB")
.fallbackToDestructiveMigration()
.build();
}
public static synchronized DatabaseClient getInstance(Context context) {
if (instance == null) {
instance = new DatabaseClient(context);
}
return instance;
}
public AppDataBase getAppDatabase() {
return appDatabase;
}
}

View File

@@ -0,0 +1,33 @@
package com.example.quiz.data.database;
import android.content.Context;
import androidx.room.Room;
import com.example.quiz.data.dao.UserActivityLogDao;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import dagger.hilt.InstallIn;
import dagger.hilt.android.qualifiers.ApplicationContext;
import dagger.hilt.components.SingletonComponent;
@Module
@InstallIn(SingletonComponent.class)
public class DatabaseModule {
@Provides
@Singleton
public static AppDataBase provideDatabase(@ApplicationContext Context context) {
return Room.databaseBuilder(context, AppDataBase.class, "QuizDB")
.fallbackToDestructiveMigration()
.build();
}
@Provides
public static UserActivityLogDao provideUserActivityLogDao(AppDataBase db) {
return db.logsDao(); // ton DAO
}
}

View File

@@ -0,0 +1,59 @@
package com.example.quiz.data.entity;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity(tableName = "user_activity_logs")
public class Logs {
@PrimaryKey(autoGenerate = true)
private int id;
private String userId;
private String action;
private String description;
private Long timestamp;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
}

View File

@@ -1,52 +0,0 @@
package com.example.quiz.data.model;
import java.time.LocalDate;
import java.util.List;
public class Bet {
private int id;
private String name;
private LocalDate date;
private List<Horse> horses;
public List<Horse> getHorses() {
return horses;
}
public void setHorses(List<Horse> horses) {
this.horses = horses;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public Bet(int id, String name, LocalDate date, List<Horse> horses) {
this.id = id;
this.name = name;
this.date = date;
this.horses = horses;
}
}

View File

@@ -0,0 +1,57 @@
package com.example.quiz.data.model;
public class Cheval {
private int number;
private String nom;
private String numero;
private boolean nonPartant;
private boolean nonEcurie;
public Cheval(int number, String nom, String numero, boolean nonPartant, boolean nonEcurie) {
this.number = number;
this.nom = nom;
this.numero = numero;
this.nonPartant = nonPartant;
this.nonEcurie = nonEcurie;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String getNumero() {
return numero;
}
public void setNumero(String numero) {
this.numero = numero;
}
public boolean isNonPartant() {
return nonPartant;
}
public void setNonPartant(boolean nonPartant) {
this.nonPartant = nonPartant;
}
public boolean isNonEcurie() {
return nonEcurie;
}
public void setNonEcurie(boolean nonEcurie) {
this.nonEcurie = nonEcurie;
}
}

View File

@@ -0,0 +1,81 @@
package com.example.quiz.data.model;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
public class Course {
private long id;
private long hippodromeId;
private long reunionNumero;
private String reunionDate;
private String nom;
private int numero;
private String heureDepartPrevue;
private boolean bettingOpen;
private String bettingClosedAt;
private String discipline;
private int distanceMetres;
private String categorie;
private int nombrePartants;
private Statut statut;
private boolean annulee;
private boolean reporteeMemeJour;
private boolean reporteeAutreJour;
private boolean incidentTechnique;
private List<Integer> nonPartants;
private List<TypeParis> typesParisOuverts;
// ===== ENUMS =====
public enum Statut {
BROUILLON,
VALIDE,
OUVERT,
FERME,
RESULTAT_PROVISOIRE,
RESULTAT_OFFICIEL,
REGLEE,
ANNULEE
}
public enum TypeParis {
COUPLE_GAGNANT,
COUPLE_PLACE,
TIERCE,
QUARTE,
QUINTE
}
// ===== GETTERS & SETTERS =====
public long getId() { return id; }
public long getHippodromeId() { return hippodromeId; }
public long getReunionNumero() { return reunionNumero; }
public String getReunionDate() { return reunionDate; }
public String getNom() { return nom; }
public int getNumero() { return numero; }
public String getHeureDepartPrevue() { return heureDepartPrevue; }
public boolean isBettingOpen() { return bettingOpen; }
public String getBettingClosedAt() { return bettingClosedAt; }
public String getDiscipline() { return discipline; }
public int getDistanceMetres() { return distanceMetres; }
public String getCategorie() { return categorie; }
public int getNombrePartants() { return nombrePartants; }
public Statut getStatut() { return statut; }
public boolean isAnnulee() { return annulee; }
public boolean isReporteeMemeJour() { return reporteeMemeJour; }
public boolean isReporteeAutreJour() { return reporteeAutreJour; }
public boolean isIncidentTechnique() { return incidentTechnique; }
public List<Integer> getNonPartants() { return nonPartants; }
public List<TypeParis> getTypesParisOuverts() { return typesParisOuverts; }
}

View File

@@ -0,0 +1,67 @@
package com.example.quiz.data.model;
public class Hippodrome {
private int id;
private String nom;
private String ville;
private String pays;
private int capacite;
private String description;
public Hippodrome(int id, String nom, String ville, String pays, int capacite, String description) {
this.id = id;
this.nom = nom;
this.ville = ville;
this.pays = pays;
this.capacite = capacite;
this.description = description;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String getVille() {
return ville;
}
public void setVille(String ville) {
this.ville = ville;
}
public String getPays() {
return pays;
}
public void setPays(String pays) {
this.pays = pays;
}
public int getCapacite() {
return capacite;
}
public void setCapacite(int capacite) {
this.capacite = capacite;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

View File

@@ -1,18 +0,0 @@
package com.example.quiz.data.model;
public class Horse {
private Integer number;
public Horse(Integer number) {
this.number = number;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
}

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,62 @@
package com.example.quiz.data.model;
import com.example.quiz.data.model.enums.Pageable;
import java.util.List;
public class PagedModel<T> {
private Long totalPages;
private Long totalElements;
private Pageable pageable;
private Long numberOfElements;
private Long size;
private List<T> content;
public Long getTotalPages() {
return totalPages;
}
public void setTotalPages(Long totalPages) {
this.totalPages = totalPages;
}
public Long getTotalElements() {
return totalElements;
}
public void setTotalElements(Long totalElements) {
this.totalElements = totalElements;
}
public Pageable getPageable() {
return pageable;
}
public void setPageable(Pageable pageable) {
this.pageable = pageable;
}
public Long getNumberOfElements() {
return numberOfElements;
}
public void setNumberOfElements(Long numberOfElements) {
this.numberOfElements = numberOfElements;
}
public Long getSize() {
return size;
}
public void setSize(Long size) {
this.size = size;
}
public List<T> getContent() {
return content;
}
public void setContent(List<T> content) {
this.content = content;
}
}

View File

@@ -0,0 +1,54 @@
package com.example.quiz.data.model;
import com.example.quiz.data.model.dtos.PariCourseDto;
import com.example.quiz.data.model.enums.PariStatut;
import java.util.List;
import java.util.Map;
import java.util.List;
import java.util.List;
public class Pari {
private String dateHeurePrise; // ISO String
private long courseId;
private long agentId;
private long terminalId;
private long pointDeVenteId;
private List<PariMise> typesParisMises;
private List<String> formules;
private String combinaison;
private double coefficient;
private String devise;
private String notes;
public Pari(String dateHeurePrise, long courseId, long agentId, long terminalId, long pointDeVenteId, List<PariMise> typesParisMises, List<String> formules, String combinaison, double coefficient, String devise, String notes) {
this.dateHeurePrise = dateHeurePrise;
this.courseId = courseId;
this.agentId = agentId;
this.terminalId = terminalId;
this.pointDeVenteId = pointDeVenteId;
this.typesParisMises = typesParisMises;
this.formules = formules;
this.combinaison = combinaison;
this.coefficient = coefficient;
this.devise = devise;
this.notes = notes;
}
public String getDateHeurePrise() { return dateHeurePrise; }
public long getCourseId() { return courseId; }
public long getAgentId() { return agentId; }
public long getTerminalId() { return terminalId; }
public long getPointDeVenteId() { return pointDeVenteId; }
public List<PariMise> getTypesParisMises() { return typesParisMises; }
public List<String> getFormules() { return formules; }
public String getCombinaison() { return combinaison; }
public double getCoefficient() { return coefficient; }
public String getDevise() { return devise; }
public String getNotes() { return notes; }
// ===== INNER CLASS =====
}

View File

@@ -0,0 +1,19 @@
package com.example.quiz.data.model;
public class PariMise {
private String typePari;
private long miseTotale;
public PariMise(String typePari, long miseTotale) {
this.typePari = typePari;
this.miseTotale = miseTotale;
}
public String getTypePari() {
return typePari;
}
public long getMiseTotale() {
return miseTotale;
}
}

View File

@@ -0,0 +1,104 @@
package com.example.quiz.data.model;
import java.io.Serializable;
import java.time.temporal.TemporalAccessor;
import java.util.List;
public class ParisResponse implements Serializable {
private long id;
private String numeroTicket;
private String dateHeurePrise;
private String qrPayload;
private long courseId;
private String courseNom;
private int courseNumero;
private String hippodromeNom;
private long reunionNumero;
private String reunionDate;
private String heureDepartPrevue;
private int nombrePartants;
private List<Integer> nonPartants;
private long agentId;
private String agentCode;
private String agentNom;
private long terminalId;
private String terminalNumeroSerie;
private long pointDeVenteId;
private String pointDeVenteCode;
private String pointDeVenteNom;
private List<PariMise> typesParisMises;
private long miseTotale;
private List<String> formules;
private double coefficient;
private String combinaison;
private StatutPari statutPari;
private long gainCalcule;
private String devise;
private String dateReglement;
private String datePaiement;
private String notes;
// ================= ENUM =================
public enum StatutPari {
ENREGISTRE,
VALIDE,
PAYE,
ANNULE,
PERDANT,
GAGNANT,
A_REMBOURSER,
REMBOURSE,
ECHEC_CACUL
}
// ================= INNER CLASS =================
// ================= GETTERS =================
public long getId() { return id; }
public String getNumeroTicket() { return numeroTicket; }
public String getDateHeurePrise() { return dateHeurePrise; }
public String getQrPayload() { return qrPayload; }
public long getCourseId() { return courseId; }
public String getCourseNom() { return courseNom; }
public int getCourseNumero() { return courseNumero; }
public String getHippodromeNom() { return hippodromeNom; }
public long getReunionNumero() { return reunionNumero; }
public String getReunionDate() { return reunionDate; }
public String getHeureDepartPrevue() { return heureDepartPrevue; }
public int getNombrePartants() { return nombrePartants; }
public List<Integer> getNonPartants() { return nonPartants; }
public long getAgentId() { return agentId; }
public String getAgentCode() { return agentCode; }
public String getAgentNom() { return agentNom; }
public long getTerminalId() { return terminalId; }
public String getTerminalNumeroSerie() { return terminalNumeroSerie; }
public long getPointDeVenteId() { return pointDeVenteId; }
public String getPointDeVenteCode() { return pointDeVenteCode; }
public String getPointDeVenteNom() { return pointDeVenteNom; }
public List<PariMise> getTypesParisMises() { return typesParisMises; }
public long getMiseTotale() { return miseTotale; }
public List<String> getFormules() { return formules; }
public double getCoefficient() { return coefficient; }
public String getCombinaison() { return combinaison; }
public StatutPari getStatutPari() { return statutPari; }
public long getGainCalcule() { return gainCalcule; }
public String getDevise() { return devise; }
public String getDateReglement() { return dateReglement; }
public String getDatePaiement() { return datePaiement; }
public String getNotes() { return notes; }
}

View File

@@ -0,0 +1,92 @@
package com.example.quiz.data.model;
public class PointDeVente {
private Long id;
private String code;
private String nom;
private String adresse;
private String ville;
private String latitude;
private String longitude;
private PointStatus statut;
public PointDeVente(Long id, String code, String nom, String adresse, String ville, String latitude, String longitude, PointStatus statut) {
this.id = id;
this.code = code;
this.nom = nom;
this.adresse = adresse;
this.ville = ville;
this.latitude = latitude;
this.longitude = longitude;
this.statut = statut;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String getAdresse() {
return adresse;
}
public void setAdresse(String adresse) {
this.adresse = adresse;
}
public String getVille() {
return ville;
}
public void setVille(String ville) {
this.ville = ville;
}
public String getLatitude() {
return latitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
public String getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
public PointStatus getStatut() {
return statut;
}
public void setStatut(PointStatus statut) {
this.statut = statut;
}
public enum PointStatus {
ACTIF,
INACTIF
}
}

View File

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

View File

@@ -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,79 @@
package com.example.quiz.data.model;
import java.time.LocalDate;
public class Reunion {
private int id;
private String code;
private String nom;
private String date;
private int numero;
private Hippodrome hippodrome;
private int totalCourses;
public Reunion(int id, String code, String nom, String date, int numero, Hippodrome hippodrome, int totalCourses) {
this.id = id;
this.code = code;
this.nom = nom;
this.date = date;
this.numero = numero;
this.hippodrome = hippodrome;
this.totalCourses = totalCourses;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public int getNumero() {
return numero;
}
public void setNumero(int numero) {
this.numero = numero;
}
public Hippodrome getHippodrome() {
return hippodrome;
}
public void setHippodrome(Hippodrome hippodrome) {
this.hippodrome = hippodrome;
}
public int getTotalCourses() {
return totalCourses;
}
public void setTotalCourses(int totalCourses) {
this.totalCourses = totalCourses;
}
}

View File

@@ -0,0 +1,114 @@
package com.example.quiz.data.model;
public class Tpe {
private String numeroSerie;
private long pointDeVenteId;
private String statut;
private String versionLogicielle;
private String typeTerminal;
private String plateforme;
private String modeleAppareil;
private String systemeExploitation;
private String versionOs;
private String adresseIp;
private String adresseMac;
private String journalSession;
public Tpe() {}
public String getNumeroSerie() {
return numeroSerie;
}
public void setNumeroSerie(String numeroSerie) {
this.numeroSerie = numeroSerie;
}
public long getPointDeVenteId() {
return pointDeVenteId;
}
public void setPointDeVenteId(long pointDeVenteId) {
this.pointDeVenteId = pointDeVenteId;
}
public String getStatut() {
return statut;
}
public void setStatut(String statut) {
this.statut = statut;
}
public String getVersionLogicielle() {
return versionLogicielle;
}
public void setVersionLogicielle(String versionLogicielle) {
this.versionLogicielle = versionLogicielle;
}
public String getTypeTerminal() {
return typeTerminal;
}
public void setTypeTerminal(String typeTerminal) {
this.typeTerminal = typeTerminal;
}
public String getPlateforme() {
return plateforme;
}
public void setPlateforme(String plateforme) {
this.plateforme = plateforme;
}
public String getModeleAppareil() {
return modeleAppareil;
}
public void setModeleAppareil(String modeleAppareil) {
this.modeleAppareil = modeleAppareil;
}
public String getSystemeExploitation() {
return systemeExploitation;
}
public void setSystemeExploitation(String systemeExploitation) {
this.systemeExploitation = systemeExploitation;
}
public String getVersionOs() {
return versionOs;
}
public void setVersionOs(String versionOs) {
this.versionOs = versionOs;
}
public String getAdresseIp() {
return adresseIp;
}
public void setAdresseIp(String adresseIp) {
this.adresseIp = adresseIp;
}
public String getAdresseMac() {
return adresseMac;
}
public void setAdresseMac(String adresseMac) {
this.adresseMac = adresseMac;
}
public String getJournalSession() {
return journalSession;
}
public void setJournalSession(String journalSession) {
this.journalSession = journalSession;
}
}

View File

@@ -0,0 +1,51 @@
package com.example.quiz.data.model;
public class TpeResponse extends Tpe {
private long id;
private String derniereConnexion;
private String derniereConnexionAgent;
private String derniereDeconnexionAgent;
private boolean assigned;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getDerniereConnexion() {
return derniereConnexion;
}
public void setDerniereConnexion(String derniereConnexion) {
this.derniereConnexion = derniereConnexion;
}
public String getDerniereConnexionAgent() {
return derniereConnexionAgent;
}
public void setDerniereConnexionAgent(String derniereConnexionAgent) {
this.derniereConnexionAgent = derniereConnexionAgent;
}
public String getDerniereDeconnexionAgent() {
return derniereDeconnexionAgent;
}
public void setDerniereDeconnexionAgent(String derniereDeconnexionAgent) {
this.derniereDeconnexionAgent = derniereDeconnexionAgent;
}
public boolean isAssigned() {
return assigned;
}
public void setAssigned(boolean assigned) {
this.assigned = assigned;
}
}

View File

@@ -0,0 +1,38 @@
package com.example.quiz.data.model;
public class TypeOfBet {
private String label;
private Course.TypeParis name;
private int numberOfHorse;
public TypeOfBet(String label, Course.TypeParis name, int numberOfHorse) {
this.label = label;
this.name = name;
this.numberOfHorse = numberOfHorse;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public Course.TypeParis getName() {
return name;
}
public void setName(Course.TypeParis name) {
this.name = name;
}
public int getNumberOfHorse() {
return numberOfHorse;
}
public void setNumberOfHorse(int numberOfHorse) {
this.numberOfHorse = numberOfHorse;
}
}

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

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

View File

@@ -0,0 +1,78 @@
package com.example.quiz.data.model.dtos.auth;
public class Agent {
private Long id;
private String code;
private String nom;
private String prenom;
private String phone;
private String zone;
private String fonction;
private boolean subAgent;
public Agent(){}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String getPrenom() {
return prenom;
}
public void setPrenom(String prenom) {
this.prenom = prenom;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getZone() {
return zone;
}
public void setZone(String zone) {
this.zone = zone;
}
public String getFonction() {
return fonction;
}
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,38 @@
package com.example.quiz.data.model.dtos.auth;
public class LoginPayload {
private String code;
private String pin;
private Long terminalId;
public LoginPayload(String code, String pin, Long terminalId) {
this.code = code;
this.pin = pin;
this.terminalId = terminalId;
}
public Long getTerminalId() {
return terminalId;
}
public void setTerminalId(Long terminalId) {
this.terminalId = terminalId;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getPin() {
return pin;
}
public void setPin(String pin) {
this.pin = pin;
}
}

View File

@@ -0,0 +1,27 @@
package com.example.quiz.data.model.dtos.auth;
public class LoginResponse {
private String token;
private Agent agent;
public LoginResponse(String token, Agent agent) {
this.token = token;
this.agent = agent;
}
public Agent getUser() {
return agent;
}
public void setUser(Agent agent) {
this.agent = agent;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}

View File

@@ -0,0 +1,237 @@
package com.example.quiz.data.model.dtos.auth;
public class User {
private int id;
private String code;
private String profile;
private String principalCode;
private String caisseProfile;
private String statut;
private String zone;
private String kiosk;
private String fonction;
private String dateEmbauche;
private String derniereConnexion;
private String nom;
private String prenom;
private String autresNom;
private String dateNaissance;
private String lieuNaissance;
private String ville;
private String adresse;
private String cni;
private double limiteInferieure;
private double limiteSuperieure;
private double limiteParTransaction;
private String autreAdresse1;
public User(int id, String code, String profile, String principalCode, String caisseProfile, String statut, String zone, String kiosk, String fonction, String dateEmbauche, String derniereConnexion, String nom, String prenom, String autresNom, String dateNaissance, String lieuNaissance, String ville, String adresse, String cni, double limiteInferieure, double limiteSuperieure, double limiteParTransaction, String autreAdresse1){
this.id = id;
this.code = code;
this.profile = profile;
this.principalCode = principalCode;
this.caisseProfile = caisseProfile;
this.statut = statut;
this.zone = zone;
this.kiosk = kiosk;
this.fonction = fonction;
this.dateEmbauche = dateEmbauche;
this.derniereConnexion = derniereConnexion;
this.nom = nom;
this.prenom = prenom;
this.autresNom = autresNom;
this.dateNaissance = dateNaissance;
this.lieuNaissance = lieuNaissance;
this.ville = ville;
this.adresse = adresse;
this.cni = cni;
this.limiteInferieure = limiteInferieure;
this.limiteSuperieure = limiteSuperieure;
this.limiteParTransaction = limiteParTransaction;
this.autreAdresse1 = autreAdresse1;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getProfile() {
return profile;
}
public void setProfile(String profile) {
this.profile = profile;
}
public String getPrincipalCode() {
return principalCode;
}
public void setPrincipalCode(String principalCode) {
this.principalCode = principalCode;
}
public String getCaisseProfile() {
return caisseProfile;
}
public void setCaisseProfile(String caisseProfile) {
this.caisseProfile = caisseProfile;
}
public String getStatut() {
return statut;
}
public void setStatut(String statut) {
this.statut = statut;
}
public String getZone() {
return zone;
}
public void setZone(String zone) {
this.zone = zone;
}
public String getKiosk() {
return kiosk;
}
public void setKiosk(String kiosk) {
this.kiosk = kiosk;
}
public String getFonction() {
return fonction;
}
public void setFonction(String fonction) {
this.fonction = fonction;
}
public String getDateEmbauche() {
return dateEmbauche;
}
public void setDateEmbauche(String dateEmbauche) {
this.dateEmbauche = dateEmbauche;
}
public String getDerniereConnexion() {
return derniereConnexion;
}
public void setDerniereConnexion(String derniereConnexion) {
this.derniereConnexion = derniereConnexion;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String getPrenom() {
return prenom;
}
public void setPrenom(String prenom) {
this.prenom = prenom;
}
public String getAutresNom() {
return autresNom;
}
public void setAutresNom(String autresNom) {
this.autresNom = autresNom;
}
public String getDateNaissance() {
return dateNaissance;
}
public void setDateNaissance(String dateNaissance) {
this.dateNaissance = dateNaissance;
}
public String getLieuNaissance() {
return lieuNaissance;
}
public void setLieuNaissance(String lieuNaissance) {
this.lieuNaissance = lieuNaissance;
}
public String getVille() {
return ville;
}
public void setVille(String ville) {
this.ville = ville;
}
public String getAdresse() {
return adresse;
}
public void setAdresse(String adresse) {
this.adresse = adresse;
}
public String getCni() {
return cni;
}
public void setCni(String cni) {
this.cni = cni;
}
public double getLimiteInferieure() {
return limiteInferieure;
}
public void setLimiteInferieure(double limiteInferieure) {
this.limiteInferieure = limiteInferieure;
}
public double getLimiteSuperieure() {
return limiteSuperieure;
}
public void setLimiteSuperieure(double limiteSuperieure) {
this.limiteSuperieure = limiteSuperieure;
}
public double getLimiteParTransaction() {
return limiteParTransaction;
}
public void setLimiteParTransaction(double limiteParTransaction) {
this.limiteParTransaction = limiteParTransaction;
}
public String getAutreAdresse1() {
return autreAdresse1;
}
public void setAutreAdresse1(String autreAdresse1) {
this.autreAdresse1 = autreAdresse1;
}
}

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

@@ -0,0 +1,38 @@
package com.example.quiz.data.model.enums;
import java.io.Serializable;
public class Pageable implements Serializable {
private boolean unpaged;
private boolean paged;
private int pageNumber;
private int pageSize;
private long offset; // ⚠️ long obligatoire
private Sort sort;
public boolean isUnpaged() {
return unpaged;
}
public boolean isPaged() {
return paged;
}
public int getPageNumber() {
return pageNumber;
}
public int getPageSize() {
return pageSize;
}
public long getOffset() {
return offset;
}
public Sort getSort() {
return sort;
}
}

View File

@@ -0,0 +1,7 @@
package com.example.quiz.data.model.enums;
public enum PariStatut {
EN_ATTENTE,
PERDANT,
VALIDEE
}

View File

@@ -0,0 +1,23 @@
package com.example.quiz.data.model.enums;
import java.io.Serializable;
public class Sort implements Serializable {
private boolean unsorted;
private boolean sorted;
private boolean empty;
public boolean isUnsorted() {
return unsorted;
}
public boolean isSorted() {
return sorted;
}
public boolean isEmpty() {
return empty;
}
}

View File

@@ -0,0 +1,71 @@
package com.example.quiz.data.remote;
import android.util.Log;
import androidx.annotation.NonNull;
import java.util.concurrent.TimeUnit;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import dagger.hilt.InstallIn;
import dagger.hilt.components.SingletonComponent;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
@Module
@InstallIn(SingletonComponent.class)
public class ApiClient {
private static final String BASE_URL = "https://alr.pmu.ml/api/";
@Provides
@Singleton
public AuthInterceptor provideInterceptor(TokenManager tokenManager){
return new AuthInterceptor(tokenManager);
}
@Provides
@Singleton
public HttpLoggingInterceptor provideLoggingInterceptor(){
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(@NonNull String s) {
Log.d("OkHttp", "log: "+s);
}
});
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return loggingInterceptor;
}
@Provides
@Singleton
public OkHttpClient provideOkHttpClient(HttpLoggingInterceptor loggingInterceptor, AuthInterceptor authInterceptor){
return new OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.addInterceptor(authInterceptor)
.connectTimeout(240, TimeUnit.SECONDS)
.readTimeout(240, TimeUnit.SECONDS)
.build();
}
@Provides
@Singleton
public Retrofit provideRetrofit(OkHttpClient okHttpClient){
return new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
@Provides
@Singleton
public ApiService provideApiService(Retrofit retrofit){
return retrofit.create(ApiService.class);
}
}

View File

@@ -0,0 +1,97 @@
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;
import retrofit2.http.Query;
public interface ApiService {
@GET("reunions/date/{date}")
Call<List<Reunion>> getReunions(@Path("date") String date);
@GET("courses")
Call<PagedModel<Course>> getCourses(@Query("reunionDate") String reunionDate, @Query("statut") String statut);
@POST("paris")
Call<ParisResponse> createPari(@Body Pari pari);
@POST("auth/agent/login")
Call<LoginResponse> login(@Body LoginPayload loginPayload);
@GET("paris/agent/{agentId}/today")
Call<List<ParisResponse>> derniersParis(@Path("agentId") String agentId);
@PATCH("paris/numero/{numeroTicket}/cancel")
Call<ParisResponse> annulerPari(@Path("numeroTicket") String numeroTicket);
@PATCH("paris/numero/{numeroTicket}/rembourser")
Call<ParisResponse> rembourserPari(@Path("numeroTicket") String numeroTicket);
@PATCH("paris/numero/{numeroTicket}/pay")
Call<ParisResponse> payerPari(@Path("numeroTicket") String numeroTicket);
@GET("paris/numero/{numeroTicket}")
Call<ParisResponse> getPariByNumero(@Path("numeroTicket") String numeroTicket);
@GET("paris/agent/{agentId}/solde/course/{courseId}")
Call<SoldeResponse> getSoldeByCourse(@Path("agentId") String createdBy, @Path("courseId") String courseId);
@GET("paris/agent/{agentId}/solde")
Call<SoldeResponse> getSoldeByDay(@Path("agentId") String agentId, @Query("date") String day);
@POST("terminaux")
Call<TpeResponse> createTpe(@Body Tpe tpe);
@GET("terminaux/{id}")
Call<TpeResponse> getTpeById(@Path("id") String id);
@GET("points-de-vente")
Call<PagedModel<PointDeVente>> getPointsDeVente(@Query("nom") String nom);
@GET("points-de-vente/{id}")
Call<PointDeVente> getPointDeVenteById(@Path("id") String id);
@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,35 @@
package com.example.quiz.data.remote;
import androidx.annotation.NonNull;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class AuthInterceptor implements Interceptor {
private final TokenManager tokenManager;
public AuthInterceptor(TokenManager tokenManager) {
this.tokenManager = tokenManager;
}
@NonNull
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
String token = tokenManager.getToken();
if (token != null) {
Request newRequest = originalRequest.newBuilder()
.addHeader("Authorization", "Bearer " + token)
.build();
return chain.proceed(newRequest);
}
return chain.proceed(originalRequest);
}
}

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

@@ -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://alr.pmu.ml/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

@@ -0,0 +1,30 @@
package com.example.quiz.data.remote;
import android.content.Context;
import android.content.SharedPreferences;
import javax.inject.Inject;
import dagger.hilt.android.qualifiers.ApplicationContext;
public class TokenManager {
private static final String PREF_NAME = "auth_pref";
private static final String KEY_TOKEN = "auth_token";
private SharedPreferences sharedPreferences;
@Inject
public TokenManager(@ApplicationContext Context context) {
this.sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
}
public void saveToken(String token){
sharedPreferences.edit().putString(KEY_TOKEN, token).apply();
}
public String getToken(){
return sharedPreferences.getString(KEY_TOKEN, null);
}
public void clearToken(){
sharedPreferences.edit().remove(KEY_TOKEN).apply();
}
}

View File

@@ -0,0 +1,166 @@
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.ResponseError;
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 com.google.gson.Gson;
import java.io.IOException;
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 {
try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveAgents.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@Override
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 {
try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveAgent.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@Override
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 {
try{
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveAvailableBets.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){
liveAvailableBets.postValue(Result.error(e.getMessage()));
}
}
}
@Override
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 {
try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveSetAccess.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@Override
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 {
try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveSetRestrictions.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void onFailure(@NonNull Call<Void> call, @NonNull Throwable throwable) {
liveSetRestrictions.postValue(Result.error(throwable.getMessage()));
}
});
return liveSetRestrictions;
}
}

View File

@@ -1,46 +0,0 @@
package com.example.quiz.data.repository;
import com.example.quiz.data.BetsBank;
import com.example.quiz.data.model.Bet;
import com.example.quiz.data.model.Horse;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class BetRepository {
private BetsBank betsBank;
@Inject
public BetRepository(BetsBank betsBank){
this.betsBank = betsBank;
}
public BetRepository(){
this.betsBank = BetsBank.getInstance();
}
public List<Bet> getAllBets(){
return betsBank.getBet();
}
public Bet getBetById(int id){
return betsBank.getBet().get(id);
}
public List<Horse> getHorsesById(int id){
return getBetById(id).getHorses();
}
public BetRepository getInstance(){
return new BetRepository();
}
public String getBetNameById(int id){
return getBetById(id).getName();
}
}

View File

@@ -0,0 +1,57 @@
package com.example.quiz.data.repository;
import android.util.Log;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.PagedModel;
import com.example.quiz.data.model.ResponseError;
import com.example.quiz.data.remote.ApiService;
import com.example.quiz.utils.Result;
import com.google.gson.Gson;
import javax.inject.Inject;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class CourseRepository {
private ApiService apiService;
private final Course.Statut OPENED_STATUT = Course.Statut.OUVERT;
@Inject
public CourseRepository(ApiService apiService) {
this.apiService = apiService;
}
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,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()));
}else{
try{
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveCourses.postValue(Result.error(errorResponse.getMessage()));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@Override
public void onFailure(Call<PagedModel<Course>> call, Throwable throwable) {
liveCourses.postValue(Result.error(throwable.getMessage()));
}
});
return liveCourses;
}
}

View File

@@ -0,0 +1,94 @@
package com.example.quiz.data.repository;
import android.util.Log;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.example.quiz.data.model.ResponseError;
import com.example.quiz.data.model.dtos.auth.ChangePin;
import com.example.quiz.data.model.dtos.auth.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;
import com.google.gson.Gson;
import java.io.IOException;
import javax.inject.Inject;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class LoginRepository {
private ApiService apiService;
private TokenManager tokenManager;
@Inject
public LoginRepository(ApiService apiService, TokenManager tokenManager) {
this.tokenManager = tokenManager;
this.apiService = apiService;
}
public LiveData<Result<LoginResponse>> login(LoginPayload loginPayload){
MutableLiveData<Result<LoginResponse>> liveLogin = new MutableLiveData<Result<LoginResponse>>();
liveLogin.setValue(Result.loading());
apiService.login(loginPayload).enqueue(new Callback<LoginResponse>() {
@Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
if(response.isSuccessful()){
liveLogin.postValue(Result.success(response.body()));
tokenManager.saveToken(response.body().getToken());
}else{
try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveLogin.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void onFailure(Call<LoginResponse> call, Throwable throwable) {
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 {
try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
liveUser.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void onFailure(Call<User> call, Throwable throwable) {
liveUser.postValue(Result.error(throwable.getMessage()));
}
});
return liveUser;
}
}

View File

@@ -0,0 +1,58 @@
package com.example.quiz.data.repository;
import android.util.Log;
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.model.ResponseError;
import com.example.quiz.data.remote.ApiService;
import com.example.quiz.data.remote.TokenManager;
import com.example.quiz.utils.Result;
import com.google.gson.Gson;
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{
try{
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
livePariMise.postValue(Result.error(errorResponse.getMessage()));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@Override
public void onFailure(Call<List<MiseInitiale>> call, Throwable throwable) {
livePariMise.postValue(Result.error(throwable.getMessage()));
}
});
return livePariMise;
}
}

View File

@@ -0,0 +1,263 @@
package com.example.quiz.data.repository;
import android.util.Log;
import android.widget.Toast;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.example.quiz.data.model.Pari;
import com.example.quiz.data.model.ParisResponse;
import com.example.quiz.data.model.ResponseError;
import com.example.quiz.data.model.dtos.paris.CancelParisPaylaod;
import com.example.quiz.data.model.dtos.paris.SoldeResponse;
import com.example.quiz.data.remote.ApiService;
import com.example.quiz.utils.Result;
import com.google.gson.Gson;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class PariRepository {
private ApiService apiService;
@Inject
public PariRepository(ApiService apiService) {
this.apiService = apiService;
}
public LiveData<Result<ParisResponse>> createPari(Pari pari) {
MutableLiveData<Result<ParisResponse>> pariResponse = new MutableLiveData<>();
pariResponse.setValue(Result.loading());
apiService.createPari(pari).enqueue(new Callback<ParisResponse>() {
@Override
public void onResponse(Call<ParisResponse> call, Response<ParisResponse> response) {
if (response.isSuccessful() && response.body() != null) {
pariResponse.postValue(Result.success(response.body()));
} else {
// On récupère l'erreur exacte envoyée par le backend
try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
pariResponse.postValue(Result.error(errorResponse.getMessage()));
} catch (Exception e) {
pariResponse.postValue(Result.error("Erreur serveur"));
}
}
}
@Override
public void onFailure(Call<ParisResponse> call, Throwable t) {
pariResponse.postValue(Result.error(t.getMessage()));
}
});
return pariResponse;
}
public LiveData<Result<List<ParisResponse>>> derniersParis(String agentId){
MutableLiveData<Result<List<ParisResponse>>> derniersParis = new MutableLiveData<>();
derniersParis.setValue(Result.loading());
apiService.derniersParis(agentId).enqueue(new Callback<List<ParisResponse>>() {
@Override
public void onResponse(Call<List<ParisResponse>> call, Response<List<ParisResponse>> response) {
if(response.isSuccessful() && response.body() != null){
derniersParis.postValue(Result.success(response.body()));
}else{
try{
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
derniersParis.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){
derniersParis.postValue(Result.error(e.getMessage()));
}
}
}
@Override
public void onFailure(Call<List<ParisResponse>> call, Throwable throwable) {
derniersParis.postValue(Result.error(throwable.getMessage()));
}
});
return derniersParis;
}
public LiveData<Result<ParisResponse>> payTicket(String numeroTicket){
MutableLiveData<Result<ParisResponse>> pariResponse = new MutableLiveData<>();
pariResponse.setValue(Result.loading());
apiService.payerPari(numeroTicket).enqueue(new Callback<ParisResponse>(){
@Override
public void onResponse(Call<ParisResponse> call, Response<ParisResponse> response) {
if(response.isSuccessful()){
pariResponse.postValue(Result.success(response.body()));
}else{
try{
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
pariResponse.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){
pariResponse.postValue(Result.error(e.getMessage()));
}
}
};
@Override
public void onFailure(Call<ParisResponse> call, Throwable throwable) {
pariResponse.postValue(Result.error(throwable.getMessage()));
}
});
return pariResponse;
}
public LiveData<Result<ParisResponse>> rembourserTicket(String numeroTicket){
MutableLiveData<Result<ParisResponse>> pariResponse = new MutableLiveData<>();
pariResponse.setValue(Result.loading());
apiService.rembourserPari(numeroTicket).enqueue(new Callback<ParisResponse>(){
@Override
public void onResponse(Call<ParisResponse> call, Response<ParisResponse> response) {
if(response.isSuccessful()){
pariResponse.postValue(Result.success(response.body()));
}else{
try{
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
pariResponse.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){
pariResponse.postValue(Result.error(e.getMessage()));
}
}
}
@Override
public void onFailure(Call<ParisResponse> call, Throwable throwable) {
pariResponse.postValue(Result.error(throwable.getMessage()));
}
});
return pariResponse;
}
public LiveData<Result<ParisResponse>> annulerPari(String numeroTicket){
MutableLiveData<Result<ParisResponse>> pariResponse = new MutableLiveData<>();
pariResponse.setValue(Result.loading());
apiService.annulerPari(numeroTicket).enqueue(new Callback<ParisResponse>(){
@Override
public void onResponse(Call<ParisResponse> call, Response<ParisResponse> response) {
if(response.isSuccessful()){
pariResponse.postValue(Result.success(response.body()));
}else{
try{
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
pariResponse.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){
pariResponse.postValue(Result.error(e.getMessage()));
}
}
}
@Override
public void onFailure(Call<ParisResponse> call, Throwable throwable) {
pariResponse.postValue(Result.error(throwable.getMessage()));
}
});
return pariResponse;
}
public LiveData<Result<SoldeResponse>> getSoldeByCourse(String agentId, String courseId){
MutableLiveData<Result<SoldeResponse>> solde = new MutableLiveData<>();
solde.setValue(Result.loading());
apiService.getSoldeByCourse(agentId, courseId).enqueue(new Callback<SoldeResponse>() {
@Override
public void onResponse(Call<SoldeResponse> call, Response<SoldeResponse> response) {
if(response.isSuccessful()){
solde.postValue(Result.success(response.body()));
}else{
try{
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
solde.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){
solde.postValue(Result.error(e.getMessage()));
}
}
}
@Override
public void onFailure(Call<SoldeResponse> call, Throwable throwable) {
solde.postValue(Result.error(throwable.getMessage()));
}
});
return solde;
}
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<SoldeResponse>() {
@Override
public void onResponse(Call<SoldeResponse> call, Response<SoldeResponse> response) {
if(response.isSuccessful()){
solde.postValue(Result.success(response.body()));
}else{
try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
solde.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){
solde.postValue(Result.error(e.getMessage()));
}
}
}
@Override
public void onFailure(Call<SoldeResponse> call, Throwable throwable) {
solde.postValue(Result.error(throwable.getMessage()));
}
});
return solde;
}
public LiveData<Result<ParisResponse>> getPariByNumero(String numeroTicket) {
MutableLiveData<Result<ParisResponse>> pari = new MutableLiveData<>();
pari.setValue(Result.loading());
apiService.getPariByNumero(numeroTicket).enqueue(new Callback<ParisResponse>() {
@Override
public void onResponse(Call<ParisResponse> call, Response<ParisResponse> response) {
if (response.isSuccessful()) {
pari.postValue(Result.success(response.body()));
}else{
try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
pari.postValue(Result.error(errorResponse.getMessage()));
}catch (Exception e){
pari.postValue(Result.error(e.getMessage()));
}
}
}
@Override
public void onFailure(Call<ParisResponse> call, Throwable throwable) {
pari.postValue(Result.error(throwable.getMessage()));
}
});
return pari;
}
}

View File

@@ -0,0 +1,94 @@
package com.example.quiz.data.repository;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.example.quiz.data.model.PagedModel;
import com.example.quiz.data.model.PointDeVente;
import com.example.quiz.data.model.ResponseError;
import com.example.quiz.data.remote.ApiService;
import com.example.quiz.utils.Result;
import com.google.gson.Gson;
import java.io.IOException;
import javax.inject.Inject;
import retrofit2.*;
public class PointDeVenteRepository {
private ApiService apiService;
@Inject
public PointDeVenteRepository(ApiService apiService) {
this.apiService = apiService;
}
public LiveData<Result<PagedModel<PointDeVente>>> getPointsDeVente(String nom) {
MutableLiveData<Result<PagedModel<PointDeVente>>> result = new MutableLiveData<>();
result.setValue(Result.loading());
apiService.getPointsDeVente(nom)
.clone()
.enqueue(new Callback<PagedModel<PointDeVente>>() {
@Override
public void onResponse(Call<PagedModel<PointDeVente>> call,
Response<PagedModel<PointDeVente>> response) {
if (response.isSuccessful() && response.body() != null) {
result.postValue(Result.success(response.body()));
} else {
try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
result.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void onFailure(Call<PagedModel<PointDeVente>> call, Throwable t) {
result.postValue(Result.error(
t.getMessage() != null ? t.getMessage() : "Erreur réseau"
));
}
});
return result;
}
public LiveData<Result<PointDeVente>> getPointDeVenteById(String id) {
MutableLiveData<Result<PointDeVente>> result = new MutableLiveData<>();
result.setValue(Result.loading());
apiService.getPointDeVenteById(id).enqueue(new Callback<PointDeVente>() {
@Override
public void onResponse(Call<PointDeVente> call, Response<PointDeVente> response) {
if(response.isSuccessful()){
result.postValue(Result.success(response.body()));
}else{
try {
String error = response.errorBody().string();
Gson gson = new Gson();
ResponseError errorResponse = gson.fromJson(error, ResponseError.class);
result.postValue(Result.error(errorResponse.getMessage()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void onFailure(Call<PointDeVente> call, Throwable throwable) {
result.postValue(Result.error(throwable.getMessage()));
}
});
return result;
}
}

View File

@@ -1,31 +0,0 @@
package com.example.quiz.data.repository;
import com.example.quiz.data.QuestionsBank;
import com.example.quiz.data.model.Question;
import java.util.List;
import java.util.Map;
public class QuestionRepository {
private QuestionsBank questionsBank;
public QuestionRepository(){
this.questionsBank = QuestionsBank.getInstance();
}
public List<Question> getQuestions(){
return questionsBank.getQuestions();
}
public Object updateQuestionById(int id, Question question){
Question myQuestion = questionsBank.getQuestions().get(id);
if(question == null) return Map.of("error", "Cette question n'existe pas!");
myQuestion.setQuestion(question.getQuestion()!=null?question.getQuestion():myQuestion.getQuestion());
myQuestion.setAnswers(!question.getAnswers().isEmpty()?question.getAnswers():myQuestion.getAnswers());
myQuestion.setIndexAnswer(question.getIndexAnswer() > 3?question.getIndexAnswer():myQuestion.getIndexAnswer());
return Map.of("success", true);
}
public QuestionRepository getInstance(){
return new QuestionRepository();
}
}

View File

@@ -0,0 +1,49 @@
package com.example.quiz.data.repository;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.example.quiz.data.model.Reunion;
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 ReunionRepository {
private ApiService apiService;
@Inject
public ReunionRepository(ApiService apiService) {
this.apiService = apiService;
}
public LiveData<Result<List<Reunion>>> getReunions(String date){
MutableLiveData<Result<List<Reunion>>> liveReunionsData = new MutableLiveData<>();
liveReunionsData.setValue(Result.loading());
apiService.getReunions(date).enqueue(new Callback<List<Reunion>>() {
@Override
public void onResponse(Call<List<Reunion>> call, Response<List<Reunion>> response) {
if(response.isSuccessful()){
liveReunionsData.postValue(Result.success(response.body()));
}else{
liveReunionsData.postValue(Result.error(response.message()));
}
}
@Override
public void onFailure(Call<List<Reunion>> call, Throwable throwable) {
liveReunionsData.postValue(Result.error(throwable.getMessage()));
}
});
return liveReunionsData;
}
}

View File

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

View File

@@ -0,0 +1,29 @@
package com.example.quiz.data.repository.module;
import com.example.quiz.data.remote.ApiService;
import com.example.quiz.data.repository.CourseRepository;
import com.example.quiz.data.repository.ReunionRepository;
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 RepositoryModule {
@Provides
@Singleton
public ReunionRepository provideReunionRepository(ApiService apiService){
return new ReunionRepository(apiService);
}
@Provides
@Singleton
public CourseRepository provideCourseRepository(ApiService apiService){
return new CourseRepository(apiService);
}
}

View File

@@ -1,38 +0,0 @@
package com.example.quiz.injection;
import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import com.example.quiz.data.repository.QuestionRepository;
import com.example.quiz.viewModel.QuestionViewModel;
public class QuestionViewModelFactory implements ViewModelProvider.Factory {
private QuestionRepository questionRepository;
private static QuestionViewModelFactory factory;
public static QuestionViewModelFactory getInstance(){
if(factory == null){
synchronized (QuestionViewModel.class){
if(factory == null){
factory = new QuestionViewModelFactory();
}
}
}
return factory;
}
private QuestionViewModelFactory(){
this.questionRepository = new QuestionRepository();
}
@Override
@NonNull
public <T extends ViewModel> T create(@NonNull Class<T> modelClass){
if(modelClass.isAssignableFrom(QuestionViewModel.class)){
return (T) new QuestionViewModel(questionRepository);
}
throw new IllegalArgumentException("Unknown ViewModel class");
}
}

View File

@@ -0,0 +1,181 @@
package com.example.quiz.utils;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelStoreOwner;
import com.example.quiz.R;
import com.example.quiz.data.model.dtos.auth.LoginPayload;
import com.example.quiz.data.model.dtos.auth.LoginResponse;
import com.example.quiz.data.remote.TokenManager;
import com.example.quiz.viewModel.LoginViewModel;
import com.example.quiz.viewModel.LogsViewModel;
import javax.inject.Inject;
public class AuthNavigator {
private final Context context;
private FragmentManager fragmentManager;
private final SessionManager sessionManager;
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,
LifecycleOwner lifecycleOwner) {
this.viewModel = viewModel;
this.logsViewModel = logsViewModel;
this.prefsHelper = SharedPrefsHelper.getInstance(context);
this.fragmentManager = fragmentManager;
this.context = context;
dialog = new Dialog(context);
this.sessionManager = sessionManager;
this.lifecycleOwner = lifecycleOwner;
}
public void navigate(Fragment destinationFragment) {
if(destinationFragment== null){
return;
}
if (sessionManager.isExpired()) {
if(!dialogIsShowing()){
showPinDialog(() -> {
sessionManager.updateLastExpiredDate();
fragmentManager.beginTransaction()
.replace(R.id.nav_host_fragment_content_main, destinationFragment)
.addToBackStack(null)
.commit();
});
}
} else {
fragmentManager.beginTransaction()
.replace(R.id.nav_host_fragment_content_main, destinationFragment)
.addToBackStack(null)
.commit();
}
}
public void showPinDialog(Runnable onSuccess) {
View view = LayoutInflater.from(context).inflate(R.layout.pin_view, null);
dialog.setContentView(view);
dialog.setCancelable(true);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
view.findViewById(R.id.cancel).setOnClickListener(v -> dialog.dismiss());
view.findViewById(R.id.pin_validate)
.setOnClickListener(v -> {
TextView code = view.findViewById(R.id.code);
TextView pin = view.findViewById(R.id.pin);
if(code.getText().toString().isEmpty()){
pin.setError("Entrez le code!");
return;
}
if(pin.getText().toString().isEmpty()){
pin.setError("Entrez le pin!");
return;
}
if(pin.getText().toString().length() < 4){
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, new Observer<Result<LoginResponse>>() {
@Override
public void onChanged(Result<LoginResponse> loginResponseResult) {
switch (loginResponseResult.status){
case LOADING:
view.findViewById(R.id.pin_validate).setEnabled(false);
view.findViewById(R.id.pin_validate).setAlpha(0.5f);
break;
case ERROR:
MessageDialog.showError(context, loginResponseResult.message);
view.findViewById(R.id.pin_validate).setEnabled(true);
view.findViewById(R.id.pin_validate).setAlpha(1f);
break;
case SUCCESS:
loginSuccess(loginResponseResult.data);
logsViewModel.insertLog(prefsHelper.get("id"), "LOGIN","Authentification sur l'appareil", System.currentTimeMillis());
sessionManager.updateLastExpiredDate();
dialog.dismiss();
view.findViewById(R.id.pin_validate).setEnabled(true);
view.findViewById(R.id.pin_validate).setAlpha(1f);
onSuccess.run();
break;
}
}
});
});
dialog.show();
}
public boolean dialogIsShowing(){
return dialog.isShowing();
}
public boolean isSessionExpired(){
return sessionManager.isExpired();
}
public void updatedLastExpiredDate(){
sessionManager.updateLastExpiredDate();
}
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);
}
public void logOut (){
prefsHelper.save("id", null);
prefsHelper.save("firstName", null);
prefsHelper.save("lastName", null);
prefsHelper.save("profile", null);
prefsHelper.save("code", null);
prefsHelper.save("isSupAgent", null);
sessionManager.setToExpire();
}
}

Some files were not shown because too many files have changed in this diff Show More