Adding Mood Comment

Even thought superapp looks working, we still have one thing to do - database schema allows users to add comments with each Mood, but MoodSelectorScreen does not have any text entry.

To create a comment we are going to add UITextView to the MoodSelectorScreen, and we will modify MoodHistoryScreen a little bit - each time user presses on a Mood object, we will show a simple alert view with a mood description that will include the comment. Let's start with layout:

      class MoodSelectorLayout < MotionKit::Layout
        def layout
          add UILabel, :select_mood_label
          add UILabel, :comment_label
          add UITextView, :comment
          add UIButton, :awesome
          add UIButton, :good
          add UIButton, :average
          add UIButton, :bad
        end

        # rest of the layout code ...

        def comment_label_style
          text "Comment:"
          text_color :gray.uicolor
          constraints do
            top.equals(:select_mood_label, :bottom).plus(20)
            left.equals(:superview, :left).plus(25)
          end
        end

        def comment_style
          font "Helvetica".uifont(18)

          layer do
            border_color :gray.cgcolor
            border_width 1
            corner_radius 7
          end

          constraints do
            top.equals(:comment_label, :bottom).plus(5)
            left.equals(:superview, :left).plus(25)
            right.equals(:superview, :right).minus(25)
            height(90)
          end
        end

        # rest of layout code ...

        def awesome_style
          shared_button_style

          title "Awesome"
          constraints do
            center_x.equals(:superview, :center_x)

            # update top constraint:
            top.equals(:comment, :bottom).plus(50)
          end
        end

        # rest of layout code ...
      end
      
If you will launch the app your MoodSelectorScreen will look like this:

Now we need to save the comment with a new Mood object. To do it, we need to access the text view in the layout, and then get it's text and save it to mood.comment:

        class MoodSelectorScreen < PM::Screen
          title "Mood Selector"

          # MoodSelectorScreen code ...

          def on_load

            # on_load code ...

            @comment = @layout.get(:comment)
          end

          # MoodSelectorScreen code ...

          def set_mood(level)
            if @forecast.is_a?(Hash) && @location.is_a?(Hash)
              mood = Mood.create level: level,
                created_at: NSDate.now,
                comment: @comment.text

              # rest of the set_mood code ...
            end
          end
        end
        
With these small modifications that took two lines of code, users can add comments to the Mood object. Let's allow them to read it.

Displaying Mood Comments

The user should be able to read a summary for each Mood object. It will be a simple alertView with mood level in the title, and comment with a forecast in the alert view body. Let's generate this summary in a Mood model, so each instance will have a summary method that will return it in a Hash:

        class Mood
          include MotionRealm
          include BaseObjectMethods

          def summary
            mood_name = "Not set"
            if self.level == 4
              mood_name = "Awesome"
            elsif self.level == 3
              mood_name = "Good"
            elsif self.level == 2
              mood_name = "Average"
            elsif self.level == 1
              mood_name = "Bad"
            end

            message = ""
            if self.comment.is_a?(String) && !self.comment.empty?
              message += self.comment
            end

            if self.forecast.is_a?(Forecast)
              weather = self.forecast.summary.gsub("-", " ")
              temp = self.forecast.temperature
              message += "\n\nIt was #{weather}, with a temperature around #{temp}°"
            end

            { title: mood_name, message: message }
          end
        end
        
Here we check the level of a current mood object to generate a readable title. Then we check if a user has a comment for the mood, and if it is not empty, we add it to a message. And the same for the forecast: we get its summary, replace - symbols with spaces for better readability, added a temperature. In the end, we return it as a hash.

So where are we going to use this summary? I think the best place is to show it when the user taps on a Mood cell in a MoodHistoryScreen.

To process tap on each cell UITableView has a delegate method called tableView(table, didSelectRowAtIndexPath: index). It passes an index of a selected cell, so we can easily figure out which mood has been tapped. Then when we got the mood object from the DB we just need to call new summary method and show an alert view:

        def tableView(table, didSelectRowAtIndexPath: index)
            @table.deselectRowAtIndexPath index, animated: true
            mood_cell = @data[index.section][:cells][index.row]
            mood_id = mood_cell[:id]
            mood = Mood.where("id = #{mood_id}").first
            return if !mood.is_a?(Mood)

            summary = mood.summary
            UIAlertController.alert self, summary[:title],
              message: summary[:message],
              buttons: ["OK"]
          end
        

UI Enhancements

Since we started to enhance MoodSelectorScreen, let's make it look better, and its code more readable.

First we will make its buttons prettier with a thin blue border with rounded corners outside. The text will be blue as well, and the background is white. To do it we need to update only one method - shared_button_style. This method defines all shared button attributes and used on every button on the screen.

        def shared_button_style
          content_edge_insets UIEdgeInsetsMake(6, 15, 6, 15)
          title_color 0x0080FF.uicolor
          background_color :white.uicolor
          layer do
            border_color 0x0080FF.cgcolor
            border_width 1
            corner_radius 7
          end
        end

        def awesome_style
          shared_button_style

          title "Awesome 😀"
          constraints do
            center_x.equals(:superview, :center_x)
            top.equals(:comment, :bottom).plus(50)
          end
        end

        # Rest of the layout code ...
        
After this small update, the screen should look much better. As you can see we also have updated button titles:

Refactoring

As you may noticed there are some places where we were repeating the code. For example button titles and Mood's summary - they both have same mood level names - Awesome, Good, etc. Just now we changed titles on buttons, but Mood's summary has not been affected. If we want them to be affected as well, we have to edit Mood model.

However, there is a better way of doing it. Mood model could return us mood level name automatically. Something like

        Mood.name_for(4)
        # => "Awesome"
      
In this case, we would update mood names once, at they would be changed everywhere automatically. Let's try it.
        class Mood
          include MotionRealm
          include BaseObjectMethods

          def self.name_for(level)
            if level == 4
              "Awesome 😀"
            elsif level == 3
              "Good 😊"
            elsif level == 2
              "Average 🙂"
            elsif level == 1
              "Bad 🙁"
            else
              "Not set"
            end
          end

          def summary
            mood_name = Mood.name_for(self.level)

            # rest of the summary code ...
          end

          # rest of the Mood model code ...

        end
        
And MoodSelectorLayout:
        class MoodSelectorLayout < MotionKit::Layout
          # layout code ...

          def awesome_style
            shared_button_style

            title Mood.name_for(4)

            # ...
          end

          def good_style
            shared_button_style

            title Mood.name_for(3)

          def average_style
            shared_button_style

            title Mood.name_for(2)

            # ...
          end

          def bad_style
            shared_button_style

            title Mood.name_for(1)

            # ...
          end
        end
      

We have finished this chapter, and it is time to do a traditional commit:

        git add .
        git commit -m "added comment view"
      

Summary

In this chapter, we finally allowed users to add comments to the Mood objects and made MoodeSelectorScreen look better. Besides, we learned and tried to make a small refactoring in order not to repeat the code.

Book Index | Next