Skip to content

Commit 35b5b60

Browse files
committedMar 19, 2025
adds the last couple of english articles, adds translated by line
1 parent 6b47895 commit 35b5b60

File tree

27 files changed

+1046
-23
lines changed

27 files changed

+1046
-23
lines changed
 

‎site/Build/apps/index.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
<div class="content">
3737
<div>
3838
<article>
39-
<h1>Apps</h1>
39+
<h1 style="margin-bottom: 0">Apps</h1>
4040
<p></p>
4141
<div id="apps">
4242
<div class="app reversed">
@@ -51,7 +51,7 @@ <h2>F1LandinhoBot</h2>
5151
</div>
5252
<div class="app">
5353
<div class="left">
54-
<img src="/images/apps/nsbrazil-small.png" height="600px" />
54+
<img src="/images/apps/nsbrazil-small.png" />
5555
</div>
5656
<div class="right">
5757
<h2>NSBrazil</h2>

‎site/Build/br/appclips/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
<div>
4343
<article>
4444
<img alt="" src="/images/appclips/header.png" class="rounded" />
45-
<h1>Criando o seu primeiro App Clip</h1>
45+
<h1 style="margin-bottom: 0">Criando o seu primeiro App Clip</h1>
4646
<p></p>
4747
<p>Na WWDC 2020, um dos anúncios mais interessantes que acabou passando batido foi o surgimento dos App Clips. App Clips são pequenos pedaços de apps que podem ser baixados sem a necessidade de passar por toda a burocracia de usar a App Store. Foram feitos para interações rápidas e simples, mas podem ser uma ótima porta de entrada do usuário para conhecer o seu app!</p>
4848
<p>Os App Clips tem um tamanho limite de 10MB por Clip, então é importante escolher bem a funcionalidade que você quer apresentar para o seu usuário nele! Neste artigo, vamos ver como foi criar o App Clip da NSBrazil, que mostra o cronograma de atividades do evento para o usuário. O importante é escolher uma funcionalidade que pode ser utilizada "na hora" pelo usuário, pois o App Clip é deletado após 30 dias e não vira um ícone na home screen do usuário para que ele acesse o aplicativo depois. Alguns exemplos interessantes são fluxos de pagamento (você pode usar o Apple Pay para deixar a interação ainda mais simples!) ou um trial de uma funcionalidade do seu app, para convencer o usuário a instalar a experiência completa.</p>

‎site/Build/br/event-based-architechture-for-spritekit/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
<div>
4343
<article>
4444
<img alt="" src="/images/images/spritekit/logo.png" class="rounded" />
45-
<h1>Arquitetura baseada em eventos para SpriteKit</h1>
45+
<h1 style="margin-bottom: 0">Arquitetura baseada em eventos para SpriteKit</h1>
4646
<p></p>
4747
<p>Este artigo é um pedaço do que apresentei na <a href="https://www.youtube.com/watch?v=69lGgGLGoJQ">talk que dei no CocoaHeads ES em Vitória</a>, realizado na Brooder, em novembro de 2019, "Criando o seu primeiro jogo com SpriteKit". Lá, falo um pouco mais sobre os objetos, funcionalidades e lifecycle do SpriteKit em si, além de introduzir a arquitetura baseada em eventos.</p>
4848
<p>O SpriteKit é um framework desenvolvido pela Apple para a criação de jogos de alta performance em 2D. Como ex-desenvolvedor de jogos, este framework me atraiu naturalmente assim que comecei a estudar Swift e desenvolver apps, mas como desenvolvia com a Unity, que é bastante opinativa em sua arquitetura, fiquei um pouco perdido ao tentar criar experiências com ele. A talk que fiz e por consequência este artigo são o resultado de uma tentativa de deixar o desenvolvimento com SpriteKit mais estruturado para facilitar o seu entendimento.</p>

‎site/Build/br/serversideswift/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
<div>
4343
<article>
4444
<img alt="" src="/images/serverswift/tux.png" class="rounded" />
45-
<h1>Vamos falar de Swift no Linux?</h1>
45+
<h1 style="margin-bottom: 0">Vamos falar de Swift no Linux?</h1>
4646
<p></p>
4747
<p>Swift no Linux é uma área pouco explorada pelo desenvolvedor de plataformas Apple, mas pode ser uma ferramenta muito útil e uma fonte de conhecimento imensa, e que vale muito a pena de se aprender.</p>
4848
<p>Escrever o código todos nós já entendemos bem, e ver o resultado da nossa criação não é muito diferente das outras plataformas quando estamos no servidor, mas uma coisa que eu pessoalmente sempre tive muito problema é: Como eu faço o meu código ficar disponível para outras pessoas? A gente já sabe como subir um app na App Store, mas e subir um serviço aberto na internet? Existem tantas formas, todas corretas, cada uma de seu jeito e é quase impossível escolher uma.</p>

‎site/Build/br/swiftui-motion-effects/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
<div>
4343
<article>
4444
<img alt="" src="/images/motion/header.jpg" class="rounded" />
45-
<h1>Fazendo MotionEffects com SwiftUI</h1>
45+
<h1 style="margin-bottom: 0">Fazendo MotionEffects com SwiftUI</h1>
4646
<p></p>
4747
<p>Pequenos detalhes fazem toda a diferença, e pequenos detalhes me deixam desproporcionalmente feliz, porque trazem deleite, fazem com que pequenas interações que temos com os nossos aparelhos um sejam pouco mais legais, mais divertidas. E o que mais pode nos fazer felizes, como desenvolvedores? O SwiftUI, é claro!</p>
4848
<p>Uma das interações mais legais e super tranquilas da gente implementar nos nossos apps UIKit é o UIInterpolationMotionEffect, que dá aquele efeito de parallax quando mexemos o celular, mais conhecido pelo efeito <a href="https://support.apple.com/pt-br/HT200285">Perspectiva</a> que podemos aplicar nas imagens de fundo de nossos iPhones e iPads. Mas quando tentei adicionar um em minha View de SwiftUI, fui pego por isso daqui:</p>

‎site/Build/br/unity3d-and-apple/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
<div class="content">
4040
<div>
4141
<article>
42-
<h1>Unity3D e o mundo Apple</h1>
42+
<h1 style="margin-bottom: 0">Unity3D e o mundo Apple</h1>
4343
<p></p>
4444
<div class="alert">
4545
<h3>Alerta</h3>

‎site/Build/contact/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
<a href="/en" id="title" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover"><p style="font-weight: 500">MC</p></a>
2626
<ul>
2727
<li><a href="/en" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>articles</p></a></li>
28-
<li><a href="/apps" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>apps</p></a></li>
28+
<li><a href="/en/apps" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>apps</p></a></li>
2929
<li><a href="/contact" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>contact</p></a></li>
3030
<li><a href="https://nsbrazil.com" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>NSBrazil</p></a></li>
3131
<li><a href="/" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>🇧🇷</p></a></li>

‎site/Build/css/style.css

+3
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,9 @@ article iframe {
765765
flex-direction: column-reverse;
766766
}
767767
}
768+
#apps .app .left {
769+
width: 100%;
770+
}
768771
@media (max-width: 767px) {
769772
#apps .app .left {
770773
display: flex;

‎site/Build/en/appclips/index.html

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
<!doctype html>
2+
<html data-bs-theme="auto" lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta content="width=device-width, initial-scale=1" name="viewport" />
6+
<meta content="In this article I share my experience of creating an App Clip for the biggest Apple platforms event in Brazil and show you how easy it is to create your own!" name="description" />
7+
<meta content="Mauricio Cardozo" name="author" />
8+
<meta content="Ignite v0.2.1" name="generator" />
9+
<title>Creating Your First App Clip – Mauricio Cardozo</title>
10+
<link href="https://mauriciocardozo.me/en/appclips" rel="canonical" />
11+
<meta content="Mauricio Cardozo" property="og:site_name" />
12+
<meta content="https://mauriciocardozo.me/appclips/header.png" property="og:image" />
13+
<meta content="https://mauriciocardozo.me/appclips/header.png" name="twitter:image" />
14+
<meta content="Creating Your First App Clip" property="og:title" />
15+
<meta content="Creating Your First App Clip" name="twitter:title" />
16+
<meta content="In this article I share my experience of creating an App Clip for the biggest Apple platforms event in Brazil and show you how easy it is to create your own!" property="og:description" />
17+
<meta content="In this article I share my experience of creating an App Clip for the biggest Apple platforms event in Brazil and show you how easy it is to create your own!" name="twitter:description" />
18+
<meta content="https://mauriciocardozo.me/en/appclips" property="og:url" />
19+
<meta content="mauriciocardozo.me" name="twitter:domain" />
20+
<meta content="summary_large_image" name="twitter:card" />
21+
<meta content="on" name="twitter:dnt" />
22+
<meta content="article" name="og:type" />
23+
<meta content="en" name="og:locale" />
24+
<meta content="In this article I share my experience of creating an App Clip for the biggest Apple platforms event in Brazil and show you how easy it is to create your own!" property="og:description" />
25+
<link href="/css/style.css" rel="stylesheet" />
26+
</head>
27+
<body class="container">
28+
<nav>
29+
<div class="site-navigation">
30+
<a href="/en" id="title" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover"><p style="font-weight: 500">MC</p></a>
31+
<ul>
32+
<li><a href="/en" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>articles</p></a></li>
33+
<li><a href="/en/apps" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>apps</p></a></li>
34+
<li><a href="/contact" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>contact</p></a></li>
35+
<li><a href="https://nsbrazil.com" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>NSBrazil</p></a></li>
36+
<li><a href="/" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>🇧🇷</p></a></li>
37+
</ul>
38+
</div>
39+
</nav>
40+
<main>
41+
<div class="content">
42+
<div>
43+
<article>
44+
<img alt="" src="/images/appclips/header.png" class="rounded" />
45+
<h1 style="margin-bottom: 0">Creating Your First App Clip</h1>
46+
<p class="muted caption" style="text-align: start">Article originally written in brazilian portuguese. Translated by: Kayque Moraes</p>
47+
<p></p>
48+
<p>At WWDC 2020, one of the most interesting announcements that ended up being overlooked was the emergence of App Clips. App Clips are small pieces of apps that can be downloaded without the need to go through all the bureaucracy of using the App Store. They were made for quick and simple interactions, but they can be a great entry point for users to get to know your app!</p>
49+
<p>App Clips have a size limit of 10MB per clip, so it's important to carefully choose the functionality you want to present to your user! In this article, we’re going to see how it was to create the NSBrazil App Clip, which shows the event's activity schedule to the user. The key is to choose a feature that can be used instantly by the user, as the App Clip is deleted after 30 days and doesn’t become an icon on the home screen. Some interesting examples include payment flows (you can use Apple Pay to make the experience even simpler!) or a trial of some feature in your app to convince the user to install the complete experience.</p>
50+
<img src="/images/appclips/chibi-clip.png" height="300px" />
51+
<p class="center muted caption">Test this Clip! I bet you won’t be disappointed.</p>
52+
<p>Starting from the beginning, App Clips are just like any other apps, with a few limitations. To create them, simply add a new target to your project with the desired App Clip. Since it is possible to create multiple clips per app, it’s a good idea to use a bundle identifier that represents your clip’s functionality. Don’t worry too much about this—you can create and configure others later. In the NSBrazil app, I created it as <code>com.cocoaheads.conf.baseClip</code>.</p>
53+
<img src="/images/appclips/creating-clip-target.png" />
54+
<p>One of the coolest things about App Clips is that they are required to support iOS 14+, meaning we can use SwiftUI's app lifecycle instead of UIKit’s classic App/SceneDelegate. You can still use the old approach, of course, but if we can opt for a simpler process, why not?</p>
55+
<pre class="splash"><code><span class="keyword">@main<br />struct</span> NSClipApp: <span class="type">App</span> {
56+
<span class="keyword">@StateObject var</span> feedModel = <span class="type">FeedViewModel</span>()
57+
58+
<span class="keyword">var</span> body: <span class="keyword">some</span> <span class="type">Scene</span> {
59+
<span class="type">WindowGroup</span> {
60+
<span class="type">ZStack</span> {
61+
<span class="keyword">switch</span> feedModel.<span class="property">isLoading</span> {
62+
<span class="keyword">case</span> .<span class="dotAccess">loading</span>:
63+
<span class="type">ActivityIndicatorView</span>()
64+
<span class="keyword">case</span> .<span class="dotAccess">loaded</span>:
65+
loadedBody
66+
<span class="keyword">case</span> .<span class="dotAccess">failed</span>:
67+
errorBody
68+
}
69+
}
70+
}
71+
}
72+
73+
<span class="keyword">var</span> loadedBody: <span class="keyword">some</span> <span class="type">View</span> {
74+
<span class="type">VStack</span> {
75+
<span class="type">DownloadCallToAction</span>()
76+
.<span class="call">padding</span>(.<span class="dotAccess">bottom</span>)
77+
<span class="type">ScheduleListView</span>(viewModel: feedModel)
78+
}
79+
}
80+
81+
<span class="keyword">var</span> errorBody: <span class="keyword">some</span> <span class="type">View</span> {
82+
<span class="type">VStack</span>(spacing: <span class="number">20</span>) {
83+
<span class="type">Text</span>(<span class="string">"Something went wrong"</span>)
84+
.<span class="call">font</span>(<span class="type">Font</span>.<span class="property">title</span>.<span class="call">bold</span>())
85+
86+
<span class="type">Button</span>(action: {
87+
<span class="keyword">self</span>.<span class="property">feedModel</span>.<span class="call">fetchInfo</span>()
88+
}, label: {
89+
<span class="type">Text</span>(<span class="string">"Try Again"</span>)
90+
})
91+
}
92+
}
93+
}</code></pre>
94+
<p>There are three ways to handle the Clip's code: create everything again for the Clip, mark existing files for compilation in the Clip target, or embed a framework from the main app into the Clip. Rewriting everything can lead to duplicated bugs and maintenance issues.</p>
95+
<p>In NSBrazil's App Clip, there’s a <code>View</code> that exists only within the Clip because it wouldn’t make sense in the full app. Using frameworks allows us to reuse modularized code and create multiple Clips without worrying about compilation flags. For NSBrazil, the simplest approach was chosen—marking files for compilation in the Clip. However, the long-term goal is to move everything into a framework to maintain the app's evolution.</p>
96+
<p>For Clip-specific code adjustments, we can use compiler flags in <code>Swift Compiler - Custom Flags</code> by adding <code>-D &lt;YOURFLAGNAME&gt;</code>:</p>
97+
<img src="/images/appclips/swiftflag.png" />
98+
<pre class="splash"><code><span class="type">VStack</span>(alignment: .<span class="dotAccess">leading</span>, spacing: <span class="number">5</span>) {
99+
<span class="type">Spacer</span>().<span class="call">frame</span>(maxHeight: <span class="number">5</span>)
100+
<span class="type">Text</span>(feedItem.<span class="property">name</span>)
101+
.<span class="call">font</span>(.<span class="dotAccess">headline</span>)
102+
<span class="type">Text</span>(feedItem.<span class="property">speaker</span>)
103+
.<span class="call">lineLimit</span>(<span class="number">3</span>)
104+
.<span class="call">font</span>(.<span class="call">system</span>(size: <span class="number">14</span>))
105+
.<span class="call">lineSpacing</span>(<span class="number">4</span>)
106+
<span class="type">Text</span>(<span class="call">date</span>())
107+
.<span class="call">font</span>(.<span class="dotAccess">callout</span>)
108+
.<span class="call">fontWeight</span>(.<span class="dotAccess">bold</span>)
109+
.<span class="call">foregroundColor</span>(.<span class="dotAccess">gray</span>)
110+
<span class="preprocessing">#if APPCLIP</span>
111+
<span class="type">Text</span>(<span class="string">"I am running inside the App Clip!"</span>)
112+
<span class="preprocessing">#endif</span>
113+
<span class="type">Spacer</span>().<span class="call">frame</span>(maxHeight: <span class="number">5</span>)
114+
}</code></pre>
115+
<img src="/images/appclips/clipcomparison.png" />
116+
<h2>Testing the App Clip</h2>
117+
<p>To properly test the App Clip, enable the associated domain capability:</p>
118+
<img src="/images/appclips/assoc-domains.png" />
119+
<p>Then, create a Local Experience in Developer settings (<code>Developer -&gt; Local Experiences -&gt; Register Local Experience</code>):</p>
120+
<img src="/images/appclips/local-experience.png" />
121+
<p>To test on other devices, archive an <em>ad-hoc</em> version or upload the app to <code>TestFlight</code>.</p>
122+
<img src="/images/appclips/testflight.png" />
123+
<p>To check the App Clip's size, archive it for <em>ad-hoc</em> installations and review the <code>App Thinning Size Report.txt</code>. The <strong>uncompressed</strong> size for the <code>Universal</code> variant must be under 10MB.</p>
124+
<p>{% highlight plain %} Variant: NSClip.ipa Supported variant descriptors: Universal App + On Demand Resources size: 333 KB compressed, 667 KB uncompressed App size: 333 KB compressed, 667 KB uncompressed On Demand Resources size: Zero KB compressed, Zero KB uncompressed {% endhighlight %}</p>
125+
<h2>Publishing the App Clip</h2>
126+
<p>App Clips can be accessed via NFC tags, QR Codes, website banners, App Clip codes, Apple Maps, and Siri suggestions. By setting up a URL domain, you cover all except Maps and Siri.</p>
127+
<p>Add a JSON file to your server at <code>.well-known/apple-app-site-association</code>:</p>
128+
<pre class="splash"><code>{
129+
<span class="string">"appclips"</span>: {
130+
<span class="string">"apps"</span>: [
131+
<span class="string">"TEAMIDENTIFIER.bundle.identifier.of.your.clip"</span>
132+
]
133+
}
134+
}</code></pre>
135+
<p>If using GitHub Pages, CloudFlare Workers can serve the JSON:</p>
136+
<pre class="splash"><code><span class="call">addEventListener</span>('fetch', event =&gt; {
137+
event.<span class="call">respondWith</span>(<span class="call">handleRequest</span>(event.<span class="property">request</span>))
138+
})
139+
140+
<span class="keyword">async</span> function <span class="call">handleRequest</span>(request) {
141+
<span class="keyword">let</span> aasa = <span class="type">JSON</span>.<span class="call">stringify</span>({
142+
appclips: {
143+
apps: [<span class="string">"V45SL99ZK4.com.cocoaheadsbr.conf.baseClip"</span>]
144+
}
145+
})
146+
<span class="keyword">return</span> new <span class="type">Response</span>(aasa, {
147+
headers: {
148+
<span class="string">"content-type"</span>: <span class="string">"application/json"</span>
149+
},
150+
status: <span class="number">200</span>
151+
})
152+
}</code></pre>
153+
<p>For easy access, create a QR Code or App Clip Code via App Store Connect or the <a href="https://developer.apple.com/app-clips/resources/">App Clip Code Generator</a>. You can also add a Smart App Banner:</p>
154+
<pre class="splash"><code>&lt;meta name=<span class="string">"apple-itunes-app"</span> content=<span class="string">"app-id=1180455342, app-clip-bundle-id=com.cocoaheads.conf.baseClip"</span>&gt;</code></pre>
155+
<img src="/images/appclips/nsclip.svg" />
156+
<p>Finally, configure your App Clip experience in App Store Connect and wait up to 48 hours for propagation.</p>
157+
<img src="/images/appclips/appstore.png" />
158+
<p>That’s it! Your App Clip is ready to be shared. Check out the full NSBrazil app on <a href="https://github.com/CocoaHeadsConference/CHConferenceApp">GitHub</a>, built entirely with SwiftUI for iOS 13+!</p>
159+
<p></p>
160+
</article>
161+
</div>
162+
</div>
163+
</main>
164+
</body>
165+
</html>

‎site/Build/en/apps/index.html

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<!doctype html>
2+
<html data-bs-theme="auto" lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta content="width=device-width, initial-scale=1" name="viewport" />
6+
<meta content="Mauricio Cardozo" name="author" />
7+
<meta content="Ignite v0.2.1" name="generator" />
8+
<title>Apps – Mauricio Cardozo</title>
9+
<link href="https://mauriciocardozo.me/en/apps" rel="canonical" />
10+
<meta content="Mauricio Cardozo" property="og:site_name" />
11+
<meta content="Apps" property="og:title" />
12+
<meta content="Apps" name="twitter:title" />
13+
<meta content="https://mauriciocardozo.me/en/apps" property="og:url" />
14+
<meta content="mauriciocardozo.me" name="twitter:domain" />
15+
<meta content="summary_large_image" name="twitter:card" />
16+
<meta content="on" name="twitter:dnt" />
17+
<meta content="article" name="og:type" />
18+
<meta content="en" name="og:locale" />
19+
<meta content="" property="og:description" />
20+
<link href="/css/style.css" rel="stylesheet" />
21+
</head>
22+
<body class="container">
23+
<nav>
24+
<div class="site-navigation">
25+
<a href="/en" id="title" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover"><p style="font-weight: 500">MC</p></a>
26+
<ul>
27+
<li><a href="/en" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>articles</p></a></li>
28+
<li><a href="/en/apps" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>apps</p></a></li>
29+
<li><a href="/contact" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>contact</p></a></li>
30+
<li><a href="https://nsbrazil.com" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>NSBrazil</p></a></li>
31+
<li><a href="/" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>🇧🇷</p></a></li>
32+
</ul>
33+
</div>
34+
</nav>
35+
<main>
36+
<div class="content">
37+
<div>
38+
<article>
39+
<h1 style="margin-bottom: 0">Apps</h1>
40+
<p class="muted caption" style="text-align: start">Article originally written in brazilian portuguese. Translated by: Kayque Moraes</p>
41+
<p></p>
42+
<div id="apps">
43+
<div class="app reversed">
44+
<div class="left">
45+
<img src="/images/serverswift/telegram.png" width="100%" />
46+
</div>
47+
<div class="right">
48+
<h2>F1LandinhoBot</h2>
49+
<p> F1LandinhoBot is a Telegram bot that brings the calendars of the main global and Brazilian motorsport categories directly to your chat, perfect for groups of friends who follow Formula 1 and other categories. Built with <a href="/post/serversideswift">Swift on Linux</a>, the bot uses an API built with Vapor. </p>
50+
<p> Want to know when the next F1 race is? <a href="https://t.me/F1LandinhoBot">Ask Landinho</a> </p>
51+
</div>
52+
</div>
53+
<div class="app">
54+
<div class="left">
55+
<img src="/images/apps/nsbrazil-small.png" />
56+
</div>
57+
<div class="right">
58+
<h2>NSBrazil</h2>
59+
<p> NSBrazil is the official app of the largest Apple platform conference in Brazil, with the official event calendar, videos, and other information. Built entirely with SwiftUI, the app is made for iOS, iPadOS, and macOS Catalyst, and its interface is entirely Server-Driven. I am the maintainer of this app, and the code for this app is available on <a href="https://github.com/CocoaHeadsConference">GitHub</a>. </p>
60+
<strong>Try the app</strong>
61+
<a href="https://apps.apple.com/br/app/nsbrazil/id1180455342" style="background-color: unset"> <img src="/images/appclips/nsclip.svg" height="300px" /> </a>
62+
</div>
63+
</div>
64+
</div>
65+
<p></p>
66+
</article>
67+
</div>
68+
</div>
69+
</main>
70+
</body>
71+
</html>
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<!doctype html>
2+
<html data-bs-theme="auto" lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta content="width=device-width, initial-scale=1" name="viewport" />
6+
<meta content="Hype or truly useful? In this talk, I gave an overview of what it is, the first steps, and why you should or shouldn't use the much-discussed TCA." name="description" />
7+
<meta content="Mauricio Cardozo" name="author" />
8+
<meta content="Ignite v0.2.1" name="generator" />
9+
<title>Let's Talk About Composable Architecture? – Mauricio Cardozo</title>
10+
<link href="https://mauriciocardozo.me/en/composable-talk" rel="canonical" />
11+
<meta content="Mauricio Cardozo" property="og:site_name" />
12+
<meta content="Let's Talk About Composable Architecture?" property="og:title" />
13+
<meta content="Let's Talk About Composable Architecture?" name="twitter:title" />
14+
<meta content="Hype or truly useful? In this talk, I gave an overview of what it is, the first steps, and why you should or shouldn't use the much-discussed TCA." property="og:description" />
15+
<meta content="Hype or truly useful? In this talk, I gave an overview of what it is, the first steps, and why you should or shouldn't use the much-discussed TCA." name="twitter:description" />
16+
<meta content="https://mauriciocardozo.me/en/composable-talk" property="og:url" />
17+
<meta content="mauriciocardozo.me" name="twitter:domain" />
18+
<meta content="summary_large_image" name="twitter:card" />
19+
<meta content="on" name="twitter:dnt" />
20+
<meta content="article" name="og:type" />
21+
<meta content="en" name="og:locale" />
22+
<meta content="Hype or truly useful? In this talk, I gave an overview of what it is, the first steps, and why you should or shouldn't use the much-discussed TCA." property="og:description" />
23+
<link href="/css/style.css" rel="stylesheet" />
24+
</head>
25+
<body class="container">
26+
<nav>
27+
<div class="site-navigation">
28+
<a href="/en" id="title" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover"><p style="font-weight: 500">MC</p></a>
29+
<ul>
30+
<li><a href="/en" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>articles</p></a></li>
31+
<li><a href="/en/apps" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>apps</p></a></li>
32+
<li><a href="/contact" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>contact</p></a></li>
33+
<li><a href="https://nsbrazil.com" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>NSBrazil</p></a></li>
34+
<li><a href="/" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>🇧🇷</p></a></li>
35+
</ul>
36+
</div>
37+
</nav>
38+
<main>
39+
<div class="content">
40+
<div>
41+
<p><iframe width="100%" height="500" src="https://www.youtube.com/embed/qbOXLK7S9_c?si=kWllG2u1XMPWyJVx" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe></p>
42+
<h1>Let's Talk About Composable Architecture?</h1>
43+
<p></p>
44+
<p>Hype or truly useful? In this talk, I gave an overview of what it is, the first steps, and why you should or shouldn't use the much-discussed TCA. This talk was presented at the <a href="https://www.meetup.com/cocoaheadscps/events/294304619/">45th CocoaTalks Campinas</a>.</p>
45+
<p>The talk notes are available <a href="/talks/composable">here</a>.</p>
46+
<p></p>
47+
</div>
48+
</div>
49+
</main>
50+
</body>
51+
</html>

‎site/Build/en/event-based-architecture-for-spritekit/index.html

+3-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
<a href="/en" id="title" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover"><p style="font-weight: 500">MC</p></a>
3131
<ul>
3232
<li><a href="/en" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>articles</p></a></li>
33-
<li><a href="/apps" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>apps</p></a></li>
33+
<li><a href="/en/apps" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>apps</p></a></li>
3434
<li><a href="/contact" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>contact</p></a></li>
3535
<li><a href="https://nsbrazil.com" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>NSBrazil</p></a></li>
3636
<li><a href="/" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>🇧🇷</p></a></li>
@@ -42,7 +42,8 @@
4242
<div>
4343
<article>
4444
<img alt="" src="/images/images/spritekit/logo.png" class="rounded" />
45-
<h1>Event-Based Architecture for SpriteKit</h1>
45+
<h1 style="margin-bottom: 0">Event-Based Architecture for SpriteKit</h1>
46+
<p class="muted caption" style="text-align: start">Article originally written in brazilian portuguese. Translated by: Kayque Moraes</p>
4647
<p></p>
4748
<p>This article is part of what I presented in the <a href="https://www.youtube.com/watch?v=69lGgGLGoJQ">talk I gave at CocoaHeads ES in Vitória</a>, held at Brooder in November 2019, "Creating Your First Game with SpriteKit." There, I talk a little more about the objects, features, and lifecycle of SpriteKit itself, as well as introducing the event-based architecture.</p>
4849
<p>SpriteKit is a framework developed by Apple for the creation of high-performance 2D games. As a former game developer, this framework naturally attracted me as soon as I started studying Swift and developing apps. However, as I was working with Unity, which has a highly opinionated architecture, I initially felt lost when trying to create experiences with SpriteKit. The talk I gave and, consequently, this article, are the result of an attempt to make development with SpriteKit more structured to facilitate its understanding.</p>

‎site/Build/en/index.html

+13-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
<a href="/en" id="title" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover"><p style="font-weight: 500">MC</p></a>
2626
<ul>
2727
<li><a href="/en" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>articles</p></a></li>
28-
<li><a href="/apps" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>apps</p></a></li>
28+
<li><a href="/en/apps" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>apps</p></a></li>
2929
<li><a href="/contact" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>contact</p></a></li>
3030
<li><a href="https://nsbrazil.com" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>NSBrazil</p></a></li>
3131
<li><a href="/" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>🇧🇷</p></a></li>
@@ -43,6 +43,18 @@ <h2>Apple tech talk and the like</h2>
4343
<h2><a href="/en/serversideswift" class="inverted link-underline link-underline-opacity-100 link-underline-opacity-100-hover">Let's talk about Swift on Linux?</a></h2>
4444
<p>Swift on Linux is an area little explored by Apple platform developers, but it can be a very useful tool and an immense source of knowledge, and it is very worth learning.</p>
4545
</div>
46+
<div>
47+
<h2><a href="/en/composable-talk" class="inverted link-underline link-underline-opacity-100 link-underline-opacity-100-hover">Let's Talk About Composable Architecture?</a></h2>
48+
<p>Hype or truly useful? In this talk, I gave an overview of what it is, the first steps, and why you should or shouldn’t use the much-discussed TCA.</p>
49+
</div>
50+
<div>
51+
<h2><a href="/en/appclips" class="inverted link-underline link-underline-opacity-100 link-underline-opacity-100-hover">Creating Your First App Clip</a></h2>
52+
<p>In this article I share my experience of creating an App Clip for the biggest Apple platforms event in Brazil and show you how easy it is to create your own!</p>
53+
</div>
54+
<div>
55+
<h2><a href="/en/swiftui-motion-effects" class="inverted link-underline link-underline-opacity-100 link-underline-opacity-100-hover">Making MotionEffects with SwiftUI</a></h2>
56+
<p>Have you ever tried applying motion effects to SwiftUI views? No? Come with me!</p>
57+
</div>
4658
<div>
4759
<h2><a href="/en/event-based-architecture-for-spritekit" class="inverted link-underline link-underline-opacity-100 link-underline-opacity-100-hover">Event-Based Architecture for SpriteKit</a></h2>
4860
<p>Let’s take a look at how we can simplify app development with SpriteKit.</p>

‎site/Build/en/serversideswift/index.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
<a href="/en" id="title" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover"><p style="font-weight: 500">MC</p></a>
3131
<ul>
3232
<li><a href="/en" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>articles</p></a></li>
33-
<li><a href="/apps" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>apps</p></a></li>
33+
<li><a href="/en/apps" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>apps</p></a></li>
3434
<li><a href="/contact" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>contact</p></a></li>
3535
<li><a href="https://nsbrazil.com" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>NSBrazil</p></a></li>
3636
<li><a href="/" class="inverted link-plain link-underline link-underline-opacity-100 link-underline-opacity-100-hover m-0"><p>🇧🇷</p></a></li>
@@ -42,9 +42,9 @@
4242
<div>
4343
<article>
4444
<img alt="" src="/images/serverswift/tux.png" class="rounded" />
45-
<h1>Let's talk about Swift on Linux?</h1>
45+
<h1 style="margin-bottom: 0">Let's talk about Swift on Linux?</h1>
46+
<p class="muted caption" style="text-align: start">Article originally written in brazilian portuguese. Translated by: Kayque Moraes</p>
4647
<p></p>
47-
<h2>Let's talk about Swift on Linux?</h2>
4848
<p>Swift on Linux is an area little explored by Apple platform developers, but it can be a very useful tool and an immense source of knowledge, and it is very worth learning.</p>
4949
<p>We all already understand writing code, and seeing the result of our creation is not very different from other platforms when we are on the server, but one thing that I personally have always had a lot of problems with is: How do I make my code available to other people? We already know how to upload an app to the App Store, but what about uploading an open service on the internet? There are so many ways, all correct, each in its own way and it is almost impossible to choose one.</p>
5050
<h2>The Project</h2>

‎site/Build/en/swiftui-motion-effects/index.html

+238
Large diffs are not rendered by default.

‎site/Build/feed.rss

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
<?xml version="1.0" encoding="UTF-8" ?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Mauricio Cardozo</title><description></description><link>https://mauriciocardozo.me</link><atom:link
22
href="https://mauriciocardozo.me/feed.rss"
33
rel="self" type="application/rss+xml"
4-
/><language>en</language><generator>Ignite v0.2.1</generator><item><guid isPermaLink="true">https://mauriciocardozo.me/apps</guid><title>Apps</title><link>https://mauriciocardozo.me/apps</link><description><![CDATA[]]></description><pubDate>Wed, 12 Mar 2025 00:27:27 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/en/serversideswift</guid><title>Let's talk about Swift on Linux?</title><link>https://mauriciocardozo.me/en/serversideswift</link><description><![CDATA[Swift on Linux is an area little explored by Apple platform developers, but it can be a very useful tool and an immense source of knowledge, and it is very worth learning.]]></description><pubDate>Wed, 25 Oct 2023 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/br/serversideswift</guid><title>Vamos falar de Swift no Linux?</title><link>https://mauriciocardozo.me/br/serversideswift</link><description><![CDATA[Swift no Linux é uma área pouco explorada pelo desenvolvedor de plataformas Apple, mas pode ser uma ferramenta muito útil e uma fonte de conhecimento imensa, e que vale muito a pena de se aprender.]]></description><pubDate>Wed, 25 Oct 2023 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/br/composable-talk</guid><title>Vamos falar de Composable Architecture?</title><link>https://mauriciocardozo.me/br/composable-talk</link><description><![CDATA[Hype ou útil de verdade? Nesta talk dei um overview do que é, os primeiros passos e por que usar ou não a tão falada TCA]]></description><pubDate>Wed, 28 Jun 2023 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/br/appclips</guid><title>Criando o seu primeiro App Clip</title><link>https://mauriciocardozo.me/br/appclips</link><description><![CDATA[Neste artigo conto como foi a experiência de criar um App Clip para o app do maior evento de plataformas Apple do Brasil, e te falo como é fácil fazer o seu próprio!]]></description><pubDate>Tue, 26 Jan 2021 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/br/swiftui-motion-effects</guid><title>Fazendo MotionEffects com SwiftUI</title><link>https://mauriciocardozo.me/br/swiftui-motion-effects</link><description><![CDATA[Já tentou aplicar efeitos de movimento em views de SwiftUI? Não? Vem comigo!]]></description><pubDate>Sat, 01 Aug 2020 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/en/event-based-architecture-for-spritekit</guid><title>Event-Based Architecture for SpriteKit</title><link>https://mauriciocardozo.me/en/event-based-architecture-for-spritekit</link><description><![CDATA[Let's take a look at how we can simplify app development with SpriteKit.]]></description><pubDate>Sun, 19 Jul 2020 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/br/event-based-architechture-for-spritekit</guid><title>Arquitetura baseada em eventos para SpriteKit</title><link>https://mauriciocardozo.me/br/event-based-architechture-for-spritekit</link><description><![CDATA[Vamos dar uma olhada em como podemos facilitar o desenvolvimento de apps com SpriteKit]]></description><pubDate>Sun, 19 Jul 2020 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/br/unity3d-and-apple</guid><title>Unity3D e o mundo Apple</title><link>https://mauriciocardozo.me/br/unity3d-and-apple</link><description><![CDATA[Este artigo é um espelho do meu artigo publicado para o equinociOS 2016, uma reunião de artigos criados durante o equinócio feitos pela comunidade Apple no Brasil.]]></description><pubDate>Fri, 11 Mar 2016 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item></channel></rss>
4+
/><language>en</language><generator>Ignite v0.2.1</generator><item><guid isPermaLink="true">https://mauriciocardozo.me/en/apps</guid><title>Apps</title><link>https://mauriciocardozo.me/en/apps</link><description><![CDATA[]]></description><pubDate>Wed, 19 Mar 2025 12:07:26 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/apps</guid><title>Apps</title><link>https://mauriciocardozo.me/apps</link><description><![CDATA[]]></description><pubDate>Wed, 12 Mar 2025 00:27:27 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/en/serversideswift</guid><title>Let's talk about Swift on Linux?</title><link>https://mauriciocardozo.me/en/serversideswift</link><description><![CDATA[Swift on Linux is an area little explored by Apple platform developers, but it can be a very useful tool and an immense source of knowledge, and it is very worth learning.]]></description><pubDate>Wed, 25 Oct 2023 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/br/serversideswift</guid><title>Vamos falar de Swift no Linux?</title><link>https://mauriciocardozo.me/br/serversideswift</link><description><![CDATA[Swift no Linux é uma área pouco explorada pelo desenvolvedor de plataformas Apple, mas pode ser uma ferramenta muito útil e uma fonte de conhecimento imensa, e que vale muito a pena de se aprender.]]></description><pubDate>Wed, 25 Oct 2023 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/en/composable-talk</guid><title>Let's Talk About Composable Architecture?</title><link>https://mauriciocardozo.me/en/composable-talk</link><description><![CDATA[Hype or truly useful? In this talk, I gave an overview of what it is, the first steps, and why you should or shouldn't use the much-discussed TCA.]]></description><pubDate>Wed, 28 Jun 2023 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/br/composable-talk</guid><title>Vamos falar de Composable Architecture?</title><link>https://mauriciocardozo.me/br/composable-talk</link><description><![CDATA[Hype ou útil de verdade? Nesta talk dei um overview do que é, os primeiros passos e por que usar ou não a tão falada TCA]]></description><pubDate>Wed, 28 Jun 2023 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/en/appclips</guid><title>Creating Your First App Clip</title><link>https://mauriciocardozo.me/en/appclips</link><description><![CDATA[In this article I share my experience of creating an App Clip for the biggest Apple platforms event in Brazil and show you how easy it is to create your own!]]></description><pubDate>Tue, 26 Jan 2021 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/br/appclips</guid><title>Criando o seu primeiro App Clip</title><link>https://mauriciocardozo.me/br/appclips</link><description><![CDATA[Neste artigo conto como foi a experiência de criar um App Clip para o app do maior evento de plataformas Apple do Brasil, e te falo como é fácil fazer o seu próprio!]]></description><pubDate>Tue, 26 Jan 2021 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/en/swiftui-motion-effects</guid><title>Making MotionEffects with SwiftUI</title><link>https://mauriciocardozo.me/en/swiftui-motion-effects</link><description><![CDATA[Have you ever tried applying motion effects to SwiftUI views? No? Come with me!]]></description><pubDate>Sat, 01 Aug 2020 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/br/swiftui-motion-effects</guid><title>Fazendo MotionEffects com SwiftUI</title><link>https://mauriciocardozo.me/br/swiftui-motion-effects</link><description><![CDATA[Já tentou aplicar efeitos de movimento em views de SwiftUI? Não? Vem comigo!]]></description><pubDate>Sat, 01 Aug 2020 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/en/event-based-architecture-for-spritekit</guid><title>Event-Based Architecture for SpriteKit</title><link>https://mauriciocardozo.me/en/event-based-architecture-for-spritekit</link><description><![CDATA[Let's take a look at how we can simplify app development with SpriteKit.]]></description><pubDate>Sun, 19 Jul 2020 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/br/event-based-architechture-for-spritekit</guid><title>Arquitetura baseada em eventos para SpriteKit</title><link>https://mauriciocardozo.me/br/event-based-architechture-for-spritekit</link><description><![CDATA[Vamos dar uma olhada em como podemos facilitar o desenvolvimento de apps com SpriteKit]]></description><pubDate>Sun, 19 Jul 2020 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item><item><guid isPermaLink="true">https://mauriciocardozo.me/br/unity3d-and-apple</guid><title>Unity3D e o mundo Apple</title><link>https://mauriciocardozo.me/br/unity3d-and-apple</link><description><![CDATA[Este artigo é um espelho do meu artigo publicado para o equinociOS 2016, uma reunião de artigos criados durante o equinócio feitos pela comunidade Apple no Brasil.]]></description><pubDate>Fri, 11 Mar 2016 00:00:00 +0000</pubDate><dc:creator><![CDATA[Mauricio Cardozo]]></dc:creator></item></channel></rss>

‎site/Build/sitemap.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"><url><loc>https://mauriciocardozo.me/</loc><priority>1.0</priority></url><url><loc>https://mauriciocardozo.me/contact</loc><priority>0.9</priority></url><url><loc>https://mauriciocardozo.me/me</loc><priority>0.9</priority></url><url><loc>https://mauriciocardozo.me/br</loc><priority>0.9</priority></url><url><loc>https://mauriciocardozo.me/en</loc><priority>0.9</priority></url><url><loc>https://mauriciocardozo.me/apps</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/en/serversideswift</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/br/serversideswift</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/br/composable-talk</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/br/appclips</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/br/swiftui-motion-effects</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/en/event-based-architecture-for-spritekit</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/br/event-based-architechture-for-spritekit</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/br/unity3d-and-apple</loc><priority>0.8</priority></url></urlset>
1+
<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"><url><loc>https://mauriciocardozo.me/</loc><priority>1.0</priority></url><url><loc>https://mauriciocardozo.me/contact</loc><priority>0.9</priority></url><url><loc>https://mauriciocardozo.me/me</loc><priority>0.9</priority></url><url><loc>https://mauriciocardozo.me/br</loc><priority>0.9</priority></url><url><loc>https://mauriciocardozo.me/en</loc><priority>0.9</priority></url><url><loc>https://mauriciocardozo.me/en/apps</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/apps</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/en/serversideswift</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/br/serversideswift</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/en/composable-talk</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/br/composable-talk</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/en/appclips</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/br/appclips</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/en/swiftui-motion-effects</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/br/swiftui-motion-effects</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/en/event-based-architecture-for-spritekit</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/br/event-based-architechture-for-spritekit</loc><priority>0.8</priority></url><url><loc>https://mauriciocardozo.me/br/unity3d-and-apple</loc><priority>0.8</priority></url></urlset>

‎site/Content/apps.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ hidden: true
2626

2727
<div class='app'>
2828
<div class='left'>
29-
<img src="/images/apps/nsbrazil-small.png" height="600px">
29+
<img src="/images/apps/nsbrazil-small.png" />
3030
</div>
3131

3232
<div class='right'>

‎site/Content/en/appclips.md

+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
---
2+
title: Creating Your First App Clip
3+
description: In this article I share my experience of creating an App Clip for the biggest Apple platforms event in Brazil and show you how easy it is to create your own!
4+
published: true
5+
header: /appclips/header.png
6+
layout: ArticleLayout
7+
date: 2021-01-26 00:00:00
8+
translated: Kayque Moraes
9+
language: en
10+
---
11+
12+
At WWDC 2020, one of the most interesting announcements that ended up being overlooked was the emergence of App Clips. App Clips are small pieces of apps that can be downloaded without the need to go through all the bureaucracy of using the App Store. They were made for quick and simple interactions, but they can be a great entry point for users to get to know your app!
13+
14+
App Clips have a size limit of 10MB per clip, so it's important to carefully choose the functionality you want to present to your user! In this article, we’re going to see how it was to create the NSBrazil App Clip, which shows the event's activity schedule to the user. The key is to choose a feature that can be used instantly by the user, as the App Clip is deleted after 30 days and doesn’t become an icon on the home screen. Some interesting examples include payment flows (you can use Apple Pay to make the experience even simpler!) or a trial of some feature in your app to convince the user to install the complete experience.
15+
16+
<img src="/images/appclips/chibi-clip.png" height="300px" />
17+
<p class="center muted caption">Test this Clip! I bet you won’t be disappointed.</p>
18+
19+
Starting from the beginning, App Clips are just like any other apps, with a few limitations. To create them, simply add a new target to your project with the desired App Clip. Since it is possible to create multiple clips per app, it’s a good idea to use a bundle identifier that represents your clip’s functionality. Don’t worry too much about this—you can create and configure others later. In the NSBrazil app, I created it as `com.cocoaheads.conf.baseClip`.
20+
21+
![](appclips/creating-clip-target.png)
22+
23+
One of the coolest things about App Clips is that they are required to support iOS 14+, meaning we can use SwiftUI's app lifecycle instead of UIKit’s classic App/SceneDelegate. You can still use the old approach, of course, but if we can opt for a simpler process, why not?
24+
25+
```
26+
@main
27+
struct NSClipApp: App {
28+
@StateObject var feedModel = FeedViewModel()
29+
30+
var body: some Scene {
31+
WindowGroup {
32+
ZStack {
33+
switch feedModel.isLoading {
34+
case .loading:
35+
ActivityIndicatorView()
36+
case .loaded:
37+
loadedBody
38+
case .failed:
39+
errorBody
40+
}
41+
}
42+
}
43+
}
44+
45+
var loadedBody: some View {
46+
VStack {
47+
DownloadCallToAction()
48+
.padding(.bottom)
49+
ScheduleListView(viewModel: feedModel)
50+
}
51+
}
52+
53+
var errorBody: some View {
54+
VStack(spacing: 20) {
55+
Text("Something went wrong")
56+
.font(Font.title.bold())
57+
58+
Button(action: {
59+
self.feedModel.fetchInfo()
60+
}, label: {
61+
Text("Try Again")
62+
})
63+
}
64+
}
65+
}
66+
```
67+
68+
There are three ways to handle the Clip's code: create everything again for the Clip, mark existing files for compilation in the Clip target, or embed a framework from the main app into the Clip. Rewriting everything can lead to duplicated bugs and maintenance issues.
69+
70+
In NSBrazil's App Clip, there’s a `View` that exists only within the Clip because it wouldn’t make sense in the full app. Using frameworks allows us to reuse modularized code and create multiple Clips without worrying about compilation flags. For NSBrazil, the simplest approach was chosen—marking files for compilation in the Clip. However, the long-term goal is to move everything into a framework to maintain the app's evolution.
71+
72+
For Clip-specific code adjustments, we can use compiler flags in `Swift Compiler - Custom Flags` by adding `-D <YOURFLAGNAME>`:
73+
74+
![](appclips/swiftflag.png)
75+
76+
```
77+
VStack(alignment: .leading, spacing: 5) {
78+
Spacer().frame(maxHeight: 5)
79+
Text(feedItem.name)
80+
.font(.headline)
81+
Text(feedItem.speaker)
82+
.lineLimit(3)
83+
.font(.system(size: 14))
84+
.lineSpacing(4)
85+
Text(date())
86+
.font(.callout)
87+
.fontWeight(.bold)
88+
.foregroundColor(.gray)
89+
#if APPCLIP
90+
Text("I am running inside the App Clip!")
91+
#endif
92+
Spacer().frame(maxHeight: 5)
93+
}
94+
```
95+
96+
![](appclips/clipcomparison.png)
97+
98+
## Testing the App Clip
99+
100+
To properly test the App Clip, enable the associated domain capability:
101+
102+
![](appclips/assoc-domains.png)
103+
104+
Then, create a Local Experience in Developer settings (`Developer -> Local Experiences -> Register Local Experience`):
105+
106+
![](appclips/local-experience.png)
107+
108+
To test on other devices, archive an *ad-hoc* version or upload the app to `TestFlight`.
109+
110+
![](appclips/testflight.png)
111+
112+
To check the App Clip's size, archive it for *ad-hoc* installations and review the `App Thinning Size Report.txt`. The **uncompressed** size for the `Universal` variant must be under 10MB.
113+
114+
{% highlight plain %}
115+
Variant: NSClip.ipa
116+
Supported variant descriptors: Universal
117+
App + On Demand Resources size: 333 KB compressed, 667 KB uncompressed
118+
App size: 333 KB compressed, 667 KB uncompressed
119+
On Demand Resources size: Zero KB compressed, Zero KB uncompressed
120+
{% endhighlight %}
121+
122+
## Publishing the App Clip
123+
124+
App Clips can be accessed via NFC tags, QR Codes, website banners, App Clip codes, Apple Maps, and Siri suggestions. By setting up a URL domain, you cover all except Maps and Siri.
125+
126+
Add a JSON file to your server at `.well-known/apple-app-site-association`:
127+
128+
```
129+
{
130+
"appclips": {
131+
"apps": [
132+
"TEAMIDENTIFIER.bundle.identifier.of.your.clip"
133+
]
134+
}
135+
}
136+
```
137+
138+
If using GitHub Pages, CloudFlare Workers can serve the JSON:
139+
140+
```
141+
addEventListener('fetch', event => {
142+
event.respondWith(handleRequest(event.request))
143+
})
144+
145+
async function handleRequest(request) {
146+
let aasa = JSON.stringify({
147+
appclips: {
148+
apps: ["V45SL99ZK4.com.cocoaheadsbr.conf.baseClip"]
149+
}
150+
})
151+
return new Response(aasa, {
152+
headers: {
153+
"content-type": "application/json"
154+
},
155+
status: 200
156+
})
157+
}
158+
```
159+
160+
For easy access, create a QR Code or App Clip Code via App Store Connect or the [App Clip Code Generator](https://developer.apple.com/app-clips/resources/). You can also add a Smart App Banner:
161+
162+
```
163+
<meta name="apple-itunes-app" content="app-id=1180455342, app-clip-bundle-id=com.cocoaheads.conf.baseClip">
164+
```
165+
166+
![](appclips/nsclip.svg)
167+
168+
Finally, configure your App Clip experience in App Store Connect and wait up to 48 hours for propagation.
169+
170+
![](appclips/appstore.png)
171+
172+
That’s it! Your App Clip is ready to be shared. Check out the full NSBrazil app on [GitHub](https://github.com/CocoaHeadsConference/CHConferenceApp), built entirely with SwiftUI for iOS 13+!
173+

‎site/Content/en/apps.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
layout: ArticleLayout
3+
title: Apps
4+
hidden: true
5+
translated: Kayque Moraes
6+
language: en
7+
---
8+
9+
<div id='apps'>
10+
<div class='app reversed'>
11+
<div class='left'>
12+
<img src="/images/serverswift/telegram.png" width='100%'>
13+
</div>
14+
<div class='right'>
15+
<h2>F1LandinhoBot</h2>
16+
<p>
17+
F1LandinhoBot is a Telegram bot that brings the calendars of the main global and Brazilian motorsport categories directly to your chat, perfect for groups of friends who follow Formula 1 and other categories. Built with <a href='/post/serversideswift'>Swift on Linux</a>, the bot uses an API built with Vapor.
18+
</p>
19+
20+
<p>
21+
Want to know when the next F1 race is? <a href="https://t.me/F1LandinhoBot">Ask Landinho</a>
22+
</p>
23+
</div>
24+
</div>
25+
26+
<div class='app'>
27+
<div class='left'>
28+
<img src="/images/apps/nsbrazil-small.png" />
29+
</div>
30+
<div class='right'>
31+
<h2>NSBrazil</h2>
32+
<p>
33+
NSBrazil is the official app of the largest Apple platform conference in Brazil, with the official event calendar, videos, and other information. Built entirely with SwiftUI, the app is made for iOS, iPadOS, and macOS Catalyst, and its interface is entirely Server-Driven. I am the maintainer of this app, and the code for this app is available on <a href='https://github.com/CocoaHeadsConference'>GitHub</a>.
34+
</p>
35+
36+
<strong>Try the app</strong>
37+
<a href="https://apps.apple.com/br/app/nsbrazil/id1180455342" style='background-color: unset'>
38+
<img src="/images/appclips/nsclip.svg" height="300px">
39+
</a>
40+
</div>
41+
</div>
42+
</div>

‎site/Content/en/composable-talk.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
title: Let's Talk About Composable Architecture?
3+
description: Hype or truly useful? In this talk, I gave an overview of what it is, the first steps, and why you should or shouldn't use the much-discussed TCA.
4+
published: true
5+
layout: VideoLayout
6+
video: https://www.youtube.com/embed/qbOXLK7S9_c?si=kWllG2u1XMPWyJVx
7+
date: 2023-06-28 00:00:00
8+
translated: Kayque Moraes
9+
language: en
10+
---
11+
12+
Hype or truly useful? In this talk, I gave an overview of what it is, the first steps, and why you should or shouldn't use the much-discussed TCA. This talk was presented at the [45th CocoaTalks Campinas](https://www.meetup.com/cocoaheadscps/events/294304619/).
13+
14+
The talk notes are available [here](/talks/composable).

‎site/Content/en/event-based-architecture-for-spritekit.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ published: true
66
header: /images/spritekit/logo.png
77
layout: ArticleLayout
88
date: 2020-07-19 00:00:00
9-
translated: Kayque
9+
translated: Kayque Moraes
1010
language: en
1111
---
1212

‎site/Content/en/serversideswift.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@ published: true
66
layout: ArticleLayout
77
header: /serverswift/tux.png
88
date: 2023-10-25 00:00:00
9-
translated: Kayque
9+
translated: Kayque Moraes
1010
language: en
1111
---
1212

13-
## Let's talk about Swift on Linux?
14-
1513
Swift on Linux is an area little explored by Apple platform developers, but it can be a very useful tool and an immense source of knowledge, and it is very worth learning.
1614

1715
We all already understand writing code, and seeing the result of our creation is not very different from other platforms when we are on the server, but one thing that I personally have always had a lot of problems with is: How do I make my code available to other people? We already know how to upload an app to the App Store, but what about uploading an open service on the internet? There are so many ways, all correct, each in its own way and it is almost impossible to choose one.
+245
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
---
2+
title: Making MotionEffects with SwiftUI
3+
thumbnail:
4+
description: Have you ever tried applying motion effects to SwiftUI views? No? Come with me!
5+
published: true
6+
header: /motion/header.jpg
7+
layout: ArticleLayout
8+
date: 2020-08-01 00:00:00
9+
translated: Kayque Moraes
10+
language: en
11+
---
12+
13+
The small details make all the difference, and small details make me more happy than they should, because they bring delight, make the small interactions that we have with our devices a little cooler, more fun. And what else can make us happy as developers? SwiftUI, of course!
14+
15+
One of the coolest and super smooth interactions for us to implement in our UIKit apps is the `UIInterpolationMotionEffect`, which gives that parallax effect when we move the phone, better known as the [Perspective effect](https://support.apple.com/pt-br/HT200285) that we can apply on the background images of our iPhones and iPads. But when I tried to add one in my SwiftUI View, I got caught by this:
16+
17+
![Image with a SwiftUI view where a motionEffect fails to apply, because it doesn't exist](motion/motionError.png)
18+
19+
Then I discovered, searching through the documentation, that there is no way to place an effect like this natively with SwiftUI! My first thought was to create a `UIViewRepresentable` that had my View inside a SwiftUI container, making a SwiftUI -> UIKit -> SwiftUI bridge, which I tried to do, without much success.
20+
21+
So I decided to see if it was possible to read the device’s sensor and manually recreate this behavior, creating a view that seems more "native" to SwiftUI. And with [CoreMotion](https://developer.apple.com/documentation/coremotion) all of this is not only possible but also very easy, and it will be easier for us to create composite effects, such as elements that move at different speeds according to my device’s movement.
22+
23+
To access the device's accelerometer/gyroscope data, we need a `CMMotionManager` instance, that [according to Apple’s recommendations](https://developer.apple.com/documentation/coremotion/cmmotionmanager), needs to be shared:
24+
25+
```swift
26+
import CoreMotion
27+
28+
extension CMMotionManager {
29+
static var shared = CMMotionManager()
30+
}
31+
```
32+
33+
With `CMMotionManager`, we can access the accelerometer, gyroscope, magnetometer, and device-motion, which is a multitude of data inferred by the Core Motion algorithms. Because I want to make my effect with the device’s rotation, I will use the gyroscope, which measures each rotation axis of the device. First, I will create a `View` that is going to handle this reading and, just like the [GeometryReader](https://developer.apple.com/documentation/swiftui/geometryreader) does, expose this data to child views, and make the necessary `MotionManager` settings in it, like the data update interval (with an update frequency of 30x per second), the start/end of data reading, and the publisher where we will read and process this data:
34+
35+
```swift
36+
struct MotionReader<Content>: View where Content: View {
37+
38+
private let contentView: () -> Content
39+
private let motionManager: CMMotionManager = .shared
40+
private let timer = Timer.publish(every: 1/30, on: .main, in: .common).autoconnect()
41+
42+
init(@ViewBuilder content: @escaping () -> Content) {
43+
contentView = content
44+
}
45+
46+
var body: some View {
47+
contentView()
48+
.onAppear {
49+
self.motionManager.gyroUpdateInterval = 1/30
50+
self.motionManager.startGyroUpdates()
51+
}
52+
.onDisappear {
53+
self.motionManager.stopAccelerometerUpdates()
54+
}
55+
.onReceive(timer) { _ in }
56+
}
57+
}
58+
```
59+
60+
And then we can start reading our manager’s data, changing `onReceive`. I also created a `struct` that encapsulates the gyroscope data (x,y, and z axes) to pass it to our child views:
61+
62+
```
63+
/// MotionReader.swift
64+
private let contentView: (MotionProxy) -> Content
65+
@State private var currentOffset: MotionProxy = .zero
66+
...
67+
contentView(currentOffset)
68+
...
69+
.onReceive(timer) { _ in
70+
guard let data = self.motionManager.gyroData else { return }
71+
let rate = data.rotationRate
72+
self.currentOffset = MotionProxy(x: rate.x, y: rate.y, z: rate.z)
73+
}
74+
75+
/// ContentView.swift
76+
struct ContentView: some View {
77+
var body: some View {
78+
MotionReader { proxy in
79+
CardView()
80+
.offset(x: proxy.x, y: proxy.y)
81+
}
82+
}
83+
}
84+
```
85+
86+
<video loop autoplay muted>
87+
<source type="video/mp4" src="/images/motion/effectless.mp4">
88+
</video>
89+
<p>
90+
<span class="caption muted">I had to shake <strong>a lot</strong> to get this little bit of change</span>
91+
</p>
92+
93+
Doing all this, we must run the app on the device (the simulator doesn’t have CoreMotion support, unfortunately), and then we can attest that almost nothing has changed, and the little that has is not noticeable when we use the device itself, being only visible on a video on a still screen. Furthermore, the movement is very shaky.
94+
95+
The values that the gyroscope emits are very low, so we need to manipulate them in a way that the `offset` of the card is altered with more intensity, and we can set some limits, like the `minimumRelativeValue` and `maximumRelativeValue` properties of the `UIInterpolationMotionEffect`, in addition to adding a basic animation to the view, so that the shaking stops:
96+
97+
```
98+
private let strength: Double
99+
private let minimum: Double
100+
private let maximum: Double
101+
...
102+
init(motionRange: ClosedRange<Double> = (-5.0...5.0),
103+
motionStrength: Double = 1,
104+
@ViewBuilder content: @escaping (MotionProxy) -> Content) {
105+
minimum = motionRange.lowerBound
106+
maximum = motionRange.upperBound
107+
contentView = content
108+
strength = motionStrength * 5
109+
}
110+
111+
var body: some View {
112+
contentView()
113+
.animation(.linear)
114+
.onAppear {
115+
self.motionManager.gyroUpdateInterval = 1/30
116+
self.motionManager.startGyroUpdates()
117+
}
118+
.onDisappear {
119+
self.motionManager.stopAccelerometerUpdates()
120+
}
121+
.onReceive(timer) { _ in
122+
guard let data = self.motionManager.gyroData else { return }
123+
let rate = data.rotationRate
124+
self.currentOffset = calculateOffset(x: rate.x, y: rate.y, z: rate.z)
125+
}
126+
}
127+
128+
private func calculateOffset(x: Double, y: Double, z: Double) -> MotionProxy {
129+
let xAxis = max(minimum, min((x * strength), maximum))
130+
let yAxis = max(minimum, min((y * strength), maximum))
131+
return MotionProxy(x: xAxis, y: yAxis, z: z)
132+
}
133+
```
134+
135+
<video loop autoplay muted>
136+
<source type="video/mp4" src="/images/motion/smooth-comp.mp4">
137+
</video>
138+
<p>
139+
<span class="caption muted">It's much smoother now, right? I was shaking the iPad again</span>
140+
</p>
141+
142+
Now in addition to having a much smoother animation, we can set all the movement values so that the effect is exactly the way we want! But when turning the device, we can see that the movement is not going in the same direction when we move our device. Why? The x and y coordinates of my view and the coordinates that the gyroscope is emitting are not consistent in each orientation, so we need to calculate and swap the values.
143+
144+
For this, we need to create a way to detect when the device changes orientation and change the offset calculation accordingly, and this is very simple:
145+
146+
```
147+
/// DeviceOrientation.swift
148+
final class DeviceOrientation: ObservableObject {
149+
private var observer: AnyCancellable?
150+
@Published var deviceOrientation: UIDeviceOrientation
151+
152+
init() {
153+
deviceOrientation = UIDevice.current.orientation
154+
observeOrientation()
155+
}
156+
157+
private func observeOrientation() {
158+
observer = NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)
159+
.compactMap({ $0.object as? UIDevice})
160+
.sink { [weak self] device in
161+
self?.deviceOrientation = device.orientation
162+
}
163+
}
164+
}
165+
166+
/// MotionReader.swift
167+
@ObservedObject var deviceOrientation = DeviceOrientation()
168+
...
169+
.onReceive(timer) { _ in
170+
guard let data = self.motionManager.gyroData else { return }
171+
let rate = data.rotationRate
172+
self.currentOffset = calculateOffsetForCurrentOrientation(x: rate.x, y: rate.y, z: rate.z)
173+
}
174+
175+
private func calculateOffsetForCurrentOrientation(x: Double, y: Double, z: Double) -> MotionProxy {
176+
let xAxis = max(minimum, min((x * strength), maximum))
177+
let yAxis = max(minimum, min((y * strength), maximum))
178+
179+
switch deviceOrientation.deviceOrientation {
180+
case .portrait:
181+
return MotionProxy(x: yAxis, y: xAxis, z: z)
182+
case .portraitUpsideDown:
183+
return MotionProxy(x: yAxis, y: -xAxis, z: z)
184+
case .landscapeLeft:
185+
return MotionProxy(x: -xAxis, y: -yAxis, z: z)
186+
case .landscapeRight:
187+
return MotionProxy(x: -xAxis, y: yAxis, z: z)
188+
case .unknown, .faceDown, .faceUp:
189+
return MotionProxy(x: xAxis, y: yAxis, z: z)
190+
@unknown default:
191+
return MotionProxy(x: xAxis, y: yAxis, z: z)
192+
}
193+
}
194+
```
195+
196+
Finally, our reader should respect any setting that the user can make on the device, such as [low power mode](https://developer.apple.com/documentation/foundation/processinfo/1617047-islowpowermodeenabled) and accessibility configuration to [reduce motion](https://developer.apple.com/videos/play/wwdc2019/244/):
197+
198+
```
199+
/// MotionReader.swift
200+
@Environment(\.accessibilityReduceMotion) var isReduceMotionOn: Bool
201+
...
202+
.onAppear {
203+
guard self.shouldEnableMotion else { return }
204+
self.motionManager.gyroUpdateInterval = 1/30
205+
self.motionManager.startGyroUpdates()
206+
}
207+
...
208+
.onReceive(timer) { publisher in
209+
guard self.shouldEnableMotion,
210+
let data = self.motionManager.gyroData else { return }
211+
212+
let rate = data.rotationRate
213+
self.currentOffset = self.calculateOffsetForCurrentOrientation(x: rate.x, y: rate.y, z: rate.z)
214+
}
215+
...
216+
private var shouldEnableMotion: Bool {
217+
!ProcessInfo.processInfo.isLowPowerModeEnabled &&
218+
motionManager.isAccelerometerAvailable &&
219+
!isReduceMotionOn
220+
}
221+
```
222+
223+
As a cherry on top to make it easier to use our Reader, we will create a `View` extension that does the entire parallaxing automatically for us!
224+
225+
```
226+
extension View {
227+
func motionEffect(scale: CGFloat = 1.2,
228+
range: ClosedRange<Double> = (-5.0...5.0),
229+
strength: Double = 1) -> some View {
230+
MotionReader(motionRange: range, motionStrength: strength) { proxy in
231+
self
232+
.scaleEffect(scale)
233+
.offset(x: proxy.x, y: proxy.y)
234+
}
235+
}
236+
}
237+
```
238+
239+
And with this, our code from the beginning works perfectly, the way that I wanted it to work :)
240+
241+
![Image with a SwiftUI view where a motionEffect is applied successfully](motion/motionSucc.png)
242+
243+
The complete project with the card example and the gyroscope reader is on my [GitHub](https://github.com/loloop/SwiftInMotion), and I would like to thank [@Alan Pégoli](https://twitter.com/alanpegoli) who did the beta test and pointed out a glaring flaw in the article :)
244+
245+

‎site/Sources/Layouts/ArticleLayout.swift

+8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ struct ArticleLayout: ContentLayout {
1717

1818
Text(content.title)
1919
.font(.title1)
20+
.style(.marginBottom, "0")
21+
22+
if let translated = content.metadata["translated"] as? String {
23+
Text("Article originally written in brazilian portuguese. Translated by: \(translated)")
24+
.class("muted caption")
25+
.style(.textAlign, "start")
26+
}
27+
2028
Text(inkMarkdown: content.body)
2129
}
2230
}

‎site/Sources/Views/Navigation.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ struct Navigation: InlineElement {
2424
List {
2525
articleLink
2626

27-
Link(target: "/apps") {
27+
Link(target: language == .english ? "/en/apps" : "/apps") {
2828
Text("apps")
2929
}
3030
.class("inverted")

‎site/_sass/page-apps.scss

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
}
99

1010
.left {
11+
width: 100%;
12+
1113
@media(max-width: $medium-ish) {
1214
display: flex;
1315
justify-content: center;
@@ -35,4 +37,4 @@
3537
}
3638
}
3739
}
38-
}
40+
}

0 commit comments

Comments
 (0)
Please sign in to comment.