[recipes] Introduce a segmented ingredients list



commit c127b9420949c0f56b43175e7dbe92fa46a40244
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Dec 20 20:02:14 2016 -0500

    Introduce a segmented ingredients list
    
    This makes it possible to have separate ingredient lists
    for, say, the dough and the frosting of a cake. There are
    multiple small visual fixups to the edit page here too,
    following a new mockup by Jakub.
    
    The text format for the ingredients list now looks like this:
    
    amount unit ingredient\tsegment\n

 src/gr-details-page.c     |   90 ++++++----
 src/gr-details-page.ui    |    7 +-
 src/gr-edit-page.c        |  292 +++++++++++++++++++++++++++------
 src/gr-edit-page.ui       |  397 ++++++++++++++++++++-------------------------
 src/gr-ingredients-list.c |   41 ++++-
 src/gr-ingredients-list.h |    4 +-
 src/gr-recipe-store.c     |   13 +-
 7 files changed, 519 insertions(+), 325 deletions(-)
---
diff --git a/src/gr-details-page.c b/src/gr-details-page.c
index 04c70c1..1ada851 100644
--- a/src/gr-details-page.c
+++ b/src/gr-details-page.c
@@ -119,7 +119,7 @@ struct _GrDetailsPage
         GtkWidget *warning_box;
         GtkWidget *spicy_warning;
         GtkWidget *garlic_warning;
-        GtkWidget *ingredients_list;
+        GtkWidget *ingredients_box;
         GtkWidget *instructions_label;
         GtkWidget *cooking_revealer;
         GtkWidget *ingredients_check;
@@ -588,9 +588,6 @@ gr_details_page_init (GrDetailsPage *page)
                                      NULL,
                                      NULL);
 
-        gtk_list_box_set_header_func (GTK_LIST_BOX (page->ingredients_list),
-                                      all_headers, NULL, NULL);
-
         g_signal_connect (gtk_text_view_get_buffer (GTK_TEXT_VIEW (page->notes_field)), "changed", 
G_CALLBACK (schedule_save), page);
 }
 
@@ -611,7 +608,7 @@ gr_details_page_class_init (GrDetailsPageClass *klass)
         gtk_widget_class_bind_template_child (widget_class, GrDetailsPage, warning_box);
         gtk_widget_class_bind_template_child (widget_class, GrDetailsPage, spicy_warning);
         gtk_widget_class_bind_template_child (widget_class, GrDetailsPage, garlic_warning);
-        gtk_widget_class_bind_template_child (widget_class, GrDetailsPage, ingredients_list);
+        gtk_widget_class_bind_template_child (widget_class, GrDetailsPage, ingredients_box);
         gtk_widget_class_bind_template_child (widget_class, GrDetailsPage, instructions_label);
         gtk_widget_class_bind_template_child (widget_class, GrDetailsPage, cooking_revealer);
         gtk_widget_class_bind_template_child (widget_class, GrDetailsPage, ingredients_check);
@@ -660,43 +657,64 @@ populate_ingredients (GrDetailsPage *page,
                       int            denom)
 {
         g_autoptr(GtkSizeGroup) group = NULL;
+        g_autofree char **segments = NULL;
         g_auto(GStrv) ings = NULL;
-        int i;
+        int i, j;
+        GtkWidget *list;
+        GtkWidget *label;
+
+        container_remove_all (GTK_CONTAINER (page->ingredients_box));
 
         group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
-        container_remove_all (GTK_CONTAINER (page->ingredients_list));
-        ings = gr_ingredients_list_get_ingredients (page->ingredients);
-        for (i = 0; ings[i]; i++) {
-                GtkWidget *row;
-                GtkWidget *box;
-                GtkWidget *label;
-                g_autofree char *s = NULL;
-
-                box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-                gtk_widget_show (box);
-
-                s = gr_ingredients_list_scale_unit (page->ingredients, ings[i], num, denom);
-                label = gtk_label_new (s);
-                g_object_set (label,
-                              "visible", TRUE,
-                              "xalign", 0.0,
-                              "margin", 10,
-                              NULL);
-                gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label");
-                gtk_container_add (GTK_CONTAINER (box), label);
-                gtk_size_group_add_widget (group, label);
-
-                label = gtk_label_new (ings[i]);
-                g_object_set (label,
-                              "visible", TRUE,
-                              "xalign", 0.0,
+        segments = gr_ingredients_list_get_segments (page->ingredients);
+        for (j = 0; segments[j]; j++) {
+                if (segments[j] && segments[j][0]) {
+                        label = gtk_label_new (segments[j]);
+                        gtk_widget_show (label);
+                        gtk_label_set_xalign (GTK_LABEL (label), 0);
+                        gtk_style_context_add_class (gtk_widget_get_style_context (label), "heading");
+                        gtk_container_add (GTK_CONTAINER (page->ingredients_box), label);
+                }
+
+                list = gtk_list_box_new ();
+                gtk_widget_show (list);
+                gtk_style_context_add_class (gtk_widget_get_style_context (list), "frame");
+                gtk_list_box_set_selection_mode (GTK_LIST_BOX (list), GTK_SELECTION_NONE);
+                gtk_list_box_set_header_func (GTK_LIST_BOX (list), all_headers, NULL, NULL);
+                gtk_container_add (GTK_CONTAINER (page->ingredients_box), list);
+
+                ings = gr_ingredients_list_get_ingredients (page->ingredients, segments[j]);
+                for (i = 0; ings[i]; i++) {
+                        GtkWidget *row;
+                        GtkWidget *box;
+                        g_autofree char *s = NULL;
+
+                        box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+                        gtk_widget_show (box);
+
+                        s = gr_ingredients_list_scale_unit (page->ingredients, ings[i], num, denom);
+                        label = gtk_label_new (s);
+                        g_object_set (label,
+                                      "visible", TRUE,
+                                      "xalign", 0.0,
+                                      "margin", 10,
+                                      NULL);
+                        gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label");
+                        gtk_container_add (GTK_CONTAINER (box), label);
+                        gtk_size_group_add_widget (group, label);
+
+                        label = gtk_label_new (ings[i]);
+                        g_object_set (label,
+                                      "visible", TRUE,
+                                      "xalign", 0.0,
                               "margin", 10,
                               NULL);
-                gtk_container_add (GTK_CONTAINER (box), label);
+                        gtk_container_add (GTK_CONTAINER (box), label);
 
-                gtk_container_add (GTK_CONTAINER (page->ingredients_list), box);
-                row = gtk_widget_get_parent (box);
-                gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
+                        gtk_container_add (GTK_CONTAINER (list), box);
+                        row = gtk_widget_get_parent (box);
+                        gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
+                }
         }
 
         gtk_widget_hide (page->warning_box);
diff --git a/src/gr-details-page.ui b/src/gr-details-page.ui
index 5a7c63f..2fe0f4b 100644
--- a/src/gr-details-page.ui
+++ b/src/gr-details-page.ui
@@ -154,12 +154,9 @@ followed</property>
                       </object>
                     </child>
                     <child>
-                      <object class="GtkListBox" id="ingredients_list">
+                      <object class="GtkBox" id="ingredients_box">
                         <property name="visible">1</property>
-                        <property name="selection-mode">none</property>
-                        <style>
-                          <class name="frame"/>
-                        </style>
+                        <property name="orientation">vertical</property>
                       </object>
                     </child>
                   </object>
diff --git a/src/gr-edit-page.c b/src/gr-edit-page.c
index 999c79b..1d219ca 100644
--- a/src/gr-edit-page.c
+++ b/src/gr-edit-page.c
@@ -60,7 +60,7 @@ struct _GrEditPage
         GtkWidget *spiciness_combo;
         GtkWidget *prep_time_combo;
         GtkWidget *cook_time_combo;
-        GtkWidget *ingredients_list;
+        GtkWidget *description_field;
         GtkWidget *instructions_field;
         GtkWidget *serves_spin;
         GtkWidget *gluten_free_check;
@@ -78,12 +78,14 @@ struct _GrEditPage
         GtkWidget *new_ingredient_amount;
         GtkWidget *new_ingredient_unit;
         GtkWidget *new_ingredient_add_button;
-        GtkWidget *remove_ingredient_button;
         GtkWidget *author_label;
+        GtkWidget *ingredients_box;
 
         GtkSizeGroup *group;
 
         guint account_response_signal_id;
+
+        GList *segments;
 };
 
 G_DEFINE_TYPE (GrEditPage, gr_edit_page, GTK_TYPE_BOX)
@@ -139,6 +141,7 @@ edit_page_finalize (GObject *object)
 
         g_clear_object (&self->recipe);
         g_clear_object (&self->group);
+        g_list_free (self->segments);
 
         G_OBJECT_CLASS (gr_edit_page_parent_class)->finalize (object);
 }
@@ -191,14 +194,17 @@ populate_season_combo (GrEditPage *page)
 }
 
 static void
-add_ingredient (GrEditPage *page)
+add_ingredient (GtkButton *button, GrEditPage *page)
 {
+        gtk_popover_set_relative_to (GTK_POPOVER (page->ingredient_popover),
+                                     GTK_WIDGET (button));
         gtk_popover_popup (GTK_POPOVER (page->ingredient_popover));
 }
 
 static void
 remove_ingredient (GrEditPage *page)
 {
+#if 0
         GtkListBoxRow *row;
 
         row = gtk_list_box_get_selected_row (GTK_LIST_BOX (page->ingredients_list));
@@ -206,22 +212,19 @@ remove_ingredient (GrEditPage *page)
                 return;
 
         gtk_container_remove (GTK_CONTAINER (page->ingredients_list), GTK_WIDGET (row));
-
+#endif
 }
 
 static void
 selected_rows_changed (GrEditPage *page)
 {
-        GtkListBoxRow *row;
-
-        row = gtk_list_box_get_selected_row (GTK_LIST_BOX (page->ingredients_list));
-        gtk_widget_set_sensitive (page->remove_ingredient_button, row != NULL);
 }
 
 static void
-add_ingredient_row (GrEditPage *page,
-                    const char *unit,
-                    const char *ingredient)
+add_ingredient_row (GtkWidget    *list,
+                    GtkSizeGroup *group,
+                    const char   *unit,
+                    const char   *ingredient)
 {
         GtkWidget *box;
         GtkWidget *label;
@@ -238,7 +241,7 @@ add_ingredient_row (GrEditPage *page,
                       NULL);
         gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label");
         gtk_container_add (GTK_CONTAINER (box), label);
-        gtk_size_group_add_widget (page->group, label);
+        gtk_size_group_add_widget (group, label);
 
         label = gtk_label_new (ingredient);
         g_object_set (label,
@@ -248,7 +251,7 @@ add_ingredient_row (GrEditPage *page,
                       NULL);
         gtk_container_add (GTK_CONTAINER (box), label);
 
-        gtk_container_add (GTK_CONTAINER (page->ingredients_list), box);
+        gtk_container_add (GTK_CONTAINER (list), box);
         row = gtk_widget_get_parent (box);
         g_object_set_data_full (G_OBJECT (row), "ingredient", g_strdup_printf ("%s %s", unit, ingredient), 
g_free);
 
@@ -256,38 +259,55 @@ add_ingredient_row (GrEditPage *page,
 }
 
 static void
-add_ingredient2 (GrEditPage *page)
+add_ingredient2 (GtkButton *button, GrEditPage *page)
 {
         const char *ingredient;
         double amount;
         const char *unit;
         g_autofree char *s = NULL;
+        GtkWidget *list;
+        GtkWidget *b;
 
         gtk_popover_popdown (GTK_POPOVER (page->ingredient_popover));
 
+        b = gtk_popover_get_relative_to (GTK_POPOVER (page->ingredient_popover));
+        list = GTK_WIDGET (g_object_get_data (G_OBJECT (b), "list"));
+
         ingredient = gtk_entry_get_text (GTK_ENTRY (page->new_ingredient_name));
         amount = gtk_spin_button_get_value (GTK_SPIN_BUTTON (page->new_ingredient_amount));
         unit = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (page->new_ingredient_unit))));
 
         s = g_strdup_printf ("%g %s", amount, unit);
-        add_ingredient_row (page, s, ingredient);
+        add_ingredient_row (list, page->group, s, ingredient);
 }
 
 static char *
 collect_ingredients (GrEditPage *page)
 {
         GString *s;
-        GList *children, *l;
+        GtkWidget *segment;
+        GtkWidget *list;
+        GtkWidget *entry;
+        GList *children, *l, *k;
 
         s = g_string_new ("");
-        children = gtk_container_get_children (GTK_CONTAINER (page->ingredients_list));
-        for (l = children; l; l = l->next) {
-                GtkWidget *row = l->data;
-                if (s->len > 0)
-                        g_string_append (s, "\n");
-                g_string_append (s, (const char *)g_object_get_data (G_OBJECT (row), "ingredient"));
+        for (k = page->segments; k; k = k->next) {
+                segment = k->data;
+                list = GTK_WIDGET (g_object_get_data (G_OBJECT (segment), "list"));
+                entry = GTK_WIDGET (g_object_get_data (G_OBJECT (segment), "entry"));
+                children = gtk_container_get_children (GTK_CONTAINER (list));
+                for (l = children; l; l = l->next) {
+                        GtkWidget *row = l->data;
+                        if (s->len > 0)
+                                g_string_append (s, "\n");
+                        g_string_append (s, (const char *)g_object_get_data (G_OBJECT (row), "ingredient"));
+                        if (page->segments->next != NULL) {
+                                g_string_append (s, "\t");
+                                g_string_append (s, gtk_entry_get_text (GTK_ENTRY (entry)));
+                        }
+                }
+                g_list_free (children);
         }
-        g_list_free (children);
 
         return g_string_free (s, FALSE);
 }
@@ -315,9 +335,6 @@ gr_edit_page_init (GrEditPage *page)
 
         page->group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
 
-        gtk_list_box_set_header_func (GTK_LIST_BOX (page->ingredients_list),
-                                      all_headers, NULL, NULL);
-
         populate_cuisine_combo (page);
         populate_category_combo (page);
         populate_season_combo (page);
@@ -344,7 +361,7 @@ gr_edit_page_class_init (GrEditPageClass *klass)
         gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, cook_time_combo);
         gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, serves_spin);
         gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, spiciness_combo);
-        gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, ingredients_list);
+        gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, description_field);
         gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, instructions_field);
         gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, gluten_free_check);
         gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, nut_free_check);
@@ -360,8 +377,8 @@ gr_edit_page_class_init (GrEditPageClass *klass)
         gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, new_ingredient_name);
         gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, new_ingredient_amount);
         gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, new_ingredient_unit);
-        gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, 
remove_ingredient_button);
         gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, author_label);
+        gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, ingredients_box);
 
         gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), dismiss_error);
         gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), add_image);
@@ -369,7 +386,6 @@ gr_edit_page_class_init (GrEditPageClass *klass)
         gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), rotate_image_left);
         gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), rotate_image_right);
         gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), images_changed);
-        gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), add_ingredient);
         gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), add_ingredient2);
         gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), remove_ingredient);
         gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), selected_rows_changed);
@@ -464,6 +480,191 @@ get_spiciness (GrEditPage *page)
                 return 90;
 }
 
+static void add_list    (GtkButton *button, GrEditPage *page);
+static void remove_list (GtkButton *button, GrEditPage *page);
+static void update_segments (GrEditPage *page);
+
+static GtkWidget *
+add_ingredients_segment (GrEditPage *page,
+                         const char *segment_label)
+{
+        GtkWidget *segment;
+        GtkWidget *label;
+        GtkWidget *entry;
+        GtkWidget *list;
+        GtkWidget *box;
+        GtkWidget *button;
+        GtkWidget *stack;
+        GtkWidget *image;
+
+        segment = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+        g_object_set (segment,
+                      "margin-top", 20,
+                      "margin-bottom", 20,
+                      NULL);
+        gtk_widget_show (segment);
+        gtk_container_add (GTK_CONTAINER (page->ingredients_box), segment);
+
+        stack = gtk_stack_new ();
+        g_object_set_data (G_OBJECT (segment), "stack", stack);
+        gtk_widget_show (stack);
+        gtk_container_add (GTK_CONTAINER (segment), stack);
+
+        label = g_object_new (GTK_TYPE_LABEL,
+                              "label", segment_label[0] ? segment_label : _("Ingredients"),
+                              "xalign", 0.0,
+                              "visible", TRUE,
+                              NULL);
+        gtk_style_context_add_class (gtk_widget_get_style_context (label), "heading");
+        gtk_stack_add_named (GTK_STACK (stack), label, "label");
+
+        box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
+        gtk_widget_set_valign (box, GTK_ALIGN_START);
+        gtk_widget_show (box);
+
+        entry = gtk_entry_new ();
+        g_object_set_data (G_OBJECT (segment), "entry", entry);
+        gtk_widget_set_halign (box, GTK_ALIGN_FILL);
+        gtk_widget_show (entry);
+        gtk_entry_set_text (GTK_ENTRY (entry), segment_label[0] ? segment_label : _("Ingredients for …"));
+
+        gtk_box_pack_start (GTK_BOX (box), entry, TRUE, TRUE, 0);
+
+        button = gtk_button_new_with_label (_("Remove"));
+        g_object_set_data (G_OBJECT (button), "segment", segment);
+        g_object_set_data (G_OBJECT (segment), "remove-list", button);
+        g_signal_connect (button, "clicked", G_CALLBACK (remove_list), page);
+        gtk_widget_show (button);
+        gtk_container_add (GTK_CONTAINER (box), button);
+
+        gtk_stack_add_named (GTK_STACK (stack), box, "entry");
+
+        list = gtk_list_box_new ();
+        g_object_set_data (G_OBJECT (segment), "list", list);
+
+        gtk_widget_show (list);
+        gtk_style_context_add_class (gtk_widget_get_style_context (list), "frame");
+        gtk_list_box_set_selection_mode (GTK_LIST_BOX (list), GTK_SELECTION_NONE);
+        gtk_list_box_set_header_func (GTK_LIST_BOX (list), all_headers, NULL, NULL);
+
+        label = g_object_new (GTK_TYPE_LABEL,
+                              "label", _("No ingredients added yet"),
+                              "xalign", 0.5,
+                              "halign", GTK_ALIGN_FILL,
+                              "margin-start", 20,
+                              "margin-end", 20,
+                              "margin-top", 10,
+                              "margin-bottom", 10,
+                              "visible", TRUE,
+                              NULL);
+        gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label");
+        gtk_list_box_set_placeholder (GTK_LIST_BOX (list), label);
+
+        gtk_container_add (GTK_CONTAINER (segment), list);
+
+        box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
+        gtk_widget_set_halign (box, GTK_ALIGN_START);
+        gtk_widget_show (box);
+
+        button = gtk_button_new ();
+        gtk_widget_set_tooltip_text (button, _("Add Ingredient"));
+        image = gtk_image_new_from_icon_name ("list-add-symbolic", 1);
+        gtk_widget_show (image);
+        gtk_widget_set_margin_top (button, 10);
+        gtk_container_add (GTK_CONTAINER (button), image);
+        gtk_style_context_add_class (gtk_widget_get_style_context (button), "dim-label");
+        gtk_style_context_add_class (gtk_widget_get_style_context (button), "image-button");
+        gtk_style_context_remove_class (gtk_widget_get_style_context (button), "text-button");
+        g_signal_connect (button, "clicked", G_CALLBACK (add_ingredient), page);
+        gtk_widget_show (button);
+        gtk_container_add (GTK_CONTAINER (box), button);
+        g_object_set_data (G_OBJECT (button), "list", list);
+
+        gtk_container_add (GTK_CONTAINER (segment), box);
+
+        page->segments = g_list_append (page->segments, segment);
+
+        return list;
+}
+
+static void
+add_list (GtkButton *button, GrEditPage *page)
+{
+        add_ingredients_segment (page, "");
+
+        update_segments (page);
+}
+
+static void
+remove_list (GtkButton *button, GrEditPage *page)
+{
+        GtkWidget *segment;
+
+        segment = GTK_WIDGET (g_object_get_data (G_OBJECT (button), "segment"));
+
+        page->segments = g_list_remove (page->segments, segment);
+        gtk_widget_destroy (segment);
+
+        update_segments (page);
+}
+
+static void
+update_segments (GrEditPage *page)
+{
+        GList *l;
+        GtkWidget *segment;
+        GtkWidget *stack;
+        GtkWidget *button;
+
+        for (l = page->segments; l; l = l->next) {
+                segment = l->data;
+                stack = GTK_WIDGET (g_object_get_data (G_OBJECT (segment), "stack"));
+                button = GTK_WIDGET (g_object_get_data (G_OBJECT (segment), "remove-list"));
+                if (page->segments->next == NULL)
+                        gtk_stack_set_visible_child_name (GTK_STACK (stack), "label");
+                else {
+                        gtk_stack_set_visible_child_name (GTK_STACK (stack), "entry");
+                        gtk_widget_set_visible (button, l != page->segments);
+                }
+        }
+}
+
+static void
+populate_ingredients (GrEditPage *page,
+                      const char *text)
+{
+        g_autoptr(GrIngredientsList) ingredients = NULL;
+        g_autofree char **segs = NULL;
+        g_auto(GStrv) ings = NULL;
+        int i, j;
+        GtkWidget *list;
+        GtkWidget *button;
+
+        container_remove_all (GTK_CONTAINER (page->ingredients_box));
+        g_list_free (page->segments);
+        page->segments = NULL;
+
+        ingredients = gr_ingredients_list_new (text);
+        segs = gr_ingredients_list_get_segments (ingredients);
+        for (j = 0; segs[j]; j++) {
+                list = add_ingredients_segment (page, segs[j]);
+                ings = gr_ingredients_list_get_ingredients (ingredients, segs[j]);
+                for (i = 0; ings[i]; i++) {
+                        g_autofree char *s = NULL;
+                        s = gr_ingredients_list_scale_unit (ingredients, ings[i], 1, 1);
+                        add_ingredient_row (list, page->group,  s, ings[i]);
+                }
+        }
+
+        button = gtk_button_new_with_label (_("Add List"));
+        gtk_widget_show (button);
+        gtk_widget_set_halign (button, GTK_ALIGN_FILL);
+        gtk_box_pack_end (GTK_BOX (page->ingredients_box), button, FALSE, TRUE, 0);
+        g_signal_connect (button, "clicked", G_CALLBACK (add_list), page);
+
+        update_segments (page);
+}
+
 void
 gr_edit_page_clear (GrEditPage *page)
 {
@@ -478,7 +679,8 @@ gr_edit_page_clear (GrEditPage *page)
         set_combo_value (GTK_COMBO_BOX (page->cook_time_combo), "");
         gtk_spin_button_set_value (GTK_SPIN_BUTTON (page->serves_spin), 1);
         set_spiciness (page, 0);
-        container_remove_all (GTK_CONTAINER (page->ingredients_list));
+        populate_ingredients (page, "");
+        set_text_view_text (GTK_TEXT_VIEW (page->description_field), "");
         set_text_view_text (GTK_TEXT_VIEW (page->instructions_field), "");
         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (page->gluten_free_check), FALSE);
         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (page->nut_free_check), FALSE);
@@ -494,25 +696,6 @@ gr_edit_page_clear (GrEditPage *page)
         g_clear_object (&page->recipe);
 }
 
-static void
-populate_ingredients (GrEditPage *page,
-                       GrRecipe   *recipe)
-{
-        g_autoptr(GrIngredientsList) ingredients = NULL;
-        g_auto(GStrv) ings = NULL;
-        int i;
-
-        container_remove_all (GTK_CONTAINER (page->ingredients_list));
-
-        ingredients = gr_ingredients_list_new (gr_recipe_get_ingredients (recipe));
-        ings = gr_ingredients_list_get_ingredients (ingredients);
-        for (i = 0; ings[i]; i++) {
-                g_autofree char *s = NULL;
-                s = gr_ingredients_list_scale_unit (ingredients, ings[i], 1, 1);
-                add_ingredient_row (page,  s, ings[i]);
-        }
-}
-
 void
 gr_edit_page_edit (GrEditPage *page,
                    GrRecipe   *recipe)
@@ -526,7 +709,9 @@ gr_edit_page_edit (GrEditPage *page,
         const char *author;
         int serves;
         int spiciness;
+        const char *description;
         const char *instructions;
+        const char *ingredients;
         g_autofree char *image_path = NULL;
         g_autoptr(GdkPixbuf) pixbuf = NULL;
         GrDiets diets;
@@ -545,7 +730,9 @@ gr_edit_page_edit (GrEditPage *page,
         prep_time = gr_recipe_get_prep_time (recipe);
         cook_time = gr_recipe_get_cook_time (recipe);
         diets = gr_recipe_get_diets (recipe);
+        description = gr_recipe_get_description (recipe);
         instructions = gr_recipe_get_instructions (recipe);
+        ingredients = gr_recipe_get_ingredients (recipe);
         author = gr_recipe_get_author (recipe);
 
         g_object_get (recipe, "images", &images, NULL);
@@ -562,9 +749,10 @@ gr_edit_page_edit (GrEditPage *page,
         set_combo_value (GTK_COMBO_BOX (page->cook_time_combo), cook_time);
         set_spiciness (page, spiciness);
         gtk_spin_button_set_value (GTK_SPIN_BUTTON (page->serves_spin), serves);
+        set_text_view_text (GTK_TEXT_VIEW (page->description_field), description);
         set_text_view_text (GTK_TEXT_VIEW (page->instructions_field), instructions);
 
-        populate_ingredients (page, recipe);
+        populate_ingredients (page, ingredients);
 
         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (page->gluten_free_check), (diets & 
GR_DIET_GLUTEN_FREE) != 0);
         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (page->nut_free_check), (diets & GR_DIET_NUT_FREE) 
!= 0);
@@ -821,6 +1009,7 @@ gr_edit_page_save (GrEditPage *page)
         g_autofree char *cook_time = NULL;
         int serves;
         int spiciness;
+        g_autofree char *description = NULL;
         g_autofree char *ingredients = NULL;
         g_autofree char *instructions = NULL;
         GrRecipeStore *store;
@@ -840,6 +1029,7 @@ gr_edit_page_save (GrEditPage *page)
         spiciness = get_spiciness (page);
         serves = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (page->serves_spin));
         ingredients = collect_ingredients (page);
+        description = get_text_view_text (GTK_TEXT_VIEW (page->description_field));
         instructions = get_text_view_text (GTK_TEXT_VIEW (page->instructions_field));
         diets = (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (page->gluten_free_check)) ? 
GR_DIET_GLUTEN_FREE : 0) |
                 (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (page->nut_free_check)) ? GR_DIET_NUT_FREE 
: 0) |
@@ -867,6 +1057,7 @@ gr_edit_page_save (GrEditPage *page)
                               "cook-time", cook_time,
                               "serves", serves,
                               "spiciness", spiciness,
+                              "description", description,
                               "ingredients", ingredients,
                               "instructions", instructions,
                               "diets", diets,
@@ -893,6 +1084,7 @@ gr_edit_page_save (GrEditPage *page)
                                        "cook-time", cook_time,
                                        "serves", serves,
                                        "spiciness", spiciness,
+                                       "description", description,
                                        "ingredients", ingredients,
                                        "instructions", instructions,
                                        "diets", diets,
diff --git a/src/gr-edit-page.ui b/src/gr-edit-page.ui
index 99f93a0..3dfd6c4 100644
--- a/src/gr-edit-page.ui
+++ b/src/gr-edit-page.ui
@@ -80,7 +80,6 @@
                   <object class="GtkBox">
                     <property name="visible">1</property>
                     <property name="orientation">vertical</property>
-                    <property name="spacing">20</property>
                     <property name="margin-top">20</property>
                     <property name="valign">start</property>
                     <property name="halign">end</property>
@@ -100,6 +99,7 @@
                       <object class="GtkBox">
                         <property name="visible">1</property>
                         <property name="halign">start</property>
+                        <property name="margin-top">10</property>
                         <style>
                           <class name="linked"/>
                         </style>
@@ -121,7 +121,7 @@
                               <object class="GtkImage">
                                 <property name="visible">1</property>
                                 <property name="icon-name">list-add-symbolic</property>
-                                <property name="pixel-size">20</property>
+                                <property name="icon-size">1</property>
                               </object>
                             </child>
                           </object>
@@ -147,7 +147,7 @@
                               <object class="GtkImage">
                                 <property name="visible">1</property>
                                 <property name="icon-name">object-rotate-left-symbolic</property>
-                                <property name="pixel-size">20</property>
+                                <property name="icon-size">1</property>
                               </object>
                             </child>
                           </object>
@@ -173,7 +173,7 @@
                               <object class="GtkImage">
                                 <property name="visible">1</property>
                                 <property name="icon-name">object-rotate-right-symbolic</property>
-                                <property name="pixel-size">20</property>
+                                <property name="icon-size">1</property>
                               </object>
                             </child>
                           </object>
@@ -199,7 +199,7 @@
                               <object class="GtkImage">
                                 <property name="visible">1</property>
                                 <property name="icon-name">user-trash-symbolic</property>
-                                <property name="pixel-size">20</property>
+                                <property name="icon-size">1</property>
                               </object>
                             </child>
                           </object>
@@ -213,120 +213,19 @@
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkLabel">
-                        <property name="visible">1</property>
-                        <property name="label" translatable="yes">Ingredients</property>
-                        <property name="xalign">0</property>
-                        <style> <class name="heading"/> </style>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkScrolledWindow">
+                      <object class="GtkBox" id="ingredients_box">
                         <property name="visible">1</property>
-                        <property name="shadow-type">none</property>
-                        <property name="hscrollbar-policy">never</property>
-                        <property name="vscrollbar-policy">never</property>
-                        <child>
-                          <object class="GtkListBox" id="ingredients_list">
-                            <property name="visible">1</property>
-                            <property name="selection-mode">single</property>
-                            <signal name="selected-rows-changed" handler="selected_rows_changed" 
swapped="yes"/>
-                            <style>
-                              <class name="frame"/>
-                            </style>
-                            <accessibility>
-                              <relation target="add_ingredient_button" type="controlled-by"/>
-                              <relation target="remove_ingredient_button" type="controlled-by"/>
-                            </accessibility>
-                            <child type="placeholder">
-                              <object class="GtkLabel">
-                                <property name="visible">1</property>
-                                <property name="margin-start">20</property>
-                                <property name="margin-end">20</property>
-                                <property name="margin-top">10</property>
-                                <property name="margin-bottom">10</property>
-                                <property name="halign">fill</property>
-                                <property name="xalign">0.5</property>
-                                <property name="label" translatable="yes">No ingredients added yet</property>
-                                <style> <class name="dim-label"/> </style>
-                              </object>
-                            </child>
-                          </object>
-                        </child>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkBox">
-                        <property name="visible">1</property>
-                        <property name="spacing">10</property>
-                        <property name="halign">start</property>
-                        <child>
-                          <object class="GtkButton" id="add_ingredient_button">
-                            <property name="visible">1</property>
-                            <property name="halign">center</property>
-                            <property name="valign">start</property>
-                            <property name="tooltip-text" translatable="yes">Add an ingredient</property>
-                            <accessibility>
-                              <relation target="ingredients_list" type="controller-for"/>
-                            </accessibility>
-                            <style>
-                              <class name="image-button"/>
-                              <class name="circular"/>
-                              <class name="dim-label"/>
-                            </style>
-                            <signal name="clicked" handler="add_ingredient" swapped="yes"/>
-                            <child>
-                              <object class="GtkImage">
-                                <property name="visible">1</property>
-                                <property name="icon-name">list-add-symbolic</property>
-                                <property name="pixel-size">20</property>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkButton" id="remove_ingredient_button">
-                            <property name="visible">1</property>
-                            <property name="halign">center</property>
-                            <property name="valign">start</property>
-                            <property name="sensitive">0</property>
-                            <property name="tooltip-text" translatable="yes">Remove an ingredient</property>
-                            <accessibility>
-                              <relation target="ingredients_list" type="controller-for"/>
-                            </accessibility>
-                            <style>
-                              <class name="image-button"/>
-                              <class name="circular"/>
-                              <class name="dim-label"/>
-                            </style>
-                            <signal name="clicked" handler="remove_ingredient" swapped="yes"/>
-                            <child>
-                              <object class="GtkImage">
-                                <property name="visible">1</property>
-                                <property name="icon-name">edit-delete-symbolic</property>
-                                <property name="pixel-size">20</property>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">1</property>
-                          </packing>
-                        </child>
+                        <property name="orientation">vertical</property>
                       </object>
-                      <packing>
-                        <property name="fill">1</property>
-                      </packing>
                     </child>
 
                     <child>
                       <object class="GtkFlowBox">
                         <property name="visible">1</property>
+                        <property name="margin-top">40</property>
                         <property name="selection-mode">none</property>
-                        <property name="min-children-per-line">4</property>
-                        <property name="max-children-per-line">4</property>
+                        <property name="min-children-per-line">3</property>
+                        <property name="max-children-per-line">3</property>
                         <child>
                           <object class="GtkCheckButton" id="gluten_free_check">
                             <property name="visible">1</property>
@@ -359,41 +258,36 @@
                         </child>
                       </object>
                     </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkGrid">
+                    <property name="visible">1</property>
+                    <property name="halign">start</property>
+                    <property name="valign">start</property>
+                    <property name="column-spacing">20</property>
                     <child>
                       <object class="GtkLabel">
                         <property name="visible">1</property>
-                        <property name="label" translatable="yes">Other Information</property>
+                        <property name="label" translatable="yes">Details</property>
                         <property name="xalign">0</property>
                         <style> <class name="heading"/> </style>
                       </object>
-                    </child>
-                    <child>
-                      <object class="GtkGrid">
-                        <property name="visible">1</property>
-                        <property name="row-spacing">20</property>
-                        <property name="column-spacing">40</property>
-                        <property name="halign">fill</property>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">1</property>
-                        <property name="use-underline">1</property>
-                        <property name="mnemonic-widget">cuisine_combo</property>
-                        <property name="label" translatable="yes">_Cuisine</property>
-                        <property name="xalign">1</property>
-                        <style> <class name="dim-label"/> </style>
-                      </object>
                       <packing>
                         <property name="left-attach">0</property>
                         <property name="top-attach">0</property>
+                        <property name="width">2</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkLabel">
+                      <object class="GtkLabel" id="name_label">
                         <property name="visible">1</property>
                         <property name="use-underline">1</property>
-                        <property name="mnemonic-widget">category_combo</property>
-                        <property name="label" translatable="yes">_Meal</property>
+                        <property name="mnemonic-widget">name_entry</property>
+                        <property name="label" translatable="yes">_Name your recipe</property>
                         <property name="xalign">1</property>
+                        <property name="halign">fill</property>
+                        <property name="valign">baseline</property>
                         <style> <class name="dim-label"/> </style>
                       </object>
                       <packing>
@@ -402,19 +296,11 @@
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkComboBoxText" id="cuisine_combo">
-                        <property name="visible">1</property>
-                        <property name="has-entry">1</property>
-                      </object>
-                      <packing>
-                        <property name="left-attach">1</property>
-                        <property name="top-attach">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkComboBoxText" id="category_combo">
+                      <object class="GtkEntry" id="name_entry">
                         <property name="visible">1</property>
-                        <property name="has-entry">1</property>
+                        <property name="hexpand">1</property>
+                        <property name="valign">baseline</property>
+                        <property name="margin-bottom">10</property>
                       </object>
                       <packing>
                         <property name="left-attach">1</property>
@@ -425,8 +311,9 @@
                       <object class="GtkLabel">
                         <property name="visible">1</property>
                         <property name="use-underline">1</property>
-                        <property name="mnemonic-widget">season_combo</property>
-                        <property name="label" translatable="yes">S_eason</property>
+                        <property name="mnemonic-widget">serves_spin</property>
+                        <property name="label" translatable="yes">Ser_ves</property>
+                        <property name="valign">baseline</property>
                         <property name="xalign">1</property>
                         <style> <class name="dim-label"/> </style>
                       </object>
@@ -436,12 +323,27 @@
                       </packing>
                     </child>
                     <child>
+                      <object class="GtkSpinButton" id="serves_spin">
+                        <property name="visible">1</property>
+                        <property name="adjustment">serves_adjustment</property>
+                        <property name="halign">start</property>
+                        <property name="valign">baseline</property>
+                        <property name="margin-bottom">10</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">1</property>
+                        <property name="top-attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
                       <object class="GtkLabel">
                         <property name="visible">1</property>
                         <property name="use-underline">1</property>
-                        <property name="mnemonic-widget">spiciness_combo</property>
-                        <property name="label" translatable="yes">S_piciness</property>
+                        <property name="mnemonic-widget">prep_time_combo</property>
+                        <property name="label" translatable="yes">_Preparation time</property>
                         <property name="xalign">1</property>
+                        <property name="valign">center</property>
+                        <property name="margin-bottom">10</property>
                         <style> <class name="dim-label"/> </style>
                       </object>
                       <packing>
@@ -450,166 +352,216 @@
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkComboBoxText" id="season_combo">
+                      <object class="GtkComboBoxText" id="prep_time_combo">
                         <property name="visible">1</property>
                         <property name="has-entry">1</property>
+                        <property name="halign">fill</property>
+                        <property name="valign">center</property>
+                        <property name="margin-bottom">10</property>
+                        <items>
+                          <item translatable="yes" id="Less than 15 minutes">Less than 15 minutes</item>
+                          <item translatable="yes" id="15 to 30 minutes">15 to 30 minutes</item>
+                          <item translatable="yes" id="30 to 45 minutes">30 to 45 minutes</item>
+                          <item translatable="yes" id="45 minutes to an hour">45 minutes to an hour</item>
+                          <item translatable="yes" id="More than an hour">More than an hour</item>
+                        </items>
                       </object>
                       <packing>
                         <property name="left-attach">1</property>
-                        <property name="top-attach">2</property>
+                        <property name="top-attach">3</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkComboBoxText" id="spiciness_combo">
+                      <object class="GtkLabel">
                         <property name="visible">1</property>
-                        <items>
-                          <item translatable="yes" id="mild">Mild</item>
-                          <item translatable="yes" id="spicy">Somewhat spicy</item>
-                          <item translatable="yes" id="hot">Hot</item>
-                          <item translatable="yes" id="extreme">Very spicy</item>
-                        </items>
+                        <property name="use-underline">1</property>
+                        <property name="mnemonic-widget">cook_time_combo</property>
+                        <property name="label" translatable="yes">C_ooking time</property>
+                        <property name="xalign">1</property>
+                        <property name="valign">center</property>
+                        <property name="margin-bottom">20</property>
+                        <style> <class name="dim-label"/> </style>
                       </object>
                       <packing>
-                        <property name="left-attach">1</property>
-                        <property name="top-attach">3</property>
+                        <property name="left-attach">0</property>
+                        <property name="top-attach">4</property>
                       </packing>
                     </child>
-                  </object>
-                </child>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkGrid">
-                    <property name="visible">1</property>
-                    <property name="halign">start</property>
-                    <property name="valign">start</property>
-                    <property name="row-spacing">20</property>
-                    <property name="column-spacing">40</property>
                     <child>
-                      <object class="GtkLabel">
+                      <object class="GtkComboBoxText" id="cook_time_combo">
                         <property name="visible">1</property>
-                        <property name="label" translatable="yes">Details</property>
-                        <property name="xalign">0</property>
-                        <style> <class name="heading"/> </style>
+                        <property name="has-entry">1</property>
+                        <property name="halign">fill</property>
+                        <property name="valign">center</property>
+                        <property name="margin-bottom">20</property>
+                        <items>
+                          <item translatable="yes" id="Less than 15 minutes">Less than 15 minutes</item>
+                          <item translatable="yes" id="15 to 30 minutes">15 to 30 minutes</item>
+                          <item translatable="yes" id="30 to 45 minutes">30 to 45 minutes</item>
+                          <item translatable="yes" id="45 minutes to an hour">45 minutes to an hour</item>
+                          <item translatable="yes" id="More than an hour">More than an hour</item>
+                        </items>
                       </object>
                       <packing>
-                        <property name="left-attach">0</property>
-                        <property name="top-attach">0</property>
-                        <property name="width">2</property>
+                        <property name="left-attach">1</property>
+                        <property name="top-attach">4</property>
                       </packing>
                     </child>
+
                     <child>
-                      <object class="GtkLabel" id="name_label">
+                      <object class="GtkLabel">
                         <property name="visible">1</property>
                         <property name="use-underline">1</property>
-                        <property name="mnemonic-widget">name_entry</property>
-                        <property name="label" translatable="yes">_Name your recipe</property>
+                        <property name="mnemonic-widget">cuisine_combo</property>
+                        <property name="label" translatable="yes">_Cuisine</property>
                         <property name="xalign">1</property>
-                        <property name="halign">fill</property>
+                        <property name="valign">center</property>
+                        <property name="margin-bottom">10</property>
                         <style> <class name="dim-label"/> </style>
                       </object>
                       <packing>
                         <property name="left-attach">0</property>
-                        <property name="top-attach">1</property>
+                        <property name="top-attach">5</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkEntry" id="name_entry">
+                      <object class="GtkComboBoxText" id="cuisine_combo">
                         <property name="visible">1</property>
-                        <property name="hexpand">1</property>
+                        <property name="has-entry">1</property>
+                        <property name="valign">center</property>
+                        <property name="margin-bottom">10</property>
                       </object>
                       <packing>
                         <property name="left-attach">1</property>
-                        <property name="top-attach">1</property>
+                        <property name="top-attach">5</property>
                       </packing>
                     </child>
+
                     <child>
                       <object class="GtkLabel">
                         <property name="visible">1</property>
                         <property name="use-underline">1</property>
-                        <property name="mnemonic-widget">serves_spin</property>
-                        <property name="label" translatable="yes">Ser_ves</property>
+                        <property name="mnemonic-widget">category_combo</property>
+                        <property name="label" translatable="yes">_Meal</property>
                         <property name="xalign">1</property>
+                        <property name="valign">center</property>
+                        <property name="margin-bottom">10</property>
                         <style> <class name="dim-label"/> </style>
                       </object>
                       <packing>
                         <property name="left-attach">0</property>
-                        <property name="top-attach">2</property>
+                        <property name="top-attach">6</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkSpinButton" id="serves_spin">
+                      <object class="GtkComboBoxText" id="category_combo">
                         <property name="visible">1</property>
-                        <property name="adjustment">serves_adjustment</property>
-                        <property name="halign">start</property>
+                        <property name="has-entry">1</property>
+                        <property name="valign">center</property>
+                        <property name="margin-bottom">10</property>
                       </object>
                       <packing>
                         <property name="left-attach">1</property>
-                        <property name="top-attach">2</property>
+                        <property name="top-attach">6</property>
                       </packing>
                     </child>
+
                     <child>
                       <object class="GtkLabel">
                         <property name="visible">1</property>
                         <property name="use-underline">1</property>
-                        <property name="mnemonic-widget">prep_time_combo</property>
-                        <property name="label" translatable="yes">_Preparation time</property>
+                        <property name="mnemonic-widget">season_combo</property>
+                        <property name="label" translatable="yes">S_eason</property>
                         <property name="xalign">1</property>
+                        <property name="valign">center</property>
+                        <property name="margin-bottom">10</property>
                         <style> <class name="dim-label"/> </style>
                       </object>
                       <packing>
                         <property name="left-attach">0</property>
-                        <property name="top-attach">3</property>
+                        <property name="top-attach">7</property>
                       </packing>
                     </child>
                     <child>
+                      <object class="GtkComboBoxText" id="season_combo">
+                        <property name="visible">1</property>
+                        <property name="has-entry">1</property>
+                        <property name="valign">center</property>
+                        <property name="margin-bottom">10</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">1</property>
+                        <property name="top-attach">7</property>
+                      </packing>
+                    </child>
+
+                    <child>
                       <object class="GtkLabel">
                         <property name="visible">1</property>
                         <property name="use-underline">1</property>
-                        <property name="mnemonic-widget">cook_time_combo</property>
-                        <property name="label" translatable="yes">C_ooking time</property>
+                        <property name="mnemonic-widget">spiciness_combo</property>
+                        <property name="label" translatable="yes">S_piciness</property>
                         <property name="xalign">1</property>
+                        <property name="valign">center</property>
+                        <property name="margin-bottom">20</property>
                         <style> <class name="dim-label"/> </style>
                       </object>
                       <packing>
                         <property name="left-attach">0</property>
-                        <property name="top-attach">4</property>
+                        <property name="top-attach">8</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkComboBoxText" id="prep_time_combo">
+                      <object class="GtkComboBoxText" id="spiciness_combo">
                         <property name="visible">1</property>
-                        <property name="has-entry">1</property>
-                        <property name="halign">fill</property>
+                        <property name="valign">center</property>
+                        <property name="margin-bottom">20</property>
                         <items>
-                          <item translatable="yes" id="Less than 15 minutes">Less than 15 minutes</item>
-                          <item translatable="yes" id="15 to 30 minutes">15 to 30 minutes</item>
-                          <item translatable="yes" id="30 to 45 minutes">30 to 45 minutes</item>
-                          <item translatable="yes" id="45 minutes to an hour">45 minutes to an hour</item>
-                          <item translatable="yes" id="More than an hour">More than an hour</item>
+                          <item translatable="yes" id="mild">Mild</item>
+                          <item translatable="yes" id="spicy">Somewhat spicy</item>
+                          <item translatable="yes" id="hot">Hot</item>
+                          <item translatable="yes" id="extreme">Very spicy</item>
                         </items>
                       </object>
                       <packing>
                         <property name="left-attach">1</property>
-                        <property name="top-attach">3</property>
+                        <property name="top-attach">8</property>
                       </packing>
                     </child>
+
                     <child>
-                      <object class="GtkComboBoxText" id="cook_time_combo">
+                      <object class="GtkLabel">
                         <property name="visible">1</property>
-                        <property name="has-entry">1</property>
-                        <property name="halign">fill</property>
-                        <items>
-                          <item translatable="yes" id="Less than 15 minutes">Less than 15 minutes</item>
-                          <item translatable="yes" id="15 to 30 minutes">15 to 30 minutes</item>
-                          <item translatable="yes" id="30 to 45 minutes">30 to 45 minutes</item>
-                          <item translatable="yes" id="45 minutes to an hour">45 minutes to an hour</item>
-                          <item translatable="yes" id="More than an hour">More than an hour</item>
-                        </items>
+                        <property name="label" translatable="yes">Description (optional)</property>
+                        <property name="xalign">0</property>
+                        <style> <class name="heading"/> </style>
                       </object>
                       <packing>
-                        <property name="left-attach">1</property>
-                        <property name="top-attach">4</property>
+                        <property name="left-attach">0</property>
+                        <property name="top-attach">9</property>
+                        <property name="width">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkScrolledWindow">
+                        <property name="visible">1</property>
+                        <property name="shadow-type">in</property>
+                        <property name="min-content-height">120</property>
+                        <child>
+                          <object class="GtkTextView" id="description_field">
+                            <property name="visible">1</property>
+                            <property name="wrap-mode">word</property>
+                            <property name="top-margin">10</property>
+                            <property name="left-margin">10</property>
+                            <property name="right-margin">10</property>
+                            <property name="bottom-margin">10</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="left-attach">0</property>
+                        <property name="top-attach">10</property>
+                        <property name="width">2</property>
                       </packing>
                     </child>
                     <child>
@@ -621,7 +573,7 @@
                       </object>
                       <packing>
                         <property name="left-attach">0</property>
-                        <property name="top-attach">5</property>
+                        <property name="top-attach">11</property>
                         <property name="width">2</property>
                       </packing>
                     </child>
@@ -643,7 +595,7 @@
                       </object>
                       <packing>
                         <property name="left-attach">0</property>
-                        <property name="top-attach">6</property>
+                        <property name="top-attach">12</property>
                         <property name="width">2</property>
                       </packing>
                     </child>
@@ -655,7 +607,7 @@
                       </object>
                       <packing>
                         <property name="left-attach">0</property>
-                        <property name="top-attach">7</property>
+                        <property name="top-attach">13</property>
                         <property name="width">2</property>
                       </packing>
                     </child>
@@ -669,7 +621,6 @@
     </child>
   </template>
   <object class="GtkPopover" id="ingredient_popover">
-    <property name="relative-to">add_ingredient_button</property>
     <property name="position">top</property>
     <child>
       <object class="GtkBox">
@@ -728,7 +679,7 @@
             <property name="visible">1</property>
             <property name="label" translatable="yes">Add</property>
             <property name="halign">end</property>
-            <signal name="clicked" handler="add_ingredient2" swapped="yes"/>
+            <signal name="clicked" handler="add_ingredient2"/>
           </object>
         </child>
       </object>
diff --git a/src/gr-ingredients-list.c b/src/gr-ingredients-list.c
index 86d0ec4..51ff26f 100644
--- a/src/gr-ingredients-list.c
+++ b/src/gr-ingredients-list.c
@@ -43,6 +43,7 @@ typedef struct
         gdouble value;
         gchar *unit;
         gchar *name;
+        gchar *segment;
 } Ingredient;
 
 static void
@@ -58,6 +59,7 @@ struct _GrIngredientsList
         GObject parent_instance;
 
         GList *ingredients;
+        GHashTable *segments;
 };
 
 G_DEFINE_TYPE (GrIngredientsList, gr_ingredients_list, G_TYPE_OBJECT)
@@ -222,6 +224,7 @@ parse_as_unit (Ingredient  *ing,
 static gboolean
 gr_ingredients_list_add_one (GrIngredientsList  *ingredients,
                              char               *line,
+                             char               *segment,
                              GError            **error)
 {
         Ingredient *ing;
@@ -250,6 +253,8 @@ gr_ingredients_list_add_one (GrIngredientsList  *ingredients,
         else
                 ing->name = g_strdup (line);
 
+        ing->segment = g_strdup (segment);
+
         ingredients->ingredients = g_list_append (ingredients->ingredients, ing);
 
         return TRUE;
@@ -262,15 +267,31 @@ gr_ingredients_list_populate (GrIngredientsList  *ingredients,
 {
         g_auto(GStrv) lines = NULL;
         int i;
+        g_autofree char *segment = NULL;
 
         lines = g_strsplit (text, "\n", 0);
 
         for (i = 0; lines[i]; i++) {
-                if (!gr_ingredients_list_add_one (ingredients, lines[i], error))
+                char *p;
+                p = strrchr (lines[i], '\t');
+                if (p) {
+                        segment = g_strdup (p + 1);
+                        *p = 0;
+                }
+                else
+                        segment = NULL;
+
+                if (segment)
+                        g_hash_table_add (ingredients->segments, g_strdup (segment));
+                if (!gr_ingredients_list_add_one (ingredients, lines[i],
+                                                  (char *)(segment ? segment : ""), error))
                         return FALSE;
         }
 
-       return TRUE;
+        if (g_hash_table_size (ingredients->segments) == 0)
+                g_hash_table_add (ingredients->segments, g_strdup (""));
+
+        return TRUE;
 
 }
 
@@ -280,6 +301,7 @@ ingredients_list_finalize (GObject *object)
         GrIngredientsList *self = GR_INGREDIENTS_LIST (object);
 
         g_list_free_full (self->ingredients, (GDestroyNotify)ingredient_free);
+        g_hash_table_unref (self->segments);
 
         G_OBJECT_CLASS (gr_ingredients_list_parent_class)->finalize (object);
 }
@@ -287,6 +309,7 @@ ingredients_list_finalize (GObject *object)
 static void
 gr_ingredients_list_init (GrIngredientsList *ingredients)
 {
+        ingredients->segments = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 }
 
 static void
@@ -452,16 +475,24 @@ gr_ingredients_list_scale (GrIngredientsList *ingredients,
 }
 
 char **
-gr_ingredients_list_get_ingredients (GrIngredientsList *ingredients)
+gr_ingredients_list_get_segments (GrIngredientsList *ingredients)
+{
+        return (char **)g_hash_table_get_keys_as_array (ingredients->segments, NULL);
+}
+
+char **
+gr_ingredients_list_get_ingredients (GrIngredientsList *ingredients,
+                                     const char        *segment)
 {
         char **ret;
         int i;
         GList *l;
 
         ret = g_new0 (char *, g_list_length (ingredients->ingredients) + 1);
-        for (i = 0, l = ingredients->ingredients; l; i++, l = l->next) {
+        for (i = 0, l = ingredients->ingredients; l; l = l->next) {
                 Ingredient *ing = (Ingredient *)l->data;
-                ret[i] = g_strdup (ing->name);
+                if (g_strcmp0 (segment, ing->segment) == 0)
+                        ret[i++] = g_strdup (ing->name);
         }
 
         return ret;
diff --git a/src/gr-ingredients-list.h b/src/gr-ingredients-list.h
index f15c9c7..086c647 100644
--- a/src/gr-ingredients-list.h
+++ b/src/gr-ingredients-list.h
@@ -39,7 +39,9 @@ char              *gr_ingredients_list_scale_unit      (GrIngredientsList  *ingr
                                                         const char         *name,
                                                         int                 num,
                                                         int                 denom);
-char             **gr_ingredients_list_get_ingredients (GrIngredientsList  *ingredients);
+char             **gr_ingredients_list_get_segments    (GrIngredientsList  *ingredients);
+char             **gr_ingredients_list_get_ingredients (GrIngredientsList  *ingredients,
+                                                        const char         *segment);
 
 
 G_END_DECLS
diff --git a/src/gr-recipe-store.c b/src/gr-recipe-store.c
index 400376d..dd2253d 100644
--- a/src/gr-recipe-store.c
+++ b/src/gr-recipe-store.c
@@ -1230,7 +1230,7 @@ gr_recipe_store_get_all_ingredients (GrRecipeStore *self,
         GrRecipe *recipe;
         GHashTable *ingreds;
         char **result;
-        int i;
+        int i, j;
 
         ingreds = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
@@ -1239,6 +1239,7 @@ gr_recipe_store_get_all_ingredients (GrRecipeStore *self,
                 const char *ingredients;
                 GrIngredientsList *list = NULL;
                 g_autofree char **ret = NULL;
+                g_autofree char **segments = NULL;
 
                 ingredients = gr_recipe_get_ingredients (recipe);
 
@@ -1246,9 +1247,12 @@ gr_recipe_store_get_all_ingredients (GrRecipeStore *self,
                         continue;
 
                 list = gr_ingredients_list_new (ingredients);
-                ret = gr_ingredients_list_get_ingredients (list);
-                for (i = 0; ret[i]; i++)
-                        g_hash_table_add (ingreds, ret[i]);
+                segments = gr_ingredients_list_get_segments (list);
+                for (j = 0; segments[j]; j++) {
+                        ret = gr_ingredients_list_get_ingredients (list, segments[j]);
+                        for (i = 0; ret[i]; i++)
+                                g_hash_table_add (ingreds, ret[i]);
+                }
 
                 g_object_unref (list);
         }
@@ -1307,7 +1311,6 @@ gr_recipe_store_remove_favorite (GrRecipeStore *self,
                         break;
                 }
         }
-
         save_favorites (self);
 
         g_signal_emit (self, changed_signal, 0, recipe);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]