<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Emilio Peláez on Medium]]></title>
        <description><![CDATA[Stories by Emilio Peláez on Medium]]></description>
        <link>https://medium.com/@Pelaez?source=rss-aff864e8163------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*EFx1ojI0_PNRZ7bSqIWgZA.jpeg</url>
            <title>Stories by Emilio Peláez on Medium</title>
            <link>https://medium.com/@Pelaez?source=rss-aff864e8163------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 13 Jul 2026 12:18:22 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@Pelaez/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Environment Values as an Alternative to Dependency Injection in SwiftUI]]></title>
            <link>https://medium.com/better-programming/environment-values-as-an-alternative-to-dependency-injection-in-swiftui-a9de89854afe?source=rss-aff864e8163------2</link>
            <guid isPermaLink="false">https://medium.com/p/a9de89854afe</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swiftui]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Emilio Peláez]]></dc:creator>
            <pubDate>Tue, 10 May 2022 17:27:20 GMT</pubDate>
            <atom:updated>2022-05-10T17:27:20.227Z</atom:updated>
            <content:encoded><![CDATA[<h4>Using Environment Values to avoid unnecessary body re-evaluations and make our views more self-contained.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*KuB9tQDDksMpDnJN" /><figcaption>Photo by <a href="https://unsplash.com/@pieterpanflute?utm_source=medium&amp;utm_medium=referral">Pieter</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><blockquote>Dependency injection is a 25-dollar term for a 5-cent concept. -<a href="https://www.jamesshore.com/v2/blog/2006/dependency-injection-demystified">James Shore</a></blockquote><p>Dependency Injection is a fancy way of saying that we will provide an object with the object(s) it requires or depends on, to perform its job.</p><p>In SwiftUI, a very common way of implementing Dependency Injection is by using environment objects. By injecting an object into our view hierarchy we can abstract the logic and data out of our views and into classes, allowing us to follow the single-responsibility principle, and making our code more testable.</p><p>For an example, let’s imagine that we have a UserSettings class with a few properties.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7bf0228351e7583c096792d268ee5495/href">https://medium.com/media/7bf0228351e7583c096792d268ee5495/href</a></iframe><p>In order to make sure that our View can access the values in our UserSettings object, we can inject it using the .environmentObject() modifier, and reading it using the @EnvironmentObject property wrapper.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/19d57dea190b56f9721e9d0e2aa043c4/href">https://medium.com/media/19d57dea190b56f9721e9d0e2aa043c4/href</a></iframe><p>In this example, ContentView needs two values found in UserSettings, but we’re creating a much deeper dependency, our view simply <strong>won’t work</strong> without a full UserSettings object.</p><p>This has two distinctive disadvantages:</p><ol><li>First, every time any of the values in the object changes, the view’s body will be re-evaluated, even if the value changed is not a value that is used by this specific view. In our example, our view’s body will be re-evaluated when soundsEnabled changes, even though it’s not being used in the body. If you happen to be using this method to inject your app’s state, like I have in the past, this object could hold many values that will trigger unnecessary view evaluations throughout your view hierarchy.</li><li>And second, when previewing a view that has a dependency to an environment object, we will need to inject that environment object to the preview, otherwise it will fail to load. Even worse, any views that display this view as a child will need to receive the environment object in their previews in order to load, even though this requirement is not obvious by looking at their body.</li></ol><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cb8cfba98cd2108bc4710f0589c122d2/href">https://medium.com/media/cb8cfba98cd2108bc4710f0589c122d2/href</a></iframe><h3>Custom Environment Values</h3><p>EnvironmentValues, like EnvironmentObjects, are injected into the view hierarchy and propagated to all descendants until they are replaced by a new value. They are the mechanism used by modifiers like .foregroundColor() or .font().</p><p>The big difference is that to define a custom environment value you need to provide a <strong>default value</strong>. It requires a bit more boilerplate, but it has it’s advantages.</p><p>To create your own environment value you need to create an environment key and extend EnvironmentValues; you can then insert the value into the hierarchy using the .environment() modifier.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0fc7d0efcf88f66bf1dc9699c4e4cea0/href">https://medium.com/media/0fc7d0efcf88f66bf1dc9699c4e4cea0/href</a></iframe><h3>Value Injection with Environment Values</h3><p>By reading from a specific environment value, our view’s body will only be re-evaluated when that value changes. And because EnvironmentValues always have a defaultValue, these views can be utilized without having to inject anything, which means you don’t need to modify your previews.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/94953e7bec2da7673d4a0627257b12eb/href">https://medium.com/media/94953e7bec2da7673d4a0627257b12eb/href</a></iframe><p>An important thing to note is that @Environment properties are <em>read-only</em>. You may have noticed that I injected the UserSettings in my SettingsProvider, that’s because any views that need to modify the values, like a SettingsView would in this example, will still need to read the whole object.</p><h3>More than just User Settings</h3><p>So far I’ve used simple values as an example, but this technique can be useful when populating our app’s views with all kinds of data.</p><p>Let’s say we’re building an app that displays the user’s transactions in different ways and subsets throughout the app.</p><p>If we were using CoreData, we could use a @FetchRequest with the relevant query in each view; if we were fetching data from the server we could fetch the required transactions from the network on each view.</p><p>My preferred alternative, however, is to inject the transactions at a very high level in the hierarchy, and read that value in any view that will display them.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/adf8968de2e060f4d4e703d70ae5d808/href">https://medium.com/media/adf8968de2e060f4d4e703d70ae5d808/href</a></iframe><p>Fetching the data is an exercise left to the reader, but once the transactions are fetched, we can inject them into the environment using the .environment modifier.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f5c47ec80421604379b3f23f2863d194/href">https://medium.com/media/f5c47ec80421604379b3f23f2863d194/href</a></iframe><p>Any views that want to display the values in the userTransactions array can read that value from the environment instead of having to fetch any values by itself.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/aecdeb9491f4bddabfdd001d3278af57/href">https://medium.com/media/aecdeb9491f4bddabfdd001d3278af57/href</a></iframe><p>This makes our views a lot simpler, and the logic for fetching the transactions is not only removed from the View struct, it’s in a different node of the view hierarchy altogether.</p><h3>Conclusion</h3><p>By using value injection, views that require <em>read-only</em> access to these values will only be refreshed when those specific values change.</p><p>Because environment values provide a <strong>default value</strong>, we no longer need to inject dependencies to the previews of views that use them.</p><p>Dependency Injection using environment objects still has its place in views that require write access to the properties of the object.</p><h4>Continue Reading</h4><p>In my previous article, I explored creating a responder chain using EnvironmentValues, allowing us to follow a “fire and forget” approach to actions in order to make our views more self-contained.</p><p><a href="https://betterprogramming.pub/building-a-responder-chain-using-the-swiftui-view-hierarchy-2a08df23689c">Building a Responder Chain Using the SwiftUI View Hierarchy</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a9de89854afe" width="1" height="1" alt=""><hr><p><a href="https://medium.com/better-programming/environment-values-as-an-alternative-to-dependency-injection-in-swiftui-a9de89854afe">Environment Values as an Alternative to Dependency Injection in SwiftUI</a> was originally published in <a href="https://betterprogramming.pub">Better Programming</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building a Responder Chain Using the SwiftUI View Hierarchy]]></title>
            <link>https://medium.com/better-programming/building-a-responder-chain-using-the-swiftui-view-hierarchy-2a08df23689c?source=rss-aff864e8163------2</link>
            <guid isPermaLink="false">https://medium.com/p/2a08df23689c</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[swiftui]]></category>
            <dc:creator><![CDATA[Emilio Peláez]]></dc:creator>
            <pubDate>Wed, 12 Jan 2022 17:02:40 GMT</pubDate>
            <atom:updated>2022-06-11T10:17:15.141Z</atom:updated>
            <content:encoded><![CDATA[<h4>Harnessing EnvironmentValues to easily respond to events generated throughout the view hierarchy</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*5f1kV0Q8d9UHPv9V" /><figcaption>Photo by <a href="https://unsplash.com/@mael_balland?utm_source=medium&amp;utm_medium=referral">Mael BALLAND</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Over the past 10 years I’ve spent a lot of time answering questions in StackOverflow, and a question I see very often is a flavor of:</p><blockquote>How do I trigger an event in class A from a function in class B?</blockquote><p>This may seem like a simple question for a seasoned developer, after all there are multiple ways we can go about this, we can use delegates, callbacks, notifications, etc., but it’s still a situation that we encounter often, and the farther apart that the two objects are, the more complex it is to communicate between them.</p><p>Part of the challenge is to implement this in a way that is scalable and maintainable. You <em>could</em> create an app where every event is sent via NotificationCenter, but you’ll be knocking your head on your desk soon enough.</p><h3>Enter Responder Chains</h3><p>A responder chain is a design pattern where responder objects form a “chain”. Events are generated in one of the “links” or “nodes” of the chain, and the node determines if it can handle the event or not. If it cannot handle the event, the event is sent to the next node in the chain. This process continues until a node can handle the event, or the end of the chain is reached.</p><p>An object-delegate relationship is a trivial example of this pattern. The object creates an event that it can’t handle itself, so the event is sent to the next node in the chain, which is the delegate. A more complex example is the UIResponder chain.</p><p>Explicit responder chains are not super common in iOS development, probably because most of the core building blocks of UIKit, like UIViewController and its subclasses, make it really easy to build without one.</p><p>With SwiftUI, however, every object is <em>linked</em> to the root view via the View Hierarchy, which means that the overall structure we need to build a responder chain is already in place, all we need to add are the responders and the events.</p><h3>The SwiftUI View Hierarchy</h3><p>An interesting property of the SwiftUI View Hierarchy is that some of its values, like the Environment and EnvironmentObjects, are passed down the hierarchy until they are replaced. We can use this, especially the Environment, to register our responders.</p><p>To make things a little bit more visual, this is the hierarchy that would be generated from this simple view. Notice how modifiers, likeforegroundColor, create a node that is a parent to the view they are modifying.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d33467f75273e19081795195e9efb48d/href">https://medium.com/media/d33467f75273e19081795195e9efb48d/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3E6O_extvecc4fbrmUe1xg.png" /></figure><h3>SwiftUI Environment</h3><p>Environment values can seem intimidating at first because they are often used for system actions, like dismissing a sheet, and adding our own requires extending a system type, EnvironmentValues. It’s perfectly safe to do so, though, and since they can be any kind of type, their Type can be a closure.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f696bd657e26e446f44fec416597b9c9/href">https://medium.com/media/f696bd657e26e446f44fec416597b9c9/href</a></iframe><p>With this value in place, any view can read our custom environment value, and also set a new value to it. Since the value we added is a closure, our view can also call this closure.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/82624620d501cb710d9a39986e0067b8/href">https://medium.com/media/82624620d501cb710d9a39986e0067b8/href</a></iframe><h3>Creating a Responder</h3><p>Earlier we mentioned that a responder has the responsibility to determine if it can handle an event or not. Our views will register themselves as responders by registering their own eventClosure into the environment.</p><p>Any child views that call eventClosure will be triggering our view’s handler, as long as an intermediate view hasn’t replaced it. If our view determines that it cannot handle the event, it can use the closure it read from the environment, which will come from a parent responder, to allow the event to continue through the chain.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U54vl3NNMkHm0nqyNkaG9w.png" /><figcaption>Two registered Responders. Yellow <strong>can’t</strong> handle the event so the event continues its path and arrives at Green, which <strong>can</strong> handle it.</figcaption></figure><p>Since this will be a common pattern, we’ll create a ViewModifier that will encapsulate this funcionality.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/519e893bd66f15518fa39e3458cbe2bf/href">https://medium.com/media/519e893bd66f15518fa39e3458cbe2bf/href</a></iframe><p>Our new handler closure has a return type of Any? because that’s how we’re going to determine if the event was handled or not. If the returned value is nil, the event will be considered handled, if the returned value is anything else, that value will be sent up the chain.</p><p>Views can now register themselves as responders by calling our modifier and passing a handler closure.</p><h3>Sending an Event</h3><p>Triggering an event is a lot simpler, all we need to do is to read the eventClosure from the environment and call it with any value.</p><p>A simple but complete example would look like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e47ab383e314f23520a32942b7ab1ed2/href">https://medium.com/media/e47ab383e314f23520a32942b7ab1ed2/href</a></iframe><p>An important detail is that for a responder to be able to receive an event, the source of the event has to be a direct descendant of the responder.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Szqclf1aXWAzrIuNnpTKAw.png" /></figure><p>In practice this means that our responders will usually be registered at the root node of each feature or screen.</p><h3>Scalable and Maintainable</h3><p>One of the more common ways of triggering events from a child view in SwiftUI is passing a closure as an argument, like you would with a Button. When the view that is responsible from calling that closure gets deeper in the view hierarchy, this closure has to be <em>carried</em> by multiple intermediate views.</p><p>Our approach is much more <strong>maintainable</strong> because only the responder and trigger views need to know about the event. This means that our hierarchy can be modified without having to “carry” this closure through multiple levels.</p><p>Thanks to this, our approach is also <strong>scalable</strong>, and creating an event is as easy as defining a new type. No need to add a new environment value for every event.</p><h3>Creating a Framework</h3><p>Following this pattern I created the framework <a href="https://github.com/EmilioPelaez/HierarchyResponder">HierarchyResponder</a>, designed to handle events and errors.</p><p>This framework takes this concept and expands it by adding specific modifiers to receive, handle, or transform an Event or Error, as well as catching errors.</p><ol><li>Receiving an Event or Error lets you decide if the event was handled or not.</li><li>Handling the Event or Error means it will be consumed, no other options.</li><li>The transforming modifiers let you replace the received Event or Error with a different value.</li></ol><p>Another feature is that each modifier has a generic version with a Type parameter that will automatically filter any values that don’t match the type you supplied.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2a08df23689c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/better-programming/building-a-responder-chain-using-the-swiftui-view-hierarchy-2a08df23689c">Building a Responder Chain Using the SwiftUI View Hierarchy</a> was originally published in <a href="https://betterprogramming.pub">Better Programming</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Recreating Tweetbot’s Refresh Bar]]></title>
            <link>https://medium.com/@Pelaez/recreating-tweetbots-refresh-bar-526c115afdf7?source=rss-aff864e8163------2</link>
            <guid isPermaLink="false">https://medium.com/p/526c115afdf7</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[user-interface]]></category>
            <category><![CDATA[design]]></category>
            <category><![CDATA[animation]]></category>
            <dc:creator><![CDATA[Emilio Peláez]]></dc:creator>
            <pubDate>Thu, 13 Dec 2018 02:28:28 GMT</pubDate>
            <atom:updated>2018-12-13T02:28:28.228Z</atom:updated>
            <content:encoded><![CDATA[<p>Tweetbot 5 came out recently, and it has a custom refresh control that looks really good. It’s a simple animation, but it gets the job done, so I decided to recreate it.</p><p><em>Note: When I started implementing this animation I thought about implementing it as a refresh control, but it quickly started feeling like work, so I decided to just focus on the animation. Anything else is left as an exercise to the reader.</em></p><h3>Introduction</h3><p>Just like my first article, <a href="https://medium.com/@Pelaez/recreating-instagrams-page-control-ebc2103b8a39">Recreating Instagram’s Page Control</a>, in this article I will recreate a UI component from an app, in this case it’s Tweetbot’s Refresh Bar.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*N9-nIvJJLfqrH8tvv9fZkA.png" /></figure><p>This control is pretty simple, it’s a bar that fills as you drag down, and once you reach a certain distance, it starts bouncing left and right.</p><p><a href="https://www.dropbox.com/s/b35a9s421k2zyms/TweetbotLoading.zip?dl=0">Download the Playground</a> and follow along. It has a page for each step.</p><h4>Step 1: Class Setup</h4><p>This step is really simple, we’ll create a UIView subclass with a single UIView property that will be used as the fill.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/aceac8a984462d9d21810c07bfc490cb/href">https://medium.com/media/aceac8a984462d9d21810c07bfc490cb/href</a></iframe><p>We’ll use two existing properties of UIView to style our control, backgroundColor for the background (shocker!), and tintColor for the fill. That way we won’t need to add any extra properties, but we will need to override tintColorDidChange() to update the background color of our fillView.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/95db9697469aef260a4184591d64182f/href">https://medium.com/media/95db9697469aef260a4184591d64182f/href</a></iframe><p>Finally, we’ll override intrinsicContentSize and return the size we want our control to have. If you’re not familiar with what intrinsicContentSize does, you can read about it in <a href="http://read about it in this article I wrote">this article I wrote</a>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/397ddaa1da66bc16fde5ed6542fbbcc9/href">https://medium.com/media/397ddaa1da66bc16fde5ed6542fbbcc9/href</a></iframe><h4>Step 2: Progress Fill</h4><p>Our view will have two states, the first one will be when it fills. Since the bar will fill as the user drags down, we’ll add an associated value to store that progress.</p><p>The second state will be when the bar is animating. To handle these two states we’ll create the following enum.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f5ae3c85bfddfd2985238911cdb55706/href">https://medium.com/media/f5ae3c85bfddfd2985238911cdb55706/href</a></iframe><p>Next we’ll implement layoutSubviews, and use it to round the corners of our views, then we’ll call our updateFrames() function.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1a1d5b580bb2231caa7a7b263aa5aa77/href">https://medium.com/media/1a1d5b580bb2231caa7a7b263aa5aa77/href</a></iframe><p>In our updateFrames(), first we’ll make sure that state is .progress, otherwise we exit early. Then we’ll use lerp to calculate the width of our fill view, and set it’s frame. The lerp function is found in my <a href="https://github.com/EmilioPelaez/CGMath">CGMath library</a>, you can learn more about it in the readme.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e7a145c3285951ce7ebedf0302d272b4/href">https://medium.com/media/e7a145c3285951ce7ebedf0302d272b4/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/280/1*3PNtF4Lwzb7x6xU1F6Qx9A.gif" /></figure><h4>Step 3: Animation</h4><p>To start implementing the animation we’ll need a couple of constants, the width of the bar and the duration of each step of the animation.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/de552cfd673b5a0e6f419961fcdb6286/href">https://medium.com/media/de552cfd673b5a0e6f419961fcdb6286/href</a></iframe><p>We’ll split the animation in two very similar steps, each step will use UIView.animate to set the frame of our fill view, and on completion, if state is still .loading, we’ll call the other step, this will cause the animation to loop endlessly.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d97a897d50d55e250eb2295f9382240f/href">https://medium.com/media/d97a897d50d55e250eb2295f9382240f/href</a></iframe><p>Now, in state.didSet we’ll call animateFirstStep() if state is .loading. If state is not .loading, we’ll check if it previously was, and if that’s the case, we’ll animate the call to updateFrames().</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/15c42f2ffd1380f8db0be51d347fcaee/href">https://medium.com/media/15c42f2ffd1380f8db0be51d347fcaee/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/280/1*FMEgD91YblLOh2kjaPhU3w.gif" /></figure><h4>Step 4: Final Touches</h4><p>To get it production-ready, we’ll turn loadingWidth and duration from private constants to variables.</p><p>We’ll make alsoRefreshBar.State conform to Equatable, and use that to exit early if state is set to the same value.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9f163b162c16e920e697c497abf88c22/href">https://medium.com/media/9f163b162c16e920e697c497abf88c22/href</a></iframe><h3>And done!</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/272/1*aDPvzG2NIdYvy_g7vNBjsg.gif" /></figure><p>This animated refresh control was quite easy to implement, the trickier part would probably be to integrate it into a scroll view, but as I mentioned before, that is an exercise that will be left to the reader.</p><p>Stay tuned for my next article about Instagram’s story loading animation!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/440/1*rtwYDbllWUT3JmXh1MW87w.gif" /><figcaption>Work in progress</figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=526c115afdf7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Recreating Instagram’s Page Control]]></title>
            <link>https://medium.com/@Pelaez/recreating-instagrams-page-control-ebc2103b8a39?source=rss-aff864e8163------2</link>
            <guid isPermaLink="false">https://medium.com/p/ebc2103b8a39</guid>
            <category><![CDATA[design]]></category>
            <category><![CDATA[animation]]></category>
            <category><![CDATA[user-interface]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Emilio Peláez]]></dc:creator>
            <pubDate>Fri, 05 Oct 2018 22:03:50 GMT</pubDate>
            <atom:updated>2019-05-09T17:16:08.552Z</atom:updated>
            <content:encoded><![CDATA[<p><em>This is the first part of a small project I’ve had in mind for a while, a series of articles where I recreate nice UI details of popular apps and explain step by step how it’s done.</em></p><h3>Introduction</h3><p>The Instagram app has a lot of nice UI details, one the always intrigued me is the page control, which shows a maximum of seven dots, and scrolls as you scroll between photos. As you can see in the gif below, it has three central dots that are full size, and up to two on each side that are smaller the further they are from the center. As you scroll through the pages, the dots scroll and change in size.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/680/1*1onB-eJeTlSeK2z6I595aQ.gif" /></figure><p>For this article I recreated that page control, and I’ll show you step by step how I did it. I strongly recommend you <a href="https://www.dropbox.com/s/e74jh2jpk1i09zp/InstagramPageControl.zip?dl=0">download the playground</a> to follow along, since I won’t post all the code here and you might miss something.</p><p>The Playground contains several numerated pages, each page corresponds to the step with the same number in this article.</p><p>It also contains, in the Sources folder, a copy of my library <a href="https://github.com/EmilioPelaez/CGMath">CGMath</a>, which extends CGGeometry types like CGRect, CGSize, etc., as well as FloatingPoint and Comparable, with some properties and methods useful for animations.</p><p>If you want to use it and have no interest in learning how it was created, you can install it with Cocoapods. <a href="https://github.com/EmilioPelaez/ScrollingPageControl/">More info here</a>.</p><h4>Step 1: Class Setup</h4><p>We’ll start by creating a UIView subclass called PageControl, and set some properties. We’ll also override draw(_ rect: CGRect), since that’s what we’ll use to draw the dots.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c7a3c5c420722c9e313af25ac066965b/href">https://medium.com/media/c7a3c5c420722c9e313af25ac066965b/href</a></iframe><h4>Step 2: Draw Dots</h4><p>To draw the dots we’ll need to calculate their position, once we have it we can use UIBezierPath to draw the dots with the correct color.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f028e2a298c47f30cc358db1b5608f62/href">https://medium.com/media/f028e2a298c47f30cc358db1b5608f62/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/632/1*xz2ZjUknG9rgIjgNVGVIdQ.png" /></figure><p>You might notice that the dots are not centered, instead they are stuck to the left of the view. We’ll fix that later.</p><h4>Step 3: Update Dots</h4><p>Since we added a property observer that calls setNeedsDisplay() to all variables, whenever any of those are changed, our view will be redrawn.</p><p>To trigger that, we’ll use the UIScrollViewDelegate to be notified whenever the scroll view ends a movement, and update our PageControl then.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ffb5f9042d5da26d1e3a07af4a93986e/href">https://medium.com/media/ffb5f9042d5da26d1e3a07af4a93986e/href</a></iframe><p>That should do it, now our PageControl will update whenever the scroll view stops scrolling.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/632/1*qI97bl_gcEvyZfu44Ko1aQ.gif" /></figure><h4>Step 4: Intrinsic Content Size</h4><p>If you are not familiar with the intrinsicContentSize property of UIView, you can <a href="https://savvyapps.com/blog/using-advanced-auto-layout-techniques-to-adapt-interfaces-to-screen-content-intrinsic-content-size-stack-views">read about it in this article I wrote</a>, but the gist of it is that the intrinsicContentSize property of a view is the size the view <em>wants</em> to be in order to show all of it’s content and no more.</p><p>UIView subclasses are in charge or returning their desired size, or .zero if that’s not possible, but we can easily calculate the required size for our view.</p><p>The height will be simply the size of the dot, the width will be the number of dots times their size, plus one less than the number of dots times the spacing. If you don’t understand why it’s one less for the spacing, count the spaces between your fingers.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3a745305bb36714d75a8b2108fd79b8a/href">https://medium.com/media/3a745305bb36714d75a8b2108fd79b8a/href</a></iframe><p>To make sure our dots are centered, even if the view has a width different from it’s intrinsicContentSize (which would be the result of using a width constraint on the view), we’ll calculate a horizontalOffset, which is simply half the difference between the actual size and the desired size.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/78bdebb9ba784497674686d2f37c16ae/href">https://medium.com/media/78bdebb9ba784497674686d2f37c16ae/href</a></iframe><p>Finally, we’ll call invalidateIntrinsicContentSize() on pages.didSet, that way, whenever the number of pages changes, the size will be recalculated and the view’s size will be updated.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c6b9af3de9cb43ab9bdac42bdcea5be1/href">https://medium.com/media/c6b9af3de9cb43ab9bdac42bdcea5be1/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/632/1*t91BdoL8FhsA2efvEwnu8w.png" /></figure><h4>Step 5: Scrolling Dots</h4><p>You might be thinking that this is pretty easy, and so far it has been, but this is the part when things get tricky, so hold on to your seat.</p><p>To scroll the dots, we’ll need to keep track of which central dot is highlighted, and how much we’ve scrolled the dots. We’ll use these two variables.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b3edf31835bb16cf6a5fc02d3259358c/href">https://medium.com/media/b3edf31835bb16cf6a5fc02d3259358c/href</a></iframe><p>Now, in selectedPage.didSet, we’ll update the value of those variables like this.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5155ddafc3fbac1a6b9ef76f3ddc4802/href">https://medium.com/media/5155ddafc3fbac1a6b9ef76f3ddc4802/href</a></iframe><p>This might be hard to understand at a glance, what it does is to calculate where selectedPage lands after being modified by the pageOffset, if it’s between 0 and 2, 0 being the left dot, 1 being the central dot, and 2 being the right dot, we’ll update centerOffset. If it falls outside those values, we’ll update pageOffset instead. That way selectedPage — pageOffset will fall in the range we want and the selected page will always be within the central dots.</p><p>Now we have to update the drawing code. We’ll start by modifying the way we calculate the horizontalOffset, for each offset we have we’ll move all the dots to the left the length of one dot and one spacing. The reason we add a 2 is that we have two dots on the left of the central three. If we’re on the leftmost page, with a pageOffset of 0, we’ll still want to move the dots to the right to make sure that the central dots are centered.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/00da525eff39026369ba7f825d013498/href">https://medium.com/media/00da525eff39026369ba7f825d013498/href</a></iframe><p>The other change you’ll notice is the scale variable, which will calculate the scale for each of the page dots. Remember that the central three are full size, and as they go farther away, they get smaller.</p><p>1 + pageOffset will tell us what is the index that is currently as the middle dot, we’ll use that to calculate the “distance” between that dot and our current page. If the distance is 0 or 1, we’ll return a scale of 1, as the distance grows bigger, we’ll return smaller numbers until we reach 0.</p><p>The 1 we add to pageOffset might seem like it comes out of nowhere, but it makes sense once you think that pageOffset tells us which page is currently on the left, central dot, if we add 1 to that, we get the index of the page in the center dot.</p><p>Finally, in intrinsicContentSize(), we’ll limit the number of pages to show to a maximum of seven.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9383ff1555866b22b09d8f3b15a75962/href">https://medium.com/media/9383ff1555866b22b09d8f3b15a75962/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/632/1*g04ki5flWtklHOrLmWKXlA.gif" /></figure><h4>Step 6: Animate Scroll</h4><p>If you run the playground you’ll notice that while it’s easy to tell when the highlighted dot moves between the central dots, once it moves to one of the dots on the sides, it’s hard or impossible to tell that something happened.</p><p>To fix this, we’ll implement a small animation, just like Instagram does.</p><p>It’s totally possible to implement this animation using the current drawing method, but UIKit already provides us with some handy methods to animate UIViews, so we’ll switch our code to use that instead and save ourselves some time.</p><p>First we’ll create a dotViews property to hold our views. Whenever it changes we’ll remove the views in the old value and add the views in the new one, then we’ll update the colors and positions (we’ll look at these functions in a minute).</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d91d833ac9cb62e018316ec04649c716/href">https://medium.com/media/d91d833ac9cb62e018316ec04649c716/href</a></iframe><p>On pages.didSet, we’ll set the dotViews value to a number of views equal to the number of pages (CircularView is a UIView subclass that will round it’s corners automatically, you can find it’s declaration in the playground).</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/245acbe1ec012a68cd27c2550a869fd0/href">https://medium.com/media/245acbe1ec012a68cd27c2550a869fd0/href</a></iframe><p>Next we’ll get rid of draw(_ rect: CGRect) and replace it with updateColors() and updatePositions(). Update colors is very straightforward:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6f93fccfd302256aab1b3aa569196a7a/href">https://medium.com/media/6f93fccfd302256aab1b3aa569196a7a/href</a></iframe><p>updatePositions() is pretty much the same as draw(_ rect: CGRect), with the difference that instead of drawing each dot with the calculated values, we’ll update the corresponding view.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bbc47afe37ca953ff80cbb6f9f1f4d92/href">https://medium.com/media/bbc47afe37ca953ff80cbb6f9f1f4d92/href</a></iframe><p>The final step is animating the change in pageOffset.didSet, since the that offset is what dictates when the dots should scroll. We can use UIView.animate to animate the position change.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7c689fe14a91332bc7b0e284bebff788/href">https://medium.com/media/7c689fe14a91332bc7b0e284bebff788/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/632/1*9NCwn1OomZfnHASvNicS9Q.gif" /></figure><p><em>Note: The animation block is wrapped inside an </em><em>asyncAfter call to add a one frame delay to this animation, that way the user will see the dot change in color and then all the dots move. It makes it easier to see what’s happening. Theres an </em><em>UIView.animate method with a </em><em>delay parameter, but that wasn’t working for me on the Playground.</em></p><h4>Step 7: Flexibility</h4><p>In order to copy the way the Instagram page control works, we’ve hard coded some values, like the max number of dots, and the number of central dots. That is good for a prototype, but not good for production code, so we’ll change that. We’ll start by adding properties for those two things.</p><p>We’ll require that the value for these two properties is odd because our design and our code relies on one dot being centered in the view at all times, which can’t happen if the number of total or central dots is even.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c2d516931944dc5888a84a057523f4fc/href">https://medium.com/media/c2d516931944dc5888a84a057523f4fc/href</a></iframe><p>In selectedPage.didSet we’ll change 0...2 to 0..&lt;centerDots. When centerDots was hardcoded to 3, those two were equivalents.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c98547ea241670b5d9de64ed3d8c6acd/href">https://medium.com/media/c98547ea241670b5d9de64ed3d8c6acd/href</a></iframe><p>We’ll modify updatePositions() by removing the constants we used before. Instead of adding 2 to -pageOffset, we&#39;ll calculate the amount of side pages and use that instead.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1d197fc6f0576e4b178b03b5bdc5c662/href">https://medium.com/media/1d197fc6f0576e4b178b03b5bdc5c662/href</a></iframe><p>The other thing we’ll change is the way we calculate the scale. After calculating the distance, we’ll return a scale of 0 if the distance from the center dot is greater than half the max number of dots. We’ll then subtract the number of dots to the left and right of the central dot from the distance we already had, and then clamp the result to a value between 0 and 3. Using that new value we’ll get a value from an array of values we defined.</p><p>Finally, we’ll update intrinsicContentSize to use maxDots instead of the hard coded value we were using.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/81675e08344575bc0dc0b0d0fe96427b/href">https://medium.com/media/81675e08344575bc0dc0b0d0fe96427b/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/632/1*sLvSoyNqQqM_ymbI6x6otA.gif" /><figcaption>5 max dots, 1 center dot</figcaption></figure><p>One unexpected upside of these last changes is that we can now fully replicate Instagram’s page control functionality. The one difference our controls had was that when Instagram’s page control had five pages or less, it would show all full dots and not scroll, while ours would always show up to three big dots and scroll.</p><p>Now we can set maxDots and centerDots to 5 whenever the number of pages is less or equal to 5, and the other values for whenever it’s greater. We won’t implement that by default because I like the scrolling dots.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/632/1*Nry3WSENt2J-ji3GPtCtiQ.png" /><figcaption>Instagram 5-page style</figcaption></figure><h4>Step 8: Final Touches</h4><p>To wrap it up and make it production ready we’ll add some guards to make sure that the control only updates when the values change. For example, if the number of pages was set to 5, and you set it to 5 again, there’s no reason to update the colors and positions of the views.</p><p>We’ll also add some checks to make sure valid values are provided for all variables. For example, you can’t have less than 0 pages.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/88fefa24ef6cf9b3691d8b43d1e8c228/href">https://medium.com/media/88fefa24ef6cf9b3691d8b43d1e8c228/href</a></iframe><p>Another change we’ll make is to change dotSize and spacing to non private variables to add more customization options to our control. We’ll also need to add some property observers to update our control when those values are changed.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d57ae1e316ac45478d79d8cfea3a5213/href">https://medium.com/media/d57ae1e316ac45478d79d8cfea3a5213/href</a></iframe><h3>Aaaand we’re done!</h3><p>That’s it, we’ve recreated Instagram’s page control in a class of just 127 lines, and other than the scrolling of the dots, it was pretty straightforward. We started using CoreGraphics to draw our dots, but halfway we realized that UIViews were better suited to do the job. Since our logic was solid and didn’t depend heavily on CoreGraphics, the switch was simple.</p><p>If you want your control to be updated as the user is scrolling, like Instagram does, you can override scrollViewDidScroll instead of scrollViewDidEndDecelerating. I didn’t do it in the example because it caused lag in the Playground, I don’t know if it’s an issue with my computer or playgrounds, but it shouldn’t be an issue on the full simulator or on the device.</p><p>You can install this in your project with Cocoapods. <a href="https://github.com/EmilioPelaez/ScrollingPageControl/">More information here.</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ebc2103b8a39" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I Haven’t Used a Light Switch in over a Year]]></title>
            <link>https://medium.com/@Pelaez/i-havent-used-a-light-switch-in-over-a-year-c9261abb8912?source=rss-aff864e8163------2</link>
            <guid isPermaLink="false">https://medium.com/p/c9261abb8912</guid>
            <category><![CDATA[smart-home-automation]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[smart-home]]></category>
            <category><![CDATA[home-automation]]></category>
            <dc:creator><![CDATA[Emilio Peláez]]></dc:creator>
            <pubDate>Thu, 17 May 2018 23:14:46 GMT</pubDate>
            <atom:updated>2019-10-09T14:43:08.399Z</atom:updated>
            <content:encoded><![CDATA[<h4>Or “This Millennial is Trying to Kill the Light Switch Industry”</h4><p><em>TL;DR: I automated the lights in my apartment. There’s a video at the end if you don’t feel like reading.</em></p><p>For the longest time I’ve had a big interest in home automation, it’s been a dream of mine to have a smart home that reacts to my needs with minimum input from my part.</p><p>In 2012 I saw the <a href="https://www.kickstarter.com/projects/limemouse/lifx-the-light-bulb-reinvented">LIFX Kickstarter</a> campaign and backed it for eight smart light bulbs. Their premise was simple, light bulbs that connect to your WiFi and you control them with your phone. Six years ago I was still living at my mom’s house, which is rather big, so we distributed the light bulbs around the house and used them scarcely.</p><p>I moved out of my mom’s shortly after but it wasn’t until the end of 2016 that I moved into an apartment all by myself, and this gave me the perfect opportunity to start developing the system I have had in mind for a while.</p><p>The main goal I set for my automated home system was simple: <strong>never to have to touch a light switch again</strong>.</p><p>A little over a year ago I pretty much reached that goal. I can’t say I haven’t touched a light switch in my apartment since, because sometimes the bulbs get disconnected from the network and the only way to reconnect them is to turn the switch off and back on, but I haven’t used them to control the lights, which was the essence of my goal.</p><p>For the past year I’ve slowly improved the functionality based on my experience with the system, there’s been a lot of trial and error, and some instances where I was left with a system with a few awkward behaviors that I had to work around for a couple of days, but it works really well now.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*p_C7fR5iE-ZyJUIUDJKDqQ.jpeg" /><figcaption>It also looks pretty cool.</figcaption></figure><p>Lately I’ve read a lot about integrating smart devices — light bulbs, garage doors, thermostats, cameras, etc — with HomeKit or Google Home, but usually what they achieve is to change the input device from a physical switch to a digital one, and in many cases it’s slower to use the digital switch, even if you use Siri, Google Home or Alexa.</p><p>Another thing to note is that not everything can be fully automated, for example, if you set the garage door to open whenever you enter the garage, it might open in the middle of the night when you go find a tool, which is undesirable and could be even dangerous.</p><p>Lights are special in the sense that the way we use them is pretty straight forward. When we enter a room, we turn the lights on, when we leave a room or go to sleep, we turn them off.</p><p>That’s one of the main reasons I chose to make my lights smart, the desired behavior is predictable, the other main reason is that I had the <a href="https://www.lifx.com">LIFX</a> bulbs to play around with, and finding motion sensors was easy enough.</p><p>Hopefully by now you’re curious about all the things the light system in my apartment can do, so here’s a list of it’s main features. You will also find a video below where you can see them in action.</p><h4>Automatic Light Switching</h4><p>This is the main feature. I have a motion sensor in each of the areas of my apartment, and whenever I move to a different area, the sensor is triggered and the light is turned on and other areas are turned off.</p><p>One neat thing I implemented is something I call “pre-heating”. In my apartment, four rooms — the living room, bedroom, bathroom and TV room — are connected to the same hallway, so it’s a given that whenever I’m in that hallway, I’m going to enter one of those four rooms (there isn’t a lot to do in the hallway).</p><p>Whenever the hallway motion sensor is triggered, all those rooms enter “pre-heat” mode, where their lights are turned on at 50% brightness, and once the motion sensor in one of the rooms is triggered, the room is fully turned on.</p><p>This is pretty useful because it takes around two seconds from the time the motion sensor detects motion to the command being executed by the lights, so this helps you avoid entering a dark room at night.</p><h4>Smart Color</h4><p>Another one of the main features is the smart color. The system keeps track of the time of the day. I have 5 “times of day” setup: Morning, Work, Day, Evening and Night. Each time of the day has a set of rules for each room, which dictate the temperature/color and brightness of the light.</p><p>For example, during work hours the lights in my living room/office are bright and white, which is better for working, but late at night, the lights are dim and warm, so if you get up in the middle of the night for a glass of water, you won’t be blinded by bright lights.</p><p>This set up is not system-wide, each house has it’s own setup configure to the owner’s needs, though currently my apartment is the only one in the system.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FIwziTAcsM2Rm8pYUmQUiQ.png" /></figure><h4>Companion iOS App</h4><p>I’ve been an iOS developer for a long time, so obviously I built an app for my phone to control the lights in the few situations that require manual input.</p><p>It’s a rather simple app that allows me to see if the lights are on/off, which rooms are active, and toggle any of the rooms and light scenes.</p><p>This app works remotely, so I can control my lights from far away, if required.</p><h4>Location Triggers</h4><p>The iOS app also tracks my location in the background and manages the lights whenever I leave or arrive to my apartment. When I get within 50 meters of my apartment, the lights are turned on, and when I get farther than 50 meters away, the lights are turned off.</p><p>The result is that lights are on by the time I open the door and I don’t have to worry about turning them off when I leave.</p><h4>Scenes</h4><p>If you looked closely at the screenshot you might have guessed what scenes are, they are basically presets that change the lights in a single room, overriding the current rules.</p><p>The one I use the most is the “Movie” scene, which dims the lights in my TV room to make it more comfortable to watch a movie, a TV show or play video games. The name “Movie, TV Show or Video Games” was too long and I couldn’t find a good icon for it.</p><h4>Siri and HomeKit</h4><p>HomeKit is designed to control individual devices, you can group them and add some automation rules, but it wasn’t enough for me, so I configured HomeKit (and thereby Siri) to work in a very similar way to the iOS app I built.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*r3TwGXKDxlfNNtzOxkhqhw.jpeg" /></figure><p>Each “light” in HomeKit is actually a room or a scene, so if I tell Siri to turn on the living room, it will relay that information to my system and my system will handle it by enabling that room and setting the correct lighting.</p><p>The system works really well with minimal input, but there’s currently no way for my system to figure out when I’m going to bed (yet), so I set up a “Good Night” scene in HomeKit, so at night I can say “Hey Siri… Good night”, and Siri will turn off the lights.</p><p>If you’re more technically inclined and you are wondering how this works, I set up <a href="https://github.com/nfarina/homebridge">Homebridge</a> in a <a href="https://www.raspberrypi.org">Raspberry Pi</a> and I used the <a href="https://github.com/rudders/homebridge-http">HTTP plugin</a> to communicate with my server.</p><h4>IFTTT Notifications</h4><p>Another neat thing I added is an alert endpoint. I connected this with <a href="https://ifttt.com">IFTTT</a> to receive different notifications on my apartment.</p><p>I currently have two notifications setup, whenever the International Space Station flies above my apartment all the lights flash blue three times, and whenever an Uber is arriving to pick me up they flash orange.</p><p>There are a more things I’ve implemented over this past year, and I have a few more in my to do list, but this should give you a good idea of how the whole thing works.</p><p>In the video below you can see most of the features in action, and if you want to know more you can contact me with the links at the bottom.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FOctMTsLf87I%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DOctMTsLf87I&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FOctMTsLf87I%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/ac215404b70b94cdf7b33b2e4c9f3292/href">https://medium.com/media/ac215404b70b94cdf7b33b2e4c9f3292/href</a></iframe><h4>Want to learn more?</h4><p>I can talk about this for hours so if you want to know more details, feel free to contact me on <a href="https://twitter.com/EmilioPelaez">twitter</a>. You can also find my email and other social media profiles on my <a href="http://oili.me">website</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c9261abb8912" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Temporary Relocation]]></title>
            <link>https://medium.com/@Pelaez/temporary-relocation-b23b6b062458?source=rss-aff864e8163------2</link>
            <guid isPermaLink="false">https://medium.com/p/b23b6b062458</guid>
            <category><![CDATA[travel]]></category>
            <category><![CDATA[digital-nomads]]></category>
            <category><![CDATA[workation]]></category>
            <category><![CDATA[remote-working]]></category>
            <dc:creator><![CDATA[Emilio Peláez]]></dc:creator>
            <pubDate>Sun, 18 Sep 2016 16:29:29 GMT</pubDate>
            <atom:updated>2016-09-18T16:29:29.269Z</atom:updated>
            <content:encoded><![CDATA[<p>I started working at Savvy Apps as a remote worker almost two years ago. I was living in Vancouver at the time, having just finished the Game Design program at the Vancouver Film School; but I had to move back to Mexico City only two months later when my student visa expired.</p><p>You’d be hard-pressed to find somebody who doesn’t like to travel. I’m not the exception. Thanks to my parents I had the opportunity to travel quite a bit when I was younger. It was living in Vancouver, however, what sparked my interest in living in other cities. I had visited a lot of places, but before Vancouver I had never had the chance to experience actually living outside of Mexico City.</p><p>During a visit to the Savvy Apps headquarters in Reston, Va., I brought this up to my boss, Ken. His reply was that as long as the quality of my work didn’t decrease, and I adjusted my work hours to sync as much as possible with the work hours in the office, it didn’t matter where I was working from. I can’t overstate how grateful I am with Ken and Savvy Apps for this unique opportunity.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/563/1*RXi1F2iIf8vBHzFzXJL61Q.jpeg" /><figcaption>Working at Savvy Apps is pretty cool.</figcaption></figure><p>I started planning the trip when I returned to Mexico. My goal was to spend less than six months in Mexico City during 2016. My initial plan consisted of two, three-month trips around Europe, since three months is the longest you can stay in Europe with a Mexican passport. After learning that the UK doesn’t share immigration laws with the rest of Europe, my plan changed into a single, five-month trip with three months in Europe and two in the UK. This would also save me some money on airfare.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/942/1*RYKcOYyeDJJc7I75rSL98w.png" /></figure><p>The next step was picking the five cities I’d be staying in. Five cities might sound like a small number for a five-month trip, but it makes a lot more sense when you remember that I’d still be working 40-hour weeks. The five cities I picked were Paris, Sheffield, Edinburgh, Milano and Lisboa.</p><p>I’m often asked how I picked where I’d be staying. I didn’t have a criteria other than a general idea of countries I wanted to visit, and in many cases it boiled down to Airbnb availability. Sheffield seems like the odd one out of the list because even though it’s England’s fourth largest city, it doesn’t have a lot going on for it. What Sheffield does have is a a couple of universities and a lot of students, one of whom happened to be one of my best friends, who I hadn’t seen in seven months.</p><p>Packing took a long time, but in the end I managed to pack everything I would need into a 22kg suitcase and a backpack. I knew I’d be using public transit often, and this setup allowed me to have one hand free while I pulled my suitcase with the other. I put all my important stuff into the backpack and all my clothes, shoes and other stuff in the suitcase. Having everything I’d need for five months in just two bags was a little bit surreal and really put things into perspective.</p><p>I arrived at Paris after a 12-hour flight. Unfortunately, je ne parle pas français. I tried using Duolingo a few times before the trip, but I didn’t put enough time into it. It didn’t help that the course is not designed to teach you useful stuff right away; it takes it’s time with the basics. Even if I had used it consistently, though, I don’t know if it would’ve helped a lot since Parisians are notoriously hard to understand. Thankfully, many spoke English, especially the younger people. Reading was a lot easier as a lot of French words are very similar to words in English or Spanish. It was a similar situation in Italy and Portugal, the two other countries where English isn’t the native language.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/750/1*x7ZUCi1zUpcxEjGHFFIh4w.jpeg" /><figcaption>Not terribly useful.</figcaption></figure><p>I used Airbnb for all my accommodations. My budget was $1500/month, and I found very nice apartments in every city I stayed in. I managed to stay under budget outside of the UK, and went over it in the UK. It might sound like an exaggeration but I don’t think I could have made this trip without Airbnb. It gave me the combination of privacy, comfort and reliable WiFi that I couldn’t have gotten from a hotel or a hostel. The only downside I found is that you have to pay when you book, and it’s best to book a few months in advance to find good places, so I was out several thousand dollars a few months before I even started my tip.</p><p>Making sure I could do my job was a top priority for me. There are two main things I need to work, one is my Mac and the other is an internet connection. I knew I’d have WiFi in every apartment I’d be staying in, but in case it failed I also bought a SIM card with data in every country I visited.</p><p>Ever since I moved to Vancouver over three years ago, I’ve been buying my iPhones, unlocked, directly from Apple. This allowed me to use any SIM I wanted and avoid ridiculous roaming charges. An internet connection on my phone was also very useful to navigate, find places to eat, and translate the things I didn’t understand. The Google Translate app, which can translate directly from the camera, proved to be very useful.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/727/1*aUSPSowNeDiQj4un6_RryA.jpeg" /><figcaption>Five of the seven SIM cards I bought</figcaption></figure><p>I usually paid about 20 euros for 2 or 3 GB per month, except in the UK, where I paid 20 pounds for an insane 12 GB per month. Apparently mobile internet in the UK is quite cheap to make up for the fact that everything else is very expensive.</p><p>Working in Europe during American work hours was confusing at first, but by the end I actually liked it. I usually started at 1 or 2 p.m., depending on the time zone. Sometimes I worked my eight hours straight and went for a late dinner afterwards; sometimes I took a break to get something to eat; and sometimes I’d go out at night after work. This meant I had the mornings free, which turned out alright because most museums and galleries close at around 6. I also had weekends free, of course, and during those days I could go to places that required more time than I could have in the morning of a weekday.</p><p>I’m not a terribly extroverted person — I probably wouldn’t be a good programmer if I was — and being in a city where I don’t speak the language just makes meeting people more complicated. What I found to be very effective was to go to <a href="http://couchsurfing.com">Couchsurfing</a> events. Even though I was not looking to host or be hosted, a lot of people there are travelers and most of them speak English. I ended up making a lot of friends and as a side effect the number of posts in my Facebook feed that are in a language I can’t understand has increased substantially.</p><p>One of the first things people ask you when they learn you are travelling is whether you are doing it for business or pleasure. My situation was not very common. I only met one other person, a programmer as well, who was doing the same thing. It always took some time to explain that I was travelling for pleasure and that my job allowed me to work remotely, “you’re very lucky to be able to do that” was the most common response.</p><p>In the end I spent more than a month in four of the cities I visited. Saying I <em>lived</em> in those cities feels like a bit of a stretch but I definitely experienced them in a way that most travellers don’t. They say that travel broadens the mind, and after all the different experiences I had during these few months, which I wouldn’t have had any other way, I think I can vouch for that.</p><p>I landed in Mexico City a few weeks ago. Overall I spent 20 weeks away, lived in five cities and visited more than 16 cities in seven countries with over seven different official languages, used three currencies, took 10 flights and 26 trains, and went through one Brexit.</p><p>You can see some of the photos I took in my <a href="https://www.instagram.com/emiliopelaez/">Instagram</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Pz8zye78eqvLtO93xkRD3w.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b23b6b062458" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>