diff --git a/docs/ff-concepts/adding-customization/_category_.json b/docs/ff-concepts/adding-customization/_category_.json new file mode 100644 index 00000000..5c66347c --- /dev/null +++ b/docs/ff-concepts/adding-customization/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Customizations", + "position": 6 +} \ No newline at end of file diff --git a/docs/ff-concepts/adding-customization/cloud-functions.md b/docs/ff-concepts/adding-customization/cloud-functions.md new file mode 100644 index 00000000..d970a3f7 --- /dev/null +++ b/docs/ff-concepts/adding-customization/cloud-functions.md @@ -0,0 +1,251 @@ +--- +title: Cloud Functions +sidebar_position: 6 +--- + +# Cloud Functions + +[Cloud Functions](https://firebase.google.com/docs/functions) allows you to run backend code in response to events triggered by Firebase features and HTTPS requests. For example, you want to automatically send a welcome email to users when they sign up for your app. You can do this using a Cloud Function that triggers on Firebase Authentication's user creation event. + +We allow you to write and deploy Firebase Cloud Functions directly within the platform. With an integrated code editor, writing JavaScript cloud functions is quick and user-friendly. Each function has customizable boilerplate settings, including pre-configured essentials like memory, region, and timeout. + +:::note +You can find some interesting use cases [*here*](https://firebase.google.com/docs/functions/use-cases). +::: + +## Adding Cloud Functions + +Let's see how to add a *Cloud Function* by building an example that generates logos based on user prompts. Here's how it looks: + +
+ +

+ +The Cloud Function takes input from a TextField widget and initiates an API call to an [image generation API](https://platform.openai.com/docs/api-reference/images/create). Once the image URL is retrieved, it's displayed within an Image widget. + +Here are the step-by-step instructions to build such an example: + +1. [Add page state variables](#1-add-page-state-variables) +5. [Build a page](#2-build-a-page) +8. [Create and deploy Cloud Function](#3-create-and-deploy-cloud-function) +11. [Optional: Add package](#4-optional-add-package) +14. [Trigger Cloud Function](#5-trigger-cloud-function) +17. [Optional: Use Cloud Function result](#6-optional-use-cloud-function-result) + +:::info[Before you Begin] + +* Make sure the project is on Blaze plan on Firebase. +* Completed all steps in the [Firebase Setup](/data-and-backend/firebase/firebase-setup). +::: + +### 1. Add page state variables + +For this example, you'll need to set up two [page state variables](/data-and-backend/state-management/page-state#1.-creating-page-state-variable): + +1. **generatingImage (*****Type: Boolean*****)**: This is used to control the visibility of a +loading indicator during the logo creation process. Its value is set to *True* before initiating the API call and switched to *False* once the logo generation is complete. +5. **logoImage (*****Type: ImagePath*****)**: This is used to hold the generated logo image. After a successful API call, the retrieved image URL is stored here, allowing the logo to be displayed in the Image widget. +![img_6.png](imgs%2Fimg_6.png) + +### 2. Build a page + +Let's add a page that allows users to enter the prompt. To speed up, you can add a page from the [template](/getting-started/adding-new-page#add-page) or use [AI Page Gen](/getting-started/adding-new-page#ai-gen-page). Here is the page added using AI Page Gen, and after some modification, it looks the below: + +Also, see how to [build a page layout](/widgets-and-components/ui-and-layout-101) if you want to build a page from scratch. + +![img_7.png](imgs%2Fimg_7.png) + +Few things to note here: + +* We use the [ConditionalBuilder](/widgets-and-components/widgets/base-elements/conditionalbuilder) widget to show/hide the loading indicator based on the *generatingImage* variable. **Tip**: The Else branch of this widget is nothing but a ProgressBar inside the Container with a [rotating loop animation](/widgets-and-components/animations#4.-rotate). +* The Image widget uses the *logoImage* variable to display the logo. + +### 3. Create and deploy Cloud Function + +To create and deploy a *Cloud Function* : + +1. Click on the **Cloud Functions** from the [*Navigation Menu*] +(/getting-started/ui-builder/navigation-menu) (left side of your screen). +5. Click **+ Add**. This will add the default newCloudFunction*.* +8. Set the **Cloud Function Name**. + +#### Boilerplate Settings + +On the right side, you can configure the following Boilerplate Settings: +1. **Memory Allocation**: You can specify the amount of memory your function should have when + it's executed based on its complexity and needs. This setting is crucial as it influences the function's performance and the cost of running it. More memory can enhance performance for intensive tasks but also increase costs. +5. **Timeout (s)**: This refers to the maximum amount of time, in seconds, that a function is allowed to run before it is automatically terminated. If your function takes longer to execute, increasing the timeout setting may be necessary. However, be aware that longer timeouts can incur higher costs since billing is based on execution time. +8. **Require Authentication**: Turn on this setting if you want users to be authenticated to execute this cloud function. +11. **Cloud Function Region**: This determines the geographical location of the servers where your functions are hosted and executed. Ideally, you should keep this same as your *Default GCP resource location* and the Cloud Function Region specified in the Firebase Advanced Settings. + +![img_8.png](imgs%2Fimg_8.png) + +#### Configuring Input & Output + +Your cloud function might need some data to process and return the result. You can do so +by configuring the input and output. + +1. To receive output from a Cloud Function, enable the **Return Value** and choose an + appropriate Type for the output, like 'String' for text. For this example, set it to *ImagePath* to get the URL of the generated logo. +5. To input data: Click **+ Add parameters**. **Name** the parameter, select its **Type**, choose single or multiple items (**Is List** option), and uncheck **Nullable** if the value can be null. For this example, add a parameter 'prompt' with *Type* set to *String*. +8. When using [Custom Data Types](/data-and-backend/custom-data-types), Cloud Function expects JSON, matching each field in the Data Type to a key-value pair in the JSON. If the Data Type is a list, the function expects a list of JSONs. For example, for a custom data type named 'Person' with fields 'Name' and 'Age,' the function should return: + + ``` + //JSON: + { "Name": "John", "Age": 30 } + + //Example Cloud Function Code: + return { + "name": person.name, + "age": person.age + }; +``` + +For a list, the function should return: + + +``` + //JSON + [ { "Name": "John", "Age": 30 }, { "Name": "Jane", "Age": 25 } ] + + //Example Cloud Function Code: + return filteredpersons.map(filteredpersons => { + return { + "name": filteredpersons.name, + "age": filteredpersons.age + }; + }); +``` + +#### To deploy +1. Click the `[]` icon to view the boilerplate code; a popup will open with the updated +code, and then click **` Copy to Editor`**. **Tip**: To see if you are able to deploy the cloud function (before adding your own code), proceed directly with steps 8 and 9. +2. Inside the code editor, add the cloud function code. **Tip**: You can copy the boilerplate code + to [ChatGPT](https://chat.openai.com/) and ask it to write the desired code based on that. +3. Click **Save Cloud Function**. +4. Click **Deploy**. + +Here's the code used for this example: + +``` +const functions = require('firebase-functions'); +const admin = require('firebase-admin'); +const https = require('https'); + +exports.logoMaker = functions.region('us-central1') + .runWith({ + timeoutSeconds: 10, + memory: '512MB' + }).https.onCall((data, context) => { + return new Promise((resolve, reject) => { + const prompt = data.prompt; + if (!prompt) { + reject(new functions.https.HttpsError('invalid-argument', 'No prompt provided')); + return; + } + + const postData = JSON.stringify({ + model: "dall-e-3", + prompt: prompt, + n: 1, + size: "1024x1024" + }); + + const options = { + hostname: 'api.openai.com', + port: 443, + path: '/v1/images/generations', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer YOUR-APIKEY`, + 'Content-Length': postData.length + } + }; + + const req = https.request(options, (res) => { + let responseBody = ''; + + res.on('data', (chunk) => { + responseBody += chunk; + }); + + res.on('end', () => { + try { + const responseJSON = JSON.parse(responseBody); + if (responseJSON.data && responseJSON.data.length > 0) { + // Retrieve the URL of the first image + const firstImageUrl = responseJSON.data[0].url; + resolve(firstImageUrl); + } else { + reject(new functions.https.HttpsError('not-found', 'No images found')); + } + } catch (error) { + reject(new functions.https.HttpsError('internal', 'Error processing response', error)); + } + }); + }); + + req.on('error', (error) => { + reject(new functions.https.HttpsError('internal', 'Error generating image', error)); + }); + + req.write(postData); + req.end(); + }); + }); +``` + +:::tip[Important] +Always regenerate and use the updated boilerplate code or adjust your own code accordingly whenever there are changes in the code, boilerplate settings, or input/output parameters. +::: + +
+ + + +### 4. Optional: Add package + +Your cloud function may require third-party packages to work. You can include any npm package (dependency) by listing it in the `package.json` file. This file not only manages the npm package dependencies for your functions but also holds project metadata, sets up scripts for tasks such as deployment and outlines the compatible Node.js versions. + +To add a dependency, open the `package.json` file and specify your package in the `dependencies` section. + +![img_9.png](imgs%2Fimg_9.png) + +### 5. Trigger Cloud Function + +The newly created *Cloud Function* will be available as an action when you are adding one. For this example, on click of a button, we'll first set the *generatingImage*to *True* and then [trigger the Cloud Function](/actions/actions/cloud-function). + +
+ + +### 6. Optional: Use Cloud Function result + +To use the *Could Function* result, ensure you provide the *Action Output Variable Name* while adding the action, and then you can access it via the **Set from Variable menu > Action Outputs > [Action Output Variable Name]**. + +For this example, we'll use the result (i.e., generated logo image URL) and set it to *logoImage*variable. Here's how you do it: + +
+ + + +## FAQs + +
+I am getting Cloud Function Deployment Errors + +![img_10.png](imgs%2Fimg_10.png) + +

+ +If you encounter deployment errors, it may be helpful to check out [this community post](https://community.flutterflow.io/discussions/post/how-to-fix-cloud-function-deployment-errors-all-solutions-discussion-wgfMLgpLrBlmnUI) for possible solutions and insights. + +
+ + + + diff --git a/docs/ff-concepts/adding-customization/custom-actions.md b/docs/ff-concepts/adding-customization/custom-actions.md new file mode 100644 index 00000000..e1cd954b --- /dev/null +++ b/docs/ff-concepts/adding-customization/custom-actions.md @@ -0,0 +1,130 @@ +--- +title: Custom Actions +sidebar_position: 3 +--- + +# Custom Actions + +Custom Actions in FlutterFlow differ from custom functions in that they always return a `Future`. +This makes them particularly useful for complex operations that may take time to complete, such +as querying a database or calling a function that returns results after a delay. Additionally, +Custom Actions are beneficial when you want to add a third-party dependency from `pub.dev`, +allowing you to extend the capabilities of your application with external packages. + +:::tip[What is a Future?] +Futures in **Flutter** represent an asynchronous operation that will return a value or an error at +some point in the future. `Future` indicates that the future will eventually provide a value of +type `T`. So if your return value is a `String`, then the Custom Action will return +a `Future`, and the `String` return value will be output at some point in the future. +::: + +## Key Use Cases + +- **Database Queries:** Perform complex queries to retrieve or update data in a database. +- **API Calls:** Make asynchronous HTTP requests to external APIs and handle the responses. +- **File Operations:** Manage file reading or writing operations that require time to complete. +- **Third-Party Integrations:** Incorporate external packages and dependencies to enhance + functionality, such as an external analytics package. + + + +## Using a Custom Action + +Once your Action code is finalized, saved, and compiled, you can start using this action as a part +of your Action flow. + +In the following example, we have a Custom Action called `executeSearch` that takes an argument +`searchItem` that is the search string from the search **TextField** of an ecommerce +app's `HomePage`. + +
+ +
+ +## Using the Custom Action Result + +In our previous example, we enabled the **Return Value** of the Custom Action to return a +`List` when the search keyword is valid. With this change the code will change from + +``` +Future executeSearch(String searchItem) async { + // Add your function code here! +} +``` + +to + +``` +Future> executeSearch(String searchItem) async { +// Add your function code here! +} +``` + +Let's modify our Action Flow now so we can use the custom action result values within our Action +Flow. + + +
+ +
+ +

+ +:::tip[LOOKING for other CUSTOM action properties?] +To learn more about Custom Action settings, such as the +[**Exclude From Compilation toggle**](custom-code.md#exclude-from-compilation), +[**Include Build Context toggle**](custom-code.md#include-buildcontext), +and other properties like [**Callback Actions**](custom-code.md#add-a-callback-action), +[**Pub Dependencies**](custom-code.md#adding-a-pub-dependency), please check out this +[**comprehensive guide**](custom-code.md). +::: + + + + + + diff --git a/docs/ff-concepts/adding-customization/custom-code.md b/docs/ff-concepts/adding-customization/custom-code.md new file mode 100644 index 00000000..df0faf11 --- /dev/null +++ b/docs/ff-concepts/adding-customization/custom-code.md @@ -0,0 +1,289 @@ +--- +title: Writing Custom Code +sidebar_position: 1 +toc_max_heading_level: 4 + +--- + +# Custom Code + +While FlutterFlow provides a wide range of pre-built components and functionalities, there may be +times when you need to extend your app with custom logic or features that are not readily available. +This +is where writing custom code comes into play. We provide the following features to accommodate +these needs: + +* **Custom Functions:** Write custom Dart functions to perform specific tasks or calculations. +* **Custom Actions:** Implement custom actions that can be triggered by user interactions or + other action triggers. +* **Custom Widgets:** Create custom Flutter widgets to achieve unique UI designs or behaviors. +* **Custom Files:** Ability to edit some parts of the `main.dart` file. + +:::tip[Why Write Custom Code?] + +- **Extend Functionality:** Add features that are not included in the standard FlutterFlow + components. +- **Custom Integrations:** Integrate with third-party packages or APIs / databases that require + specific handling. +- **Unique UI Elements:** Create unique user interface elements that require custom rendering or + interactions. + ::: + +## Common Properties + +There are several properties and settings that are common to each type of custom code in +FlutterFlow. Most of these common properties are highlighted in the diagram below. For more +information about some of these properties, see the details provided below. + +![custom-code-common.png](imgs%2Fcustom-code-common.png) + +### Code Copilot + +Code Copilot is an AI-assisted feature that helps you generate code snippets, +functions, or entire blocks of code based on natural language descriptions of what you want to +achieve. It simplifies the app-building process by allowing you to describe the functionality you +need, such as 'calculate the total price of items in a cart', and then the Copilot generates the +necessary code. + +This can significantly speed up the building process and reduce the need for in-depth programming +knowledge, making it especially useful for custom functions and actions. + +**Limitation:** The prompts are limited to 100 characters currently. + +
+ +
+ +### Compile Code + +When you are done adding your code snippets, you can compile it to ensure there are no +compilation errors. To do so, click the **Compile Code** button. + + +
+ ![compile-errors.png](imgs%2Fcompile-errors.png) +
How to recognize compile time errors
+
+ +### Code Analyzer + +The code analyzer is available in all your custom code snippets and ensures the quality and +correctness of your custom code. It automatically checks your Dart code for errors and warnings, +providing real-time feedback as you write. +![code-analyzer.png](imgs%2Fcode-analyzer.png) +When there is a compilation error, the code analyzer will stop running and display the errors caught +by the compiler. Once fixed, save the code and rerun using the Compile Code button. The code analyzer +should then be reconnected. You can also manually reconnect it if needed. + +### Custom Code Automatic Imports + +When creating a new custom code snippet (actions, widgets, or functions) in FlutterFlow, some fundamental imports will be automatically added for you. These imports cannot be modified by the developer. Custom Functions do not allow adding any custom imports, but you can add custom imports in Custom Actions and Widgets after the line **"Do not remove or modify the code above"**. + +![automatic-imports.png](imgs%2Fautomatic-imports.png) + +### Custom Code Settings + +When you edit a custom code snippet in FlutterFlow, the Settings block will open on the right. This +block may vary slightly depending on the type of custom code (actions, functions, widgets), but here +we will discuss the common settings. + +#### Exclude From Compilation + +If, for some reason, your action or widget fails to compile but you still want to compile the rest +of your code, you can enable this toggle. Doing so will exclude the problematic code from the +compile process. + +:::tip[Scope] + +This option is only available for Custom Widgets and Custom Actions. +::: +![action-settings.png](imgs%2Faction-settings.png) + +#### Include BuildContext + +This setting determines whether to pass the BuildContext of the widget calling this custom action as +an argument. This is useful for actions that need to interact with the widget tree or access +context-specific data. + +:::tip[Scope] +This option is only available for Custom Actions. +::: + +#### Input Arguments + +When writing custom code in FlutterFlow, you can define input arguments to make your custom +functions, widgets, or actions more dynamic and reusable. Input arguments allow you to pass data +into your custom code, enabling it to perform different tasks based on the input provided. By using +input arguments, you can create more flexible and powerful custom code that can adapt to various +scenarios within your application. + +Here's an example of an action that takes 2 arguments: `cartItems` that is a `List of +ItemsStruct` and `productId` that is a String. +![action-arguments.png](imgs%2Faction-arguments.png) + +:::tip[Generated Code for custom data types] +When you define a custom data type in FlutterFlow, the generated code will refer to the type +as `Struct`. For example, if your custom data type is called `Items`, it will be +referenced in the generated code as `ItemsStruct`. +::: + +##### Add a Callback Action + +A callback action is an action passed as a parameter to a custom action or widget and triggered at some point in the future when a specific event occurs. + +This is especially helpful when you want to trigger actions from within the custom action or custom widget logic and include them as part of the custom behavior. For example, if an error occurs inside the custom logic, you could trigger an action immediately to inform the user about the error, and then continue execution or end with a default value to return. + +:::tip[What are callbacks?] + +In programming, callbacks are functions passed to other functions to be called when a specific event +occurs. +::: +In the following example, we have a Custom Action that takes an `onError(searchKeyword)` callback +action with an Action Parameter `searchKeyword`. This means that the custom action will provide this search keyword back to the callback action when it calls it. + +![explain-callback-action.png](imgs%2Fexplain-callback-action.png) + +##### Provide an Action to Callback Action + + +To provide a callback action to your main custom action, check out this quick guide where we provide a "**Show Snackbar**" action to `onError`, displaying a combined text using the search keyword. + +
+ +
+ +#### Return Values + +In FlutterFlow, custom code can not only take input arguments but also return values, back to +the caller. Return values allow your custom functions, or actions to pass data back to the +main application, enabling further processing or UI updates based on the results of the custom code. + +:::warning[Scope] +Return Values are only enabled for Custom functions & Custom Actions. Custom Widgets **cannot** +return a value at the moment. +::: + +Here's an example of an Action that returns a _nullable_ integer. + +![return-value-actions.png](imgs%2Freturn-value-actions.png) + +#### Adding a Pub Dependency + +:::tip[Scope] +You can only add a pub dependency to Custom Action & Custom Widgets. +::: + +If you plan to use a dependency from [*pub.dev*](https://pub.dev/) into a custom widget or action, +you must go through the following steps: + +1. [Choosing dependency](#1-choosing-dependency) +5. [Copying dependency/package name](#2-copying-dependency-name) +8. [Copying import statement](#3-copying-import-statement) + +##### 1. Choosing dependency + +You will find varieties of dependencies for a specific requirement, and choosing the best one can be +challenging. This section helps you identify the right dependency by examining its score. + +When you search for any dependency in *pub.dev*, you will get a list of dependencies. You can filter +out the result based on which dependency is more inclined toward your needs. You can do so by +opening and checking each dependency manually. + +Once you have a handful of dependencies, consider the following factors while choosing the final +one. + +- **WEB**: It must support Web to run your app in our Run/Test Mode. +- **Likes**: This shows how many developers have liked a dependency. +- **Pub Points**: Tells the quality of the dependency (out of 130) based on code style, platform + support, and maintainability. +- **Popularity**: This metric indicates how many apps use the package. A high popularity score + (out of 100%) can suggest that the package is stable and trusted by many developers. +- **Documentation:** A well-documented package will save you time and reduce ambiguity. Check if + the package has clear usage examples, a comprehensive README, and ideally API documentation. +- **Maintenance & Updates**: Check the last update date. A regularly updated package is more + likely compatible with the latest Dart/Flutter versions and has fewer bugs. + +

+ +![Dependency-score.png](imgs%2FDependency-score.png) + +##### 2. Copying dependency name + +To use the dependency code in our code editor, copy its name with the version. To do so, click +the **Copy to Clipboard** icon. + +

+ +![img.png](imgs%2Fimg.png) + +

+ +:::warning +The current dependency might depend on other dependencies to work. So make sure you also copy the +name and version of all the additional dependencies to specify in the code editor. +::: + +You can check if the current dependency has any additional dependencies inside the '*Dependencies'* +section at the bottom right side. + +![img_1.png](imgs%2Fimg_1.png) + +##### 3. Copying import statement + +An import statement points to where the dependency's code is located. When making a custom widget or +action, place this statement at the beginning of the code editor. + +Open the dependency page and select the installing tab; under the Import it section, you'll find +the import statement. To copy, click the **Copy to Clipboard** icon. + +![img_2.png](imgs%2Fimg_2.png) + + + + + + diff --git a/docs/ff-concepts/adding-customization/custom-files.md b/docs/ff-concepts/adding-customization/custom-files.md new file mode 100644 index 00000000..5185ac68 --- /dev/null +++ b/docs/ff-concepts/adding-customization/custom-files.md @@ -0,0 +1,149 @@ +--- +title: Custom Files +sidebar_position: 5 +--- +# Custom Files + +We allow you to add a custom code directly into the `main.dart` file of your app. This means that you can easily implement specific functionalities and customize your app as per your requirements without downloading the entire project and manually modifying the file. + +By default, the file you want to edit is in 'read-only' mode. However, using our editor, you can add a code snippet in the form of [custom actions](/customizing-your-app/custom-functions/custom-actions). + +:::warning[Please note] +You can only add custom actions that have no arguments (including *BuildContext*). +::: + +## Edit `main.dart` + +The **main.dart** is a critical file in your project, as it serves as the entry point for the +application. This file contains the `main()` function, which is responsible for starting the application by running the code that builds the UI and initializes any other necessary components. + +You can edit the **main.dart** file to include anything in `main()` function that we don't yet +support. For example, initializing third-party plugins or libraries and setting up system-level configurations, such as changing the status bar color or orientation. + +Let's see an example of how you can add a code in **main.dart** file to change the status bar +color for the mobile app. Here's how it looks: + +
+ ![img_3.png](imgs%2Fimg_3.png) +
Changing the status bar color for the mobile device
+
+ +To do so, you can edit *main.dart* file by following the steps below: + +1. Create a [custom action](/customizing-your-app/custom-functions/custom-actions#adding-custom +-action) for the code you want to include in a *main.dart* file. For this example, here's code in a custom action named 'setStatusbarColor'. + +```dart +// Automatic FlutterFlow imports +import '/backend/backend.dart'; +import '/flutter_flow/flutter_flow_theme.dart'; +import '/flutter_flow/flutter_flow_util.dart'; +import '/custom_code/actions/index.dart'; // Imports other custom actions +import '/flutter_flow/custom_functions.dart'; // Imports custom functions +import 'package:flutter/material.dart'; +// Begin custom action code +// DO NOT REMOVE OR MODIFY THE CODE ABOVE! + +import 'package:flutter/services.dart'; + +Future setStatusbarColor() async { + // Add your function code here! + + // Set status bar color + SystemChrome.setSystemUIOverlayStyle( + SystemUiOverlayStyle( + statusBarColor: Colors.redAccent, // <-- see here + statusBarIconBrightness: + Brightness.dark, //<-- For Android see here (dark icons) + statusBarBrightness: Brightness.light, //<-- For iOS see here (dark icons) + ), + ); +} +``` + +2. Now click on **Custom Functions** from the [*Navigation Menu*](/getting-started/ui-builder/navigation-menu) (left side of your screen) and open the **Custom Files > main.dart**. +5. Determine where to place the code (i.e., **Initial Action** or **Final Action**), click the **+** button, and select the custom action. +8. Click **Save**. + +
+ + +## More examples + +Let's see some more examples of adding code to the *main.dart* file to solidify understanding and use it in real-world scenarios. + +### Example 1: Lock device orientation + +You might want to lock the device orientation in portrait or landscape mode to prevent it from rotating the screen automatically when the user tilts or rotates the device. This is useful in scenarios where the layout of the app is designed to work only in one specific orientation or when you want to ensure that the app is always displayed in a consistent manner. + +To set the device orientation in landscape-only mode, [create a custom action](/customizing-your-app/custom-functions/custom-actions#adding-custom-action) with the following code and [add it to a *main.dart*](/customizing-your-app/custom-functions/custom-files#edit-main.dart) file. + +```dart +// Automatic FlutterFlow imports +import '/backend/backend.dart'; +import '/flutter_flow/flutter_flow_theme.dart'; +import '/flutter_flow/flutter_flow_util.dart'; +import '/custom_code/actions/index.dart'; // Imports other custom actions +import '/flutter_flow/custom_functions.dart'; // Imports custom functions +import 'package:flutter/material.dart'; +// Begin custom action code +// DO NOT REMOVE OR MODIFY THE CODE ABOVE! + +import 'package:flutter/services.dart'; + +Future setLandscapeMode() async { + // Add your function code here! + await SystemChrome.setPreferredOrientations([ + DeviceOrientation.landscapeLeft, + DeviceOrientation.landscapeRight, + ]); +} +``` + +
+ ![img_4.png](imgs%2Fimg_4.png) +
Edit main.dart file to lock the device orientation
+
+ + +### Example 2: Getting app lifecycle callback + +If you want to ensure that your app appropriately manages its lifecycle and handles any necessary actions when it transitions between different states, such as 'resumed' and 'paused,' you can add the `AppLifecycleObserver` in the *main.dart* file. + +To do so, [create a custom action](/customizing-your-app/custom-functions/custom-actions#adding-custom-action) with the following code and [add it to a *main.dart*](/customizing-your-app/custom-functions/custom-files#edit-main.dart) file. + + +```dart +// Automatic FlutterFlow imports +import '/backend/backend.dart'; +import '/flutter_flow/flutter_flow_theme.dart'; +import '/flutter_flow/flutter_flow_util.dart'; +import '/custom_code/actions/index.dart'; // Imports other custom actions +import '/flutter_flow/custom_functions.dart'; // Imports custom functions +import 'package:flutter/material.dart'; +// Begin custom action code +// DO NOT REMOVE OR MODIFY THE CODE ABOVE! + +Future onAppBackground() async { +// Add your function code here! +WidgetsBinding.instance.addObserver(AppLifecycleObserver()); +} + +class AppLifecycleObserver with WidgetsBindingObserver { +@override +void didChangeAppLifecycleState(AppLifecycleState state) { +if (state == AppLifecycleState.resumed) { +// Do something when app is resumed +print('App is in foreground'); +} else if (state == AppLifecycleState.paused) { +// Do something when app is paused +print('App is in background'); +} +} +} +``` +
+ ![img_5.png](imgs%2Fimg_5.png) +
Edit main.dart file to get lifecycle callback
+
diff --git a/docs/ff-concepts/adding-customization/custom-functions.md b/docs/ff-concepts/adding-customization/custom-functions.md new file mode 100644 index 00000000..15873a9c --- /dev/null +++ b/docs/ff-concepts/adding-customization/custom-functions.md @@ -0,0 +1,110 @@ +--- +title: Custom Functions +sidebar_position: 2 +--- + +# Custom Functions +Custom Functions in FlutterFlow allow you to perform simple Dart calculations and logic. These functions are ideal for tasks that require immediate results, such as data transformations, mathematical calculations, or simple logic operations. **Custom Functions** enable you to encapsulate reusable logic, making your code more organized and maintainable. + +## Key Use Cases + +- **Data Transformation:** Convert or manipulate data before displaying it in the UI. +- **Mathematical Calculations:** Perform complex calculations directly within your app. +- **String Manipulation:** Format or parse strings based on specific requirements. +- **Conditional Logic:** Implement logic that determines output based on given inputs. + + + +## Test Functions + +Custom Functions are typically straightforward input-output expressions designed to perform specific tasks. It is highly recommended to test your Custom Functions before integrating them into your project. Testing the Custom Function code ensures that it works as expected with various inputs, helping you catch potential issues early. Overall, it boosts your confidence in shipping your app to production, knowing that your logic is reliable and robust. + +
+ +
+ +:::tip[LOOKING for other CUSTOM Function properties?] +To learn more about Custom Function properties such as +[**Input Arguments**](custom-code.md#input-arguments) and +**[Return Values](custom-code.md#return-values)**, please +check out this +[**comprehensive guide**](custom-code.md). +::: + + +## FAQs + +
+I can't add imports! + +You can't have imports in a custom function. To be able to add imports, consider using a Custom Action. + +
+ + +
+Getting error: The function 'FFAppState' isn't defined. + +You can't use the app state variable (i.e., FFAppState().variablename) directly in your custom +function code. Instead, you can pass the app state variable as a parameter and then use it in your code. + +
+ + +## Some common examples + +
+Calculating Discounts: + +``` +double calculateDiscount(double price, double discountRate) { +return price - (price * discountRate / 100); +} +``` + +
+ + +
+String Capitalization: + +``` +String capitalize(String input) { +return input.isNotEmpty ? '${input[0].toUpperCase()}${input.substring(1)}' : ''; +} +``` +
+ +
+Temperature Conversion: + +``` +double celsiusToFahrenheit(double celsius) { +return (celsius * 9/5) + 32; +} + +``` +
+ diff --git a/docs/ff-concepts/adding-customization/custom-widgets.md b/docs/ff-concepts/adding-customization/custom-widgets.md new file mode 100644 index 00000000..a635630a --- /dev/null +++ b/docs/ff-concepts/adding-customization/custom-widgets.md @@ -0,0 +1,175 @@ +--- +title: Custom Widgets +sidebar_position: 4 +--- + +# Custom Widgets + +Custom Widgets allow you to create unique and reusable UI components that extend beyond the +standard widget offerings in FlutterFlow. By leveraging Custom Widgets, you can achieve a higher +level of +customization and control over your app's user interface. + +In most cases, you can create a reusable component with the basic widget set available in +FlutterFlow. However, when you want to include a UI package from [**pub.dev**](https://pub.dev), +**Custom Widgets** are the better choice. + +## Key Use Cases + +- **Unique UI Elements:** Create complex UI components that are not available in the default + FlutterFlow widget set. + +- **Third-Party Integrations:** Integrate external UI packages from pub.dev to enhance the + functionality and appearance of your app. + +## Creating a New Custom Widget + +To create a new custom widget, add a new Custom Code snippet and follow the quick guide below. In +this example, we will create a `ProductRatingBar` widget that uses a pub.dev dependency to display the rating bar UI. It will also take a callback action to provide the rating value back to the caller. + +
+ +
+ +### Properties: Width & Height + +For custom widgets, it is mandatory to specify both width and height. These properties are required to size the custom widget appropriately. Without setting these dimensions, the custom widget will not render correctly within your application. + +## Adding a pub.dev dependency + +In this example, we are using the +[**flutter_rating_bar**](https://pub.dev/packages/flutter_rating_bar) dependency to create a +`ProductRatingBar` widget for our +Product pages. See how we utilize the example code from pub.dev and add the customized widget in +FlutterFlow: + +
+ +
+ +## Using a Custom Widget +To add a custom widget to your page, you can drag and drop it from the Widget Palette's Components section or through the Widget Tree section. Here is a demo: + +
+ +
+ + +### Providing the Callback Actions + +Since we created the `onRating` callback action in our custom widget, we must provide an action +when setting the widget in page. In this example, we set the `ratingValue` to the page state +variable `userRating`. + +
+ +
+ +## Preview Widget + +FlutterFlow also allows you to view your custom widget once it is successfully compiled. + +![preview-widget.png](imgs%2Fpreview-widget.png) + +:::tip[LOOKING for other CUSTOM action properties?] +To learn more about Custom Widget settings, such as the +[**Exclude From Compilation toggle**](custom-code.md#exclude-from-compilation), +and other properties like [**Callback Actions**](custom-code.md#add-a-callback-action), +[**Pub Dependencies**](custom-code.md#adding-a-pub-dependency), please check out this +[**comprehensive guide**](custom-code.md). +::: + + + + + + + diff --git a/docs/ff-concepts/adding-customization/imgs/Dependency-score.png b/docs/ff-concepts/adding-customization/imgs/Dependency-score.png new file mode 100644 index 00000000..1ab2283d Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/Dependency-score.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/action-arguments.png b/docs/ff-concepts/adding-customization/imgs/action-arguments.png new file mode 100644 index 00000000..10b85f3b Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/action-arguments.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/action-settings.png b/docs/ff-concepts/adding-customization/imgs/action-settings.png new file mode 100644 index 00000000..1abf63a3 Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/action-settings.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/automatic-imports.png b/docs/ff-concepts/adding-customization/imgs/automatic-imports.png new file mode 100644 index 00000000..42deb414 Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/automatic-imports.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/code-analyzer.png b/docs/ff-concepts/adding-customization/imgs/code-analyzer.png new file mode 100644 index 00000000..b8412d9d Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/code-analyzer.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/compile-errors.png b/docs/ff-concepts/adding-customization/imgs/compile-errors.png new file mode 100644 index 00000000..b4f087d7 Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/compile-errors.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/custom-code-common.png b/docs/ff-concepts/adding-customization/imgs/custom-code-common.png new file mode 100644 index 00000000..bb0692a4 Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/custom-code-common.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/explain-callback-action.png b/docs/ff-concepts/adding-customization/imgs/explain-callback-action.png new file mode 100644 index 00000000..873c6c4b Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/explain-callback-action.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/img.png b/docs/ff-concepts/adding-customization/imgs/img.png new file mode 100644 index 00000000..ecc1536b Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/img.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/img_1.png b/docs/ff-concepts/adding-customization/imgs/img_1.png new file mode 100644 index 00000000..c6008064 Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/img_1.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/img_10.png b/docs/ff-concepts/adding-customization/imgs/img_10.png new file mode 100644 index 00000000..43c25ed7 Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/img_10.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/img_2.png b/docs/ff-concepts/adding-customization/imgs/img_2.png new file mode 100644 index 00000000..4a7ecd9c Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/img_2.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/img_3.png b/docs/ff-concepts/adding-customization/imgs/img_3.png new file mode 100644 index 00000000..955b5a1c Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/img_3.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/img_4.png b/docs/ff-concepts/adding-customization/imgs/img_4.png new file mode 100644 index 00000000..94f06069 Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/img_4.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/img_5.png b/docs/ff-concepts/adding-customization/imgs/img_5.png new file mode 100644 index 00000000..5aae9a70 Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/img_5.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/img_6.png b/docs/ff-concepts/adding-customization/imgs/img_6.png new file mode 100644 index 00000000..7711f721 Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/img_6.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/img_7.png b/docs/ff-concepts/adding-customization/imgs/img_7.png new file mode 100644 index 00000000..e81c93c4 Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/img_7.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/img_8.png b/docs/ff-concepts/adding-customization/imgs/img_8.png new file mode 100644 index 00000000..3aacd0c4 Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/img_8.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/img_9.png b/docs/ff-concepts/adding-customization/imgs/img_9.png new file mode 100644 index 00000000..aabf66c6 Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/img_9.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/preview-widget.png b/docs/ff-concepts/adding-customization/imgs/preview-widget.png new file mode 100644 index 00000000..53d9727b Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/preview-widget.png differ diff --git a/docs/ff-concepts/adding-customization/imgs/return-value-actions.png b/docs/ff-concepts/adding-customization/imgs/return-value-actions.png new file mode 100644 index 00000000..4aa9461a Binary files /dev/null and b/docs/ff-concepts/adding-customization/imgs/return-value-actions.png differ diff --git a/docs/ff-concepts/navigation-routing/_category_.json b/docs/ff-concepts/navigation-routing/_category_.json index 2818df93..6e5cd310 100644 --- a/docs/ff-concepts/navigation-routing/_category_.json +++ b/docs/ff-concepts/navigation-routing/_category_.json @@ -1,3 +1,4 @@ { - "label": "Navigation & Routing" + "label": "Navigation & Routing", + "position": 4 } \ No newline at end of file diff --git a/src/css/custom.css b/src/css/custom.css index 639fb06e..e6b9286f 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -117,6 +117,14 @@ h4 { } +h5 { + color:var(--black-700); + font-size: 18px; + font-weight: 600; + font-family: Product Sans, sans-serif; + +} +