├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.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 │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── 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 ├── lib │ ├── main.dart │ ├── views │ │ └── home │ │ │ ├── home_view.dart │ │ │ ├── home_view_mobile.dart │ │ │ └── home_view_tablet.dart │ └── widgets │ │ ├── app_drawer │ │ ├── app_drawer.dart │ │ ├── app_drawer_mobile.dart │ │ └── app_drawer_tablet.dart │ │ └── drawer_option │ │ ├── drawer_option.dart │ │ ├── drawer_option_mobile.dart │ │ └── drawer_option_tablet.dart ├── pubspec.yaml ├── test │ └── widget_test.dart ├── web │ ├── favicon.png │ ├── icons │ │ ├── Icon-192.png │ │ └── Icon-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 │ ├── run_loop.cpp │ ├── run_loop.h │ ├── runner.exe.manifest │ ├── utils.cpp │ ├── utils.h │ ├── win32_window.cpp │ └── win32_window.h ├── lib ├── responsive_builder.dart └── src │ ├── device_screen_type.dart │ ├── helpers │ ├── device_width.dart │ ├── device_width_web.dart │ └── helpers.dart │ ├── responsive_sizing_config.dart │ ├── responsive_wrapper.dart │ ├── scroll │ ├── scroll_transform_item.dart │ └── scroll_transform_view.dart │ ├── sizing_information.dart │ └── widget_builders.dart ├── pubspec.yaml ├── responsive-builder-banner.jpeg ├── responsive_example.gif └── test └── responsive_builder_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .packages 28 | .pub-cache/ 29 | .pub/ 30 | build/ 31 | 32 | # Android related 33 | **/android/**/gradle-wrapper.jar 34 | **/android/.gradle 35 | **/android/captures/ 36 | **/android/gradlew 37 | **/android/gradlew.bat 38 | **/android/local.properties 39 | **/android/**/GeneratedPluginRegistrant.java 40 | 41 | # iOS/XCode related 42 | **/ios/**/*.mode1v3 43 | **/ios/**/*.mode2v3 44 | **/ios/**/*.moved-aside 45 | **/ios/**/*.pbxuser 46 | **/ios/**/*.perspectivev3 47 | **/ios/**/*sync/ 48 | **/ios/**/.sconsign.dblite 49 | **/ios/**/.tags* 50 | **/ios/**/.vagrant/ 51 | **/ios/**/DerivedData/ 52 | **/ios/**/Icon? 53 | **/ios/**/Pods/ 54 | **/ios/**/.symlinks/ 55 | **/ios/**/profile 56 | **/ios/**/xcuserdata 57 | **/ios/.generated/ 58 | **/ios/Flutter/App.framework 59 | **/ios/Flutter/Flutter.framework 60 | **/ios/Flutter/Generated.xcconfig 61 | **/ios/Flutter/app.flx 62 | **/ios/Flutter/app.zip 63 | **/ios/Flutter/flutter_assets/ 64 | **/ios/Flutter/flutter_export_environment.sh 65 | **/ios/ServiceDefinitions.json 66 | **/ios/Runner/GeneratedPluginRegistrant.* 67 | 68 | # Exceptions to above rules. 69 | !**/ios/**/default.mode1v3 70 | !**/ios/**/default.mode2v3 71 | !**/ios/**/default.pbxuser 72 | !**/ios/**/default.perspectivev3 73 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 74 | pubspec.lock 75 | -------------------------------------------------------------------------------- /.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: 1aedbb1835bd6eb44550293d57d4d124f19901f0 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.7.1 2 | 3 | - Fixes [#53](https://github.com/FilledStacks/responsive_builder/issues/53) 4 | 5 | ## 0.7.0 6 | 7 | - Fixes #50 8 | 9 | ## 0.6.4 10 | 11 | - Fixes #48 12 | 13 | ## 0.6.3 14 | 15 | - Fixes bug with preferDesktop and `getValueForScreenType` 16 | 17 | ## 0.6.2 18 | 19 | - Fixes bug with preferDesktop where it always returns desktop UI even if there is a mobile UI. 20 | 21 | ## 0.6.1 22 | 23 | - Adds `preferDesktop` to `ResponsiveApp` which tells the builders that if there's no layout supplied for the current size prefer the desktop over the mobileLayout. Default value is `false` to maintain mobile first behaviour. 24 | 25 | ## 0.6.0 26 | 27 | ### New Feature 28 | Adds responsive sizing by using the `ResponsiveApp` widget at the highest level which allows: 29 | - Using `20.screenHeight` / `number.screenHeight` shorthand to get the percentage of the Screen Height 30 | - The same exists for the `screenWidth` 31 | - There are also shorthand extensions for both. `screenHeight` => `sh` and `screenWidth` => `sw` 32 | 33 | ## 0.5.1 34 | 35 | - Adds checks to ensure desktop returns as Flutter web 36 | 37 | ## 0.5.0+1 38 | 39 | - Adds banner to readme 40 | 41 | ## 0.5.0 42 | 43 | ### New Feature 44 | Adds the `ScrollTransform` functionality which allows you to more easily create scroll effects based on the scrolling position. 45 | 46 | ## 0.4.3 47 | 48 | - Added small size for getValueForRefinedSize 49 | - Adds funding link to coffee 50 | 51 | ## 0.4.2 52 | 53 | - Added optional override property in orientation builder 54 | 55 | ## 0.4.0-nullsafety.1 56 | 57 | - Adds null safety and correct small refined sizing 58 | 59 | ## 0.3.0 60 | 61 | - Adds the refined sizing functionality 62 | 63 | ## 0.2.0+2 64 | 65 | - Added `getValueForScreenType` functionality to the readme 66 | 67 | ## 0.2.0+1 68 | - export the sizing config which I forgot to do first time. 69 | 70 | ## 0.2.0 71 | 72 | - Adds responsive sizing config for global breakpoint setting 73 | 74 | ## 0.1.9 75 | 76 | - Reverted the change for returning the mobile layout when break points doesn't define any. 77 | 78 | ## 0.1.8+1 79 | 80 | - readme updates 81 | 82 | ## 0.1.8 83 | 84 | - Changed enum naming to lowerCamelCase to follow convention 85 | - Add a return for mobile when no breakpoints match 86 | 87 | ## 0.1.7 88 | 89 | - Made 600 inclusive for tablet devices and 900 inclusive for desktop 90 | 91 | ## 0.1.6 92 | 93 | - Added ScreenTypeValue builder to allow us to return different values depending on the screen type 94 | 95 | ## 0.1.4+1 96 | 97 | Changelog styling updates 98 | 99 | ## 0.1.4 100 | 101 | - Added optional screen break points definition to pass in to the ResponsiveBuilder or the ScreenLayoutView. 102 | 103 | ## 0.1.3 104 | 105 | - Added shorthand bool properties to sizing information to check which device screen type is currently being show. 106 | 107 | ## 0.1.2 108 | 109 | - Updated screen type calculation to account for being on the Web. Width was swapping with the height when it got too wide so we're checking for web explicitly and using the width of the window. 110 | 111 | ## 0.1.1 112 | 113 | - Update the ScreenTypeLayout widget to use an incremental layout approach. If the desktop isn't supplied and we're in desktop mode we check if there's a tablet layout and show that, otherwise we show the mobile layout. 114 | 115 | ## 0.1.0 116 | 117 | - Added initial widgets required for a clean responsive UI architecture. 118 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 FilledStacks (Pty) Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Responsive UI in Flutter Banner](https://github.com/FilledStacks/responsive_builder/blob/master/responsive-builder-banner.jpeg)](https://youtu.be/neRnM_SiTfA) 2 | 3 | # Responsive Builder 💻➡️🖥➡️📱➡️⌚️ 4 | 5 | The responsive builder package contains widgets that allows you to create a readable responsive UI. The package is inspired by the [Responsive UI Flutter series](https://www.youtube.com/playlist?list=PLQQBiNtFxeyJbOkeKBe_JG36gm1V2629H) created by FilledStacks. 6 | 7 | It aims to provide you with widgets that make it easy to build different UI's along two different Axis. Orientation x ScreenType. This means you can have a separate layout for Mobile - Landscape, Mobile - Portrait, Tablet - Landscape and Tablet-Portrait. 8 | 9 | If you follow along with the series you will have a complete understanding of how it's built and how to use it. [Part 2](https://youtu.be/udsysUj-X4w) goes over how we build the example included in this project. 10 | 11 | ![Responsive Layout Preview](./responsive_example.gif) 12 | 13 | ## Installation 14 | 15 | Add responsive_builder as dependency to your pubspec file. 16 | 17 | ``` 18 | responsive_builder: 19 | ``` 20 | 21 | ## Usage 22 | 23 | This package provides a widget called `ResponsiveBuilder` that provides you with a builder function that returns the current `SizingInformation`. The `SizingInformation` includes the `DeviceScreenType`, `screenSize` and `localWidgetSize`. This can be used for fine grained responsive control from a view level down to per widget responsive level. 24 | 25 | ### Responsive Builder 26 | 27 | The `ResponsiveBuilder` is used as any other builder widget. 28 | 29 | ```dart 30 | // import the package 31 | import 'package:responsive_builder/responsive_builder.dart'; 32 | 33 | // Use the widget 34 | ResponsiveBuilder( 35 | builder: (context, sizingInformation) { 36 | // Check the sizing information here and return your UI 37 | if (sizingInformation.deviceScreenType == DeviceScreenType.desktop) { 38 | return Container(color:Colors.blue); 39 | } 40 | 41 | if (sizingInformation.deviceScreenType == DeviceScreenType.tablet) { 42 | return Container(color:Colors.red); 43 | } 44 | 45 | if (sizingInformation.deviceScreenType == DeviceScreenType.watch) { 46 | return Container(color:Colors.yellow); 47 | } 48 | 49 | return Container(color:Colors.purple); 50 | }, 51 | }, 52 | ); 53 | } 54 | ``` 55 | 56 | This will return different colour containers depending on which device it's being shown on. A simple way to test this is to either run your code on Flutter web and resize the window or add the [device_preview](https://pub.dev/packages/device_preview) package and view on different devices. 57 | 58 | ## Orientation Layout Builder 59 | 60 | This widget can be seen as a duplicate of the `OrientationBuilder` that comes with Flutter, but the point of this library is to help you produce a readable responsive UI code base. As mentioned in the [follow along tutorial](https://youtu.be/udsysUj-X4w) I didn't want responsive code riddled with conditionals around orientation, `MediaQuery` or Renderbox sizes. That's why I created this builder. 61 | 62 | The usage is easy. Provide a builder function that returns a UI for each of the orientations. 63 | 64 | ```dart 65 | // import the package 66 | import 'package:responsive_builder/responsive_builder.dart'; 67 | 68 | // Return a widget function per orientation 69 | OrientationLayoutBuilder( 70 | portrait: (context) => Container(color: Colors.green), 71 | landscape: (context) => Container(color: Colors.pink), 72 | ), 73 | ``` 74 | 75 | This will return a different coloured container when you swap orientations for your device. In a more readable manner than checking the orientation with a conditional. 76 | 77 | Sometimes you want your app to stay in a certain orientation. use `mode` property in `OrientationLayoutBuilder` to enforce this. 78 | 79 | ```dart 80 | OrientationLayoutBuilder( 81 | /// default mode is 'auto' 82 | mode: info.isMobile 83 | ? OrientationLayoutBuilderMode.portrait 84 | : OrientationLayoutBuilderMode.auto, 85 | ... 86 | ), 87 | ``` 88 | 89 | ## Screen Type Layout 90 | 91 | This widget is similar to the Orientation Layout Builder in that it takes in Widgets that are named and displayed for different screen types. 92 | 93 | ```dart 94 | // import the package 95 | import 'package:responsive_builder/responsive_builder.dart'; 96 | 97 | // Construct and pass in a widget per screen type 98 | ScreenTypeLayout( 99 | mobile: Container(color:Colors.blue) 100 | tablet: Container(color: Colors.yellow), 101 | desktop: Container(color: Colors.red), 102 | watch: Container(color: Colors.purple), 103 | ); 104 | ``` 105 | 106 | If you don't want to build all the widgets at once, you can use the widget builder. A widget for the right type of screen will be created only when needed. 107 | 108 | ```dart 109 | // Construct and pass in a widget builder per screen type 110 | ScreenTypeLayout.builder( 111 | mobile: (BuildContext context) => Container(color:Colors.blue), 112 | tablet: (BuildContext context) => Container(color:Colors.yellow), 113 | desktop: (BuildContext context) => Container(color:Colors.red), 114 | watch: (BuildContext context) => Container(color:Colors.purple), 115 | ); 116 | ``` 117 | 118 | ## Custom Screen Breakpoints 119 | 120 | If you wish to define your own custom break points you can do so by supplying either the `ScreenTypeLayout` or `ResponsiveBuilder` widgets with a `breakpoints` argument. 121 | 122 | ```dart 123 | // import the package 124 | import 'package:responsive_builder/responsive_builder.dart'; 125 | 126 | //ScreenTypeLayout with custom breakpoints supplied 127 | ScreenTypeLayout( 128 | breakpoints: ScreenBreakpoints( 129 | tablet: 600, 130 | desktop: 950, 131 | watch: 300 132 | ), 133 | mobile: Container(color:Colors.blue) 134 | tablet: Container(color: Colors.yellow), 135 | desktop: Container(color: Colors.red), 136 | watch: Container(color: Colors.purple), 137 | ); 138 | ``` 139 | 140 | To get a more in depth run through of this package I would highly recommend [watching this tutorial](https://youtu.be/udsysUj-X4w) where I show you how it was built and how to use it. 141 | 142 | ## Global Screen Breakpoints 143 | 144 | If you want to set the breakpoints for the responsive builders once you can call the line below before the app starts, or wherever you see fit. 145 | 146 | ```dart 147 | void main() { 148 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 149 | ScreenBreakpoints(desktop: 800, tablet: 550, watch: 200), 150 | ); 151 | runApp(MyApp()); 152 | } 153 | ``` 154 | 155 | This will then reflect the screen types based on what you have set here. You can then still pass in custom break points per `ScreenTypeLayout` if you wish that will override these values for that specific `ScreenTypeLayout` builder. 156 | 157 | ## Screen Type specific values 158 | 159 | Sometimes you don't want to write an entire new UI just to change one value. Say for instance you want your padding on mobile to be 10, on the tablet 30 and desktop 60. Instead of re-writing UI you can use the `getValueForScreenType` function. This is a generic function that will return your value based on the screen type you're on. Take this example below. 160 | 161 | ```dart 162 | Container( 163 | padding: EdgeInsets.all(10), 164 | child: Text('Best Responsive Package'), 165 | ) 166 | ``` 167 | 168 | What if you ONLY want to update the padding based on the device screen size. You could do. 169 | 170 | ```dart 171 | var deviceType = getDeviceType(MediaQuery.of(context).size); 172 | var paddingValue = 0; 173 | switch(deviceType) { 174 | case DeviceScreenType.desktop: 175 | paddingValue = 60; 176 | break; 177 | case DeviceScreenType.tablet: 178 | paddingValue = 30; 179 | break; 180 | case DeviceScreenType.mobile: 181 | paddingValue = 10; 182 | break; 183 | } 184 | Container( 185 | padding: EdgeInsets.all(paddingValue), 186 | child: Text('Best Responsive Package'), 187 | ) 188 | ``` 189 | 190 | Ooooorrrr, you can use shorthand for that. 191 | 192 | ```dart 193 | Container( 194 | padding: EdgeInsets.all(getValueForScreenType( 195 | context: context, 196 | mobile: 10, 197 | tablet: 30, 198 | desktop: 60, 199 | )), 200 | child: Text('Best Responsive Package'), 201 | ) 202 | ``` 203 | 204 | It will return the value you give it for the DeviceScreen you're viewing the app on. For instance you want to hide a widget on mobile and not on tablet? 205 | 206 | ```dart 207 | getValueForScreenType( 208 | context: context, 209 | mobile: false, 210 | tablet: true, 211 | ) ? MyWidget() : Container() 212 | ``` 213 | 214 | That will return true on tablet devices and false on mobile. 215 | 216 | ## Responsive Sizing 217 | 218 | In addition to providing specific layouts per device type there's also the requirement to size items based on the screen width or height. To use this functionality we added some responsive extensions. To use this wrap your Material or Cupertino App with the `ResponsiveApp` widget. 219 | 220 | ```dart 221 | ResponsiveApp( 222 | builder: (context) => MaterialApp( 223 | ... 224 | ) 225 | ) 226 | ``` 227 | 228 | This is required to use the following functionality. 229 | 230 | ### Responsive Sizing 231 | 232 | To use the responsive sizing all you need to do is the following. 233 | 234 | ```dart 235 | import 'package:responsive_builder/responsive_builder.dart'; 236 | 237 | SizedBox(height: 30.screenHeight); // Or sh for shorthand 238 | Text('respond to width', style: TextStyle(fontSize: 10.sw)); 239 | ``` 240 | 241 | Use the number you want as the percentage and call the `screenHeight` or `screenWidth` extension. These also have shorthand extensions `sh` and `sw`. 242 | 243 | ## Contribution 244 | 245 | 1. Fork it! 246 | 2. Create your feature branch: `git checkout -b my-new-feature` 247 | 3. Commit your changes: `git commit -am 'Add some feature'` 248 | 4. Push to the branch: `git push origin my-new-feature` 249 | 5. Submit a pull request. 250 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .packages 28 | .pub-cache/ 29 | .pub/ 30 | /build/ 31 | 32 | # Web related 33 | lib/generated_plugin_registrant.dart 34 | 35 | # Exceptions to above rules. 36 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 37 | -------------------------------------------------------------------------------- /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: 2cedd559bb9798ac1ba09f0ee959a2dcb1388644 8 | channel: master 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Responsive Builder Example 💻➡️🖥➡️📱➡️⌚️ 2 | 3 | The example included in this project is built in this tutorial which is [Part 2](https://youtu.be/udsysUj-X4w) of the responsive UI series by FilledStacks. 4 | 5 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 30 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | defaultConfig { 36 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 37 | applicationId "com.example.example" 38 | minSdkVersion 16 39 | targetSdkVersion 30 40 | versionCode flutterVersionCode.toInteger() 41 | versionName flutterVersionName 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 59 | } 60 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 13 | 17 | 21 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 7 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /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 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXCopyFilesBuildPhase section */ 19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 20 | isa = PBXCopyFilesBuildPhase; 21 | buildActionMask = 2147483647; 22 | dstPath = ""; 23 | dstSubfolderSpec = 10; 24 | files = ( 25 | ); 26 | name = "Embed Frameworks"; 27 | runOnlyForDeploymentPostprocessing = 0; 28 | }; 29 | /* End PBXCopyFilesBuildPhase section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 9740EEB11CF90186004384FC /* Flutter */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 65 | ); 66 | name = Flutter; 67 | sourceTree = ""; 68 | }; 69 | 97C146E51CF9000F007C117D = { 70 | isa = PBXGroup; 71 | children = ( 72 | 9740EEB11CF90186004384FC /* Flutter */, 73 | 97C146F01CF9000F007C117D /* Runner */, 74 | 97C146EF1CF9000F007C117D /* Products */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 97C146EF1CF9000F007C117D /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 97C146EE1CF9000F007C117D /* Runner.app */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | 97C146F01CF9000F007C117D /* Runner */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 92 | 97C147021CF9000F007C117D /* Info.plist */, 93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 97 | ); 98 | path = Runner; 99 | sourceTree = ""; 100 | }; 101 | /* End PBXGroup section */ 102 | 103 | /* Begin PBXNativeTarget section */ 104 | 97C146ED1CF9000F007C117D /* Runner */ = { 105 | isa = PBXNativeTarget; 106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 107 | buildPhases = ( 108 | 9740EEB61CF901F6004384FC /* Run Script */, 109 | 97C146EA1CF9000F007C117D /* Sources */, 110 | 97C146EB1CF9000F007C117D /* Frameworks */, 111 | 97C146EC1CF9000F007C117D /* Resources */, 112 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 114 | ); 115 | buildRules = ( 116 | ); 117 | dependencies = ( 118 | ); 119 | name = Runner; 120 | productName = Runner; 121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 122 | productType = "com.apple.product-type.application"; 123 | }; 124 | /* End PBXNativeTarget section */ 125 | 126 | /* Begin PBXProject section */ 127 | 97C146E61CF9000F007C117D /* Project object */ = { 128 | isa = PBXProject; 129 | attributes = { 130 | LastUpgradeCheck = 1020; 131 | ORGANIZATIONNAME = ""; 132 | TargetAttributes = { 133 | 97C146ED1CF9000F007C117D = { 134 | CreatedOnToolsVersion = 7.3.1; 135 | LastSwiftMigration = 1100; 136 | }; 137 | }; 138 | }; 139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 140 | compatibilityVersion = "Xcode 9.3"; 141 | developmentRegion = en; 142 | hasScannedForEncodings = 0; 143 | knownRegions = ( 144 | en, 145 | Base, 146 | ); 147 | mainGroup = 97C146E51CF9000F007C117D; 148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 149 | projectDirPath = ""; 150 | projectRoot = ""; 151 | targets = ( 152 | 97C146ED1CF9000F007C117D /* Runner */, 153 | ); 154 | }; 155 | /* End PBXProject section */ 156 | 157 | /* Begin PBXResourcesBuildPhase section */ 158 | 97C146EC1CF9000F007C117D /* Resources */ = { 159 | isa = PBXResourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXShellScriptBuildPhase section */ 172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 173 | isa = PBXShellScriptBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | ); 177 | inputPaths = ( 178 | ); 179 | name = "Thin Binary"; 180 | outputPaths = ( 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | shellPath = /bin/sh; 184 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 185 | }; 186 | 9740EEB61CF901F6004384FC /* Run Script */ = { 187 | isa = PBXShellScriptBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | ); 191 | inputPaths = ( 192 | ); 193 | name = "Run Script"; 194 | outputPaths = ( 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | shellPath = /bin/sh; 198 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 199 | }; 200 | /* End PBXShellScriptBuildPhase section */ 201 | 202 | /* Begin PBXSourcesBuildPhase section */ 203 | 97C146EA1CF9000F007C117D /* Sources */ = { 204 | isa = PBXSourcesBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 208 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXSourcesBuildPhase section */ 213 | 214 | /* Begin PBXVariantGroup section */ 215 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 216 | isa = PBXVariantGroup; 217 | children = ( 218 | 97C146FB1CF9000F007C117D /* Base */, 219 | ); 220 | name = Main.storyboard; 221 | sourceTree = ""; 222 | }; 223 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 224 | isa = PBXVariantGroup; 225 | children = ( 226 | 97C147001CF9000F007C117D /* Base */, 227 | ); 228 | name = LaunchScreen.storyboard; 229 | sourceTree = ""; 230 | }; 231 | /* End PBXVariantGroup section */ 232 | 233 | /* Begin XCBuildConfiguration section */ 234 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 235 | isa = XCBuildConfiguration; 236 | buildSettings = { 237 | ALWAYS_SEARCH_USER_PATHS = NO; 238 | CLANG_ANALYZER_NONNULL = YES; 239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 240 | CLANG_CXX_LIBRARY = "libc++"; 241 | CLANG_ENABLE_MODULES = YES; 242 | CLANG_ENABLE_OBJC_ARC = YES; 243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 244 | CLANG_WARN_BOOL_CONVERSION = YES; 245 | CLANG_WARN_COMMA = YES; 246 | CLANG_WARN_CONSTANT_CONVERSION = YES; 247 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 249 | CLANG_WARN_EMPTY_BODY = YES; 250 | CLANG_WARN_ENUM_CONVERSION = YES; 251 | CLANG_WARN_INFINITE_RECURSION = YES; 252 | CLANG_WARN_INT_CONVERSION = YES; 253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 258 | CLANG_WARN_STRICT_PROTOTYPES = YES; 259 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 260 | CLANG_WARN_UNREACHABLE_CODE = YES; 261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 263 | COPY_PHASE_STRIP = NO; 264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 265 | ENABLE_NS_ASSERTIONS = NO; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | GCC_C_LANGUAGE_STANDARD = gnu99; 268 | GCC_NO_COMMON_BLOCKS = YES; 269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 271 | GCC_WARN_UNDECLARED_SELECTOR = YES; 272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 273 | GCC_WARN_UNUSED_FUNCTION = YES; 274 | GCC_WARN_UNUSED_VARIABLE = YES; 275 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 276 | MTL_ENABLE_DEBUG_INFO = NO; 277 | SDKROOT = iphoneos; 278 | SUPPORTED_PLATFORMS = iphoneos; 279 | TARGETED_DEVICE_FAMILY = "1,2"; 280 | VALIDATE_PRODUCT = YES; 281 | }; 282 | name = Profile; 283 | }; 284 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 285 | isa = XCBuildConfiguration; 286 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 287 | buildSettings = { 288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 289 | CLANG_ENABLE_MODULES = YES; 290 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 291 | ENABLE_BITCODE = NO; 292 | INFOPLIST_FILE = Runner/Info.plist; 293 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 294 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 295 | PRODUCT_NAME = "$(TARGET_NAME)"; 296 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 297 | SWIFT_VERSION = 5.0; 298 | VERSIONING_SYSTEM = "apple-generic"; 299 | }; 300 | name = Profile; 301 | }; 302 | 97C147031CF9000F007C117D /* Debug */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ALWAYS_SEARCH_USER_PATHS = NO; 306 | CLANG_ANALYZER_NONNULL = YES; 307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 308 | CLANG_CXX_LIBRARY = "libc++"; 309 | CLANG_ENABLE_MODULES = YES; 310 | CLANG_ENABLE_OBJC_ARC = YES; 311 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_COMMA = YES; 314 | CLANG_WARN_CONSTANT_CONVERSION = YES; 315 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 316 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 317 | CLANG_WARN_EMPTY_BODY = YES; 318 | CLANG_WARN_ENUM_CONVERSION = YES; 319 | CLANG_WARN_INFINITE_RECURSION = YES; 320 | CLANG_WARN_INT_CONVERSION = YES; 321 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 322 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 323 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 325 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 326 | CLANG_WARN_STRICT_PROTOTYPES = YES; 327 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 328 | CLANG_WARN_UNREACHABLE_CODE = YES; 329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 330 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 331 | COPY_PHASE_STRIP = NO; 332 | DEBUG_INFORMATION_FORMAT = dwarf; 333 | ENABLE_STRICT_OBJC_MSGSEND = YES; 334 | ENABLE_TESTABILITY = YES; 335 | GCC_C_LANGUAGE_STANDARD = gnu99; 336 | GCC_DYNAMIC_NO_PIC = NO; 337 | GCC_NO_COMMON_BLOCKS = YES; 338 | GCC_OPTIMIZATION_LEVEL = 0; 339 | GCC_PREPROCESSOR_DEFINITIONS = ( 340 | "DEBUG=1", 341 | "$(inherited)", 342 | ); 343 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 344 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 345 | GCC_WARN_UNDECLARED_SELECTOR = YES; 346 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 347 | GCC_WARN_UNUSED_FUNCTION = YES; 348 | GCC_WARN_UNUSED_VARIABLE = YES; 349 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 350 | MTL_ENABLE_DEBUG_INFO = YES; 351 | ONLY_ACTIVE_ARCH = YES; 352 | SDKROOT = iphoneos; 353 | TARGETED_DEVICE_FAMILY = "1,2"; 354 | }; 355 | name = Debug; 356 | }; 357 | 97C147041CF9000F007C117D /* Release */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | ALWAYS_SEARCH_USER_PATHS = NO; 361 | CLANG_ANALYZER_NONNULL = YES; 362 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 363 | CLANG_CXX_LIBRARY = "libc++"; 364 | CLANG_ENABLE_MODULES = YES; 365 | CLANG_ENABLE_OBJC_ARC = YES; 366 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 367 | CLANG_WARN_BOOL_CONVERSION = YES; 368 | CLANG_WARN_COMMA = YES; 369 | CLANG_WARN_CONSTANT_CONVERSION = YES; 370 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 371 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 372 | CLANG_WARN_EMPTY_BODY = YES; 373 | CLANG_WARN_ENUM_CONVERSION = YES; 374 | CLANG_WARN_INFINITE_RECURSION = YES; 375 | CLANG_WARN_INT_CONVERSION = YES; 376 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 377 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 378 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 379 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 380 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 381 | CLANG_WARN_STRICT_PROTOTYPES = YES; 382 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 383 | CLANG_WARN_UNREACHABLE_CODE = YES; 384 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 385 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 386 | COPY_PHASE_STRIP = NO; 387 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 388 | ENABLE_NS_ASSERTIONS = NO; 389 | ENABLE_STRICT_OBJC_MSGSEND = YES; 390 | GCC_C_LANGUAGE_STANDARD = gnu99; 391 | GCC_NO_COMMON_BLOCKS = YES; 392 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 393 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 394 | GCC_WARN_UNDECLARED_SELECTOR = YES; 395 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 396 | GCC_WARN_UNUSED_FUNCTION = YES; 397 | GCC_WARN_UNUSED_VARIABLE = YES; 398 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 399 | MTL_ENABLE_DEBUG_INFO = NO; 400 | SDKROOT = iphoneos; 401 | SUPPORTED_PLATFORMS = iphoneos; 402 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 403 | TARGETED_DEVICE_FAMILY = "1,2"; 404 | VALIDATE_PRODUCT = YES; 405 | }; 406 | name = Release; 407 | }; 408 | 97C147061CF9000F007C117D /* Debug */ = { 409 | isa = XCBuildConfiguration; 410 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 411 | buildSettings = { 412 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 413 | CLANG_ENABLE_MODULES = YES; 414 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 415 | ENABLE_BITCODE = NO; 416 | INFOPLIST_FILE = Runner/Info.plist; 417 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 418 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 419 | PRODUCT_NAME = "$(TARGET_NAME)"; 420 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 421 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 422 | SWIFT_VERSION = 5.0; 423 | VERSIONING_SYSTEM = "apple-generic"; 424 | }; 425 | name = Debug; 426 | }; 427 | 97C147071CF9000F007C117D /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 430 | buildSettings = { 431 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 432 | CLANG_ENABLE_MODULES = YES; 433 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 434 | ENABLE_BITCODE = NO; 435 | INFOPLIST_FILE = Runner/Info.plist; 436 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 437 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 438 | PRODUCT_NAME = "$(TARGET_NAME)"; 439 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 440 | SWIFT_VERSION = 5.0; 441 | VERSIONING_SYSTEM = "apple-generic"; 442 | }; 443 | name = Release; 444 | }; 445 | /* End XCBuildConfiguration section */ 446 | 447 | /* Begin XCConfigurationList section */ 448 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 449 | isa = XCConfigurationList; 450 | buildConfigurations = ( 451 | 97C147031CF9000F007C117D /* Debug */, 452 | 97C147041CF9000F007C117D /* Release */, 453 | 249021D3217E4FDB00AE95B9 /* Profile */, 454 | ); 455 | defaultConfigurationIsVisible = 0; 456 | defaultConfigurationName = Release; 457 | }; 458 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 459 | isa = XCConfigurationList; 460 | buildConfigurations = ( 461 | 97C147061CF9000F007C117D /* Debug */, 462 | 97C147071CF9000F007C117D /* Release */, 463 | 249021D4217E4FDB00AE95B9 /* Profile */, 464 | ); 465 | defaultConfigurationIsVisible = 0; 466 | defaultConfigurationName = Release; 467 | }; 468 | /* End XCConfigurationList section */ 469 | }; 470 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 471 | } 472 | -------------------------------------------------------------------------------- /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 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/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 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/views/home/home_view.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:responsive_builder/responsive_builder.dart'; 4 | 5 | void main() => runApp(MyApp()); 6 | 7 | class MyApp extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return ResponsiveApp( 11 | builder: (context) { 12 | return MaterialApp( 13 | title: 'Flutter Demo', 14 | home: HomeView(), 15 | ); 16 | }, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /example/lib/views/home/home_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/views/home/home_view_mobile.dart'; 2 | import 'package:example/views/home/home_view_tablet.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:responsive_builder/responsive_builder.dart'; 5 | 6 | class HomeView extends StatelessWidget { 7 | const HomeView({Key? key}) : super(key: key); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return ScreenTypeLayout.builder( 12 | breakpoints: ScreenBreakpoints(desktop: 900, tablet: 650, watch: 250), 13 | mobile: (_) => OrientationLayoutBuilder( 14 | portrait: (context) => HomeMobilePortrait(), 15 | landscape: (context) => HomeMobileLandscape(), 16 | ), 17 | tablet: (_) => HomeViewTablet(), 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /example/lib/views/home/home_view_mobile.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/widgets/app_drawer/app_drawer.dart'; 2 | /// Contains the widgets that will be used for Mobile layout of home, 3 | /// portrait and landscape 4 | 5 | import 'package:flutter/material.dart'; 6 | 7 | class HomeMobilePortrait extends StatelessWidget { 8 | final GlobalKey _scaffoldKey = GlobalKey(); 9 | HomeMobilePortrait({Key? key}) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | key: _scaffoldKey, 15 | drawer: AppDrawer(), 16 | body: Column( 17 | children: [ 18 | Padding( 19 | padding: const EdgeInsets.all(16), 20 | child: IconButton( 21 | icon: Icon(Icons.menu, size: 30), 22 | onPressed: () { 23 | _scaffoldKey.currentState!.openDrawer(); 24 | }, 25 | ), 26 | ) 27 | ], 28 | ), 29 | ); 30 | } 31 | } 32 | 33 | class HomeMobileLandscape extends StatelessWidget { 34 | const HomeMobileLandscape({Key? key}) : super(key: key); 35 | 36 | @override 37 | Widget build(BuildContext context) { 38 | return Scaffold( 39 | body: Row(children: [ 40 | AppDrawer() 41 | ],), 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /example/lib/views/home/home_view_tablet.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/widgets/app_drawer/app_drawer.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class HomeViewTablet extends StatelessWidget { 5 | const HomeViewTablet({Key? key}) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | var children = [ 10 | Expanded( 11 | child: Container(), 12 | ), 13 | AppDrawer() 14 | ]; 15 | var orientation = MediaQuery.of(context).orientation; 16 | return Scaffold( 17 | body: orientation == Orientation.portrait 18 | ? Column(children: children) 19 | : Row(children: children.reversed.toList()), 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /example/lib/widgets/app_drawer/app_drawer.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/widgets/drawer_option/drawer_option.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:responsive_builder/responsive_builder.dart'; 4 | 5 | import 'app_drawer_mobile.dart'; 6 | import 'app_drawer_tablet.dart'; 7 | 8 | class AppDrawer extends StatelessWidget { 9 | const AppDrawer({Key? key}) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return ScreenTypeLayout.builder( 14 | mobile: (_) => AppDrawerMobile(), 15 | tablet: (_) => OrientationLayoutBuilder( 16 | portrait: (context) => AppDrawerTabletPortrait(), 17 | landscape: (context) => AppDrawerTabletLandscape(), 18 | ), 19 | ); 20 | } 21 | 22 | static List getDrawerOptions() { 23 | return [ 24 | DrawerOption( 25 | title: 'Images', 26 | iconData: Icons.image, 27 | ), 28 | DrawerOption( 29 | title: 'Reports', 30 | iconData: Icons.photo_filter, 31 | ), 32 | DrawerOption( 33 | title: 'Incidents', 34 | iconData: Icons.message, 35 | ), 36 | DrawerOption( 37 | title: 'Settings', 38 | iconData: Icons.settings, 39 | ), 40 | ]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /example/lib/widgets/app_drawer/app_drawer_mobile.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'app_drawer.dart'; 4 | 5 | class AppDrawerMobile extends StatelessWidget { 6 | const AppDrawerMobile({Key? key}) : super(key: key); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | var orientation = MediaQuery.of(context).orientation; 11 | return Container( 12 | width: orientation == Orientation.portrait ? 250 : 100, 13 | decoration: BoxDecoration(color: Colors.white, boxShadow: [ 14 | BoxShadow( 15 | blurRadius: 16, 16 | color: Colors.black12, 17 | ) 18 | ]), 19 | child: Column(children: AppDrawer.getDrawerOptions(),), 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /example/lib/widgets/app_drawer/app_drawer_tablet.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'app_drawer.dart'; 4 | 5 | class AppDrawerTabletPortrait extends StatelessWidget { 6 | const AppDrawerTabletPortrait({Key? key}) : super(key: key); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Container( 11 | height: 130, 12 | decoration: BoxDecoration(color: Colors.white, boxShadow: [ 13 | BoxShadow( 14 | blurRadius: 16, 15 | color: Colors.black12, 16 | ) 17 | ]), 18 | child: Row( 19 | children: AppDrawer.getDrawerOptions(), 20 | ), 21 | ); 22 | } 23 | } 24 | 25 | class AppDrawerTabletLandscape extends StatelessWidget { 26 | const AppDrawerTabletLandscape({Key? key}) : super(key: key); 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return Container( 31 | width: 250, 32 | decoration: BoxDecoration(color: Colors.white, boxShadow: [ 33 | BoxShadow( 34 | blurRadius: 16, 35 | color: Colors.black12, 36 | ) 37 | ]), 38 | child: Column( 39 | children: AppDrawer.getDrawerOptions(), 40 | ), 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /example/lib/widgets/drawer_option/drawer_option.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:responsive_builder/responsive_builder.dart'; 3 | 4 | import 'drawer_option_mobile.dart'; 5 | import 'drawer_option_tablet.dart'; 6 | 7 | class DrawerOption extends StatelessWidget { 8 | final String? title; 9 | final IconData? iconData; 10 | const DrawerOption({ 11 | Key? key, 12 | this.title, 13 | this.iconData, 14 | }) : super(key: key); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return ScreenTypeLayout.builder( 19 | mobile: (_) => OrientationLayoutBuilder( 20 | landscape: (context) => DrawerOptionMobileLandscape( 21 | iconData: iconData, 22 | ), 23 | portrait: (context) => DrawerOptionMobilePortrait( 24 | title: title, 25 | iconData: iconData, 26 | ), 27 | ), 28 | tablet: (_) => OrientationLayoutBuilder( 29 | portrait: (context) => DrawerOptionTabletPortrait( 30 | iconData: iconData, 31 | title: title, 32 | ), 33 | landscape: (context) => DrawerOptionMobilePortrait( 34 | iconData: iconData, 35 | title: title, 36 | ), 37 | ), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /example/lib/widgets/drawer_option/drawer_option_mobile.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DrawerOptionMobilePortrait extends StatelessWidget { 4 | final String? title; 5 | final IconData? iconData; 6 | const DrawerOptionMobilePortrait({ 7 | Key? key, 8 | this.title, 9 | this.iconData, 10 | }) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Container( 15 | padding: const EdgeInsets.only(left: 25), 16 | height: 80, 17 | child: Row( 18 | children: [ 19 | Icon( 20 | iconData, 21 | size: 25, 22 | ), 23 | SizedBox( 24 | width: 25, 25 | ), 26 | Text( 27 | title!, 28 | style: TextStyle(fontSize: 21), 29 | ) 30 | ], 31 | ), 32 | ); 33 | } 34 | } 35 | 36 | class DrawerOptionMobileLandscape extends StatelessWidget { 37 | final IconData? iconData; 38 | const DrawerOptionMobileLandscape({Key? key, this.iconData}) : super(key: key); 39 | 40 | @override 41 | Widget build(BuildContext context) { 42 | return Container( 43 | height: 70, 44 | alignment: Alignment.center, 45 | child: Icon(iconData), 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/lib/widgets/drawer_option/drawer_option_tablet.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DrawerOptionTabletPortrait extends StatelessWidget { 4 | final String? title; 5 | final IconData? iconData; 6 | const DrawerOptionTabletPortrait({ 7 | Key? key, 8 | this.title, 9 | this.iconData, 10 | }) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Container( 15 | width: 152, 16 | alignment: Alignment.center, 17 | child: Column( 18 | mainAxisSize: MainAxisSize.min, 19 | children: [ 20 | Icon( 21 | iconData, 22 | size: 45, 23 | ), 24 | Text(title!, style: TextStyle(fontSize: 20)), 25 | ], 26 | ), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: A new Flutter project. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # In Android, build-name is used as versionName while build-number used as versionCode. 10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 12 | # Read more about iOS versioning at 13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 14 | version: 1.0.0+1 15 | publish_to: none 16 | 17 | environment: 18 | sdk: ">=2.12.0 <=4.0.0" 19 | 20 | dependencies: 21 | flutter: 22 | sdk: flutter 23 | 24 | # The following adds the Cupertino Icons font to your application. 25 | # Use with the CupertinoIcons class for iOS style icons. 26 | cupertino_icons: ^1.0.2 27 | responsive_builder: 28 | path: ../ 29 | 30 | dev_dependencies: 31 | flutter_test: 32 | sdk: flutter 33 | 34 | # For information on the generic Dart part of this file, see the 35 | # following page: https://dart.dev/tools/pub/pubspec 36 | 37 | # The following section is specific to Flutter. 38 | flutter: 39 | # The following line ensures that the Material Icons font is 40 | # included with your application, so that you can use the icons in 41 | # the material Icons class. 42 | uses-material-design: true 43 | 44 | # To add assets to your application, add an assets section, like this: 45 | # assets: 46 | # - images/a_dot_burr.jpeg 47 | # - images/a_dot_ham.jpeg 48 | 49 | # An image asset can refer to one or more resolution-specific "variants", see 50 | # https://flutter.dev/assets-and-images/#resolution-aware. 51 | 52 | # For details regarding adding assets from package dependencies, see 53 | # https://flutter.dev/assets-and-images/#from-packages 54 | 55 | # To add custom fonts to your application, add a fonts section here, 56 | # in this "flutter" section. Each entry in this list should have a 57 | # "family" key with the font family name, and a "fonts" key with a 58 | # list giving the asset and other descriptors for the font. For 59 | # example: 60 | # fonts: 61 | # - family: Schyler 62 | # fonts: 63 | # - asset: fonts/Schyler-Regular.ttf 64 | # - asset: fonts/Schyler-Italic.ttf 65 | # style: italic 66 | # - family: Trajan Pro 67 | # fonts: 68 | # - asset: fonts/TrajanPro.ttf 69 | # - asset: fonts/TrajanPro_Bold.ttf 70 | # weight: 700 71 | # 72 | # For details regarding fonts from package dependencies, 73 | # see https://flutter.dev/custom-fonts/#from-packages 74 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:example/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/example/web/favicon.png -------------------------------------------------------------------------------- /example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | example 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /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 | } 24 | -------------------------------------------------------------------------------- /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 | cmake_minimum_required(VERSION 3.15) 2 | project(example LANGUAGES CXX) 3 | 4 | set(BINARY_NAME "example") 5 | 6 | cmake_policy(SET CMP0063 NEW) 7 | 8 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") 9 | 10 | # Configure build options. 11 | get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) 12 | if(IS_MULTICONFIG) 13 | set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" 14 | CACHE STRING "" FORCE) 15 | else() 16 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 17 | set(CMAKE_BUILD_TYPE "Debug" CACHE 18 | STRING "Flutter build mode" FORCE) 19 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 20 | "Debug" "Profile" "Release") 21 | endif() 22 | endif() 23 | 24 | set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") 25 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") 26 | set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") 27 | set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") 28 | 29 | # Use Unicode for all projects. 30 | add_definitions(-DUNICODE -D_UNICODE) 31 | 32 | # Compilation settings that should be applied to most targets. 33 | function(APPLY_STANDARD_SETTINGS TARGET) 34 | target_compile_features(${TARGET} PUBLIC cxx_std_17) 35 | target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") 36 | target_compile_options(${TARGET} PRIVATE /EHsc) 37 | target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") 38 | target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") 39 | endfunction() 40 | 41 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 42 | 43 | # Flutter library and tool build rules. 44 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 45 | 46 | # Application build 47 | add_subdirectory("runner") 48 | 49 | # Generated plugin build rules, which manage building the plugins and adding 50 | # them to the application. 51 | include(flutter/generated_plugins.cmake) 52 | 53 | 54 | # === Installation === 55 | # Support files are copied into place next to the executable, so that it can 56 | # run in place. This is done instead of making a separate bundle (as on Linux) 57 | # so that building and running from within Visual Studio will work. 58 | set(BUILD_BUNDLE_DIR "$") 59 | # Make the "install" step default, as it's required to run. 60 | set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) 61 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 62 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 63 | endif() 64 | 65 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 66 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") 67 | 68 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 69 | COMPONENT Runtime) 70 | 71 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 72 | COMPONENT Runtime) 73 | 74 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 75 | COMPONENT Runtime) 76 | 77 | if(PLUGIN_BUNDLED_LIBRARIES) 78 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" 79 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 80 | COMPONENT Runtime) 81 | endif() 82 | 83 | # Fully re-copy the assets directory on each build to avoid having stale files 84 | # from a previous install. 85 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 86 | install(CODE " 87 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 88 | " COMPONENT Runtime) 89 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 90 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 91 | 92 | # Install the AOT library on non-Debug builds only. 93 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 94 | CONFIGURATIONS Profile;Release 95 | COMPONENT Runtime) 96 | -------------------------------------------------------------------------------- /example/windows/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 4 | 5 | # Configuration provided via flutter tool. 6 | include(${EPHEMERAL_DIR}/generated_config.cmake) 7 | 8 | # TODO: Move the rest of this into files in ephemeral. See 9 | # https://github.com/flutter/flutter/issues/57146. 10 | set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") 11 | 12 | # === Flutter Library === 13 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") 14 | 15 | # Published to parent scope for install step. 16 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 17 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 18 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 19 | set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) 20 | 21 | list(APPEND FLUTTER_LIBRARY_HEADERS 22 | "flutter_export.h" 23 | "flutter_windows.h" 24 | "flutter_messenger.h" 25 | "flutter_plugin_registrar.h" 26 | "flutter_texture_registrar.h" 27 | ) 28 | list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") 29 | add_library(flutter INTERFACE) 30 | target_include_directories(flutter INTERFACE 31 | "${EPHEMERAL_DIR}" 32 | ) 33 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") 34 | add_dependencies(flutter flutter_assemble) 35 | 36 | # === Wrapper === 37 | list(APPEND CPP_WRAPPER_SOURCES_CORE 38 | "core_implementations.cc" 39 | "standard_codec.cc" 40 | ) 41 | list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") 42 | list(APPEND CPP_WRAPPER_SOURCES_PLUGIN 43 | "plugin_registrar.cc" 44 | ) 45 | list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") 46 | list(APPEND CPP_WRAPPER_SOURCES_APP 47 | "flutter_engine.cc" 48 | "flutter_view_controller.cc" 49 | ) 50 | list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") 51 | 52 | # Wrapper sources needed for a plugin. 53 | add_library(flutter_wrapper_plugin STATIC 54 | ${CPP_WRAPPER_SOURCES_CORE} 55 | ${CPP_WRAPPER_SOURCES_PLUGIN} 56 | ) 57 | apply_standard_settings(flutter_wrapper_plugin) 58 | set_target_properties(flutter_wrapper_plugin PROPERTIES 59 | POSITION_INDEPENDENT_CODE ON) 60 | set_target_properties(flutter_wrapper_plugin PROPERTIES 61 | CXX_VISIBILITY_PRESET hidden) 62 | target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) 63 | target_include_directories(flutter_wrapper_plugin PUBLIC 64 | "${WRAPPER_ROOT}/include" 65 | ) 66 | add_dependencies(flutter_wrapper_plugin flutter_assemble) 67 | 68 | # Wrapper sources needed for the runner. 69 | add_library(flutter_wrapper_app STATIC 70 | ${CPP_WRAPPER_SOURCES_CORE} 71 | ${CPP_WRAPPER_SOURCES_APP} 72 | ) 73 | apply_standard_settings(flutter_wrapper_app) 74 | target_link_libraries(flutter_wrapper_app PUBLIC flutter) 75 | target_include_directories(flutter_wrapper_app PUBLIC 76 | "${WRAPPER_ROOT}/include" 77 | ) 78 | add_dependencies(flutter_wrapper_app flutter_assemble) 79 | 80 | # === Flutter tool backend === 81 | # _phony_ is a non-existent file to force this command to run every time, 82 | # since currently there's no way to get a full input/output list from the 83 | # flutter tool. 84 | set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") 85 | set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) 86 | add_custom_command( 87 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 88 | ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} 89 | ${CPP_WRAPPER_SOURCES_APP} 90 | ${PHONY_OUTPUT} 91 | COMMAND ${CMAKE_COMMAND} -E env 92 | ${FLUTTER_TOOL_ENVIRONMENT} 93 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" 94 | windows-x64 $ 95 | VERBATIM 96 | ) 97 | add_custom_target(flutter_assemble DEPENDS 98 | "${FLUTTER_LIBRARY}" 99 | ${FLUTTER_LIBRARY_HEADERS} 100 | ${CPP_WRAPPER_SOURCES_CORE} 101 | ${CPP_WRAPPER_SOURCES_PLUGIN} 102 | ${CPP_WRAPPER_SOURCES_APP} 103 | ) 104 | -------------------------------------------------------------------------------- /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.15) 2 | project(runner LANGUAGES CXX) 3 | 4 | add_executable(${BINARY_NAME} WIN32 5 | "flutter_window.cpp" 6 | "main.cpp" 7 | "run_loop.cpp" 8 | "utils.cpp" 9 | "win32_window.cpp" 10 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 11 | "Runner.rc" 12 | "runner.exe.manifest" 13 | ) 14 | apply_standard_settings(${BINARY_NAME}) 15 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 16 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 17 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 18 | add_dependencies(${BINARY_NAME} flutter_assemble) 19 | -------------------------------------------------------------------------------- /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 | #ifdef FLUTTER_BUILD_NUMBER 64 | #define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER 65 | #else 66 | #define VERSION_AS_NUMBER 1,0,0 67 | #endif 68 | 69 | #ifdef FLUTTER_BUILD_NAME 70 | #define VERSION_AS_STRING #FLUTTER_BUILD_NAME 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", "A new Flutter project." "\0" 94 | VALUE "FileVersion", VERSION_AS_STRING "\0" 95 | VALUE "InternalName", "example" "\0" 96 | VALUE "LegalCopyright", "Copyright (C) 2021 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(RunLoop* run_loop, 8 | const flutter::DartProject& project) 9 | : run_loop_(run_loop), project_(project) {} 10 | 11 | FlutterWindow::~FlutterWindow() {} 12 | 13 | bool FlutterWindow::OnCreate() { 14 | if (!Win32Window::OnCreate()) { 15 | return false; 16 | } 17 | 18 | RECT frame = GetClientArea(); 19 | 20 | // The size here must match the window dimensions to avoid unnecessary surface 21 | // creation / destruction in the startup path. 22 | flutter_controller_ = std::make_unique( 23 | frame.right - frame.left, frame.bottom - frame.top, project_); 24 | // Ensure that basic setup of the controller was successful. 25 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 26 | return false; 27 | } 28 | RegisterPlugins(flutter_controller_->engine()); 29 | run_loop_->RegisterFlutterInstance(flutter_controller_->engine()); 30 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 31 | return true; 32 | } 33 | 34 | void FlutterWindow::OnDestroy() { 35 | if (flutter_controller_) { 36 | run_loop_->UnregisterFlutterInstance(flutter_controller_->engine()); 37 | flutter_controller_ = nullptr; 38 | } 39 | 40 | Win32Window::OnDestroy(); 41 | } 42 | 43 | LRESULT 44 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 45 | WPARAM const wparam, 46 | LPARAM const lparam) noexcept { 47 | // Give Flutter, including plugins, an opporutunity to handle window messages. 48 | if (flutter_controller_) { 49 | std::optional result = 50 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 51 | lparam); 52 | if (result) { 53 | return *result; 54 | } 55 | } 56 | 57 | switch (message) { 58 | case WM_FONTCHANGE: 59 | flutter_controller_->engine()->ReloadSystemFonts(); 60 | break; 61 | } 62 | 63 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 64 | } 65 | -------------------------------------------------------------------------------- /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 "run_loop.h" 10 | #include "win32_window.h" 11 | 12 | // A window that does nothing but host a Flutter view. 13 | class FlutterWindow : public Win32Window { 14 | public: 15 | // Creates a new FlutterWindow driven by the |run_loop|, hosting a 16 | // Flutter view running |project|. 17 | explicit FlutterWindow(RunLoop* run_loop, 18 | const flutter::DartProject& project); 19 | virtual ~FlutterWindow(); 20 | 21 | protected: 22 | // Win32Window: 23 | bool OnCreate() override; 24 | void OnDestroy() override; 25 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 26 | LPARAM const lparam) noexcept override; 27 | 28 | private: 29 | // The run loop driving events for this window. 30 | RunLoop* run_loop_; 31 | 32 | // The project to run. 33 | flutter::DartProject project_; 34 | 35 | // The Flutter instance hosted by this window. 36 | std::unique_ptr flutter_controller_; 37 | }; 38 | 39 | #endif // RUNNER_FLUTTER_WINDOW_H_ 40 | -------------------------------------------------------------------------------- /example/windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "run_loop.h" 7 | #include "utils.h" 8 | 9 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 10 | _In_ wchar_t *command_line, _In_ int show_command) { 11 | // Attach to console when present (e.g., 'flutter run') or create a 12 | // new console when running with a debugger. 13 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 14 | CreateAndAttachConsole(); 15 | } 16 | 17 | // Initialize COM, so that it is available for use in the library and/or 18 | // plugins. 19 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 20 | 21 | RunLoop run_loop; 22 | 23 | flutter::DartProject project(L"data"); 24 | 25 | std::vector command_line_arguments = 26 | GetCommandLineArguments(); 27 | 28 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 29 | 30 | FlutterWindow window(&run_loop, project); 31 | Win32Window::Point origin(10, 10); 32 | Win32Window::Size size(1280, 720); 33 | if (!window.CreateAndShow(L"example", origin, size)) { 34 | return EXIT_FAILURE; 35 | } 36 | window.SetQuitOnClose(true); 37 | 38 | run_loop.Run(); 39 | 40 | ::CoUninitialize(); 41 | return EXIT_SUCCESS; 42 | } 43 | -------------------------------------------------------------------------------- /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/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/example/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /example/windows/runner/run_loop.cpp: -------------------------------------------------------------------------------- 1 | #include "run_loop.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | RunLoop::RunLoop() {} 8 | 9 | RunLoop::~RunLoop() {} 10 | 11 | void RunLoop::Run() { 12 | bool keep_running = true; 13 | TimePoint next_flutter_event_time = TimePoint::clock::now(); 14 | while (keep_running) { 15 | std::chrono::nanoseconds wait_duration = 16 | std::max(std::chrono::nanoseconds(0), 17 | next_flutter_event_time - TimePoint::clock::now()); 18 | ::MsgWaitForMultipleObjects( 19 | 0, nullptr, FALSE, static_cast(wait_duration.count() / 1000), 20 | QS_ALLINPUT); 21 | bool processed_events = false; 22 | MSG message; 23 | // All pending Windows messages must be processed; MsgWaitForMultipleObjects 24 | // won't return again for items left in the queue after PeekMessage. 25 | while (::PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) { 26 | processed_events = true; 27 | if (message.message == WM_QUIT) { 28 | keep_running = false; 29 | break; 30 | } 31 | ::TranslateMessage(&message); 32 | ::DispatchMessage(&message); 33 | // Allow Flutter to process messages each time a Windows message is 34 | // processed, to prevent starvation. 35 | next_flutter_event_time = 36 | std::min(next_flutter_event_time, ProcessFlutterMessages()); 37 | } 38 | // If the PeekMessage loop didn't run, process Flutter messages. 39 | if (!processed_events) { 40 | next_flutter_event_time = 41 | std::min(next_flutter_event_time, ProcessFlutterMessages()); 42 | } 43 | } 44 | } 45 | 46 | void RunLoop::RegisterFlutterInstance( 47 | flutter::FlutterEngine* flutter_instance) { 48 | flutter_instances_.insert(flutter_instance); 49 | } 50 | 51 | void RunLoop::UnregisterFlutterInstance( 52 | flutter::FlutterEngine* flutter_instance) { 53 | flutter_instances_.erase(flutter_instance); 54 | } 55 | 56 | RunLoop::TimePoint RunLoop::ProcessFlutterMessages() { 57 | TimePoint next_event_time = TimePoint::max(); 58 | for (auto instance : flutter_instances_) { 59 | std::chrono::nanoseconds wait_duration = instance->ProcessMessages(); 60 | if (wait_duration != std::chrono::nanoseconds::max()) { 61 | next_event_time = 62 | std::min(next_event_time, TimePoint::clock::now() + wait_duration); 63 | } 64 | } 65 | return next_event_time; 66 | } 67 | -------------------------------------------------------------------------------- /example/windows/runner/run_loop.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_RUN_LOOP_H_ 2 | #define RUNNER_RUN_LOOP_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | // A runloop that will service events for Flutter instances as well 10 | // as native messages. 11 | class RunLoop { 12 | public: 13 | RunLoop(); 14 | ~RunLoop(); 15 | 16 | // Prevent copying 17 | RunLoop(RunLoop const&) = delete; 18 | RunLoop& operator=(RunLoop const&) = delete; 19 | 20 | // Runs the run loop until the application quits. 21 | void Run(); 22 | 23 | // Registers the given Flutter instance for event servicing. 24 | void RegisterFlutterInstance( 25 | flutter::FlutterEngine* flutter_instance); 26 | 27 | // Unregisters the given Flutter instance from event servicing. 28 | void UnregisterFlutterInstance( 29 | flutter::FlutterEngine* flutter_instance); 30 | 31 | private: 32 | using TimePoint = std::chrono::steady_clock::time_point; 33 | 34 | // Processes all currently pending messages for registered Flutter instances. 35 | TimePoint ProcessFlutterMessages(); 36 | 37 | std::set flutter_instances_; 38 | }; 39 | 40 | #endif // RUNNER_RUN_LOOP_H_ 41 | -------------------------------------------------------------------------------- /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 | if (target_length == 0) { 52 | return std::string(); 53 | } 54 | std::string utf8_string; 55 | utf8_string.resize(target_length); 56 | int converted_length = ::WideCharToMultiByte( 57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 58 | -1, utf8_string.data(), 59 | target_length, nullptr, nullptr); 60 | if (converted_length == 0) { 61 | return std::string(); 62 | } 63 | return utf8_string; 64 | } 65 | -------------------------------------------------------------------------------- /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.cpp: -------------------------------------------------------------------------------- 1 | #include "win32_window.h" 2 | 3 | #include 4 | 5 | #include "resource.h" 6 | 7 | namespace { 8 | 9 | constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; 10 | 11 | // The number of Win32Window objects that currently exist. 12 | static int g_active_window_count = 0; 13 | 14 | using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); 15 | 16 | // Scale helper to convert logical scaler values to physical using passed in 17 | // scale factor 18 | int Scale(int source, double scale_factor) { 19 | return static_cast(source * scale_factor); 20 | } 21 | 22 | // Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. 23 | // This API is only needed for PerMonitor V1 awareness mode. 24 | void EnableFullDpiSupportIfAvailable(HWND hwnd) { 25 | HMODULE user32_module = LoadLibraryA("User32.dll"); 26 | if (!user32_module) { 27 | return; 28 | } 29 | auto enable_non_client_dpi_scaling = 30 | reinterpret_cast( 31 | GetProcAddress(user32_module, "EnableNonClientDpiScaling")); 32 | if (enable_non_client_dpi_scaling != nullptr) { 33 | enable_non_client_dpi_scaling(hwnd); 34 | FreeLibrary(user32_module); 35 | } 36 | } 37 | 38 | } // namespace 39 | 40 | // Manages the Win32Window's window class registration. 41 | class WindowClassRegistrar { 42 | public: 43 | ~WindowClassRegistrar() = default; 44 | 45 | // Returns the singleton registar instance. 46 | static WindowClassRegistrar* GetInstance() { 47 | if (!instance_) { 48 | instance_ = new WindowClassRegistrar(); 49 | } 50 | return instance_; 51 | } 52 | 53 | // Returns the name of the window class, registering the class if it hasn't 54 | // previously been registered. 55 | const wchar_t* GetWindowClass(); 56 | 57 | // Unregisters the window class. Should only be called if there are no 58 | // instances of the window. 59 | void UnregisterWindowClass(); 60 | 61 | private: 62 | WindowClassRegistrar() = default; 63 | 64 | static WindowClassRegistrar* instance_; 65 | 66 | bool class_registered_ = false; 67 | }; 68 | 69 | WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; 70 | 71 | const wchar_t* WindowClassRegistrar::GetWindowClass() { 72 | if (!class_registered_) { 73 | WNDCLASS window_class{}; 74 | window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); 75 | window_class.lpszClassName = kWindowClassName; 76 | window_class.style = CS_HREDRAW | CS_VREDRAW; 77 | window_class.cbClsExtra = 0; 78 | window_class.cbWndExtra = 0; 79 | window_class.hInstance = GetModuleHandle(nullptr); 80 | window_class.hIcon = 81 | LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); 82 | window_class.hbrBackground = 0; 83 | window_class.lpszMenuName = nullptr; 84 | window_class.lpfnWndProc = Win32Window::WndProc; 85 | RegisterClass(&window_class); 86 | class_registered_ = true; 87 | } 88 | return kWindowClassName; 89 | } 90 | 91 | void WindowClassRegistrar::UnregisterWindowClass() { 92 | UnregisterClass(kWindowClassName, nullptr); 93 | class_registered_ = false; 94 | } 95 | 96 | Win32Window::Win32Window() { 97 | ++g_active_window_count; 98 | } 99 | 100 | Win32Window::~Win32Window() { 101 | --g_active_window_count; 102 | Destroy(); 103 | } 104 | 105 | bool Win32Window::CreateAndShow(const std::wstring& title, 106 | const Point& origin, 107 | const Size& size) { 108 | Destroy(); 109 | 110 | const wchar_t* window_class = 111 | WindowClassRegistrar::GetInstance()->GetWindowClass(); 112 | 113 | const POINT target_point = {static_cast(origin.x), 114 | static_cast(origin.y)}; 115 | HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); 116 | UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); 117 | double scale_factor = dpi / 96.0; 118 | 119 | HWND window = CreateWindow( 120 | window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 121 | Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), 122 | Scale(size.width, scale_factor), Scale(size.height, scale_factor), 123 | nullptr, nullptr, GetModuleHandle(nullptr), this); 124 | 125 | if (!window) { 126 | return false; 127 | } 128 | 129 | return OnCreate(); 130 | } 131 | 132 | // static 133 | LRESULT CALLBACK Win32Window::WndProc(HWND const window, 134 | UINT const message, 135 | WPARAM const wparam, 136 | LPARAM const lparam) noexcept { 137 | if (message == WM_NCCREATE) { 138 | auto window_struct = reinterpret_cast(lparam); 139 | SetWindowLongPtr(window, GWLP_USERDATA, 140 | reinterpret_cast(window_struct->lpCreateParams)); 141 | 142 | auto that = static_cast(window_struct->lpCreateParams); 143 | EnableFullDpiSupportIfAvailable(window); 144 | that->window_handle_ = window; 145 | } else if (Win32Window* that = GetThisFromHandle(window)) { 146 | return that->MessageHandler(window, message, wparam, lparam); 147 | } 148 | 149 | return DefWindowProc(window, message, wparam, lparam); 150 | } 151 | 152 | LRESULT 153 | Win32Window::MessageHandler(HWND hwnd, 154 | UINT const message, 155 | WPARAM const wparam, 156 | LPARAM const lparam) noexcept { 157 | switch (message) { 158 | case WM_DESTROY: 159 | window_handle_ = nullptr; 160 | Destroy(); 161 | if (quit_on_close_) { 162 | PostQuitMessage(0); 163 | } 164 | return 0; 165 | 166 | case WM_DPICHANGED: { 167 | auto newRectSize = reinterpret_cast(lparam); 168 | LONG newWidth = newRectSize->right - newRectSize->left; 169 | LONG newHeight = newRectSize->bottom - newRectSize->top; 170 | 171 | SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, 172 | newHeight, SWP_NOZORDER | SWP_NOACTIVATE); 173 | 174 | return 0; 175 | } 176 | case WM_SIZE: { 177 | RECT rect = GetClientArea(); 178 | if (child_content_ != nullptr) { 179 | // Size and position the child window. 180 | MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, 181 | rect.bottom - rect.top, TRUE); 182 | } 183 | return 0; 184 | } 185 | 186 | case WM_ACTIVATE: 187 | if (child_content_ != nullptr) { 188 | SetFocus(child_content_); 189 | } 190 | return 0; 191 | } 192 | 193 | return DefWindowProc(window_handle_, message, wparam, lparam); 194 | } 195 | 196 | void Win32Window::Destroy() { 197 | OnDestroy(); 198 | 199 | if (window_handle_) { 200 | DestroyWindow(window_handle_); 201 | window_handle_ = nullptr; 202 | } 203 | if (g_active_window_count == 0) { 204 | WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); 205 | } 206 | } 207 | 208 | Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { 209 | return reinterpret_cast( 210 | GetWindowLongPtr(window, GWLP_USERDATA)); 211 | } 212 | 213 | void Win32Window::SetChildContent(HWND content) { 214 | child_content_ = content; 215 | SetParent(content, window_handle_); 216 | RECT frame = GetClientArea(); 217 | 218 | MoveWindow(content, frame.left, frame.top, frame.right - frame.left, 219 | frame.bottom - frame.top, true); 220 | 221 | SetFocus(child_content_); 222 | } 223 | 224 | RECT Win32Window::GetClientArea() { 225 | RECT frame; 226 | GetClientRect(window_handle_, &frame); 227 | return frame; 228 | } 229 | 230 | HWND Win32Window::GetHandle() { 231 | return window_handle_; 232 | } 233 | 234 | void Win32Window::SetQuitOnClose(bool quit_on_close) { 235 | quit_on_close_ = quit_on_close; 236 | } 237 | 238 | bool Win32Window::OnCreate() { 239 | // No-op; provided for subclasses. 240 | return true; 241 | } 242 | 243 | void Win32Window::OnDestroy() { 244 | // No-op; provided for subclasses. 245 | } 246 | -------------------------------------------------------------------------------- /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 and shows a win32 window with |title| and position and size 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 to will treat the width height passed in to this function 35 | // as logical pixels and scale to appropriate for the default monitor. Returns 36 | // true if the window was created successfully. 37 | bool CreateAndShow(const std::wstring& title, 38 | const Point& origin, 39 | const Size& size); 40 | 41 | // Release OS resources associated with window. 42 | void Destroy(); 43 | 44 | // Inserts |content| into the window tree. 45 | void SetChildContent(HWND content); 46 | 47 | // Returns the backing Window handle to enable clients to set icon and other 48 | // window properties. Returns nullptr if the window has been destroyed. 49 | HWND GetHandle(); 50 | 51 | // If true, closing this window will quit the application. 52 | void SetQuitOnClose(bool quit_on_close); 53 | 54 | // Return a RECT representing the bounds of the current client area. 55 | RECT GetClientArea(); 56 | 57 | protected: 58 | // Processes and route salient window messages for mouse handling, 59 | // size change and DPI. Delegates handling of these to member overloads that 60 | // inheriting classes can handle. 61 | virtual LRESULT MessageHandler(HWND window, 62 | UINT const message, 63 | WPARAM const wparam, 64 | LPARAM const lparam) noexcept; 65 | 66 | // Called when CreateAndShow is called, allowing subclass window-related 67 | // setup. Subclasses should return false if setup fails. 68 | virtual bool OnCreate(); 69 | 70 | // Called when Destroy is called. 71 | virtual void OnDestroy(); 72 | 73 | private: 74 | friend class WindowClassRegistrar; 75 | 76 | // OS callback called by message pump. Handles the WM_NCCREATE message which 77 | // is passed when the non-client area is being created and enables automatic 78 | // non-client DPI scaling so that the non-client area automatically 79 | // responsponds to changes in DPI. All other messages are handled by 80 | // MessageHandler. 81 | static LRESULT CALLBACK WndProc(HWND const window, 82 | UINT const message, 83 | WPARAM const wparam, 84 | LPARAM const lparam) noexcept; 85 | 86 | // Retrieves a class instance pointer for |window| 87 | static Win32Window* GetThisFromHandle(HWND const window) noexcept; 88 | 89 | bool quit_on_close_ = false; 90 | 91 | // window handle for top level window. 92 | HWND window_handle_ = nullptr; 93 | 94 | // window handle for hosted content. 95 | HWND child_content_ = nullptr; 96 | }; 97 | 98 | #endif // RUNNER_WIN32_WINDOW_H_ 99 | -------------------------------------------------------------------------------- /lib/responsive_builder.dart: -------------------------------------------------------------------------------- 1 | library responsive_builder; 2 | 3 | export 'src/device_screen_type.dart'; 4 | export 'src/helpers/helpers.dart'; 5 | export 'src/responsive_sizing_config.dart'; 6 | export 'src/responsive_wrapper.dart'; 7 | export 'src/scroll/scroll_transform_item.dart'; 8 | export 'src/scroll/scroll_transform_view.dart'; 9 | export 'src/sizing_information.dart'; 10 | export 'src/widget_builders.dart'; 11 | -------------------------------------------------------------------------------- /lib/src/device_screen_type.dart: -------------------------------------------------------------------------------- 1 | enum DeviceScreenType { 2 | @Deprecated('Use lowercase version') 3 | Mobile, 4 | @Deprecated('Use lowercase version') 5 | Tablet, 6 | @Deprecated('Use lowercase version') 7 | Desktop, 8 | @Deprecated('Use lowercase version') 9 | Watch, 10 | mobile, 11 | tablet, 12 | desktop, 13 | watch 14 | } 15 | 16 | enum RefinedSize { small, normal, large, extraLarge } 17 | -------------------------------------------------------------------------------- /lib/src/helpers/device_width.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:ui'; 3 | 4 | double deviceWidth(Size size) { 5 | if (Platform.isMacOS || Platform.isWindows || Platform.isLinux) { 6 | return size.width; 7 | } 8 | return size.shortestSide; 9 | } 10 | -------------------------------------------------------------------------------- /lib/src/helpers/device_width_web.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | double deviceWidth(Size size) => size.width; 4 | -------------------------------------------------------------------------------- /lib/src/helpers/helpers.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:responsive_builder/responsive_builder.dart'; 4 | 5 | import 'device_width.dart' if (dart.library.js) 'device_width_web.dart' 6 | as width; 7 | 8 | /// Returns the [DeviceScreenType] that the application is currently running on 9 | DeviceScreenType getDeviceType( 10 | Size size, [ 11 | ScreenBreakpoints? breakpoint, 12 | ]) { 13 | double deviceWidth = width.deviceWidth(size); 14 | 15 | // Replaces the defaults with the user defined definitions 16 | if (breakpoint != null) { 17 | if (deviceWidth > breakpoint.desktop) { 18 | return DeviceScreenType.desktop; 19 | } 20 | 21 | if (deviceWidth > breakpoint.tablet) { 22 | return DeviceScreenType.tablet; 23 | } 24 | 25 | if (deviceWidth < breakpoint.watch) { 26 | return DeviceScreenType.watch; 27 | } 28 | } else { 29 | // If no user defined definitions are passed through use the defaults 30 | if (deviceWidth >= ResponsiveSizingConfig.instance.breakpoints.desktop) { 31 | return DeviceScreenType.desktop; 32 | } 33 | 34 | if (deviceWidth >= ResponsiveSizingConfig.instance.breakpoints.tablet) { 35 | return DeviceScreenType.tablet; 36 | } 37 | 38 | if (deviceWidth < ResponsiveSizingConfig.instance.breakpoints.watch) { 39 | return DeviceScreenType.watch; 40 | } 41 | } 42 | 43 | return DeviceScreenType.mobile; 44 | } 45 | 46 | /// Returns the [RefindedSize] for each device that the application is currently running on 47 | RefinedSize getRefinedSize( 48 | Size size, { 49 | RefinedBreakpoints? refinedBreakpoint, 50 | bool isWebOrDesktop = kIsWeb, 51 | }) { 52 | DeviceScreenType deviceScreenType = getDeviceType(size); 53 | double deviceWidth = size.shortestSide; 54 | 55 | if (isWebOrDesktop) { 56 | deviceWidth = size.width; 57 | } 58 | 59 | // Replaces the defaults with the user defined definitions 60 | if (refinedBreakpoint != null) { 61 | if (deviceScreenType == DeviceScreenType.desktop) { 62 | if (deviceWidth > refinedBreakpoint.desktopExtraLarge) { 63 | return RefinedSize.extraLarge; 64 | } 65 | 66 | if (deviceWidth > refinedBreakpoint.desktopLarge) { 67 | return RefinedSize.large; 68 | } 69 | 70 | if (deviceWidth > refinedBreakpoint.desktopNormal) { 71 | return RefinedSize.normal; 72 | } 73 | } 74 | 75 | if (deviceScreenType == DeviceScreenType.tablet) { 76 | if (deviceWidth > refinedBreakpoint.tabletExtraLarge) { 77 | return RefinedSize.extraLarge; 78 | } 79 | 80 | if (deviceWidth > refinedBreakpoint.tabletLarge) { 81 | return RefinedSize.large; 82 | } 83 | 84 | if (deviceWidth > refinedBreakpoint.tabletNormal) { 85 | return RefinedSize.normal; 86 | } 87 | } 88 | 89 | if (deviceScreenType == DeviceScreenType.mobile) { 90 | if (deviceWidth > refinedBreakpoint.mobileExtraLarge) { 91 | return RefinedSize.extraLarge; 92 | } 93 | 94 | if (deviceWidth > refinedBreakpoint.mobileLarge) { 95 | return RefinedSize.large; 96 | } 97 | 98 | if (deviceWidth > refinedBreakpoint.mobileNormal) { 99 | return RefinedSize.normal; 100 | } 101 | } 102 | 103 | if (deviceScreenType == DeviceScreenType.watch) { 104 | return RefinedSize.normal; 105 | } 106 | } else { 107 | // If no user defined definitions are passed through use the defaults 108 | 109 | // Desktop 110 | if (deviceScreenType == DeviceScreenType.desktop) { 111 | if (deviceWidth >= 112 | ResponsiveSizingConfig 113 | .instance.refinedBreakpoints.desktopExtraLarge) { 114 | return RefinedSize.extraLarge; 115 | } 116 | 117 | if (deviceWidth >= 118 | ResponsiveSizingConfig.instance.refinedBreakpoints.desktopLarge) { 119 | return RefinedSize.large; 120 | } 121 | 122 | if (deviceWidth >= 123 | ResponsiveSizingConfig.instance.refinedBreakpoints.desktopNormal) { 124 | return RefinedSize.normal; 125 | } 126 | } 127 | 128 | // Tablet 129 | if (deviceScreenType == DeviceScreenType.tablet) { 130 | if (deviceWidth >= 131 | ResponsiveSizingConfig.instance.refinedBreakpoints.tabletExtraLarge) { 132 | return RefinedSize.extraLarge; 133 | } 134 | 135 | if (deviceWidth >= 136 | ResponsiveSizingConfig.instance.refinedBreakpoints.tabletLarge) { 137 | return RefinedSize.large; 138 | } 139 | 140 | if (deviceWidth >= 141 | ResponsiveSizingConfig.instance.refinedBreakpoints.tabletNormal) { 142 | return RefinedSize.normal; 143 | } 144 | } 145 | 146 | // Mobile 147 | if (deviceScreenType == DeviceScreenType.mobile) { 148 | if (deviceWidth >= 149 | ResponsiveSizingConfig.instance.refinedBreakpoints.mobileExtraLarge) { 150 | return RefinedSize.extraLarge; 151 | } 152 | 153 | if (deviceWidth >= 154 | ResponsiveSizingConfig.instance.refinedBreakpoints.mobileLarge) { 155 | return RefinedSize.large; 156 | } 157 | 158 | if (deviceWidth >= 159 | ResponsiveSizingConfig.instance.refinedBreakpoints.mobileNormal) { 160 | return RefinedSize.normal; 161 | } 162 | } 163 | } 164 | 165 | return RefinedSize.small; 166 | } 167 | 168 | /// Will return one of the values passed in for the device it's running on 169 | T getValueForScreenType({ 170 | required BuildContext context, 171 | required T mobile, 172 | T? tablet, 173 | T? desktop, 174 | T? watch, 175 | }) { 176 | var deviceScreenType = getDeviceType(MediaQuery.of(context).size); 177 | // If we're at desktop size 178 | if (deviceScreenType == DeviceScreenType.desktop) { 179 | // If we have supplied the desktop layout then display that 180 | if (desktop != null) return desktop; 181 | // If no desktop layout is supplied we want to check if we have the size below it and display that 182 | if (tablet != null) return tablet; 183 | } 184 | 185 | if (deviceScreenType == DeviceScreenType.tablet) { 186 | if (tablet != null) return tablet; 187 | } 188 | 189 | if (deviceScreenType == DeviceScreenType.watch && watch != null) { 190 | return watch; 191 | } 192 | 193 | if (deviceScreenType == DeviceScreenType.mobile) { 194 | if (mobile != null) return mobile; 195 | } 196 | 197 | // If none of the layouts above are supplied we use the prefered layout based on the flag 198 | final buildDesktopLayout = ResponsiveAppUtil.preferDesktop && desktop != null; 199 | 200 | return buildDesktopLayout ? desktop : mobile; 201 | } 202 | 203 | /// Will return one of the values passed in for the refined size 204 | T getValueForRefinedSize({ 205 | required BuildContext context, 206 | required T normal, 207 | T? large, 208 | T? extraLarge, 209 | T? small, 210 | }) { 211 | var refinedSize = getRefinedSize(MediaQuery.of(context).size); 212 | // If we're at extra large size 213 | if (refinedSize == RefinedSize.extraLarge) { 214 | // If we have supplied the extra large layout then display that 215 | if (extraLarge != null) return extraLarge; 216 | // If no extra large layout is supplied we want to check if we have the size below it and display that 217 | if (large != null) return large; 218 | } 219 | 220 | if (refinedSize == RefinedSize.large) { 221 | // If we have supplied the large layout then display that 222 | if (large != null) return large; 223 | // If no large layout is supplied we want to check if we have the size below it and display that 224 | if (normal != null) return normal; 225 | } 226 | 227 | if (refinedSize == RefinedSize.normal) { 228 | // If we have supplied the normal layout then display that 229 | if (normal != null) return normal; 230 | } 231 | 232 | if (refinedSize == RefinedSize.small) { 233 | // If we have supplied the small layout then display that 234 | if (small != null) return small; 235 | } 236 | 237 | // If none of the layouts above are supplied or we're on the normal size layout then we show the normal layout 238 | return normal; 239 | } 240 | 241 | class ScreenTypeValueBuilder { 242 | @Deprecated('Use better named global function getValueForScreenType') 243 | T getValueForType({ 244 | required BuildContext context, 245 | required T mobile, 246 | T? tablet, 247 | T? desktop, 248 | T? watch, 249 | }) { 250 | return getValueForScreenType( 251 | context: context, 252 | mobile: mobile, 253 | tablet: tablet, 254 | desktop: desktop, 255 | watch: watch, 256 | ); 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /lib/src/responsive_sizing_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:responsive_builder/responsive_builder.dart'; 2 | 3 | /// Keeps the configuration that will determines the breakpoints for different device sizes 4 | class ResponsiveSizingConfig { 5 | static ResponsiveSizingConfig? _instance; 6 | static ResponsiveSizingConfig get instance { 7 | if (_instance == null) { 8 | _instance = ResponsiveSizingConfig(); 9 | } 10 | 11 | return _instance!; 12 | } 13 | 14 | static const ScreenBreakpoints _defaultBreakPoints = const ScreenBreakpoints( 15 | desktop: 950, 16 | tablet: 600, 17 | watch: 300, 18 | ); 19 | 20 | ScreenBreakpoints? _customBreakPoints; 21 | 22 | static const RefinedBreakpoints _defaultRefinedBreakPoints = 23 | const RefinedBreakpoints( 24 | // Desktop 25 | desktopExtraLarge: 4096, 26 | desktopLarge: 3840, 27 | desktopNormal: 1920, 28 | desktopSmall: 950, 29 | // Tablet 30 | tabletExtraLarge: 900, 31 | tabletLarge: 850, 32 | tabletNormal: 768, 33 | tabletSmall: 600, 34 | // Mobile 35 | mobileExtraLarge: 480, 36 | mobileLarge: 414, 37 | mobileNormal: 375, 38 | mobileSmall: 320, 39 | ); 40 | 41 | RefinedBreakpoints? _customRefinedBreakPoints; 42 | 43 | /// Set the breakPoints which will then be returned through the [breakpoints] 44 | void setCustomBreakpoints( 45 | ScreenBreakpoints? customBreakpoints, { 46 | RefinedBreakpoints? customRefinedBreakpoints, 47 | }) { 48 | _customBreakPoints = customBreakpoints; 49 | if (customRefinedBreakpoints != null) { 50 | _customRefinedBreakPoints = customRefinedBreakpoints; 51 | } 52 | } 53 | 54 | ScreenBreakpoints get breakpoints => 55 | _customBreakPoints ?? _defaultBreakPoints; 56 | 57 | RefinedBreakpoints get refinedBreakpoints => 58 | _customRefinedBreakPoints ?? _defaultRefinedBreakPoints; 59 | } 60 | -------------------------------------------------------------------------------- /lib/src/responsive_wrapper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// Wrap your app with this widget if you want to use the responsive sizing extension 4 | class ResponsiveApp extends StatelessWidget { 5 | final Widget Function(BuildContext) builder; 6 | 7 | /// Tells ResponsiveApp if we prefer desktop or mobile when a layout is not supplied 8 | final bool preferDesktop; 9 | 10 | const ResponsiveApp( 11 | {Key? key, required this.builder, this.preferDesktop = false}) 12 | : super(key: key); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return LayoutBuilder(builder: (context, constraints) { 17 | return OrientationBuilder(builder: (context, orientation) { 18 | ResponsiveAppUtil.setScreenSize(constraints, orientation); 19 | ResponsiveAppUtil.preferDesktop = preferDesktop; 20 | return builder(context); 21 | }); 22 | }); 23 | } 24 | } 25 | 26 | extension ResponsiveAppExtensions on num { 27 | /// Returns the pecentage of screen height based on the extended number 28 | /// Example: 20.screenHeight = (20 / 100) * currentScreenHeight 29 | double get screenHeight => (this / 100) * ResponsiveAppUtil.height; 30 | 31 | /// Returns the pecentage of screen width based on the extended number 32 | /// Example: 20.screenHeight = (20 / 100) * currentScreenHeight 33 | double get screenWidth => (this / 100) * ResponsiveAppUtil.width; 34 | 35 | /// Shorthand for [screenHeight] 36 | double get sh => screenHeight; 37 | 38 | /// Shorthand for [screenWidth] 39 | double get sw => screenWidth; 40 | } 41 | 42 | class ResponsiveAppUtil { 43 | static late double height; 44 | static late double width; 45 | static bool preferDesktop = false; 46 | 47 | /// Saves the screenSzie for access through the extensions later 48 | static void setScreenSize( 49 | BoxConstraints constraints, 50 | Orientation orientation, 51 | ) { 52 | if (orientation == Orientation.portrait) { 53 | width = constraints.maxWidth; 54 | height = constraints.maxHeight; 55 | } else { 56 | width = constraints.maxHeight; 57 | height = constraints.maxWidth; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/src/scroll/scroll_transform_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | 4 | class ScrollTransformItem extends StatelessWidget { 5 | final Offset Function(double scrollOffset)? offsetBuilder; 6 | final double Function(double scrollOffset)? scaleBuilder; 7 | final Widget Function(double scrollOffset) builder; 8 | final bool logOffset; 9 | const ScrollTransformItem({ 10 | Key? key, 11 | required this.builder, 12 | this.offsetBuilder, 13 | this.scaleBuilder, 14 | this.logOffset = false, 15 | }) : super(key: key); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Consumer( 20 | builder: (context, value, child) { 21 | final builtOffset = offsetBuilder?.call(value.offset); 22 | return Transform.scale( 23 | scale: scaleBuilder?.call(value.offset) ?? 1, 24 | child: Transform.translate( 25 | offset: builtOffset ?? Offset.zero, 26 | child: builder(value.offset), 27 | ), 28 | ); 29 | }, 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/src/scroll/scroll_transform_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:responsive_builder/src/scroll/scroll_transform_item.dart'; 4 | 5 | class ScrollTransformView extends StatefulWidget { 6 | final List children; 7 | const ScrollTransformView({ 8 | Key? key, 9 | required this.children, 10 | }) : super(key: key); 11 | 12 | @override 13 | State createState() => _ScrollTransformViewState(); 14 | } 15 | 16 | class _ScrollTransformViewState extends State { 17 | final scrollController = ScrollController(); 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return SingleChildScrollView( 22 | controller: scrollController, 23 | child: ChangeNotifierProvider( 24 | create: (context) => scrollController, 25 | child: Column( 26 | children: widget.children, 27 | ), 28 | ), 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/src/sizing_information.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'device_screen_type.dart'; 3 | 4 | /// Contains sizing information to make responsive choices for the current screen 5 | class SizingInformation { 6 | final DeviceScreenType deviceScreenType; 7 | final RefinedSize refinedSize; 8 | final Size screenSize; 9 | final Size localWidgetSize; 10 | 11 | bool get isMobile => deviceScreenType == DeviceScreenType.mobile; 12 | 13 | bool get isTablet => deviceScreenType == DeviceScreenType.tablet; 14 | 15 | bool get isDesktop => deviceScreenType == DeviceScreenType.desktop; 16 | 17 | bool get isWatch => deviceScreenType == DeviceScreenType.watch; 18 | 19 | // Refined 20 | 21 | bool get isExtraLarge => refinedSize == RefinedSize.extraLarge; 22 | 23 | bool get isLarge => refinedSize == RefinedSize.large; 24 | 25 | bool get isNormal => refinedSize == RefinedSize.normal; 26 | 27 | bool get isSmall => refinedSize == RefinedSize.small; 28 | 29 | SizingInformation({ 30 | required this.deviceScreenType, 31 | required this.refinedSize, 32 | required this.screenSize, 33 | required this.localWidgetSize, 34 | }); 35 | 36 | @override 37 | String toString() { 38 | return 'DeviceType:$deviceScreenType RefinedSize:$refinedSize ScreenSize:$screenSize LocalWidgetSize:$localWidgetSize'; 39 | } 40 | } 41 | 42 | /// Manually define screen resolution breakpoints 43 | /// 44 | /// Overrides the defaults 45 | class ScreenBreakpoints { 46 | final double watch; 47 | final double tablet; 48 | final double desktop; 49 | 50 | const ScreenBreakpoints({ 51 | required this.desktop, 52 | required this.tablet, 53 | required this.watch, 54 | }); 55 | 56 | @override 57 | String toString() { 58 | return "Desktop: $desktop, Tablet: $tablet, Watch: $watch"; 59 | } 60 | } 61 | 62 | /// Manually define refined breakpoints 63 | /// 64 | /// Overrides the defaults 65 | class RefinedBreakpoints { 66 | final double mobileSmall; 67 | final double mobileNormal; 68 | final double mobileLarge; 69 | final double mobileExtraLarge; 70 | 71 | final double tabletSmall; 72 | final double tabletNormal; 73 | final double tabletLarge; 74 | final double tabletExtraLarge; 75 | 76 | final double desktopSmall; 77 | final double desktopNormal; 78 | final double desktopLarge; 79 | final double desktopExtraLarge; 80 | 81 | const RefinedBreakpoints({ 82 | this.mobileSmall = 320, 83 | this.mobileNormal = 375, 84 | this.mobileLarge = 414, 85 | this.mobileExtraLarge = 480, 86 | this.tabletSmall = 600, 87 | this.tabletNormal = 768, 88 | this.tabletLarge = 850, 89 | this.tabletExtraLarge = 900, 90 | this.desktopSmall = 950, 91 | this.desktopNormal = 1920, 92 | this.desktopLarge = 3840, 93 | this.desktopExtraLarge = 4096, 94 | }); 95 | 96 | @override 97 | String toString() { 98 | return "Desktop: Small - $desktopSmall Normal - $desktopNormal Large - $desktopLarge ExtraLarge - $desktopExtraLarge" + 99 | "\nTablet: Small - $tabletSmall Normal - $tabletNormal Large - $tabletLarge ExtraLarge - $tabletExtraLarge" + 100 | "\nMobile: Small - $mobileSmall Normal - $mobileNormal Large - $mobileLarge ExtraLarge - $mobileExtraLarge"; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /lib/src/widget_builders.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../responsive_builder.dart'; 4 | 5 | typedef WidgetBuilder = Widget Function(BuildContext); 6 | 7 | /// A widget with a builder that provides you with the sizingInformation 8 | /// 9 | /// This widget is used by the ScreenTypeLayout to provide different widget builders 10 | class ResponsiveBuilder extends StatelessWidget { 11 | final Widget Function( 12 | BuildContext context, 13 | SizingInformation sizingInformation, 14 | ) builder; 15 | 16 | final ScreenBreakpoints? breakpoints; 17 | final RefinedBreakpoints? refinedBreakpoints; 18 | 19 | const ResponsiveBuilder({ 20 | Key? key, 21 | required this.builder, 22 | this.breakpoints, 23 | this.refinedBreakpoints, 24 | }) : super(key: key); 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return LayoutBuilder(builder: (context, boxConstraints) { 29 | var mediaQuery = MediaQuery.of(context); 30 | var sizingInformation = SizingInformation( 31 | deviceScreenType: getDeviceType(mediaQuery.size, breakpoints), 32 | refinedSize: getRefinedSize( 33 | mediaQuery.size, 34 | refinedBreakpoint: refinedBreakpoints, 35 | ), 36 | screenSize: mediaQuery.size, 37 | localWidgetSize: 38 | Size(boxConstraints.maxWidth, boxConstraints.maxHeight), 39 | ); 40 | return builder(context, sizingInformation); 41 | }); 42 | } 43 | } 44 | 45 | enum OrientationLayoutBuilderMode { 46 | auto, 47 | landscape, 48 | portrait, 49 | } 50 | 51 | /// Provides a builder function for a landscape and portrait widget 52 | class OrientationLayoutBuilder extends StatelessWidget { 53 | final WidgetBuilder? landscape; 54 | final WidgetBuilder portrait; 55 | final OrientationLayoutBuilderMode mode; 56 | 57 | const OrientationLayoutBuilder({ 58 | Key? key, 59 | this.landscape, 60 | required this.portrait, 61 | this.mode = OrientationLayoutBuilderMode.auto, 62 | }) : super(key: key); 63 | 64 | @override 65 | Widget build(BuildContext context) { 66 | return Builder( 67 | builder: (context) { 68 | var orientation = MediaQuery.of(context).orientation; 69 | if (mode != OrientationLayoutBuilderMode.portrait && 70 | (orientation == Orientation.landscape || 71 | mode == OrientationLayoutBuilderMode.landscape)) { 72 | if (landscape != null) { 73 | return landscape!(context); 74 | } 75 | } 76 | 77 | return portrait(context); 78 | }, 79 | ); 80 | } 81 | } 82 | 83 | /// Provides a builder function for different screen types 84 | /// 85 | /// Each builder will get built based on the current device width. 86 | /// [breakpoints] define your own custom device resolutions 87 | /// [watch] will be built and shown when width is less than 300 88 | /// [mobile] will be built when width greater than 300 89 | /// [tablet] will be built when width is greater than 600 90 | /// [desktop] will be built if width is greater than 950 91 | class ScreenTypeLayout extends StatelessWidget { 92 | final ScreenBreakpoints? breakpoints; 93 | 94 | final WidgetBuilder? watch; 95 | final WidgetBuilder? mobile; 96 | final WidgetBuilder? tablet; 97 | final WidgetBuilder? desktop; 98 | 99 | @Deprecated( 100 | 'Use ScreenTypeLayout.builder instead for performance improvements', 101 | ) 102 | ScreenTypeLayout({ 103 | Key? key, 104 | this.breakpoints, 105 | Widget? watch, 106 | required Widget mobile, 107 | Widget? tablet, 108 | Widget? desktop, 109 | }) : this.watch = _builderOrNull(watch), 110 | this.mobile = _builderOrNull(mobile)!, 111 | this.tablet = _builderOrNull(tablet), 112 | this.desktop = _builderOrNull(desktop), 113 | super(key: key) { 114 | _checkIfMobileOrDesktopIsSupplied(); 115 | } 116 | 117 | ScreenTypeLayout.builder({ 118 | Key? key, 119 | this.breakpoints, 120 | this.watch, 121 | this.mobile, 122 | this.tablet, 123 | this.desktop, 124 | }) : super(key: key) { 125 | _checkIfMobileOrDesktopIsSupplied(); 126 | } 127 | 128 | void _checkIfMobileOrDesktopIsSupplied() { 129 | final hasMobileLayout = mobile != null; 130 | final hasDesktopLayout = desktop != null; 131 | 132 | assert( 133 | hasMobileLayout || hasDesktopLayout, 134 | 'You should supply either a mobile layout or a desktop layout. If you don\'t need two layouts then remove this widget and use the widget you want to use directly. ', 135 | ); 136 | } 137 | 138 | static WidgetBuilder? _builderOrNull(Widget? widget) { 139 | return widget == null ? null : ((_) => widget); 140 | } 141 | 142 | @override 143 | Widget build(BuildContext context) { 144 | return ResponsiveBuilder( 145 | breakpoints: breakpoints, 146 | builder: (context, sizingInformation) { 147 | // If we're at desktop size 148 | if (sizingInformation.deviceScreenType == DeviceScreenType.desktop) { 149 | // If we have supplied the desktop layout then display that 150 | if (desktop != null) return desktop!(context); 151 | // If no desktop layout is supplied we want to check if we have the size below it and display that 152 | if (tablet != null) return tablet!(context); 153 | } 154 | 155 | if (sizingInformation.deviceScreenType == DeviceScreenType.tablet) { 156 | if (tablet != null) return tablet!(context); 157 | } 158 | 159 | if (sizingInformation.deviceScreenType == DeviceScreenType.watch && 160 | watch != null) { 161 | return watch!(context); 162 | } 163 | 164 | if (sizingInformation.deviceScreenType == DeviceScreenType.mobile) { 165 | if (mobile != null) return mobile!(context); 166 | } 167 | 168 | // If none of the layouts above are supplied we use the prefered layout based on the flag 169 | final buildDesktopLayout = 170 | ResponsiveAppUtil.preferDesktop && desktop != null; 171 | 172 | return buildDesktopLayout ? desktop!(context) : mobile!(context); 173 | }, 174 | ); 175 | } 176 | } 177 | 178 | /// Provides a builder function for refined screen sizes to be used with [ScreenTypeLayout] 179 | /// 180 | /// Each builder will get built based on the current device width. 181 | /// [breakpoints] define your own custom device resolutions 182 | /// [extraLarge] will be built if width is greater than 2160 on Desktops, 1280 on Tablets, and 600 on Mobiles 183 | /// [large] will be built when width is greater than 1440 on Desktops, 1024 on Tablets, and 414 on Mobiles 184 | /// [normal] will be built when width is greater than 1080 on Desktops, 768 on Tablets, and 375 on Mobiles 185 | /// [small] will be built if width is less than 720 on Desktops, 600 on Tablets, and 320 on Mobiles 186 | class RefinedLayoutBuilder extends StatelessWidget { 187 | final RefinedBreakpoints? refinedBreakpoints; 188 | 189 | final WidgetBuilder? extraLarge; 190 | final WidgetBuilder? large; 191 | final WidgetBuilder normal; 192 | final WidgetBuilder? small; 193 | 194 | const RefinedLayoutBuilder({ 195 | Key? key, 196 | this.refinedBreakpoints, 197 | this.extraLarge, 198 | this.large, 199 | required this.normal, 200 | this.small, 201 | }) : super(key: key); 202 | 203 | @override 204 | Widget build(BuildContext context) { 205 | return ResponsiveBuilder( 206 | refinedBreakpoints: refinedBreakpoints, 207 | builder: (context, sizingInformation) { 208 | // If we're at extra large size 209 | if (sizingInformation.refinedSize == RefinedSize.extraLarge) { 210 | // If we have supplied the extra large layout then display that 211 | if (extraLarge != null) return extraLarge!(context); 212 | // If no extra large layout is supplied we want to check if we have the size below it and display that 213 | if (large != null) return large!(context); 214 | } 215 | 216 | if (sizingInformation.refinedSize == RefinedSize.large) { 217 | // If we have supplied the large layout then display that 218 | if (large != null) return large!(context); 219 | // If no large layout is supplied we want to check if we have the size below it and display that 220 | return normal(context); 221 | } 222 | 223 | if (sizingInformation.refinedSize == RefinedSize.small) { 224 | // If we have supplied the small layout then display that 225 | if (small != null) return small!(context); 226 | } 227 | 228 | // If none of the layouts above are supplied or we're on the small size layout then we show the small layout 229 | return normal(context); 230 | }, 231 | ); 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: responsive_builder 2 | description: A set of widgets that can be used to define a readable responsive UI for widgets. 3 | version: 0.7.1 4 | homepage: https://github.com/FilledStacks/responsive_builder 5 | 6 | funding: 7 | - https://ko-fi.com/filledstacks 8 | 9 | environment: 10 | sdk: ">=2.17.0 <4.0.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | provider: ^6.0.5 16 | 17 | dev_dependencies: 18 | flutter_test: 19 | sdk: flutter 20 | 21 | # For information on the generic Dart part of this file, see the 22 | # following page: https://dart.dev/tools/pub/pubspec 23 | 24 | # The following section is specific to Flutter. 25 | flutter: 26 | # To add assets to your package, add an assets section, like this: 27 | # assets: 28 | # - images/a_dot_burr.jpeg 29 | # - images/a_dot_ham.jpeg 30 | # 31 | # For details regarding assets in packages, see 32 | # https://flutter.dev/assets-and-images/#from-packages 33 | # 34 | # An image asset can refer to one or more resolution-specific "variants", see 35 | # https://flutter.dev/assets-and-images/#resolution-aware. 36 | # To add custom fonts to your package, add a fonts section here, 37 | # in this "flutter" section. Each entry in this list should have a 38 | # "family" key with the font family name, and a "fonts" key with a 39 | # list giving the asset and other descriptors for the font. For 40 | # example: 41 | # fonts: 42 | # - family: Schyler 43 | # fonts: 44 | # - asset: fonts/Schyler-Regular.ttf 45 | # - asset: fonts/Schyler-Italic.ttf 46 | # style: italic 47 | # - family: Trajan Pro 48 | # fonts: 49 | # - asset: fonts/TrajanPro.ttf 50 | # - asset: fonts/TrajanPro_Bold.ttf 51 | # weight: 700 52 | # 53 | # For details regarding fonts in packages, see 54 | # https://flutter.dev/custom-fonts/#from-packages 55 | -------------------------------------------------------------------------------- /responsive-builder-banner.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/responsive-builder-banner.jpeg -------------------------------------------------------------------------------- /responsive_example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FilledStacks/responsive_builder/94f90251ded8d58369430e350b73fe1a9c7d6e07/responsive_example.gif -------------------------------------------------------------------------------- /test/responsive_builder_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:responsive_builder/responsive_builder.dart'; 4 | 5 | void main() { 6 | group('getDeviceType-Defaults', () { 7 | test('When on device with width between 600 and 300 should return mobile', 8 | () async { 9 | var screenType = getDeviceType(Size(599, 800)); 10 | expect(screenType, DeviceScreenType.mobile); 11 | }); 12 | 13 | test('When on device with width between 600 and 950 should return mobile', 14 | () async { 15 | var screenType = getDeviceType(Size(949, 1200)); 16 | expect(screenType, DeviceScreenType.tablet); 17 | }); 18 | 19 | test('When on device with width higher than 950 should return desktop', 20 | () async { 21 | var screenType = getDeviceType(Size(1000, 1200)); 22 | expect(screenType, DeviceScreenType.desktop); 23 | }); 24 | 25 | test('When on device with width lower than 300 should return watch', 26 | () async { 27 | var screenType = getDeviceType(Size(1000, 1200)); 28 | expect(screenType, DeviceScreenType.desktop); 29 | }); 30 | }); 31 | 32 | group('getDeviceType-Custom Breakpoint', () { 33 | test( 34 | 'given break point with desktop at 1200 and width at 1201 should return desktop', 35 | () { 36 | var breakPoint = 37 | ScreenBreakpoints(desktop: 1200, tablet: 550, watch: 300); 38 | var screenType = getDeviceType(Size(1201, 1400), breakPoint); 39 | expect(screenType, DeviceScreenType.desktop); 40 | }); 41 | 42 | test( 43 | 'given break point with tablet at 550 and width at 1199 should return tablet', 44 | () { 45 | var breakPoint = 46 | ScreenBreakpoints(desktop: 1200, tablet: 550, watch: 300); 47 | var screenType = getDeviceType(Size(1199, 1400), breakPoint); 48 | expect(screenType, DeviceScreenType.tablet); 49 | }); 50 | 51 | test( 52 | 'given break point with watch at 150 and width at 149 should return watch', 53 | () { 54 | var breakPoint = 55 | ScreenBreakpoints(desktop: 1200, tablet: 550, watch: 150); 56 | var screenType = getDeviceType(Size(149, 340), breakPoint); 57 | expect(screenType, DeviceScreenType.watch); 58 | }); 59 | 60 | test( 61 | 'given break point with desktop 1200, tablet 550, should return mobile if width is under 550 above 150', 62 | () { 63 | var breakPoint = 64 | ScreenBreakpoints(desktop: 1200, tablet: 550, watch: 150); 65 | var screenType = getDeviceType(Size(549, 800), breakPoint); 66 | expect(screenType, DeviceScreenType.mobile); 67 | }); 68 | }); 69 | 70 | group('getDeviceType-Config set', () { 71 | test( 72 | 'When global config desktop set to 800, should return desktop when width is 801', 73 | () { 74 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 75 | ScreenBreakpoints(desktop: 800, tablet: 550, watch: 200)); 76 | 77 | var screenType = getDeviceType(Size(801, 1000)); 78 | expect(screenType, DeviceScreenType.desktop); 79 | }); 80 | test( 81 | 'When global config tablet set to 550, should return tablet when width is 799', 82 | () { 83 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 84 | ScreenBreakpoints(desktop: 800, tablet: 550, watch: 200)); 85 | 86 | var screenType = getDeviceType(Size(799, 1000)); 87 | expect(screenType, DeviceScreenType.tablet); 88 | }); 89 | test( 90 | 'When global config tablet set to 550, should return mobile when width is 799', 91 | () { 92 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 93 | ScreenBreakpoints(desktop: 800, tablet: 550, watch: 200)); 94 | 95 | var screenType = getDeviceType(Size(799, 1000)); 96 | expect(screenType, DeviceScreenType.tablet); 97 | }); 98 | 99 | test( 100 | 'When global config watch set to 200, should return watch when width is 199', 101 | () { 102 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 103 | ScreenBreakpoints(desktop: 800, tablet: 550, watch: 200)); 104 | 105 | var screenType = getDeviceType(Size(799, 1000)); 106 | expect(screenType, DeviceScreenType.tablet); 107 | }); 108 | }); 109 | 110 | group('getDeviceType-Config+Breakpoint', () { 111 | tearDown(() => ResponsiveSizingConfig.instance.setCustomBreakpoints(null)); 112 | test( 113 | 'When global config desktop set to 1000, should return desktop when custom breakpoint desktop is 800 and width is 801', 114 | () { 115 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 116 | ScreenBreakpoints(desktop: 1000, tablet: 600, watch: 200)); 117 | var breakPoint = ScreenBreakpoints(desktop: 800, tablet: 750, watch: 200); 118 | var screenType = getDeviceType(Size(801, 1000), breakPoint); 119 | expect(screenType, DeviceScreenType.desktop); 120 | }); 121 | test( 122 | 'When global config tablet set to 600, should return tablet when custom breakpoint tablet is 800 and width is 801', 123 | () { 124 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 125 | ScreenBreakpoints(desktop: 800, tablet: 600, watch: 200)); 126 | var breakPoint = ScreenBreakpoints(desktop: 950, tablet: 800, watch: 200); 127 | var screenType = getDeviceType(Size(801, 1000), breakPoint); 128 | expect(screenType, DeviceScreenType.tablet); 129 | }); 130 | test( 131 | 'When global config is set tablet 600, desktop 800, should return mobile if custom breakpoint has range of 200, 300 and width is 201', 132 | () { 133 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 134 | ScreenBreakpoints(desktop: 800, tablet: 600, watch: 200)); 135 | var breakPoint = ScreenBreakpoints(desktop: 950, tablet: 300, watch: 200); 136 | var screenType = getDeviceType(Size(201, 500), breakPoint); 137 | expect(screenType, DeviceScreenType.mobile); 138 | }); 139 | test( 140 | 'When global config watch set to 200, should return watch if custom breakpoint watch is 400 and width is 399', 141 | () { 142 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 143 | ScreenBreakpoints(desktop: 800, tablet: 600, watch: 200)); 144 | var breakPoint = ScreenBreakpoints(desktop: 950, tablet: 800, watch: 400); 145 | var screenType = getDeviceType(Size(399, 1000), breakPoint); 146 | expect(screenType, DeviceScreenType.watch); 147 | }); 148 | }); 149 | 150 | group('getRefinedSize - Custom break points -', () { 151 | test( 152 | 'When called with mobile size in small range, should return RefinedSize.small', 153 | () { 154 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 155 | ScreenBreakpoints(desktop: 800, tablet: 600, watch: 200)); 156 | var breakPoint = RefinedBreakpoints( 157 | mobileSmall: 300, 158 | mobileNormal: 370, 159 | mobileLarge: 440, 160 | mobileExtraLarge: 520, 161 | ); 162 | var refinedSize = getRefinedSize( 163 | Size(301, 1000), 164 | refinedBreakpoint: breakPoint, 165 | isWebOrDesktop: true, 166 | ); 167 | expect(refinedSize, RefinedSize.small); 168 | }); 169 | 170 | test( 171 | 'When called with mobile size in normal range, should return RefinedSize.normal', 172 | () { 173 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 174 | ScreenBreakpoints(desktop: 800, tablet: 600, watch: 200)); 175 | var breakPoint = RefinedBreakpoints( 176 | mobileSmall: 300, 177 | mobileNormal: 370, 178 | mobileLarge: 440, 179 | mobileExtraLarge: 520, 180 | ); 181 | var refinedSize = getRefinedSize( 182 | Size(371, 1000), 183 | refinedBreakpoint: breakPoint, 184 | isWebOrDesktop: true, 185 | ); 186 | expect(refinedSize, RefinedSize.normal); 187 | }); 188 | 189 | test( 190 | 'When called with mobile size in large range, should return RefinedSize.large', 191 | () { 192 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 193 | ScreenBreakpoints(desktop: 800, tablet: 600, watch: 200)); 194 | var breakPoint = RefinedBreakpoints( 195 | mobileSmall: 300, 196 | mobileNormal: 370, 197 | mobileLarge: 440, 198 | mobileExtraLarge: 520, 199 | ); 200 | var refinedSize = getRefinedSize( 201 | Size(441, 1000), 202 | refinedBreakpoint: breakPoint, 203 | isWebOrDesktop: true, 204 | ); 205 | expect(refinedSize, RefinedSize.large); 206 | }); 207 | 208 | test( 209 | 'When called with mobile size in extraLarge range, should return RefinedSize.extraLarge', 210 | () { 211 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 212 | ScreenBreakpoints(desktop: 800, tablet: 600, watch: 200)); 213 | var breakPoint = RefinedBreakpoints( 214 | mobileSmall: 300, 215 | mobileNormal: 370, 216 | mobileLarge: 440, 217 | mobileExtraLarge: 520, 218 | ); 219 | var refinedSize = getRefinedSize( 220 | Size(521, 1000), 221 | refinedBreakpoint: breakPoint, 222 | isWebOrDesktop: true, 223 | ); 224 | expect(refinedSize, RefinedSize.extraLarge); 225 | }); 226 | 227 | test( 228 | 'When called with desktop size in small range, should return RefinedSize.small', 229 | () { 230 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 231 | ScreenBreakpoints(desktop: 800, tablet: 600, watch: 200)); 232 | var breakPoint = RefinedBreakpoints( 233 | desktopSmall: 850, 234 | desktopNormal: 900, 235 | desktopLarge: 950, 236 | desktopExtraLarge: 1000); 237 | var refinedSize = getRefinedSize( 238 | Size(851, 1000), 239 | refinedBreakpoint: breakPoint, 240 | isWebOrDesktop: true, 241 | ); 242 | expect(refinedSize, RefinedSize.small); 243 | }); 244 | 245 | test( 246 | 'When called with desktop size in normal range, should return RefinedSize.normal', 247 | () { 248 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 249 | ScreenBreakpoints(desktop: 800, tablet: 600, watch: 200)); 250 | var breakPoint = RefinedBreakpoints( 251 | desktopSmall: 850, 252 | desktopNormal: 900, 253 | desktopLarge: 950, 254 | desktopExtraLarge: 1000); 255 | var refinedSize = getRefinedSize( 256 | Size(901, 1000), 257 | refinedBreakpoint: breakPoint, 258 | isWebOrDesktop: true, 259 | ); 260 | expect(refinedSize, RefinedSize.normal); 261 | }); 262 | 263 | test( 264 | 'When called with desktop size in large range, should return RefinedSize.large', 265 | () { 266 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 267 | ScreenBreakpoints(desktop: 800, tablet: 600, watch: 200)); 268 | var breakPoint = RefinedBreakpoints( 269 | desktopSmall: 850, 270 | desktopNormal: 900, 271 | desktopLarge: 950, 272 | desktopExtraLarge: 1000); 273 | var refinedSize = getRefinedSize( 274 | Size(951, 1000), 275 | refinedBreakpoint: breakPoint, 276 | isWebOrDesktop: true, 277 | ); 278 | expect(refinedSize, RefinedSize.large); 279 | }); 280 | 281 | test( 282 | 'When called with desktop size in extraLarge range, should return RefinedSize.extraLarge', 283 | () { 284 | ResponsiveSizingConfig.instance.setCustomBreakpoints( 285 | ScreenBreakpoints(desktop: 800, tablet: 600, watch: 200)); 286 | var breakPoint = RefinedBreakpoints( 287 | desktopSmall: 850, 288 | desktopNormal: 900, 289 | desktopLarge: 950, 290 | desktopExtraLarge: 1000); 291 | var refinedSize = getRefinedSize( 292 | Size(1001, 1000), 293 | refinedBreakpoint: breakPoint, 294 | isWebOrDesktop: true, 295 | ); 296 | expect(refinedSize, RefinedSize.extraLarge); 297 | }); 298 | }); 299 | 300 | group('getRefinedSize -', () { 301 | setUp(() => ResponsiveSizingConfig.instance.setCustomBreakpoints(null)); 302 | test( 303 | 'When called with desktop size in extra large range, should return RefinedSize.extraLarge', 304 | () { 305 | var refinedSize = getRefinedSize(Size(4097, 1000), isWebOrDesktop: true); 306 | expect(refinedSize, RefinedSize.extraLarge); 307 | }); 308 | test( 309 | 'When called with desktop size in large range, should return RefinedSize.large', 310 | () { 311 | var refinedSize = getRefinedSize(Size(3840, 1000), isWebOrDesktop: true); 312 | expect(refinedSize, RefinedSize.large); 313 | }); 314 | test( 315 | 'When called with desktop size in normal range, should return RefinedSize.normal', 316 | () { 317 | var refinedSize = getRefinedSize(Size(1921, 1000), isWebOrDesktop: true); 318 | expect(refinedSize, RefinedSize.normal); 319 | }); 320 | 321 | test( 322 | 'When called with tablet size in extra large range, should return RefinedSize.extraLarge', 323 | () { 324 | var refinedSize = getRefinedSize(Size(901, 1000)); 325 | expect(refinedSize, RefinedSize.extraLarge); 326 | }); 327 | test( 328 | 'When called with tablet size in large range, should return RefinedSize.large', 329 | () { 330 | var refinedSize = getRefinedSize(Size(851, 1000)); 331 | expect(refinedSize, RefinedSize.large); 332 | }); 333 | test( 334 | 'When called with tablet size in normal range, should return RefinedSize.normal', 335 | () { 336 | var refinedSize = getRefinedSize(Size(769, 1000)); 337 | expect(refinedSize, RefinedSize.normal); 338 | }); 339 | }); 340 | } 341 | --------------------------------------------------------------------------------