Commit 1e56f1e7 authored by Aral Balkan's avatar Aral Balkan

Add status image; work around bugs w image view sizing w dynamic type

parent 33f021c4
<?xml version="1.0" encoding="UTF-8"?>
<document type="" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="ipad9_7" orientation="landscape">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
......@@ -14,16 +14,16 @@
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="AutoLayout" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="1024" height="768"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="cUA-A3-7ag" userLabel="Top Margin">
<rect key="frame" x="16" y="20" width="992" height="38.5"/>
<rect key="frame" x="16" y="44" width="382" height="43.5"/>
<color key="backgroundColor" red="0.54029709100000001" green="0.54598444700000004" blue="0.54598444700000004" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="ho7-yh-GuY"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4IP-2x-4dT" userLabel="Status Badge Left Margin">
<rect key="frame" x="16" y="58.5" width="310" height="155"/>
<rect key="frame" x="16" y="87.5" width="119.5" height="173.5"/>
<color key="backgroundColor" red="0.54029709100000001" green="0.54598444700000004" blue="0.54598444700000004" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
<constraint firstAttribute="width" constant="242.66666666666663" id="nCR-eJ-yK1">
......@@ -43,10 +43,10 @@
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="1c7-hR-87O" userLabel="Status Badge">
<rect key="frame" x="326" y="58.5" width="372" height="155"/>
<rect key="frame" x="135.5" y="87.5" width="143" height="173.5"/>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Enabled" translatesAutoresizingMaskIntoConstraints="NO" id="e5t-G8-1L2" customClass="LDAlignmentImageView">
<rect key="frame" x="0.0" y="0.0" width="372" height="155"/>
<rect key="frame" x="0.0" y="0.0" width="143" height="173.5"/>
<color key="backgroundColor" red="0.54029709100000001" green="0.54598444700000004" blue="0.54598444700000004" alpha="0.75429137323943662" colorSpace="custom" customColorSpace="sRGB"/>
......@@ -59,7 +59,7 @@
<viewLayoutGuide key="safeArea" id="9aK-DD-cV1"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="P7i-RA-bJJ" userLabel="Status Badge Right Margin">
<rect key="frame" x="698" y="58.5" width="310" height="155"/>
<rect key="frame" x="278.5" y="87.5" width="119.5" height="173.5"/>
<color key="backgroundColor" red="0.54029709100000001" green="0.54598444700000004" blue="0.54598444700000004" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
<constraint firstAttribute="width" constant="242.33333333333337" id="Imv-cs-8U2">
......@@ -79,7 +79,7 @@
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="97y-ZH-spg" userLabel="Bottom Margin">
<rect key="frame" x="16" y="213.5" width="992" height="39"/>
<rect key="frame" x="16" y="261" width="382" height="43.5"/>
<color key="backgroundColor" red="0.54029709100000001" green="0.54598444700000004" blue="0.54598444700000004" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
<constraint firstAttribute="height" constant="12.333333333333343" id="vGG-al-dxa">
......@@ -99,10 +99,10 @@
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Q2i-Mp-9LN" userLabel="Status Text">
<rect key="frame" x="264" y="252.5" width="496" height="348.5"/>
<rect key="frame" x="16" y="304.5" width="382" height="390.5"/>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" usesAttributedText="YES" translatesAutoresizingMaskIntoConstraints="NO" id="PB8-0H-gLc">
<rect key="frame" x="0.0" y="0.0" width="496" height="348.5"/>
<rect key="frame" x="0.0" y="0.0" width="382" height="390.5"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<attributedString key="attributedText">
<fragment content="Status Text">
......@@ -125,7 +125,7 @@
<viewLayoutGuide key="safeArea" id="gOH-cY-A90"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Da0-nj-Gxr" userLabel="Base">
<rect key="frame" x="16" y="20" width="992" height="581"/>
<rect key="frame" x="16" y="44" width="382" height="651"/>
<color key="backgroundColor" red="0.57965375782876882" green="0.79642258872084581" blue="1" alpha="0.48630061619718312" colorSpace="custom" customColorSpace="displayP3"/>
......@@ -22,7 +22,7 @@ struct BetterFontSet {
var body: UIFont!
class ViewController: UIViewController {
class ViewController: UIViewController, UITextViewDelegate {
@IBOutlet weak var statusTextView: UITextView!
@IBOutlet weak var statusImageView: LDAlignmentImageView!
......@@ -35,9 +35,14 @@ class ViewController: UIViewController {
@IBOutlet weak var layoutElementStatusBadge: UIView!
@IBOutlet weak var layoutElementStatusText: UIView!
// Will hold references to the images used in the view header to display blocker status.
var blockerEnabledShieldImage: UIImage!
var blockerDisabledShieldImage: UIImage!
// Hard code the blocker state for the spike.
let blockerEnabled = true
let blockerEnabled = false
// Enable layout guides to debug layout and responsiveness.
let showLayoutGuides = false
......@@ -65,10 +70,18 @@ class ViewController: UIViewController {
override func viewDidLoad() {
// BonMot: adapt to content size changes (dynamic type).
// We will handle link press notifications from the text view.
self.statusTextView.delegate = self
// Initialise the success and failure images for the data update.
blockerDisabledShieldImage = UIImage(named: "Disabled")
blockerEnabledShieldImage = UIImage(named: "Enabled")
// Should we show layout guides?
if (!showLayoutGuides) {
// Hide the layout guides and reset the background colours on the layout elements.
let layoutGuides = [layoutGuideBase, layoutGuideTopMargin, layoutGuideStatusBadgeLeftMargin, layoutGuideStatusBadgeRightMargin, layoutGuideBottomMargin]
......@@ -77,7 +90,6 @@ class ViewController: UIViewController {
for layoutElement in layoutElements { layoutElement!.backgroundColor = UIColor.white }
// Set the image view to align the image internally from the left while also satisfying aspect fit.
statusImageView.imageContentMode = LDImageContentModeScaleAspectFit
......@@ -138,7 +150,7 @@ class ViewController: UIViewController {
let linkStyle = bodyStyle.byAdding(.paragraphSpacingBefore(fontSet.body.lineHeight/4.0))
var statusAttributedString:NSMutableAttributedString
// var statusImage:UIImage!
var statusImage:UIImage!
if blockerEnabled
......@@ -148,7 +160,7 @@ class ViewController: UIViewController {
"Check again now.".styled(with: linkStyle)
]).mutableCopy() as! NSMutableAttributedString
_ ="Check again now.", to: "better://check-for-updates")
// statusImage = self.blockerEnabledShieldImage
statusImage = self.blockerEnabledShieldImage
......@@ -158,16 +170,48 @@ class ViewController: UIViewController {
"Launch Safari settings.".styled(with: linkStyle)
]).mutableCopy() as! NSMutableAttributedString
_ ="Launch Safari settings.", to: "better://launch-settings")
// statusImage = self.blockerDisabledShieldImage
statusImage = self.blockerDisabledShieldImage
// Set the status text view’s text and also:
// 1. Turn off (and on the next stack frame) turn back on scrolling on it to
// work around a bug where otherwise on some aspect ratios the UITextView’s
// UITextContainerView incorrectly clips the UITextView’s content.
// (See
// 2. Scroll the text view to top. (The text view can scroll as it supports
// Dynamic Type for accessibility so the text may display far larger than the
// art-directed sizes we’ve picked as pretty defaults.) (Accessibility)
statusTextView.attributedText = statusAttributedString.adapted(to: traitCollection)
_ = delay(0) { self.statusTextView.setContentOffset(.zero, animated: false) }
_ = delay(0) {
self.statusTextView.setContentOffset(.zero, animated: false)
self.statusTextView.isScrollEnabled = true
statusTextView.isScrollEnabled = false
// The link’s text attributes have to be overwritten manually.
self.statusTextView.linkTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.darkGray, NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue, NSAttributedString.Key.underlineColor: UIColor.darkGray]
// Update the status image.
statusImageView.image = statusImage
// Note: we are setting the imageContentMode to AspectFill first so that we can
// be sure that the AspectFit setting is applied even if the imageContentMode is already
// set to AspectFit as otherwise the image does not update correctly when returning
// to the app after making changes to the Dynamic Type settings under Settings.
statusImageView.imageContentMode = LDImageContentModeScaleAspectFill
statusImageView.imageContentMode = LDImageContentModeScaleAspectFit
/// Align the status image differently on compact vertical sizes.
/// (So that it aligns flush left with the text in our compact vertical layouts.)
func updateStatusImageHorizontalAlignmentBasedOnTraitCollection(_ traitCollection: UITraitCollection) {
var statusImageViewHorizontalAlignment: LDImageHorizontalAlignment
if traitCollection.verticalSizeClass == .compact {
......@@ -186,34 +230,44 @@ class ViewController: UIViewController {
// MARK: - Notification handlers
/// When the view transitions to a different size, update the text attributes and make sure
/// the text area is scrolled to the top if it overflows the visible area.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
// Scroll the status text to the top in the next stack frame in case the text overflows the visible
// area so that the top of the message is always visible. (This can happen when the text size is set
// to a large setting via Dynamic Type (Accessibility).
print("Will transition to size: \(size).")
// Queue a call to scroll the text view to the top in the next stack frame.
_ = delay(0) {
// Update the text in case the size changes.
coordinator.animate(alongsideTransition: nil) {
/* with */ (coordinatorContext) in
// Scroll the status text view to the top (in case the person’s Dynamic Type
// settings have made the text overflow the visible region). (Accessibility)
self.statusTextView.setContentOffset(.zero, animated: false)
/// When transitioning to a new trait collection, make sure the status badge image is
/// aligned correctly.
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
// TODO: LEFT OFF: Set the image horizontal alignment based on the vertical size class.
// (Left for compressed, centre for all others.)
print("Will transition to new trait collection.")
/// Handle link presses from the status text view.
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
let launchSettingsURL = Foundation.URL(string: "better://launch-settings"),
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment