In this tutorial we will create a view for notes with a rich text editor for editing the body of the note. We will introduce the custom renderer which enables you take full control of the render area for your view. We will also set up a context pane for a note and configure it with relevant actions.

We are designing the CVU (pronounced as: c view) language. CVU stands for Cascading View. It’s a language that is easy to understand and allows you to control your view (or perspective) on your information. Think of it as the window through which you can see your information. The CVU language describes how you view your data, such as notes, emails, messages and photos.

Follow this tutorial below, or jump to another part of this series to learn more about the CVU language.

We're building a simple view for a note. The note has a title property which holds the description of the note. The contents property holds the body of the note as HTML. We'll define a view in the CVU language that will render the title in a TextField and the contents in a RichTextField.

Let's create the basic cvu definition for a single note:

Note {
    title: {{title}}
    editActionButton: toggleEditMode
    filterButtons: showContextPane
}

We'll set the title of the screen to the title of the note. The action button in the top right will toggle the edit mode on and off. Finally the filterButtons configure the buttons in the bottom right in the search area. They show a button that shows the context pane (see more about that below).

Next we'll configure the renderer for the view. In this case we use the custom renderer that allows us to fill the entire renderer area that sits between the top toolbar and the bottom search bar.

Note {
    [renderer = custom] {
    
    }
}

The following cvu code creates a TextField and RichTextField to edit the title and content properties of the note. The first element in the custom view is a VStack which stacks its children vertically. With the padding and spacing properties we bring the elements into place.

Note {
    [renderer = custom] {
        VStack {
            padding: 10
            spacing: 5

            TextField {
                value: {{.title}}
                hint: "Enter a title",
                color: lightInputText
                font: {{ setting('/user/gui/fontSize/heading/note') }} semibold
            }
            RichTextField {
                value: {{.contents}}
                color: inputText
                fontSize: {{ setting('/user/gui/fontSize/text/note') }} 
            }
        }
    }
}

The TextField's value is set to the title property of the note that is loaded in this view. It has a hint message that shows when the title is empty and the color is set to a named color lightInputText. Lastly the font is set to an expression for the size of the font and the boldness is set to semibold which is in between regular and bold text.

The font expression fetches a setting. Settings in memri are paths that can occur anywhere in an expression and will fetch a value from the settings stored in the database. There are three kinds of settings:

  • User settings are available on every device of the same user
  • Device settings are available on a specific device
  • Default settings are like factory settings of the memri browser

User and device settings can be set by the views and users directly. In this case the settings for heading is used in the user settings. Memri will first find a setting under /user/gui/fontSize/heading/note and if that is not set it will use the more general setting /user/gui/fontSize/heading.

Users can set their preferences in the settings area of memri:

A user defined view

Everyone uses their notes differently. You may never change font settings often, yet others may change them constantly to show others, or because they don't wear their glasses all of the time. Let us, for argument sake imagine that we are a user that wishes to change the font settings on a daily basis. We'll create a user view that alters the view we just defined to get what we want.

/* User defined view */
Note {
    filterButtons: [
        setSetting {
            icon: plus
            arguments {
                path: "/user/gui/fontSize/text/note"
                value: {{ setting('/user/gui/fontSize/text/note') + 1 }}
            }
        }
        setSetting {
            icon: min
            arguments {
                path: "/user/general/ui/fontSize/text/note"
                value: {{ setting('/user/gui/fontSize/text/note') - 1 }}
            }
        }
    ]
}

With the above cvu we create a user defined view. As you may remember from the cascading view article, the user defined views always take priority over any other views. In this case, we add two buttons to the filterButtons. These are the buttons on the right bottom corner of the screen in the search bar.

The first button will display a + icon and when tapped will add one to the headingSize setting. The second button does the opposite and subtract one fro that setting.

In order to keep the user from create a size that is too big or too small we can use the min() and max() functions to keep the change in their bounds:

value: {{ min(30, setting('/user/gui/fontSize/text/note') + 1) }}
value: {{ max(1, setting('/user/gui/fontSize/text/note') - 1) }}

Check out the new Memri forum where all Memri engineers are active to answer questions and participate in discussions. You can find all the memri source code on the Memri gitlab.

Continue to learn about sub views or pick a topic you want to dive in from the list below.