Developing for offline use
Related links:
For a static presentation, minimal work is required to prepare for a potential loss of internet connectivity during a presentation. However, there are several use-cases and features where clear offline mode communication is required to provide a smooth and informed experience despite any connectivity hiccoughs.
What you get "for free"
LivePreso provides offline support by syncing content and data to a user's local copy of the app - this covers the latest approved deck version, and any approved deck version used by a preso scheduled 14 days prior and 14 days proceeding (28 day period).
Included in the sync:
- Custom slides
- Caching of dynamic images uploaded to editable slides, PresoManager editable Slides and templates
- Current context and feeds data associated to the synced preso
- Context and feeds image caching (see below)
Caching is available for images supplied as URLs to both the context and feeds. Learn how to make use of this feature in the image caching guide below.
Unapproved deck versions (Author Approval and Client Approval) are never synced to an app, even if they were used to generate a preso that falls within the 28 day syncing period. Read more about LivePreso approval statuses here.
What is not supported in offline mode?
While cached presentations can continue in offline mode, any app functionality that requires an internet connect to create or update cannot. This includes, but is not limited to:
- Creating a new preso
- Editing an existing preso (preso details page)
- Uploading a custom slide
- Sending PDF, shares, invites
- Creating/editing a preset
- Adding a customer
- Updating a deck in PresoManager
- etc.
Similarly, the following content functionality is also not supported in offline mode:
- Context updates
- Updating editable slides
- API requests (eg. fetching new data)
- Ordering and visibility updates made to slides and subslides
Any slide ordering and visibility updates made while in offline mode are applied for the current session but not saved. Context changes are pushed to the server when the user navigates to a new slide and/or closes the preso, if a user does not reconnect before performing one of these actions their context changes will not be saved. This means a user could return to their preso to find any updates they made while offline have been reset.
When an online-only feature is encountered in offline mode, it is important to clearly communicate the situation to the user and provide a graceful fallback where possible.
An example of a graceful fallback would be to display an offline mode indicator icon so they know as soon as they land on the affected slide, and a contextual message triggered when they initiate the online-only action. Continue reading to learn how to detect offline mode and provide the best user experience possible.
How to cache images
The majority of dynamic images used in presos are supplied as URL links to an online resource, and as such, you will need to know how to cache these images for offline use.
We offer a simple way to cache images available to both the context and feeds:
Context
Caching images stored here is as straight forward as saving the desired URL to the context on preso creation and edit, that's it!
The image will be cached automatically and the corresponding field updated to reference the cached image - no need for the content to switch between "live" and "cached" references as it all happens behind the scenes.
Any URLs added to the context during a presentation will not be cached unless the user returns to the preso details page, edits and saves the preso.
Feeds
The process of caching images included in a feed requires a couple more steps than caching in the context, but it's still pretty breezy.
In order to specify what images to cache, you first need to know the expected output of the data feed providing the images.
Example feed data:
{
"feature_image": "https://foo.bar/feature.png",
"products": [
{
"code": "12",
"title": "highlight",
"images": ["https://foo.bar/prod-1.png", "https://foo.bar/prod-2.png"]
},
{
"code": "56",
"title": "feature",
"images": ["https://foo.bar/prod-5.png", "https://foo.bar/prod-6.png"]
}
],
"promotions": [
{
"marketing": {
"code": "market-1-poster",
"title": "A4 poster",
"image": "https://foo.bar/market-1.png"
},
"code": "market-1",
"title": "January campaign"
},
{
"marketing": {
"code": "market-2-TVC",
"title": "TVC",
"image": "https://foo.bar/market-2.png"
},
"code": "market-2",
"title": "TVC"
}
]
}
From here, we are going to use JSONSelect to specify in the project.yaml file where the images we wish to cache are located in the feed:
feeds:
products:
source: "/api/products/?filter_id={{ filter_id }}"
preprocessors:
- UseServerHostname
- AuthenticateWithSalesPresoApi
offline_images:
- .feature_image
- .products .images
- .promotions .marketing .image
And there we go! Now when presos are created using this deck version, all images declared in this fashion will be cached to the user's app.
Learn how to review cached images in the CDK.
Offline mode detection
For online-only features (eg. fetching new data, updating the context, sorting slides etc.) we provide offline mode detection methods, giving you the opportunity to communicate the situation to the user, and provide a graceful fallback to deliver the best possible experience.
There are three options available for offline mode detection, each with a particular use-case it endeavours to service.
Body class
When a preso is being viewed in offline mode, the class offline
is
added to the body of the LivePreso app, and conversely, when online
online
will be present instead.
We recommend using this for simple style changes such as toggling any offline notifications or icons, visually disabling any affected buttons etc.
<body class="offline">
<!-- LivePreso -->
</body>
Example:
Show/hide an offline indicator icon when the internet connectivity status changes.
#slideshow .icon-offline {
display: none;
width: 64px;
height: 64px;
background: url("css/icons/offline.svg") center/contain no-repeat;
.offline & {
display: flex;
}
}
Bridge flag
When crafting JS logic, you may prefer to access a simple flag instead
of querying a body class. Well, we have you covered! Whenever you need
to know the preso's current connection status, you can check the flag
Bridge.Status.isOnline
for a boolean of the preso's online status.
Example:
The client has briefed in a slide with the ability to sort subsequent slides based on a list of priorities ordered by the user during the presentation. As slide sorting is a feature not supported in offline mode, any sorting applied will be honoured for the duration of the current presentation but not saved.
The proposed offline mode fallback is to permit the sorting action (allowing the conversation to progress), but notify the user that these changes will be reset if they are to return to the preso in the future.
const $slideArticle = Bridge.Slides.getArticle();
$slideArticle.on("slideready", () => {
$(".js-sort-slides-btn", $slideArticle).on("click", () => {
if (Bridge.Status.isOnline) {
// Sort slides - changes will be saved to the preso
sortSlides();
} else {
// Trigger a toast communicating to the client the
// limitations of sorting slides while offline
let $toast = $("<p/>")
.text("No internet connection, sorting changes will not be saved")
.addClass("toast");
$slideArticle.append($toast);
setTimeout(() => {
$toast.remove();
}, 2000);
// Sort slides - for current presentation session only
sortSlides();
}
});
});
Bridge event
We also offer a Bridge event that your deck can listen into for those use-cases where a stable internet connection is integral to a slide's functionality, and the design and interactivity needs to adjust accordingly as the connection status updates to keep the client informed and the presentation running smoothly.
Example 1:
A calculator slide has been requested that can be filled in during a presentation with the client. Similar to the slide sorting example given above, any changes made to the calculator in offline mode will persist for the current session, but will not be saved to the preso.
A suggested fallback is to provide an offline indicator icon with a brief message (eg. "changes cannot be saved while offline"), coupled with a toast that notifies the user when internet connectivity is updated.
const $slideArticle = Bridge.Slides.getArticle();
$slideArticle.on("slideready", () => {
// Offline mode indicator icon and message
const $offlineIndicator = $(".js-offline-indicator", $slideArticle);
function createToast({ $target, message }) {
let $toast = $("<p/>")
.text(message)
.addClass("toast");
$target.append($toast);
setTimeout(() => {
$toast.remove();
}, 2000);
}
$("#slideshow").on("connectionChanged", (e, isOnline) => {
$offlineIndicator.toggleClass(".is-active", !isOnline);
if (isOnline) {
createToast(
$target: $slideArticle,
message: "You're back online! Calculator updates will be saved."
});
} else {
createToast(
$target: $slideArticle,
message: "You are offline, calculator updates will not be saved."
});
}
});
)};
Example 2:
A slide has been briefed to include a form and with a submit button that pushes data collected during a presentation to an endpoint. To prevent frustration if the presenter runs into connectivity problems, this Bridge event can be used to listen in for status changes, update the DOM (eg. add a message to the form and disable the submit button) and trigger a toast informing the user they are experiencing connectivity issues.
const $slideArticle = Bridge.Slides.getArticle();
$slideArticle.on("slideready", () => {
function createToast({ $target, message }) {
let $toast = $("<p/>")
.text(message)
.addClass("toast");
$target.append($toast);
setTimeout(() => {
$toast.remove();
}, 2000);
}
// A <p> tag element situated under the form
const $message = $(".js-form-message", $slideArticle);
$("#slideshow").on("connectionChanged", (e, isOnline) => {
$(".js-submit-form", $slideArticle).toggleClass(".is-disabled", !isOnline);
if (isOnline) {
createToast(
$target: $slideArticle,
message: "You're back online! Form submission reactivated."
});
$message.text("Click 'submit' to update your client's data in the CMS.");
} else {
createToast(
$target: $slideArticle,
message: "Data cannot be submitted while offline, please check your connection."
});
$message.text("Data cannot be submitted while offline.");
}
});
)};