Skip to content

Commit 92f9e21

Browse files
authored
Merge pull request #126 from FlutterFlow/pooja/generated-code-1
Generated Code - Models & FFAppState
2 parents 69ed65a + 93c51e9 commit 92f9e21

File tree

14 files changed

+404
-26
lines changed

14 files changed

+404
-26
lines changed

docs/ff-concepts/adding-customization/custom-actions.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,15 @@ app's `HomePage`.
7272
In our previous example, we enabled the **Return Value** of the Custom Action to return a
7373
`List<Product>` when the search keyword is valid. With this change the code will change from
7474

75-
```
75+
```js
7676
Future executeSearch(String searchItem) async {
7777
// Add your function code here!
7878
}
7979
```
8080

8181
to
8282

83-
```
83+
```js
8484
Future<List<ProductStruct>> executeSearch(String searchItem) async {
8585
// Add your function code here!
8686
}

docs/ff-concepts/adding-customization/custom-files.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ To do so, you can edit *main.dart* file by following the steps below:
4040
dart` file. For this
4141
example, here's code in a custom action named 'setStatusbarColor'.
4242

43-
```dart
43+
```js
4444
// Automatic FlutterFlow imports
4545
import '/backend/backend.dart';
4646
import '/flutter_flow/flutter_flow_theme.dart';
@@ -88,7 +88,7 @@ You might want to lock the device orientation in portrait or landscape mode to p
8888
To set the device orientation in landscape-only mode, [create a custom action](custom-actions.md) with the
8989
following code and [add it to a `main.dart`](#edit-maindart) file.
9090

91-
```dart
91+
```js
9292
// Automatic FlutterFlow imports
9393
import '/backend/backend.dart';
9494
import '/flutter_flow/flutter_flow_theme.dart';
@@ -123,7 +123,7 @@ If you want to ensure that your app appropriately manages its lifecycle and hand
123123
To do so, [create a custom action](custom-actions.md) with the following code and [add it to a `main.dart`](#edit-maindart) file.
124124

125125

126-
```dart
126+
```js
127127
// Automatic FlutterFlow imports
128128
import '/backend/backend.dart';
129129
import '/flutter_flow/flutter_flow_theme.dart';
@@ -136,21 +136,22 @@ import 'package:flutter/material.dart';
136136

137137
Future onAppBackground() async {
138138
// Add your function code here!
139-
WidgetsBinding.instance.addObserver(AppLifecycleObserver());
139+
WidgetsBinding.instance.addObserver(AppLifecycleObserver());
140140
}
141141

142142
class AppLifecycleObserver with WidgetsBindingObserver {
143143
@override
144-
void didChangeAppLifecycleState(AppLifecycleState state) {
145-
if (state == AppLifecycleState.resumed) {
144+
void didChangeAppLifecycleState(AppLifecycleState state) {
145+
if (state == AppLifecycleState.resumed) {
146146
// Do something when app is resumed
147-
print('App is in foreground');
148-
} else if (state == AppLifecycleState.paused) {
147+
print('App is in foreground');
148+
} else if (state == AppLifecycleState.paused) {
149149
// Do something when app is paused
150-
print('App is in background');
151-
}
152-
}
150+
print('App is in background');
151+
}
152+
}
153153
}
154+
154155
```
155156
<figure>
156157
![img_5.png](imgs/img_5.png)
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
---
2+
title: Directory Structure
3+
slug: /generated-code/project-structure
4+
sidebar_position: 1
5+
---
6+
7+
# Directory Structure
8+
9+
When you download the code generated by FlutterFlow, you'll notice many additional files and folders beyond what you see in FlutterFlow's Code Viewer. These files make up the complete project structure, organized according to a specific architecture. Understanding this structure is like having a detailed map, guiding you through the code and making it easier to navigate and customize your FlutterFlow project later. So, let's dive in and explore this directory structure.
10+
11+
## Folder Structure
12+
13+
```
14+
assets/
15+
lib/
16+
- actions/actions.dart
17+
- auth/
18+
- firebase_auth/
19+
- auth_manager.dart
20+
- base_auth_user_provider.dart
21+
- backend/
22+
- api_requests/
23+
- api_calls.dart
24+
- api_manager.dart
25+
- get_streamed_response.dart
26+
- cloud_functions/
27+
- firebase/
28+
- firebase_dynamic_links/firebase_dynamic_links.dart
29+
- supabase/
30+
- schema/
31+
- enums/enums.dart
32+
- structs/
33+
- address_struct.dart
34+
- cart_struct.dart
35+
- ...
36+
- util/
37+
- firestore_util.dart
38+
- schema_util.dart
39+
- carts_record.dart
40+
- ...
41+
- index.dart
42+
- backend.dart
43+
- pages/ ---// empty in this project
44+
- cart/
45+
- cart_counter/
46+
- cart_counter_model.dart
47+
- cart_counter_widget.dart
48+
...
49+
- components/
50+
- square_leading_model.dart
51+
- square_leading_widget.dart
52+
- styled_button_model.dart
53+
- styled_button_widget.dart
54+
- custom_code/
55+
- actions/
56+
- execute_search.dart
57+
...
58+
- flutter_flow/ ---//FF generated files
59+
- custom_functions.dart
60+
- flutter_flow_animations.dart
61+
- flutter_flow_....dart
62+
- nav/
63+
- app_constants.dart
64+
- app_state.dart
65+
- index.dart
66+
- main.dart
67+
pubspec.yaml
68+
```
69+
### Pages & Components
70+
71+
FlutterFlow follows a layer-first approach to keep your app organized as it grows. Authentication and backend methods are neatly organized into their own sections **[auth](#auth)** and **[backend](#backend)**. Each page you create in FlutterFlow will generate its own folder, containing the `widget` file and the corresponding `model` file. Shared components are placed in subfolders under `components/`.
72+
73+
If you've created nested folders in the FlutterFlow UI, these will directly translate into corresponding folders in the exported code. This gives you even more control to group and organize different features as you like. For instance, you could have separate folders for `products`, `user profile`, and `orders`. In the example above, `cart` is a folder explicitly created to hold all cart related pages and components.
74+
75+
### assets/
76+
The assets/ directory is where you store static files that your app uses, such as images, fonts, and other resources. These files can be accessed in your code through asset paths and are bundled with your app when it's built.
77+
78+
### lib/
79+
The `lib/` directory contains all the Dart code that drives your Flutter app. This is where the main structure of your application resides. It's organized into several subdirectories to keep the codebase clean and manageable:
80+
81+
### actions/
82+
The actions folder contains app-level **Action Blocks**. Each Action Block is created as a separate function within this directory. For example, in the case of eCommerce demo app, the `addToWishlist` function is an app-level Action Block that is included in the `actions.dart` file.
83+
84+
```dart
85+
Future addToWishlist(
86+
BuildContext context, {
87+
required String? productId}) async {
88+
// Add productId to wishlist object
89+
FFAppState().addToLocalWishlist(productId!);
90+
FFAppState().update(() {});
91+
}
92+
```
93+
94+
### auth/
95+
Contains files and folders related to authentication logic, including integrations with Firebase or other authentication services.
96+
97+
### backend/
98+
The `backend/` directory is responsible for handling all the backend logic and integrations for your Flutter app. This includes API requests, cloud functions, database interactions, and managing data schemas. Each subdirectory within backend/ serves a specific purpose:
99+
100+
- **api_requests/**: The api_requests/ directory handles all communication between your app and external services via APIs. It centralizes and organizes the code for making and managing HTTP requests and responses.
101+
102+
- **cloud_functions/**: This directory is used to store functions that interact with cloud-based services, such as Firebase Cloud Functions. These functions are used for operations that need to be performed on the server side, such as complex calculations, data processing, or sending notifications.
103+
104+
- **schema/**: The schema/ directory is crucial for defining the structure of data used throughout your app. It contains the following subdirectories and files:
105+
- **enums/:** Stores enumeration types used across the app.
106+
- **structs/:** These are used to represent custom data types like `Address` or `Cart`.
107+
- **util/:** Contains utility functions like `firestore_util.dart` and `schema_util.dart`.
108+
109+
### custom_code/
110+
Stores custom Dart code that doesn’t fit within the standard FlutterFlow structure. This could include unique actions, widgets, or other custom functionalities.
111+
112+
### flutter_flow/
113+
This directory is generated by FlutterFlow and contains various utility files that support the app's operation, such as custom functions, generated themes, and navigation.
114+
115+
### app_constants.dart
116+
This class is used to store constant values that are used throughout the application.
117+
118+
### app_state.dart
119+
This file is responsible for managing the app states created in the FlutterFlow app.
120+
121+
### main.dart
122+
The primary entry point of the app. This file runs the Flutter app and sets up the initial configuration, such as setting the home page and initializing the app’s state.
123+
124+
### pubspec.yaml
125+
This file is the configuration file for your Flutter project. It defines the dependencies, assets, and other project settings. It also specifies which versions of Dart and Flutter your project uses, along with any third-party packages or plugins your app relies on.
126+
127+
128+
This structure makes it easier to manage and scale your app!

docs/generated-code/ff-app-state.md

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
---
2+
title: FFAppState
3+
---
4+
5+
# FFAppState
6+
7+
The `FFAppState` class in FlutterFlow acts as a central hub for managing the application's global state. It's designed as a singleton, meaning there's only one instance of this class throughout the app's lifecycle. This class extends [**ChangeNotifier**](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html), allowing widgets to listen and react to state changes.
8+
9+
It includes methods for initializing and updating the app's persisted state and also defines various state variables with corresponding getters and setters for manipulating these values.
10+
11+
Here is a basic template of the class, taken from the eCommerce app's generated code:
12+
13+
```js
14+
class FFAppState extends ChangeNotifier {
15+
static FFAppState _instance = FFAppState._internal();
16+
17+
factory FFAppState() {
18+
return _instance;
19+
}
20+
21+
FFAppState._internal();
22+
23+
static void reset() {
24+
_instance = FFAppState._internal();
25+
}
26+
27+
void update(VoidCallback callback) {
28+
callback();
29+
notifyListeners();
30+
}
31+
32+
// App State variable of primitive type with a getter and setter
33+
bool _enableDarkMode = false;
34+
35+
bool get enableDarkMode => _enableDarkMode;
36+
37+
set enableDarkMode(bool value) {
38+
_enableDarkMode = value;
39+
}
40+
41+
}
42+
```
43+
44+
The `_enableDarkMode` is an App State variable created by developer that creates its own corresponding getter and setter.
45+
46+
## Updating FFAppState
47+
When updating the FFAppState from the Action Flow Editor, you will be presented with several **[update type](../resources/data-representation/app-state.md#update-type)** options such as **Rebuild All Pages**, **Rebuild Current Page**, and **No Rebuild**. Let's see how the generated code changes when these options are selected.
48+
49+
### Rebuild Current Page
50+
When a developer chooses to update App State with the update type set to **Rebuild Current Page**, the corresponding `setter` is called. Immediately after, `setState((){});` is invoked, which updates only the current page.
51+
52+
Here's an example of the generated code when we update the App State `enableDarkMode` in the `onInitialization` action trigger of the `ProductListPage`.
53+
54+
```js
55+
SchedulerBinding.instance.addPostFrameCallback((_) async {
56+
FFAppState().enableDarkMode = !(FFAppState().enableDarkMode ?? true);
57+
setState(() {});
58+
});
59+
```
60+
61+
### Rebuild All Pages
62+
63+
In this case, the update type is set to **Rebuild All Pages**, meaning that the `setter` is called, followed by the `update()` method. This method internally calls `notifyListeners()`, which is crucial for updating any widgets that depend on this variable.
64+
65+
```js
66+
SchedulerBinding.instance.addPostFrameCallback((_) async {
67+
FFAppState().enableDarkMode = !(FFAppState().enableDarkMode ?? true);
68+
FFAppState().update(() {});
69+
});
70+
```
71+
72+
:::tip[Updating App State from Custom Code]
73+
When updating App State variables from custom code, such as Custom Actions, it's crucial to call the update function to ensure that the changes are reflected across all pages. For example, you should use:
74+
75+
```js
76+
FFAppState().update(() => FFAppState().enableDarkMode = !(FFAppState().enableDarkMode ?? true));
77+
```
78+
:::
79+
80+
### No Rebuild
81+
Only the setter is called with no setState or update method invoked afterward. This means that only the variable is updated, with no state changes occurring after the data update.
82+
83+
## watch\<FFAppState\>
84+
85+
When you add an [**Update App State**](../resources/data-representation/app-state.md#update-app-state-action) action via the Action Flow Editor, the corresponding pages will include this line within the build method:
86+
87+
```js
88+
@override
89+
Widget build(BuildContext context) {
90+
context.watch<FFAppState>();
91+
...
92+
```
93+
By using `context.watch<FFAppState>()`, the widget effectively subscribes to any changes in the `FFAppState` class. Whenever there's a change in the `FFAppState` object, this widget automatically rebuilds to reflect those changes. This ensures that your widget always displays the most current data and state of the app, maintaining an up-to-date and responsive user interface.
94+
95+
## Managing AppState\<List\>
96+
When you add an App State variable of `List` type in FlutterFlow, several utility functions are automatically generated to help you manage this list. These functions include a getter, a setter, and methods for adding, removing, and updating items in the list. This setup ensures that you can easily interact with the list while keeping the app state consistent and responsive. Below is an explanation of these generated functions using the specific example of a LatLngList.
97+
98+
```js
99+
100+
late LoggableList<LatLng> _LatLngList =
101+
LoggableList([LatLng(37.4071594, -122.0775312), LatLng(40.7358633, -73.9910835)]);
102+
103+
List<LatLng> get LatLngList => _LatLngList?..logger = () => debugLogAppState(this);
104+
105+
set LatLngList(List<LatLng> value) {
106+
if (value != null) {
107+
_LatLngList = LoggableList(value);
108+
}
109+
110+
debugLogAppState(this);
111+
}
112+
113+
void addToLatLngList(LatLng value) {
114+
LatLngList.add(value);
115+
}
116+
117+
void removeFromLatLngList(LatLng value) {
118+
LatLngList.remove(value);
119+
}
120+
121+
void removeAtIndexFromLatLngList(int index) {
122+
LatLngList.removeAt(index);
123+
}
124+
125+
void updateLatLngListAtIndex(
126+
int index,
127+
LatLng Function(LatLng) updateFn,
128+
) {
129+
LatLngList[index] = updateFn(_LatLngList[index]);
130+
}
131+
132+
void insertAtIndexInLatLngList(int index, LatLng value) {
133+
LatLngList.insert(index, value);
134+
}
135+
```
136+
137+
These functions are automatically generated to provide a convenient and consistent way to manage list-type App State variables, making it easier to maintain the app's state:
138+
139+
- The list `LatLngList` is initialized as a private variable `_LatLngList` of type `LoggableList`, which helps in managing the list with additional logging capabilities.
140+
- The get `LatLngList` method allows other parts of the app to access the `LatLngList`.
141+
- The set `LatLngList` method allows you to replace the entire `LatLngList` with a new one. When a new list is assigned, it updates the private variable `_LatLngList` and logs this change using `debugLogAppState`.
142+
- The `addToLatLngList` function appends a new `LatLng` object to the LatLngList, dynamically updating the list as the app runs.
143+
- The `removeFromLatLngList` function removes a specific `LatLng` object from the `LatLngList`, ensuring the list remains accurate and up-to-date.
144+
- The `removeAtIndexFromLatLngList` function removes a `LatLng` object from the list based on its index position.
145+
- The `updateLatLngListAtIndex` function allows you to update a `LatLng` object at a specific index by applying an update function (`updateFn`) to it.
146+
- The `insertAtIndexInLatLngList` function inserts a new `LatLng` object into the `LatLngList` at a specific index, shifting the existing items as necessary.
147+
148+
149+
150+
151+
:::info[How to create App State variables]
152+
To learn more about creating and using App State variables in FlutterFlow's UI, check out the[ **App State**](../resources/data-representation/app-state.md) guide.
153+
:::

0 commit comments

Comments
 (0)