├── .gitattributes
├── .gitignore
├── .metadata
├── CHANGELOG.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── dash-tools.png
├── documentations
└── adaptive_ui_with_platform_type_detection.md
├── example
├── .gitignore
├── .metadata
├── README.md
├── android
│ ├── .gitignore
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ └── example
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── res
│ │ │ │ ├── drawable-v21
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── values-night
│ │ │ │ └── styles.xml
│ │ │ │ └── values
│ │ │ │ └── styles.xml
│ │ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ └── settings.gradle
├── ios
│ ├── .gitignore
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Podfile
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ │ ├── Icon-App-20x20@1x.png
│ │ │ │ ├── Icon-App-20x20@2x.png
│ │ │ │ ├── Icon-App-20x20@3x.png
│ │ │ │ ├── Icon-App-29x29@1x.png
│ │ │ │ ├── Icon-App-29x29@2x.png
│ │ │ │ ├── Icon-App-29x29@3x.png
│ │ │ │ ├── Icon-App-40x40@1x.png
│ │ │ │ ├── Icon-App-40x40@2x.png
│ │ │ │ ├── Icon-App-40x40@3x.png
│ │ │ │ ├── Icon-App-60x60@2x.png
│ │ │ │ ├── Icon-App-60x60@3x.png
│ │ │ │ ├── Icon-App-76x76@1x.png
│ │ │ │ ├── Icon-App-76x76@2x.png
│ │ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ │ └── LaunchImage.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── LaunchImage.png
│ │ │ │ ├── LaunchImage@2x.png
│ │ │ │ ├── LaunchImage@3x.png
│ │ │ │ └── README.md
│ │ ├── Base.lproj
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── Runner-Bridging-Header.h
│ └── RunnerTests
│ │ └── RunnerTests.swift
├── lib
│ ├── countries.dart
│ └── main.dart
├── linux
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── flutter
│ │ ├── CMakeLists.txt
│ │ ├── generated_plugin_registrant.cc
│ │ ├── generated_plugin_registrant.h
│ │ └── generated_plugins.cmake
│ ├── main.cc
│ ├── my_application.cc
│ └── my_application.h
├── macos
│ ├── .gitignore
│ ├── Flutter
│ │ ├── Flutter-Debug.xcconfig
│ │ ├── Flutter-Release.xcconfig
│ │ └── GeneratedPluginRegistrant.swift
│ ├── Podfile
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ └── xcshareddata
│ │ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── Runner
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ │ └── AppIcon.appiconset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── app_icon_1024.png
│ │ │ │ ├── app_icon_128.png
│ │ │ │ ├── app_icon_16.png
│ │ │ │ ├── app_icon_256.png
│ │ │ │ ├── app_icon_32.png
│ │ │ │ ├── app_icon_512.png
│ │ │ │ └── app_icon_64.png
│ │ ├── Base.lproj
│ │ │ └── MainMenu.xib
│ │ ├── Configs
│ │ │ ├── AppInfo.xcconfig
│ │ │ ├── Debug.xcconfig
│ │ │ ├── Release.xcconfig
│ │ │ └── Warnings.xcconfig
│ │ ├── DebugProfile.entitlements
│ │ ├── Info.plist
│ │ ├── MainFlutterWindow.swift
│ │ └── Release.entitlements
│ └── RunnerTests
│ │ └── RunnerTests.swift
├── pubspec.lock
├── pubspec.yaml
├── web
│ ├── favicon.png
│ ├── icons
│ │ ├── Icon-192.png
│ │ ├── Icon-512.png
│ │ ├── Icon-maskable-192.png
│ │ └── Icon-maskable-512.png
│ ├── index.html
│ └── manifest.json
└── windows
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── flutter
│ ├── CMakeLists.txt
│ ├── generated_plugin_registrant.cc
│ ├── generated_plugin_registrant.h
│ └── generated_plugins.cmake
│ └── runner
│ ├── CMakeLists.txt
│ ├── Runner.rc
│ ├── flutter_window.cpp
│ ├── flutter_window.h
│ ├── main.cpp
│ ├── resource.h
│ ├── resources
│ └── app_icon.ico
│ ├── runner.exe.manifest
│ ├── utils.cpp
│ ├── utils.h
│ ├── win32_window.cpp
│ └── win32_window.h
├── lib
├── flutter_helper_utils.dart
└── src
│ ├── ai_docs.txt
│ ├── extensions
│ ├── extensions.dart
│ ├── flutter_extensions
│ │ ├── align.dart
│ │ ├── carousel_controller.dart
│ │ ├── colors
│ │ │ ├── colors.dart
│ │ │ ├── on_colors.dart
│ │ │ └── on_string.dart
│ │ ├── directionality.dart
│ │ ├── flutter_extensions.dart
│ │ ├── focus_scope_extensions.dart
│ │ ├── future.dart
│ │ ├── list_widget.dart
│ │ ├── media_query_extension.dart
│ │ ├── navigation.dart
│ │ ├── on_numbers.dart
│ │ ├── padding.dart
│ │ ├── platform_extension.dart
│ │ ├── scaffold_messenger_extension.dart
│ │ ├── scroll_extensions.dart
│ │ └── theme_extension.dart
│ ├── num_extensions.dart
│ └── string_extensions
│ │ ├── general_string_extensions.dart
│ │ └── string_extensions.dart
│ ├── platform_env
│ ├── platform_env.dart
│ ├── platform_env_io.dart
│ └── platform_env_web.dart
│ ├── src.dart
│ ├── value_notifier
│ ├── extensions
│ │ ├── extensions.dart
│ │ ├── listenable_extensions.dart
│ │ ├── notifier_extensions.dart
│ │ ├── stream_to_notifier.dart
│ │ └── value_notifier_extensions.dart
│ ├── notifier_classes
│ │ ├── bool_notifier.dart
│ │ ├── color_notifier.dart
│ │ ├── date_notifier.dart
│ │ ├── double_notifier.dart
│ │ ├── doubly_linked_list_notifier.dart
│ │ ├── duration_notifier.dart
│ │ ├── int_notifier.dart
│ │ ├── list_notifier.dart
│ │ ├── map_notifier.dart
│ │ ├── notifier_classes.dart
│ │ ├── num_notifier.dart
│ │ ├── set_notifier.dart
│ │ ├── string_notifier.dart
│ │ ├── theme_mode_notifier.dart
│ │ └── uri_notifier.dart
│ ├── value_notifier.dart
│ └── widgets
│ │ ├── listenables_builder.dart
│ │ └── widgets.dart
│ └── widgets
│ ├── adaptive_ui.dart
│ ├── gradient_widget.dart
│ ├── multi_tap_detector.dart
│ ├── typed_list_view.dart
│ └── widgets.dart
├── logo.svg
├── migration_guides.md
├── pubspec.yaml
└── test
└── string_to_colors_test.dart
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.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 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
26 | /pubspec.lock
27 | **/doc/api/
28 | .dart_tool/
29 | .packages
30 | build/
31 |
--------------------------------------------------------------------------------
/.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: f1875d570e39de09040c8f79aa13cc56baab8db1
8 | channel: stable
9 |
10 | project_type: package
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2023, Omar Khaled
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:very_good_analysis/analysis_options.7.0.0.yaml
2 | linter:
3 | rules:
4 | public_member_api_docs: false
5 | sort_pub_dependencies: false
6 | lines_longer_than_80_chars: false
7 | always_use_package_imports: false
8 | literal_only_boolean_expressions: false
9 | require_trailing_commas: false
10 | comment_references: false
11 | only_throw_errors: false
12 | unnecessary_library_directive: false
13 | avoid_positional_boolean_parameters: false
14 | avoid_catches_without_on_clauses: false
15 | document_ignores: false
16 | avoid_redundant_argument_values: false
17 | # avoid_dynamic_calls: false
18 | # use_build_context_synchronously: false
19 |
--------------------------------------------------------------------------------
/dash-tools.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/dash-tools.png
--------------------------------------------------------------------------------
/documentations/adaptive_ui_with_platform_type_detection.md:
--------------------------------------------------------------------------------
1 | # Adaptive UI with Platform Type Detection
2 |
3 | This documentation is part of the [flutter_helper_utils](https://pub.dev/packages/flutter_helper_utils) package.
4 |
5 | ## Table of Contents
6 |
7 | - [Features](#features)
8 | - [Usage](#usage)
9 | - [Customizing Breakpoints](#customizing-breakpoints)
10 | - [Complete Example](#complete-example-with-customizations)
11 |
12 | ## Features
13 |
14 | - **Efficient:** Rebuild widgets only when the platform type changes, not on every size change.
15 | - **Native Dart:** Built with native Dart code, no 3rd party dependencies are used.
16 | - **Easy Access:** Use context extensions to easily get platform and orientation details.
17 | - **Customizable:** Define your own breakpoints and helper extensions.
18 |
19 | ## Usage
20 |
21 | ### 1. Wrap with PlatformTypeProvider
22 |
23 | Wrap the root of your application with `PlatformTypeProvider` to make platform and orientation information accessible throughout your widget tree.
24 |
25 | ```dart
26 | import 'package:flutter_helper_utils/flutter_helper_utils.dart';
27 |
28 | runApp(PlatformTypeProvider(
29 | breakpoints: Breakpoint.defaults, // Use default breakpoints or provide your own
30 | child: MyApp()
31 | ));
32 | ```
33 |
34 | ### 2. Build UI Using Context Extensions
35 |
36 | Leverage context extensions for a streamlined approach to building adaptive UIs:
37 |
38 | ```dart
39 | @override
40 | Widget build(BuildContext context) {
41 | final breakpoint = context.watchBreakpoint; // Automatically rebuilds when the breakpoint changes
42 | return breakpoint.isMobile ? const MobileLayout() : const TabletLayout();
43 | }
44 | ```
45 |
46 | **Other context extensions:**
47 |
48 | * `context.platformSizeInfo`: Provides `orientation`, `platform`, and `breakpoint` information, rebuilding the widget when any of these values change.
49 | * `context.deviceOrientation`: Offers the current orientation (rebuilds on change).
50 |
51 | ### 3. Build UI Using Layout Builder Widgets
52 |
53 | #### BreakpointLayoutBuilder
54 |
55 | Use this to build widgets based solely on the current breakpoint (e.g., mobile, tablet).
56 |
57 | ```dart
58 | BreakpointLayoutBuilder(
59 | builder: (context, breakpoint) {
60 | if (breakpoint.isMobile) {
61 | // Mobile layout
62 | } else if (breakpoint.isTablet) {
63 | // Tablet layout
64 | } else if (breakpoint.isDesktop) {
65 | // Desktop layout
66 | } // ... (add more conditions for other breakpoints)
67 | },
68 | );
69 | ```
70 |
71 | #### PlatformInfoLayoutBuilder
72 |
73 | This widget provides both the platform type and orientation for building your UI:
74 |
75 | ```dart
76 | PlatformInfoLayoutBuilder(
77 | builder: (context, platformSizeInfo) {
78 | // Access platform, breakpoint, and orientation
79 | if (platformSizeInfo.breakpoint.isMobile) {
80 | // Mobile layout
81 | } // ... (add more conditions)
82 | },
83 | );
84 | ```
85 |
86 | ## Customizing Breakpoints
87 |
88 | The `PlatformTypeProvider` widget lets you build responsive layouts by defining breakpoints for different screen sizes. It comes with default breakpoints for mobile, tablet, and desktop devices, but you can easily customize these or create your own to match your app's unique requirements.
89 |
90 | ### Default Breakpoints
91 |
92 | The package provides convenient constructors for default breakpoints:
93 |
94 | - `Breakpoint.mobile()`: Creates a mobile breakpoint with a default width of 600.
95 | - `Breakpoint.tablet()`: Creates a tablet breakpoint with a default width of 1200.
96 | - `Breakpoint.desktop()`: Creates a desktop breakpoint with a default width of 1800.
97 |
98 | You can use these directly or as a basis for customization:
99 |
100 | ```dart
101 | const smallerMobileBreakpoint = Breakpoint.mobile(
102 | name: 'mobileSmall',
103 | width: 360
104 | );
105 | ```
106 |
107 | ### Defining and Using Custom Breakpoints
108 |
109 | Create a `Breakpoint` instance with your desired size and a unique name:
110 |
111 | ```dart
112 | const watchBreakPoint = Breakpoint(size: Size(250, 250), name: 'watch');
113 | ```
114 |
115 | **To use your custom breakpoint**, pass it to the `PlatformTypeProvider`:
116 |
117 | ```dart
118 | PlatformTypeProvider(
119 | breakpoints: [
120 | watchBreakPoint, // Your custom breakpoint
121 | ...Breakpoint.defaults, // Include default breakpoints if needed
122 | ],
123 | child: MyApp(),
124 | ),
125 | ```
126 |
127 | Now, within your `BreakpointLayoutBuilder`, you can easily check for your custom breakpoint using the `match` method:
128 |
129 | ```dart
130 | BreakpointLayoutBuilder(
131 | builder: (context, breakpoint) {
132 | if (breakpoint.match('watch')) {
133 | // Render a watch-specific UI
134 | } else if (breakpoint.isMobile) {
135 | // Render a mobile UI
136 | } // ... and so on
137 | },
138 | );
139 | ```
140 |
141 | **Important Note:** When defining your own breakpoints, consider screen dimensions and pixel densities for various watch models.
142 |
143 | ### Extending Breakpoint Functionality
144 |
145 | To make your breakpoint logic more readable and reusable, create extensions:
146 |
147 | ```dart
148 | extension CustomBreakpoint on Breakpoint {
149 | bool get isWatch => match('watch');
150 | }
151 |
152 | if (breakpoint.isWatch) {
153 | // Watch-specific layout
154 | }
155 | ```
156 |
157 | ### Complete Example with customizations
158 |
159 | ```dart
160 | import 'package:flutter/material.dart';
161 | import 'package:flutter_helper_utils/flutter_helper_utils.dart';
162 |
163 | const watchBreakPoint = Breakpoint(size: Size(250, 250), name: 'watch');
164 |
165 | extension CustomBreakpointEx on Breakpoint {
166 | bool get isWatch => match('watch');
167 | // if you prefer to match with size not name you can use:
168 | // bool get isWatch => this == watchBreakPoint;
169 | }
170 |
171 | void main() {
172 | runApp(
173 | PlatformTypeProvider(
174 | breakpoints: [
175 | watchBreakPoint,
176 | ...Breakpoint.defaults,
177 | ],
178 | child: MyApp(),
179 | ),
180 | );
181 | }
182 |
183 | class MyApp extends StatelessWidget {
184 | const MyApp({super.key});
185 |
186 | @override
187 | Widget build(BuildContext context) {
188 | return MaterialApp(
189 | title: 'Adaptive UI',
190 | home: BreakpointLayoutBuilder(
191 | builder: (context, breakpoint) {
192 | if (breakpoint.isWatch) {
193 | // Render a watch-specific UI
194 | } else if (breakpoint.isMobile) {
195 | // Render a mobile UI
196 | } // ... and so on
197 | // the breakpoint understands operators like >, <=, ==, etc
198 | // e.g. breakpoint > watchBreakPoint
199 | },
200 | ),
201 | );
202 | }
203 | }
204 | ```
205 |
206 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .build/
9 | .buildlog/
10 | .history
11 | .svn/
12 | .swiftpm/
13 | migrate_working_dir/
14 |
15 | # IntelliJ related
16 | *.iml
17 | *.ipr
18 | *.iws
19 | .idea/
20 |
21 | # The .vscode folder contains launch configuration and tasks you configure in
22 | # VS Code which you may wish to be included in version control, so this line
23 | # is commented out by default.
24 | #.vscode/
25 |
26 | # Flutter/Dart/Pub related
27 | **/doc/api/
28 | **/ios/Flutter/.last_build_id
29 | .dart_tool/
30 | .flutter-plugins
31 | .flutter-plugins-dependencies
32 | .packages
33 | .pub-cache/
34 | .pub/
35 | /build/
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # Android Studio will place build artifacts here
44 | /android/app/debug
45 | /android/app/profile
46 | /android/app/release
47 |
--------------------------------------------------------------------------------
/example/.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: "78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9"
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: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
17 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
18 | - platform: android
19 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
20 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
21 | - platform: ios
22 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
23 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
24 | - platform: linux
25 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
26 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
27 | - platform: macos
28 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
29 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
30 | - platform: web
31 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
32 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
33 | - platform: windows
34 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
35 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9
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 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # example
2 |
3 | A new Flutter project.
4 |
5 | ## Getting Started
6 |
7 | This project is a starting point for a Flutter application.
8 |
9 | A few resources to get you started if this is your first Flutter project:
10 |
11 | - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
13 |
14 | For help getting started with Flutter development, view the
15 | [online documentation](https://docs.flutter.dev/), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "com.android.application"
3 | id "kotlin-android"
4 | id "dev.flutter.flutter-gradle-plugin"
5 | }
6 |
7 | def localProperties = new Properties()
8 | def localPropertiesFile = rootProject.file('local.properties')
9 | if (localPropertiesFile.exists()) {
10 | localPropertiesFile.withReader('UTF-8') { reader ->
11 | localProperties.load(reader)
12 | }
13 | }
14 |
15 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
16 | if (flutterVersionCode == null) {
17 | flutterVersionCode = '1'
18 | }
19 |
20 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
21 | if (flutterVersionName == null) {
22 | flutterVersionName = '1.0'
23 | }
24 |
25 | android {
26 | namespace "com.example.example"
27 | compileSdkVersion flutter.compileSdkVersion
28 | ndkVersion flutter.ndkVersion
29 |
30 | compileOptions {
31 | sourceCompatibility JavaVersion.VERSION_1_8
32 | targetCompatibility JavaVersion.VERSION_1_8
33 | }
34 |
35 | kotlinOptions {
36 | jvmTarget = '1.8'
37 | }
38 |
39 | sourceSets {
40 | main.java.srcDirs += 'src/main/kotlin'
41 | }
42 |
43 | defaultConfig {
44 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
45 | applicationId "com.example.example"
46 | // You can update the following values to match your application needs.
47 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
48 | minSdkVersion flutter.minSdkVersion
49 | targetSdkVersion flutter.targetSdkVersion
50 | versionCode flutterVersionCode.toInteger()
51 | versionName flutterVersionName
52 | }
53 |
54 | buildTypes {
55 | release {
56 | // TODO: Add your own signing config for the release build.
57 | // Signing with the debug keys for now, so `flutter run --release` works.
58 | signingConfig signingConfigs.debug
59 | }
60 | }
61 | }
62 |
63 | flutter {
64 | source '../..'
65 | }
66 |
67 | dependencies {}
68 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
14 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
29 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.example
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.7.10'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
10 | }
11 | }
12 |
13 | allprojects {
14 | repositories {
15 | google()
16 | mavenCentral()
17 | }
18 | }
19 |
20 | rootProject.buildDir = '../build'
21 | subprojects {
22 | project.buildDir = "${rootProject.buildDir}/${project.name}"
23 | }
24 | subprojects {
25 | project.evaluationDependsOn(':app')
26 | }
27 |
28 | tasks.register("clean", Delete) {
29 | delete rootProject.buildDir
30 | }
31 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx4G
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
6 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | def flutterSdkPath = {
3 | def properties = new Properties()
4 | file("local.properties").withInputStream { properties.load(it) }
5 | def flutterSdkPath = properties.getProperty("flutter.sdk")
6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
7 | return flutterSdkPath
8 | }
9 | settings.ext.flutterSdkPath = flutterSdkPath()
10 |
11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
12 |
13 | repositories {
14 | google()
15 | mavenCentral()
16 | gradlePluginPortal()
17 | }
18 |
19 | plugins {
20 | id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
21 | }
22 | }
23 |
24 | plugins {
25 | id "dev.flutter.flutter-plugin-loader" version "1.0.0"
26 | id "com.android.application" version "7.3.0" apply false
27 | }
28 |
29 | include ":app"
30 |
--------------------------------------------------------------------------------
/example/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 12.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '12.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | target 'RunnerTests' do
36 | inherit! :search_paths
37 | end
38 | end
39 |
40 | post_install do |installer|
41 | installer.pods_project.targets.each do |target|
42 | flutter_additional_ios_build_settings(target)
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
65 |
71 |
72 |
73 |
74 |
80 |
82 |
88 |
89 |
90 |
91 |
93 |
94 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @main
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Example
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | example
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Main
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | CADisableMinimumFrameDurationOnPhone
45 |
46 | UIApplicationSupportsIndirectInputEvents
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/example/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/example/ios/RunnerTests/RunnerTests.swift:
--------------------------------------------------------------------------------
1 | import Flutter
2 | import UIKit
3 | import XCTest
4 |
5 | class RunnerTests: XCTestCase {
6 |
7 | func testExample() {
8 | // If you add code to the Runner application, consider adding tests here.
9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/example/lib/countries.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_helper_utils/flutter_helper_utils.dart';
5 |
6 | class Countries extends StatefulWidget {
7 | const Countries({super.key});
8 |
9 | @override
10 | State createState() => _CountriesState();
11 | }
12 |
13 | class _CountriesState extends State {
14 | final List countries = DHUCountry.generate();
15 | List filteredCountries = [];
16 | String searchQuery = '';
17 | Timer? _debounce;
18 |
19 | @override
20 | void initState() {
21 | super.initState();
22 | filteredCountries = countries;
23 | }
24 |
25 | // Debounce search to optimize performance
26 | void updateSearch(String query) {
27 | if (_debounce?.isActive ?? false) _debounce!.cancel();
28 | _debounce = Timer(const Duration(milliseconds: 300), () {
29 | performSearch(query);
30 | });
31 | }
32 |
33 | void performSearch(String query) {
34 | setState(() {
35 | searchQuery = query.toLowerCase().trim();
36 | filteredCountries = CountrySearchService(countries).search(searchQuery);
37 | });
38 | }
39 |
40 | @override
41 | Widget build(BuildContext context) {
42 | return Column(
43 | children: [
44 | // Search widget
45 | Padding(
46 | padding: const EdgeInsets.all(8),
47 | child: TextField(
48 | decoration: const InputDecoration(
49 | labelText: 'Search Countries',
50 | border: OutlineInputBorder(),
51 | ),
52 | onChanged: updateSearch,
53 | ),
54 | ),
55 | if (filteredCountries.isEmpty)
56 | Padding(
57 | padding: const EdgeInsets.all(20),
58 | child: Text(
59 | 'No countries found for "$searchQuery".',
60 | style: const TextStyle(fontSize: 18),
61 | ),
62 | )
63 | else
64 | SizedBox(
65 | height: 600,
66 | child: ListView.builder(
67 | itemCount: filteredCountries.length,
68 | itemBuilder: (context, i) {
69 | final country = filteredCountries[i];
70 | final nativeCommonName = country.nativeNames.isNotEmpty
71 | ? '(${country.nativeNames.first.common})'
72 | : '';
73 |
74 | return ListTile(
75 | leading: Text(
76 | country.flagEmoji,
77 | style: const TextStyle(fontSize: 50),
78 | ),
79 | title: buildHighlightedText(
80 | '${country.commonName} $nativeCommonName', searchQuery),
81 | subtitle: Column(
82 | crossAxisAlignment: CrossAxisAlignment.start,
83 | children: [
84 | Text('Official: ${country.officialName}'),
85 | Text('Region: ${country.region}, ${country.subregion}'),
86 | Text('Capital: ${country.capital ?? 'N/A'}'),
87 | Text('ISO: ${country.iso2} / ${country.iso3}'),
88 | Text('Phone Code: ${country.phoneCode}'),
89 | Text('Area: ${country.area.toStringAsFixed(0)} km²'),
90 | if (country.currencies.isNotEmpty)
91 | Text(
92 | 'Currency: ${country.currencies.map((c) => c.name).join(', ')}'),
93 | if (country.languages.isNotEmpty)
94 | Text(
95 | 'Languages: ${country.languages.map((l) => l.name).join(', ')}'),
96 | ],
97 | ),
98 | );
99 | },
100 | ),
101 | ),
102 | ],
103 | );
104 | }
105 |
106 | // Highlight matching text
107 | Widget buildHighlightedText(String text, String query) {
108 | final queryRegex = RegExp(RegExp.escape(query), caseSensitive: false);
109 | final matches = queryRegex.allMatches(text);
110 | if (matches.isEmpty) return Text(text);
111 |
112 | final spans = [];
113 | var lastIndex = 0;
114 | for (final match in matches) {
115 | if (match.start > lastIndex) {
116 | spans.add(TextSpan(text: text.substring(lastIndex, match.start)));
117 | }
118 | spans.add(TextSpan(
119 | text: text.substring(match.start, match.end),
120 | style: const TextStyle(backgroundColor: Colors.yellow),
121 | ));
122 | lastIndex = match.end;
123 | }
124 | if (lastIndex < text.length) {
125 | spans.add(TextSpan(text: text.substring(lastIndex)));
126 | }
127 |
128 | return RichText(
129 | text:
130 | TextSpan(children: spans, style: DefaultTextStyle.of(context).style),
131 | );
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/example/linux/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral
2 |
--------------------------------------------------------------------------------
/example/linux/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Project-level configuration.
2 | cmake_minimum_required(VERSION 3.10)
3 | project(runner LANGUAGES CXX)
4 |
5 | # The name of the executable created for the application. Change this to change
6 | # the on-disk name of your application.
7 | set(BINARY_NAME "example")
8 | # The unique GTK application identifier for this application. See:
9 | # https://wiki.gnome.org/HowDoI/ChooseApplicationID
10 | set(APPLICATION_ID "com.example.example")
11 |
12 | # Explicitly opt in to modern CMake behaviors to avoid warnings with recent
13 | # versions of CMake.
14 | cmake_policy(SET CMP0063 NEW)
15 |
16 | # Load bundled libraries from the lib/ directory relative to the binary.
17 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
18 |
19 | # Root filesystem for cross-building.
20 | if(FLUTTER_TARGET_PLATFORM_SYSROOT)
21 | set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
22 | set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
23 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
24 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
25 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
26 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
27 | endif()
28 |
29 | # Define build configuration options.
30 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
31 | set(CMAKE_BUILD_TYPE "Debug" CACHE
32 | STRING "Flutter build mode" FORCE)
33 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
34 | "Debug" "Profile" "Release")
35 | endif()
36 |
37 | # Compilation settings that should be applied to most targets.
38 | #
39 | # Be cautious about adding new options here, as plugins use this function by
40 | # default. In most cases, you should add new options to specific targets instead
41 | # of modifying this function.
42 | function(APPLY_STANDARD_SETTINGS TARGET)
43 | target_compile_features(${TARGET} PUBLIC cxx_std_14)
44 | target_compile_options(${TARGET} PRIVATE -Wall -Werror)
45 | target_compile_options(${TARGET} PRIVATE "$<$>:-O3>")
46 | target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>")
47 | endfunction()
48 |
49 | # Flutter library and tool build rules.
50 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
51 | add_subdirectory(${FLUTTER_MANAGED_DIR})
52 |
53 | # System-level dependencies.
54 | find_package(PkgConfig REQUIRED)
55 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
56 |
57 | add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
58 |
59 | # Define the application target. To change its name, change BINARY_NAME above,
60 | # not the value here, or `flutter run` will no longer work.
61 | #
62 | # Any new source files that you add to the application should be added here.
63 | add_executable(${BINARY_NAME}
64 | "main.cc"
65 | "my_application.cc"
66 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
67 | )
68 |
69 | # Apply the standard set of build settings. This can be removed for applications
70 | # that need different build settings.
71 | apply_standard_settings(${BINARY_NAME})
72 |
73 | # Add dependency libraries. Add any application-specific dependencies here.
74 | target_link_libraries(${BINARY_NAME} PRIVATE flutter)
75 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
76 |
77 | # Run the Flutter tool portions of the build. This must not be removed.
78 | add_dependencies(${BINARY_NAME} flutter_assemble)
79 |
80 | # Only the install-generated bundle's copy of the executable will launch
81 | # correctly, since the resources must in the right relative locations. To avoid
82 | # people trying to run the unbundled copy, put it in a subdirectory instead of
83 | # the default top-level location.
84 | set_target_properties(${BINARY_NAME}
85 | PROPERTIES
86 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
87 | )
88 |
89 |
90 | # Generated plugin build rules, which manage building the plugins and adding
91 | # them to the application.
92 | include(flutter/generated_plugins.cmake)
93 |
94 |
95 | # === Installation ===
96 | # By default, "installing" just makes a relocatable bundle in the build
97 | # directory.
98 | set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
99 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
100 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
101 | endif()
102 |
103 | # Start with a clean build bundle directory every time.
104 | install(CODE "
105 | file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
106 | " COMPONENT Runtime)
107 |
108 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
109 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
110 |
111 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
112 | COMPONENT Runtime)
113 |
114 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
115 | COMPONENT Runtime)
116 |
117 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
118 | COMPONENT Runtime)
119 |
120 | foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
121 | install(FILES "${bundled_library}"
122 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
123 | COMPONENT Runtime)
124 | endforeach(bundled_library)
125 |
126 | # Copy the native assets provided by the build.dart from all packages.
127 | set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/")
128 | install(DIRECTORY "${NATIVE_ASSETS_DIR}"
129 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
130 | COMPONENT Runtime)
131 |
132 | # Fully re-copy the assets directory on each build to avoid having stale files
133 | # from a previous install.
134 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
135 | install(CODE "
136 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
137 | " COMPONENT Runtime)
138 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
139 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
140 |
141 | # Install the AOT library on non-Debug builds only.
142 | if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
143 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
144 | COMPONENT Runtime)
145 | endif()
146 |
--------------------------------------------------------------------------------
/example/linux/flutter/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file controls Flutter-level build steps. It should not be edited.
2 | cmake_minimum_required(VERSION 3.10)
3 |
4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
5 |
6 | # Configuration provided via flutter tool.
7 | include(${EPHEMERAL_DIR}/generated_config.cmake)
8 |
9 | # TODO: Move the rest of this into files in ephemeral. See
10 | # https://github.com/flutter/flutter/issues/57146.
11 |
12 | # Serves the same purpose as list(TRANSFORM ... PREPEND ...),
13 | # which isn't available in 3.10.
14 | function(list_prepend LIST_NAME PREFIX)
15 | set(NEW_LIST "")
16 | foreach(element ${${LIST_NAME}})
17 | list(APPEND NEW_LIST "${PREFIX}${element}")
18 | endforeach(element)
19 | set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
20 | endfunction()
21 |
22 | # === Flutter Library ===
23 | # System-level dependencies.
24 | find_package(PkgConfig REQUIRED)
25 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
26 | pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
27 | pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
28 |
29 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
30 |
31 | # Published to parent scope for install step.
32 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
33 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
34 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
35 | set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
36 |
37 | list(APPEND FLUTTER_LIBRARY_HEADERS
38 | "fl_basic_message_channel.h"
39 | "fl_binary_codec.h"
40 | "fl_binary_messenger.h"
41 | "fl_dart_project.h"
42 | "fl_engine.h"
43 | "fl_json_message_codec.h"
44 | "fl_json_method_codec.h"
45 | "fl_message_codec.h"
46 | "fl_method_call.h"
47 | "fl_method_channel.h"
48 | "fl_method_codec.h"
49 | "fl_method_response.h"
50 | "fl_plugin_registrar.h"
51 | "fl_plugin_registry.h"
52 | "fl_standard_message_codec.h"
53 | "fl_standard_method_codec.h"
54 | "fl_string_codec.h"
55 | "fl_value.h"
56 | "fl_view.h"
57 | "flutter_linux.h"
58 | )
59 | list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
60 | add_library(flutter INTERFACE)
61 | target_include_directories(flutter INTERFACE
62 | "${EPHEMERAL_DIR}"
63 | )
64 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
65 | target_link_libraries(flutter INTERFACE
66 | PkgConfig::GTK
67 | PkgConfig::GLIB
68 | PkgConfig::GIO
69 | )
70 | add_dependencies(flutter flutter_assemble)
71 |
72 | # === Flutter tool backend ===
73 | # _phony_ is a non-existent file to force this command to run every time,
74 | # since currently there's no way to get a full input/output list from the
75 | # flutter tool.
76 | add_custom_command(
77 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
78 | ${CMAKE_CURRENT_BINARY_DIR}/_phony_
79 | COMMAND ${CMAKE_COMMAND} -E env
80 | ${FLUTTER_TOOL_ENVIRONMENT}
81 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
82 | ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
83 | VERBATIM
84 | )
85 | add_custom_target(flutter_assemble DEPENDS
86 | "${FLUTTER_LIBRARY}"
87 | ${FLUTTER_LIBRARY_HEADERS}
88 | )
89 |
--------------------------------------------------------------------------------
/example/linux/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #include "generated_plugin_registrant.h"
8 |
9 |
10 | void fl_register_plugins(FlPluginRegistry* registry) {
11 | }
12 |
--------------------------------------------------------------------------------
/example/linux/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
8 | #define GENERATED_PLUGIN_REGISTRANT_
9 |
10 | #include
11 |
12 | // Registers Flutter plugins.
13 | void fl_register_plugins(FlPluginRegistry* registry);
14 |
15 | #endif // GENERATED_PLUGIN_REGISTRANT_
16 |
--------------------------------------------------------------------------------
/example/linux/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # Generated file, do not edit.
3 | #
4 |
5 | list(APPEND FLUTTER_PLUGIN_LIST
6 | )
7 |
8 | list(APPEND FLUTTER_FFI_PLUGIN_LIST
9 | )
10 |
11 | set(PLUGIN_BUNDLED_LIBRARIES)
12 |
13 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
14 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
15 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
16 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
18 | endforeach(plugin)
19 |
20 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
21 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
23 | endforeach(ffi_plugin)
24 |
--------------------------------------------------------------------------------
/example/linux/main.cc:
--------------------------------------------------------------------------------
1 | #include "my_application.h"
2 |
3 | int main(int argc, char** argv) {
4 | g_autoptr(MyApplication) app = my_application_new();
5 | return g_application_run(G_APPLICATION(app), argc, argv);
6 | }
7 |
--------------------------------------------------------------------------------
/example/linux/my_application.cc:
--------------------------------------------------------------------------------
1 | #include "my_application.h"
2 |
3 | #include
4 | #ifdef GDK_WINDOWING_X11
5 | #include
6 | #endif
7 |
8 | #include "flutter/generated_plugin_registrant.h"
9 |
10 | struct _MyApplication {
11 | GtkApplication parent_instance;
12 | char** dart_entrypoint_arguments;
13 | };
14 |
15 | G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
16 |
17 | // Implements GApplication::activate.
18 | static void my_application_activate(GApplication* application) {
19 | MyApplication* self = MY_APPLICATION(application);
20 | GtkWindow* window =
21 | GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
22 |
23 | // Use a header bar when running in GNOME as this is the common style used
24 | // by applications and is the setup most users will be using (e.g. Ubuntu
25 | // desktop).
26 | // If running on X and not using GNOME then just use a traditional title bar
27 | // in case the window manager does more exotic layout, e.g. tiling.
28 | // If running on Wayland assume the header bar will work (may need changing
29 | // if future cases occur).
30 | gboolean use_header_bar = TRUE;
31 | #ifdef GDK_WINDOWING_X11
32 | GdkScreen* screen = gtk_window_get_screen(window);
33 | if (GDK_IS_X11_SCREEN(screen)) {
34 | const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
35 | if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
36 | use_header_bar = FALSE;
37 | }
38 | }
39 | #endif
40 | if (use_header_bar) {
41 | GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
42 | gtk_widget_show(GTK_WIDGET(header_bar));
43 | gtk_header_bar_set_title(header_bar, "example");
44 | gtk_header_bar_set_show_close_button(header_bar, TRUE);
45 | gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
46 | } else {
47 | gtk_window_set_title(window, "example");
48 | }
49 |
50 | gtk_window_set_default_size(window, 1280, 720);
51 | gtk_widget_show(GTK_WIDGET(window));
52 |
53 | g_autoptr(FlDartProject) project = fl_dart_project_new();
54 | fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
55 |
56 | FlView* view = fl_view_new(project);
57 | gtk_widget_show(GTK_WIDGET(view));
58 | gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
59 |
60 | fl_register_plugins(FL_PLUGIN_REGISTRY(view));
61 |
62 | gtk_widget_grab_focus(GTK_WIDGET(view));
63 | }
64 |
65 | // Implements GApplication::local_command_line.
66 | static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
67 | MyApplication* self = MY_APPLICATION(application);
68 | // Strip out the first argument as it is the binary name.
69 | self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
70 |
71 | g_autoptr(GError) error = nullptr;
72 | if (!g_application_register(application, nullptr, &error)) {
73 | g_warning("Failed to register: %s", error->message);
74 | *exit_status = 1;
75 | return TRUE;
76 | }
77 |
78 | g_application_activate(application);
79 | *exit_status = 0;
80 |
81 | return TRUE;
82 | }
83 |
84 | // Implements GObject::dispose.
85 | static void my_application_dispose(GObject* object) {
86 | MyApplication* self = MY_APPLICATION(object);
87 | g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
88 | G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
89 | }
90 |
91 | static void my_application_class_init(MyApplicationClass* klass) {
92 | G_APPLICATION_CLASS(klass)->activate = my_application_activate;
93 | G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
94 | G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
95 | }
96 |
97 | static void my_application_init(MyApplication* self) {}
98 |
99 | MyApplication* my_application_new() {
100 | return MY_APPLICATION(g_object_new(my_application_get_type(),
101 | "application-id", APPLICATION_ID,
102 | "flags", G_APPLICATION_NON_UNIQUE,
103 | nullptr));
104 | }
105 |
--------------------------------------------------------------------------------
/example/linux/my_application.h:
--------------------------------------------------------------------------------
1 | #ifndef FLUTTER_MY_APPLICATION_H_
2 | #define FLUTTER_MY_APPLICATION_H_
3 |
4 | #include
5 |
6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
7 | GtkApplication)
8 |
9 | /**
10 | * my_application_new:
11 | *
12 | * Creates a new Flutter-based application.
13 | *
14 | * Returns: a new #MyApplication.
15 | */
16 | MyApplication* my_application_new();
17 |
18 | #endif // FLUTTER_MY_APPLICATION_H_
19 |
--------------------------------------------------------------------------------
/example/macos/.gitignore:
--------------------------------------------------------------------------------
1 | # Flutter-related
2 | **/Flutter/ephemeral/
3 | **/Pods/
4 |
5 | # Xcode-related
6 | **/dgph
7 | **/xcuserdata/
8 |
--------------------------------------------------------------------------------
/example/macos/Flutter/Flutter-Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/macos/Flutter/Flutter-Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/macos/Flutter/GeneratedPluginRegistrant.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | import FlutterMacOS
6 | import Foundation
7 |
8 |
9 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
10 | }
11 |
--------------------------------------------------------------------------------
/example/macos/Podfile:
--------------------------------------------------------------------------------
1 | platform :osx, '10.14'
2 |
3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
5 |
6 | project 'Runner', {
7 | 'Debug' => :debug,
8 | 'Profile' => :release,
9 | 'Release' => :release,
10 | }
11 |
12 | def flutter_root
13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
14 | unless File.exist?(generated_xcode_build_settings_path)
15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
16 | end
17 |
18 | File.foreach(generated_xcode_build_settings_path) do |line|
19 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
20 | return matches[1].strip if matches
21 | end
22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
23 | end
24 |
25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
26 |
27 | flutter_macos_podfile_setup
28 |
29 | target 'Runner' do
30 | use_frameworks!
31 | use_modular_headers!
32 |
33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
34 | target 'RunnerTests' do
35 | inherit! :search_paths
36 | end
37 | end
38 |
39 | post_install do |installer|
40 | installer.pods_project.targets.each do |target|
41 | flutter_additional_macos_build_settings(target)
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
65 |
71 |
72 |
73 |
74 |
80 |
82 |
88 |
89 |
90 |
91 |
93 |
94 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/example/macos/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/macos/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | @main
5 | class AppDelegate: FlutterAppDelegate {
6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
7 | return true
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "16x16",
5 | "idiom" : "mac",
6 | "filename" : "app_icon_16.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "16x16",
11 | "idiom" : "mac",
12 | "filename" : "app_icon_32.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "32x32",
17 | "idiom" : "mac",
18 | "filename" : "app_icon_32.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "32x32",
23 | "idiom" : "mac",
24 | "filename" : "app_icon_64.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "128x128",
29 | "idiom" : "mac",
30 | "filename" : "app_icon_128.png",
31 | "scale" : "1x"
32 | },
33 | {
34 | "size" : "128x128",
35 | "idiom" : "mac",
36 | "filename" : "app_icon_256.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "256x256",
41 | "idiom" : "mac",
42 | "filename" : "app_icon_256.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "256x256",
47 | "idiom" : "mac",
48 | "filename" : "app_icon_512.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "512x512",
53 | "idiom" : "mac",
54 | "filename" : "app_icon_512.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "512x512",
59 | "idiom" : "mac",
60 | "filename" : "app_icon_1024.png",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
--------------------------------------------------------------------------------
/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
--------------------------------------------------------------------------------
/example/macos/Runner/Configs/AppInfo.xcconfig:
--------------------------------------------------------------------------------
1 | // Application-level settings for the Runner target.
2 | //
3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
4 | // future. If not, the values below would default to using the project name when this becomes a
5 | // 'flutter create' template.
6 |
7 | // The application's name. By default this is also the title of the Flutter window.
8 | PRODUCT_NAME = example
9 |
10 | // The application's bundle identifier
11 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example
12 |
13 | // The copyright displayed in application information
14 | PRODUCT_COPYRIGHT = Copyright © 2024 com.example. All rights reserved.
15 |
--------------------------------------------------------------------------------
/example/macos/Runner/Configs/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Debug.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/macos/Runner/Configs/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Release.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/macos/Runner/Configs/Warnings.xcconfig:
--------------------------------------------------------------------------------
1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
2 | GCC_WARN_UNDECLARED_SELECTOR = YES
3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
6 | CLANG_WARN_PRAGMA_PACK = YES
7 | CLANG_WARN_STRICT_PROTOTYPES = YES
8 | CLANG_WARN_COMMA = YES
9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES
10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
12 | GCC_WARN_SHADOW = YES
13 | CLANG_WARN_UNREACHABLE_CODE = YES
14 |
--------------------------------------------------------------------------------
/example/macos/Runner/DebugProfile.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.cs.allow-jit
8 |
9 | com.apple.security.network.server
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/example/macos/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSMinimumSystemVersion
24 | $(MACOSX_DEPLOYMENT_TARGET)
25 | NSHumanReadableCopyright
26 | $(PRODUCT_COPYRIGHT)
27 | NSMainNibFile
28 | MainMenu
29 | NSPrincipalClass
30 | NSApplication
31 |
32 |
33 |
--------------------------------------------------------------------------------
/example/macos/Runner/MainFlutterWindow.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | class MainFlutterWindow: NSWindow {
5 | override func awakeFromNib() {
6 | let flutterViewController = FlutterViewController()
7 | let windowFrame = self.frame
8 | self.contentViewController = flutterViewController
9 | self.setFrame(windowFrame, display: true)
10 |
11 | RegisterGeneratedPlugins(registry: flutterViewController)
12 |
13 | super.awakeFromNib()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/example/macos/Runner/Release.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/macos/RunnerTests/RunnerTests.swift:
--------------------------------------------------------------------------------
1 | import FlutterMacOS
2 | import Cocoa
3 | import XCTest
4 |
5 | class RunnerTests: XCTestCase {
6 |
7 | func testExample() {
8 | // If you add code to the Runner application, consider adding tests here.
9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: example
2 | description: A new Flutter project.
3 | publish_to: 'none'
4 | version: 1.0.0+1
5 |
6 | environment:
7 | sdk: '>=3.0.6 <4.0.0'
8 |
9 | dependencies:
10 | flutter:
11 | sdk: flutter
12 |
13 | enefty_icons: ^1.0.7
14 | intl: ^0.19.0
15 |
16 | # internal packages
17 | flutter_helper_utils:
18 | path: ../
19 |
20 | dev_dependencies:
21 | flutter_test:
22 | sdk: flutter
23 |
24 | flutter:
25 | uses-material-design: true
26 |
--------------------------------------------------------------------------------
/example/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/web/favicon.png
--------------------------------------------------------------------------------
/example/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/example/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/example/web/icons/Icon-maskable-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/web/icons/Icon-maskable-192.png
--------------------------------------------------------------------------------
/example/web/icons/Icon-maskable-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/web/icons/Icon-maskable-512.png
--------------------------------------------------------------------------------
/example/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | example
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/example/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "short_name": "example",
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 |
--------------------------------------------------------------------------------
/example/windows/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral/
2 |
3 | # Visual Studio user-specific files.
4 | *.suo
5 | *.user
6 | *.userosscache
7 | *.sln.docstates
8 |
9 | # Visual Studio build-related files.
10 | x64/
11 | x86/
12 |
13 | # Visual Studio cache files
14 | # files ending in .cache can be ignored
15 | *.[Cc]ache
16 | # but keep track of directories ending in .cache
17 | !*.[Cc]ache/
18 |
--------------------------------------------------------------------------------
/example/windows/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Project-level configuration.
2 | cmake_minimum_required(VERSION 3.14)
3 | project(example LANGUAGES CXX)
4 |
5 | # The name of the executable created for the application. Change this to change
6 | # the on-disk name of your application.
7 | set(BINARY_NAME "example")
8 |
9 | # Explicitly opt in to modern CMake behaviors to avoid warnings with recent
10 | # versions of CMake.
11 | cmake_policy(VERSION 3.14...3.25)
12 |
13 | # Define build configuration option.
14 | get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
15 | if(IS_MULTICONFIG)
16 | set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
17 | CACHE STRING "" FORCE)
18 | else()
19 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
20 | set(CMAKE_BUILD_TYPE "Debug" CACHE
21 | STRING "Flutter build mode" FORCE)
22 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
23 | "Debug" "Profile" "Release")
24 | endif()
25 | endif()
26 | # Define settings for the Profile build mode.
27 | set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
28 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
29 | set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
30 | set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
31 |
32 | # Use Unicode for all projects.
33 | add_definitions(-DUNICODE -D_UNICODE)
34 |
35 | # Compilation settings that should be applied to most targets.
36 | #
37 | # Be cautious about adding new options here, as plugins use this function by
38 | # default. In most cases, you should add new options to specific targets instead
39 | # of modifying this function.
40 | function(APPLY_STANDARD_SETTINGS TARGET)
41 | target_compile_features(${TARGET} PUBLIC cxx_std_17)
42 | target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
43 | target_compile_options(${TARGET} PRIVATE /EHsc)
44 | target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
45 | target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>")
46 | endfunction()
47 |
48 | # Flutter library and tool build rules.
49 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
50 | add_subdirectory(${FLUTTER_MANAGED_DIR})
51 |
52 | # Application build; see runner/CMakeLists.txt.
53 | add_subdirectory("runner")
54 |
55 |
56 | # Generated plugin build rules, which manage building the plugins and adding
57 | # them to the application.
58 | include(flutter/generated_plugins.cmake)
59 |
60 |
61 | # === Installation ===
62 | # Support files are copied into place next to the executable, so that it can
63 | # run in place. This is done instead of making a separate bundle (as on Linux)
64 | # so that building and running from within Visual Studio will work.
65 | set(BUILD_BUNDLE_DIR "$")
66 | # Make the "install" step default, as it's required to run.
67 | set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
68 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
69 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
70 | endif()
71 |
72 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
73 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
74 |
75 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
76 | COMPONENT Runtime)
77 |
78 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
79 | COMPONENT Runtime)
80 |
81 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
82 | COMPONENT Runtime)
83 |
84 | if(PLUGIN_BUNDLED_LIBRARIES)
85 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
86 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
87 | COMPONENT Runtime)
88 | endif()
89 |
90 | # Copy the native assets provided by the build.dart from all packages.
91 | set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/")
92 | install(DIRECTORY "${NATIVE_ASSETS_DIR}"
93 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
94 | COMPONENT Runtime)
95 |
96 | # Fully re-copy the assets directory on each build to avoid having stale files
97 | # from a previous install.
98 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
99 | install(CODE "
100 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
101 | " COMPONENT Runtime)
102 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
103 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
104 |
105 | # Install the AOT library on non-Debug builds only.
106 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
107 | CONFIGURATIONS Profile;Release
108 | COMPONENT Runtime)
109 |
--------------------------------------------------------------------------------
/example/windows/flutter/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file controls Flutter-level build steps. It should not be edited.
2 | cmake_minimum_required(VERSION 3.14)
3 |
4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
5 |
6 | # Configuration provided via flutter tool.
7 | include(${EPHEMERAL_DIR}/generated_config.cmake)
8 |
9 | # TODO: Move the rest of this into files in ephemeral. See
10 | # https://github.com/flutter/flutter/issues/57146.
11 | set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
12 |
13 | # Set fallback configurations for older versions of the flutter tool.
14 | if (NOT DEFINED FLUTTER_TARGET_PLATFORM)
15 | set(FLUTTER_TARGET_PLATFORM "windows-x64")
16 | endif()
17 |
18 | # === Flutter Library ===
19 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
20 |
21 | # Published to parent scope for install step.
22 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
23 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
24 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
25 | set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
26 |
27 | list(APPEND FLUTTER_LIBRARY_HEADERS
28 | "flutter_export.h"
29 | "flutter_windows.h"
30 | "flutter_messenger.h"
31 | "flutter_plugin_registrar.h"
32 | "flutter_texture_registrar.h"
33 | )
34 | list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
35 | add_library(flutter INTERFACE)
36 | target_include_directories(flutter INTERFACE
37 | "${EPHEMERAL_DIR}"
38 | )
39 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
40 | add_dependencies(flutter flutter_assemble)
41 |
42 | # === Wrapper ===
43 | list(APPEND CPP_WRAPPER_SOURCES_CORE
44 | "core_implementations.cc"
45 | "standard_codec.cc"
46 | )
47 | list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
48 | list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
49 | "plugin_registrar.cc"
50 | )
51 | list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
52 | list(APPEND CPP_WRAPPER_SOURCES_APP
53 | "flutter_engine.cc"
54 | "flutter_view_controller.cc"
55 | )
56 | list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
57 |
58 | # Wrapper sources needed for a plugin.
59 | add_library(flutter_wrapper_plugin STATIC
60 | ${CPP_WRAPPER_SOURCES_CORE}
61 | ${CPP_WRAPPER_SOURCES_PLUGIN}
62 | )
63 | apply_standard_settings(flutter_wrapper_plugin)
64 | set_target_properties(flutter_wrapper_plugin PROPERTIES
65 | POSITION_INDEPENDENT_CODE ON)
66 | set_target_properties(flutter_wrapper_plugin PROPERTIES
67 | CXX_VISIBILITY_PRESET hidden)
68 | target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
69 | target_include_directories(flutter_wrapper_plugin PUBLIC
70 | "${WRAPPER_ROOT}/include"
71 | )
72 | add_dependencies(flutter_wrapper_plugin flutter_assemble)
73 |
74 | # Wrapper sources needed for the runner.
75 | add_library(flutter_wrapper_app STATIC
76 | ${CPP_WRAPPER_SOURCES_CORE}
77 | ${CPP_WRAPPER_SOURCES_APP}
78 | )
79 | apply_standard_settings(flutter_wrapper_app)
80 | target_link_libraries(flutter_wrapper_app PUBLIC flutter)
81 | target_include_directories(flutter_wrapper_app PUBLIC
82 | "${WRAPPER_ROOT}/include"
83 | )
84 | add_dependencies(flutter_wrapper_app flutter_assemble)
85 |
86 | # === Flutter tool backend ===
87 | # _phony_ is a non-existent file to force this command to run every time,
88 | # since currently there's no way to get a full input/output list from the
89 | # flutter tool.
90 | set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
91 | set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
92 | add_custom_command(
93 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
94 | ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
95 | ${CPP_WRAPPER_SOURCES_APP}
96 | ${PHONY_OUTPUT}
97 | COMMAND ${CMAKE_COMMAND} -E env
98 | ${FLUTTER_TOOL_ENVIRONMENT}
99 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
100 | ${FLUTTER_TARGET_PLATFORM} $
101 | VERBATIM
102 | )
103 | add_custom_target(flutter_assemble DEPENDS
104 | "${FLUTTER_LIBRARY}"
105 | ${FLUTTER_LIBRARY_HEADERS}
106 | ${CPP_WRAPPER_SOURCES_CORE}
107 | ${CPP_WRAPPER_SOURCES_PLUGIN}
108 | ${CPP_WRAPPER_SOURCES_APP}
109 | )
110 |
--------------------------------------------------------------------------------
/example/windows/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #include "generated_plugin_registrant.h"
8 |
9 |
10 | void RegisterPlugins(flutter::PluginRegistry* registry) {
11 | }
12 |
--------------------------------------------------------------------------------
/example/windows/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
8 | #define GENERATED_PLUGIN_REGISTRANT_
9 |
10 | #include
11 |
12 | // Registers Flutter plugins.
13 | void RegisterPlugins(flutter::PluginRegistry* registry);
14 |
15 | #endif // GENERATED_PLUGIN_REGISTRANT_
16 |
--------------------------------------------------------------------------------
/example/windows/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # Generated file, do not edit.
3 | #
4 |
5 | list(APPEND FLUTTER_PLUGIN_LIST
6 | )
7 |
8 | list(APPEND FLUTTER_FFI_PLUGIN_LIST
9 | )
10 |
11 | set(PLUGIN_BUNDLED_LIBRARIES)
12 |
13 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
14 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
15 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
16 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
18 | endforeach(plugin)
19 |
20 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
21 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
23 | endforeach(ffi_plugin)
24 |
--------------------------------------------------------------------------------
/example/windows/runner/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.14)
2 | project(runner LANGUAGES CXX)
3 |
4 | # Define the application target. To change its name, change BINARY_NAME in the
5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
6 | # work.
7 | #
8 | # Any new source files that you add to the application should be added here.
9 | add_executable(${BINARY_NAME} WIN32
10 | "flutter_window.cpp"
11 | "main.cpp"
12 | "utils.cpp"
13 | "win32_window.cpp"
14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
15 | "Runner.rc"
16 | "runner.exe.manifest"
17 | )
18 |
19 | # Apply the standard set of build settings. This can be removed for applications
20 | # that need different build settings.
21 | apply_standard_settings(${BINARY_NAME})
22 |
23 | # Add preprocessor definitions for the build version.
24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
29 |
30 | # Disable Windows macros that collide with C++ standard library functions.
31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
32 |
33 | # Add dependency libraries and include directories. Add any application-specific
34 | # dependencies here.
35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
36 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
38 |
39 | # Run the Flutter tool portions of the build. This must not be removed.
40 | add_dependencies(${BINARY_NAME} flutter_assemble)
41 |
--------------------------------------------------------------------------------
/example/windows/runner/Runner.rc:
--------------------------------------------------------------------------------
1 | // Microsoft Visual C++ generated resource script.
2 | //
3 | #pragma code_page(65001)
4 | #include "resource.h"
5 |
6 | #define APSTUDIO_READONLY_SYMBOLS
7 | /////////////////////////////////////////////////////////////////////////////
8 | //
9 | // Generated from the TEXTINCLUDE 2 resource.
10 | //
11 | #include "winres.h"
12 |
13 | /////////////////////////////////////////////////////////////////////////////
14 | #undef APSTUDIO_READONLY_SYMBOLS
15 |
16 | /////////////////////////////////////////////////////////////////////////////
17 | // English (United States) resources
18 |
19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
21 |
22 | #ifdef APSTUDIO_INVOKED
23 | /////////////////////////////////////////////////////////////////////////////
24 | //
25 | // TEXTINCLUDE
26 | //
27 |
28 | 1 TEXTINCLUDE
29 | BEGIN
30 | "resource.h\0"
31 | END
32 |
33 | 2 TEXTINCLUDE
34 | BEGIN
35 | "#include ""winres.h""\r\n"
36 | "\0"
37 | END
38 |
39 | 3 TEXTINCLUDE
40 | BEGIN
41 | "\r\n"
42 | "\0"
43 | END
44 |
45 | #endif // APSTUDIO_INVOKED
46 |
47 |
48 | /////////////////////////////////////////////////////////////////////////////
49 | //
50 | // Icon
51 | //
52 |
53 | // Icon with lowest ID value placed first to ensure application icon
54 | // remains consistent on all systems.
55 | IDI_APP_ICON ICON "resources\\app_icon.ico"
56 |
57 |
58 | /////////////////////////////////////////////////////////////////////////////
59 | //
60 | // Version
61 | //
62 |
63 | #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
64 | #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
65 | #else
66 | #define VERSION_AS_NUMBER 1,0,0,0
67 | #endif
68 |
69 | #if defined(FLUTTER_VERSION)
70 | #define VERSION_AS_STRING FLUTTER_VERSION
71 | #else
72 | #define VERSION_AS_STRING "1.0.0"
73 | #endif
74 |
75 | VS_VERSION_INFO VERSIONINFO
76 | FILEVERSION VERSION_AS_NUMBER
77 | PRODUCTVERSION VERSION_AS_NUMBER
78 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
79 | #ifdef _DEBUG
80 | FILEFLAGS VS_FF_DEBUG
81 | #else
82 | FILEFLAGS 0x0L
83 | #endif
84 | FILEOS VOS__WINDOWS32
85 | FILETYPE VFT_APP
86 | FILESUBTYPE 0x0L
87 | BEGIN
88 | BLOCK "StringFileInfo"
89 | BEGIN
90 | BLOCK "040904e4"
91 | BEGIN
92 | VALUE "CompanyName", "com.example" "\0"
93 | VALUE "FileDescription", "example" "\0"
94 | VALUE "FileVersion", VERSION_AS_STRING "\0"
95 | VALUE "InternalName", "example" "\0"
96 | VALUE "LegalCopyright", "Copyright (C) 2024 com.example. All rights reserved." "\0"
97 | VALUE "OriginalFilename", "example.exe" "\0"
98 | VALUE "ProductName", "example" "\0"
99 | VALUE "ProductVersion", VERSION_AS_STRING "\0"
100 | END
101 | END
102 | BLOCK "VarFileInfo"
103 | BEGIN
104 | VALUE "Translation", 0x409, 1252
105 | END
106 | END
107 |
108 | #endif // English (United States) resources
109 | /////////////////////////////////////////////////////////////////////////////
110 |
111 |
112 |
113 | #ifndef APSTUDIO_INVOKED
114 | /////////////////////////////////////////////////////////////////////////////
115 | //
116 | // Generated from the TEXTINCLUDE 3 resource.
117 | //
118 |
119 |
120 | /////////////////////////////////////////////////////////////////////////////
121 | #endif // not APSTUDIO_INVOKED
122 |
--------------------------------------------------------------------------------
/example/windows/runner/flutter_window.cpp:
--------------------------------------------------------------------------------
1 | #include "flutter_window.h"
2 |
3 | #include
4 |
5 | #include "flutter/generated_plugin_registrant.h"
6 |
7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project)
8 | : project_(project) {}
9 |
10 | FlutterWindow::~FlutterWindow() {}
11 |
12 | bool FlutterWindow::OnCreate() {
13 | if (!Win32Window::OnCreate()) {
14 | return false;
15 | }
16 |
17 | RECT frame = GetClientArea();
18 |
19 | // The size here must match the window dimensions to avoid unnecessary surface
20 | // creation / destruction in the startup path.
21 | flutter_controller_ = std::make_unique(
22 | frame.right - frame.left, frame.bottom - frame.top, project_);
23 | // Ensure that basic setup of the controller was successful.
24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) {
25 | return false;
26 | }
27 | RegisterPlugins(flutter_controller_->engine());
28 | SetChildContent(flutter_controller_->view()->GetNativeWindow());
29 |
30 | flutter_controller_->engine()->SetNextFrameCallback([&]() {
31 | this->Show();
32 | });
33 |
34 | // Flutter can complete the first frame before the "show window" callback is
35 | // registered. The following call ensures a frame is pending to ensure the
36 | // window is shown. It is a no-op if the first frame hasn't completed yet.
37 | flutter_controller_->ForceRedraw();
38 |
39 | return true;
40 | }
41 |
42 | void FlutterWindow::OnDestroy() {
43 | if (flutter_controller_) {
44 | flutter_controller_ = nullptr;
45 | }
46 |
47 | Win32Window::OnDestroy();
48 | }
49 |
50 | LRESULT
51 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
52 | WPARAM const wparam,
53 | LPARAM const lparam) noexcept {
54 | // Give Flutter, including plugins, an opportunity to handle window messages.
55 | if (flutter_controller_) {
56 | std::optional result =
57 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
58 | lparam);
59 | if (result) {
60 | return *result;
61 | }
62 | }
63 |
64 | switch (message) {
65 | case WM_FONTCHANGE:
66 | flutter_controller_->engine()->ReloadSystemFonts();
67 | break;
68 | }
69 |
70 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
71 | }
72 |
--------------------------------------------------------------------------------
/example/windows/runner/flutter_window.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_FLUTTER_WINDOW_H_
2 | #define RUNNER_FLUTTER_WINDOW_H_
3 |
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | #include "win32_window.h"
10 |
11 | // A window that does nothing but host a Flutter view.
12 | class FlutterWindow : public Win32Window {
13 | public:
14 | // Creates a new FlutterWindow hosting a Flutter view running |project|.
15 | explicit FlutterWindow(const flutter::DartProject& project);
16 | virtual ~FlutterWindow();
17 |
18 | protected:
19 | // Win32Window:
20 | bool OnCreate() override;
21 | void OnDestroy() override;
22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
23 | LPARAM const lparam) noexcept override;
24 |
25 | private:
26 | // The project to run.
27 | flutter::DartProject project_;
28 |
29 | // The Flutter instance hosted by this window.
30 | std::unique_ptr flutter_controller_;
31 | };
32 |
33 | #endif // RUNNER_FLUTTER_WINDOW_H_
34 |
--------------------------------------------------------------------------------
/example/windows/runner/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "flutter_window.h"
6 | #include "utils.h"
7 |
8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
9 | _In_ wchar_t *command_line, _In_ int show_command) {
10 | // Attach to console when present (e.g., 'flutter run') or create a
11 | // new console when running with a debugger.
12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
13 | CreateAndAttachConsole();
14 | }
15 |
16 | // Initialize COM, so that it is available for use in the library and/or
17 | // plugins.
18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
19 |
20 | flutter::DartProject project(L"data");
21 |
22 | std::vector command_line_arguments =
23 | GetCommandLineArguments();
24 |
25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
26 |
27 | FlutterWindow window(project);
28 | Win32Window::Point origin(10, 10);
29 | Win32Window::Size size(1280, 720);
30 | if (!window.Create(L"example", origin, size)) {
31 | return EXIT_FAILURE;
32 | }
33 | window.SetQuitOnClose(true);
34 |
35 | ::MSG msg;
36 | while (::GetMessage(&msg, nullptr, 0, 0)) {
37 | ::TranslateMessage(&msg);
38 | ::DispatchMessage(&msg);
39 | }
40 |
41 | ::CoUninitialize();
42 | return EXIT_SUCCESS;
43 | }
44 |
--------------------------------------------------------------------------------
/example/windows/runner/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by Runner.rc
4 | //
5 | #define IDI_APP_ICON 101
6 |
7 | // Next default values for new objects
8 | //
9 | #ifdef APSTUDIO_INVOKED
10 | #ifndef APSTUDIO_READONLY_SYMBOLS
11 | #define _APS_NEXT_RESOURCE_VALUE 102
12 | #define _APS_NEXT_COMMAND_VALUE 40001
13 | #define _APS_NEXT_CONTROL_VALUE 1001
14 | #define _APS_NEXT_SYMED_VALUE 101
15 | #endif
16 | #endif
17 |
--------------------------------------------------------------------------------
/example/windows/runner/resources/app_icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omar-hanafy/flutter_helper_utils/946dffb197253a974c79e9a5f945f8d97120378d/example/windows/runner/resources/app_icon.ico
--------------------------------------------------------------------------------
/example/windows/runner/runner.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PerMonitorV2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/example/windows/runner/utils.cpp:
--------------------------------------------------------------------------------
1 | #include "utils.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | void CreateAndAttachConsole() {
11 | if (::AllocConsole()) {
12 | FILE *unused;
13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
14 | _dup2(_fileno(stdout), 1);
15 | }
16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
17 | _dup2(_fileno(stdout), 2);
18 | }
19 | std::ios::sync_with_stdio();
20 | FlutterDesktopResyncOutputStreams();
21 | }
22 | }
23 |
24 | std::vector GetCommandLineArguments() {
25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
26 | int argc;
27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
28 | if (argv == nullptr) {
29 | return std::vector();
30 | }
31 |
32 | std::vector command_line_arguments;
33 |
34 | // Skip the first argument as it's the binary name.
35 | for (int i = 1; i < argc; i++) {
36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
37 | }
38 |
39 | ::LocalFree(argv);
40 |
41 | return command_line_arguments;
42 | }
43 |
44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) {
45 | if (utf16_string == nullptr) {
46 | return std::string();
47 | }
48 | int target_length = ::WideCharToMultiByte(
49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
50 | -1, nullptr, 0, nullptr, nullptr)
51 | -1; // remove the trailing null character
52 | int input_length = (int)wcslen(utf16_string);
53 | std::string utf8_string;
54 | if (target_length <= 0 || target_length > utf8_string.max_size()) {
55 | return utf8_string;
56 | }
57 | utf8_string.resize(target_length);
58 | int converted_length = ::WideCharToMultiByte(
59 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
60 | input_length, utf8_string.data(), target_length, nullptr, nullptr);
61 | if (converted_length == 0) {
62 | return std::string();
63 | }
64 | return utf8_string;
65 | }
66 |
--------------------------------------------------------------------------------
/example/windows/runner/utils.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_UTILS_H_
2 | #define RUNNER_UTILS_H_
3 |
4 | #include
5 | #include
6 |
7 | // Creates a console for the process, and redirects stdout and stderr to
8 | // it for both the runner and the Flutter library.
9 | void CreateAndAttachConsole();
10 |
11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
12 | // encoded in UTF-8. Returns an empty std::string on failure.
13 | std::string Utf8FromUtf16(const wchar_t* utf16_string);
14 |
15 | // Gets the command line arguments passed in as a std::vector,
16 | // encoded in UTF-8. Returns an empty std::vector on failure.
17 | std::vector GetCommandLineArguments();
18 |
19 | #endif // RUNNER_UTILS_H_
20 |
--------------------------------------------------------------------------------
/example/windows/runner/win32_window.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_WIN32_WINDOW_H_
2 | #define RUNNER_WIN32_WINDOW_H_
3 |
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | // A class abstraction for a high DPI-aware Win32 Window. Intended to be
11 | // inherited from by classes that wish to specialize with custom
12 | // rendering and input handling
13 | class Win32Window {
14 | public:
15 | struct Point {
16 | unsigned int x;
17 | unsigned int y;
18 | Point(unsigned int x, unsigned int y) : x(x), y(y) {}
19 | };
20 |
21 | struct Size {
22 | unsigned int width;
23 | unsigned int height;
24 | Size(unsigned int width, unsigned int height)
25 | : width(width), height(height) {}
26 | };
27 |
28 | Win32Window();
29 | virtual ~Win32Window();
30 |
31 | // Creates a win32 window with |title| that is positioned and sized using
32 | // |origin| and |size|. New windows are created on the default monitor. Window
33 | // sizes are specified to the OS in physical pixels, hence to ensure a
34 | // consistent size this function will scale the inputted width and height as
35 | // as appropriate for the default monitor. The window is invisible until
36 | // |Show| is called. Returns true if the window was created successfully.
37 | bool Create(const std::wstring& title, const Point& origin, const Size& size);
38 |
39 | // Show the current window. Returns true if the window was successfully shown.
40 | bool Show();
41 |
42 | // Release OS resources associated with window.
43 | void Destroy();
44 |
45 | // Inserts |content| into the window tree.
46 | void SetChildContent(HWND content);
47 |
48 | // Returns the backing Window handle to enable clients to set icon and other
49 | // window properties. Returns nullptr if the window has been destroyed.
50 | HWND GetHandle();
51 |
52 | // If true, closing this window will quit the application.
53 | void SetQuitOnClose(bool quit_on_close);
54 |
55 | // Return a RECT representing the bounds of the current client area.
56 | RECT GetClientArea();
57 |
58 | protected:
59 | // Processes and route salient window messages for mouse handling,
60 | // size change and DPI. Delegates handling of these to member overloads that
61 | // inheriting classes can handle.
62 | virtual LRESULT MessageHandler(HWND window,
63 | UINT const message,
64 | WPARAM const wparam,
65 | LPARAM const lparam) noexcept;
66 |
67 | // Called when CreateAndShow is called, allowing subclass window-related
68 | // setup. Subclasses should return false if setup fails.
69 | virtual bool OnCreate();
70 |
71 | // Called when Destroy is called.
72 | virtual void OnDestroy();
73 |
74 | private:
75 | friend class WindowClassRegistrar;
76 |
77 | // OS callback called by message pump. Handles the WM_NCCREATE message which
78 | // is passed when the non-client area is being created and enables automatic
79 | // non-client DPI scaling so that the non-client area automatically
80 | // responds to changes in DPI. All other messages are handled by
81 | // MessageHandler.
82 | static LRESULT CALLBACK WndProc(HWND const window,
83 | UINT const message,
84 | WPARAM const wparam,
85 | LPARAM const lparam) noexcept;
86 |
87 | // Retrieves a class instance pointer for |window|
88 | static Win32Window* GetThisFromHandle(HWND const window) noexcept;
89 |
90 | // Update the window frame's theme to match the system theme.
91 | static void UpdateTheme(HWND const window);
92 |
93 | bool quit_on_close_ = false;
94 |
95 | // window handle for top level window.
96 | HWND window_handle_ = nullptr;
97 |
98 | // window handle for hosted content.
99 | HWND child_content_ = nullptr;
100 | };
101 |
102 | #endif // RUNNER_WIN32_WINDOW_H_
103 |
--------------------------------------------------------------------------------
/lib/flutter_helper_utils.dart:
--------------------------------------------------------------------------------
1 | export 'src/src.dart';
2 |
--------------------------------------------------------------------------------
/lib/src/extensions/extensions.dart:
--------------------------------------------------------------------------------
1 | export 'flutter_extensions/flutter_extensions.dart';
2 | export 'string_extensions/string_extensions.dart';
3 |
--------------------------------------------------------------------------------
/lib/src/extensions/flutter_extensions/align.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | extension FHUAlignExtensions on Widget {
4 | Align alignAtBottomCenter({
5 | Key? key,
6 | double? heightFactor,
7 | double? widthFactor,
8 | }) =>
9 | Align(
10 | key: key,
11 | alignment: Alignment.bottomCenter,
12 | heightFactor: heightFactor,
13 | widthFactor: widthFactor,
14 | child: this,
15 | );
16 |
17 | Align alignAtTopLeft({
18 | Key? key,
19 | double? heightFactor,
20 | double? widthFactor,
21 | }) =>
22 | Align(
23 | key: key,
24 | alignment: Alignment.topLeft,
25 | heightFactor: heightFactor,
26 | widthFactor: widthFactor,
27 | child: this,
28 | );
29 |
30 | Align alignAtBottomLeft({
31 | Key? key,
32 | double? heightFactor,
33 | double? widthFactor,
34 | }) =>
35 | Align(
36 | key: key,
37 | alignment: Alignment.bottomLeft,
38 | heightFactor: heightFactor,
39 | widthFactor: widthFactor,
40 | child: this,
41 | );
42 |
43 | Align alignAtBottomRight({
44 | Key? key,
45 | double? heightFactor,
46 | double? widthFactor,
47 | }) =>
48 | Align(
49 | key: key,
50 | alignment: Alignment.bottomRight,
51 | heightFactor: heightFactor,
52 | widthFactor: widthFactor,
53 | child: this,
54 | );
55 |
56 | Align alignAtCenterLeft({
57 | Key? key,
58 | double? heightFactor,
59 | double? widthFactor,
60 | }) =>
61 | Align(
62 | key: key,
63 | alignment: Alignment.centerLeft,
64 | heightFactor: heightFactor,
65 | widthFactor: widthFactor,
66 | child: this,
67 | );
68 |
69 | Align alignAtCenter({
70 | Key? key,
71 | double? heightFactor,
72 | double? widthFactor,
73 | }) =>
74 | Align(
75 | key: key,
76 | heightFactor: heightFactor,
77 | widthFactor: widthFactor,
78 | child: this,
79 | );
80 |
81 | Align alignAtCenterRight({
82 | Key? key,
83 | double? heightFactor,
84 | double? widthFactor,
85 | }) =>
86 | Align(
87 | key: key,
88 | alignment: Alignment.centerRight,
89 | heightFactor: heightFactor,
90 | widthFactor: widthFactor,
91 | child: this,
92 | );
93 |
94 | Align alignAtLERP(
95 | Alignment a,
96 | Alignment b,
97 | double t, {
98 | Key? key,
99 | double? heightFactor,
100 | double? widthFactor,
101 | }) =>
102 | Align(
103 | key: key,
104 | alignment: Alignment.lerp(a, b, t)!,
105 | heightFactor: heightFactor,
106 | widthFactor: widthFactor,
107 | child: this,
108 | );
109 |
110 | Align alignXY(
111 | double x,
112 | double y, {
113 | Key? key,
114 | double? heightFactor,
115 | double? widthFactor,
116 | }) =>
117 | Align(
118 | key: key,
119 | alignment: Alignment(x, y),
120 | heightFactor: heightFactor,
121 | widthFactor: widthFactor,
122 | child: this,
123 | );
124 |
125 | Align alignAtTopCenter({
126 | Key? key,
127 | double? heightFactor,
128 | double? widthFactor,
129 | }) =>
130 | Align(
131 | key: key,
132 | alignment: Alignment.topCenter,
133 | heightFactor: heightFactor,
134 | widthFactor: widthFactor,
135 | child: this,
136 | );
137 |
138 | Align alignAtTopRight({
139 | Key? key,
140 | double? heightFactor,
141 | double? widthFactor,
142 | }) =>
143 | Align(
144 | key: key,
145 | alignment: Alignment.topRight,
146 | heightFactor: heightFactor,
147 | widthFactor: widthFactor,
148 | child: this,
149 | );
150 | }
151 |
--------------------------------------------------------------------------------
/lib/src/extensions/flutter_extensions/colors/colors.dart:
--------------------------------------------------------------------------------
1 | export 'on_colors.dart';
2 | export 'on_string.dart';
3 |
--------------------------------------------------------------------------------
/lib/src/extensions/flutter_extensions/directionality.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: depend_on_referenced_packages
2 | import 'package:flutter/material.dart';
3 | import 'package:intl/intl.dart' as intl;
4 |
5 | /// DHUIntlTextDirectionExtensions
6 | extension DHUIntlTextDirectionExtensions on intl.TextDirection {
7 | TextDirection get toEnum => switch (this) {
8 | intl.TextDirection.RTL => TextDirection.rtl,
9 | _ => TextDirection.ltr,
10 | };
11 | }
12 |
13 | /// A collection of utility extensions for working with text directionality and localization.
14 | ///
15 | /// These extensions provide convenient methods for handling RTL/LTR text direction
16 | /// and locale-specific functionality in Flutter applications.
17 | ///
18 | /// Example usage:
19 | /// ```dart
20 | /// // Check text direction
21 | /// if (context.isRTL) {
22 | /// // Handle RTL layout
23 | /// }
24 | ///
25 | /// // Get locale information
26 | /// print(context.languageCode); // e.g., 'en'
27 | /// ```
28 | extension FHUTextDirection on TextDirection {
29 | /// Whether the text direction is right-to-left.
30 | bool get isRTL => this == TextDirection.rtl;
31 |
32 | /// Whether the text direction is left-to-right.
33 | bool get isLTR => this == TextDirection.ltr;
34 |
35 | /// Converts the text direction to a string representation.
36 | String get name => this == TextDirection.ltr ? 'ltr' : 'rtl';
37 |
38 | /// Returns the opposite text direction.
39 | TextDirection get opposite => isRTL ? TextDirection.ltr : TextDirection.rtl;
40 |
41 | /// Returns a multiplier (-1 or 1) useful for RTL-aware calculations.
42 | ///
43 | /// Returns:
44 | /// * 1 for LTR
45 | /// * -1 for RTL
46 | double get multiplier => isRTL ? -1.0 : 1.0;
47 | }
48 |
49 | /// Extension methods for accessing text directionality from a [BuildContext].
50 | extension FHUContextDirectionality on BuildContext {
51 | /// The current text direction from the ambient [Directionality].
52 | TextDirection get directionality => Directionality.of(this);
53 |
54 | /// Whether the current text direction is left-to-right.
55 | bool get isLTR => directionality.isLTR;
56 |
57 | /// Whether the current text direction is right-to-left.
58 | bool get isRTL => directionality.isRTL;
59 |
60 | /// The current locale from [Localizations].
61 | Locale get locale => Localizations.localeOf(this);
62 |
63 | /// A string representation of the current locale.
64 | ///
65 | /// Examples:
66 | /// * "en" for English
67 | /// * "en_US" for US English
68 | /// * "ar" for Arabic
69 | /// * "zh_Hant" for Traditional Chinese
70 | String get localeString {
71 | final currentLocale = locale;
72 | if (currentLocale.scriptCode != null) {
73 | return '${currentLocale.languageCode}_${currentLocale.scriptCode}';
74 | } else if (currentLocale.countryCode != null) {
75 | return '${currentLocale.languageCode}_${currentLocale.countryCode}';
76 | }
77 | return currentLocale.languageCode;
78 | }
79 |
80 | /// The language code of the current locale (e.g., "en" for English).
81 | String get languageCode => locale.languageCode;
82 |
83 | /// The country code of the current locale (e.g., "US" for United States).
84 | String? get countryCode => locale.countryCode;
85 |
86 | /// The script code of the current locale (e.g., "Hant" for Traditional Chinese).
87 | String? get scriptCode => locale.scriptCode;
88 |
89 | /// Returns true if the current locale matches the given language code.
90 | bool isLanguageCode(String languageCode) => this.languageCode == languageCode;
91 |
92 | /// Returns true if the current locale matches the given script code.
93 | bool isScriptCode(String scriptCode) => this.scriptCode == scriptCode;
94 |
95 | /// Returns true if the current locale matches the given country code.
96 | bool isCountryCode(String? countryCode) => this.countryCode == countryCode;
97 |
98 | /// Helper for RTL-aware logical start position.
99 | /// Returns 1.0 for RTL and 0.0 for LTR.
100 | double get logicalStart => isRTL ? 1.0 : 0.0;
101 |
102 | /// Helper for RTL-aware logical end position.
103 | /// Returns 0.0 for RTL and 1.0 for LTR.
104 | double get logicalEnd => isRTL ? 0.0 : 1.0;
105 |
106 | /// Returns an RTL-aware alignment for logical start position.
107 | AlignmentGeometry get logicalStartAlignment =>
108 | isRTL ? AlignmentDirectional.centerEnd : AlignmentDirectional.centerStart;
109 |
110 | /// Returns an RTL-aware alignment for logical end position.
111 | AlignmentGeometry get logicalEndAlignment =>
112 | isRTL ? AlignmentDirectional.centerStart : AlignmentDirectional.centerEnd;
113 |
114 | /// Creates RTL-aware directional padding.
115 | ///
116 | /// Example:
117 | /// ```dart
118 | /// Container(
119 | /// padding: context.logicalPadding(start: 16, end: 8),
120 | /// child: Text('Hello'),
121 | /// )
122 | /// ```
123 | EdgeInsetsGeometry logicalPadding({
124 | double start = 0.0,
125 | double end = 0.0,
126 | double top = 0.0,
127 | double bottom = 0.0,
128 | }) =>
129 | EdgeInsetsDirectional.fromSTEB(start, top, end, bottom);
130 |
131 | /// Creates RTL-aware directional margin.
132 | EdgeInsetsGeometry logicalMargin({
133 | double start = 0.0,
134 | double end = 0.0,
135 | double top = 0.0,
136 | double bottom = 0.0,
137 | }) =>
138 | EdgeInsetsDirectional.fromSTEB(start, top, end, bottom);
139 |
140 | /// Common language checks
141 | bool get isArabic => languageCode == 'ar';
142 |
143 | bool get isEnglish => languageCode == 'en';
144 |
145 | bool get isPersian => languageCode == 'fa';
146 |
147 | bool get isHebrew => languageCode == 'he';
148 |
149 | bool get isUrdu => languageCode == 'ur';
150 |
151 | /// Returns true if the current language is typically written RTL.
152 | bool get isRTLLanguage => isArabic || isPersian || isHebrew || isUrdu;
153 |
154 | /// Returns a direction-aware translation offset.
155 | ///
156 | /// Useful for animations and positioning that need to respect text direction.
157 | Offset directionAwareOffset(double x, double y) =>
158 | Offset(x * directionality.multiplier, y);
159 |
160 | /// Returns a size adjusted for text direction.
161 | ///
162 | /// Useful when you need to flip dimensions based on text direction.
163 | Size directionAwareSize(double width, double height) =>
164 | isRTL ? Size(height, width) : Size(width, height);
165 | }
166 |
167 | /// Extension for RTL-aware list operations.
168 | extension FHUDirectionalIterable on Iterable {
169 | /// Returns the iterable in logical order based on the given text direction.
170 | ///
171 | /// For RTL, the iterable is reversed.
172 | Iterable inDirection(TextDirection direction) =>
173 | direction.isRTL ? toList().reversed : this;
174 |
175 | /// Returns the iterable in logical order based on the current context's direction.
176 | List inContextDirection(BuildContext context) =>
177 | inDirection(context.directionality).toList();
178 | }
179 |
--------------------------------------------------------------------------------
/lib/src/extensions/flutter_extensions/flutter_extensions.dart:
--------------------------------------------------------------------------------
1 | export 'align.dart';
2 | export 'carousel_controller.dart';
3 | export 'colors/colors.dart';
4 | export 'directionality.dart';
5 | export 'focus_scope_extensions.dart';
6 | export 'future.dart';
7 | export 'list_widget.dart';
8 | export 'media_query_extension.dart';
9 | export 'navigation.dart';
10 | export 'on_numbers.dart';
11 | export 'padding.dart';
12 | export 'platform_extension.dart';
13 | export 'scaffold_messenger_extension.dart';
14 | export 'scroll_extensions.dart';
15 | export 'theme_extension.dart';
16 |
--------------------------------------------------------------------------------
/lib/src/extensions/flutter_extensions/focus_scope_extensions.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | extension FHUFocusScopeExtension on BuildContext {
4 | /// Returns the [FocusNode.nearestScope] of the [Focus] or [FocusScope] that
5 | /// most tightly encloses the given [context].
6 | ///
7 | /// If this node doesn't have a [Focus] or [FocusScope] widget ancestor, then
8 | /// the [FocusManager.rootScope] is returned.
9 | FocusScopeNode get focusScope => FocusScope.of(this);
10 |
11 | /// Removes the focus on this node by moving the primary focus to another node.
12 | ///
13 | /// This method removes focus from a node that has the primary focus, cancels
14 | /// any outstanding requests to focus it, while setting the primary focus to
15 | /// another node according to the `disposition`.
16 | ///
17 | /// It is safe to call regardless of whether this node has ever requested
18 | /// focus or not. If this node doesn't have focus or primary focus, nothing
19 | /// happens.
20 | void unFocus() => focusScope.unfocus();
21 |
22 | /// is commonly used to hide keyboard on onTap/onPress call. Usage could be
23 | /// `onTap: () => context.requestFocus` or `onTap: context.requestFocusCall`.
24 | void requestFocus() => focusScope.requestFocus(FocusNode());
25 |
26 | GestureTapCallback get requestFocusCall =>
27 | () => focusScope.requestFocus(FocusNode());
28 |
29 | /// Whether this node has input focus.
30 | ///
31 | /// A [FocusNode] has focus when it is an ancestor of a node that returns true
32 | /// from [hasPrimaryFocus], or it has the primary focus itself.
33 | bool get hasFocus => focusScope.hasFocus;
34 |
35 | /// Returns true if this node currently has the application-wide input focus.
36 | ///
37 | /// A [FocusNode] has the primary focus when the node is focused in its
38 | /// nearest ancestor [FocusScopeNode] and [hasFocus] is true for all its
39 | /// ancestor nodes, but none of its descendants.
40 | ///
41 | /// This is different from [hasFocus] in that [hasFocus] is true if the node
42 | /// is anywhere in the focus chain, but here the node has to be at the end of
43 | /// the chain to return true.
44 | bool get hasPrimaryFocus => focusScope.hasPrimaryFocus;
45 | }
46 |
--------------------------------------------------------------------------------
/lib/src/extensions/flutter_extensions/future.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | /// Extension on [Future] that provides useful utilities and shortcuts for productivity.
6 | extension FHUFuture on Future {
7 | /// Builds a [FutureBuilder] widget for this [Future].
8 | ///
9 | /// The [builder] function defines how the UI should update based on the [AsyncSnapshot].
10 | /// [initialData] is the initial data used to create the snapshot before the [Future] completes.
11 | Widget builder(
12 | AsyncWidgetBuilder builder, {
13 | T? initialData,
14 | }) =>
15 | FutureBuilder(
16 | future: this,
17 | builder: builder,
18 | initialData: initialData,
19 | );
20 |
21 | /// Transforms the result of the [Future] using the provided [transformer] function.
22 | ///
23 | /// Returns a new [Future] of the transformed result.
24 | Future map(R Function(T value) transformer) {
25 | return then((value) => transformer(value));
26 | }
27 |
28 | /// Builds a widget based on the snapshot state of this [Future] using provided callbacks.
29 | ///
30 | /// - [onSuccess] is called when the [Future] completes successfully with data.
31 | /// - [onError] is called if the [Future] completes with an error.
32 | /// - [onLoading] is displayed while the [Future] is in progress.
33 | Widget buildWidget({
34 | required Widget Function(BuildContext context, T data) onSuccess,
35 | required Widget Function(BuildContext context, Object? error) onError,
36 | Widget Function(BuildContext context)? onLoading,
37 | }) {
38 | return builder(
39 | (context, snapshot) => snapshot.buildWidget(
40 | onSuccess: (data) => onSuccess.call(context, data),
41 | onError: (error) => onError.call(context, error),
42 | onLoading: onLoading == null ? null : () => onLoading.call(context)),
43 | );
44 | }
45 | }
46 |
47 | /// Extension on [ConnectionState] providing utility properties for checking the connection state.
48 | extension FHUConnectionState on ConnectionState {
49 | /// Returns true if the connection state is [ConnectionState.none].
50 | bool get isNone => this == ConnectionState.none;
51 |
52 | /// Returns true if the connection state is [ConnectionState.waiting].
53 | bool get isWaiting => this == ConnectionState.waiting;
54 |
55 | /// Returns true if the connection state is [ConnectionState.active].
56 | bool get isActive => this == ConnectionState.active;
57 |
58 | /// Returns true if the connection state is [ConnectionState.done].
59 | bool get isDone => this == ConnectionState.done;
60 | }
61 |
62 | /// Extension on [AsyncSnapshot] that provides convenient utilities for checking snapshot states.
63 | extension FHUAsyncSnapshot on AsyncSnapshot {
64 | /// Returns true if the snapshot has no connection state.
65 | bool get isNone => connectionState.isNone;
66 |
67 | /// Returns true if the snapshot is currently waiting for data.
68 | bool get isWaiting => connectionState.isWaiting;
69 |
70 | /// Returns true if the snapshot is active (data is actively streaming).
71 | bool get isActive => connectionState.isActive;
72 |
73 | /// Returns true if the snapshot is done receiving data.
74 | bool get isDone => connectionState.isDone;
75 |
76 | /// Returns true if the snapshot has completed successfully with data, either active or done.
77 | bool get isSuccess => hasData && (isDone || isActive);
78 |
79 | /// Returns true if the snapshot has an error and is done receiving data.
80 | bool get hasErrorAndDone => hasError && isDone;
81 |
82 | /// Returns true if the snapshot is either waiting or active.
83 | bool get isWaitingOrActive => isWaiting || isActive;
84 |
85 | /// Provides access to data with a default value if data is not available.
86 | ///
87 | /// - [defaultValue] is returned if the snapshot does not contain data.
88 | T dataOr(T defaultValue) => hasData ? data! : defaultValue;
89 |
90 | /// Transforms the snapshot's data if available using the provided [transform] function.
91 | ///
92 | /// Returns a transformed result of type [R] if data is available, or null otherwise.
93 | R? mapData(R Function(T data) transform) {
94 | return hasData ? transform(data as T) : null;
95 | }
96 |
97 | /// Handles different snapshot states and returns a result based on the current state.
98 | ///
99 | /// - [none]: Called if the snapshot has no connection.
100 | /// - [waiting]: Called while the snapshot is waiting for data.
101 | /// - [active]: Called when the snapshot is active with data.
102 | /// - [done]: Called when the snapshot is done and has data.
103 | /// - [error]: Called if the snapshot has encountered an error.
104 | /// - [orElse]: Optional fallback for unhandled states.
105 | R dataWhen({
106 | required R Function() none,
107 | required R Function() waiting,
108 | required R Function(T data) active,
109 | required R Function(T data) done,
110 | required R Function(Object error) error,
111 | R Function()? orElse,
112 | }) {
113 | if (hasError) return error(this.error!);
114 |
115 | if (isSuccess) {
116 | if (isActive) return active(data as T);
117 | if (isDone) return done(data as T);
118 | }
119 |
120 | if (isWaiting) return waiting();
121 | if (isNone) return none();
122 | if (orElse != null) return orElse();
123 |
124 | return none();
125 | }
126 |
127 | /// Builds a widget based on the snapshot state using provided callbacks.
128 | ///
129 | /// - [onSuccess]: Called when the snapshot has data, in either active or done state.
130 | /// - [onError]: Called if the snapshot has an error.
131 | /// - [onLoading]: Optional, displayed while waiting for data; defaults to a [CircularProgressIndicator] if not provided.
132 | Widget buildWidget({
133 | required Widget Function(T data) onSuccess,
134 | required Widget Function(Object? error) onError,
135 | Widget Function()? onLoading,
136 | }) {
137 | if (hasError) return onError(error);
138 | if (hasData && (isActive || isDone)) onSuccess.call(data as T);
139 | return onLoading?.call() ??
140 | const Center(child: CircularProgressIndicator());
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/lib/src/extensions/flutter_extensions/list_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/gestures.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | extension FHUListExtensions on List {
5 | Widget toRow({
6 | Key? key,
7 | MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
8 | MainAxisSize mainAxisSize = MainAxisSize.max,
9 | CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
10 | TextDirection? textDirection,
11 | VerticalDirection verticalDirection = VerticalDirection.down,
12 | TextBaseline? textBaseline,
13 | }) =>
14 | Row(
15 | key: key,
16 | mainAxisAlignment: mainAxisAlignment,
17 | mainAxisSize: mainAxisSize,
18 | crossAxisAlignment: crossAxisAlignment,
19 | textDirection: textDirection,
20 | verticalDirection: verticalDirection,
21 | textBaseline: textBaseline,
22 | children: this,
23 | );
24 |
25 | Widget toStack({
26 | Key? key,
27 | AlignmentGeometry alignment = AlignmentDirectional.topStart,
28 | TextDirection? textDirection,
29 | StackFit fit = StackFit.loose,
30 | Clip clip = Clip.hardEdge,
31 | }) =>
32 | Stack(
33 | key: key,
34 | alignment: alignment,
35 | textDirection: textDirection,
36 | fit: fit,
37 | clipBehavior: clip,
38 | children: this,
39 | );
40 |
41 | Widget toColumn({
42 | Key? key,
43 | MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
44 | MainAxisSize mainAxisSize = MainAxisSize.max,
45 | CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
46 | TextDirection? textDirection,
47 | VerticalDirection verticalDirection = VerticalDirection.down,
48 | TextBaseline? textBaseline,
49 | }) =>
50 | Column(
51 | key: key,
52 | mainAxisAlignment: mainAxisAlignment,
53 | mainAxisSize: mainAxisSize,
54 | crossAxisAlignment: crossAxisAlignment,
55 | textDirection: textDirection,
56 | verticalDirection: verticalDirection,
57 | textBaseline: textBaseline,
58 | children: this,
59 | );
60 |
61 | Widget toList({
62 | Key? key,
63 | Axis scrollDirection = Axis.vertical,
64 | bool reverse = false,
65 | ScrollController? controller,
66 | bool? primary,
67 | ScrollPhysics? physics,
68 | bool shrinkWrap = false,
69 | EdgeInsetsGeometry? padding,
70 | double? itemExtent,
71 | Widget? prototypeItem,
72 | double? cacheExtent,
73 | DragStartBehavior dragStartBehavior = DragStartBehavior.start,
74 | ScrollViewKeyboardDismissBehavior keyboardDismissBehavior =
75 | ScrollViewKeyboardDismissBehavior.manual,
76 | String? restorationId,
77 | Clip clipBehavior = Clip.hardEdge,
78 | bool addAutomaticKeepAlives = true,
79 | bool addRepaintBoundaries = true,
80 | bool addSemanticIndexes = true,
81 | int? semanticChildCount,
82 | }) =>
83 | ListView(
84 | key: key,
85 | scrollDirection: scrollDirection,
86 | reverse: reverse,
87 | controller: controller,
88 | primary: primary,
89 | physics: physics,
90 | shrinkWrap: shrinkWrap,
91 | padding: padding,
92 | itemExtent: itemExtent,
93 | prototypeItem: prototypeItem,
94 | cacheExtent: cacheExtent,
95 | dragStartBehavior: dragStartBehavior,
96 | keyboardDismissBehavior: keyboardDismissBehavior,
97 | restorationId: restorationId,
98 | clipBehavior: clipBehavior,
99 | addAutomaticKeepAlives: addAutomaticKeepAlives,
100 | addRepaintBoundaries: addRepaintBoundaries,
101 | addSemanticIndexes: addSemanticIndexes,
102 | semanticChildCount: semanticChildCount,
103 | children: this,
104 | );
105 |
106 | Widget toListView({
107 | required NullableIndexedWidgetBuilder itemBuilder,
108 | Key? key,
109 | Axis scrollDirection = Axis.vertical,
110 | bool reverse = false,
111 | ScrollController? controller,
112 | bool? primary,
113 | ScrollPhysics? physics,
114 | bool shrinkWrap = false,
115 | EdgeInsetsGeometry? padding,
116 | double? itemExtent,
117 | Widget? prototypeItem,
118 | double? cacheExtent,
119 | DragStartBehavior dragStartBehavior = DragStartBehavior.start,
120 | ScrollViewKeyboardDismissBehavior keyboardDismissBehavior =
121 | ScrollViewKeyboardDismissBehavior.manual,
122 | String? restorationId,
123 | Clip clipBehavior = Clip.hardEdge,
124 | bool addAutomaticKeepAlives = true,
125 | bool addRepaintBoundaries = true,
126 | bool addSemanticIndexes = true,
127 | int? semanticChildCount,
128 | ChildIndexGetter? findChildIndexCallback,
129 | int? itemCount,
130 | }) =>
131 | ListView.builder(
132 | key: key,
133 | scrollDirection: scrollDirection,
134 | reverse: reverse,
135 | controller: controller,
136 | primary: primary,
137 | physics: physics,
138 | shrinkWrap: shrinkWrap,
139 | padding: padding,
140 | itemExtent: itemExtent,
141 | prototypeItem: prototypeItem,
142 | cacheExtent: cacheExtent,
143 | dragStartBehavior: dragStartBehavior,
144 | keyboardDismissBehavior: keyboardDismissBehavior,
145 | restorationId: restorationId,
146 | clipBehavior: clipBehavior,
147 | addAutomaticKeepAlives: addAutomaticKeepAlives,
148 | addRepaintBoundaries: addRepaintBoundaries,
149 | addSemanticIndexes: addSemanticIndexes,
150 | semanticChildCount: semanticChildCount,
151 | findChildIndexCallback: findChildIndexCallback,
152 | itemCount: itemCount ?? length,
153 | itemBuilder: itemBuilder,
154 | );
155 | }
156 |
--------------------------------------------------------------------------------
/lib/src/extensions/flutter_extensions/padding.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | extension FHUPaddingExtensions on Widget {
4 | Padding paddingAll(double value, {Key? key}) {
5 | return Padding(
6 | key: key,
7 | padding: EdgeInsets.all(value),
8 | child: this,
9 | );
10 | }
11 |
12 | Padding paddingLTRB(
13 | double left,
14 | double top,
15 | double right,
16 | double bottom, {
17 | Key? key,
18 | }) =>
19 | Padding(
20 | key: key,
21 | padding: EdgeInsets.fromLTRB(left, top, right, bottom),
22 | child: this,
23 | );
24 |
25 | Padding paddingSymmetric({
26 | Key? key,
27 | double v = 0.0,
28 | double h = 0.0,
29 | }) =>
30 | Padding(
31 | key: key,
32 | padding: EdgeInsets.symmetric(
33 | vertical: v,
34 | horizontal: h,
35 | ),
36 | child: this,
37 | );
38 |
39 | Padding paddingOnly({
40 | Key? key,
41 | double left = 0.0,
42 | double right = 0.0,
43 | double top = 0.0,
44 | double bottom = 0.0,
45 | }) =>
46 | Padding(
47 | key: key,
48 | padding:
49 | EdgeInsets.only(left: left, right: right, top: top, bottom: bottom),
50 | child: this,
51 | );
52 | }
53 |
54 | EdgeInsets edgeInsetsFlexible({
55 | double? all,
56 | double? horizontal,
57 | double? vertical,
58 | double? top,
59 | double? bottom,
60 | double? left,
61 | double? right,
62 | }) {
63 | // Priority:
64 | // 1. 'all'
65 | // 2. Symmetrical values (if applicable)
66 | // 3. Individual values (with fallbacks to 0 if not provided)
67 |
68 | if (all != null) {
69 | return EdgeInsets.all(all);
70 | }
71 |
72 | if (horizontal != null || vertical != null) {
73 | return EdgeInsets.symmetric(
74 | horizontal: horizontal ?? 0.0,
75 | vertical: vertical ?? 0.0,
76 | );
77 | }
78 |
79 | // If no symmetrical values, use individual ones
80 | return EdgeInsets.fromLTRB(
81 | left ?? 0.0,
82 | top ?? 0.0,
83 | right ?? 0.0,
84 | bottom ?? 0.0,
85 | );
86 | }
87 |
--------------------------------------------------------------------------------
/lib/src/extensions/flutter_extensions/scaffold_messenger_extension.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | extension FHUScaffoldMessengerExtension on BuildContext {
4 | /// The state from the closest instance of this class that encloses the given
5 | /// context.
6 | ScaffoldMessengerState get scaffoldMessenger => ScaffoldMessenger.of(this);
7 |
8 | /// Shows a [MaterialBanner] across all registered [Scaffold]s. Scaffolds register
9 | /// to receive material banners from their closest [ScaffoldMessenger] ancestor.
10 | /// If there are several registered scaffolds the material banner is shown
11 | /// simultaneously on all of them.
12 | ScaffoldFeatureController
13 | showMaterialBanner(MaterialBanner materialBanner) =>
14 | scaffoldMessenger.showMaterialBanner(materialBanner);
15 |
16 | /// Shows a [SnackBar] across all registered [Scaffold]s. Scaffolds register
17 | /// to receive snack bars from their closest [ScaffoldMessenger] ancestor.
18 | /// If there are several registered scaffolds the snack bar is shown
19 | /// simultaneously on all of them.
20 | ScaffoldFeatureController showSnackBar(
21 | SnackBar snackBar,
22 | ) =>
23 | scaffoldMessenger.showSnackBar(snackBar);
24 |
25 | /// Removes the current [MaterialBanner] by running its normal exit animation.
26 | ///
27 | /// The closed completer is called after the animation is complete.
28 | void hideCurrentMaterialBanner() =>
29 | scaffoldMessenger.hideCurrentMaterialBanner();
30 |
31 | /// Removes the current [SnackBar] by running its normal exit animation.
32 | ///
33 | /// The closed completer is called after the animation is complete.
34 | void hideCurrentSnackBar() => scaffoldMessenger.hideCurrentSnackBar();
35 |
36 | /// Removes the current [MaterialBanner] (if any) immediately from registered
37 | /// [Scaffold]s.
38 | ///
39 | /// The removed material banner does not run its normal exit animation. If there are
40 | /// any queued material banners, they begin their entrance animation immediately.
41 | void removeCurrentMaterialBanner() =>
42 | scaffoldMessenger.removeCurrentMaterialBanner();
43 |
44 | /// Removes the current [SnackBar] (if any) immediately from registered
45 | /// [Scaffold]s.
46 | ///
47 | /// The removed snack bar does not run its normal exit animation. If there are
48 | /// any queued snack bars, they begin their entrance animation immediately.
49 | void removeCurrentSnackBar() => scaffoldMessenger.removeCurrentSnackBar();
50 |
51 | /// Removes all the [MaterialBanner]s currently in queue by clearing the queue
52 | /// and running normal exit animation on the current [MaterialBanner].
53 | void clearMaterialBanners() => scaffoldMessenger.clearMaterialBanners();
54 |
55 | /// Removes all the snackBars currently in queue by clearing the queue
56 | /// and running normal exit animation on the current snackBar.
57 | void clearSnackBars() => scaffoldMessenger.clearSnackBars();
58 | }
59 |
--------------------------------------------------------------------------------
/lib/src/extensions/num_extensions.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | extension FHUIntExtensions on int {
4 | /// Construct a color from the lower 32 bits of an [int].
5 | ///
6 | /// The bits are interpreted as follows:
7 | ///
8 | /// * Bits 24-31 are the alpha value.
9 | /// * Bits 16-23 are the red value.
10 | /// * Bits 8-15 are the green value.
11 | /// * Bits 0-7 are the blue value.
12 | ///
13 | /// In other words, if AA is the alpha value in hex, RR the red value in hex,
14 | /// GG the green value in hex, and BB the blue value in hex, a color can be
15 | /// expressed as `const Color(0xAARRGGBB)`.
16 | ///
17 | /// For example, to get a fully opaque orange, you would use `const
18 | /// Color(0xFFFF9000)` (`FF` for the alpha, `FF` for the red, `90` for the
19 | /// green, and `00` for the blue).
20 | Color get color => Color(this);
21 | }
22 |
--------------------------------------------------------------------------------
/lib/src/extensions/string_extensions/general_string_extensions.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | extension FHUNullSafeStringExtensions on String? {
4 | // all string extensions could be found in the https://
5 | // String get withoutWhiteSpaces => isEmptyOrNull ? '' : this!.replaceAll(RegExp(r'\s+\b|\b\s'), '');
6 | Size get textSize {
7 | final textPainter = TextPainter(
8 | text: TextSpan(text: this),
9 | maxLines: 1,
10 | )..layout();
11 | return textPainter.size;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lib/src/extensions/string_extensions/string_extensions.dart:
--------------------------------------------------------------------------------
1 | export 'general_string_extensions.dart';
2 |
--------------------------------------------------------------------------------
/lib/src/platform_env/platform_env.dart:
--------------------------------------------------------------------------------
1 | export 'platform_env_io.dart' if (dart.library.html) 'platform_env_web.dart';
2 |
--------------------------------------------------------------------------------
/lib/src/platform_env/platform_env_io.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/foundation.dart';
4 |
5 | /// A platform-independent class providing information about the operating system,
6 | /// with web compatibility considerations.
7 | abstract class PlatformEnv {
8 | /// Returns the `TargetPlatform` corresponding to the current operating system.
9 | static TargetPlatform get targetPlatform {
10 | switch (operatingSystem) {
11 | case 'android':
12 | return TargetPlatform.android;
13 | case 'fuchsia':
14 | return TargetPlatform.fuchsia;
15 | case 'ios':
16 | return TargetPlatform.iOS;
17 | case 'linux':
18 | return TargetPlatform.linux;
19 | case 'macos':
20 | return TargetPlatform.macOS;
21 | case 'windows':
22 | return TargetPlatform.windows;
23 | default:
24 | return defaultTargetPlatform;
25 | }
26 | }
27 |
28 | /// Returns `true` if the current platform is Linux.
29 | static bool get isLinux => Platform.isLinux;
30 |
31 | /// Returns `true` if the current platform is macOS.
32 | static bool get isMacOS => Platform.isMacOS;
33 |
34 | /// Returns `true` if the current platform is Windows.
35 | static bool get isWindows => Platform.isWindows;
36 |
37 | /// Returns `true` if the current platform is Android.
38 | static bool get isAndroid => Platform.isAndroid;
39 |
40 | /// Returns `true` if the current platform is iOS.
41 | static bool get isIOS => Platform.isIOS;
42 |
43 | /// Returns `true` if the current platform is not web.
44 | static bool get isWeb => false;
45 |
46 | /// Returns `true` if the current platform is Fuchsia.
47 | static bool get isFuchsia => Platform.isFuchsia;
48 |
49 | /// Returns the name of the operating system.
50 | static String get operatingSystem => Platform.operatingSystem;
51 |
52 | /// Returns the version of the operating system.
53 | static String get operatingSystemVersion => Platform.operatingSystemVersion;
54 |
55 | /// Returns the number of processors available to the Dart VM.
56 | static int get numberOfProcessors => Platform.numberOfProcessors;
57 |
58 | /// Returns the path separator used by the operating system.
59 | static String get pathSeparator => Platform.pathSeparator;
60 |
61 | /// Returns the local hostname for the system.
62 | static String get localHostname => Platform.localHostname;
63 |
64 | /// Returns the version of the current Dart runtime.
65 | static String get version => Platform.version;
66 |
67 | /// Returns the name of the current locale.
68 | static String get localeName => Platform.localeName;
69 |
70 | /// Returns the environment for this process as a map.
71 | static Map get environment => Platform.environment;
72 |
73 | /// Returns the path of the executable used to run the script in this isolate.
74 | static String get executable => Platform.executable;
75 |
76 | /// Returns the path of the executable used to run the script in this isolate after it has been resolved by the OS.
77 | static String get resolvedExecutable => Platform.resolvedExecutable;
78 |
79 | /// Returns the absolute URI of the script being run in this isolate.
80 | static Uri get script => Platform.script;
81 |
82 | /// Returns the flags passed to the executable used to run the script in this isolate.
83 | static List get executableArguments => Platform.executableArguments;
84 |
85 | /// Returns the `--packages` flag passed to the executable used to run the script in this isolate, or `null` if no such flag was provided.
86 | static String? get packageConfig => Platform.packageConfig;
87 |
88 | /// Returns the system's default line terminator.
89 | static String get lineTerminator => Platform.isWindows ? '\r\n' : '\n';
90 |
91 | static Map report() => {
92 | 'targetPlatform': targetPlatform.name,
93 | 'isLinux': '$isLinux',
94 | 'isMacOS': '$isMacOS',
95 | 'isWindows': '$isWindows',
96 | 'isAndroid': '$isAndroid',
97 | 'isIOS': '$isIOS',
98 | 'isWeb': '$isWeb',
99 | 'isFuchsia': '$isFuchsia',
100 | 'operatingSystem': operatingSystem,
101 | 'operatingSystemVersion': operatingSystemVersion,
102 | 'numberOfProcessors': '$numberOfProcessors',
103 | 'pathSeparator': pathSeparator,
104 | 'localHostname': localHostname,
105 | 'version': version,
106 | 'localeName': localeName,
107 | ...environment,
108 | 'executable': executable,
109 | 'resolvedExecutable': resolvedExecutable,
110 | 'script': '$script',
111 | 'executableArguments': '$executableArguments',
112 | 'packageConfig': '$packageConfig',
113 | 'lineTerminator': lineTerminator,
114 | };
115 | }
116 |
--------------------------------------------------------------------------------
/lib/src/platform_env/platform_env_web.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 |
3 | /// A platform-independent class providing information about the operating system,
4 | /// with web compatibility considerations.
5 | abstract class PlatformEnv {
6 | /// Returns the `TargetPlatform` corresponding to the current operating system.
7 | static TargetPlatform get targetPlatform => defaultTargetPlatform;
8 |
9 | /// Returns `false` since the current platform is not Linux.
10 | static bool get isLinux => false;
11 |
12 | /// Returns `false` since the current platform is not macOS.
13 | static bool get isMacOS => false;
14 |
15 | /// Returns `false` since the current platform is not Windows.
16 | static bool get isWindows => false;
17 |
18 | /// Returns `false` since the current platform is not Android.
19 | static bool get isAndroid => false;
20 |
21 | /// Returns `false` since the current platform is not iOS.
22 | static bool get isIOS => false;
23 |
24 | /// Returns `true` since the current platform is web.
25 | static bool get isWeb => true;
26 |
27 | /// Returns `false` since the current platform is not Fuchsia.
28 | static bool get isFuchsia => false;
29 |
30 | /// Returns the string 'web' as the operating system.
31 | static String get operatingSystem => 'web';
32 |
33 | /// Returns 'N/A' as the operating system version on web platforms.
34 | static String get operatingSystemVersion => 'N/A';
35 |
36 | /// Returns `0` since the number of processors is not available on web platforms.
37 | static int get numberOfProcessors => 0;
38 |
39 | /// Returns `/` as the path separator on web platforms.
40 | static String get pathSeparator => '/';
41 |
42 | /// Returns 'localhost' as the local hostname on web platforms.
43 | static String get localHostname => 'localhost';
44 |
45 | /// Returns 'N/A' as the version of the current Dart runtime on web platforms.
46 | static String get version => 'N/A';
47 |
48 | /// Returns 'en' as the default locale name on web platforms.
49 | static String get localeName => 'en';
50 |
51 | /// Returns an empty map since environment variables are not available on web platforms.
52 | static Map get environment => {};
53 |
54 | /// Returns 'N/A' as the executable path on web platforms.
55 | static String get executable => 'N/A';
56 |
57 | /// Returns 'N/A' as the resolved executable path on web platforms.
58 | static String get resolvedExecutable => 'N/A';
59 |
60 | /// Returns an empty URI as the script URI on web platforms.
61 | static Uri get script => Uri();
62 |
63 | /// Returns an empty list since no executable arguments are available on web platforms.
64 | static List get executableArguments => [];
65 |
66 | /// Returns `null` since the `--packages` flag is not applicable on web platforms.
67 | static String? get packageConfig => null;
68 |
69 | /// Returns `'\n'` as the system's default line terminator on web platforms.
70 | static String get lineTerminator => '\n';
71 |
72 | static Map report() => {
73 | 'targetPlatform': targetPlatform.name,
74 | 'operatingSystem': operatingSystem,
75 | 'operatingSystemVersion': operatingSystemVersion,
76 | 'numberOfProcessors': '$numberOfProcessors',
77 | 'pathSeparator': pathSeparator,
78 | 'localHostname': localHostname,
79 | 'version': version,
80 | 'localeName': localeName,
81 | ...environment,
82 | 'executable': executable,
83 | 'resolvedExecutable': resolvedExecutable,
84 | 'script': '$script',
85 | 'executableArguments': '$executableArguments',
86 | 'packageConfig': '$packageConfig',
87 | 'lineTerminator': lineTerminator,
88 | };
89 | }
90 |
--------------------------------------------------------------------------------
/lib/src/src.dart:
--------------------------------------------------------------------------------
1 | export 'package:dart_helper_utils/dart_helper_utils.dart';
2 |
3 | export 'extensions/extensions.dart';
4 | export 'platform_env/platform_env.dart';
5 | export 'value_notifier/value_notifier.dart';
6 | export 'widgets/widgets.dart';
7 |
--------------------------------------------------------------------------------
/lib/src/value_notifier/extensions/extensions.dart:
--------------------------------------------------------------------------------
1 | export 'listenable_extensions.dart';
2 | export 'notifier_extensions.dart';
3 | export 'stream_to_notifier.dart';
4 | export 'value_notifier_extensions.dart';
5 |
--------------------------------------------------------------------------------
/lib/src/value_notifier/extensions/listenable_extensions.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_helper_utils/flutter_helper_utils.dart';
4 |
5 | /// Extension on [Listenable] to integrate with [ListenableBuilder].
6 | ///
7 | /// Provides a convenient method to create a [ListenableBuilder] that listens to the [Listenable].
8 | /// This extension simplifies reacting to changes in the [Listenable] within the UI.
9 | extension FHUListenableExtension on Listenable {
10 | /// Creates a [ListenableBuilder] widget that listens to this [Listenable].
11 | ///
12 | /// The [builder] function is called whenever this [Listenable] changes, allowing the UI to react to these changes.
13 | ///
14 | /// Example:
15 | /// ```dart
16 | /// final myNotifier = ValueNotifier(0);
17 | /// myNotifier.builder(
18 | /// (context) => Text('Value is ${myNotifier.value}'),
19 | /// );
20 | /// // The Text widget will update whenever [myNotifier] changes.
21 | /// ```
22 | Widget builder(Widget Function(BuildContext context) builder) {
23 | return ListenableBuilder(
24 | listenable: this,
25 | builder: (context, child) => builder(context),
26 | );
27 | }
28 | }
29 |
30 | /// Extension on a list of [Listenable] objects to integrate with [ListenablesBuilder].
31 | ///
32 | /// Facilitates the creation of a [ListenablesBuilder] widget that listens to multiple [Listenable] instances.
33 | /// Ideal for scenarios where the UI needs to respond to changes in multiple listenable sources.
34 | extension FHUListenablesExtension on List {
35 | /// Creates a [ListenablesBuilder] widget that listens to this list of [Listenable] objects.
36 | ///
37 | /// The [builder] function is called whenever any of the [Listenable] objects in this list change,
38 | /// allowing the UI to react to these changes. Optional parameters [buildWhen] and [threshold]
39 | /// can be used to control when the builder is called.
40 | ///
41 | /// Example:
42 | /// ```dart
43 | /// final textController = TextEditingController();
44 | /// final scrollController = ScrollController();
45 | /// final myNotifier = ValueNotifier(0);
46 | /// final myListeners = [textController, scrollController, myNotifier];
47 | /// myListeners.builder(
48 | /// (context) => Text('Value is ${myNotifier.value}'),
49 | /// );
50 | /// // The Text widget will update whenever any of myListeners change.
51 | /// ```
52 | Widget builder(
53 | Widget Function(BuildContext context) builder, {
54 | bool Function()? buildWhen,
55 | Duration? threshold,
56 | }) {
57 | return ListenablesBuilder(
58 | listenables: this,
59 | buildWhen: buildWhen,
60 | threshold: threshold,
61 | builder: builder,
62 | );
63 | }
64 | }
65 |
66 | /// Extension on [ValueListenable] to seamlessly create a [ValueListenableBuilder] widget.
67 | ///
68 | /// Simplifies the instantiation of [ValueListenableBuilder], allowing for direct UI updates in response to [ValueListenable] changes.
69 | /// Enhances code readability and efficiency by reducing boilerplate.
70 | extension FHUValueListenableExtension on ValueListenable {
71 | /// Creates a [ValueListenableBuilder] widget that listens to this [ValueListenable].
72 | ///
73 | /// The [builder] function is called with the current value of the [ValueListenable] whenever it changes,
74 | /// allowing the UI to react to these changes.
75 | ///
76 | /// Example:
77 | /// ```dart
78 | /// final myNotifier = ValueNotifier(0);
79 | /// myNotifier.builder(
80 | /// (value) => Text('Value is $value'),
81 | /// );
82 | /// // The Text widget will update whenever [myNotifier] changes.
83 | /// ```
84 | Widget builder(
85 | Widget Function(T value) builder, {
86 | Key? key,
87 | }) {
88 | return ValueListenableBuilder(
89 | valueListenable: this,
90 | key: key,
91 | builder: (_, value, __) => builder(value),
92 | );
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/lib/src/value_notifier/extensions/notifier_extensions.dart:
--------------------------------------------------------------------------------
1 | import 'package:dart_helper_utils/dart_helper_utils.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_helper_utils/src/value_notifier/notifier_classes/notifier_classes.dart';
4 |
5 | /// Extension on any non-nullable [Object].
6 | ///
7 | /// Allows you to directly create a [ValueNotifier] instance from the object.
8 | ///
9 | /// Example:
10 | /// ```dart
11 | /// // Creates ValueNotifier(User()) where User is your custom type/class.
12 | /// final userNotifier = User().notifier;
13 | /// ```
14 | extension FHUValueNotifierExtension on T {
15 | /// Creates a [ValueNotifier] for the current instance.
16 | ValueNotifier get notifier => ValueNotifier(this);
17 | }
18 |
19 | /// Extension on `bool` to provide easy access to creating a [ValueNotifier] for boolean values.
20 | extension FHUBoolNotifierEx on bool {
21 | /// Creates a [BoolNotifier] instance from the current `bool` value.
22 | BoolNotifier get notifier => BoolNotifier(this);
23 | }
24 |
25 | /// Extension on `num` to provide easy access to creating a [ValueNotifier] for numeric types.
26 | extension FHUNumNotifierEx on num {
27 | /// Creates a [NumNotifier] instance from the current `num` value.
28 | NumNotifier get notifier => NumNotifier(this);
29 | }
30 |
31 | /// Extension on `double` to provide easy access to creating a [ValueNotifier] for double values.
32 | extension FHUDoubleNotifierEx on double {
33 | /// Creates a [DoubleNotifier] instance from the current `double` value.
34 | DoubleNotifier get notifier => DoubleNotifier(this);
35 | }
36 |
37 | /// Extension on `int` to provide easy access to creating a [ValueNotifier] for integer values.
38 | extension FHUIntNotifierEx on int {
39 | /// Creates an [IntNotifier] instance from the current `int` value.
40 | IntNotifier get notifier => IntNotifier(this);
41 | }
42 |
43 | /// Extension on `DateTime` to provide easy access to creating a [ValueNotifier] for `DateTime` objects.
44 | extension FHUDateTimeNotifierEx on DateTime {
45 | /// Creates a [DateTimeNotifier] instance from the current `DateTime` value.
46 | DateTimeNotifier get notifier => DateTimeNotifier(this);
47 | }
48 |
49 | /// Extension on `String` to provide easy access to creating a [ValueNotifier] for `String` values.
50 | extension FHUStringNotifierEx on String {
51 | /// Creates a [StringNotifier] instance from the current `String` value.
52 | StringNotifier get notifier => StringNotifier(this);
53 | }
54 |
55 | /// Extension on `Color` to provide easy access to creating a [ValueNotifier] for `Color` objects.
56 | extension FHUColorNotifierEx on Color {
57 | /// Creates a [ColorNotifier] instance from the current `Color` value.
58 | ColorNotifier get notifier => ColorNotifier(this);
59 | }
60 |
61 | /// Extension on `Uri` to provide easy access to creating a [ValueNotifier] for `Uri` objects.
62 | extension FHUUriNotifierEx on Uri {
63 | /// Creates a [UriNotifier] instance from the current `Uri` value.
64 | UriNotifier get notifier => UriNotifier(this);
65 | }
66 |
67 | /// Extension on `ThemeMode` to provide easy access to creating a [ValueNotifier] for `ThemeMode`.
68 | extension FHUThemeModeNotifierEx on ThemeMode {
69 | /// Creates a [ThemeModeNotifier] instance from the current `ThemeMode` value.
70 | ThemeModeNotifier get notifier => ThemeModeNotifier(this);
71 | }
72 |
73 | /// Extension on `Brightness` to provide easy access to creating a [ValueNotifier] for `Brightness`.
74 | extension FHUBrightnessNotifierEx on Brightness {
75 | /// Creates a [BrightnessNotifier] instance from the current `Brightness` value.
76 | BrightnessNotifier get notifier => BrightnessNotifier(this);
77 | }
78 |
79 | /// Extension on `Iterable` to provide easy access to creating various [ValueNotifier] instances.
80 | ///
81 | /// - [ListNotifier] for lists.
82 | /// - [SetNotifier] for sets.
83 | /// - [DoublyLinkedListNotifier] for doubly linked lists.
84 | extension FHUIterableNotifierEx on Iterable {
85 | /// Creates a [ListNotifier] instance from the current `Iterable`.
86 | ListNotifier get listNotifier => ListNotifier.from(this);
87 |
88 | /// Creates a [SetNotifier] instance from the current `Iterable`.
89 | SetNotifier get setNotifier => SetNotifier.from(this);
90 |
91 | /// Creates a [DoublyLinkedListNotifier] instance from the current `Iterable`.
92 | DoublyLinkedListNotifier get doublyLinkedListNotifier =>
93 | DoublyLinkedListNotifier.from(this);
94 | }
95 |
96 | /// Extension on `List` to provide easy access to creating a [ValueNotifier] for lists.
97 | extension FHUListNotifierEx on List {
98 | /// Creates a [ListNotifier] instance from the current `List`.
99 | ListNotifier get notifier => ListNotifier(this);
100 | }
101 |
102 | /// Extension on `DoublyLinkedList` to provide easy access to creating a [ValueNotifier] for doubly linked lists.
103 | ///
104 | /// [DoublyLinkedList] is a part of the `dart:collection` library.
105 | extension FHUDoublyLinkedListNotifierEx on DoublyLinkedList {
106 | /// Creates a [DoublyLinkedListNotifier] instance from the current `DoublyLinkedList`.
107 | DoublyLinkedListNotifier get notifier => DoublyLinkedListNotifier(this);
108 | }
109 |
110 | /// Extension on `Set` to provide easy access to creating a [ValueNotifier] for sets.
111 | extension FHUSetNotifierEx on Set {
112 | /// Creates a [SetNotifier] instance from the current `Set`.
113 | SetNotifier get notifier => SetNotifier(this);
114 | }
115 |
116 | /// Extension on `Map` to provide easy access to creating a [ValueNotifier] for maps.
117 | ///
118 | /// Allows creating a [MapNotifier] instance from a `Map`.
119 | extension FHUMapNotifierEx on Map {
120 | /// Creates a [MapNotifier] instance from the current `Map`.
121 | MapNotifier get notifier => MapNotifier(this);
122 | }
123 |
--------------------------------------------------------------------------------
/lib/src/value_notifier/extensions/stream_to_notifier.dart:
--------------------------------------------------------------------------------
1 | import 'dart:developer';
2 |
3 | import 'package:flutter/foundation.dart';
4 |
5 | /// Extension on `Stream` to convert any stream into a `ValueNotifier`.
6 | ///
7 | /// This extension provides a convenient way to bridge the reactive world of streams
8 | /// with the `ValueNotifier` pattern used for state management in Flutter applications. By converting
9 | /// a stream into a `ValueNotifier`, you can easily integrate asynchronous stream data into your
10 | /// Flutter widgets with the reactive and efficient update mechanism that `ValueNotifier` provides.
11 | extension FHUStreamToValueNotifier on Stream {
12 | /// Converts the current stream into a `ValueListenable` which is effectively a `ValueNotifier`.
13 | ///
14 | /// The conversion process involves listening to the stream and updating the `ValueNotifier`'s value
15 | /// each time the stream emits a new item. This allows Flutter widgets to reactively rebuild whenever
16 | /// the `ValueNotifier`'s value changes, based on the latest data emitted by the stream.
17 | ///
18 | /// Parameters:
19 | /// - `initialValue`: The initial value to be used for the `ValueNotifier` before any data is received from the stream.
20 | /// - `onDone`: An optional callback that gets called when the stream is done. The last value received
21 | /// from the stream is passed to this callback.
22 | /// - `onError`: An optional error handler for stream errors. If not provided, a default error handler
23 | /// that logs the error is used.
24 | ///
25 | /// Returns a `ValueListenable` which is a `ValueNotifier` that updates its value based on the stream's emissions.
26 | ValueListenable toValueNotifier(
27 | T initialValue, {
28 | void Function(T)? onDone,
29 | void Function(Object, StackTrace)? onError,
30 | }) {
31 | final notifier = ValueNotifier(initialValue);
32 | listen(
33 | (value) => notifier.value = value,
34 | onError: onError ?? _defaultOnError,
35 | onDone: () => onDone?.call(notifier.value),
36 | );
37 | return notifier;
38 | }
39 |
40 | /// Default error handler that logs any errors coming from the stream.
41 | ///
42 | /// This function is used as the error handler for the stream listener if no custom
43 | /// `onError` function is provided when calling `toValueNotifier`.
44 | ///
45 | /// Parameters:
46 | /// - `error`: The error object emitted by the stream.
47 | /// - `stackTrace`: The stack trace associated with the error.
48 | void _defaultOnError(Object error, StackTrace stackTrace) => log(
49 | 'Error on stream $toString()',
50 | // Log the error with stream identification
51 | error: error,
52 | stackTrace: stackTrace,
53 | );
54 | }
55 |
--------------------------------------------------------------------------------
/lib/src/value_notifier/extensions/value_notifier_extensions.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/foundation.dart';
4 |
5 | extension FHUValueNotifierExtensions on ValueNotifier {
6 | /// Equivalent to the getter [value] but in shorter syntax.
7 | T get v => value;
8 |
9 | set v(T newValue) => value = newValue;
10 | }
11 |
12 | extension FHUValueListenableExtensions on ValueListenable {
13 | /// Registers a callback to be invoked whenever the `ValueNotifier`'s value changes.
14 | VoidCallback onChange(void Function(T value) action) {
15 | void listener() => action(value);
16 | addListener(listener);
17 | return () => removeListener(listener);
18 | }
19 |
20 | /// Registers a debounced callback which is invoked only after the notifier's value
21 | /// is stable for the specified [duration].
22 | VoidCallback debounce(Duration duration, void Function(T value) action) {
23 | Timer? debounceTimer;
24 |
25 | void listener() {
26 | debounceTimer?.cancel();
27 | debounceTimer = Timer(duration, () => action(value));
28 | }
29 |
30 | addListener(listener);
31 |
32 | return () => {
33 | debounceTimer?.cancel(),
34 | removeListener(listener),
35 | };
36 | }
37 |
38 | /// Converts the [ValueNotifier] into a [Stream]. This stream emits values whenever the
39 | /// [value] changes. The use of [distinct] ensures that consecutive duplicate values are
40 | /// filtered out, thus the stream only emits when the value actually changes.
41 | Stream get stream =>
42 | Stream.periodic(Duration.zero, (_) => value).distinct();
43 | }
44 |
--------------------------------------------------------------------------------
/lib/src/value_notifier/notifier_classes/bool_notifier.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter_helper_utils/flutter_helper_utils.dart';
3 |
4 | /// allows to quickly create a ValueNotifier of type bool.
5 | class BoolNotifier extends ValueNotifier {
6 | BoolNotifier(super.initial);
7 |
8 | @override
9 | void notifyListeners() {
10 | try {
11 | super.notifyListeners();
12 | } catch (_) {}
13 | }
14 |
15 | void refresh() => notifyListeners();
16 |
17 | /// similar to value setter but this one force trigger the notifyListeners()
18 | /// event if newValue == value.
19 | void update(bool newValue) {
20 | value = newValue;
21 | refresh();
22 | }
23 | }
24 |
25 | /// BoolValueNotifierExtension
26 | ///
27 | /// Extension on `ValueNotifier` providing additional boolean-specific functionalities.
28 | /// This extension simplifies toggling and other boolean operations directly on
29 | /// the [ValueNotifier] without the need to perform actions in the value itself.
30 | ///
31 | /// Example:
32 | /// ```dart
33 | /// final boolValueNotifier = true.notifier;
34 | /// boolValueNotifier.toggle(); // Toggles the boolean value.
35 | /// ```
36 | extension FHUBoolValueNotifierExtension on ValueNotifier {
37 | /// toggle the value of the [ValueNotifier]
38 | void toggle() => value = !value;
39 |
40 | /// toggle the value of the [ValueNotifier] and run the provided function.
41 | void toggleWithCallback(VoidCallback callback) {
42 | toggle();
43 | callback();
44 | }
45 |
46 | /// toggle after a specific time.
47 | Future delayedToggle(Duration delay) async {
48 | await delay.delayed();
49 | toggle();
50 | }
51 |
52 | /// toggle the value of the ValueNotifier based on a condition.
53 | void conditionalToggle({required bool condition}) {
54 | if (condition) toggle();
55 | }
56 |
57 | /// make the value of the [ValueNotifier] true
58 | void setTrue() => value = true;
59 |
60 | /// make the value of the [ValueNotifier] false
61 | void setFalse() => value = false;
62 |
63 | /// The logical conjunction ("and") of this and [other].
64 | ///
65 | /// Returns `true` if both this and [other] are `true`, and `false` otherwise.
66 | bool operator &(bool other) => value & other;
67 |
68 | /// The logical disjunction ("inclusive or") of this and [other].
69 | ///
70 | /// Returns `true` if either this or [other] is `true`, and `false` otherwise.)
71 | bool operator |(bool other) => value | other;
72 |
73 | /// The logical exclusive disjunction ("exclusive or") of this and [other].
74 | ///
75 | /// Returns whether this and [other] are neither both `true` nor both `false`.
76 | bool operator ^(bool other) => value ^ other;
77 | }
78 |
--------------------------------------------------------------------------------
/lib/src/value_notifier/notifier_classes/color_notifier.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/foundation.dart';
3 | import 'package:flutter_helper_utils/flutter_helper_utils.dart';
4 |
5 | /// allows to quickly create a ValueNotifier of type Color.
6 | class ColorNotifier extends ValueNotifier {
7 | ColorNotifier(super.initial);
8 |
9 | @override
10 | void notifyListeners() {
11 | try {
12 | super.notifyListeners();
13 | } catch (_) {}
14 | }
15 |
16 | void refresh() => notifyListeners();
17 |
18 | /// similar to value setter but this one force trigger the notifyListeners()
19 | /// event if newValue == value.
20 | void update(Color newValue) {
21 | value = newValue;
22 | refresh();
23 | }
24 | }
25 |
26 | /// Extension: ColorValueNotifierExtension
27 | ///
28 | /// Description:
29 | /// Adds convenience methods to `ValueNotifier` for managing color state changes
30 | ///
31 | /// Example:
32 | /// ```dart
33 | /// final colorValueNotifier = Colors.blue.notifier;
34 | /// colorValueNotifier.withOpacity(0.5);
35 | /// ```
36 | extension FHUColorValueNotifierExtension on ValueListenable {
37 | /// The alpha channel of this color in an 8 bit value.
38 | ///
39 | /// A value of 0 means this color is fully transparent. A value of 255 means
40 | /// this color is fully opaque.
41 | double get alpha => value.a;
42 |
43 | /// **Deprecated:** Use [alpha] instead.
44 | ///
45 | /// The alpha channel of this color as a double.
46 | ///
47 | /// A value of 0.0 means this color is fully transparent. A value of 1.0 means
48 | /// this color is fully opaque.
49 | @Deprecated('Use alpha instead. This will be removed in future versions.')
50 | double get opacity => value.a;
51 |
52 | /// The red channel of this color in an 8 bit value.
53 | double get red => value.r;
54 |
55 | /// The green channel of this color in an 8 bit value.
56 | double get green => value.g;
57 |
58 | /// The blue channel of this color in an 8 bit value.
59 | double get blue => value.b;
60 |
61 | /// Returns a new color that matches this color with the alpha channel
62 | /// replaced with `a` (which ranges from 0 to 255).
63 | ///
64 | /// Out of range values will have unexpected effects.
65 | Color withAlpha(int a) => value.withAlpha(a);
66 |
67 | /// Returns a new color that matches this color with the alpha channel
68 | /// replaced with the given `opacity` (which ranges from 0.0 to 1.0).
69 | ///
70 | /// Out of range values will have unexpected effects.
71 | Color withOpacity(double opacity) => value.addOpacity(opacity);
72 |
73 | /// Returns a new color that matches this color with the red channel replaced
74 | /// with `r` (which ranges from 0 to 255).
75 | ///
76 | /// Out of range values will have unexpected effects.
77 | Color withRed(int r) => value.withRed(r);
78 |
79 | /// Returns a new color that matches this color with the green channel
80 | /// replaced with `g` (which ranges from 0 to 255).
81 | ///
82 | /// Out of range values will have unexpected effects.
83 | Color withGreen(int g) => value.withGreen(g);
84 |
85 | /// Returns a new color that matches this color with the blue channel replaced
86 | /// with `b` (which ranges from 0 to 255).
87 | ///
88 | /// Out of range values will have unexpected effects.
89 | Color withBlue(int b) => value.withBlue(b);
90 |
91 | /// Returns a brightness value between 0 for darkest and 1 for lightest.
92 | ///
93 | /// Represents the relative luminance of the color. This value is computationally
94 | /// expensive to calculate.
95 | ///
96 | /// See .
97 | double computeLuminance() => value.computeLuminance();
98 | }
99 |
--------------------------------------------------------------------------------
/lib/src/value_notifier/notifier_classes/duration_notifier.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | /// create a [ValueNotifier] of type [Duration], which reacts just like normal [Duration],
4 | /// but with notifier capabilities.
5 | class DurationNotifier extends ValueNotifier implements Duration {
6 | DurationNotifier(super.initial);
7 |
8 | @override
9 | void notifyListeners() {
10 | try {
11 | super.notifyListeners();
12 | } catch (_) {}
13 | }
14 |
15 | void refresh() => notifyListeners();
16 |
17 | /// similar to value setter but this one force trigger the notifyListeners()
18 | /// event if newValue == value.
19 | void update(Duration newValue) {
20 | value = newValue;
21 | refresh();
22 | }
23 |
24 | /// documentation available in the original overridden method.
25 | @override
26 | Duration operator *(num factor) => value * factor;
27 |
28 | /// documentation available in the original overridden method.
29 | @override
30 | Duration operator +(Duration other) => value + other;
31 |
32 | /// documentation available in the original overridden method.
33 | @override
34 | Duration operator -() => -value;
35 |
36 | /// documentation available in the original overridden method.
37 | @override
38 | Duration operator -(Duration other) => value - other;
39 |
40 | /// documentation available in the original overridden method.
41 | @override
42 | bool operator <(Duration other) => value < other;
43 |
44 | /// documentation available in the original overridden method.
45 | @override
46 | bool operator <=(Duration other) => value <= other;
47 |
48 | /// documentation available in the original overridden method.
49 | @override
50 | bool operator >(Duration other) => value > other;
51 |
52 | /// documentation available in the original overridden method.
53 | @override
54 | bool operator >=(Duration other) => value >= other;
55 |
56 | /// documentation available in the original overridden method.
57 | @override
58 | Duration operator ~/(int quotient) => value ~/ quotient;
59 |
60 | /// documentation available in the original overridden method.
61 | @override
62 | Duration abs() => value.abs();
63 |
64 | /// documentation available in the original overridden method.
65 | @override
66 | int compareTo(Duration other) => value.compareTo(other);
67 |
68 | /// documentation available in the original overridden method.
69 | @override
70 | int get inDays => value.inDays;
71 |
72 | /// documentation available in the original overridden method.
73 | @override
74 | int get inHours => value.inHours;
75 |
76 | /// documentation available in the original overridden method.
77 | @override
78 | int get inMicroseconds => value.inMicroseconds;
79 |
80 | /// documentation available in the original overridden method.
81 | @override
82 | int get inMilliseconds => value.inMilliseconds;
83 |
84 | /// documentation available in the original overridden method.
85 | @override
86 | int get inMinutes => value.inMinutes;
87 |
88 | /// documentation available in the original overridden method.
89 | @override
90 | int get inSeconds => value.inSeconds;
91 |
92 | /// documentation available in the original overridden method.
93 | @override
94 | bool get isNegative => value.isNegative;
95 | }
96 |
--------------------------------------------------------------------------------
/lib/src/value_notifier/notifier_classes/notifier_classes.dart:
--------------------------------------------------------------------------------
1 | export 'bool_notifier.dart';
2 | export 'color_notifier.dart';
3 | export 'date_notifier.dart';
4 | export 'double_notifier.dart';
5 | export 'doubly_linked_list_notifier.dart';
6 | export 'duration_notifier.dart';
7 | export 'int_notifier.dart';
8 | export 'list_notifier.dart';
9 | export 'map_notifier.dart';
10 | export 'num_notifier.dart';
11 | export 'set_notifier.dart';
12 | export 'string_notifier.dart';
13 | export 'theme_mode_notifier.dart';
14 | export 'uri_notifier.dart';
15 |
--------------------------------------------------------------------------------
/lib/src/value_notifier/notifier_classes/theme_mode_notifier.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_helper_utils/flutter_helper_utils.dart';
3 |
4 | class ThemeModeNotifier extends ValueNotifier {
5 | ThemeModeNotifier(super.value);
6 |
7 | @override
8 | void notifyListeners() {
9 | try {
10 | super.notifyListeners();
11 | } catch (_) {}
12 | }
13 |
14 | void refresh() => notifyListeners();
15 |
16 | /// similar to value setter but this one force trigger the notifyListeners()
17 | /// event if newValue == value.
18 | void update(ThemeMode newValue) {
19 | value = newValue;
20 | refresh();
21 | }
22 | }
23 |
24 | extension ThemeModeNotifierEx on ValueNotifier {
25 | bool get isDark => value.isDark;
26 |
27 | bool get isLight => value.isLight;
28 |
29 | bool get isSystem => value.isSystem;
30 |
31 | void setDark() => value = ThemeMode.dark;
32 |
33 | void setLight() => value = ThemeMode.light;
34 |
35 | void setSystem() => value = ThemeMode.system;
36 | }
37 |
38 | class BrightnessNotifier extends ValueNotifier {
39 | BrightnessNotifier(super.value);
40 |
41 | @override
42 | void notifyListeners() {
43 | try {
44 | super.notifyListeners();
45 | } catch (_) {}
46 | }
47 |
48 | void refresh() => notifyListeners();
49 |
50 | /// similar to value setter but this one force trigger the notifyListeners()
51 | /// event if newValue == value.
52 | void update(Brightness newValue) {
53 | value = newValue;
54 | refresh();
55 | }
56 | }
57 |
58 | extension BrightnessNotifierEx on ValueNotifier {
59 | bool get isDark => value.isDark;
60 |
61 | bool get isLight => value.isLight;
62 |
63 | void setDart() => value = Brightness.dark;
64 |
65 | void setLight() => value = Brightness.light;
66 | }
67 |
--------------------------------------------------------------------------------
/lib/src/value_notifier/value_notifier.dart:
--------------------------------------------------------------------------------
1 | export 'extensions/extensions.dart';
2 | export 'notifier_classes/notifier_classes.dart';
3 | export 'widgets/widgets.dart';
4 |
--------------------------------------------------------------------------------
/lib/src/value_notifier/widgets/listenables_builder.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | /// [ListenablesBuilder]
4 | ///
5 | /// A widget that rebuilds itself when any of the provided [Listenable] objects notify their listeners.
6 | /// This allows for responsive and dynamic UI updates based on changes in multiple [Listenable] sources.
7 | ///
8 | /// The `ListenablesBuilder` widget is designed to listen to a collection of [Listenable] objects,
9 | /// such as [ValueNotifier], [ChangeNotifier], or custom [Listenable] instances. When any of the
10 | /// specified `listenables` notify their listeners of changes, the widget will trigger a rebuild,
11 | /// ensuring that the UI reflects the latest state.
12 | ///
13 | /// This widget offers flexibility in its configuration:
14 | /// - You can provide a list of [Listenable] objects to listen to.
15 | /// - You can define a custom `builder` function to specify the UI.
16 | /// - You can optionally provide a `buildWhen` callback to control when the widget should rebuild,
17 | /// optimizing performance by preventing unnecessary rebuilds.
18 | /// - You can also specify a `threshold` duration to limit the frequency of rebuilds during rapid
19 | /// state changes, helping to avoid performance issues and UI flickering.
20 | /// **Example:**
21 | /// ```dart
22 | /// ListenablesBuilder(
23 | /// listenables: [myValueNotifier1, myChangeNotifier],
24 | /// builder: (context) => Text('Value 1: ${myValueNotifier1.value}, Value 2: ${myChangeNotifier.someProperty}'),
25 | /// );
26 | /// ```
27 | class ListenablesBuilder extends StatefulWidget {
28 | const ListenablesBuilder({
29 | required this.listenables,
30 | required this.builder,
31 | this.buildWhen,
32 | this.threshold,
33 | super.key,
34 | });
35 |
36 | /// A list of [Listenable] objects that this widget listens to.
37 | /// The widget will rebuild when any of the `listenables` notify their listeners.
38 | final List listenables;
39 |
40 | /// A function that returns the widget to be built.
41 | /// This function is called whenever the widget needs to rebuild.
42 | final Widget Function(BuildContext context) builder;
43 |
44 | /// An optional function that determines whether the widget should rebuild
45 | /// when any of the `listenables` notify their listeners.
46 | /// If it returns `true`, the [builder] function is called to rebuild the widget.
47 | /// If `false`, the widget is not rebuilt. If null, the widget rebuilds on every notification.
48 | final bool Function()? buildWhen;
49 |
50 | /// An optional [Duration] that sets a minimum interval between rebuilds
51 | /// to limit the frequency of rebuilds during rapid state changes.
52 | final Duration? threshold;
53 |
54 | @override
55 | State createState() => _ListenablesBuilderState();
56 | }
57 |
58 | class _ListenablesBuilderState extends State {
59 | DateTime? _lastBuildTime;
60 | final Set _activeListenables = {}; // Track active listeners
61 |
62 | @override
63 | void initState() {
64 | super.initState();
65 | _addListeners();
66 | }
67 |
68 | void _addListeners() {
69 | for (final listenable in widget.listenables) {
70 | if (listenable != null && !_activeListenables.contains(listenable)) {
71 | listenable.addListener(_listener);
72 | _activeListenables.add(listenable);
73 | }
74 | }
75 | }
76 |
77 | void _removeListeners() {
78 | for (final listenable in _activeListenables) {
79 | listenable.removeListener(_listener);
80 | }
81 | _activeListenables.clear();
82 | }
83 |
84 | void _listener() {
85 | if (widget.buildWhen?.call() ?? true) {
86 | final now = DateTime.now();
87 | if (widget.threshold == null ||
88 | _lastBuildTime == null ||
89 | now.difference(_lastBuildTime!) > widget.threshold!) {
90 | setState(() {
91 | _lastBuildTime = now;
92 | });
93 | }
94 | }
95 | }
96 |
97 | @override
98 | void didUpdateWidget(ListenablesBuilder oldWidget) {
99 | super.didUpdateWidget(oldWidget);
100 | if (oldWidget.listenables != widget.listenables) {
101 | _removeListeners();
102 | _addListeners();
103 | }
104 | }
105 |
106 | @override
107 | void dispose() {
108 | _removeListeners();
109 | super.dispose();
110 | }
111 |
112 | @override
113 | Widget build(BuildContext context) => widget.builder(context);
114 | }
115 |
--------------------------------------------------------------------------------
/lib/src/value_notifier/widgets/widgets.dart:
--------------------------------------------------------------------------------
1 | export 'listenables_builder.dart';
2 |
--------------------------------------------------------------------------------
/lib/src/widgets/gradient_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | /// A [GradientWidget] applies a gradient effect to its child widget
4 | /// and offers extensive customization options for blending, alignment,
5 | /// and opacity.
6 | ///
7 | /// This widget uses a [ShaderMask] to overlay the provided [gradient] on top
8 | /// of the [child] widget. Additionally, it provides options to control how the
9 | /// gradient interacts with the child, including blend mode, child alignment, and opacity.
10 | ///
11 | /// Example usage:
12 | /// ```dart
13 | /// GradientWidget(
14 | /// gradient: LinearGradient(
15 | /// colors: [Colors.blue, Colors.purple, Colors.pink],
16 | /// begin: AlignmentDirectional.topStart,
17 | /// end: AlignmentDirectional.bottomEnd,
18 | /// ),
19 | /// blendMode: BlendMode.srcIn,
20 | /// opacity: 0.8,
21 | /// child: Text(
22 | /// 'Gradient Text!',
23 | /// style: TextStyle(fontSize: 40, color: Colors.white),
24 | /// ),
25 | /// )
26 | /// ```
27 | ///
28 | /// The gradient can be customized with any [Gradient], and the child can
29 | /// be any widget, not limited to just text.
30 | class GradientWidget extends StatelessWidget {
31 | /// Creates a [GradientWidget] with customizable gradient, blend mode, opacity,
32 | /// and alignments for both the gradient and the child.
33 | const GradientWidget({
34 | required this.child,
35 | required this.gradient,
36 | this.blendMode = BlendMode.srcIn,
37 | @Deprecated(
38 | "Use the gradient's own positioning properties instead (like begin/end for LinearGradient)")
39 | this.gradientAlignment = Alignment.topLeft,
40 | this.opacity = 1.0,
41 | this.childAlignment = AlignmentDirectional.center,
42 | super.key,
43 | }) : assert(opacity >= 0.0 && opacity <= 1.0,
44 | 'Opacity must be between 0.0 and 1.0');
45 |
46 | /// The widget that will have the gradient applied to it.
47 | final Widget child;
48 |
49 | /// The gradient to apply on the child widget.
50 | /// Use the gradient's own positioning properties (like begin/end for LinearGradient)
51 | /// to control its placement.
52 | final Gradient gradient;
53 |
54 | /// The blend mode to determine how the gradient interacts with the
55 | /// child widget's existing colors. Defaults to [BlendMode.srcIn].
56 | final BlendMode blendMode;
57 |
58 | /// The alignment of the gradient relative to the child widget's bounds.
59 | /// This controls how the gradient is positioned. Defaults to [Alignment.topLeft].
60 | ///
61 | /// @deprecated Use the gradient's own positioning properties instead
62 | /// (like begin/end for LinearGradient).
63 | @Deprecated(
64 | "Use the gradient's own positioning properties instead (like begin/end for LinearGradient)")
65 | final Alignment gradientAlignment;
66 |
67 | /// The opacity of the gradient, ranging from 0.0 (fully transparent)
68 | /// to 1.0 (fully opaque). Defaults to 1.0.
69 | final double opacity;
70 |
71 | /// The alignment of the child within the widget. Useful if the child does not
72 | /// fill the entire available space. Defaults to [AlignmentDirectional.center].
73 | final AlignmentDirectional childAlignment;
74 |
75 | @override
76 | Widget build(BuildContext context) {
77 | return Opacity(
78 | opacity: opacity,
79 | child: ShaderMask(
80 | blendMode: blendMode,
81 | shaderCallback: gradient.createShader,
82 | child: Align(
83 | alignment: childAlignment,
84 | child: child,
85 | ),
86 | ),
87 | );
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/lib/src/widgets/multi_tap_detector.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/gestures.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | /// A widget that detects multiple taps on its child within a specified duration.
7 | ///
8 | /// The [onTap] callback is triggered when the specified number of taps ([tapCount])
9 | /// occurs within the given [duration].
10 | ///
11 | /// This widget can detect gestures where the user taps multiple times on the child
12 | /// widget within a configurable time interval. It handles both rapid tapping
13 | /// and accidental taps where the user pauses or performs other gestures.
14 | class MultiTapDetector extends StatefulWidget {
15 | const MultiTapDetector({
16 | required this.child,
17 | required this.onTap,
18 | this.tapCount = 3,
19 | this.duration = const Duration(milliseconds: 500),
20 | this.onTapProgress,
21 | super.key,
22 | }) : assert(tapCount > 1, 'tapCount must be greater than 1');
23 |
24 | /// The widget to which the multi-tap detection will be applied.
25 | final Widget child;
26 |
27 | /// The callback function to be executed when the multi-tap gesture is detected.
28 | final VoidCallback onTap;
29 |
30 | /// Optional callback that reports the progress of tapping sequence.
31 | /// The integer parameter represents the current tap count.
32 | final void Function(int currentCount)? onTapProgress;
33 |
34 | /// The number of taps required to trigger the [onTap] callback.
35 | final int tapCount;
36 |
37 | /// The maximum duration allowed between consecutive taps within a multi-tap sequence.
38 | final Duration duration;
39 |
40 | @override
41 | State createState() => _MultiTapDetectorState();
42 | }
43 |
44 | class _MultiTapDetectorState extends State {
45 | Timer? _resetTimer;
46 |
47 | @override
48 | void dispose() {
49 | _resetTimer?.cancel();
50 | super.dispose();
51 | }
52 |
53 | void _startResetTimer() {
54 | _resetTimer?.cancel();
55 | _resetTimer = Timer(widget.duration, () {
56 | // Reset timer expired without completing the sequence
57 | if (widget.onTapProgress != null) {
58 | widget.onTapProgress?.call(0);
59 | }
60 | });
61 | }
62 |
63 | @override
64 | Widget build(BuildContext context) {
65 | return RawGestureDetector(
66 | gestures: {
67 | SerialTapGestureRecognizer:
68 | GestureRecognizerFactoryWithHandlers(
69 | () => SerialTapGestureRecognizer(
70 | supportedDevices: null, // Support all devices
71 | ),
72 | (SerialTapGestureRecognizer instance) {
73 | instance
74 | ..onSerialTapDown = (SerialTapDownDetails details) {
75 | _startResetTimer();
76 |
77 | // Report progress if callback is provided
78 | if (widget.onTapProgress != null) {
79 | widget.onTapProgress?.call(details.count);
80 | }
81 | }
82 | ..onSerialTapUp = (SerialTapUpDetails details) {
83 | if (details.count == widget.tapCount) {
84 | _resetTimer?.cancel();
85 | widget.onTap();
86 |
87 | // Reset progress
88 | if (widget.onTapProgress != null) {
89 | widget.onTapProgress?.call(0);
90 | }
91 | }
92 | }
93 | ..onSerialTapCancel = (SerialTapCancelDetails details) {
94 | _resetTimer?.cancel();
95 |
96 | // Reset progress
97 | if (widget.onTapProgress != null) {
98 | widget.onTapProgress?.call(0);
99 | }
100 | };
101 | },
102 | ),
103 | },
104 | child: widget.child,
105 | );
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/lib/src/widgets/widgets.dart:
--------------------------------------------------------------------------------
1 | export 'adaptive_ui.dart';
2 | export 'gradient_widget.dart';
3 | export 'multi_tap_detector.dart';
4 | export 'typed_list_view.dart';
5 |
--------------------------------------------------------------------------------
/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_helper_utils
2 | description: The Flutter Helper Utils Package offers various extensions and helper methods that can make development more efficient.
3 | repository: https://github.com/omar-hanafy/flutter_helper_utils
4 | version: 8.0.2
5 | topics:
6 | - utilities
7 | - helpers
8 | - extensions
9 | - productivity
10 | - adaptive
11 |
12 | environment:
13 | sdk: '>=3.4.0 <4.0.0'
14 | flutter: ">=3.29.0 <4.0.0"
15 |
16 | dependencies:
17 | flutter:
18 | sdk: flutter
19 | dart_helper_utils: ">=4.1.2 <6.0.0"
20 | intl: ">=0.19.0 <1.0.0"
21 |
22 | dev_dependencies:
23 | flutter_test:
24 | sdk: flutter
25 | very_good_analysis: ^7.0.0
26 |
--------------------------------------------------------------------------------