From 55912c0679670671859de3252fdca5d5939cbe89 Mon Sep 17 00:00:00 2001 From: Erwann PHILIPPE Date: Thu, 5 Feb 2026 15:30:42 +0100 Subject: [PATCH] S5 : menu et liste adapter interactive --- .idea/deploymentTargetSelector.xml | 27 ++- app/build.gradle | 3 +- ...ivityTest.java => CalculActivityTest.java} | 5 +- app/src/main/AndroidManifest.xml | 15 +- .../java/com/example/coach/api/HelperApi.java | 45 +++++ .../com/example/coach/api/ICallbackApi.java | 6 + .../com/example/coach/api/IRequestApi.java | 5 + .../com/example/coach/contract/IAllView.java | 5 + .../example/coach/contract/ICalculView.java | 2 +- .../example/coach/contract/IHistoView.java | 10 + .../java/com/example/coach/model/Profil.java | 5 +- .../coach/presenter/CalculPresenter.java | 58 +++--- .../coach/presenter/HistoPresenter.java | 74 ++++++++ .../example/coach/view/CalculActivity.java | 167 +++++++++++++++++ .../com/example/coach/view/HistoActivity.java | 74 ++++++++ .../example/coach/view/HistoListAdapter.java | 128 +++++++++++++ .../com/example/coach/view/MainActivity.java | 127 ++----------- app/src/main/res/drawable/historique.png | Bin 0 -> 21566 bytes app/src/main/res/drawable/suppr.png | Bin 0 -> 5315 bytes app/src/main/res/layout/activity_calcul.xml | 173 ++++++++++++++++++ app/src/main/res/layout/activity_histo.xml | 22 +++ app/src/main/res/layout/activity_main.xml | 156 +++------------- app/src/main/res/layout/layout_list_histo.xml | 57 ++++++ app/src/main/res/values-night/themes.xml | 2 +- app/src/main/res/values/themes.xml | 2 +- gradle/libs.versions.toml | 2 + 26 files changed, 889 insertions(+), 281 deletions(-) rename app/src/androidTest/java/com/example/coach/view/{MainActivityTest.java => CalculActivityTest.java} (90%) create mode 100644 app/src/main/java/com/example/coach/api/HelperApi.java create mode 100644 app/src/main/java/com/example/coach/api/ICallbackApi.java create mode 100644 app/src/main/java/com/example/coach/contract/IAllView.java create mode 100644 app/src/main/java/com/example/coach/contract/IHistoView.java create mode 100644 app/src/main/java/com/example/coach/presenter/HistoPresenter.java create mode 100644 app/src/main/java/com/example/coach/view/CalculActivity.java create mode 100644 app/src/main/java/com/example/coach/view/HistoActivity.java create mode 100644 app/src/main/java/com/example/coach/view/HistoListAdapter.java create mode 100644 app/src/main/res/drawable/historique.png create mode 100644 app/src/main/res/drawable/suppr.png create mode 100644 app/src/main/res/layout/activity_calcul.xml create mode 100644 app/src/main/res/layout/activity_histo.xml create mode 100644 app/src/main/res/layout/layout_list_histo.xml diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index 4ee0cbf..94ca3b7 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -3,8 +3,8 @@ - - diff --git a/app/build.gradle b/app/build.gradle index 5f4dffa..23c6f7d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ android { defaultConfig { applicationId "com.example.coach" - minSdk 16 + minSdk 21 targetSdk 36 versionCode 1 versionName "1.0" @@ -34,6 +34,7 @@ dependencies { implementation libs.material implementation libs.activity implementation libs.constraintlayout + implementation libs.recyclerview testImplementation libs.junit androidTestImplementation libs.ext.junit androidTestImplementation libs.espresso.core diff --git a/app/src/androidTest/java/com/example/coach/view/MainActivityTest.java b/app/src/androidTest/java/com/example/coach/view/CalculActivityTest.java similarity index 90% rename from app/src/androidTest/java/com/example/coach/view/MainActivityTest.java rename to app/src/androidTest/java/com/example/coach/view/CalculActivityTest.java index f832232..e00961b 100644 --- a/app/src/androidTest/java/com/example/coach/view/MainActivityTest.java +++ b/app/src/androidTest/java/com/example/coach/view/CalculActivityTest.java @@ -12,15 +12,14 @@ import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.action.ViewActions.typeText; import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard; import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.ViewMatchers.withText; import com.example.coach.R; @RunWith(AndroidJUnit4.class) -public class MainActivityTest { +public class CalculActivityTest { @Rule - public ActivityScenarioRule activityRule = new ActivityScenarioRule<>(MainActivity.class); + public ActivityScenarioRule activityRule = new ActivityScenarioRule<>(CalculActivity.class); @Test public void testCalculIMG(){ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3e8cf32..d72a35e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + + + android:exported="true" + android:launchMode="singleTop"> + - + \ No newline at end of file diff --git a/app/src/main/java/com/example/coach/api/HelperApi.java b/app/src/main/java/com/example/coach/api/HelperApi.java new file mode 100644 index 0000000..8985b28 --- /dev/null +++ b/app/src/main/java/com/example/coach/api/HelperApi.java @@ -0,0 +1,45 @@ +package com.example.coach.api; + +import android.util.Log; + +import com.example.coach.model.Profil; + +import java.util.List; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class HelperApi { + private static final IRequestApi api = CoachApi.getRetrofit().create(IRequestApi.class); + + public static IRequestApi getApi() + { + return api; + } + + public static void call(Call> call, ICallbackApi callback) + { + call.enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + Log.d("API", "code : " + response.body().getCode() + + " message : " + response.body().getMessage() + + " result : " + response.body().getResult() + ); + if (response.isSuccessful() && response.body() != null) { + callback.onSuccess(response.body().getResult()); + } else { + callback.onError(); + Log.e("API", "Erreur API: " + response.code()); + } + } + + @Override + public void onFailure(Call> call, Throwable throwable) { + callback.onError(); + Log.e("API", "Erreur API", throwable); + } + }); + } +} diff --git a/app/src/main/java/com/example/coach/api/ICallbackApi.java b/app/src/main/java/com/example/coach/api/ICallbackApi.java new file mode 100644 index 0000000..b9fa9bf --- /dev/null +++ b/app/src/main/java/com/example/coach/api/ICallbackApi.java @@ -0,0 +1,6 @@ +package com.example.coach.api; + +public interface ICallbackApi { + void onSuccess(T result); + void onError(); +} diff --git a/app/src/main/java/com/example/coach/api/IRequestApi.java b/app/src/main/java/com/example/coach/api/IRequestApi.java index 13967ee..0cbc9c6 100644 --- a/app/src/main/java/com/example/coach/api/IRequestApi.java +++ b/app/src/main/java/com/example/coach/api/IRequestApi.java @@ -5,10 +5,12 @@ import com.example.coach.model.Profil; import java.util.List; import retrofit2.Call; +import retrofit2.http.DELETE; import retrofit2.http.Field; import retrofit2.http.FormUrlEncoded; import retrofit2.http.GET; import retrofit2.http.POST; +import retrofit2.http.Path; public interface IRequestApi { @GET("profil") @@ -17,4 +19,7 @@ public interface IRequestApi { @FormUrlEncoded @POST("profil") Call> creerProfil(@Field("champs") String profilJson); + + @DELETE("profil/{champs}") + Call> supprProfil(@Path(value = "champs", encoded = true) String profilJson); } diff --git a/app/src/main/java/com/example/coach/contract/IAllView.java b/app/src/main/java/com/example/coach/contract/IAllView.java new file mode 100644 index 0000000..9bf7e20 --- /dev/null +++ b/app/src/main/java/com/example/coach/contract/IAllView.java @@ -0,0 +1,5 @@ +package com.example.coach.contract; + +public interface IAllView { + void afficherMessage(String message); +} diff --git a/app/src/main/java/com/example/coach/contract/ICalculView.java b/app/src/main/java/com/example/coach/contract/ICalculView.java index cb0d94b..e76e396 100644 --- a/app/src/main/java/com/example/coach/contract/ICalculView.java +++ b/app/src/main/java/com/example/coach/contract/ICalculView.java @@ -3,7 +3,7 @@ package com.example.coach.contract; /** * Contrat pour que le CalculPresenter puisse envoyer des infos à la vue */ -public interface ICalculView { +public interface ICalculView extends IAllView{ /** * Méthode permettant le transfert des résultats vers la vue * @param image nom du fichier du smiley diff --git a/app/src/main/java/com/example/coach/contract/IHistoView.java b/app/src/main/java/com/example/coach/contract/IHistoView.java new file mode 100644 index 0000000..6ce6a36 --- /dev/null +++ b/app/src/main/java/com/example/coach/contract/IHistoView.java @@ -0,0 +1,10 @@ +package com.example.coach.contract; + +import com.example.coach.model.Profil; + +import java.util.List; + +public interface IHistoView extends IAllView { + void afficherListe(List profils); + void transfertProfil(Profil profil); +} diff --git a/app/src/main/java/com/example/coach/model/Profil.java b/app/src/main/java/com/example/coach/model/Profil.java index 9729238..861c5ca 100644 --- a/app/src/main/java/com/example/coach/model/Profil.java +++ b/app/src/main/java/com/example/coach/model/Profil.java @@ -1,11 +1,12 @@ package com.example.coach.model; +import java.io.Serializable; import java.util.Date; /** * Classe métier contenant les informations d'un profil */ -public class Profil { +public class Profil implements Serializable { private static final int MIN_FEMME = 25; private static final int MAX_FEMME = 30; private static final int MIN_HOMME = 15; @@ -83,7 +84,7 @@ public class Profil { * @return Valeur de l'img */ public double getImg(){ - return this.img; + return calculImg(); } /** diff --git a/app/src/main/java/com/example/coach/presenter/CalculPresenter.java b/app/src/main/java/com/example/coach/presenter/CalculPresenter.java index 1a86538..608bc17 100644 --- a/app/src/main/java/com/example/coach/presenter/CalculPresenter.java +++ b/app/src/main/java/com/example/coach/presenter/CalculPresenter.java @@ -5,6 +5,8 @@ import android.util.Log; import androidx.annotation.NonNull; import com.example.coach.api.CoachApi; +import com.example.coach.api.HelperApi; +import com.example.coach.api.ICallbackApi; import com.example.coach.api.IRequestApi; import com.example.coach.api.ResponseApi; import com.example.coach.contract.ICalculView; @@ -43,53 +45,51 @@ public class CalculPresenter { public void creerProfil(Integer sexe, Integer poids, Integer taille, Integer age) { Profil profil = new Profil(poids, taille, age, sexe, new Date()); + vue.AfficherResultat(profil.getImage(), profil.getImg(), profil.getMessage(), profil.normal()); String profilJson = CoachApi.getGson().toJson(profil); - - IRequestApi api = CoachApi.getRetrofit().create(IRequestApi.class); - Call> call = api.creerProfil(profilJson); - - call.enqueue(new Callback>() { + HelperApi.call(HelperApi.getApi().creerProfil(profilJson), new ICallbackApi() { @Override - public void onResponse(Call> call, Response> response) { - Log.d("API", "code : " + response.body().getCode() + - " message : " + response.body().getMessage() + - " result : " + response.body().getResult() - ); - if(response.isSuccessful() && response.body().getResult() == 1){ - vue.AfficherResultat(profil.getImage(), profil.getImg(), profil.getMessage(), profil.normal()); + public void onSuccess(Integer result) { + if (result == 1) { + vue.afficherMessage("profil enregistré"); }else{ - Log.e("API", "Erreur API: " + response.code()); + vue.afficherMessage("échec enregistrement profil"); } } @Override - public void onFailure(Call> call, @NonNull Throwable throwable) { - Log.e("API", "Échec d'accès à l'api", throwable); + public void onError() { + vue.afficherMessage("échec enregistrement profil"); } }); } public void chargerDernierProfil() { - IRequestApi api = CoachApi.getRetrofit().create(IRequestApi.class); - Call>> call = api.getProfils(); - - call.enqueue(new Callback>>() { + IRequestApi api = HelperApi.getApi(); + HelperApi.call(api.getProfils(), new ICallbackApi>() { @Override - public void onResponse(Call>> call, Response>> response) { - List profils = response.body().getResult(); - if(profils != null && !profils.isEmpty()){ - Profil dernier = Collections.max( - profils, - (p1, p2) -> p1.getDateMesure().compareTo(p2.getDateMesure()) - ); - vue.remplirChamps(dernier.getPoids(), dernier.getTaille(), dernier.getAge(), dernier.getSexe()); + public void onSuccess(List result) { + if(result != null){ + List profils = result; + if (profils != null && !profils.isEmpty()) { + // récupérer le plus récent + Profil dernier = Collections.max(profils, + (p1, p2) -> p1.getDateMesure().compareTo(p2.getDateMesure()) + ); + vue.remplirChamps(dernier.getPoids(), dernier.getTaille(), + dernier.getAge(), dernier.getSexe()); + }else{ + vue.afficherMessage("échec récupération dernier profil"); + } + }else{ + vue.afficherMessage("échec récupération dernier profil"); } } @Override - public void onFailure(Call>> call, Throwable throwable) { - Log.e("API", "Échec d'accès à l'api", throwable); + public void onError() { + vue.afficherMessage("échec récupération dernier profil"); } }); } diff --git a/app/src/main/java/com/example/coach/presenter/HistoPresenter.java b/app/src/main/java/com/example/coach/presenter/HistoPresenter.java new file mode 100644 index 0000000..f4835a0 --- /dev/null +++ b/app/src/main/java/com/example/coach/presenter/HistoPresenter.java @@ -0,0 +1,74 @@ +package com.example.coach.presenter; + +import android.util.Log; + +import com.example.coach.api.CoachApi; +import com.example.coach.api.HelperApi; +import com.example.coach.api.ICallbackApi; +import com.example.coach.api.IRequestApi; +import com.example.coach.api.ResponseApi; +import com.example.coach.contract.IHistoView; +import com.example.coach.model.Profil; + +import java.util.Collections; +import java.util.List; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class HistoPresenter { + private IHistoView vue; + + public HistoPresenter(IHistoView vue) + { + this.vue = vue; + } + + public void chargerProfils() + { + HelperApi.call(HelperApi.getApi().getProfils(), new ICallbackApi>() { + @Override + public void onSuccess(List result) { + if(result != null){ + List profils = result; + Collections.sort(profils, (p1, p2) -> p2.getDateMesure().compareTo(p1.getDateMesure())); + vue.afficherListe(profils); + }else{ + vue.afficherMessage("échec récupération des derniers profils"); + } + } + + @Override + public void onError() { + vue.afficherMessage("échec récupération des derniers profils"); + } + }); + } + + public void supprProfil(Profil profil, ICallbackApi callback) + { + String profilJson = CoachApi.getGson().toJson(profil); + HelperApi.call(HelperApi.getApi().supprProfil(profilJson), new ICallbackApi() { + @Override + public void onSuccess(Integer result) { + if (result == 1) { + vue.afficherMessage("profil supprimé"); + callback.onSuccess(null); + }else{ + vue.afficherMessage("échec suppression profil"); + } + } + + @Override + public void onError() { + vue.afficherMessage("échec suppression profil"); + } + }); + } + + public void transfertProfil(Profil profil) + { + vue.transfertProfil(profil); + } +} diff --git a/app/src/main/java/com/example/coach/view/CalculActivity.java b/app/src/main/java/com/example/coach/view/CalculActivity.java new file mode 100644 index 0000000..f6f713f --- /dev/null +++ b/app/src/main/java/com/example/coach/view/CalculActivity.java @@ -0,0 +1,167 @@ +package com.example.coach.view; + +import android.graphics.Color; +import android.os.Bundle; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.RadioButton; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.activity.EdgeToEdge; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; + +import com.example.coach.R; +import com.example.coach.contract.ICalculView; +import com.example.coach.model.Profil; +import com.example.coach.presenter.CalculPresenter; + +/** + * Activity qui permet le calcul de l'img + */ +public class CalculActivity extends AppCompatActivity implements ICalculView { + + private EditText txtPoids; + private EditText txtTaille; + private EditText txtAge; + private RadioButton rdHomme; + private RadioButton rdFemme; + private TextView lblIMG; + private ImageView imgSmiley; + private Button btnCalc; + + private CalculPresenter presenter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EdgeToEdge.enable(this); + setContentView(R.layout.activity_calcul); + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { + Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); + v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); + return insets; + }); + init(); + } + + /** + * Méthode permettant l'affichage du résultat du calcul de l'img + * @param image nom du fichier drawable pour le smiley + * @param img valeur de l'img + * @param message message à afficher + * @param normal faux si l'img n'est pas normal, vrai dans le cas inverse + */ + @Override + public void AfficherResultat(String image, double img, String message, boolean normal) { + int iamgeId = getResources().getIdentifier(image, "drawable", getPackageName()); + String texte = String.format("%.01f", img) + " : IMG " + message; + + if(iamgeId == 0){ + imgSmiley.setImageResource(R.drawable.normal); + }else{ + imgSmiley.setImageResource(iamgeId); + } + lblIMG.setText(texte); + if(!normal){ + lblIMG.setTextColor(Color.RED); + }else{ + lblIMG.setTextColor(Color.GREEN); + } + } + + /** + * @param poids poids stocké + * @param taille taille stockée + * @param age âge stocké + * @param sexe sexe stocké + */ + @Override + public void remplirChamps(Integer poids, Integer taille, Integer age, Integer sexe) { + txtPoids.setText(poids.toString()); + txtTaille.setText(taille.toString()); + txtAge.setText(age.toString()); + + if(sexe == 1){ + rdHomme.setChecked(true); + }else{ + rdFemme.setChecked(true); + } + } + + /** + * Traitements à réaliser lors du lancement de l'application + */ + private void init() + { + chargeObjetsGraphiques(); + presenter = new CalculPresenter(this); + btnCalc.setOnClickListener(v -> btnCalcClic()); + recupProfil(); + } + + /** + * Récupère les objets graphiques + */ + private void chargeObjetsGraphiques() + { + txtPoids = (EditText) findViewById(R.id.txtPoids); + txtTaille = (EditText) findViewById(R.id.txtTaille); + txtAge = (EditText) findViewById(R.id.txtAge); + + rdHomme = (RadioButton) findViewById(R.id.rdHomme); + rdFemme = (RadioButton) findViewById(R.id.rdFemme); + + lblIMG = (TextView) findViewById(R.id.lblResultat); + + imgSmiley = (ImageView) findViewById(R.id.imgSmiley); + + btnCalc = (Button) findViewById(R.id.btnCalc); + } + + /** + * Traitements à réaliser lors du clic sur le bouton + */ + private void btnCalcClic() + { + int poids = 0, taille = 0, age = 0, sexe = 0; + + try { + poids = Integer.parseInt(txtPoids.getText().toString()); + taille = Integer.parseInt(txtTaille.getText().toString()); + age = Integer.parseInt(txtAge.getText().toString()); + }catch (Exception ignored){} + + if(rdHomme.isChecked()){ + sexe = 1; + } + + if(poids == 0 || taille == 0 || age == 0){ + Toast.makeText(this, "Veuillez remplir tous les champs", Toast.LENGTH_SHORT).show(); + }else{ + presenter.creerProfil(sexe, poids, taille, age); + } + } + + /** + * @param message + */ + @Override + public void afficherMessage(String message) { + Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); + } + + private void recupProfil() + { + Profil profil = (Profil) getIntent().getSerializableExtra("profil"); + if(profil != null){ + remplirChamps(profil.getPoids(), profil.getTaille(), profil.getAge(), profil.getSexe()); + }else{ + presenter.chargerDernierProfil(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/coach/view/HistoActivity.java b/app/src/main/java/com/example/coach/view/HistoActivity.java new file mode 100644 index 0000000..56df044 --- /dev/null +++ b/app/src/main/java/com/example/coach/view/HistoActivity.java @@ -0,0 +1,74 @@ +package com.example.coach.view; + +import android.content.Intent; +import android.os.Bundle; +import android.widget.Toast; + +import androidx.activity.EdgeToEdge; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.example.coach.R; +import com.example.coach.contract.IHistoView; +import com.example.coach.model.Profil; +import com.example.coach.presenter.HistoPresenter; + +import java.util.List; + +public class HistoActivity extends AppCompatActivity implements IHistoView { + HistoPresenter presenter; + + private void init() + { + presenter = new HistoPresenter(this); + presenter.chargerProfils(); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EdgeToEdge.enable(this); + setContentView(R.layout.activity_histo); + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { + Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); + v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); + init(); + return insets; + }); + } + + /** + * @param profils + */ + @Override + public void afficherListe(List profils) { + if(profils != null){ + RecyclerView lstHisto = (RecyclerView) findViewById(R.id.lstHisto); + HistoListAdapter adapter = new HistoListAdapter(profils, HistoActivity.this); + lstHisto.setAdapter(adapter); + lstHisto.setLayoutManager(new LinearLayoutManager(HistoActivity.this)); + } + } + + /** + * @param profil + */ + @Override + public void transfertProfil(Profil profil) { + Intent intent = new Intent(HistoActivity.this, CalculActivity.class); + intent.putExtra("profil", profil); + startActivity(intent); + } + + /** + * @param message + */ + @Override + public void afficherMessage(String message) { + Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/coach/view/HistoListAdapter.java b/app/src/main/java/com/example/coach/view/HistoListAdapter.java new file mode 100644 index 0000000..e2d1ca2 --- /dev/null +++ b/app/src/main/java/com/example/coach/view/HistoListAdapter.java @@ -0,0 +1,128 @@ +package com.example.coach.view; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.example.coach.R; +import com.example.coach.api.ICallbackApi; +import com.example.coach.contract.IHistoView; +import com.example.coach.model.Profil; +import com.example.coach.presenter.HistoPresenter; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +public class HistoListAdapter extends RecyclerView.Adapter { + + private List profils; + private IHistoView vue; + + /** + * Retourne une ligne de la liste + * @param parent The ViewGroup into which the new View will be added after it is bound to + * an adapter position. + * @param viewType The view type of the new View. + * @return + */ + @NonNull + @Override + public HistoListAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + Context parentContext = parent.getContext(); + LayoutInflater layout = LayoutInflater.from(parentContext); + View view = layout.inflate(R.layout.layout_list_histo, parent, false); + + return new HistoListAdapter.ViewHolder(view); + } + + /** + * Rempli une ligne + * @param holder The ViewHolder which should be updated to represent the contents of the + * item at the given position in the data set. + * @param position The position of the item within the adapter's data set. + */ + @Override + public void onBindViewHolder(@NonNull HistoListAdapter.ViewHolder holder, int position) { + Double img = profils.get(position).getImg(); + String img1desimal = String.format("%.01f", img); + holder.txtListIMG.setText(img1desimal); + + Date dateMesure = profils.get(position).getDateMesure(); + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss", Locale.getDefault()); + String dateFormatee = sdf.format(dateMesure); + holder.txtListDate.setText(dateFormatee); + } + + /** + * Compte le nombre de lignes + * @return int + */ + @Override + public int getItemCount() { + return profils.size(); + } + + public HistoListAdapter(List profils, IHistoView vue) + { + this.profils = profils; + this.vue = vue; + } + + public class ViewHolder extends RecyclerView.ViewHolder{ + final TextView txtListDate; + final TextView txtListIMG; + final ImageButton btnListSuppr; + + HistoPresenter presenter; + public ViewHolder(@NonNull View itemView) { + super(itemView); + + txtListDate = (TextView) itemView.findViewById(R.id.txtListDate); + txtListIMG = (TextView) itemView.findViewById(R.id.txtListIMG); + btnListSuppr = (ImageButton) itemView.findViewById(R.id.btnListSuppr); + init(); + } + + private void btnListSuppr_clic() + { + int position = getBindingAdapterPosition(); + presenter.supprProfil(profils.get(position), new ICallbackApi() { + @Override + public void onSuccess(Void result) { + profils.remove(position); + notifyItemRemoved(position); + } + + @Override + public void onError() { + + } + }); + } + + private void init() + { + btnListSuppr.setOnClickListener(v -> btnListSuppr_clic()); + txtListDate.setOnClickListener(v -> txtListDateOrImg_clic()); + txtListIMG.setOnClickListener(v -> txtListDateOrImg_clic()); + presenter = new HistoPresenter(vue); + + + } + + private void txtListDateOrImg_clic() + { + int position = getBindingAdapterPosition(); + presenter.transfertProfil(profils.get(position)); + } + } +} diff --git a/app/src/main/java/com/example/coach/view/MainActivity.java b/app/src/main/java/com/example/coach/view/MainActivity.java index 6227c8a..07fef40 100644 --- a/app/src/main/java/com/example/coach/view/MainActivity.java +++ b/app/src/main/java/com/example/coach/view/MainActivity.java @@ -1,13 +1,8 @@ package com.example.coach.view; -import android.graphics.Color; +import android.content.Intent; import android.os.Bundle; -import android.widget.Button; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.RadioButton; -import android.widget.TextView; -import android.widget.Toast; +import android.widget.ImageButton; import androidx.activity.EdgeToEdge; import androidx.appcompat.app.AppCompatActivity; @@ -16,24 +11,11 @@ import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; import com.example.coach.R; -import com.example.coach.contract.ICalculView; -import com.example.coach.presenter.CalculPresenter; -/** - * Activity qui permet le calcul de l'img - */ -public class MainActivity extends AppCompatActivity implements ICalculView { +public class MainActivity extends AppCompatActivity { - private EditText txtPoids; - private EditText txtTaille; - private EditText txtAge; - private RadioButton rdHomme; - private RadioButton rdFemme; - private TextView lblIMG; - private ImageView imgSmiley; - private Button btnCalc; - - private CalculPresenter presenter; + private ImageButton btnMonIMG; + private ImageButton btnMonHistorique; @Override protected void onCreate(Bundle savedInstanceState) { @@ -43,107 +25,32 @@ public class MainActivity extends AppCompatActivity implements ICalculView { ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); + init(); return insets; }); - init(); } - /** - * Méthode permettant l'affichage du résultat du calcul de l'img - * @param image nom du fichier drawable pour le smiley - * @param img valeur de l'img - * @param message message à afficher - * @param normal faux si l'img n'est pas normal, vrai dans le cas inverse - */ - @Override - public void AfficherResultat(String image, double img, String message, boolean normal) { - int iamgeId = getResources().getIdentifier(image, "drawable", getPackageName()); - String texte = String.format("%.01f", img) + " : IMG " + message; - - if(iamgeId == 0){ - imgSmiley.setImageResource(R.drawable.normal); - }else{ - imgSmiley.setImageResource(iamgeId); - } - lblIMG.setText(texte); - if(!normal){ - lblIMG.setTextColor(Color.RED); - }else{ - lblIMG.setTextColor(Color.GREEN); - } - } - - /** - * @param poids poids stocké - * @param taille taille stockée - * @param age âge stocké - * @param sexe sexe stocké - */ - @Override - public void remplirChamps(Integer poids, Integer taille, Integer age, Integer sexe) { - txtPoids.setText(poids.toString()); - txtTaille.setText(taille.toString()); - txtAge.setText(age.toString()); - - if(sexe == 1){ - rdHomme.setChecked(true); - }else{ - rdFemme.setChecked(false); - } - } - - /** - * Traitements à réaliser lors du lancement de l'application - */ private void init() { chargeObjetsGraphiques(); - presenter = new CalculPresenter(this); - btnCalc.setOnClickListener(v -> btnCalcClic()); - - presenter.chargerDernierProfil(); + creerMenu(); } - /** - * Récupère les objets graphiques - */ private void chargeObjetsGraphiques() { - txtPoids = (EditText) findViewById(R.id.txtPoids); - txtTaille = (EditText) findViewById(R.id.txtTaille); - txtAge = (EditText) findViewById(R.id.txtAge); - - rdHomme = (RadioButton) findViewById(R.id.rdHomme); - rdFemme = (RadioButton) findViewById(R.id.rdFemme); - - lblIMG = (TextView) findViewById(R.id.lblResultat); - - imgSmiley = (ImageView) findViewById(R.id.imgSmiley); - - btnCalc = (Button) findViewById(R.id.btnCalc); + btnMonIMG = (ImageButton) findViewById(R.id.btnMonIMG); + btnMonHistorique = (ImageButton) findViewById(R.id.btnMonHistorique); } - /** - * Traitements à réaliser lors du clic sur le bouton - */ - private void btnCalcClic() + private void ecouteMenu(Class classe) { - int poids = 0, taille = 0, age = 0, sexe = 0; + Intent intent = new Intent(MainActivity.this, classe); + startActivity(intent); + } - try { - poids = Integer.parseInt(txtPoids.getText().toString()); - taille = Integer.parseInt(txtTaille.getText().toString()); - age = Integer.parseInt(txtAge.getText().toString()); - }catch (Exception ignored){} - - if(rdHomme.isChecked()){ - sexe = 1; - } - - if(poids == 0 || taille == 0 || age == 0){ - Toast.makeText(this, "Veuillez remplir tous les champs", Toast.LENGTH_SHORT).show(); - }else{ - presenter.creerProfil(sexe, poids, taille, age); - } + private void creerMenu() + { + btnMonIMG.setOnClickListener(v -> ecouteMenu(CalculActivity.class)); + btnMonHistorique.setOnClickListener(v -> ecouteMenu(HistoActivity.class)); } } \ No newline at end of file diff --git a/app/src/main/res/drawable/historique.png b/app/src/main/res/drawable/historique.png new file mode 100644 index 0000000000000000000000000000000000000000..0ca73bea8a45f67f54ec5d20e12d7e65c77a5236 GIT binary patch literal 21566 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/suppr.png b/app/src/main/res/drawable/suppr.png new file mode 100644 index 0000000000000000000000000000000000000000..d6944126ef15ae118a19f431185e6e13d740df6b GIT binary patch literal 5315 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 V1d?Uzg2n&<002ovPDHLkV1lT-7AF7z literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/activity_calcul.xml b/app/src/main/res/layout/activity_calcul.xml new file mode 100644 index 0000000..d7663a3 --- /dev/null +++ b/app/src/main/res/layout/activity_calcul.xml @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +