├── .gitignore ├── .metadata ├── .vscode ├── launch.json └── settings.json ├── LICENSE ├── README.md ├── analysis_options.yaml ├── lib └── main.dart ├── pubspec.lock ├── pubspec.yaml ├── test └── widget_test.dart └── web ├── favicon.png ├── flutter_bootstrap.js ├── icons ├── Icon-192.png ├── Icon-512.png ├── Icon-maskable-192.png └── Icon-maskable-512.png ├── index.html ├── manifest.json └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | 35 | # Symbolication related 36 | app.*.symbols 37 | 38 | # Obfuscation related 39 | app.*.map.json 40 | 41 | # Android Studio will place build artifacts here 42 | /android/app/debug 43 | /android/app/profile 44 | /android/app/release 45 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "367f9ea16bfae1ca451b9cc27c1366870b187ae2" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2 17 | base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2 18 | - platform: android 19 | create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2 20 | base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2 21 | - platform: ios 22 | create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2 23 | base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2 24 | - platform: linux 25 | create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2 26 | base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2 27 | - platform: macos 28 | create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2 29 | base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2 30 | - platform: web 31 | create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2 32 | base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2 33 | - platform: windows 34 | create_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2 35 | base_revision: 367f9ea16bfae1ca451b9cc27c1366870b187ae2 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations":[ 4 | { 5 | "name": "Flutter Web Loading Tips", 6 | "request": "launch", 7 | "type": "dart", 8 | "args":[ 9 | "-d", 10 | "chrome", 11 | "--web-renderer", 12 | "canvaskit", 13 | ] 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll": true, 4 | "source.organizeImports": true, 5 | } 6 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Daniel Coyula 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter Web Loading Tips 2 | 3 | https://github.com/monster555/flutter_web_loading_tips/assets/32662133/83df94b8-fa19-4a89-a646-1ad55765a373 4 | 5 | Buy Me A Coffee 6 | 7 | ## Introduction 8 | 9 | User experience is essential in the software development world, and the loading process is a crucial aspect often overlooked. A slow or clunky loading experience can frustrate users and cause them to abandon your app before it even has a chance to load your Flutter Web app. 10 | 11 | ## Key Features 12 | 13 | - **Smooth Progress Bar**: Create an elegant progress bar that reflects the loading progress of your Flutter Web application. 14 | - **Graceful Fading**: Implement a graceful fading effect for the progress bar upon loading completion. 15 | - **Seamless Transition**: Ensure a seamless transition from the loading screen to displaying your Flutter content. 16 | 17 | ## Getting Started 18 | 19 | To get started with improving your Flutter Web loading experience, follow these steps: 20 | 21 | 1. **Clone the Repository**: Begin by cloning this repository to your local development environment. 22 | 23 | ```shell 24 | git clone https://github.com/monster555/flutter_web_loading_tips.git 25 | ``` 26 | 27 | 2. Enhance Your App: Apply the techniques learned from the guide to your Flutter Web project, and watch as your loading experience becomes smoother and more professional. 28 | 29 | ## See How Smooth the Loading Experience is on FaceFolio 30 | 31 | This is one of my portfolio projects. To see the smooth loading experience in action, visit the [FaceFolio homepage](https://facefolio.dctech.dev). 32 | 33 | ## Step-by-Step 34 | 35 | Improving the loading experience in your Flutter Web application involves just a few steps. Follow each step closely to ensure proper implementation. The provided code snippets should be integrated into your project as described. 36 | 37 | ### Step 1: Adding Progress Bar Elements in index.html 38 | 39 | In your `index.html` file, add the following `
` elements to display the progress bar. These will visually represent the loading progress of the Flutter Engine. 40 | 41 | ```html 42 | 43 |
44 |
45 |
46 | ``` 47 | 48 | ### Step 2: Adding the Script in `flutter_bootstrap.js` 49 | 50 | To ensure the proper initialization of your Flutter app using the new method available in Flutter 3.22 and later, you need to update the `web/flutter_bootstrap.js` file (not the `build/web/flutter_bootstrap.js`, which is auto-generated during the build process and will be overwritten). 51 | 52 | Below is an example of how your `web/flutter_bootstrap.js` file should look with the necessary changes in place: 53 | 54 | ```javascript 55 | /** 56 | * This function creates a delay of 500 milliseconds. 57 | * 58 | * @returns {Promise} A Promise that resolves after the delay. 59 | */ 60 | function addDelay() { 61 | return new Promise((resolve) => setTimeout(resolve, 500)); 62 | } 63 | 64 | // Get the progress and progressBar elements from the DOM 65 | const progress = document.getElementById("progress"); 66 | const progressBar = document.getElementById("progressbar"); 67 | 68 | // Initialize the width of the progress bar to 0% 69 | progress.style.width = `0%`; 70 | 71 | {{flutter_js}} 72 | 73 | progress.style.width = `33%`; 74 | 75 | {{flutter_build_config}} 76 | 77 | // Load the Flutter engine 78 | _flutter.loader.load({ 79 | onEntrypointLoaded: async function(engineInitializer) { 80 | // Update the progress bar to 66% after the engine is loaded 81 | progressBar.style.width = `66%`; 82 | 83 | // Initialize the Flutter engine. 84 | const appRunner = await engineInitializer.initializeEngine(); 85 | 86 | // Set progress to 100% before adding a delay. 87 | progressBar.style.width = `100%`; 88 | 89 | // Add a delay bofreo running the app to create a smooth crossfade effect. 90 | await addDelay(); 91 | 92 | // Hide the progress bar by reducing its opacity. 93 | // This will create the fade out effect by animating the opacity. 94 | progress.style.opacity = 0; 95 | 96 | // Run the Flutter app. 97 | await appRunner.runApp(); 98 | 99 | // Add a fade-in effect to the Flutter view element. 100 | document.querySelector("flutter-view").classList.add("fade-in"); 101 | } 102 | }); 103 | ``` 104 | 105 | ### Step 3: Creating `style.css` 106 | 107 | Create a `style.css` file with the following content to style the progress bar and create the fade-in effect: 108 | 109 | ```css 110 | /* Styles for the body element */ 111 | body { 112 | display: flex; 113 | justify-content: center; 114 | align-items: center; 115 | height: 100vh; 116 | margin: 0; 117 | background-color: #fff; 118 | } 119 | 120 | /* Styles for the progress bar container */ 121 | .progress-container { 122 | width: 300px; 123 | height: 8px; 124 | background-color: #e0e0e0; 125 | border-radius: 10px; 126 | overflow: hidden; 127 | transition: opacity 0.25s ease-out; 128 | } 129 | 130 | /* Styles for the progress bar */ 131 | .progress-bar { 132 | display: block; 133 | height: 100%; 134 | background-color: #6a6a6a; 135 | width: 0; 136 | transition: width 0.5s ease; 137 | } 138 | 139 | /* CSS for a fade-in animation */ 140 | .fade-in { 141 | opacity: 0; 142 | animation: fadeIn 1s ease-in-out forwards; 143 | } 144 | 145 | /* Keyframes for the fadeIn animation */ 146 | @keyframes fadeIn { 147 | 0% { 148 | opacity: 0; 149 | } 150 | 60% { 151 | opacity: 0; 152 | } 153 | 100% { 154 | opacity: 1; 155 | } 156 | } 157 | ``` 158 | 159 | ### Step 4: Referencing `style.css` 160 | 161 | In your `index.html`, reference the `style.css` file to apply the defined styles: 162 | 163 | ```html 164 | 165 | ``` 166 | 167 | By following these steps, you can implement a smooth loading experience in your Flutter Web application. 168 | 169 | ## License 170 | 171 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 172 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at https://dart.dev/lints. 17 | # 18 | # Instead of disabling a lint rule for the entire project in the 19 | # section below, it can also be suppressed for a single line of code 20 | # or a specific dart file by using the `// ignore: name_of_lint` and 21 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 22 | # producing the lint. 23 | rules: 24 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 25 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 26 | 27 | # Additional information about this file can be found at 28 | # https://dart.dev/guides/language/analysis-options 29 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | void main() { 4 | runApp(const MyApp()); 5 | } 6 | 7 | class MyApp extends StatelessWidget { 8 | const MyApp({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return MaterialApp( 13 | title: 'Flutter Web Loading Tips', 14 | theme: ThemeData( 15 | colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), 16 | useMaterial3: true, 17 | ), 18 | home: const MyHomePage(title: 'Flutter Demo Home Page'), 19 | ); 20 | } 21 | } 22 | 23 | class MyHomePage extends StatefulWidget { 24 | const MyHomePage({super.key, required this.title}); 25 | 26 | final String title; 27 | 28 | @override 29 | State createState() => _MyHomePageState(); 30 | } 31 | 32 | class _MyHomePageState extends State { 33 | int _counter = 0; 34 | 35 | void _incrementCounter() { 36 | setState(() { 37 | _counter++; 38 | }); 39 | } 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | final theme = Theme.of(context); 44 | 45 | return Scaffold( 46 | appBar: AppBar( 47 | backgroundColor: theme.colorScheme.inversePrimary, 48 | title: Text(widget.title), 49 | ), 50 | body: Center( 51 | child: Column( 52 | mainAxisAlignment: MainAxisAlignment.center, 53 | children: [ 54 | const Text( 55 | 'You have pushed the button this many times:', 56 | ), 57 | Text( 58 | '$_counter', 59 | style: theme.textTheme.headlineMedium, 60 | ), 61 | ], 62 | ), 63 | ), 64 | floatingActionButton: FloatingActionButton( 65 | onPressed: _incrementCounter, 66 | tooltip: 'Increment', 67 | child: const Icon(Icons.add), 68 | ), 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.17.2" 44 | cupertino_icons: 45 | dependency: "direct main" 46 | description: 47 | name: cupertino_icons 48 | sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.0.6" 52 | fake_async: 53 | dependency: transitive 54 | description: 55 | name: fake_async 56 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.3.1" 60 | flutter: 61 | dependency: "direct main" 62 | description: flutter 63 | source: sdk 64 | version: "0.0.0" 65 | flutter_lints: 66 | dependency: "direct dev" 67 | description: 68 | name: flutter_lints 69 | sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 70 | url: "https://pub.dev" 71 | source: hosted 72 | version: "2.0.3" 73 | flutter_test: 74 | dependency: "direct dev" 75 | description: flutter 76 | source: sdk 77 | version: "0.0.0" 78 | lints: 79 | dependency: transitive 80 | description: 81 | name: lints 82 | sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" 83 | url: "https://pub.dev" 84 | source: hosted 85 | version: "2.1.1" 86 | matcher: 87 | dependency: transitive 88 | description: 89 | name: matcher 90 | sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" 91 | url: "https://pub.dev" 92 | source: hosted 93 | version: "0.12.16" 94 | material_color_utilities: 95 | dependency: transitive 96 | description: 97 | name: material_color_utilities 98 | sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" 99 | url: "https://pub.dev" 100 | source: hosted 101 | version: "0.5.0" 102 | meta: 103 | dependency: transitive 104 | description: 105 | name: meta 106 | sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" 107 | url: "https://pub.dev" 108 | source: hosted 109 | version: "1.9.1" 110 | path: 111 | dependency: transitive 112 | description: 113 | name: path 114 | sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" 115 | url: "https://pub.dev" 116 | source: hosted 117 | version: "1.8.3" 118 | sky_engine: 119 | dependency: transitive 120 | description: flutter 121 | source: sdk 122 | version: "0.0.99" 123 | source_span: 124 | dependency: transitive 125 | description: 126 | name: source_span 127 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 128 | url: "https://pub.dev" 129 | source: hosted 130 | version: "1.10.0" 131 | stack_trace: 132 | dependency: transitive 133 | description: 134 | name: stack_trace 135 | sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 136 | url: "https://pub.dev" 137 | source: hosted 138 | version: "1.11.0" 139 | stream_channel: 140 | dependency: transitive 141 | description: 142 | name: stream_channel 143 | sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" 144 | url: "https://pub.dev" 145 | source: hosted 146 | version: "2.1.1" 147 | string_scanner: 148 | dependency: transitive 149 | description: 150 | name: string_scanner 151 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 152 | url: "https://pub.dev" 153 | source: hosted 154 | version: "1.2.0" 155 | term_glyph: 156 | dependency: transitive 157 | description: 158 | name: term_glyph 159 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 160 | url: "https://pub.dev" 161 | source: hosted 162 | version: "1.2.1" 163 | test_api: 164 | dependency: transitive 165 | description: 166 | name: test_api 167 | sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" 168 | url: "https://pub.dev" 169 | source: hosted 170 | version: "0.6.0" 171 | vector_math: 172 | dependency: transitive 173 | description: 174 | name: vector_math 175 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 176 | url: "https://pub.dev" 177 | source: hosted 178 | version: "2.1.4" 179 | web: 180 | dependency: transitive 181 | description: 182 | name: web 183 | sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 184 | url: "https://pub.dev" 185 | source: hosted 186 | version: "0.1.4-beta" 187 | sdks: 188 | dart: ">=3.1.2 <4.0.0" 189 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_web_loading_tips 2 | description: Flutter Web loading tips 3 | 4 | publish_to: 'none' 5 | 6 | version: 1.0.0+1 7 | 8 | environment: 9 | sdk: '>=3.1.2 <4.0.0' 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | 15 | cupertino_icons: ^1.0.2 16 | 17 | dev_dependencies: 18 | flutter_test: 19 | sdk: flutter 20 | 21 | flutter_lints: ^2.0.0 22 | 23 | flutter: 24 | uses-material-design: true 25 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility in the flutter_test package. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:flutter_web_loading_tips/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(const MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monster555/flutter_web_loading_tips/d2a6b32ef69f4c1fe21c5f512976d15c0aa66a72/web/favicon.png -------------------------------------------------------------------------------- /web/flutter_bootstrap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This function creates a delay of 500 milliseconds. 3 | * 4 | * @returns {Promise} A Promise that resolves after the delay. 5 | */ 6 | function addDelay() { 7 | return new Promise((resolve) => setTimeout(resolve, 500)); 8 | } 9 | 10 | // Get the progress and progressBar elements from the DOM 11 | const progress = document.getElementById("progress"); 12 | const progressBar = document.getElementById("progressbar"); 13 | 14 | // Initialize the width of the progress bar to 0% 15 | progress.style.width = `0%`; 16 | 17 | {{flutter_js}} 18 | 19 | progress.style.width = `33%`; 20 | 21 | {{flutter_build_config}} 22 | 23 | // Load the Flutter engine 24 | _flutter.loader.load({ 25 | onEntrypointLoaded: async function(engineInitializer) { 26 | // Update the progress bar to 66% after the engine is loaded 27 | progressBar.style.width = `66%`; 28 | 29 | // Initialize the Flutter engine. 30 | const appRunner = await engineInitializer.initializeEngine(); 31 | 32 | // Set progress to 100% before adding a delay. 33 | progressBar.style.width = `100%`; 34 | 35 | // Add a delay before running the app to create a smooth crossfade effect. 36 | await addDelay(); 37 | 38 | // Hide the progress bar by reducing its opacity. 39 | // This will create the fade out effect by animating the opacity. 40 | progress.style.opacity = 0; 41 | 42 | // Run the Flutter app. 43 | await appRunner.runApp(); 44 | 45 | // Add a fade-in effect to the Flutter view element. 46 | document.querySelector("flutter-view").classList.add("fade-in"); 47 | } 48 | }); 49 | -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monster555/flutter_web_loading_tips/d2a6b32ef69f4c1fe21c5f512976d15c0aa66a72/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monster555/flutter_web_loading_tips/d2a6b32ef69f4c1fe21c5f512976d15c0aa66a72/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monster555/flutter_web_loading_tips/d2a6b32ef69f4c1fe21c5f512976d15c0aa66a72/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monster555/flutter_web_loading_tips/d2a6b32ef69f4c1fe21c5f512976d15c0aa66a72/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | Flutter Web Loading Tips 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
32 |
33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flutter_web_loading_tips", 3 | "short_name": "flutter_web_loading_tips", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /web/style.css: -------------------------------------------------------------------------------- 1 | /* Styles for the body element */ 2 | body { 3 | display: flex; 4 | justify-content: center; 5 | align-items: center; 6 | height: 100vh; 7 | margin: 0; 8 | background-color: #fff; 9 | } 10 | 11 | /* Styles for the progress bar container */ 12 | .progress-container { 13 | width: 300px; 14 | height: 8px; 15 | background-color: #e0e0e0; 16 | border-radius: 10px; 17 | overflow: hidden; 18 | transition: opacity 0.25s ease-out; 19 | } 20 | 21 | /* Styles for the progress bar */ 22 | .progress-bar { 23 | display: block; 24 | height: 100%; 25 | background-color: #6a6a6a; 26 | width: 0; 27 | transition: width 0.5s ease; 28 | } 29 | 30 | /* CSS for a fade-in animation */ 31 | .fade-in { 32 | opacity: 0; 33 | animation: fadeIn 1s ease-in-out forwards; 34 | } 35 | 36 | /* Keyframes for the fadeIn animation */ 37 | @keyframes fadeIn { 38 | 0% { 39 | opacity: 0; 40 | } 41 | 60% { 42 | opacity: 0; 43 | } 44 | 100% { 45 | opacity: 1; 46 | } 47 | } 48 | --------------------------------------------------------------------------------