Skip to content

crm_sdk: screens and widgets

The screens, the overlay and the widgets package:crm_sdk/crm_sdk.dart exports, and the theme they are drawn with.

import 'package:crm_sdk/crm_sdk.dart';
NameWhat it is
CrmArticleScreenOne article: its title, its words, “Was this helpful?”, the articles beside it, and a way to send us a message; its shape standing in for it until it arrives.
CrmCarouselPresenterShows a carousel until it is done.
CrmCarouselSessionWhat a presenter tells PurrCRM about a carousel as the guest goes through it, and what it may ask of the host.
CrmCollectionOne collection of articles: what it is about and its articles, its shape standing in for it until it arrives.
CrmConversationScreenOne conversation in the messenger, or a new one when conversationId is empty: the parts as bubbles, the guest’s on the right in PurrCRM’s accent and staff’s on the left beside their initial and under their first name, in runs, with the time under each run and a line where a day starts; the rating prompt when the conversation asks for one, and the composer at the foot.
CrmCountBadgeThe count of unread replies, on a row or a button: the ground’s colour on the text’s, and drawn for nobody but the eye (the row or the button says the count to a screen reader).
CrmFlutterCarouselPresenterThe package’s presenter, drawn by Flutter.
CrmHelpCenterThe help center: a search over every article, pinned under the top bar as the page scrolls, the topics (collections, each with what it is about and how many articles it has) and the popular articles, and, where the messenger is on, a way to send us a message.
CrmImageForMakes the picture at an https url: by default the cached network image every picture of PurrCRM’s uses, so that a picture precached before a carousel opens is the one it draws.
CrmInboxListThe guest’s notices, newest first, each with when it came and a dot while it is unread, and a button for older ones while there are more.
CrmMessengerScreenThe messenger’s first screen: the team’s faces, “Talk to the product’s team”, how soon we usually reply (or when we are back), “Send us a message”, the guest’s open conversations (who wrote last, what, when, and how many replies are unread), the tickets with where each has got to, a few help articles where the help center is on, and the conversations that are closed.
CrmMotionHow PurrCRM moves: the canvas’s timings and curves, and none at all when the phone has asked for no animations (still).
CrmNoticeTileOne notice: its title, its body, when it came, and a dot while it is unread.
CrmNoticesBuilderBuilds with the guest’s inbox (Crm.notices), again whenever it changes: for the count on a host’s bell, or a host’s own inbox.
CrmOverlayShows the in-app messages of the CrmScope’s facade over child: a host puts it over its routes, once, in its MaterialApp’s builder (under the CrmScope, above the Navigator).
CrmPreferencesScreenThe preferences screen: each topic a group of switches, one a channel, kept as the guest turns them (the switch moves at once, and goes back with a sentence when PurrCRM does not keep it); a line under the heading that says when they are saved; and the way to turn everything off.
CrmRadiiPurrCRM’s corner radii, from the smallest part to a sheet.
CrmRowOne row: something on the left (leading, often a CrmRowIcon), a title and a line under it, and something on the right (trailing: a count, a pill).
CrmRowGroupRows gathered on one rounded surface, with a line between each, under an optional small heading.
CrmRowIconA row’s picture: an icon in a rounded square, tinted.
CrmSizesThe sizes of PurrCRM’s parts, in logical pixels: the heights of its buttons and rows, its round buttons and icon tiles, and the widths its words are kept to.
CrmSpacingThe steps PurrCRM is laid out in, in logical pixels.
CrmTestModeBannerchild, with a small “CRM TEST” ribbon across a corner while the facade is in test mode, as Flutter’s own DEBUG banner is drawn.
CrmTestPhoneTileThe Test phone group, for a guest staff chose as a test phone (as the last check-in said, Crm.testPhone) and nobody else: “Check for tests now”, which asks PurrCRM at once for the tests sent from PurrCRM site and says what came (Crm.checkNow).
CrmThemePurrCRM’s theme, as a ThemeExtension of the host’s ThemeData.
CrmTicketScreenOne ticket: its title and where it has got to (CrmTicketStepper), what staff wrote it is for, the fields the guest may see, and the conversation about it with a composer at the foot, waited on as a conversation is.
CrmTicketsThe guest’s tickets, the most recently changed first, each with its ref and where it has got to: read as the page opens, again on coming back from a ticket and when it is pulled down.
CrmTypographyPurrCRM’s type: the families its explicit styles are set in, and those styles.
CrmUnreadBuilderBuilds with the messenger’s count of unread replies (Crm.unread), again whenever it changes: for the badge on a host’s own button or row that opens the messenger. 0 with no CrmScope above it.
NavigatorCrmNavigatorShows PurrCRM’s pages on the host’s navigatorKey’s Navigator, each as a page of its own pushed over the one the guest is on: a tapped push’s page (open) as well as a tap’s (push), since a Navigator has no place to put one in place of another.
crmNetworkImageThe picture at url, from the cache PurrCRM’s pictures share.
class CrmArticleScreen extends StatefulWidget

One article: its title, its words, “Was this helpful?”, the articles beside it, and a way to send us a message; its shape standing in for it until it arrives.

const CrmArticleScreen({Key? key, required String slug})
final String slug
abstract interface class CrmCarouselPresenter

Shows a carousel until it is done.

Future<void> present(NavigatorState navigator, CrmCarouselSession session)

Shows session’s carousel over navigator’s routes; done once it has gone, however it went.

abstract interface class CrmCarouselSession

What a presenter tells PurrCRM about a carousel as the guest goes through it, and what it may ask of the host. The overlay makes one for each carousel it shows.

Future<bool> Function(CarouselPermission)? get askPermission

Asks the phone for a permission (CrmHost.askPermission): whether it was given. Null when the host cannot, and a permission button then goes on at once.

InAppMessage get message

The message: its carousel, and whether it is a test copy.

void answered({required String screen, required List<String> answers, required List<String> path})

A choice on screen answered with answers, options’ ids.

void clicked({required String screen, required String button, String link, required List<String> path})

button of screen tapped (each time), or swiped past where it is the screen’s main button and does next; link is a link button’s.

void completed({required String screen, required List<String> path})

Taken to its end on screen.

void dismissed({required String screen, required List<String> path})

Closed on screen before its end.

void follow(String link)

Follows link with nothing said: a link button’s, once the carousel has said it ended.

void openLink(String link, {required String screen, required List<String> path, required void Function() close})

A link in screen’s words tapped: said (clicked, with the link) and followed as the content’s rules let it; close takes the carousel away first when it leads to a place in the product.

void seen({required List<String> path})

It is on the screen, opened on the first screen of path.

class CrmCollection extends StatefulWidget

One collection of articles: what it is about and its articles, its shape standing in for it until it arrives.

const CrmCollection({Key? key, required String slug})
final String slug
class CrmConversationScreen extends StatelessWidget

One conversation in the messenger, or a new one when conversationId is empty: the parts as bubbles, the guest’s on the right in PurrCRM’s accent and staff’s on the left beside their initial and under their first name, in runs, with the time under each run and a line where a day starts; the rating prompt when the conversation asks for one, and the composer at the foot. The header says how soon we usually reply; a new one starts with the team saying hello, and the help bot’s first words and question, when it speaks first.

While it is open the conversation is waited on, so a reply arrives by itself, and what arrives is marked read; the waiting stops while the product is in the background.

const CrmConversationScreen({Key? key, String conversationId = ''})
final String conversationId
class CrmCountBadge extends StatelessWidget

The count of unread replies, on a row or a button: the ground’s colour on the text’s, and drawn for nobody but the eye (the row or the button says the count to a screen reader). Nothing at all for none.

const CrmCountBadge(int count, {Key? key})
final int count
final class CrmFlutterCarouselPresenter implements CrmCarouselPresenter

The package’s presenter, drawn by Flutter. See the library’s comment.

const CrmFlutterCarouselPresenter({TargetPlatform? platform, ImageProvider<Object> Function(String) imageFor = crmNetworkImage})
final ImageProvider<Object> Function(String) imageFor

How a picture is fetched; PurrCRM’s network cache by default.

final TargetPlatform? platform

Whose look a sheet has (iOS’s page sheet, or Material’s bottom sheet on anything else); null for the host theme’s platform.

class CrmHelpCenter extends StatefulWidget

The help center: a search over every article, pinned under the top bar as the page scrolls, the topics (collections, each with what it is about and how many articles it has) and the popular articles, and, where the messenger is on, a way to send us a message. The topics and the results cross-fade as a search starts and ends, and a thin line runs under the search while one is refined. The shape of the page stands in for it until it arrives; pulled down, it is read again.

const CrmHelpCenter({Key? key, void Function()? onExit})
final void Function()? onExit

What Back does when there is no page before this one (the help center opened by a link): the host’s own page, which crmGoRoutes names.

typedef CrmImageFor = ImageProvider<Object> Function(String)

Makes the picture at an https url: by default the cached network image every picture of PurrCRM’s uses, so that a picture precached before a carousel opens is the one it draws.

class CrmInboxList extends StatelessWidget

The guest’s notices, newest first, each with when it came and a dot while it is unread, and a button for older ones while there are more. Tapping one marks it read and follows its link (Crm.openLink), unless onOpen says otherwise. empty is what an inbox with nothing in it shows, in the host’s words; a first page on its way shows the shape of a few notices, which cross-fades into them.

It is a scrolling list of its own, read again when it is pulled down, unless shrinkWrap, for a host page that scrolls itself.

const CrmInboxList({Key? key, required Widget empty, void Function(CrmNotice)? onOpen, bool shrinkWrap = false, EdgeInsetsGeometry? padding})
final Widget empty

What an empty inbox shows.

final void Function(CrmNotice)? onOpen

A notice was tapped, in place of marking it read and following its link.

final EdgeInsetsGeometry? padding

Around the list.

final bool shrinkWrap

Whether the list sizes itself to its notices and does not scroll.

class CrmMessengerScreen extends StatefulWidget

The messenger’s first screen: the team’s faces, “Talk to the product’s team”, how soon we usually reply (or when we are back), “Send us a message”, the guest’s open conversations (who wrote last, what, when, and how many replies are unread), the tickets with where each has got to, a few help articles where the help center is on, and the conversations that are closed.

Read each time it is opened, again on coming back to it from a conversation, whose replies are then read, and when it is pulled down. The shape of the page stands in for it until it arrives; a home that could not be read again stays, under a floating “Try again”.

const CrmMessengerScreen({Key? key, void Function()? onExit})
final void Function()? onExit

What Back does when there is no page before this one (the messenger opened by a link): the host’s own page, which crmGoRoutes names.

class CrmMotion

How PurrCRM moves: the canvas’s timings and curves, and none at all when the phone has asked for no animations (still).

const CrmMotion({Duration quick = const Duration(milliseconds: 150), Duration standard = const Duration(milliseconds: 250), Duration emphasis = const Duration(milliseconds: 350), Curve enter = Curves.easeOutCubic, Curve exit = Curves.easeInCubic})
final Duration emphasis

A state that matters arriving, a message coming up.

final Curve enter

What comes in eases out.

final Curve exit

What goes eases in.

final Duration quick

A control’s state.

final Duration standard

A part of a page swapped, a banner coming in.

Duration of(BuildContext context, Duration duration)

duration, or none when the phone has asked for no animations.

bool still(BuildContext context)

Whether the phone has asked for no animations.

class CrmNoticeTile extends StatelessWidget

One notice: its title, its body, when it came, and a dot while it is unread.

const CrmNoticeTile({Key? key, required CrmNotice notice, required DateTime now, void Function()? onTap})
final CrmNotice notice
final DateTime now

Against when notice came is said.

final void Function()? onTap
class CrmNoticesBuilder extends StatelessWidget

Builds with the guest’s inbox (Crm.notices), again whenever it changes: for the count on a host’s bell, or a host’s own inbox. An empty inbox with no CrmScope above it.

const CrmNoticesBuilder({Key? key, required Widget Function(BuildContext, CrmNotices) builder})
final Widget Function(BuildContext, CrmNotices) builder
class CrmOverlay extends StatefulWidget

Shows the in-app messages of the CrmScope’s facade over child: a host puts it over its routes, once, in its MaterialApp’s builder (under the CrmScope, above the Navigator).

const CrmOverlay({Key? key, required GlobalKey<NavigatorState> navigatorKey, required Widget child, CrmCarouselPresenter carouselPresenter = const CrmFlutterCarouselPresenter()})
final CrmCarouselPresenter carouselPresenter

How a carousel is shown: the package’s, drawn by Flutter in the look of the host theme’s platform, unless the host names a platform (CrmFlutterCarouselPresenter(platform: TargetPlatform.iOS)) or a presenter of its own.

final Widget child
final GlobalKey<NavigatorState> navigatorKey

The host’s Navigator, which a full-screen message is pushed on and a survey’s sheet is shown over: its router’s (GoRouter.routerDelegate.navigatorKey), or its MaterialApp’s navigatorKey.

class CrmPreferencesScreen extends StatefulWidget

The preferences screen: each topic a group of switches, one a channel, kept as the guest turns them (the switch moves at once, and goes back with a sentence when PurrCRM does not keep it); a line under the heading that says when they are saved; and the way to turn everything off. Pulled down, it reads them again.

wording is the version of the words the guest agrees under, kept with each choice: the package’s own by default. onExit is what Back does when there is no page before it.

const CrmPreferencesScreen({Key? key, void Function()? onExit, String wording = crmPreferencesWording})
final void Function()? onExit
final String wording
class CrmRadii

PurrCRM’s corner radii, from the smallest part to a sheet. The defaults are the package’s own.

const CrmRadii({double tag = 8, double cell = 10, double cellLarge = 12, double rowIcon = 13, double row = 16, double notice = 18, double bubble = 20, double bubbleJoined = 6, double tile = 22, double composer = 24, double card = 24, double hero = 28, double sheet = 32, double pill = 999})
final double bubble

A message’s bubble.

final double bubbleJoined

A bubble’s corner where it joins the one before it in a run.

final double card

A large card.

final double cell

A small picture.

final double cellLarge

A picture in a reply, a chip.

final double composer

The composer’s box.

final double hero

A post’s picture.

final double notice

A banner, a notice, and the tile of an empty state’s icon.

final double pill

A pill: chips, tags, the main button.

final double row

A choice’s row.

final double rowIcon

The rounded square of a row’s icon.

final double sheet

A sheet’s top corners.

final double tag

A compact tag.

final double tile

A group of rows, a card.

class CrmRow extends StatelessWidget

One row: something on the left (leading, often a CrmRowIcon), a title and a line under it, and something on the right (trailing: a count, a pill). With onTap the whole row is one button, with a chevron unless chevron is false or there is a trailing.

const CrmRow({Key? key, required String title, String? subtitle, Widget? leading, Widget? trailing, void Function()? onTap, bool chevron = true, Color? titleColor, String? semanticsLabel, Widget? below, double? minHeight, EdgeInsetsGeometry? padding})
final Widget? below

A third line under subtitle.

final bool chevron
final Widget? leading
final double? minHeight

At least this high; CrmSizes.row, as the canvas’s rows are, when null.

final void Function()? onTap
final EdgeInsetsGeometry? padding

The row’s padding: the gutter across and the between step up and down, unless given.

final String? semanticsLabel

What a screen reader says for the whole row, in place of the drawn words, when they are not enough on their own.

final String? subtitle
final String title
final Color? titleColor

The title’s colour, for a row that is a warning.

final Widget? trailing
class CrmRowGroup extends StatelessWidget

Rows gathered on one rounded surface, with a line between each, under an optional small heading.

const CrmRowGroup({Key? key, required List<Widget> children, String? title, String? footer})
final List<Widget> children
final String? footer

A sentence under the group.

final String? title
class CrmRowIcon extends StatelessWidget

A row’s picture: an icon in a rounded square, tinted.

const CrmRowIcon(IconData icon, {Key? key, Color? color, Color? background})
final Color? background
final Color? color
final IconData icon
class CrmSizes

The sizes of PurrCRM’s parts, in logical pixels: the heights of its buttons and rows, its round buttons and icon tiles, and the widths its words are kept to. The defaults are the package’s own.

const CrmSizes({double pill = 54, double pillCompact = 48, double pillRetry = 46, double pillChip = 44, double roundButton = 44, double target = 48, double topBar = 56, double row = 60, double rowTall = 72, double iconTile = 40, double iconTileSmall = 36, double emptyIcon = 56, double icon = 20, double iconLabel = 19, double iconSmall = 18, double iconTag = 14, double statusPill = 28, double countBadge = 22, double field = 52, double choice = 56, double bubbleMax = 440, double centred = 480, double readable = 560})
final double bubbleMax

The widest a message’s bubble is, on a phone wider than it needs.

final double centred

The widest a page’s centred words are (a survey’s introduction).

final double choice

A survey choice’s least height.

final double countBadge

The count badge’s least side.

final double emptyIcon

An empty state’s icon in its rounded square.

final double field

A search box’s least height.

final double icon

An icon on its own: in a round button, a chevron that leads on.

final double iconLabel

An icon beside a label, in a pill or a banner.

final double iconSmall

A small icon: a row’s chevron, an error’s mark.

final double iconTag

An icon in a tag or a status pill.

final double iconTile

A row’s icon in its rounded square, and a face in a list.

final double iconTileSmall

A banner’s icon in its rounded square.

final double pill

The main button: a pill this high.

final double pillChip

One of several choices in a row (the help bot’s buttons).

final double pillCompact

A button beside words, rather than at a page’s foot (a rating’s Send, “Was this helpful?”, a reply’s button) and the quiet “Not now”.

final double pillRetry

“Try again” in an empty or error state.

final double readable

The widest a column of words reads well at (a post, a survey’s questions).

final double roundButton

The circle of a round icon button.

final double row

The least a row is high.

final double rowTall

A row with a face and two lines (a conversation).

final double statusPill

A status pill’s least height.

final double target

The least a finger is given round a round button, and the slot a top bar keeps for one so that its title stays centred.

final double topBar

A page’s top bar.

class CrmSpacing

The steps PurrCRM is laid out in, in logical pixels. The defaults are the package’s own; a host passes its own to match its app.

const CrmSpacing({double hair = 4, double tight = 6, double chip = 8, double between = 10, double near = 12, double inset = 14, double gutter = 16, double card = 20, double block = 24, double section = 30})
final double between

Cards side by side.

final double block

Between blocks of one section.

final double card

Inside a large card.

final double chip

Chips in a row, a pair of round buttons.

final double gutter

A page’s side margin, and inside a card.

final double hair

An icon and its word, a tag’s parts.

final double inset

Inside a small card, and a row’s parts.

final double near

A picture and its name.

final double section

Between a page’s sections.

final double tight

A line and the line under it in one block.

class CrmTestModeBanner extends StatelessWidget

child, with a small “CRM TEST” ribbon across a corner while the facade is in test mode, as Flutter’s own DEBUG banner is drawn. Opt in by wrapping the app in it, in the MaterialApp’s builder, round the overlay and with the same navigator key:

final navigatorKey = GlobalKey&lt;NavigatorState&gt;();
MaterialApp(
navigatorKey: navigatorKey,
builder: (context, child) =&gt; CrmTestModeBanner(
child: CrmOverlay(navigatorKey: navigatorKey, child: child!),
),
);

Debug and profile builds only: a release build draws child alone, whatever its key, and says so in the log instead (lib/src/core/ test_mode.dart). Nothing either for the live app, or with no CrmScope above it. The ribbon’s words are for the developer, as DEBUG is, and are not translated.

const CrmTestModeBanner({Key? key, required Widget child, BannerLocation location = BannerLocation.topStart})
final Widget child
static const Color color

The ribbon’s colour: the orange PurrCRM site marks test mode with.

final BannerLocation location

Which corner: the top start unless said, so that it is clear of the DEBUG banner at the top end.

static const String message

The ribbon’s words.

class CrmTestPhoneTile extends StatefulWidget

The Test phone group, for a guest staff chose as a test phone (as the last check-in said, Crm.testPhone) and nobody else: “Check for tests now”, which asks PurrCRM at once for the tests sent from PurrCRM site and says what came (Crm.checkNow). The tests themselves are shown over the screen as any in-app message is, by the CrmOverlay.

Nothing at all for anyone else, and with no CrmScope above it, so a host can put it on its page unconditionally.

const CrmTestPhoneTile({Key? key})
class CrmTheme extends ThemeExtension<CrmTheme>

PurrCRM’s theme, as a ThemeExtension of the host’s ThemeData.

factory CrmTheme.fromScheme(ColorScheme scheme)

PurrCRM’s theme from scheme alone: the primary as the accent, and the rest worked out from the scheme as the canvas works out its washes (a colour at 10 or 12% over the surface).

const CrmTheme({required Color accent, required Color onAccent, required Color accentTint, required Color controlLine, required Color tagLine, required Color tagInk, required Color ok, required Color okTint, required Color shadow, required Color barLine, CrmSpacing spacing = const CrmSpacing(), CrmRadii radii = const CrmRadii(), CrmSizes sizes = const CrmSizes(), CrmTypography typography = const CrmTypography(), CrmMotion motion = const CrmMotion()})
final Color accent

What PurrCRM draws its own actions in: a message’s buttons, the guest’s bubbles, the composer’s send, the steps done.

final Color accentTint

accent’s wash, behind a banner’s icon or a picked answer.

final Color barLine

The edge of what floats over a page.

final Color controlLine

The edge of a control a finger can change (a choice in a survey), which WCAG asks to stand 3:1 from what is round it.

final CrmMotion motion
final Color ok

Something that worked (a survey sent, a rating given), and its wash.

final Color okTint
final Color onAccent

Words and icons on accent.

final CrmRadii radii
final Color shadow

The shadow under what floats: a floating banner, a sheet.

final CrmSizes sizes
final CrmSpacing spacing
final Color tagInk
final Color tagLine

The edge and the words of a tag that only says what a thing is.

final CrmTypography typography
CrmTheme lerp(CrmTheme? other, double t)

The colours blend; the spacing, the corners, the sizes, the type and the motion are this one’s until halfway, and other’s after.

static CrmTheme of(BuildContext context)

The theme’s own, or CrmTheme.fromScheme of its colour scheme when the host put none in.

class CrmTicketScreen extends StatefulWidget

One ticket: its title and where it has got to (CrmTicketStepper), what staff wrote it is for, the fields the guest may see, and the conversation about it with a composer at the foot, waited on as a conversation is.

Its header is its ref and its type from the moment it opens, where the list it was opened from knew them, and the ticket and its conversation arrive behind one shape of the page.

const CrmTicketScreen({Key? key, required String ticketId})
final String ticketId
class CrmTickets extends StatefulWidget

The guest’s tickets, the most recently changed first, each with its ref and where it has got to: read as the page opens, again on coming back from a ticket and when it is pulled down. Their shape stands in for them until they arrive; a list that could not be read again stays, under a floating “Try again”.

const CrmTickets({Key? key})
class CrmTypography

PurrCRM’s type: the families its explicit styles are set in, and those styles. Everything else is the host’s TextTheme.

const CrmTypography({String? displayFamily, String? textFamily})
final String? displayFamily

Headings; the host’s default family when null.

final String? textFamily

Everything else; the host’s default family when null.

double get compactLabel

The size of a smaller pill’s label (CrmSizes.pillCompact and less): 15, where the main button’s is the theme’s labelLarge.

TextStyle count({Color? color})

A count on a badge: 13 on a line of 20, the heaviest weight.

TextStyle display(double size, double lineHeight, FontWeight weight, {double em = 0, Color? color})

A style in the display family: size high, lines lineHeight times that apart, tracked by em of its size.

TextStyle? rowTitle(TextTheme styles, {FontWeight weight = FontWeight.w600, Color? color})

A row’s title: the host’s titleMedium at 16, semi-bold unless weight says (an unread conversation’s is heavier).

TextStyle text(double size, double lineHeight, FontWeight weight, {Color? color})

A style in the text family.

TextStyle? topBarTitle(TextTheme styles)

A top bar’s title: the host’s titleMedium at 17, its lines 1.2 apart.

class CrmUnreadBuilder extends StatelessWidget

Builds with the messenger’s count of unread replies (Crm.unread), again whenever it changes: for the badge on a host’s own button or row that opens the messenger. 0 with no CrmScope above it.

const CrmUnreadBuilder({Key? key, required Widget Function(BuildContext, int) builder})
final Widget Function(BuildContext, int) builder
class NavigatorCrmNavigator implements CrmNavigator

Shows PurrCRM’s pages on the host’s navigatorKey’s Navigator, each as a page of its own pushed over the one the guest is on: a tapped push’s page (open) as well as a tap’s (push), since a Navigator has no place to put one in place of another. A page whose feature the guest does not have (Crm.features) is not shown, and open says so.

The Navigator must be under the host’s CrmScope (a CrmScope above its MaterialApp), which is where the pages find PurrCRM.

NavigatorCrmNavigator(GlobalKey<NavigatorState> navigatorKey)
final GlobalKey<NavigatorState> navigatorKey

The Navigator the pages are pushed on: a MaterialApp’s navigatorKey.

ImageProvider<Object> crmNetworkImage(String url)

The picture at url, from the cache PurrCRM’s pictures share.