An app that helps document your unique experience and share it with others

is an iOS social travel app that allows users to document trips they take, search for other users’ trips, and plan future trips.

The aim of the application is to give travelers a unique space where they can meet to share experiences of past and current trips and ideas for future trips. New users who join the platform will receive access to a lot of ideas and practical tips about locations that can be used to plan their travels.

Our clients Maddy and Eric were inspired by the way Instagram and Pinterest let people share bits of their experiences, but they wanted an app that would be populated by a growing community of travelers. Just like Pinterest, Jet Journal is structured around visual content and is easy to use on the go.

“I wanted something specific for travelers. For people going to new places, trying new things, who wanted to share their experiences in a way mainstream social media doesn’t allow,” says Madeline.

Main features of Jet Journal


Journals contain information about particular trips. The author of a journal can invite others with whom they traveled to be co-authors. Journals can contain photos, links to tours, and places to visit in the future.


The places tab contains places and ideas that are sourced from a user’s friends, from publicly shared content, and from Google Places. Places are shown based on a user’s current location or a place they choose on the map.

Places on the map are numbered so that it’s easy to locate them in relation to other locations where users had checked in before. In the map view, there’s also a list of places at the bottom of the screen.

Users can scroll through this list and tap to see locations on the map. They can also open more places by tapping Search this area and filter places by types (museums, hotels, backeries, etc.)


User profiles include a full list of their journals along with all posts and ideas. Each user’s profile picture is a customized map that shows all the places they have journals for. Or they can change the map to any photo to make their profile unique.

Map with a list of locations

A user’s profile contains all journals, and each journal contains locations of places mentioned in this journal. Using these locations, users can plan routes or view places they’ve already visited. On the map, users can view details about these places, including addresses and pictures.


Jet Journal is centered around a feed where users can preview posts of users you’re subscribed to. However, if a user is new to the app they see posts of Jet Journal account.


Explore is where users collect ideas about travel destinations. Ideas can come in different forms: links to sightseeing tours in downtown Athens, a list of the best seafood restaurants in Barcelona, a picture of an old cathedral in rural England, and so on.

Users can search the app with filters, including:

  • People
  • Hashtags
  • Places
  • Journals

UI/ scope

To get the right feel for the design of our client’s product, we studied popular travel blogs and websites and asked Maddy to share which existing platforms she particularly likes. We started by creating a mood board and testing how it compared to our clients’ expectations. This allowed us to confirm some assumptions and move on with our design work. We also created a logo for the app.

Our project team has a lot of experience with product development in Agile environments, so we were able to react to incoming change requests in a timely manner.

The app was designed with a rich set of privacy settings in mind. Privacy settings can be adjusted to control information about users, journals, ideas, and places in posts.

Including a map where a user’s places and ideas are displayed was another UX challenge because we wanted to avoid cluttering the screen.

Engineering challenges:

Designing complex screens with the help of a form builder

Jet Journal has multiple screens that can be filled with different types of data. To make sure our design was consistent and easy to work with, we created a form builder to create and change screens depending on the type of data that’s being displayed.

To do this, we presented screens of the app as tables with multiple sections. Each screen of this type uses the FormView protocol and uses the configure() method to create the initial table layout. All sections in this table are connected with the help of the SectionModelType protocol, which assumes that each section has multiple elements, called items.

Each item is an element that belongs to the FormField enum. Items can be initialized with parameters that are then processed in one of the table cells. By using this form builder, we were able to avoid duplicate code and significantly reduce development time for complex screens with various types of data.

Using DataSources to process data arrays

Jet Journal works with various data arrays (posts, journals, and images), and this data can be received on a page-by-page basis or all at once. Some screens display several arrays at the same time; for example, users can switch between post, journal, and idea tabs in their profiles.

Methods for processing these types of data are similar, which is why we needed to find a common approach for processing all these data arrays. To do that, we used DataSources. DataSource behavior is controlled by a shared protocol that contains an Observable array of data and methods for data processing (deletion, changes, and requests for the next page of data)

We also added a default way of implementing certain methods (for example, a method to request the next portion of data) to this protocol. As a result, we were able to reuse a lot of our code in different classes and all data was processed using the same logic regardless of data type. We were also able to reduce the amount of code and make it easier to work with.


As the app scaled, we noticed that performance was decreasing. One of the reasons for this reduced performance was that our UI included a lot of images with rounded edges.

We initially used the layer.cornerRadius of the UIView class to create rounded edges, but this function significantly affected the app’s performance.

To resolve this issue, we created a method that belongs to the UIImage class that rounds image edges with the help of UIBezierPath. This modification doesn’t change the quality of the images, but processing is no longer done in the main thread of the app and thus doesn’t slow it down.

Introducing support for hashtags, mentions, and links

We needed to make sure the app supported hashtags, mentions, and links. In particular, it had to recognize these objects in text, highlight them, and react when hashtags, mentions, and links are pressed (for example, by switching screens between the profile screen and the list of journals).

We decided to use the ActiveLabel library since it perfectly fit out needs. ActiveLabel is lightweight and easy to use. It also has support for custom types via regex. This allowed us to use ActiveLabel to implement expandable text functionality.

Finding the ideal solution for image processing

Jet Journal is an image-rich app: users pick profile photos, then add photographs and other images to journals and posts. We needed to make sure that image processing was fast and efficient.

We wanted to find a solution that would let users easily pick a fragment of an image, rotate it, then add it to a journal or post.

TOCropViewController is an open-source component that helped us implement this functionality. With its help, we were able to crop images by dragging the edge of a grid overlay, crop circular copies of images, and fix the crop box to a specific aspect ratio. TOCropViewController is adjustable and easy to use.

Technology stack

RxSwift — A Swift implementation of reactive programming concepts. Reactive programming is an asynchronous programming paradigm concerned with data streams and change propagation. These concepts allowed us to reduce work related to updating the UI and add handy methods for data manipulations.

EventNode — An app routing paradigm and its implementation that allows developers to encapsulate routing-related tasks from all applications by grouping all MVC/MVVM submodules into separate flows. Developed by Yalantis’ iOS team.

Google Maps — A mapping service developed by Google that allows us to fully customize the way maps are presented; used for displaying places users have been.

APIClient — A network layer abstraction over the Alamofire framework; used for all network-related tasks. Developed by Yalantis’ iOS team.

DBClient — A database layer abstraction over the Core Data framework; used for all database-related tasks. Developed by Yalantis’ iOS team.

ActiveLabel — A reach UI component that supports hashtags (#hashtag) and user mentions (@user) in native UILabel components.

TOCropViewController — An awesome image cropping UI component; used for all image uploading in order to select the desired part of an image.

SlackTextViewController — A UIViewController subclass that includes a fully customizable input toolbar; used for comment flow.

Kingfisher — A library for downloading and caching images; this library handles all image fetching operations to reduce internet traffic.

Crashlytics by — A crash reporting library.

Application architecture:

The application’s architecture is based on the Model–View–View-Model (MVVM) pattern with the EventNode paradigm for routing. Each module (e.g. each screen with its model, view model (if present) and views) represents an EventNode and uses a treelike linking structure to deliver routing signals to the appropriate part of the application.

The diagram above demonstrates a single module profile. Black arrow shows that one component stores another in memory. The green path represents the simple logout flow –the user clicks the Logout button in the ProfileViewController, which passes the action to its ViewModel, which propagates it to the ProfileModel. The ProfileModule raises the signal (green dashed line) to its parent EventNode. Every node in the tree should either handle the signal or propagate it to its parent.

Almost all modules in the application have an MVVM structure. The example below demonstrates one of them — Journal Details.

Here, the black arrows show that one component stores another in memory. The yellow path shows that a user has initiated data fetching or reloading. This action starts with a ViewController and goes to a DataProvider. The DataProvider fetches data and passes it back (along the red path) using promises. Once the data reaches the model, the ViewModel refreshes the View (here we adopted RxCocoa with its bindings).

The Jet Journal app was developed to help people enjoy their traveling, and is an example of a product that was well thought through and implemented with real users’ needs in mind. Maddy, who came up with the idea for this app, and her father, who was doing the backend development, performed the function of product owners and worked in close cooperation with our development team throughout all stages of the project.

The key to successful project delivery was, of course, timely and effective communication and gathering detailed feedback from real users who were asked to test the application.

Source link—-819cc2aaeee0—4


Please enter your comment!
Please enter your name here