From 555b621b618e4810324a2658d33315b05157e6be Mon Sep 17 00:00:00 2001 From: Joris Date: Fri, 23 Dec 2016 09:52:20 +0100 Subject: Add programs grouped by level --- src/main/scala/reading/Books.scala | 71 +++++++------ src/main/scala/reading/component/index/Books.scala | 4 + .../reading/component/index/FiltersMenu.scala | 111 ++++++++++++++++----- .../reading/component/index/style/Books.scala | 5 + src/main/scala/reading/models/Book.scala | 1 + src/main/scala/reading/models/Difficulty.scala | 6 +- src/main/scala/reading/models/Filter.scala | 10 ++ src/main/scala/reading/models/Level.scala | 33 ++++++ src/main/scala/reading/models/Program.scala | 70 +++++++++++++ 9 files changed, 250 insertions(+), 61 deletions(-) create mode 100644 src/main/scala/reading/models/Level.scala create mode 100644 src/main/scala/reading/models/Program.scala (limited to 'src/main') diff --git a/src/main/scala/reading/Books.scala b/src/main/scala/reading/Books.scala index 29c26d2..af23146 100644 --- a/src/main/scala/reading/Books.scala +++ b/src/main/scala/reading/Books.scala @@ -1,52 +1,61 @@ package reading -import reading.models.{Book, Period, Theme, Genre}, Period._, Theme._, Genre._ +import reading.models.{Book, Period, Theme, Genre, Program} +import Period._ +import Theme._ +import Genre._ +import Program._ object Books { def apply(): Seq[Book] = Seq( Book( - title = "Les Dix petits nègres", - author = "Agatha Christie", - period = Siecle20, - genres = Seq(Policier), - themes = Seq(Peur), - pages = 250 + title = "Les Dix petits nègres", + author = "Agatha Christie", + period = Siecle20, + genres = Seq(Policier), + themes = Seq(Peur), + program = Monstre, + pages = 250 ), Book( - title = "Le Joueur", - author = "Fiódor Dostoyevski", - period = Siecle19, - genres = Seq(), - themes = Seq(Peur), - pages = 170 + title = "Le Joueur", + author = "Fiódor Dostoyevski", + period = Siecle19, + genres = Seq(), + themes = Seq(Peur), + program = Heros, + pages = 170 ), Book( - title = "Voyage au bout de la nuit", - author = "Céline", - period = Siecle20, - genres = Seq(), - themes = Seq(Peur), - pages = 380 + title = "Voyage au bout de la nuit", + author = "Céline", + period = Siecle20, + genres = Seq(), + themes = Seq(Peur), + program = IndividuEtSociete, + pages = 380 ), Book( - title = "Le Petit Prince", - author = "Antoine de Saint Exupéry", - period = Siecle19, - genres = Seq(Policier), - themes = Seq(Amitie), - pages = 130 + title = "Le Petit Prince", + author = "Antoine de Saint Exupéry", + period = Siecle19, + genres = Seq(Policier), + themes = Seq(Amitie), + program = RecitAventure, + pages = 130 ), Book( - title = "Les Frères Karamazov", - author = "Fiódor Dostoyevski", - period = Siecle19, - genres = Seq(), - themes = Seq(Famille), - pages = 850 + title = "Les Frères Karamazov", + author = "Fiódor Dostoyevski", + period = Siecle19, + genres = Seq(), + themes = Seq(Famille), + program = Autrui, + pages = 850 ) ) } diff --git a/src/main/scala/reading/component/index/Books.scala b/src/main/scala/reading/component/index/Books.scala index 39c0e67..dacfe4e 100644 --- a/src/main/scala/reading/component/index/Books.scala +++ b/src/main/scala/reading/component/index/Books.scala @@ -35,6 +35,10 @@ object Books { BooksStyle.themes, s"thème: ${book.themes.mkString(", ")}" ), + div( + BooksStyle.program, + s"programme: ${book.program}" + ), div( BooksStyle.pages, s"${book.pages} pages" diff --git a/src/main/scala/reading/component/index/FiltersMenu.scala b/src/main/scala/reading/component/index/FiltersMenu.scala index 81220e3..02f591b 100644 --- a/src/main/scala/reading/component/index/FiltersMenu.scala +++ b/src/main/scala/reading/component/index/FiltersMenu.scala @@ -8,21 +8,31 @@ import scalacss.Defaults._ import scalacss.ScalatagsCss._ import reading.component.index.style.{FiltersMenu => FiltersMenuStyle} -import reading.models.{Book, Filter, Period, Genre, Theme, Difficulty} +import reading.models.{Book, Filter, Period, Genre, Theme, Program, Difficulty, FilterFactory} import reading.utils.{RxTag, RxAttr} object FiltersMenu { def apply(books: Rx[Seq[Book]], filters: Var[Seq[Filter]]): Frag = - div( - FiltersMenuStyle.render, - FiltersMenuStyle.groups, - group(books, filters, "Période", Period.values.map(Filter.apply(_))), - group(books, filters, "Genre", Genre.values.map(Filter.apply(_))), - group(books, filters, "Theme", Theme.values.map(Filter.apply(_))), - group(books, filters, "Difficulté", Difficulty.filters) - ) + RxTag { implicit context => + div( + FiltersMenuStyle.render, + FiltersMenuStyle.groups, + group(books, filters, "Période", Period.values.map(Filter.apply(_))), + group(books, filters, "Genre", Genre.values.map(Filter.apply(_))), + group(books, filters, "Theme", Theme.values.map(Filter.apply(_))), + multiGroup(books, filters, "Programme", Program.values, Program.level _), + group(books, filters, "Difficulté", Difficulty.filters) + ) + } - def group(books: Rx[Seq[Book]], filters: Var[Seq[Filter]], name: String, groupFilters: Seq[Filter]): Frag = { + def group( + books: Rx[Seq[Book]], + filters: Var[Seq[Filter]], + name: String, + groupFilters: Seq[Filter] + )( + implicit context: Ctx.Data + ): Frag = { val filtersWithCount = Rx { groupFilters .filter(filter => !Filter.contains(filters(), filter)) @@ -30,25 +40,72 @@ object FiltersMenu { .filter(_._2 > 0) } - RxTag { implicit context => - if(filtersWithCount().isEmpty) - span("") - else + if(filtersWithCount().isEmpty) + span("") + else + div( + FiltersMenuStyle.group, + div(FiltersMenuStyle.groupTitle, name), div( - FiltersMenuStyle.group, - - div(FiltersMenuStyle.groupTitle, name), - - div( - filtersWithCount().map { case (filter, count) => - button( - FiltersMenuStyle.filter, - RxAttr(onclick, Rx(() => filters() = filter +: filters())), - span(s"${filter.name} ($count)") - ) - } - ) + filtersWithCount().map { case (filter, count) => + button( + FiltersMenuStyle.filter, + RxAttr(onclick, Rx(() => filters() = filter +: filters())), + span(s"${filter.name} ($count)") + ) + } + ) + ) + } + + + + def multiGroup[A: FilterFactory, B: Ordering]( + books: Rx[Seq[Book]], + filters: Var[Seq[Filter]], + name: String, + groupFilters: Seq[A], + superGroup: A => B + )( + implicit context: Ctx.Data + ): Frag = + div( + FiltersMenuStyle.group, + div(FiltersMenuStyle.groupTitle, name), + groupFilters.groupBy(superGroup).toList.sortBy(_._1).map { case (superGroup, subGroupFilters) => + div( + superGroup.toString, + subGroup(books, filters, name, subGroupFilters.map(Filter(_))) ) + } + ) + + def subGroup( + books: Rx[Seq[Book]], + filters: Var[Seq[Filter]], + name: String, + groupFilters: Seq[Filter] + )( + implicit context: Ctx.Data + ): Frag = { + val filtersWithCount = Rx { + groupFilters + .filter(filter => !Filter.contains(filters(), filter)) + .map(filter => (filter, Book.filter(books(), filter +: filters()).length)) + .filter(_._2 > 0) } + + if(filtersWithCount().isEmpty) + span("") + else + div( + filtersWithCount().map { case (filter, count) => + button( + FiltersMenuStyle.filter, + RxAttr(onclick, Rx(() => filters() = filter +: filters())), + span(s"${filter.name} ($count)") + ) + } + ) } } diff --git a/src/main/scala/reading/component/index/style/Books.scala b/src/main/scala/reading/component/index/style/Books.scala index c023e66..69e1c55 100644 --- a/src/main/scala/reading/component/index/style/Books.scala +++ b/src/main/scala/reading/component/index/style/Books.scala @@ -41,6 +41,11 @@ object Books extends StyleSheet.Inline { marginBottom(10.px) ) + val program = style( + marginLeft(20.px), + marginBottom(10.px) + ) + val pages = style( marginLeft(20.px) ) diff --git a/src/main/scala/reading/models/Book.scala b/src/main/scala/reading/models/Book.scala index 7c4bf8a..ef9eb9b 100644 --- a/src/main/scala/reading/models/Book.scala +++ b/src/main/scala/reading/models/Book.scala @@ -6,6 +6,7 @@ case class Book ( period: Period, genres: Seq[Genre], themes: Seq[Theme], + program: Program, pages: Int ) extends Ordered[Book] { def compare(that: Book) = { diff --git a/src/main/scala/reading/models/Difficulty.scala b/src/main/scala/reading/models/Difficulty.scala index aade5f5..e20d7b2 100644 --- a/src/main/scala/reading/models/Difficulty.scala +++ b/src/main/scala/reading/models/Difficulty.scala @@ -6,17 +6,17 @@ object Difficulty { new Filter { def filter(book: Book): Boolean = book.pages < 200 val kind: FilterKind = DifficultyKind - def name: String = "facile" + val name: String = "facile" }, new Filter { def filter(book: Book): Boolean = book.pages >= 200 && book.pages < 400 val kind: FilterKind = DifficultyKind - def name: String = "moyen" + val name: String = "moyen" }, new Filter { def filter(book: Book): Boolean = book.pages > 400 val kind: FilterKind = DifficultyKind - def name: String = "difficile" + val name: String = "difficile" } ) } diff --git a/src/main/scala/reading/models/Filter.scala b/src/main/scala/reading/models/Filter.scala index 5e96cf9..a74a6f1 100644 --- a/src/main/scala/reading/models/Filter.scala +++ b/src/main/scala/reading/models/Filter.scala @@ -11,6 +11,7 @@ case object PeriodKind extends FilterKind case object ThemeKind extends FilterKind case object GenreKind extends FilterKind case object DifficultyKind extends FilterKind +case object ProgramKind extends FilterKind object Filter { def apply[T](in: T)(implicit filterFactory: FilterFactory[T]): Filter = @@ -54,4 +55,13 @@ object FilterFactory { val name: String = genre.toString() } } + + implicit object ProgramFilter extends FilterFactory[Program] { + def create(program: Program): Filter = + new Filter { + def filter(book: Book): Boolean = book.program == program + val kind: FilterKind = ProgramKind + val name: String = program.toString() + } + } } diff --git a/src/main/scala/reading/models/Level.scala b/src/main/scala/reading/models/Level.scala new file mode 100644 index 0000000..1f7e153 --- /dev/null +++ b/src/main/scala/reading/models/Level.scala @@ -0,0 +1,33 @@ +package reading.models + +import enumeratum._ + +sealed trait Level extends EnumEntry with Ordered[Level] { + import Level._ + + def compare(that: Level) = { + def toInt(level: Level): Int = level match { + case Sixieme => 6 + case Cinquieme => 5 + case Quatrieme => 4 + case Troisieme => 3 + } + toInt(that) - toInt(this) + } + + override def toString(): String = this match { + case Sixieme => "6ème" + case Cinquieme => "5ème" + case Quatrieme => "4ème" + case Troisieme => "3ème" + } +} + +object Level extends Enum[Level] { + val values = findValues + + case object Sixieme extends Level + case object Cinquieme extends Level + case object Quatrieme extends Level + case object Troisieme extends Level +} diff --git a/src/main/scala/reading/models/Program.scala b/src/main/scala/reading/models/Program.scala new file mode 100644 index 0000000..4603b03 --- /dev/null +++ b/src/main/scala/reading/models/Program.scala @@ -0,0 +1,70 @@ +package reading.models + +import enumeratum._ + +sealed trait Program extends EnumEntry { + import Program._ + + override def toString(): String = this match { + case Monstre => "Le monstre, aux limites de l'humain" + case RecitAventure => "Récits d'aventures" + case CreationPoetique => "Récit de création, création poétique" + case Resister => "Résister au plus fort : ruses, mensonges et masques" + + case VoyageEtAventure => "le voyage et l'aventure. Pourquoi aller vers l'inconnu ?" + case Autrui => "avec autrui : familles, amis, réseaux." + case UniversNouveaux => "imaginer des univers nouveaux." + case Heros => "héros, héroïnes et héroïsmes." + case HommeEtNature => "l'être humain est-il maître de la nature ?" + + case DireAmour => "Dire l'amour" + case IndividuEtSociete => "Individu et société : confrontations de valeur ?" + case FictionEtReel => "la fiction pour interroger le réel" + case Informer => "Informer, s'informer, déformer ?" + case Ville => "La ville, lieu de tous les possibles ?" + + case RaconterRepresenter => "Se raconter, se représenter" + case TraversSociete => "Dénoncer les travers de la société" + case VisionsPoetiques => "Visions poétiques du monde" + case AgirCite => "Agir dans la cité : individu et pouvoir" + case ProgresReveScientifique => "Progrès et rêves scientifiques" + } +} + +object Program extends Enum[Program] { + val values = findValues + + case object Monstre extends Program + case object RecitAventure extends Program + case object CreationPoetique extends Program + case object Resister extends Program + + case object VoyageEtAventure extends Program + case object Autrui extends Program + case object UniversNouveaux extends Program + case object Heros extends Program + case object HommeEtNature extends Program + + case object DireAmour extends Program + case object IndividuEtSociete extends Program + case object FictionEtReel extends Program + case object Informer extends Program + case object Ville extends Program + + case object RaconterRepresenter extends Program + case object TraversSociete extends Program + case object VisionsPoetiques extends Program + case object AgirCite extends Program + case object ProgresReveScientifique extends Program + + def level(program: Program): Level = { + import Level._ + + program match { + case Monstre | RecitAventure | CreationPoetique | Resister => Sixieme + case VoyageEtAventure | Autrui | UniversNouveaux | Heros | HommeEtNature => Cinquieme + case DireAmour | IndividuEtSociete | FictionEtReel | Informer | Ville => Quatrieme + case RaconterRepresenter | TraversSociete | VisionsPoetiques | AgirCite | ProgresReveScientifique => Troisieme + } + } +} -- cgit v1.2.3