Skip to content
Snippets Groups Projects
Commit fb8532da authored by Cedric LHOUSSAINE's avatar Cedric LHOUSSAINE
Browse files

Initial commit

parents
Branches
No related tags found
No related merge requests found
Showing
with 728 additions and 0 deletions
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
# Default ignored files
/shelf/
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<value>
<entry key="app">
<State />
</entry>
</value>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
\ No newline at end of file
README.md 0 → 100644
Ce contrôle TP est d'une durée de 2h. L’usage des documents papier, d'internet et des précédents TP sont
autorisés. **Attention: toute modification de votre dépôt strictement postérieure à
l'heure limite de la remise sera ignorée**. Vous devez bien entendu soumettre un travail
original, dont vous êtes l'unique auteur.
---
# Description du projet
L'objectif de ce projet est de créer l'application (élémentaire) de gestion de tâches appelée `Super Tâches`.
Une tâche comprend:
- un nom (c'est-à-dire une description courte);
- une description longue;
- une catégorie;
- une date d'échéance;
- un status (`AFAIRE` ou `FAIT`);
- une priorité (`FAIBLE`, `MOYENNE` ou `HAUTE`).
L'application finale sera composée de deux activités:
- une activité d'accueil comprenant deux boutons permettant, respectivement, d'accèder à la liste des tâches et de quitter l'application; cette activité affiche également le nombre de tâches "à faire" et de tâches "urgentes";
![Activité 1](./figs/activite1_small.png)
- une activité qui liste les tâches et permet de les (dé)cocher afin de les basculer entre les status `FAIT` et à `AFAIRE`.
![Activité 2](./figs/activite2_small.png)
# Déroulement du contrôle
## Mise en place
Vous venez de `fork` ce dépôt qui contient:
- Ce sujet de contrôle TP
- L'ensemble des sources et ressources dont vous aurez besoin pour ce contrôle.
Vous n'arriverez peut-être pas au bout de ce contrôle volumineux. Pas de panique! Le barème sera sur plus de 20 points.
Un jeu d'essai est préchargé à partir du fichier json (présent comme une ressource 'raw' de nom cand.json).
la commande
```{shell}
adb install ./demo.apk
```
exécutée depuis le volet 'Terminal' installe une version complète du programme sur votre android virtuel.
Restitution
Ajoutez votre enseignant comme développeur sur votre dépôt gitlab (que vous venez juste de fork)
Après chaque question (votre projet doit compiler et être fonctionnel), vous enregistrerez l'état de votre projet.
## Rappel des commandes:
```{shell}
git commit -am 'Question X'
git tag Qx
git push --tag # peut être éventuellement différé en fin de tp
```
## Rappels git
La commande:
```{shell}
git config --global credential.helper cache
```
vous évitera d'avoir à ressaisir vos identifiants/mot de passe à chaque fois.
Les commandes suivantes vous permettront de compléter une question déjà validée (par exemple la Qx):
```{shell}
git tag -d Qx
git commit -am 'Question X (complément)'
git tag Qx
git push --tag # peut être éventuellement différé en fin de tp
```
# Questions
## Q1 - Affichage dans le Logcat
Avant tout, vérifier que les informations sont bien extraites du fichier
`raw/des_taches`. Pour cela, afficher la liste des tâches et des catégories dans
le `Logcat` (en priorité `INFO`).
## Q2 - Page d'accueil
> Avant de passer à cette question, n'oubliez pas de `commit` la précédente.
Définir un layout pour la page d'accueil sur ce modèle:
![Q2](./figs/Q2_small.png)
avec un titre "Super Tâches" et deux boutons:
- "Mes tâches" permettant d'accéder à la liste des tâches, et
- "Quitter" permettant de quitter l'application.
_Pour l'instant on ne demande pas d'afficher les nombres de tâches "à faire" et urgentes_.
Modifiez le code de la classe `MainActivity` pour afficher ce layout à l'aide de `ViewBindings`.
## Q3 - Quitter l'application avec le bouton `Quitter`
> Avant de passer à cette question, n'oubliez pas de `commit` la précédente.
Implémenter l'action associée au bouton "Quitter". Cliquer sur ce bouton fermera donc l'activité (on ne cherchera pas à complétement quitter l'application. Retourner à l'écran d'accueil Android sera suffisant).
## Q4 - Affichage du nombre de tâches en cours et urgentes
> Avant de passer à cette question, n'oubliez pas de `commit` la précédente.
Ajouter, sous le bouton "Quitter", des champs texte qui affichent le nombre de tâches en cours (c'est-à-dire avec le status `AFAIRE`) et le nombre de tâches urgentes (c'est-à-dire de priorité `HAUTE`).
## Q5 - Accès à une 2ème activité avec le bouton `Mes tâches`
> Avant de passer à cette question, n'oubliez pas de `commit` la précédente.
Créer une nouvelle activité `TacheActivity` et son layout `activity_tache.xml` qui permettront (dans la question suivante) d'afficher la liste des tâches. Faites-en sorte que le bouton "Mes tâches" permette d'accèder à cette nouvelle activité (une page blanche pour l'instant).
## Q6 - Liste des tâches dans la 2ème activité
> Avant de passer à cette question, n'oubliez pas de `commit` la précédente.
Créer un layout pour l'affichage d'un item de la liste des tâches. Ce layout comprendra une case à cocher (`checkbox`) représentant le status de la tâche, ainsi que les autres informations sous forme textuelle à l'exception de la description longue. Dans un premier temps vous réaliserez un layout rudimentaire que vous pourrez améliorer en fin de contrôle si vous avez le temps. Programmez les classes `TacheViewHolder` et `TacheAdapter`, et modifiez le reste du code pour permettre l'affichage de la liste des tâches (pour l'instant on ne tient pas compte du comportement de la case à cocher).
## Q7 - Bascule `AFAIRE`/`FAIT` des tâches via la case à cocher
> Avant de passer à cette question, n'oubliez pas de `commit` la précédente.
Faites en sorte que lorsqu'on coche la `checkbox` d'une tâche le status de cette case bascule en `FAIT` (resp. `AFAIRE`) si la case était précédemment cochée (resp. décochée). Pour ce faire, vous pourrez utiliser la méthode `setOnCheckedChangeListener` pour passer le callback qui gère le clic sur la `checkbox`. Pour vérifier que votre implantation est correcte, après avoir coché une tâche, revenez sur la page d'accueil à l'aide du bouton `Back`, puis à nouveau sur la liste des tâches avec le bouton "Mes Tâches" et la tâche cochée devrait toujours l'être.
## Q8 - Mise-à-jour des statistiques
> Avant de passer à cette question, n'oubliez pas de `commit` la précédente.
Faites en sorte que, depuis l'activité d'affichage des tâches, le retour à l'activité d'acceuil mette à jour le nombre de liste à faire si celui-ci a changé.
\ No newline at end of file
/build
\ No newline at end of file
plugins {
id("com.android.application")
}
android {
namespace = "fr.iutlille.ctp2024"
compileSdk = 34
defaultConfig {
applicationId = "fr.iutlille.ctp2024"
minSdk = 27
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}
\ No newline at end of file
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
\ No newline at end of file
package fr.iutlille.ctp2024;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("fr.iutlille.ctp2024", appContext.getPackageName());
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.CTP2024"
tools:targetApi="31"
android:name=".TacheApplication">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
\ No newline at end of file
package fr.iutlille.ctp2024;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
\ No newline at end of file
package fr.iutlille.ctp2024;
public enum Priorite {
FAIBLE, MOYENNE, HAUTE
}
package fr.iutlille.ctp2024;
public enum Status {
AFAIRE, FAIT
}
package fr.iutlille.ctp2024;
import java.util.Date;
public class Tache {
private String nom;
private Date echeance;
private Status status = Status.AFAIRE;
private Priorite priorite = Priorite.FAIBLE;
private String categorie;
private String description;
public Tache(String nom, Date echeance, Priorite priorite, String categorie, String description) {
this.nom = nom;
this.echeance = echeance;
this.priorite = priorite;
this.categorie = categorie;
this.description = description;
}
public String getCategorie() {
return categorie;
}
public String getNom() {
return nom;
}
public Date getEcheance() {
return echeance;
}
public Status getStatus() {
return status;
}
public Priorite getPriorite() {
return priorite;
}
public String getDescription() {
return description;
}
public void setNom(String nom) {
this.nom = nom;
}
public void setEcheance(Date echeance) {
this.echeance = echeance;
}
public void setStatus(Status status) {
this.status = status;
}
public void setPriorite(Priorite priorite) {
this.priorite = priorite;
}
public void setCategorie(String categorie) {
this.categorie = categorie;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString(){
return "----------\nNom: " + nom + "\nÉchéance: " + echeance + "\nPriorité : " + priorite + "\nStatus : " + status + "\nCatégorie : " + categorie + "\nDescription : " + description + "\n";
}
}
package fr.iutlille.ctp2024;
import android.app.Application;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class TacheApplication extends Application {
public static final String LOG_TAG = "TASKS";
private final List<Tache> lesTaches = new ArrayList<Tache>();
private final Set<String> lesCategories = new HashSet<String>();
@Override public void onCreate() {
super.onCreate();
try {
initTaches();
} catch (JSONException e) {
Log.e(LOG_TAG, "Erreur de lecture du fichier des taches...");
e.printStackTrace();
}
}
public List<Tache> getTaches() {
return lesTaches;
}
public Set<String> getLesCategories() {
return lesCategories;
}
public void initTaches() throws JSONException {
StringBuilder text = getConfig() ;
JSONObject json = new JSONObject(text.toString());
JSONArray array = json.getJSONArray("tasks");
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
for (int i = 0 ; i < array.length(); i++) {
String category = array.getJSONObject(i).getString("category");
Priorite priority = Priorite.valueOf(array.getJSONObject(i).getString("priority"));
String description = array.getJSONObject(i).getString("description");
String short_description = array.getJSONObject(i).getString("short_description");
Date date;
try {
date = formatter.parse(array.getJSONObject(i).getString("due_date"));
} catch (ParseException e) {
throw new RuntimeException(e);
}
if (!lesCategories.contains(category)) lesCategories.add(category);
lesTaches.add(new Tache(short_description,date,priority,category,description));
}
}
private StringBuilder getConfig() {
StringBuilder text = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(this.getResources().openRawResource(R.raw.des_taches)));
try {
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append('\n');
}
br.close();
return text;
} catch (IOException e) {
e.printStackTrace();
}
return text;
}
}
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment