WEBVTT

1
00:00:02.520 --> 00:00:03.940
Hey guys, happy Tuesday.

2
00:00:04.059 --> 00:00:05.680
Welcome to another weekly training

3
00:00:05.680 --> 00:00:07.700
that we're doing with our internal team

4
00:00:07.700 --> 00:00:08.980
here at our dev agency.

5
00:00:09.180 --> 00:00:13.260
We have been working to put these out every Tuesday.

6
00:00:13.420 --> 00:00:15.200
We've been training our team every Tuesday,

7
00:00:15.200 --> 00:00:16.760
and now we're just starting to stream the call.

8
00:00:16.840 --> 00:00:18.820
So if you're interested in learning about how we work

9
00:00:19.120 --> 00:00:21.900
and how we build applications, this

10
00:00:21.900 --> 00:00:23.940
is a great thing to tune into.

11
00:00:24.220 --> 00:00:26.380
So we've been particularly focusing

12
00:00:26.380 --> 00:00:30.200
on how to take the shape up concept from 37signals,

13
00:00:30.380 --> 00:00:32.720
how to take all the AI vibe coding,

14
00:00:33.300 --> 00:00:35.520
and kind of put all that together in a way to have

15
00:00:36.060 --> 00:00:39.000
our team, where we have a single person developing

16
00:00:39.160 --> 00:00:41.440
an application and working with clients,

17
00:00:41.520 --> 00:00:44.180
and how we just organize and run our agency.

18
00:00:44.480 --> 00:00:46.580
So today, we actually have one of our team members,

19
00:00:47.140 --> 00:00:49.740
Janata, who's been working with us, I think,

20
00:00:49.960 --> 00:00:50.860
a little over a year.

21
00:00:51.880 --> 00:00:54.900
And Janata's located in Brazil, and has

22
00:00:54.900 --> 00:00:56.940
been a phenomenal asset to our team,

23
00:00:57.560 --> 00:01:00.900
just has fixed so many things in our previous Flutter flow

24
00:01:01.540 --> 00:01:04.040
applications, and now helped us move out of Flutter flow

25
00:01:04.400 --> 00:01:08.180
into a Flutter app, where we can now use AI and clone

26
00:01:08.580 --> 00:01:09.660
everything to code.

27
00:01:09.720 --> 00:01:10.760
So I'm going to turn this over to him,

28
00:01:10.760 --> 00:01:13.000
and he's going to be doing an introduction to Flutter.

29
00:01:13.120 --> 00:01:15.660
So this is the first time we're working on a Flutter app.

30
00:01:15.720 --> 00:01:17.320
Especially if you're working on it with our team,

31
00:01:17.440 --> 00:01:19.540
this is something that would be required learning,

32
00:01:19.620 --> 00:01:21.900
just to kind of get up to speed on how Flutter works

33
00:01:21.960 --> 00:01:23.600
and how it all connects.

34
00:01:23.600 --> 00:01:25.000
So I'm going to turn it over to Janata.

35
00:01:25.380 --> 00:01:26.980
And there you go.

36
00:01:27.260 --> 00:01:27.760
What's up?

37
00:01:30.120 --> 00:01:30.960
Hey, man.

38
00:01:31.020 --> 00:01:31.720
Thank you, Bruce.

39
00:01:32.280 --> 00:01:35.440
Very happy to share a little bit of my experience.

40
00:01:37.060 --> 00:01:39.520
For this presentation, I prepared

41
00:01:39.800 --> 00:01:43.200
a kind of practical introduction to Flutter and Dart.

42
00:01:43.320 --> 00:01:45.500
And also, we'll be touching a little bit

43
00:01:45.500 --> 00:01:48.280
of how we use it on Tribe Social Mobile.

44
00:01:48.600 --> 00:01:51.280
But the idea is that this presentation

45
00:01:51.280 --> 00:01:54.460
will lay the foundation for future talks

46
00:01:54.460 --> 00:01:56.360
as well, so we can go deeper.

47
00:01:57.120 --> 00:02:00.900
So this will be a really nice overview

48
00:02:00.900 --> 00:02:03.740
over the Flutter structure, the Flutter framework,

49
00:02:04.120 --> 00:02:07.780
and the main concepts that I think

50
00:02:07.780 --> 00:02:11.480
are important to understand in order

51
00:02:11.480 --> 00:02:14.920
to be able to create applications that perform

52
00:02:14.920 --> 00:02:19.000
better and that have a great user experience overall.

53
00:02:19.960 --> 00:02:24.560
So I'm looking at the chat here.

54
00:02:24.640 --> 00:02:28.100
So if anyone has any questions, you can also send on the chat.

55
00:02:28.180 --> 00:02:30.520
I'll be looking at it.

56
00:02:30.800 --> 00:02:36.420
And also, feel free to jump at any time to ask questions.

57
00:02:36.560 --> 00:02:37.720
So let's start.

58
00:02:42.140 --> 00:02:48.980
So let's start with a very, I would

59
00:02:48.980 --> 00:02:49.380
Flutter.

60
00:02:49.600 --> 00:02:51.640
So Flutter is a Google open source.

61
00:02:52.440 --> 00:02:54.180
And this part, it's open source.

62
00:02:54.360 --> 00:02:55.960
I think it's very interesting, because it

63
00:02:55.960 --> 00:02:59.280
allows us to move things around as we need

64
00:02:59.460 --> 00:03:01.680
and really dive deep into the code

65
00:03:01.680 --> 00:03:03.280
if we need to do something custom.

66
00:03:03.460 --> 00:03:05.920
But it's an open source UI toolkit

67
00:03:06.060 --> 00:03:11.840
that enables developers to build natively compiled applications

68
00:03:11.840 --> 00:03:15.300
for mobile and web and desktop.

69
00:03:16.020 --> 00:03:18.860
From a single code base, it's powered by Dart.

70
00:03:19.560 --> 00:03:23.020
And it's three lines development by eliminating,

71
00:03:23.720 --> 00:03:26.720
and I said, like, most of code duplication.

72
00:03:26.880 --> 00:03:30.860
Because as we see, there's still some native coding necessary

73
00:03:30.860 --> 00:03:34.740
for some specific features, especially the ones that

74
00:03:34.740 --> 00:03:37.940
are very hardware dependent or OS dependent.

75
00:03:38.260 --> 00:03:41.540
So it's still needed to do some work on Swift or Kotlin

76
00:03:41.540 --> 00:03:43.740
if we are doing some very specific things.

77
00:03:44.460 --> 00:03:49.820
And also, Flutter was designed to have a native performance

78
00:03:49.820 --> 00:03:52.640
that's achieved through direct compilation.

79
00:03:53.180 --> 00:03:57.220
And I will show how this handling system for Flutter

80
00:03:57.220 --> 00:04:04.260
works and why it's different from other hybrid platforms,

81
00:04:05.580 --> 00:04:06.160
hybrid frameworks.

82
00:04:07.980 --> 00:04:11.820
And I will showcase a little bit of the difference

83
00:04:11.820 --> 00:04:15.100
between web and mobile development for Flutter

84
00:04:15.100 --> 00:04:19.320
and how the performance-wise works for both platforms.

85
00:04:20.620 --> 00:04:23.920
So I added here on the web on the end

86
00:04:23.920 --> 00:04:26.820
that web version still has some handling and scheduling issues.

87
00:04:27.600 --> 00:04:29.900
Mobile is a lot better in terms of performance.

88
00:04:30.060 --> 00:04:32.820
But we'll look through this in detail on the next slide.

89
00:04:34.560 --> 00:04:40.140
So really quick here, doing a kind of reality check

90
00:04:40.900 --> 00:04:43.980
for the cross-platform idea for Flutter.

91
00:04:44.460 --> 00:04:47.860
So the idea is that you write once and you run anywhere.

92
00:04:48.580 --> 00:04:52.040
And this promise does come with a few exceptions,

93
00:04:52.640 --> 00:04:56.400
especially that developers need to tweak the platform's

94
00:04:56.400 --> 00:04:59.100
specific behaviors or accommodate

95
00:04:59.240 --> 00:04:59.980
or add or remove.

96
00:05:00.000 --> 00:05:02.820
OS or hardware level integration separately.

97
00:05:04.180 --> 00:05:09.300
There are tools that we need to use, for instance,

98
00:05:09.360 --> 00:05:16.980
if you are going to depend on a lot of work with camera,

99
00:05:17.160 --> 00:05:20.340
or with the gyroscope from the phone,

100
00:05:20.820 --> 00:05:22.780
from these hardware specific things,

101
00:05:22.920 --> 00:05:28.720
there's a chance that you won't find a Flutter component or a pub,

102
00:05:28.720 --> 00:05:33.620
as we call the extra package we can add on top of the Flutter framework.

103
00:05:34.160 --> 00:05:38.240
You may not find this already done,

104
00:05:38.400 --> 00:05:40.840
like this integration in the hardware level,

105
00:05:40.940 --> 00:05:44.500
so you may need to write native code.

106
00:05:44.920 --> 00:05:49.020
But the interesting part is that Flutter is very open to it,

107
00:05:49.040 --> 00:05:52.400
and it allows for us to have native breed.

108
00:05:52.460 --> 00:05:55.180
You can write your code in Kotlin,

109
00:05:55.300 --> 00:05:56.940
and also you can write in Swift,

110
00:05:56.940 --> 00:06:01.660
and you can use this code on your Flutter application,

111
00:06:01.840 --> 00:06:04.140
which is a very interesting ability that we have.

112
00:06:05.900 --> 00:06:10.880
So that's it in the hardware level integration.

113
00:06:11.700 --> 00:06:15.940
Also, Flutter web apps tend to have larger bundle size,

114
00:06:16.000 --> 00:06:19.280
which impacts initial load times and browser performance.

115
00:06:20.160 --> 00:06:22.120
And SEO remains a challenge,

116
00:06:22.320 --> 00:06:24.340
because as we'll see on the next slide,

117
00:06:25.100 --> 00:06:29.580
Flutter uses a very specific way of rendering the interface.

118
00:06:30.820 --> 00:06:34.120
We basically use painters to draw the interface,

119
00:06:34.280 --> 00:06:39.600
so we are not using the usual HTML or material

120
00:06:39.600 --> 00:06:43.600
or Cupertino components provided by Apple, Google.

121
00:06:45.120 --> 00:06:48.440
So we kind of, the Flutter framework

122
00:06:48.440 --> 00:06:50.900
is drawing everything from zero, let's say,

123
00:06:50.900 --> 00:06:56.440
which is a challenge for having a proper SEO for these pages.

124
00:06:57.280 --> 00:07:00.640
And we also have some browsers compatibility issues,

125
00:07:00.880 --> 00:07:03.500
especially for advanced device features

126
00:07:03.560 --> 00:07:06.800
requiring fallback logic or native implementations.

127
00:07:08.400 --> 00:07:12.040
Flutter web excels at internal tools, dashboards,

128
00:07:12.560 --> 00:07:15.440
complex UIs, and cross-device user experience

129
00:07:15.440 --> 00:07:17.100
where SEO is less important.

130
00:07:17.540 --> 00:07:19.920
These are the ideal use cases for Flutter web.

131
00:07:20.520 --> 00:07:23.800
And also it's great for happy prototyping

132
00:07:24.180 --> 00:07:27.680
and reducing the development cycle

133
00:07:27.680 --> 00:07:31.140
by reusing the logic across different platforms.

134
00:07:31.480 --> 00:07:35.920
And also Flutter web is doing a great job on the PWA side,

135
00:07:36.280 --> 00:07:38.000
on the PWA support side.

136
00:07:38.440 --> 00:07:42.820
So if you have a Flutter web application

137
00:07:42.820 --> 00:07:48.260
that you'll be running only as a PWA,

138
00:07:48.900 --> 00:07:50.920
it usually has a better performance

139
00:07:50.920 --> 00:07:55.420
than if you treat it as a normal web application.

140
00:07:57.980 --> 00:08:02.460
Also, I wanted to kind of bring a little bit of a comparison

141
00:08:05.460 --> 00:08:08.540
across other cross-platform frameworks.

142
00:08:09.200 --> 00:08:11.140
So as you can see here,

143
00:08:11.720 --> 00:08:16.300
the usage of Flutter is growing across the years

144
00:08:16.940 --> 00:08:21.840
and Reactive Native is actually slowing down.

145
00:08:21.860 --> 00:08:27.380
The growth is actually slowing down for this platform

146
00:08:27.380 --> 00:08:31.000
and the user is actually getting lower volume

147
00:08:31.000 --> 00:08:32.179
as the years passes.

148
00:08:32.620 --> 00:08:35.340
And I think a lot of this is because

149
00:08:37.539 --> 00:08:40.080
Flutter has a very interesting ability

150
00:08:41.299 --> 00:08:45.300
in how it's generating, in how it's handling the interface.

151
00:08:45.980 --> 00:08:51.780
So one last piece of information regarding this comparison,

152
00:08:51.960 --> 00:08:53.960
because I think like Reactive Native and Flutter

153
00:08:53.960 --> 00:08:55.320
are the main players

154
00:08:55.320 --> 00:08:59.360
when we talk about hybrid development right now.

155
00:08:59.600 --> 00:09:05.260
So one interesting data is that the Flutter repository

156
00:09:05.260 --> 00:09:08.840
has a little bit more stars than Reactive Native,

157
00:09:09.240 --> 00:09:12.300
showing how the Flutter community is still active.

158
00:09:12.940 --> 00:09:18.920
And one fun fact is that I've started working with Flutter,

159
00:09:19.180 --> 00:09:22.800
I believe like six years ago, six or seven years ago.

160
00:09:23.280 --> 00:09:26.700
And since then, almost every year,

161
00:09:27.460 --> 00:09:31.500
it comes around some form of news that Flutter is dying

162
00:09:31.500 --> 00:09:33.040
or Flutter is dead,

163
00:09:33.120 --> 00:09:37.180
and only to continue living for the next year.

164
00:09:37.300 --> 00:09:41.560
So this is one thing we need to take with a grain of salt

165
00:09:41.560 --> 00:09:46.600
when looking at this type of hybrid platforms development.

166
00:09:47.400 --> 00:09:49.020
So moving forward,

167
00:09:50.020 --> 00:09:53.360
one very important piece of Flutter

168
00:09:53.360 --> 00:09:56.960
is how it works with rendering.

169
00:09:57.640 --> 00:09:59.980
So Flutter delivers a...

170
00:10:00.000 --> 00:10:07.940
native-like apps by skipping the device's built-in UI components, the OEM widgets,

171
00:10:08.480 --> 00:10:14.880
and instead drawing everything itself. So it uses the Skia or Impeller in the

172
00:10:14.880 --> 00:10:20.420
newer version on Flutter 3.29 forward. I think the default is Impeller

173
00:10:20.420 --> 00:10:26.740
handling engine or CanvasKit for the web to handle directly on the device's GPU.

174
00:10:26.740 --> 00:10:33.200
So the OEM widgets in mobile developments refer to the built-in UI

175
00:10:33.200 --> 00:10:37.960
components provided by the device operating system, such as buttons,

176
00:10:38.400 --> 00:10:43.460
sliders, lists, and text fields created by platforms like Android that has the

177
00:10:43.460 --> 00:10:50.740
material guidelines and the iOS with the Cupertino components. So Flutter doesn't

178
00:10:50.740 --> 00:10:57.880
use it directly. If you see the Flutter widget catalog that you'll see a little

179
00:10:57.880 --> 00:11:03.880
bit further on the presentation, you'll see that we have the material widgets and

180
00:11:03.880 --> 00:11:10.500
the Cupertino widgets, but they are being drawn from zero using these rendering

181
00:11:10.500 --> 00:11:19.980
systems instead of relying on converting the code to Swift or to Kotlin to use the

182
00:11:20.230 --> 00:11:25.730
material or Cupertino libraries. We draw it from zero. So these widgets use system

183
00:11:25.730 --> 00:11:30.490
level code and styles, ensuring the app looks and behaves in a way that matches

184
00:11:30.490 --> 00:11:35.790
the native experience of that device, and they're called native because they are

185
00:11:35.790 --> 00:11:41.470
maintained and handled by the operating system, not by the app developer. Flutter

186
00:11:41.470 --> 00:11:48.030
skips all that and draws the interface directly. So this is very important to

187
00:11:48.030 --> 00:11:55.770
be aware because Flutter is very dependent on handling the components, and

188
00:11:55.770 --> 00:12:01.970
this changes a lot on how we think about it in terms of performance of the system.

189
00:12:02.590 --> 00:12:10.870
And so in a lot of cases, we would be avoiding drawing things directly, but in

190
00:12:10.870 --> 00:12:17.830
Flutter click case, it's actually better. So sometimes if we need a very

191
00:12:17.830 --> 00:12:22.110
custom component, sometimes it's just better to just get a custom panther and

192
00:12:22.110 --> 00:12:29.290
draw it on the interface. And since we have this very optimized hander, the

193
00:12:29.290 --> 00:12:36.790
skia or the impaler, it's usually very performance oriented to do this kind of

194
00:12:36.990 --> 00:12:48.790
performance directly using the handlers. So now moving forward about the Flutter

195
00:12:48.810 --> 00:12:56.870
philosophy itself, you see that as we go over the next pages of this

196
00:12:57.510 --> 00:13:04.030
presentation, we will be diving deep into the very initial Flutter concepts that

197
00:13:04.030 --> 00:13:10.390
are necessary to build our knowledge blocks to be able to add more complex

198
00:13:10.390 --> 00:13:16.230
things on top. So first of all, the very basic thing about Flutter is that

199
00:13:16.230 --> 00:13:22.370
everything is a widget. So you hear it often if you read the documentation, if

200
00:13:22.370 --> 00:13:26.750
you're watching tutorial, that widgets are the building blocks of Flutter app's

201
00:13:26.750 --> 00:13:33.890
user interface. And each widget is an immutable declaration of a part of the

202
00:13:33.890 --> 00:13:39.430
user interface. So widgets are used to describe all aspects of a user interface,

203
00:13:39.770 --> 00:13:45.410
including physical aspects such as text, buttons, and even like paddings or

204
00:13:45.410 --> 00:13:51.330
centering something. You don't have like a parameter that you center. Instead, you

205
00:13:51.330 --> 00:13:58.930
have a widget that's called center and all the widgets that are added as child

206
00:13:58.930 --> 00:14:07.210
from this center widget, then will be centered. So it's a very hierarchical

207
00:14:07.490 --> 00:14:14.530
based composition and each widget nests inside its parent and can receive context

208
00:14:14.530 --> 00:14:20.350
from the parent. This structure carries all the way up to the root widget, as we

209
00:14:20.350 --> 00:14:28.530
can see here. So this is basically the hello word from Flutter. So here, as you

210
00:14:28.530 --> 00:14:37.210
can see, we have a material app, which is a widget. So it's the basis where

211
00:14:37.210 --> 00:14:41.850
everything is built on top. It's the material app. And then you have a scaffold,

212
00:14:42.230 --> 00:14:47.330
which is basically a structure that allows you to have an app bar and to have

213
00:14:47.330 --> 00:14:52.330
a body that is the basis for building the rest of the application. And as you

214
00:14:52.330 --> 00:14:59.090
can see here, it's all is very like HTML-like. We'll be nesting these

215
00:14:59.150 --> 00:14:59.750
components.

216
00:15:00.000 --> 00:15:06.980
and when they are indented a little bit further,

217
00:15:07.160 --> 00:15:12.000
this means that this part is a child from this one,

218
00:15:12.040 --> 00:15:15.040
and if they are on the same line,

219
00:15:15.140 --> 00:15:16.120
as you can see here,

220
00:15:16.520 --> 00:15:20.300
this means that they are on the same level of hierarchy.

221
00:15:20.780 --> 00:15:25.300
I have an image below here that makes it easier for us to see.

222
00:15:25.520 --> 00:15:29.220
This is the visual result from

223
00:15:29.220 --> 00:15:31.000
this code would be something like this.

224
00:15:31.140 --> 00:15:33.060
We have a app bar here on the top,

225
00:15:33.620 --> 00:15:39.040
you have the Hello World text that is right here,

226
00:15:39.480 --> 00:15:41.600
and you have a sized box.

227
00:15:42.720 --> 00:15:45.400
Even this sized box is a widget,

228
00:15:45.520 --> 00:15:49.740
which basically a widget that has a specific space to add

229
00:15:50.600 --> 00:15:53.620
between components and a button.

230
00:15:54.200 --> 00:15:55.980
As you can see here on the right,

231
00:15:55.980 --> 00:16:00.920
we can see the hierarchy more easily.

232
00:16:01.420 --> 00:16:05.940
We have the center and the column that's inside the center,

233
00:16:06.100 --> 00:16:08.460
because the column is centered, as you can see here.

234
00:16:08.700 --> 00:16:10.960
It's a child from the center widget,

235
00:16:11.340 --> 00:16:12.900
and then we have the text,

236
00:16:13.400 --> 00:16:14.640
sized box, and button,

237
00:16:15.180 --> 00:16:19.840
all of them as children of the column,

238
00:16:21.760 --> 00:16:23.260
all on the same level.

239
00:16:25.520 --> 00:16:28.240
Moving to the next part,

240
00:16:28.640 --> 00:16:31.600
which is also one of the core concepts of Flutter,

241
00:16:31.840 --> 00:16:35.440
is that we have a declarative UI.

242
00:16:36.160 --> 00:16:39.080
Basically, when you code with Flutter,

243
00:16:39.300 --> 00:16:43.340
you write what the UI should look like.

244
00:16:43.340 --> 00:16:47.640
Rather than imperatively specifying draw steps,

245
00:16:48.500 --> 00:16:52.060
Flutter redraws automatically on when data changes,

246
00:16:52.060 --> 00:16:53.260
similar to React.

247
00:16:55.220 --> 00:16:58.620
For instance, if we look at Swift,

248
00:16:59.180 --> 00:17:06.440
now Swift has a bit more of reactive touches to it,

249
00:17:06.440 --> 00:17:08.319
so it's a little bit more declarative,

250
00:17:08.560 --> 00:17:10.060
especially with the Swift UI.

251
00:17:10.599 --> 00:17:13.460
But on the early days of Swift,

252
00:17:13.839 --> 00:17:17.420
we had a structure very similar to this imperative style.

253
00:17:17.560 --> 00:17:21.859
Imagine that we want to turn this view into this view.

254
00:17:21.859 --> 00:17:24.880
We have a yellow background with two components.

255
00:17:25.900 --> 00:17:27.740
In the imperative style,

256
00:17:28.099 --> 00:17:30.380
we would have to do something like,

257
00:17:30.680 --> 00:17:33.760
let's take the B view and set the color to red,

258
00:17:34.220 --> 00:17:36.120
let's clear all its children,

259
00:17:36.260 --> 00:17:45.360
and let's create the C tree view and add as a child for the B view.

260
00:17:46.960 --> 00:17:51.860
This would be the process in the imperative style

261
00:17:51.860 --> 00:17:57.480
to move this screen on the left to the state on the right.

262
00:17:57.660 --> 00:17:59.740
It's the same screen, different state.

263
00:18:00.280 --> 00:18:03.240
On the declarative style,

264
00:18:03.880 --> 00:18:05.380
this is a little bit different.

265
00:18:05.540 --> 00:18:09.700
We just return a view B with the color,

266
00:18:10.100 --> 00:18:12.080
the child, and the information that we

267
00:18:12.080 --> 00:18:14.760
have as its own component, as its own widget.

268
00:18:16.600 --> 00:18:22.200
Here we have a small image to make it easier to understand.

269
00:18:22.860 --> 00:18:26.140
Basically, in the declarative style,

270
00:18:26.320 --> 00:18:30.820
you describe the UI structure and you return a composite widget,

271
00:18:30.960 --> 00:18:33.700
so it's a widget composite of other widgets.

272
00:18:34.960 --> 00:18:39.080
In the imperative, you have a mutable objective state,

273
00:18:39.080 --> 00:18:45.660
and you call methods in sequence in order to update this object.

274
00:18:48.820 --> 00:18:52.920
Also, please just jump on if you have any questions.

275
00:18:53.020 --> 00:18:55.520
If I'm going too fast,

276
00:18:56.340 --> 00:19:00.760
I can slow down and go back to any of the items.

277
00:19:02.500 --> 00:19:05.220
Awesome. The next big thing,

278
00:19:05.820 --> 00:19:10.600
and I really love this little formula right here,

279
00:19:10.600 --> 00:19:12.880
because it basically says that

280
00:19:13.240 --> 00:19:16.380
the UI is always a function of the current state.

281
00:19:16.520 --> 00:19:20.020
That's how you think about the interface on Flutter.

282
00:19:20.400 --> 00:19:23.040
It's a function of the states that we have.

283
00:19:23.740 --> 00:19:27.240
When the state of your app changes, for example,

284
00:19:27.300 --> 00:19:29.820
the user flips a switch in the setting screen,

285
00:19:30.300 --> 00:19:31.640
then you change the state,

286
00:19:31.640 --> 00:19:35.360
and that triggers a redraw of the user interface.

287
00:19:36.000 --> 00:19:39.860
Here is the power of the Flutter handler.

288
00:19:40.400 --> 00:19:42.680
Since it's very fast and very optimized,

289
00:19:43.520 --> 00:19:48.840
the user never notices or almost never notices this redraw.

290
00:19:49.240 --> 00:19:54.200
You can be redrawing all the screen to change just one component,

291
00:19:54.620 --> 00:19:58.740
and sometimes the user won't even notice if this is done right.

292
00:20:00.000 --> 00:20:01.820
you can rebuild the whole screen

293
00:20:01.820 --> 00:20:03.880
and the user will only see that,

294
00:20:04.340 --> 00:20:05.360
oh, that little component,

295
00:20:05.720 --> 00:20:07.600
that little button changed the state,

296
00:20:08.080 --> 00:20:09.120
but behind the scenes,

297
00:20:09.240 --> 00:20:11.300
you could be rebuilding all the screen.

298
00:20:14.200 --> 00:20:18.160
So there is no way of changing the UI itself,

299
00:20:18.240 --> 00:20:20.060
like widget set text.

300
00:20:20.460 --> 00:20:23.600
You change the state and the UI rebuilds from scratch.

301
00:20:24.240 --> 00:20:29.000
So that's how we think in terms of building interfaces

302
00:20:29.000 --> 00:20:32.460
and the main, let's say,

303
00:20:33.620 --> 00:20:36.320
philosophy behind the Flutter structure.

304
00:20:36.580 --> 00:20:38.440
It's the reactive model,

305
00:20:38.960 --> 00:20:41.120
it's the declarative UI,

306
00:20:41.680 --> 00:20:44.500
and it's the everything is a widget.

307
00:20:44.600 --> 00:20:46.900
So it's these three basis concepts

308
00:20:46.900 --> 00:20:50.120
that serves as the foundation

309
00:20:50.120 --> 00:20:54.240
for us to lay the rest of the interface

310
00:20:54.240 --> 00:20:56.620
and the rest of the structure of the framework

311
00:20:56.620 --> 00:20:59.260
on top of the three main core concepts.

312
00:21:00.600 --> 00:21:02.480
So let's move further.

313
00:21:03.180 --> 00:21:04.940
Now, diving a little bit deeper

314
00:21:04.940 --> 00:21:07.340
into the widget fundamentals itself.

315
00:21:07.520 --> 00:21:10.320
Like I said, everything is a widget inside Flutter,

316
00:21:10.980 --> 00:21:15.680
but we have mainly two types of widgets,

317
00:21:16.360 --> 00:21:18.840
the stateless widgets and the stateful widgets.

318
00:21:19.100 --> 00:21:20.600
Let's start with the stateless,

319
00:21:21.000 --> 00:21:24.240
which is the most used generally.

320
00:21:24.240 --> 00:21:29.080
So the stateless widgets are used

321
00:21:29.080 --> 00:21:32.600
when the UI doesn't depend on dynamic data.

322
00:21:33.680 --> 00:21:36.080
So widgets that have no mutable state,

323
00:21:36.480 --> 00:21:39.140
they have no class properties that change over time,

324
00:21:39.640 --> 00:21:41.880
they subclass the stateless widget.

325
00:21:42.360 --> 00:21:44.120
So they declare themselves

326
00:21:44.120 --> 00:21:47.300
by extending the stateless widget.

327
00:21:47.760 --> 00:21:49.380
Like on this example below,

328
00:21:49.520 --> 00:21:51.500
we are creating a class that's called,

329
00:21:51.500 --> 00:21:54.440
in this example, it's nice to mention,

330
00:21:55.260 --> 00:21:59.900
it's actually both examples are from our tribe app.

331
00:21:59.980 --> 00:22:02.060
And in this specific case,

332
00:22:02.100 --> 00:22:05.720
we are looking at the chat feature,

333
00:22:05.960 --> 00:22:07.420
the chat feature that we have.

334
00:22:08.080 --> 00:22:10.060
When we draw the interface and we say,

335
00:22:10.400 --> 00:22:12.060
hey, this is a text message,

336
00:22:12.080 --> 00:22:15.480
and this is the text that needs to be inside this bubble

337
00:22:15.860 --> 00:22:17.780
of text inside the chat,

338
00:22:18.080 --> 00:22:20.300
we won't be changing it anymore.

339
00:22:20.300 --> 00:22:24.720
So that's why the text message itself is a stateless widget.

340
00:22:25.200 --> 00:22:27.660
Once we say, hey, the user said hi,

341
00:22:28.880 --> 00:22:31.000
and they send the message,

342
00:22:31.240 --> 00:22:33.740
there's no going back, they can delete it,

343
00:22:33.800 --> 00:22:35.680
but they will be removing,

344
00:22:36.020 --> 00:22:40.300
they won't be updating the content of that text message.

345
00:22:41.040 --> 00:22:43.700
So as you can see here,

346
00:22:44.980 --> 00:22:46.620
also just to mention,

347
00:22:46.780 --> 00:22:48.580
many built-in widgets are stateless,

348
00:22:48.580 --> 00:22:50.960
like padding, text, and icons,

349
00:22:51.240 --> 00:22:52.660
things that don't change very frequently.

350
00:22:53.340 --> 00:22:56.240
And when you create your own widgets,

351
00:22:56.400 --> 00:22:59.140
you create stateless widgets most of the time.

352
00:22:59.300 --> 00:23:00.600
So here on the left,

353
00:23:00.720 --> 00:23:04.620
we have this small example for the text message class

354
00:23:04.640 --> 00:23:08.960
that extends the stateless widget and only has the text.

355
00:23:09.100 --> 00:23:11.140
If it's a reply to someone,

356
00:23:11.580 --> 00:23:15.220
the text color that should be used for this bubble,

357
00:23:15.220 --> 00:23:18.140
and if it's on the mobile view or not.

358
00:23:18.660 --> 00:23:22.040
And that's all we need for building this component.

359
00:23:23.000 --> 00:23:26.820
And since it's not dependent on dynamic data,

360
00:23:26.980 --> 00:23:29.480
then it can be a stateless widget,

361
00:23:30.380 --> 00:23:32.340
meaning it doesn't have a state.

362
00:23:33.800 --> 00:23:35.020
For the stateable widget,

363
00:23:35.560 --> 00:23:39.860
then it's our widgets that hold local state,

364
00:23:40.080 --> 00:23:42.300
like a counter or a toggle switch.

365
00:23:42.300 --> 00:23:45.360
For example, if a widget has a counter

366
00:23:46.200 --> 00:23:50.020
that increments whenever the user taps a button,

367
00:23:50.180 --> 00:23:54.000
then the value of the counter is the state for that widget.

368
00:23:56.340 --> 00:23:59.840
So if something changes

369
00:24:00.420 --> 00:24:03.080
and the interface needs to change

370
00:24:03.080 --> 00:24:04.980
because that piece of data changed,

371
00:24:05.520 --> 00:24:08.180
then we are probably talking about a stateful widget.

372
00:24:09.020 --> 00:24:13.860
The widget needs to be rebuilt to update its part of the UI.

373
00:24:14.420 --> 00:24:17.620
And these widgets then will subclass the stateful widget

374
00:24:19.060 --> 00:24:23.180
and they store multiple states in a separated class.

375
00:24:23.380 --> 00:24:25.760
So this is very interesting, I'll show here below.

376
00:24:26.680 --> 00:24:29.220
We declare first the chat page,

377
00:24:29.600 --> 00:24:31.380
extending the stateful widget,

378
00:24:31.860 --> 00:24:36.700
and we define the structure for that chat page.

379
00:24:36.700 --> 00:24:40.200
So on this specific chat page,

380
00:24:40.260 --> 00:24:44.840
we have the group that this chat is inside.

381
00:24:45.140 --> 00:24:47.600
We have a reference to a conversation

382
00:24:47.600 --> 00:24:49.900
that contains all the data of message

383
00:24:49.900 --> 00:24:51.740
and users involved on this conversation.

384
00:24:52.100 --> 00:24:55.620
And we also have a static root name

385
00:24:55.620 --> 00:24:59.980
and a static root path that's using for a user.

386
00:25:00.000 --> 00:25:03.420
the location of the app on the web page.

387
00:25:04.560 --> 00:25:07.260
We have the chat page state,

388
00:25:08.000 --> 00:25:11.100
and it extends a state.

389
00:25:11.940 --> 00:25:15.740
As you can see here, it's a state for the chat page itself.

390
00:25:16.040 --> 00:25:20.180
We only can do this extension if we

391
00:25:20.180 --> 00:25:24.620
declare the chat page as a stateful widget.

392
00:25:25.100 --> 00:25:27.220
If we try to do the same thing for

393
00:25:27.220 --> 00:25:29.380
a one that's here on the left,

394
00:25:29.380 --> 00:25:35.120
it won't work because it won't have a state associated with it.

395
00:25:37.260 --> 00:25:40.600
Then we have some cool abilities like we have

396
00:25:41.180 --> 00:25:45.080
this overwrite method for the init state so we can

397
00:25:45.580 --> 00:25:48.000
decide what we'll do when

398
00:25:48.340 --> 00:25:52.620
we initiate the state for this widget that we are building.

399
00:25:53.080 --> 00:25:55.500
In this case, we create the model for it,

400
00:25:55.720 --> 00:25:59.300
and we'll talk more about the model on the next field.

401
00:25:59.300 --> 00:26:01.680
These slides, but basically the model is

402
00:26:01.680 --> 00:26:03.480
the data structure behind the widget.

403
00:26:04.740 --> 00:26:06.860
We'll log a Firebase event,

404
00:26:07.860 --> 00:26:13.380
and we then move on with the initialization of the component.

405
00:26:17.360 --> 00:26:20.020
Just to sum things up,

406
00:26:20.620 --> 00:26:25.120
a stateful widget holds mutable states and it builds on state change.

407
00:26:25.120 --> 00:26:30.460
A stateless widget, it's mutable and there's no local state.

408
00:26:31.020 --> 00:26:33.860
So the stateless widget is not rebuilt

409
00:26:34.400 --> 00:26:38.340
when there's a change on the state of the page.

410
00:26:40.620 --> 00:26:44.340
So the stateless widget is static.

411
00:26:49.660 --> 00:26:55.940
Now, moving to a little bit of a more,

412
00:26:59.180 --> 00:27:02.280
let's say, the fun part,

413
00:27:02.460 --> 00:27:06.500
let's say, is the layout system itself because personally,

414
00:27:06.640 --> 00:27:12.760
I really like how Flutter deals with UI building because it's

415
00:27:12.760 --> 00:27:18.380
very easy to read the UI components itself.

416
00:27:18.840 --> 00:27:22.020
As we can see, very,

417
00:27:23.100 --> 00:27:28.040
very dense library and

418
00:27:28.040 --> 00:27:34.220
very complete library of widgets that are already available on Flutter.

419
00:27:34.360 --> 00:27:36.080
As I said before,

420
00:27:36.240 --> 00:27:39.400
we have here two design system,

421
00:27:39.400 --> 00:27:42.640
Cupertino, that's the Apple design system,

422
00:27:42.900 --> 00:27:45.420
and Material Component, the Google design system.

423
00:27:45.980 --> 00:27:51.460
Both of them, and that's very interesting because they look exactly

424
00:27:52.360 --> 00:27:56.560
like the iOS and the Material Component,

425
00:27:57.600 --> 00:28:02.480
but they're actually being drawn by the render.

426
00:28:02.860 --> 00:28:08.500
So they use painters behind the scenes to draw the square,

427
00:28:08.500 --> 00:28:17.020
add text, and make it feel and look like the components we have familiarity with,

428
00:28:17.480 --> 00:28:22.360
but they are not using the components behind the scenes.

429
00:28:23.360 --> 00:28:26.700
That can create some form of lagging.

430
00:28:26.840 --> 00:28:27.800
As you can see, for instance,

431
00:28:28.040 --> 00:28:32.940
all the Cupertino components that we have here are old now,

432
00:28:32.940 --> 00:28:35.260
that we have all these new iOS versions.

433
00:28:35.260 --> 00:28:39.200
So if you look at the iOS 26, for instance,

434
00:28:39.280 --> 00:28:42.800
we have a different design for a few of these components,

435
00:28:43.460 --> 00:28:52.600
but the Flutter library didn't catch up yet because we need to redraw everything from zero.

436
00:28:53.600 --> 00:28:57.340
But if you, as a Flutter developer,

437
00:28:57.400 --> 00:29:04.140
really wants to have the look and feel of iOS 26,

438
00:29:04.140 --> 00:29:04.740
for instance,

439
00:29:04.860 --> 00:29:10.360
then you can basically create these components yourself using custom painters,

440
00:29:10.860 --> 00:29:16.820
which is basically what these components are using behind the scenes to design

441
00:29:17.660 --> 00:29:22.220
and to draw the components on the interface.

442
00:29:23.580 --> 00:29:26.240
So let me go back to the presentation.

443
00:29:27.520 --> 00:29:31.460
So here are the main components, row and column,

444
00:29:32.100 --> 00:29:32.720
stack.

445
00:29:33.040 --> 00:29:36.740
Stack is for putting things on top of each other using the z-axis.

446
00:29:37.520 --> 00:29:39.680
Row and column are pretty self-explanatory.

447
00:29:40.960 --> 00:29:42.700
Container, it's a container.

448
00:29:43.060 --> 00:29:44.160
Padding, it's the spacing.

449
00:29:44.380 --> 00:29:47.340
So this is a very interesting thing about Flutter.

450
00:29:47.640 --> 00:29:50.720
When you want to add space,

451
00:29:50.920 --> 00:29:54.820
you literally add a widget that's called padding,

452
00:29:54.900 --> 00:29:59.220
and then you inform if it's going to be a top padding,

453
00:29:59.220 --> 00:29:59.980
if it's going to be a bottom padding.

454
00:30:00.000 --> 00:30:06.440
left, or if it's going to be a top, left, right, and bottom. So it's a widget as everything else

455
00:30:06.440 --> 00:30:12.160
we have. Just like the flexible and expanded widgets, for instance. If you place something

456
00:30:12.160 --> 00:30:23.120
inside the expanded widget, it will take all the available space. And this, it's a kind of

457
00:30:23.120 --> 00:30:31.640
different way of looking at things, because on some other cases, this would be like a property

458
00:30:31.640 --> 00:30:38.900
of the component. So you have like a column, and then you set that that column has the expanded

459
00:30:38.760 --> 00:30:44.860
property. In Flutter, you'll be declaring the expanded widget, and you'll be adding a column

460
00:30:44.860 --> 00:30:52.860
as a child for that expanded widget, and then the column will take all the

461
00:30:53.680 --> 00:30:56.440
available space on the screen for that component.

462
00:31:00.340 --> 00:31:08.780
Now, we'll be moving from the Flutter framework itself to the Dart, which is the language that

463
00:31:09.030 --> 00:31:16.650
Flutter uses. And I will not spend a lot of time on this topic for now. I just wanted to

464
00:31:17.010 --> 00:31:26.770
give the three things that I think are useful here. So basically, Dart language is strongly

465
00:31:26.770 --> 00:31:34.030
typed with inference, which is a very interesting thing. So we can do something like final data

466
00:31:34.030 --> 00:31:42.850
and pass a string, and then from now on, since you declared as final, the data is expected to be

467
00:31:42.850 --> 00:31:50.850
a string. And if you try to parse it to something else, it can cause an error.

468
00:31:51.910 --> 00:31:58.510
We also have no safety built-in, so variables are non-nullable by default. So if you declare a

469
00:31:58.850 --> 00:32:05.970
string name, the Flutter framework, the Dart language actually expects for it to not be null

470
00:32:06.890 --> 00:32:14.370
unless you explicitly say that that string can be null. So this prevents null reference and errors

471
00:32:14.370 --> 00:32:23.550
that compile time. Finally, the soundness. So Dart's type system, like the type systems for Java

472
00:32:23.550 --> 00:32:30.310
or C Sharp, is sound. So it enforces that soundness by using a combination of static

473
00:32:31.630 --> 00:32:41.270
checking, compile time errors, and runtime checks. For example, if we assign a string to an int,

474
00:32:41.530 --> 00:32:49.610
it's a compile error. So if you declare a string A equals to one, we'll get a compile error.

475
00:32:50.250 --> 00:32:58.410
You won't be able to build the project. But if we try to cast an object to a string using

476
00:32:58.550 --> 00:33:07.030
as a string, but we are trying to cast the object that is a double, for instance,

477
00:33:07.490 --> 00:33:13.630
then it will fail at the runtime, throwing an error that you can't do that casting.

478
00:33:14.190 --> 00:33:21.670
And one useful thing here is that you can do a nullable casting. So we can try to cast

479
00:33:21.750 --> 00:33:26.330
something, and if it fails, it will be null, and you can check for it, and then you can

480
00:33:26.330 --> 00:33:30.210
treat this error according to prevent failing it on runtime.

481
00:33:34.870 --> 00:33:50.990
Now, regarding the asynchronous management on Dart, we basically have two keywords that

482
00:33:50.990 --> 00:33:57.570
handle all asynchronous programming here. So it's the async and await keywords. So they provide

483
00:33:57.570 --> 00:34:04.490
declarative ways to define asynchronous functions and use the results. So basically,

484
00:34:04.910 --> 00:34:11.010
to define an async function, you need to add async before the functional body,

485
00:34:11.449 --> 00:34:18.510
and the await keyword works only if you are declaring an async function. So this is very

486
00:34:18.510 --> 00:34:24.790
basic, but I think it's interesting to bring this up because this is something we'll be using a lot

487
00:34:24.790 --> 00:34:32.050
in basically, I think, almost every page that we'll be building. There will be some form of

488
00:34:32.050 --> 00:34:39.070
asynchronous call that you need to be making, and you need to wait for stuff. So this is used a lot.

489
00:34:39.670 --> 00:34:45.730
So there is a simple example here that we are declaring a future. So we are declaring, hey,

490
00:34:45.830 --> 00:34:52.830
on the future, we will be receiving a string for this create order message. We declare it as

491
00:34:52.830 --> 00:34:59.810
synchronous function, and we say, hey, we need to get the order variable, but

492
00:35:00.000 --> 00:35:05.180
To get it, we need to await for the FetchUserOrder function

493
00:35:05.500 --> 00:35:07.000
to complete.

494
00:35:07.920 --> 00:35:12.240
And when we add a await inside async function,

495
00:35:13.020 --> 00:35:17.680
the return will only be called once the await is complete.

496
00:35:17.980 --> 00:35:21.620
So this return right here only will

497
00:35:21.620 --> 00:35:25.360
be called when we have the FetchUserOrder response.

498
00:35:25.880 --> 00:35:28.240
On this case, the FetchUserOrder is just

499
00:35:28.240 --> 00:35:32.620
a delayed return with a two seconds delay.

500
00:35:32.780 --> 00:35:38.520
But you can imagine how this can be any FavAp call or anything

501
00:35:38.520 --> 00:35:40.900
that we need to await the response from.

502
00:35:41.420 --> 00:35:44.400
And then to call the function we just created,

503
00:35:44.520 --> 00:35:48.000
we just need to use the await as well.

504
00:35:48.500 --> 00:35:54.300
So this will be automatically handled by Flutter.

505
00:35:54.300 --> 00:35:59.640
So when we run the main, it will print the FetchUserOrder

506
00:36:00.080 --> 00:36:00.760
instantaneously.

507
00:36:01.340 --> 00:36:04.780
And since this is on the await, it

508
00:36:04.780 --> 00:36:06.880
will wait on the two seconds.

509
00:36:06.940 --> 00:36:11.500
And then it will print the URL there is and the data,

510
00:36:12.660 --> 00:36:17.340
the large late, large late, that we are passing here

511
00:36:17.340 --> 00:36:18.800
on the FetchUserOrder.

512
00:36:20.340 --> 00:36:24.040
So just to nail this down, the key

513
00:36:24.040 --> 00:36:26.500
terms we need to think about in asynchronous programming

514
00:36:26.500 --> 00:36:28.640
for Flutter is basically the async and await.

515
00:36:28.900 --> 00:36:31.500
You can use the async keyword before a function's body

516
00:36:31.500 --> 00:36:32.580
to mark it as synchronous.

517
00:36:32.880 --> 00:36:34.700
And you can use the await keyword

518
00:36:34.700 --> 00:36:38.580
to get the completed result of an asynchronous expression.

519
00:36:39.160 --> 00:36:44.400
And the await keyword only works with the async function.

520
00:36:46.900 --> 00:36:51.780
So that's it regarding the asynchronous part.

521
00:36:52.380 --> 00:36:54.280
I see Ira had a question, like, is a future

522
00:36:54.280 --> 00:36:55.880
the same as a promise?

523
00:36:58.280 --> 00:37:00.820
Yeah, perfect, perfect, perfect analogy.

524
00:37:01.040 --> 00:37:02.600
It's exactly the same thing.

525
00:37:04.400 --> 00:37:07.040
And future type is always, yeah, exactly.

526
00:37:07.140 --> 00:37:09.500
If you declare a synchronous function,

527
00:37:09.600 --> 00:37:14.620
you always need to have a future as a return for it.

528
00:37:14.920 --> 00:37:19.460
And you can define which type of future you'll be receiving.

529
00:37:19.460 --> 00:37:22.180
And this can be even a generic.

530
00:37:22.560 --> 00:37:24.900
So you can have, like, a generic future.

531
00:37:25.300 --> 00:37:29.440
So you don't need to specify what you'll be receiving.

532
00:37:29.680 --> 00:37:34.480
And you can have, like, custom classes here.

533
00:37:34.500 --> 00:37:36.960
For instance, if we have, like, a user record,

534
00:37:37.460 --> 00:37:40.800
we can receive a future that's a user record

535
00:37:40.840 --> 00:37:46.300
and that has all the data mapping to the name property,

536
00:37:46.300 --> 00:37:50.060
the age property, and all the user information

537
00:37:50.060 --> 00:37:51.060
that we may need.

538
00:37:52.820 --> 00:37:55.420
Let me take a look in the chat.

539
00:37:57.380 --> 00:37:59.780
Perfect, I think I covered it all.

540
00:38:04.560 --> 00:38:11.720
So moving forward, the state management part.

541
00:38:12.700 --> 00:38:18.260
So we basically have two kind of state management.

542
00:38:18.600 --> 00:38:20.000
We have the ephemeral state,

543
00:38:20.340 --> 00:38:24.020
meaning the state that's UI-related,

544
00:38:24.180 --> 00:38:25.560
or it's the local state,

545
00:38:26.820 --> 00:38:30.280
meaning things you can neatly contain a single widget.

546
00:38:30.740 --> 00:38:35.240
So this is intentionally left as a vague definition

547
00:38:36.020 --> 00:38:38.740
from the documentation, and you'll see below,

548
00:38:39.040 --> 00:38:41.160
because you don't necessarily need to choose

549
00:38:41.160 --> 00:38:44.900
one over the other, and the line is not so clear-cut.

550
00:38:45.060 --> 00:38:48.680
But some examples are the current page in a page view,

551
00:38:49.100 --> 00:38:51.300
the current progress of a complex animation,

552
00:38:51.440 --> 00:38:55.040
or the current selected tab in a bottom navigation bar,

553
00:38:55.160 --> 00:38:57.280
all are examples of ephemeral states.

554
00:38:57.940 --> 00:39:00.640
And probably we won't be needing this

555
00:39:00.640 --> 00:39:02.160
on the next page of the app,

556
00:39:02.200 --> 00:39:04.860
or we don't need to keep this for the whole user session.

557
00:39:04.960 --> 00:39:06.920
So this is what you call the ephemeral state.

558
00:39:07.640 --> 00:39:11.120
The app state is basically everything that's not ephemeral,

559
00:39:11.380 --> 00:39:15.020
so it's things that you want to share across all the app.

560
00:39:15.580 --> 00:39:18.120
So if you want to keep between user sessions,

561
00:39:18.700 --> 00:39:23.000
we have user preference, login info, notifications,

562
00:39:23.600 --> 00:39:25.940
the shopping cart in an e-commerce app,

563
00:39:26.000 --> 00:39:29.440
and the read or unread state of articles

564
00:39:29.440 --> 00:39:30.880
in a new app, for instance.

565
00:39:31.140 --> 00:39:33.580
So this is what we call the app state.

566
00:39:36.580 --> 00:39:39.860
And for managing the app state,

567
00:39:40.660 --> 00:39:43.600
this more complex state,

568
00:39:43.940 --> 00:39:46.680
then your choice depends on the complex

569
00:39:46.680 --> 00:39:48.140
and the nature of your app,

570
00:39:48.360 --> 00:39:50.520
and your team's previous experience,

571
00:39:50.740 --> 00:39:52.680
and many other aspects.

572
00:39:53.000 --> 00:39:58.240
So we have basically three built-in approaches in Flutter,

573
00:39:58.420 --> 00:39:59.980
like three native approaches.

574
00:40:00.000 --> 00:40:02.880
just for Flutter and how we handle states.

575
00:40:03.320 --> 00:40:06.540
The first and probably the most we use it

576
00:40:06.540 --> 00:40:08.860
because it's also the simplest is the set state.

577
00:40:09.700 --> 00:40:14.480
So it's the first time I was learning about Flutter,

578
00:40:14.540 --> 00:40:16.880
I was like, hey, this is funny because it's like,

579
00:40:17.040 --> 00:40:19.720
it's literally like a function that you call

580
00:40:19.820 --> 00:40:24.440
and everything that you use inside means

581
00:40:24.440 --> 00:40:27.500
that you are updating a state that you need

582
00:40:27.500 --> 00:40:29.320
to rebuild the application.

583
00:40:29.320 --> 00:40:34.980
So it's only works with a stateful widget

584
00:40:35.060 --> 00:40:38.120
and with only a single stateful widget.

585
00:40:39.700 --> 00:40:43.500
This stateful widget can be like a whole page

586
00:40:43.500 --> 00:40:46.720
or even a set of pages that are built over time,

587
00:40:47.080 --> 00:40:49.960
but in the code, it will be declared

588
00:40:49.960 --> 00:40:51.540
as a single stateful widget.

589
00:40:51.640 --> 00:40:55.800
And that's the limitation of the set state also.

590
00:40:55.800 --> 00:40:58.900
You can't share the state with other widgets,

591
00:40:59.280 --> 00:41:01.400
which can lead to duplicate logic

592
00:41:01.580 --> 00:41:04.400
if multiple widgets use the same data.

593
00:41:05.200 --> 00:41:07.860
So it's the best use case for it is

594
00:41:07.860 --> 00:41:10.560
for simple widget specific UI updates.

595
00:41:12.080 --> 00:41:15.000
And this directly tells the framework

596
00:41:15.000 --> 00:41:15.960
to rebuild the widget.

597
00:41:16.120 --> 00:41:19.400
So it's like kind of the hard code way of saying,

598
00:41:19.740 --> 00:41:22.060
hey, right now I need to rebuild this

599
00:41:22.060 --> 00:41:24.220
because I've increased the counter

600
00:41:24.220 --> 00:41:27.060
and this will cause all the interface to rebuild

601
00:41:27.060 --> 00:41:29.260
for that specific stateful widget.

602
00:41:29.580 --> 00:41:33.280
So the set state is a function of the stateful widget.

603
00:41:36.420 --> 00:41:40.720
Now getting a little bit more nuanced here,

604
00:41:40.760 --> 00:41:44.920
we have the value notifier and the inherited notifier.

605
00:41:48.680 --> 00:41:52.360
So this built-in Flutter APIs that you organize

606
00:41:52.360 --> 00:41:58.800
and share state and trigger UI rebuilds when it changes.

607
00:41:58.920 --> 00:42:01.800
So we have the value notifier for a single value

608
00:42:01.800 --> 00:42:04.600
and the change notifier for complex state.

609
00:42:05.380 --> 00:42:08.320
Both have listeners that you can subscribe to.

610
00:42:08.780 --> 00:42:11.980
So you can use a inherited notifier

611
00:42:11.980 --> 00:42:15.780
to allow child widgets to listen efficiently

612
00:42:15.780 --> 00:42:17.480
for changing a parent state.

613
00:42:18.880 --> 00:42:21.360
The scope for it is that you can share

614
00:42:21.360 --> 00:42:23.540
different from the set state.

615
00:42:24.100 --> 00:42:26.720
You can share state across multiple widgets,

616
00:42:26.940 --> 00:42:28.040
not just locally.

617
00:42:28.520 --> 00:42:30.840
And the use cases for simple values,

618
00:42:31.140 --> 00:42:32.940
you use the value notifier.

619
00:42:33.980 --> 00:42:38.800
And for more complex use cases,

620
00:42:38.860 --> 00:42:40.840
then you have to use the change notifiers,

621
00:42:41.360 --> 00:42:42.420
the change notifier.

622
00:42:42.900 --> 00:42:46.080
And this triggers a build in listeners

623
00:42:46.720 --> 00:42:48.440
that are the value listener builder.

624
00:42:53.280 --> 00:42:55.760
So one example here,

625
00:42:56.480 --> 00:43:00.000
as you can see, we are the same way we have a count here.

626
00:43:00.360 --> 00:43:01.880
We are trying to keep like,

627
00:43:02.020 --> 00:43:03.220
this is the example of a counter.

628
00:43:03.760 --> 00:43:07.280
So we have a value notifier that's an integer,

629
00:43:07.580 --> 00:43:11.320
that's the counter and declared the initial state as zero.

630
00:43:11.860 --> 00:43:16.780
And then we instantiate a listenable builder

631
00:43:16.980 --> 00:43:18.580
that basically says,

632
00:43:18.580 --> 00:43:21.780
hey, the value I'm listing is the counter.

633
00:43:22.180 --> 00:43:23.840
And every time it's changed,

634
00:43:24.020 --> 00:43:26.140
I want to run this builder right here.

635
00:43:26.600 --> 00:43:28.900
This builder has the context, the value,

636
00:43:29.120 --> 00:43:31.180
the new value from that was received

637
00:43:31.180 --> 00:43:32.540
from the value notifier.

638
00:43:32.960 --> 00:43:36.400
And we have the child itself.

639
00:43:36.600 --> 00:43:41.560
On this case, we are returning a text widget

640
00:43:41.560 --> 00:43:44.980
with only the value that we are receiving.

641
00:43:45.880 --> 00:43:49.960
The advantages for this method is that it's the state,

642
00:43:50.060 --> 00:43:52.700
the couple of the state change, then UI updates.

643
00:43:52.940 --> 00:43:55.120
And it's useful for shared values

644
00:43:55.120 --> 00:43:58.680
and more dynamic scenarios rather than the basic set state.

645
00:43:59.000 --> 00:44:02.180
The limitation is that we have some kind

646
00:44:02.200 --> 00:44:04.620
of manual listener management,

647
00:44:04.620 --> 00:44:08.680
and it's not always ideal for deeply shared state,

648
00:44:10.060 --> 00:44:14.820
which is kind of resolved by the last guy on our list,

649
00:44:14.820 --> 00:44:18.160
which is the inherited widget and the inherited model.

650
00:44:19.360 --> 00:44:22.040
The inherited widget basically is a way

651
00:44:22.800 --> 00:44:26.420
to provide shared data to child widgets

652
00:44:26.420 --> 00:44:31.600
with minimal boilerplates, avoiding manual data passing,

653
00:44:32.140 --> 00:44:34.220
what you call prop drilling.

654
00:44:35.120 --> 00:44:38.660
So child's widgets use a static method

655
00:44:38.660 --> 00:44:40.800
to access the shared state,

656
00:44:40.900 --> 00:44:43.400
and rebuilds are triggered only when needed.

657
00:44:44.120 --> 00:44:46.160
Many, and this is very interesting.

658
00:44:49.540 --> 00:44:52.560
So basically, we will see below,

659
00:44:52.760 --> 00:44:56.380
we have a lot of community-based adoptions

660
00:44:56.380 --> 00:44:59.980
that the community has viewed for providers on how.

661
00:45:00.000 --> 00:45:04.120
how we can manage the states for more complex use cases,

662
00:45:05.120 --> 00:45:09.480
but most of them are using this inherited widget

663
00:45:09.480 --> 00:45:14.200
and inherited model as the basis to build their providers

664
00:45:14.200 --> 00:45:16.800
and to build their infrastructure as well.

665
00:45:17.880 --> 00:45:22.520
So the scope is API-wide and can be used in any sub-tree

666
00:45:22.760 --> 00:45:26.180
and can share data with any descendant.

667
00:45:26.420 --> 00:45:29.020
So when you want to avoid passing data down

668
00:45:29.020 --> 00:45:32.600
to every construction, so every constructor,

669
00:45:33.920 --> 00:45:37.260
we can use this inherited widget,

670
00:45:37.620 --> 00:45:39.220
which makes the code cleaner,

671
00:45:39.740 --> 00:45:44.120
so you don't have to pass the kind of creating

672
00:45:44.120 --> 00:45:47.460
a lot of boilerplate by repeating that,

673
00:45:47.980 --> 00:45:51.400
hey, this widget has a name

674
00:45:51.400 --> 00:45:54.620
and its child inherits its name

675
00:45:54.620 --> 00:45:58.540
and its child inherits its name and so on.

676
00:45:58.540 --> 00:46:02.120
So instead of like having to pass to every constructor,

677
00:46:02.500 --> 00:46:04.080
we can use this inherited widget.

678
00:46:04.680 --> 00:46:06.680
So here we have a small example.

679
00:46:07.280 --> 00:46:10.220
So let's say you have a class called MyState

680
00:46:10.220 --> 00:46:12.220
that extends the inherited widget

681
00:46:12.940 --> 00:46:15.920
with a count as a property

682
00:46:16.080 --> 00:46:18.680
and a callback that's called the increment.

683
00:46:19.420 --> 00:46:23.240
So we declare the state and we say,

684
00:46:24.120 --> 00:46:28.400
we depend on the inherited widget of exact type

685
00:46:28.400 --> 00:46:30.680
and we pass the state we are creating,

686
00:46:31.780 --> 00:46:34.280
where we assert that the value is not new

687
00:46:34.280 --> 00:46:36.820
and we return the result.

688
00:46:37.720 --> 00:46:43.560
And here we override the update should notify.

689
00:46:44.440 --> 00:46:48.980
So on this line right here is where we are stating

690
00:46:50.180 --> 00:46:52.940
when we want the state,

691
00:46:53.700 --> 00:46:57.300
or actually when we want the widget to be reviewed.

692
00:46:57.580 --> 00:47:01.800
So in this case, we only be notifying when the count,

693
00:47:01.840 --> 00:47:05.460
the count value is different from the old count value.

694
00:47:06.520 --> 00:47:11.620
And for usage, we can just call the class we just created,

695
00:47:12.500 --> 00:47:14.620
passing the context of the application

696
00:47:14.620 --> 00:47:16.800
and calling the increment.

697
00:47:17.560 --> 00:47:21.440
This will update the count

698
00:47:21.440 --> 00:47:29.000
and will notify the inherited widgets once this is changed.

699
00:47:30.200 --> 00:47:32.160
The advantage is that it's cleaner,

700
00:47:32.580 --> 00:47:35.580
it's more scalable with many shared data

701
00:47:35.580 --> 00:47:39.240
and many state management solutions like providers

702
00:47:39.240 --> 00:47:41.000
are built on top of it.

703
00:47:41.420 --> 00:47:46.400
Limitations, more boilerplate compared to basic options

704
00:47:46.400 --> 00:47:51.940
and not as flexible for fine grained state control,

705
00:47:52.260 --> 00:47:54.440
unless paired with the notifiers.

706
00:47:55.700 --> 00:48:00.840
So here I have a small table to compare

707
00:48:00.860 --> 00:48:03.460
for make it easier to understand.

708
00:48:04.040 --> 00:48:07.700
So the method set state is for a single widget,

709
00:48:08.180 --> 00:48:12.080
it's for local and very simple ephemeral states,

710
00:48:12.680 --> 00:48:16.620
updates the whole widget and doesn't have a sharing,

711
00:48:17.480 --> 00:48:19.680
it doesn't have the ability to share its state

712
00:48:19.680 --> 00:48:20.600
with other widgets.

713
00:48:21.560 --> 00:48:26.420
The value notifier, we can scope to multiple widgets,

714
00:48:27.060 --> 00:48:33.140
it's best for shared, simple and complex use cases.

715
00:48:33.800 --> 00:48:35.860
The listener reviews the interface

716
00:48:36.000 --> 00:48:39.020
and allow us to share the state.

717
00:48:39.580 --> 00:48:43.000
Finally, the inherited, the scope is three wide

718
00:48:43.000 --> 00:48:46.400
because we can inherit it at any point of the tree.

719
00:48:47.040 --> 00:48:50.340
So we can use it for a global shared in that state

720
00:48:50.940 --> 00:48:53.280
and all the descendants will have viewed

721
00:48:53.280 --> 00:48:56.880
when the parent is updated.

722
00:48:57.440 --> 00:49:02.460
If the update returns as true for this update

723
00:49:03.040 --> 00:49:05.100
should notify that we are overriding

724
00:49:05.360 --> 00:49:07.140
for the inherited widget.

725
00:49:09.020 --> 00:49:13.100
And to finish this part, there is no clear cut rule.

726
00:49:13.620 --> 00:49:16.080
So to be clear, you can use state,

727
00:49:16.700 --> 00:49:19.900
you could build the most complex application

728
00:49:19.900 --> 00:49:24.100
using only the set state to manage all the states of that.

729
00:49:24.740 --> 00:49:27.320
In fact, the Flutter team actually does it

730
00:49:27.320 --> 00:49:28.860
in many of their examples,

731
00:49:29.720 --> 00:49:32.420
including the starter app we saw before.

732
00:49:33.700 --> 00:49:38.500
But we can decide that for our specific context

733
00:49:38.500 --> 00:49:39.900
or our particular app,

734
00:49:40.500 --> 00:49:45.740
the selected tab bar is actually not a femoral state.

735
00:49:45.880 --> 00:49:50.160
For instance, if we want to remember that the last tab

736
00:49:50.160 --> 00:49:54.840
the user selected in our application was the community tab

737
00:49:55.020 --> 00:49:57.400
and the user closed the application

738
00:49:57.400 --> 00:49:59.980
and when you open again, we want to be on the community.

739
00:50:00.000 --> 00:50:06.440
unit step, then we probably can't rely only on the state

740
00:50:06.440 --> 00:50:08.140
and sub-state management for it.

741
00:50:08.140 --> 00:50:10.900
We need to make it into a app state management.

742
00:50:14.080 --> 00:50:15.700
So key takeaways.

743
00:50:18.100 --> 00:50:21.000
Build the class cross-platform power of Flutter.

744
00:50:21.120 --> 00:50:23.600
So you build once, and you deploy everywhere,

745
00:50:23.780 --> 00:50:25.980
even if you have some performance

746
00:50:26.300 --> 00:50:27.920
issues on some places.

747
00:50:27.920 --> 00:50:32.600
I think, in general, the trade-off is usually worth it,

748
00:50:33.120 --> 00:50:36.060
especially because you cut a lot of costs

749
00:50:36.060 --> 00:50:38.380
by having just one code base that you can

750
00:50:38.380 --> 00:50:40.160
run on mobile, web, and desktop.

751
00:50:40.320 --> 00:50:44.600
This is very good for quick MVP and prototyping and getting

752
00:50:44.600 --> 00:50:46.120
a faster time to market.

753
00:50:46.760 --> 00:50:49.160
We have the widget first thingy.

754
00:50:49.340 --> 00:50:50.740
So everything is a widget.

755
00:50:50.880 --> 00:50:55.300
You can compose complex UIs from simple reusable building blocks

756
00:50:55.300 --> 00:50:57.120
using the declarative syntax.

757
00:50:58.060 --> 00:51:00.320
We have access to the Dart modern features

758
00:51:00.320 --> 00:51:04.380
like strong typing, no safety, and elegant async await

759
00:51:04.380 --> 00:51:07.580
patterns that make your code safer and more maintainable.

760
00:51:07.920 --> 00:51:10.840
And we have scalable state management,

761
00:51:10.960 --> 00:51:13.320
meaning we can start with very simple things

762
00:51:13.320 --> 00:51:16.260
like the set state and then graduate

763
00:51:16.260 --> 00:51:20.440
to more complex things like the provider as we want.

764
00:51:21.080 --> 00:51:24.100
One thing I forgot to mention here

765
00:51:24.980 --> 00:51:33.000
is that we have, right now, I'm showing inside the PubDev,

766
00:51:33.160 --> 00:51:36.580
which is basically the library for all pubs related

767
00:51:36.580 --> 00:51:42.100
to Flutter, which are the packages that are built

768
00:51:43.580 --> 00:51:46.340
that community builds to help other devs.

769
00:51:50.520 --> 00:51:53.360
So it should be state management.

770
00:51:53.360 --> 00:51:55.440
So we have Flutter block.

771
00:51:55.740 --> 00:51:56.840
We have RiverPod.

772
00:51:57.320 --> 00:51:59.080
We have Hooks.

773
00:51:59.540 --> 00:52:02.740
We have a lot of variations of blocks.

774
00:52:05.140 --> 00:52:07.700
And as you can see, there are ones

775
00:52:07.700 --> 00:52:09.920
that have 3 million downloads.

776
00:52:10.280 --> 00:52:11.640
Others have a little bit less.

777
00:52:11.700 --> 00:52:14.080
And it's really up to you to take a look

778
00:52:14.080 --> 00:52:16.120
into what you like, what you think

779
00:52:16.120 --> 00:52:18.180
it fits best to your project.

780
00:52:18.540 --> 00:52:21.420
My recommendation is to usually don't

781
00:52:21.420 --> 00:52:24.140
start by adding a external dependency.

782
00:52:24.660 --> 00:52:26.520
You can try to, oh, sorry.

783
00:52:27.380 --> 00:52:28.900
Let me share my screen again.

784
00:52:36.380 --> 00:52:39.520
One second, I think.

785
00:52:42.820 --> 00:52:49.580
So my suggestion will be to always start

786
00:52:49.580 --> 00:52:51.380
with the built-in options.

787
00:52:51.740 --> 00:52:53.980
So try to use head state, value modifier,

788
00:52:54.160 --> 00:52:55.300
or the inherited widget.

789
00:52:55.580 --> 00:52:58.320
If, for some reason, you think this

790
00:52:58.320 --> 00:53:01.020
is adding too much boilerplate, or this

791
00:53:01.020 --> 00:53:03.700
is being too much of a pain to manage,

792
00:53:03.980 --> 00:53:07.320
then look into the pubs.

793
00:53:07.380 --> 00:53:11.060
Because if you start by refusing a provider,

794
00:53:11.680 --> 00:53:15.880
you probably won't understand why the provider is

795
00:53:15.880 --> 00:53:17.080
needed in the first place.

796
00:53:17.080 --> 00:53:20.720
So it's good to have this.

797
00:53:26.100 --> 00:53:30.100
Yeah, I think it's borrowed from React solution.

798
00:53:30.760 --> 00:53:32.400
I think it's borrowed from React.

799
00:53:32.660 --> 00:53:35.680
I don't think it's like a fledged solution.

800
00:53:42.220 --> 00:53:44.160
We may be losing him a little bit.

801
00:53:44.220 --> 00:53:45.040
I don't know if that's me.

802
00:53:45.380 --> 00:53:46.160
You guys can hear me?

803
00:53:46.160 --> 00:53:47.160
OK, yeah, I think it's Janata.

804
00:53:48.800 --> 00:53:49.500
This is awesome.

805
00:53:49.540 --> 00:53:51.060
I know we're coming up on a couple more minutes.

806
00:53:51.140 --> 00:53:53.940
I'll give him a second to hop back in.

807
00:53:54.340 --> 00:53:55.980
But let me clear this.

808
00:53:56.920 --> 00:53:57.460
There we go.

809
00:53:58.200 --> 00:53:59.860
We'll wait for you to unfreeze.

810
00:54:00.560 --> 00:54:01.520
I thought it was you.

811
00:54:01.860 --> 00:54:02.800
OK, this is great.

812
00:54:04.500 --> 00:54:07.320
If he comes back, we'll let him wrap it up.

813
00:54:07.900 --> 00:54:09.060
But this is good.

814
00:54:09.100 --> 00:54:10.920
We'll probably do some more deep dives like this.

815
00:54:10.940 --> 00:54:11.500
Oh, there's Janata.

816
00:54:11.780 --> 00:54:12.280
You're back.

817
00:54:13.080 --> 00:54:14.260
We lost you for a minute.

818
00:54:15.240 --> 00:54:16.880
Maybe we lost you again.

819
00:54:17.300 --> 00:54:18.480
You lost me?

820
00:54:19.840 --> 00:54:19.840


821
00:54:21.200 --> 00:54:22.140
Can you hear me?

822
00:54:22.180 --> 00:54:22.920
Can you see my screen?

823
00:54:23.020 --> 00:54:24.520
Do you have any final thoughts?

824
00:54:24.800 --> 00:54:25.040
A couple of minutes.

825
00:54:25.160 --> 00:54:26.060
I know we have a couple of minutes left.

826
00:54:26.160 --> 00:54:27.900
We may have to go to a part two next week.

827
00:54:28.760 --> 00:54:32.520
Yeah, I was thinking about that because I still

828
00:54:34.380 --> 00:54:36.780
have some stuff to talk regarding

829
00:54:36.780 --> 00:54:40.960
like how we are applying this to the tribe itself.

830
00:54:40.960 --> 00:54:46.020
But I think we can kind of cut it for now

831
00:54:46.460 --> 00:54:50.240
because actually the next slide, it

832
00:54:50.240 --> 00:54:52.660
will be like the Tribe Act title review.

833
00:54:53.640 --> 00:54:56.620
I'll just share a small spoiler right here.

834
00:54:56.800 --> 00:54:59.980
So it's basically we'll be looking at the key directory.

835
00:55:00.000 --> 00:55:01.800
how the folders are structured,

836
00:55:02.380 --> 00:55:05.320
and how all these foundational concepts

837
00:55:05.320 --> 00:55:06.640
actually apply to Stripe.

838
00:55:06.940 --> 00:55:11.380
But I think it's better for us to leave this for a second.

839
00:55:11.600 --> 00:55:13.540
Yeah, we'll do that in part two.

840
00:55:13.980 --> 00:55:16.460
So like and subscribe if you wanna see part two.

841
00:55:16.640 --> 00:55:17.980
We'll be back here next week.

842
00:55:18.540 --> 00:55:19.220
But thanks, Gennaro.

843
00:55:19.320 --> 00:55:20.160
That was great.

844
00:55:20.160 --> 00:55:21.420
If you guys have comments or questions,

845
00:55:21.480 --> 00:55:22.600
you can always drop them in the comments

846
00:55:22.600 --> 00:55:23.640
if you're watching the replay.

847
00:55:24.460 --> 00:55:27.480
And always, if you're interested in joining our team,

848
00:55:27.500 --> 00:55:29.340
there's always an application in the description.

849
00:55:29.340 --> 00:55:30.100
So thanks, Gennaro.

850
00:55:30.220 --> 00:55:31.880
We'll be back for a part two.

851
00:55:32.060 --> 00:55:33.740
And we'll hang out for a second with the team,

852
00:55:33.800 --> 00:55:34.760
but I'll go ahead and end the stream.

853
00:55:34.840 --> 00:55:35.460
So thanks, guys.
